summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2014-02-11 12:44:57 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2014-02-11 13:00:48 (GMT)
commit2e14f216312a047233b345e2641161b9eb016152 (patch) (side-by-side diff)
treef49df2c799938b60f4494c8476a101938f04fabc
parent99ed51a2dadb4d5ffca77003524cf9b0900966d0 (diff)
downloadpam-modules-2e14f216312a047233b345e2641161b9eb016152.tar.gz
pam-modules-2e14f216312a047233b345e2641161b9eb016152.tar.bz2
pam_ldaphome: control where home directories can be created
* pam_ldaphome/pam_ldaphome.c (create_interdir): Fail if unable to chown, (store_pubkeys): Log error if fchown or ftruncate fails. (dir_in_path): New static function. (create_home_dir): Return enum create_status. If allow-home-dir statement is present, create directory only if it is located in one of the directories listed in it, otherwise return create_skip. (pam_sm_authenticate): Import keys only if home dir exists. * doc/pam-modules.texi: Document allow-home-dir.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--doc/pam-modules.texi7
-rw-r--r--pam_ldaphome/pam_ldaphome.c75
2 files changed, 70 insertions, 12 deletions
diff --git a/doc/pam-modules.texi b/doc/pam-modules.texi
index e7b460f..b9fd91a 100644
--- a/doc/pam-modules.texi
+++ b/doc/pam-modules.texi
@@ -1170,6 +1170,13 @@ Actual module configuration is read from the configuration file, which
has the same syntax as described in @ref{config, SQL configuration
file}. The following keywords are defined:
+@deffn {pam_ldaphome config} allow-home-dir path
+If present, this option controls where @command{pam_ldaphome} should
+try to create home directories. Its value is a list of directories
+separated by colons. The user's home directory will be created only
+if the directory part of its name is listed in @var{path}.
+@end deffn
+
@deffn {pam_ldaphome config} skel dir
Supplies the name of a @dfn{skeleton directory}. The contents of this
directory is copied to the newly created user home directory. The
diff --git a/pam_ldaphome/pam_ldaphome.c b/pam_ldaphome/pam_ldaphome.c
index b86fa70..53754de 100644
--- a/pam_ldaphome/pam_ldaphome.c
+++ b/pam_ldaphome/pam_ldaphome.c
@@ -961,7 +961,7 @@ create_interdir(const char *path, struct passwd *pw)
dir[len] = 0;
rc = create_hierarchy(dir, strlen(pw->pw_dir));
if (rc == 0)
- chown(dir, pw->pw_uid, pw->pw_gid);
+ rc = chown(dir, pw->pw_uid, pw->pw_gid);
free(dir);
return rc;
}
@@ -1261,8 +1261,9 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env)
free(file_name);
return PAM_SERVICE_ERR;
}
- free(file_name);
- fchown(fileno(fp), pw->pw_uid, pw->pw_gid);
+ if (fchown(fileno(fp), pw->pw_uid, pw->pw_gid))
+ _pam_log(LOG_ERR, "chown %s: %s",
+ file_name, strerror(errno));
if (!update) {
i = 0;
@@ -1286,8 +1287,14 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env)
if (update) {
rewind(fp);
- ftruncate(fileno(fp), 0);
+ if (ftruncate(fileno(fp), 0)) {
+ _pam_log(LOG_ERR, "truncate %s: %s",
+ file_name, strerror(errno));
+ free(file_name);
+ return PAM_SERVICE_ERR;
+ }
}
+ free(file_name);
}
if (update) {
@@ -1348,25 +1355,62 @@ import_public_key(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
}
static int
+dir_in_path(const char *dir, const char *path)
+{
+ char *p;
+ size_t dirlen;
+
+ p = strrchr(dir, '/');
+ if (p)
+ dirlen = p - dir;
+ else
+ return 0;
+
+ while (*path) {
+ size_t len = strcspn(path, ":");
+ while (len > 0 && path[len-1] == '/')
+ --len;
+ if (len == dirlen && memcmp(path, dir, len) == 0)
+ return 1;
+ path += len;
+ if (*path == ':')
+ ++path;
+ }
+ return 0;
+}
+
+enum create_status {
+ create_ok,
+ create_failure,
+ create_skip
+};
+
+static enum create_status
create_home_dir(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
{
struct stat st;
if (stat(pw->pw_dir, &st)) {
unsigned long mode = 0755;
+ char *val;
if (errno != ENOENT) {
_pam_log(LOG_ERR, "cannot stat home directory %s: %s",
pw->pw_dir, strerror(errno));
- return PAM_SERVICE_ERR;
+ return create_failure;
}
+
+ val = gray_env_get(env, "allow-home-dir");
+ if (val && !dir_in_path(pw->pw_dir, val))
+ return create_skip;
+
if (get_intval(env, "home-dir-mode", 8, &mode) == -1)
- return PAM_SERVICE_ERR;
+ return create_failure;
mode &= 07777;
if (mkdir(pw->pw_dir, 0700)) {
_pam_log(LOG_ERR, "cannot create %s: %s",
pw->pw_dir, strerror(errno));
- return PAM_SERVICE_ERR;
+ return create_failure;
}
populate_homedir(pamh, pw, env);
if (chown(pw->pw_dir, pw->pw_uid, pw->pw_gid) ||
@@ -1374,15 +1418,15 @@ create_home_dir(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
_pam_log(LOG_ERR,
"cannot change mode or ownership of %s: %s",
pw->pw_dir, strerror(errno));
- return PAM_SERVICE_ERR;
+ return create_failure;
}
} else if (!S_ISDIR(st.st_mode)) {
_pam_log(LOG_ERR, "%s exists, but is not a directory",
pw->pw_dir);
- return PAM_SERVICE_ERR;
+ return create_failure;
}
- return PAM_SUCCESS;
+ return create_ok;
}
PAM_EXTERN int
@@ -1403,9 +1447,16 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
authorized_keys_file = val;
if (check_user_groups(pamh, env, &pw, &retval) == 0) {
- retval = create_home_dir(pamh, pw, env);
- if (retval == PAM_SUCCESS)
+ switch (create_home_dir(pamh, pw, env)) {
+ case create_ok:
retval = import_public_key(pamh, pw, env);
+ break;
+ case create_failure:
+ retval = PAM_SERVICE_ERR;
+ break;
+ case create_skip:
+ retval = PAM_SUCCESS;
+ }
}
gray_env_free(env);
}

Return to:

Send suggestions and report system problems to the System administrator.