From 7b14630ef39e71f603aeca0c47edf2f384717176 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 19 Jan 2009 09:09:15 +0000 Subject: [PATCH] Relevant BUGIDs: rhbz#476784 Purpose of commit: new feature Commit summary: --------------- 2009-01-19 Tomas Mraz * modules/pam_mkhomedir/Makefile.am: Add mkhomedir_helper. * modules/pam_mkhomedir/mkhomedir_helper.8.xml: New file. Manual page for mkhomedir_helper. * modules/pam_mkhomedir/mkhomedir_helper.c: New file. Source for mkhomedir_helper. Most of the code moved from pam_mkhomedir.c. * modules/pam_mkhomedir/pam_mkhomedir.c (_pam_parse): Do not convert umask to integer. (rec_mkdir): Moved to mkhomedir_helper.c. (create_homedir): Just exec the helper. (pam_sm_open_session): Improve logging. --- ChangeLog | 13 + modules/pam_mkhomedir/Makefile.am | 12 +- modules/pam_mkhomedir/mkhomedir_helper.8.xml | 78 ++++ modules/pam_mkhomedir/mkhomedir_helper.c | 422 +++++++++++++++++++ modules/pam_mkhomedir/pam_mkhomedir.c | 421 ++++-------------- 5 files changed, 603 insertions(+), 343 deletions(-) create mode 100644 modules/pam_mkhomedir/mkhomedir_helper.8.xml create mode 100644 modules/pam_mkhomedir/mkhomedir_helper.c diff --git a/ChangeLog b/ChangeLog index c083f341..a00752cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2009-01-19 Tomas Mraz + + * modules/pam_mkhomedir/Makefile.am: Add mkhomedir_helper. + * modules/pam_mkhomedir/mkhomedir_helper.8.xml: New file. Manual page + for mkhomedir_helper. + * modules/pam_mkhomedir/mkhomedir_helper.c: New file. Source + for mkhomedir_helper. Most of the code moved from pam_mkhomedir.c. + * modules/pam_mkhomedir/pam_mkhomedir.c (_pam_parse): Do not convert umask + to integer. + (rec_mkdir): Moved to mkhomedir_helper.c. + (create_homedir): Just exec the helper. + (pam_sm_open_session): Improve logging. + 2009-01-19 Daniel Cabrera * po/es.po: Updated translations. diff --git a/modules/pam_mkhomedir/Makefile.am b/modules/pam_mkhomedir/Makefile.am index 7ed3a9f0..42031472 100644 --- a/modules/pam_mkhomedir/Makefile.am +++ b/modules/pam_mkhomedir/Makefile.am @@ -1,21 +1,23 @@ # # Copyright (c) 2005, 2006 Thorsten Kukuk +# Copyright (c) 2008 Red Hat, Inc. # CLEANFILES = *~ EXTRA_DIST = README $(MANS) $(XMLS) tst-pam_mkhomedir -man_MANS = pam_mkhomedir.8 +man_MANS = pam_mkhomedir.8 mkhomedir_helper.8 -XMLS = README.xml pam_mkhomedir.8.xml +XMLS = README.xml pam_mkhomedir.8.xml mkhomedir_helper.8.xml TESTS = tst-pam_mkhomedir securelibdir = $(SECUREDIR) secureconfdir = $(SCONFIGDIR) -AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include +AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ + -DMKHOMEDIR_HELPER=\"$(sbindir)/mkhomedir_helper\" AM_LDFLAGS = -no-undefined -avoid-version -module if HAVE_VERSIONING AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map @@ -25,6 +27,10 @@ securelib_LTLIBRARIES = pam_mkhomedir.la pam_mkhomedir_la_SOURCES = pam_mkhomedir.c pam_mkhomedir_la_LIBADD = -L$(top_builddir)/libpam -lpam +sbin_PROGRAMS = mkhomedir_helper +mkhomedir_helper_SOURCES = mkhomedir_helper.c +mkhomedir_helper_LDADD = -L$(top_builddir)/libpam -lpam + if ENABLE_REGENERATE_MAN noinst_DATA = README README: pam_mkhomedir.8.xml diff --git a/modules/pam_mkhomedir/mkhomedir_helper.8.xml b/modules/pam_mkhomedir/mkhomedir_helper.8.xml new file mode 100644 index 00000000..c834eddd --- /dev/null +++ b/modules/pam_mkhomedir/mkhomedir_helper.8.xml @@ -0,0 +1,78 @@ + + + + + + + mkhomedir_helper + 8 + Linux-PAM Manual + + + + mkhomedir_helper + Helper binary that creates home directories + + + + + mkhomedir_helper + + user + + + umask + + path-to-skel + + + + + + + + DESCRIPTION + + + mkhomedir_helper is a helper program for the + pam_mkhomedir module that creates home directories + and populates them with contents of the specified skel directory. + + + + The default value of umask is 0022 and the + default value of path-to-skel is + /etc/skel. + + + + The helper is separated from the module to not require direct access from + login SELinux domains to the contents of user home directories. The + SELinux domain transition happens when the module is executing the + mkhomedir_helper. + + + + The helper never touches home directories if they already exist. + + + + + SEE ALSO + + + pam_mkhomedir8 + + + + + + AUTHOR + + Written by Tomas Mraz based on the code originally in + pam_mkhomedir module. + + + + diff --git a/modules/pam_mkhomedir/mkhomedir_helper.c b/modules/pam_mkhomedir/mkhomedir_helper.c new file mode 100644 index 00000000..550a1354 --- /dev/null +++ b/modules/pam_mkhomedir/mkhomedir_helper.c @@ -0,0 +1,422 @@ +/* mkhomedir_helper - helper for pam_mkhomedir module + + Released under the GNU LGPL version 2 or later + + Copyright (c) Red Hat, Inc., 2009 + Originally written by Jason Gunthorpe Feb 1999 + Structure taken from pam_lastlogin by Andrew Morgan + 1996 + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static unsigned long u_mask = 0022; +static char skeldir[BUFSIZ] = "/etc/skel"; + +static int +rec_mkdir(const char *dir, mode_t mode) +{ + char *cp; + char *parent = strdup(dir); + + if (parent == NULL) + return 1; + + cp = strrchr(parent, '/'); + + if (cp != NULL && cp != parent) + { + struct stat st; + + *cp++ = '\0'; + if (stat(parent, &st) == -1 && errno == ENOENT) + if (rec_mkdir(parent, mode) != 0) + { + free(parent); + return 1; + } + } + + free(parent); + + if (mkdir(dir, mode) != 0 && errno != EEXIST) + return 1; + + return 0; +} + +/* Do the actual work of creating a home dir */ +static int +create_homedir(const struct passwd *pwd, + const char *source, const char *dest) +{ + char remark[BUFSIZ]; + DIR *d; + struct dirent *dent; + int retval = PAM_SESSION_ERR; + + /* Create the new directory */ + if (rec_mkdir(dest, 0755) != 0) + { + pam_syslog(NULL, LOG_ERR, "unable to create directory %s: %m", dest); + return PAM_PERM_DENIED; + } + + /* See if we need to copy the skel dir over. */ + if ((source == NULL) || (strlen(source) == 0)) + { + retval = PAM_SUCCESS; + goto go_out; + } + + /* Scan the directory */ + d = opendir(source); + if (d == NULL) + { + pam_syslog(NULL, LOG_DEBUG, "unable to read directory %s: %m", source); + retval = PAM_PERM_DENIED; + goto go_out; + } + + for (dent = readdir(d); dent != NULL; dent = readdir(d)) + { + int srcfd; + int destfd; + int res; + struct stat st; +#ifndef PATH_MAX + char *newsource = NULL, *newdest = NULL; + /* track length of buffers */ + int nslen = 0, ndlen = 0; + int slen = strlen(source), dlen = strlen(dest); +#else + char newsource[PATH_MAX], newdest[PATH_MAX]; +#endif + + /* Skip some files.. */ + if (strcmp(dent->d_name,".") == 0 || + strcmp(dent->d_name,"..") == 0) + continue; + + /* Determine what kind of file it is. */ +#ifndef PATH_MAX + nslen = slen + strlen(dent->d_name) + 2; + + if (nslen <= 0) + { + retval = PAM_BUF_ERR; + goto go_out; + } + + if ((newsource = malloc(nslen)) == NULL) + { + retval = PAM_BUF_ERR; + goto go_out; + } + + sprintf(newsource, "%s/%s", source, dent->d_name); +#else + snprintf(newsource, sizeof(newsource), "%s/%s", source, dent->d_name); +#endif + + if (lstat(newsource, &st) != 0) +#ifndef PATH_MAX + { + free(newsource); + newsource = NULL; + continue; + } +#else + continue; +#endif + + + /* We'll need the new file's name. */ +#ifndef PATH_MAX + ndlen = dlen + strlen(dent->d_name)+2; + + if (ndlen <= 0) + { + retval = PAM_BUF_ERR; + goto go_out; + } + + if ((newdest = malloc(ndlen)) == NULL) + { + free (newsource); + retval = PAM_BUF_ERR; + goto go_out; + } + + sprintf (newdest, "%s/%s", dest, dent->d_name); +#else + snprintf (newdest, sizeof (newdest), "%s/%s", dest, dent->d_name); +#endif + + /* If it's a directory, recurse. */ + if (S_ISDIR(st.st_mode)) + { + retval = create_homedir(pwd, newsource, newdest); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + + if (retval != PAM_SUCCESS) + { + closedir(d); + goto go_out; + } + continue; + } + + /* If it's a symlink, create a new link. */ + if (S_ISLNK(st.st_mode)) + { + int pointedlen = 0; +#ifndef PATH_MAX + char *pointed = NULL; + { + int size = 100; + + while (1) { + pointed = malloc(size); + if (pointed == NULL) { + free(newsource); + free(newdest); + return PAM_BUF_ERR; + } + pointedlen = readlink(newsource, pointed, size); + if (pointedlen < 0) break; + if (pointedlen < size) break; + free(pointed); + size *= 2; + } + } + if (pointedlen < 0) + free(pointed); + else + pointed[pointedlen] = 0; +#else + char pointed[PATH_MAX]; + memset(pointed, 0, sizeof(pointed)); + + pointedlen = readlink(newsource, pointed, sizeof(pointed) - 1); +#endif + + if (pointedlen >= 0) { + if(symlink(pointed, newdest) == 0) + { + if (lchown(newdest, pwd->pw_uid, pwd->pw_gid) != 0) + { + pam_syslog(NULL, LOG_DEBUG, + "unable to change perms on link %s: %m", newdest); + closedir(d); +#ifndef PATH_MAX + free(pointed); + free(newsource); + free(newdest); +#endif + return PAM_PERM_DENIED; + } + } +#ifndef PATH_MAX + free(pointed); +#endif + } +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + 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)) + { +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + continue; + } + + /* Open the source file */ + if ((srcfd = open(newsource, O_RDONLY)) < 0 || fstat(srcfd, &st) != 0) + { + pam_syslog(NULL, LOG_DEBUG, + "unable to open src file %s: %m", newsource); + closedir(d); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + + return PAM_PERM_DENIED; + } + if (stat(newsource, &st) != 0) + { + pam_syslog(NULL, LOG_DEBUG, "unable to stat src file %s: %m", + newsource); + close(srcfd); + closedir(d); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + + return PAM_PERM_DENIED; + } + + /* Open the dest file */ + if ((destfd = open(newdest, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) + { + pam_syslog(NULL, LOG_DEBUG, + "unable to open dest file %s: %m", newdest); + close(srcfd); + closedir(d); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + 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) & (~u_mask)) != 0 || + fchown(destfd, pwd->pw_uid, pwd->pw_gid) != 0) + { + pam_syslog(NULL, LOG_DEBUG, + "unable to change perms on copy %s: %m", newdest); + close(srcfd); + close(destfd); + closedir(d); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + + return PAM_PERM_DENIED; + } + + /* Copy the file */ + do + { + res = pam_modutil_read(srcfd, remark, sizeof(remark)); + + if (res == 0) + continue; + + if (res > 0) { + if (pam_modutil_write(destfd, remark, res) == res) + continue; + } + + /* If we get here, pam_modutil_read returned a -1 or + pam_modutil_write returned something unexpected. */ + pam_syslog(NULL, LOG_DEBUG, "unable to perform IO: %m"); + close(srcfd); + close(destfd); + closedir(d); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + + return PAM_PERM_DENIED; + } + while (res != 0); + close(srcfd); + close(destfd); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + + } + closedir(d); + + retval = PAM_SUCCESS; + + go_out: + + if (chmod(dest, 0777 & (~u_mask)) != 0 || + chown(dest, pwd->pw_uid, pwd->pw_gid) != 0) + { + pam_syslog(NULL, LOG_DEBUG, + "unable to change perms on directory %s: %m", dest); + return PAM_PERM_DENIED; + } + + return retval; +} + +int +main(int argc, char *argv[]) +{ + const struct passwd *pwd; + struct stat st; + + if (argc < 2) { + fprintf(stderr, "Usage: %s [ []]\n", argv[0]); + return PAM_SESSION_ERR; + } + + pwd = getpwnam(argv[1]); + if (pwd == NULL) { + pam_syslog(NULL, LOG_ERR, "User unknown."); + return PAM_CRED_INSUFFICIENT; + } + + if (argc >= 3) { + char *eptr; + errno = 0; + u_mask = strtoul(argv[2], &eptr, 0); + if (errno != 0 || *eptr != '\0') { + pam_syslog(NULL, LOG_ERR, "Bogus umask value %s", argv[2]); + return PAM_SESSION_ERR; + } + } + + if (argc >= 4) { + if (strlen(argv[3]) >= sizeof(skeldir)) { + pam_syslog(NULL, LOG_ERR, "Too long skeldir path."); + return PAM_SESSION_ERR; + } + strcpy(skeldir, argv[3]); + } + + /* Stat the home directory, if something exists then we assume it is + correct and return a success */ + if (stat(pwd->pw_dir, &st) == 0) + return PAM_SUCCESS; + + return create_homedir(pwd, skeldir, pwd->pw_dir); +} + diff --git a/modules/pam_mkhomedir/pam_mkhomedir.c b/modules/pam_mkhomedir/pam_mkhomedir.c index 44b092c1..a0c389c5 100644 --- a/modules/pam_mkhomedir/pam_mkhomedir.c +++ b/modules/pam_mkhomedir/pam_mkhomedir.c @@ -22,6 +22,7 @@ password required pam_unix.so Released under the GNU LGPL version 2 or later + Copyright (c) Red Hat, Inc. 2009 Originally written by Jason Gunthorpe Feb 1999 Structure taken from pam_lastlogin by Andrew Morgan 1996 @@ -29,18 +30,19 @@ #include "config.h" -#include #include #include -#include +#include +#include +#include #include #include #include #include #include #include -#include #include +#include /* * here, we make a definition for the externally accessible function @@ -56,12 +58,13 @@ #include #include +#define MAX_FD_NO 10000 /* argument parsing */ #define MKHOMEDIR_DEBUG 020 /* be verbose about things */ #define MKHOMEDIR_QUIET 040 /* keep quiet about things */ -static unsigned int UMask = 0022; +static char UMask[16] = "0022"; static char SkelDir[BUFSIZ] = "/etc/skel"; /* THIS MODULE IS NOT THREAD SAFE */ static int @@ -81,7 +84,8 @@ _pam_parse (const pam_handle_t *pamh, int flags, int argc, const char **argv) } else if (!strcmp(*argv, "debug")) { ctrl |= MKHOMEDIR_DEBUG; } else if (!strncmp(*argv,"umask=",6)) { - UMask = strtol(*argv+6,0,0); + strncpy(SkelDir,*argv+6,sizeof(UMask)); + UMask[sizeof(UMask)-1] = '\0'; } else if (!strncmp(*argv,"skel=",5)) { strncpy(SkelDir,*argv+5,sizeof(SkelDir)); SkelDir[sizeof(SkelDir)-1] = '\0'; @@ -94,357 +98,88 @@ _pam_parse (const pam_handle_t *pamh, int flags, int argc, const char **argv) return ctrl; } -static int -rec_mkdir (const char *dir, mode_t mode) -{ - char *cp; - char *parent = strdup (dir); - - if (parent == NULL) - return 1; - - cp = strrchr (parent, '/'); - - if (cp != NULL && cp != parent) - { - struct stat st; - - *cp++ = '\0'; - if (stat (parent, &st) == -1 && errno == ENOENT) - if (rec_mkdir (parent, mode) != 0) - { - free (parent); - return 1; - } - } - - free (parent); - - if (mkdir (dir, mode) != 0 && errno != EEXIST) - return 1; - - return 0; -} - /* Do the actual work of creating a home dir */ static int -create_homedir (pam_handle_t * pamh, int ctrl, - const struct passwd *pwd, - const char *source, const char *dest) +create_homedir (pam_handle_t *pamh, int ctrl, + const struct passwd *pwd) { - char remark[BUFSIZ]; - DIR *D; - struct dirent *Dir; - int retval = PAM_AUTH_ERR; + int retval, child; + void (*sighandler)(int) = NULL; /* Mention what is happening, if the notification fails that is OK */ - if ((ctrl & MKHOMEDIR_QUIET) != MKHOMEDIR_QUIET) - pam_info(pamh, _("Creating directory '%s'."), dest); - - /* Create the new directory */ - if (rec_mkdir (dest,0755) != 0) - { - pam_error(pamh, _("Unable to create directory %s: %m"), dest); - pam_syslog(pamh, LOG_ERR, "unable to create directory %s: %m", dest); - return PAM_PERM_DENIED; - } - - /* See if we need to copy the skel dir over. */ - if ((source == NULL) || (strlen(source) == 0)) - { - retval = PAM_SUCCESS; - goto go_out; - } - - /* Scan the directory */ - D = opendir (source); - if (D == 0) - { - pam_syslog(pamh, LOG_DEBUG, "unable to read directory %s: %m", source); - retval = PAM_PERM_DENIED; - goto go_out; - } - - for (Dir = readdir(D); Dir != 0; Dir = readdir(D)) - { - int SrcFd; - int DestFd; - int Res; - struct stat St; -#ifndef PATH_MAX - char *newsource = NULL, *newdest = NULL; - /* track length of buffers */ - int nslen = 0, ndlen = 0; - int slen = strlen(source), dlen = strlen(dest); -#else - char newsource[PATH_MAX], newdest[PATH_MAX]; -#endif - - /* Skip some files.. */ - if (strcmp(Dir->d_name,".") == 0 || - strcmp(Dir->d_name,"..") == 0) - continue; - - /* Determine what kind of file it is. */ -#ifndef PATH_MAX - nslen = slen + strlen(Dir->d_name) + 2; - - if (nslen <= 0) - { - retval = PAM_BUF_ERR; - goto go_out; - } - - if ((newsource = malloc (nslen)) == NULL) - { - retval = PAM_BUF_ERR; - goto go_out; - } + if (!(ctrl & MKHOMEDIR_QUIET)) + pam_info(pamh, _("Creating directory '%s'."), pwd->pw_dir); - sprintf(newsource, "%s/%s", source, Dir->d_name); -#else - snprintf(newsource,sizeof(newsource),"%s/%s",source,Dir->d_name); -#endif - if (lstat(newsource,&St) != 0) -#ifndef PATH_MAX - { - free(newsource); - newsource = NULL; - continue; - } -#else - continue; -#endif + D(("called.")); + /* + * This code arranges that the demise of the child does not cause + * the application to receive a signal it is not expecting - which + * may kill the application or worse. + */ + sighandler = signal(SIGCHLD, SIG_DFL); - /* We'll need the new file's name. */ -#ifndef PATH_MAX - ndlen = dlen + strlen(Dir->d_name)+2; + if (ctrl & MKHOMEDIR_DEBUG) { + pam_syslog(pamh, LOG_DEBUG, "Executing mkhomedir_helper."); + } - if (ndlen <= 0) - { - retval = PAM_BUF_ERR; - goto go_out; + /* fork */ + child = fork(); + if (child == 0) { + int i; + struct rlimit rlim; + static char *envp[] = { NULL }; + char *args[] = { NULL, NULL, NULL, NULL, NULL }; + + if (getrlimit(RLIMIT_NOFILE, &rlim)==0) { + if (rlim.rlim_max >= MAX_FD_NO) + rlim.rlim_max = MAX_FD_NO; + for (i=0; i < (int)rlim.rlim_max; i++) { + close(i); + } } - if ((newdest = malloc(ndlen)) == NULL) - { - free (newsource); - retval = PAM_BUF_ERR; - goto go_out; + /* exec the mkhomedir helper */ + args[0] = x_strdup(MKHOMEDIR_HELPER); + args[1] = pwd->pw_name; + args[2] = UMask; + args[3] = SkelDir; + + execve(MKHOMEDIR_HELPER, args, envp); + + /* should not get here: exit with error */ + D(("helper binary is not available")); + exit(PAM_SYSTEM_ERR); + } else if (child > 0) { + int rc; + while ((rc=waitpid(child, &retval, 0)) < 0 && errno == EINTR); + if (rc < 0) { + pam_syslog(pamh, LOG_ERR, "waitpid failed: %m"); + retval = PAM_SYSTEM_ERR; + } else { + retval = WEXITSTATUS(retval); } - - sprintf (newdest, "%s/%s", dest, Dir->d_name); -#else - snprintf (newdest,sizeof (newdest),"%s/%s",dest,Dir->d_name); -#endif - - /* If it's a directory, recurse. */ - if (S_ISDIR(St.st_mode)) - { - retval = create_homedir (pamh, ctrl, pwd, newsource, newdest); - -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - - if (retval != PAM_SUCCESS) - { - closedir(D); - goto go_out; - } - continue; - } - - /* If it's a symlink, create a new link. */ - if (S_ISLNK(St.st_mode)) - { - int pointedlen = 0; -#ifndef PATH_MAX - char *pointed = NULL; - { - int size = 100; - - while (1) { - pointed = (char *) malloc(size); - if ( ! pointed ) { - free(newsource); - free(newdest); - return PAM_BUF_ERR; - } - pointedlen = readlink (newsource, pointed, size); - if ( pointedlen < 0 ) break; - if ( pointedlen < size ) break; - free (pointed); - size *= 2; - } - } - if ( pointedlen < 0 ) - free(pointed); - else - pointed[pointedlen] = 0; -#else - char pointed[PATH_MAX]; - memset(pointed, 0, sizeof(pointed)); - - pointedlen = readlink(newsource, pointed, sizeof(pointed) - 1); -#endif - - if ( pointedlen >= 0 ) { - if(symlink(pointed, newdest) == 0) - { - if (lchown(newdest,pwd->pw_uid,pwd->pw_gid) != 0) - { - pam_syslog(pamh, LOG_DEBUG, - "unable to change perms on link %s: %m", newdest); - closedir(D); -#ifndef PATH_MAX - free(pointed); - free(newsource); - free(newdest); -#endif - return PAM_PERM_DENIED; - } - } -#ifndef PATH_MAX - free(pointed); -#endif - } -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - 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)) - { -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - continue; - } - - /* Open the source file */ - if ((SrcFd = open(newsource,O_RDONLY)) < 0 || fstat(SrcFd,&St) != 0) - { - pam_syslog(pamh, LOG_DEBUG, - "unable to open src file %s: %m", newsource); - closedir(D); - -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - - return PAM_PERM_DENIED; - } - if (stat(newsource,&St) != 0) - { - pam_syslog(pamh, LOG_DEBUG, "unable to stat src file %s: %m", - newsource); - close(SrcFd); - closedir(D); - -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - - return PAM_PERM_DENIED; - } - - /* Open the dest file */ - if ((DestFd = open(newdest,O_WRONLY | O_TRUNC | O_CREAT,0600)) < 0) - { - pam_syslog(pamh, LOG_DEBUG, - "unable to open dest file %s: %m", newdest); - close(SrcFd); - closedir(D); - -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - 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) - { - pam_syslog(pamh, LOG_DEBUG, - "unable to change perms on copy %s: %m", newdest); - close(SrcFd); - close(DestFd); - closedir(D); - -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - - return PAM_PERM_DENIED; - } - - /* Copy the file */ - do - { - Res = pam_modutil_read(SrcFd,remark,sizeof(remark)); - - if (Res == 0) - continue; - - if (Res > 0) { - if (pam_modutil_write(DestFd,remark,Res) == Res) - continue; - } - - /* If we get here, pam_modutil_read returned a -1 or - pam_modutil_write returned something unexpected. */ - pam_syslog(pamh, LOG_DEBUG, "unable to perform IO: %m"); - close(SrcFd); - close(DestFd); - closedir(D); - -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - - return PAM_PERM_DENIED; - } - while (Res != 0); - close(SrcFd); - close(DestFd); - -#ifndef PATH_MAX - free(newsource); newsource = NULL; - free(newdest); newdest = NULL; -#endif - + } else { + D(("fork failed")); + pam_syslog(pamh, LOG_ERR, "fork failed: %m"); + retval = PAM_SYSTEM_ERR; } - closedir(D); - retval = PAM_SUCCESS; + if (sighandler != SIG_ERR) { + (void) signal(SIGCHLD, sighandler); /* restore old signal handler */ + } - go_out: + if (ctrl & MKHOMEDIR_DEBUG) { + pam_syslog(pamh, LOG_DEBUG, "mkhomedir_helper returned %d", retval); + } - if (chmod(dest,0777 & (~UMask)) != 0 || - chown(dest,pwd->pw_uid,pwd->pw_gid) != 0) - { - pam_syslog(pamh, LOG_DEBUG, - "unable to change perms on directory %s: %m", dest); - return PAM_PERM_DENIED; + if (retval != PAM_SUCCESS && !(ctrl & MKHOMEDIR_QUIET)) { + pam_error(pamh, _("Unable to create and initialize directory '%s'."), + pwd->pw_dir); } + D(("returning %d", retval)); return retval; } @@ -466,7 +201,7 @@ pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, retval = pam_get_item(pamh, PAM_USER, &user); if (retval != PAM_SUCCESS || user == NULL || *(const char *)user == '\0') { - pam_syslog(pamh, LOG_NOTICE, "user unknown"); + pam_syslog(pamh, LOG_NOTICE, "Cannot obtain the user name."); return PAM_USER_UNKNOWN; } @@ -474,16 +209,22 @@ pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, pwd = pam_modutil_getpwnam (pamh, user); if (pwd == NULL) { + pam_syslog(pamh, LOG_NOTICE, "User unknown."); D(("couldn't identify user %s", user)); return PAM_CRED_INSUFFICIENT; } /* Stat the home directory, if something exists then we assume it is correct and return a success*/ - if (stat(pwd->pw_dir,&St) == 0) + if (stat(pwd->pw_dir, &St) == 0) { + if (ctrl & MKHOMEDIR_DEBUG) { + pam_syslog(pamh, LOG_DEBUG, "Home directory %s already exists.", + pwd->pw_dir); + } return PAM_SUCCESS; + } - return create_homedir(pamh,ctrl,pwd,SkelDir,pwd->pw_dir); + return create_homedir(pamh, ctrl, pwd); } /* Ignore */ -- 2.40.0