NOTE: This page is part of the Ubuntu Specification process. Please check the status and details in Launchpad before editing. If the spec is Approved then you should contact the Assignee, or another knowledgeable person, before making changes.

Summary

Rather than store their home directories up on a server, some users would like to plug in flash media, and run off their memory stick. This currently works on the live CD. We should look at getting this to work for LTSP thin clients as well.

Rationale

Maintaining permanent home directories on an LTSP server may not be a desirable option for some administrators. For instance, in a public walk-up library terminal, where userids could be based off your library patron number, keeping the home directory around after the user logs out will be a management problem that the administrator won't want.

Use cases

Scope

Affects:

Design

Currently, the persistent home system on the live cd requires the user to reformat/repartition their usb stick with an EXT3 filesystem. We'd like to avoid this, for support reasons. This requires us to create another layer of filesystem.

We'll need a filesystem shim that will provide standard unix filesystem semantics on top of a vfat filesystem. Things we'll need to handle that a fat formatted memory stick don't have are:

Overall process will look something like the following:

However, while "complete", in the sense that it will provide a persistent home directory, it relies on a fuse filesystem that doesn't exist as of yet, as well as some fairly intrusive changes to the LTSP management process. So, a nice intermediate step would be to have proper temporary home directories.

The pam module pam_mkhomedir will MAKE the homedirectory, however, the pam_sm_close_session function in the module currently simply returns PAM_SUCCESS. What we'd like to do is modify pam_mkhomedir in the following way:

Implementation

Code

--- pam-0.79/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c    2006-11-07 19:25:50.000000000 -0600
+++ pam-0.79-sbalneav/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c   2006-11-08 02:14:29.000000000 -0600
@@ -31,10 +31,12 @@
 #define _GNU_SOURCE 1
 #include <stdarg.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <pwd.h>
+#include <grp.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -57,9 +59,12 @@
 /* argument parsing */
 #define MKHOMEDIR_DEBUG      020       /* keep quiet about things */
 #define MKHOMEDIR_QUIET      040       /* keep quiet about things */
+#define MKHOMEDIR_REMOVE    0200       /* Remove home dir on exit */
 
 static unsigned int UMask = 0022;
 static char SkelDir[BUFSIZ] = "/etc/skel"; /* THIS MODULE IS NOT THREAD SAFE */
+static char TmpHome[BUFSIZ] = "\0";
+static char TmpGrp[BUFSIZ] = "\0";
 
 /* some syslogging */
 static void _log_err(int err, const char *format, ...)
@@ -91,6 +96,14 @@
       } else if (!strncmp(*argv,"skel=",5)) {
         strncpy(SkelDir,*argv+5,sizeof(SkelDir));
         SkelDir[sizeof(SkelDir)-1] = '\0';
+      } else if (!strncmp(*argv,"tmphome",7)) {
+        ctrl |= MKHOMEDIR_REMOVE;
+      } else if (!strncmp(*argv,"dir=",4)) {
+        strncpy(TmpHome,*argv+4,sizeof(TmpHome));
+        TmpHome[sizeof(TmpHome)-1] = '\0';
+      } else if (!strncmp(*argv,"group=",6)) {
+        strncpy(TmpGrp,*argv+6,sizeof(TmpGrp));
+        TmpGrp[sizeof(TmpGrp)-1] = '\0';
       } else {
         _log_err(LOG_ERR, "unknown option; %s", *argv);
       }
@@ -458,6 +471,41 @@
    return PAM_SUCCESS;
 }
 
+static int remove_homedir(pam_handle_t * pamh, int ctrl,
+                          const struct passwd *pwd)
+{
+   int status;
+   pid_t child;
+   char *null_env[] = { NULL };
+   char *remove_cmd[] = { "/bin/rm", "-r", "-f",  pwd->pw_dir, NULL };
+
+   child = fork();
+
+   if (child == 0) {
+      execve(remove_cmd[0], remove_cmd, null_env);
+      _log_err(LOG_DEBUG, "execl() returned");
+      exit (1);                 /* exec should never return */
+   } else if (child > 0) {
+      if (waitpid(child, &status, 0) < 0) {
+         _log_err(LOG_DEBUG, "wait() failed");
+         exit(1);
+      }
+   } else if (child < 0) {
+      _log_err(LOG_DEBUG, "fork() failed");
+      exit(1);
+   }
+
+   if (!WIFEXITED(status)) {
+      _log_err(LOG_DEBUG, "execve() returned no status");
+      return PAM_SYSTEM_ERR;
+   }
+
+   if (WEXITSTATUS(status) != 0)
+      return PAM_SYSTEM_ERR;
+
+   return PAM_SUCCESS;
+}
+
 /* --- authentication management functions (only) --- */
 
 PAM_EXTERN
@@ -501,7 +549,71 @@
 int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc
                         ,const char **argv)
 {
-   return PAM_SUCCESS;
+   int retval, ctrl;
+   const char *user;
+   const struct passwd *pwd;
+   const struct group *grp = NULL;
+   int got_home = 0, got_group = 0;
+   struct stat St;
+
+   /* Parse the flag values */
+   ctrl = _pam_parse(flags, argc, argv);
+
+   /* Check and see if tmphome= has been specified. */
+   if ((ctrl & MKHOMEDIR_REMOVE) != MKHOMEDIR_REMOVE)
+      return PAM_SUCCESS;
+
+   /* Determine the user name so we can get the home directory */
+   retval = pam_get_item(pamh, PAM_USER, (const void **) &user);
+   if (retval != PAM_SUCCESS || user == NULL || *user == '\0')
+   {
+      _log_err(LOG_NOTICE, "user unknown");
+      return PAM_USER_UNKNOWN;
+   }
+
+   /* Get the password entry */
+   pwd = _pammodutil_getpwnam (pamh, user);
+   if (pwd == NULL)
+   {
+      D(("couldn't identify user %s", user));
+      return PAM_CRED_INSUFFICIENT;
+   }
+
+   if (stat(pwd->pw_dir,&St) != 0)     /* Home directory has already gone? */
+      return PAM_SUCCESS;
+
+   if (strlen(TmpGrp) > 0)             /* group= filled out */
+   {
+      grp = _pammodutil_getgrnam (pamh, TmpGrp);
+      if (grp == NULL)
+         grp = _pammodutil_getgrgid(pamh, atoi(TmpGrp));
+      if (grp && (grp->gr_gid == 0))           /* atoi failed, groupid = 0 */
+         grp = NULL;
+   }
+ 
+   if (grp) {
+      char **members = grp->gr_mem;
+
+      while (*members)
+      {
+         if (!strcmp(user, *(members)))
+         {
+            got_group = 1;
+            break;
+         }
+      }
+   }
+      
+   if (strlen(TmpHome) > 0)
+   {
+      if (strncmp(pwd->pw_dir, TmpHome, strlen(TmpHome)) == 0)
+         got_home = 1;
+   }
+
+   if (got_home || got_group)
+      return remove_homedir(pamh,ctrl,pwd);
+   else
+      return PAM_SUCCESS;
 }
 
 #ifdef PAM_STATIC

Data preservation and migration

None.

Administrator can add:

session required pam_mkhomedir.so tmphome dir=/tmphome/ skel=/etc/skel/ umask=0077

or

session required pam_mkhomedir.so tmphome group=tmphome skel=/etc/skel/ umask=0077

To their /etc/pam.d/common-session to use.

Unresolved issues


CategorySpec CategoryEdubuntuSpec

LtspPersistentHome (last edited 2009-07-24 03:07:01 by 201)