diff --git a/pam-1.0.90-mkhomedir-helper.patch b/pam-1.0.90-mkhomedir-helper.patch new file mode 100644 index 0000000..46b8534 --- /dev/null +++ b/pam-1.0.90-mkhomedir-helper.patch @@ -0,0 +1,1065 @@ +diff -up /dev/null Linux-PAM-1.0.90/modules/pam_mkhomedir/mkhomedir_helper.c +--- /dev/null 2009-01-09 08:55:49.164063715 +0100 ++++ Linux-PAM-1.0.90/modules/pam_mkhomedir/mkhomedir_helper.c 2009-01-19 10:15:39.000000000 +0100 +@@ -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 -up Linux-PAM-1.0.90/modules/pam_mkhomedir/Makefile.am.mkhomedir-helper Linux-PAM-1.0.90/modules/pam_mkhomedir/Makefile.am +--- Linux-PAM-1.0.90/modules/pam_mkhomedir/Makefile.am.mkhomedir-helper 2007-09-03 09:57:30.000000000 +0200 ++++ Linux-PAM-1.0.90/modules/pam_mkhomedir/Makefile.am 2009-01-19 10:15:39.000000000 +0100 +@@ -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 -up /dev/null Linux-PAM-1.0.90/modules/pam_mkhomedir/mkhomedir_helper.8.xml +--- /dev/null 2009-01-09 08:55:49.164063715 +0100 ++++ Linux-PAM-1.0.90/modules/pam_mkhomedir/mkhomedir_helper.8.xml 2009-01-19 10:15:39.000000000 +0100 +@@ -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 -up Linux-PAM-1.0.90/modules/pam_mkhomedir/pam_mkhomedir.c.mkhomedir-helper Linux-PAM-1.0.90/modules/pam_mkhomedir/pam_mkhomedir.c +--- Linux-PAM-1.0.90/modules/pam_mkhomedir/pam_mkhomedir.c.mkhomedir-helper 2007-06-28 11:00:30.000000000 +0200 ++++ Linux-PAM-1.0.90/modules/pam_mkhomedir/pam_mkhomedir.c 2009-01-19 10:15:39.000000000 +0100 +@@ -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, in + } 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, in + 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); ++ if (!(ctrl & MKHOMEDIR_QUIET)) ++ pam_info(pamh, _("Creating directory '%s'."), pwd->pw_dir); + +- /* 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; +- } ++ D(("called.")); + +- /* 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; +- } +- +- 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 +- +- +- /* We'll need the new file's name. */ +-#ifndef PATH_MAX +- ndlen = dlen + strlen(Dir->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; ++ /* ++ * 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); ++ ++ if (ctrl & MKHOMEDIR_DEBUG) { ++ pam_syslog(pamh, LOG_DEBUG, "Executing mkhomedir_helper."); ++ } ++ ++ /* 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); ++ } + } + +- 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; ++ /* 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); + } +- +- /* 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, + 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, + 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 */ diff --git a/pam.spec b/pam.spec index 70db182..5fccfe2 100644 --- a/pam.spec +++ b/pam.spec @@ -3,7 +3,7 @@ Summary: An extensible library which provides authentication for applications Name: pam Version: 1.0.90 -Release: 1%{?dist} +Release: 2%{?dist} # The library is BSD licensed with option to relicense as GPLv2+ - this option is redundant # as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+, # pam_rhosts_auth module is BSD with advertising @@ -20,6 +20,7 @@ Source9: system-auth.5 Source10: config-util.5 Source11: 90-nproc.conf Patch1: pam-1.0.90-redhat-modules.patch +Patch2: pam-1.0.90-mkhomedir-helper.patch %define _sbindir /sbin %define _moduledir /%{_lib}/security @@ -82,6 +83,7 @@ PAM-aware applications and modules for use with PAM. mv pam-redhat-%{pam_redhat_version}/* modules %patch1 -p1 -b .redhat-modules +%patch2 -p1 -b .mkhomedir-helper autoreconf @@ -217,6 +219,7 @@ fi %attr(4755,root,root) %{_sbindir}/pam_timestamp_check %attr(4755,root,root) %{_sbindir}/unix_chkpwd %attr(0700,root,root) %{_sbindir}/unix_update +%attr(0755,root,root) %{_sbindir}/mkhomedir_helper %if %{_lib} != lib %dir /lib/security %endif @@ -313,6 +316,9 @@ fi %doc doc/adg/*.txt doc/adg/html %changelog +* Mon Jan 19 2009 Tomas Mraz 1.0.90-2 +- add helper to pam_mkhomedir for proper SELinux confinement (#476784) + * Tue Dec 16 2008 Tomas Mraz 1.0.90-1 - upgrade to new upstream release - add --disable-prelude (#466242)