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.
This commit is contained in:
Sergey Poznyakoff 2014-02-11 14:44:57 +02:00
parent 99ed51a2da
commit 2e14f21631
2 changed files with 70 additions and 12 deletions

View file

@ -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

View file

@ -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,9 +1287,15 @@ 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) {
for (i = 0; keys[i]; i++) {
@ -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);
}