[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[patch] pam_mkhomedir sgid support



We just switched to LDAP authentication, and use pam_mkhomedir to create
directories on the first login.  However, the standard pam_mkhomedir does
not support our security model.  We have each user's home directory owned
by group www-data and mode 750, so apache can read user web pages, but
users can not look into other users' home directories.  The attached patch
significantly changes the behavior of pam_mkhomedir.

The umask is only used in the creation of the homedir itself.  For
everything else, it copies the permissions of the source file in the skel
directory.  SUID and sticky are never set.  SGID is set only for
directories in the skel directory which have SGID set, never for files or
the homedir itself.

If the current directory being acted on is the homedir, and the parent
directory has the SGID bit set, then group ownership of the homedir is
taken from the parent directory.  Otherwise, group ownership of the
homedir is the primary group of the user.

The patch looks big, but it's mostly duplication of code, with slight
variations for different situations.  I was worried more with having it
working and readable than with shrinking it.

-- 
Marshal Newrock, Simon's Rock College of Bard
Caution: product may be hot after heating

--- pam_mkhomedir-old.c	2002-08-07 08:42:29.000000000 -0400
+++ pam_mkhomedir.c	2002-08-07 16:08:41.000000000 -0400
@@ -7,7 +7,7 @@
    
    Here is a sample /etc/pam.d/login file for Debian GNU/Linux
    2.1:
-   
+ 
    auth       requisite  pam_securetty.so
    auth       sufficient pam_ldap.so
    auth       required   pam_pwdb.so
@@ -39,6 +39,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <dirent.h>
+#include <libgen.h>
 
 /*
  * here, we make a definition for the externally accessible function
@@ -177,6 +178,10 @@
    char remark[BUFSIZ];
    DIR *D;
    struct dirent *Dir;
+   
+   struct stat FileEntry;
+   char DirBase[BUFSIZ];
+   char *FilePath;
 
    /* Mention what is happening, if the notification fails that is OK */
    if (snprintf(remark,sizeof(remark),"Creating directory '%s'.", dest) == -1)
@@ -189,14 +194,70 @@
    {
       _log_err(LOG_DEBUG, "unable to create directory %s",source);
       return PAM_PERM_DENIED;
-   }   
-   if (chmod(dest,0777 & (~UMask)) != 0 ||
-       chown(dest,pwd->pw_uid,pwd->pw_gid) != 0)
+   }
+   
+   /* Watch for SGID bits, action depends on directory */
+   
+   /* If this is the homedir itself and SGID is set, */
+   /* set group ownership to that of parent directory */
+   if (strcmp(dest,pwd->pw_dir)==0)
+   {
+      FilePath=strdup(dest);
+      snprintf(DirBase, sizeof(DirBase), "%s", dirname(FilePath));
+      if (stat(DirBase,&FileEntry) != 0)
+      {
+         _log_err(LOG_DEBUG, "unable to read perms on directory %s",DirBase);
+         return PAM_PERM_DENIED;
+      }
+      if (FileEntry.st_mode & S_ISGID)
+      {
+         if (chmod(dest,0777 & (~UMask)) != 0 ||
+             chown(dest,pwd->pw_uid,FileEntry.st_gid) != 0)
+         {
+            _log_err(LOG_DEBUG, "unable to change perms on directory %s",dest);
+            return PAM_PERM_DENIED;
+         }
+      }
+      else
+      {
+         if (chmod(dest,0777 & (~UMask)) != 0 ||
+             chown(dest,pwd->pw_uid,pwd->pw_gid) != 0)
+         {
+            _log_err(LOG_DEBUG, "unable to change perms on directory %s",dest);
+	    return PAM_PERM_DENIED;
+	 }
+      }
+      free(FilePath);
+   }
+   /* If this is a skel directory, keep all permissions of original directory */
+   /* if SGID is set, keep group ownership of original file */
+   else
    {
-      _log_err(LOG_DEBUG, "unable to change perms on directory %s",dest);
-      return PAM_PERM_DENIED;
+      if (stat(source,&FileEntry) != 0)
+      {
+         _log_err(LOG_DEBUG, "unable to read perms on directory %s",dest);
+         return PAM_PERM_DENIED;
+      }
+      if (FileEntry.st_mode & S_ISGID)
+      {
+         if (chmod(dest,FileEntry.st_mode) != 0 ||
+             chown(dest,pwd->pw_uid,FileEntry.st_gid) != 0)
+         {
+            _log_err(LOG_DEBUG, "unable to change perms on directory %s",dest);
+            return PAM_PERM_DENIED;
+         }
+      }
+      else
+      {
+         if (chmod(dest,FileEntry.st_mode) != 0 ||
+	     chown(dest,pwd->pw_uid,pwd->pw_gid) != 0)
+	 {
+	    _log_err(LOG_DEBUG, "unable to change perms on directory %s",dest);
+	    return PAM_PERM_DENIED;
+	 }
+      }
    }
-
+      
    /* See if we need to copy the skel dir over. */
    if ((source == NULL) || (strlen(source) == 0))
    {
@@ -250,7 +311,7 @@
             {
                if (lchown(newdest,pwd->pw_uid,pwd->pw_gid) != 0)
                {
-                   _log_err(LOG_DEBUG, "unable to chang perms on link %s",
+                   _log_err(LOG_DEBUG, "unable to change perms on link %s",
                             newdest);
                    return PAM_PERM_DENIED;
                }
@@ -274,6 +335,10 @@
       }
       stat(newsource,&St);
 
+      FilePath=strdup(newsource);
+      snprintf(DirBase, sizeof(DirBase), "%s", dirname(FilePath));
+      stat(DirBase,&FileEntry);
+      
       /* Open the dest file */
       if ((DestFd = open(newdest,O_WRONLY | O_TRUNC | O_CREAT,0600)) < 0)
       {
@@ -282,18 +347,34 @@
 	 return PAM_PERM_DENIED;
       }
 
-      /* Set the proper ownership and permissions for the module. We make
-       	 the file a+w and then mask it with the set mask. This preseves
-       	 execute bits */
-      if (fchmod(DestFd,(St.st_mode | 0222) & (~UMask)) != 0 ||
-	  fchown(DestFd,pwd->pw_uid,pwd->pw_gid) != 0)
-      {
-         close(SrcFd);
-         close(DestFd);
-         _log_err(LOG_DEBUG, "unable to chang perms on copy %s",newdest);
-	 return PAM_PERM_DENIED;
+      /* Check for SGID on parent directory
+       * Always keep original permissions of file
+       * excluding SUID, SGID, sticky */
+         
+      /* If SGID is set, set group to group of parent directory */
+      if (FileEntry.st_mode & S_ISGID)
+      {
+         if (fchmod(DestFd,(St.st_mode & 0777)) != 0 ||
+	     fchown(DestFd,pwd->pw_uid,FileEntry.st_gid) != 0)
+         {
+            close(SrcFd);
+            close(DestFd);
+            _log_err(LOG_DEBUG, "unable to change perms on copy %s",newdest);
+	    return PAM_PERM_DENIED;
+         }
       }
-
+      else
+      {
+         if (fchmod(DestFd,(St.st_mode & 0777)) != 0 ||
+	     fchown(DestFd,pwd->pw_uid,pwd->pw_gid) != 0)
+         {
+            close(SrcFd);
+            close(DestFd);
+            _log_err(LOG_DEBUG, "unable to change perms on copy %s",newdest);
+	    return PAM_PERM_DENIED;
+         }
+      }
+      
       /* Copy the file */
       do
       {
@@ -309,6 +390,8 @@
       while (Res != 0);
       close(SrcFd);
       close(DestFd);
+      
+      free(FilePath);
    }
 
    return PAM_SUCCESS;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index] []