X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=modules%2Fpam_mkhomedir%2Fpam_mkhomedir.c;h=6814056f007682792617a1d7a066cd057d9766a9;hb=31668ed6f0bf6d2b1c6d621cca42aee0daf23a65;hp=ec6bd46d6dfc71b5d5b0f956b01a75762415a7e7;hpb=47c5c31a6ceb6abe8b406eb74d87aa429c3b93ea;p=linux-pam diff --git a/modules/pam_mkhomedir/pam_mkhomedir.c b/modules/pam_mkhomedir/pam_mkhomedir.c index ec6bd46d..6814056f 100644 --- a/modules/pam_mkhomedir/pam_mkhomedir.c +++ b/modules/pam_mkhomedir/pam_mkhomedir.c @@ -4,10 +4,10 @@ when the session begins. This allows users to be present in central database (such as nis, kerb or ldap) without using a distributed file system or pre-creating a large number of directories. - + 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 @@ -19,11 +19,11 @@ session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 session required pam_pwdb.so session optional pam_lastlog.so - password required pam_pwdb.so - + password required pam_pwdb.so + Released under the GNU LGPL version 2 or later Originally written by Jason Gunthorpe Feb 1999 - Structure taken from pam_lastlogin by Andrew Morgan + Structure taken from pam_lastlogin by Andrew Morgan 1996 */ @@ -51,6 +51,8 @@ #include #include +#include + /* argument parsing */ #define MKHOMEDIR_DEBUG 020 /* keep quiet about things */ @@ -98,8 +100,8 @@ static int _pam_parse(int flags, int argc, const char **argv) return ctrl; } -/* This common function is used to send a message to the applications - conversion function. Our only use is to ask the application to print +/* This common function is used to send a message to the applications + conversion function. Our only use is to ask the application to print an informative message that we are creating a home directory */ static int converse(pam_handle_t * pamh, int ctrl, int nargs ,struct pam_message **message @@ -111,7 +113,7 @@ static int converse(pam_handle_t * pamh, int ctrl, int nargs D(("begin to converse")); retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - if (retval == PAM_SUCCESS) + if (retval == PAM_SUCCESS && conv) { retval = conv->conv(nargs, (const struct pam_message **) message @@ -130,6 +132,8 @@ static int converse(pam_handle_t * pamh, int ctrl, int nargs { _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" ,pam_strerror(pamh, retval)); + if (retval == PAM_SUCCESS) + retval = PAM_BAD_ITEM; /* conv was NULL */ } D(("ready to return from module conversation")); @@ -171,104 +175,121 @@ static int make_remark(pam_handle_t * pamh, int ctrl, const char *remark) /* Do the actual work of creating a home dir */ static int create_homedir(pam_handle_t * pamh, int ctrl, - const struct passwd *pwd) + const struct passwd *pwd, + const char *source, const char *dest) { - char *remark; + char remark[BUFSIZ]; DIR *D; struct dirent *Dir; - - /* Some scratch space */ - remark = malloc(BUFSIZ); - if (remark == NULL) - { - D(("no memory for last login remark")); - return PAM_BUF_ERR; - } /* Mention what is happening, if the notification fails that is OK */ - if (snprintf(remark,BUFSIZ,"Creating home directory '%s'.", - pwd->pw_dir) == -1) + if (snprintf(remark,sizeof(remark),"Creating directory '%s'.", dest) == -1) return PAM_PERM_DENIED; - + make_remark(pamh, ctrl, remark); - /* Crete the home directory */ - if (mkdir(pwd->pw_dir,0700) != 0) + /* Create the new directory */ + if (mkdir(dest,0700) != 0) { - free(remark); - _log_err(LOG_DEBUG, "unable to create home directory %s",pwd->pw_dir); + _log_err(LOG_DEBUG, "unable to create directory %s",dest); return PAM_PERM_DENIED; - } - if (chmod(pwd->pw_dir,0777 & (~UMask)) != 0 || - chown(pwd->pw_dir,pwd->pw_uid,pwd->pw_gid) != 0) + } + if (chmod(dest,0777 & (~UMask)) != 0 || + chown(dest,pwd->pw_uid,pwd->pw_gid) != 0) { - free(remark); - _log_err(LOG_DEBUG, "unable to chance perms on home directory %s",pwd->pw_dir); + _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 (SkelDir[0] == 0) + if ((source == NULL) || (strlen(source) == 0)) { - free(remark); return PAM_SUCCESS; } /* Scan the directory */ - D = opendir(SkelDir); + D = opendir(source); if (D == 0) { - free(remark); - _log_err(LOG_DEBUG, "unable to read directory %s",SkelDir); + _log_err(LOG_DEBUG, "unable to read directory %s",source); return PAM_PERM_DENIED; } - + for (Dir = readdir(D); Dir != 0; Dir = readdir(D)) - { + { int SrcFd; int DestFd; int Res; struct stat St; - + char newsource[PATH_MAX], newdest[PATH_MAX]; + /* Skip some files.. */ if (strcmp(Dir->d_name,".") == 0 || strcmp(Dir->d_name,"..") == 0) continue; - - /* Check if it is a directory */ - snprintf(remark,BUFSIZ,"%s/%s",SkelDir,Dir->d_name); - if (stat(remark,&St) != 0) - continue; + + /* Determine what kind of file it is. */ + snprintf(newsource,sizeof(newsource),"%s/%s",source,Dir->d_name); + if (lstat(newsource,&St) != 0) + continue; + + /* We'll need the new file's name. */ + snprintf(newdest,sizeof(newdest),"%s/%s",dest,Dir->d_name); + + /* If it's a directory, recurse. */ if (S_ISDIR(St.st_mode)) { - snprintf(remark,BUFSIZ,"%s/%s",pwd->pw_dir,Dir->d_name); - if (mkdir(remark,(St.st_mode | 0222) & (~UMask)) != 0 || - chmod(remark,(St.st_mode | 0222) & (~UMask)) != 0 || - chown(remark,pwd->pw_uid,pwd->pw_gid) != 0) - { - free(remark); - _log_err(LOG_DEBUG, "unable to change perms on copy %s",remark); - return PAM_PERM_DENIED; - } - continue; + int retval = create_homedir(pamh, ctrl, pwd, newsource, newdest); + if (retval != PAM_SUCCESS) { + closedir(D); + return retval; + } + continue; + } + + /* If it's a symlink, create a new link. */ + if (S_ISLNK(St.st_mode)) + { + char pointed[PATH_MAX]; + memset(pointed, 0, sizeof(pointed)); + if(readlink(newsource, pointed, sizeof(pointed) - 1) != -1) + { + if(symlink(pointed, newdest) == 0) + { + if (lchown(newdest,pwd->pw_uid,pwd->pw_gid) != 0) + { + closedir(D); + _log_err(LOG_DEBUG, "unable to chang perms on link %s", + newdest); + return PAM_PERM_DENIED; + } + } + } + continue; + } + + /* If it's not a regular file, it's probably not a good idea to create + * the new device node, FIFO, or whatever it is. */ + if (!S_ISREG(St.st_mode)) + { + continue; } /* Open the source file */ - if ((SrcFd = open(remark,O_RDONLY)) < 0 || fstat(SrcFd,&St) != 0) + if ((SrcFd = open(newsource,O_RDONLY)) < 0 || fstat(SrcFd,&St) != 0) { - free(remark); - _log_err(LOG_DEBUG, "unable to open src file %s",remark); + closedir(D); + _log_err(LOG_DEBUG, "unable to open src file %s",newsource); return PAM_PERM_DENIED; } - stat(remark,&St); - + stat(newsource,&St); + /* Open the dest file */ - snprintf(remark,BUFSIZ,"%s/%s",pwd->pw_dir,Dir->d_name); - if ((DestFd = open(remark,O_WRONLY | O_TRUNC | O_CREAT,0600)) < 0) + if ((DestFd = open(newdest,O_WRONLY | O_TRUNC | O_CREAT,0600)) < 0) { close(SrcFd); - free(remark); - _log_err(LOG_DEBUG, "unable to open dest file %s",remark); + closedir(D); + _log_err(LOG_DEBUG, "unable to open dest file %s",newdest); return PAM_PERM_DENIED; } @@ -278,30 +299,40 @@ static int create_homedir(pam_handle_t * pamh, int ctrl, if (fchmod(DestFd,(St.st_mode | 0222) & (~UMask)) != 0 || fchown(DestFd,pwd->pw_uid,pwd->pw_gid) != 0) { - free(remark); - _log_err(LOG_DEBUG, "unable to chang perms on copy %s",remark); + close(SrcFd); + close(DestFd); + closedir(D); + _log_err(LOG_DEBUG, "unable to chang perms on copy %s",newdest); return PAM_PERM_DENIED; - } - + } + /* Copy the file */ do { - Res = read(SrcFd,remark,BUFSIZ); - if (Res < 0 || write(DestFd,remark,Res) != Res) - { - close(SrcFd); - close(DestFd); - free(remark); - _log_err(LOG_DEBUG, "unable to perform IO"); - return PAM_PERM_DENIED; + Res = _pammodutil_read(SrcFd,remark,sizeof(remark)); + + if (Res == 0) + continue; + + if (Res > 0) { + if (_pammodutil_write(DestFd,remark,Res) == Res) + continue; } + + /* If we get here, pammodutil_read returned a -1 or + _pammodutil_write returned something unexpected. */ + close(SrcFd); + close(DestFd); + closedir(D); + _log_err(LOG_DEBUG, "unable to perform IO"); + return PAM_PERM_DENIED; } while (Res != 0); close(SrcFd); close(DestFd); } - - free(remark); + closedir(D); + return PAM_SUCCESS; } @@ -315,7 +346,7 @@ int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc const char *user; const struct passwd *pwd; struct stat St; - + /* Parse the flag values */ ctrl = _pam_parse(flags, argc, argv); @@ -328,7 +359,7 @@ int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc } /* Get the password entry */ - pwd = getpwnam(user); + pwd = _pammodutil_getpwnam (pamh, user); if (pwd == NULL) { D(("couldn't identify user %s", user)); @@ -340,11 +371,11 @@ int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc if (stat(pwd->pw_dir,&St) == 0) return PAM_SUCCESS; - return create_homedir(pamh,ctrl,pwd); + return create_homedir(pamh,ctrl,pwd,SkelDir,pwd->pw_dir); } /* Ignore */ -PAM_EXTERN +PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc ,const char **argv) {