diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-02-11 14:44:57 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-02-11 15:00:48 +0200 |
commit | 2e14f216312a047233b345e2641161b9eb016152 (patch) | |
tree | f49df2c799938b60f4494c8476a101938f04fabc | |
parent | 99ed51a2dadb4d5ffca77003524cf9b0900966d0 (diff) | |
download | pam-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.
-rw-r--r-- | doc/pam-modules.texi | 7 | ||||
-rw-r--r-- | pam_ldaphome/pam_ldaphome.c | 75 |
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 @@ -1167,12 +1167,19 @@ Read configuration from @var{file}. Default is @end table 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 file modes and permissions are retained. @end deffn 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 @@ -958,13 +958,13 @@ create_interdir(const char *path, struct passwd *pw) len = p - path; dir = gray_malloc(len + 1); memcpy(dir, path, len); 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; } struct namebuf { char *name; @@ -1258,14 +1258,15 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env) if (!fp) { _pam_log(LOG_EMERG, "cannot open file %s: %s", file_name, strerror(errno)); 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; do { const char *kp = keys[i++]; if (!kp) { @@ -1283,14 +1284,20 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env) break; } } while (c != EOF && (c = getc(fp)) == '\n'); 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) { for (i = 0; keys[i]; i++) { fwrite(keys[i], strlen(keys[i]), 1, fp); fputc('\n', fp); @@ -1345,47 +1352,84 @@ import_public_key(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env) } ldap_unbind(ld); return retval; } 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) || chmod(pw->pw_dir, mode)) { _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 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int retval = PAM_AUTH_ERR; @@ -1400,15 +1444,22 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) struct passwd *pw; if (val = gray_env_get(env, "authorized_keys")) 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); } DEBUG(90,("exit pam_sm_authenticate: %d", retval)); return retval; } |