summaryrefslogtreecommitdiff
path: root/modules/pam_mkhomedir/mkhomedir_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_mkhomedir/mkhomedir_helper.c')
-rw-r--r--modules/pam_mkhomedir/mkhomedir_helper.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/modules/pam_mkhomedir/mkhomedir_helper.c b/modules/pam_mkhomedir/mkhomedir_helper.c
index 8969da52..643d5d01 100644
--- a/modules/pam_mkhomedir/mkhomedir_helper.c
+++ b/modules/pam_mkhomedir/mkhomedir_helper.c
@@ -27,6 +27,7 @@
#include <security/pam_modutil.h>
static unsigned long u_mask = 0022;
+static unsigned long home_mode = 0;
static char skeldir[BUFSIZ] = "/etc/skel";
/* Do the actual work of creating a home dir */
@@ -38,6 +39,7 @@ create_homedir(const struct passwd *pwd,
DIR *d;
struct dirent *dent;
int retval = PAM_SESSION_ERR;
+ struct stat stat_buf;
/* Create the new directory */
if (mkdir(dest, 0700) && errno != EEXIST)
@@ -53,6 +55,12 @@ create_homedir(const struct passwd *pwd,
goto go_out;
}
+ /* Various things such as an autofs mount with browsing disabled
+ * can cause the directory to appear only on stat. The intent is
+ * to minimize network traversal when a file explorer tries to
+ * traverse large chunks of a directory tree. So stat first.*/
+ stat(source, &stat_buf);
+
/* Scan the directory */
d = opendir(source);
if (d == NULL)
@@ -183,8 +191,7 @@ create_homedir(const struct passwd *pwd,
else
pointed[pointedlen] = 0;
#else
- char pointed[PATH_MAX];
- memset(pointed, 0, sizeof(pointed));
+ char pointed[PATH_MAX] = {};
pointedlen = readlink(newsource, pointed, sizeof(pointed) - 1);
#endif
@@ -232,6 +239,8 @@ create_homedir(const struct passwd *pwd,
{
pam_syslog(NULL, LOG_DEBUG,
"unable to open or stat src file %s: %m", newsource);
+ if (srcfd >= 0)
+ close(srcfd);
closedir(d);
#ifndef PATH_MAX
@@ -258,7 +267,7 @@ create_homedir(const struct passwd *pwd,
}
/* 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
+ the file a+w and then mask it with the set mask. This preserves
execute bits */
if (fchmod(destfd, (st.st_mode | 0222) & (~u_mask)) != 0 ||
fchown(destfd, pwd->pw_uid, pwd->pw_gid) != 0)
@@ -332,6 +341,24 @@ create_homedir(const struct passwd *pwd,
}
static int
+create_homedir_helper(const struct passwd *_pwd,
+ const char *_skeldir, const char *_homedir)
+{
+ int retval = PAM_SESSION_ERR;
+
+ retval = create_homedir(_pwd, _skeldir, _homedir);
+
+ if (chmod(_homedir, home_mode) != 0)
+ {
+ pam_syslog(NULL, LOG_DEBUG,
+ "unable to change perms on home directory %s: %m", _homedir);
+ return PAM_PERM_DENIED;
+ }
+
+ return retval;
+}
+
+static int
make_parent_dirs(char *dir, int make)
{
int rc = PAM_SUCCESS;
@@ -364,9 +391,10 @@ main(int argc, char *argv[])
{
struct passwd *pwd;
struct stat st;
+ char *eptr;
if (argc < 2) {
- fprintf(stderr, "Usage: %s <username> [<umask> [<skeldir>]]\n", argv[0]);
+ fprintf(stderr, "Usage: %s <username> [<umask> [<skeldir> [<home_mode>]]]\n", argv[0]);
return PAM_SESSION_ERR;
}
@@ -377,7 +405,6 @@ main(int argc, char *argv[])
}
if (argc >= 3) {
- char *eptr;
errno = 0;
u_mask = strtoul(argv[2], &eptr, 0);
if (errno != 0 || *eptr != '\0') {
@@ -394,6 +421,18 @@ main(int argc, char *argv[])
strcpy(skeldir, argv[3]);
}
+ if (argc >= 5) {
+ errno = 0;
+ home_mode = strtoul(argv[4], &eptr, 0);
+ if (errno != 0 || *eptr != '\0') {
+ pam_syslog(NULL, LOG_ERR, "Bogus home_mode value %s", argv[4]);
+ return PAM_SESSION_ERR;
+ }
+ }
+
+ if (home_mode == 0)
+ home_mode = 0777 & ~u_mask;
+
/* Stat the home directory, if something exists then we assume it is
correct and return a success */
if (stat(pwd->pw_dir, &st) == 0)
@@ -402,5 +441,5 @@ main(int argc, char *argv[])
if (make_parent_dirs(pwd->pw_dir, 0) != PAM_SUCCESS)
return PAM_PERM_DENIED;
- return create_homedir(pwd, skeldir, pwd->pw_dir);
+ return create_homedir_helper(pwd, skeldir, pwd->pw_dir);
}