mirror of
git://git.gnu.org.ua/pam-modules.git
synced 2025-04-27 00:49:53 +03:00
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:
parent
99ed51a2da
commit
2e14f21631
2 changed files with 70 additions and 12 deletions
|
@ -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
|
has the same syntax as described in @ref{config, SQL configuration
|
||||||
file}. The following keywords are defined:
|
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
|
@deffn {pam_ldaphome config} skel dir
|
||||||
Supplies the name of a @dfn{skeleton directory}. The contents of this
|
Supplies the name of a @dfn{skeleton directory}. The contents of this
|
||||||
directory is copied to the newly created user home directory. The
|
directory is copied to the newly created user home directory. The
|
||||||
|
|
|
@ -961,7 +961,7 @@ create_interdir(const char *path, struct passwd *pw)
|
||||||
dir[len] = 0;
|
dir[len] = 0;
|
||||||
rc = create_hierarchy(dir, strlen(pw->pw_dir));
|
rc = create_hierarchy(dir, strlen(pw->pw_dir));
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
chown(dir, pw->pw_uid, pw->pw_gid);
|
rc = chown(dir, pw->pw_uid, pw->pw_gid);
|
||||||
free(dir);
|
free(dir);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1261,8 +1261,9 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env)
|
||||||
free(file_name);
|
free(file_name);
|
||||||
return PAM_SERVICE_ERR;
|
return PAM_SERVICE_ERR;
|
||||||
}
|
}
|
||||||
free(file_name);
|
if (fchown(fileno(fp), pw->pw_uid, pw->pw_gid))
|
||||||
fchown(fileno(fp), pw->pw_uid, pw->pw_gid);
|
_pam_log(LOG_ERR, "chown %s: %s",
|
||||||
|
file_name, strerror(errno));
|
||||||
|
|
||||||
if (!update) {
|
if (!update) {
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -1286,8 +1287,14 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env)
|
||||||
|
|
||||||
if (update) {
|
if (update) {
|
||||||
rewind(fp);
|
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) {
|
if (update) {
|
||||||
|
@ -1348,25 +1355,62 @@ import_public_key(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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)
|
create_home_dir(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (stat(pw->pw_dir, &st)) {
|
if (stat(pw->pw_dir, &st)) {
|
||||||
unsigned long mode = 0755;
|
unsigned long mode = 0755;
|
||||||
|
char *val;
|
||||||
|
|
||||||
if (errno != ENOENT) {
|
if (errno != ENOENT) {
|
||||||
_pam_log(LOG_ERR, "cannot stat home directory %s: %s",
|
_pam_log(LOG_ERR, "cannot stat home directory %s: %s",
|
||||||
pw->pw_dir, strerror(errno));
|
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)
|
if (get_intval(env, "home-dir-mode", 8, &mode) == -1)
|
||||||
return PAM_SERVICE_ERR;
|
return create_failure;
|
||||||
mode &= 07777;
|
mode &= 07777;
|
||||||
if (mkdir(pw->pw_dir, 0700)) {
|
if (mkdir(pw->pw_dir, 0700)) {
|
||||||
_pam_log(LOG_ERR, "cannot create %s: %s",
|
_pam_log(LOG_ERR, "cannot create %s: %s",
|
||||||
pw->pw_dir, strerror(errno));
|
pw->pw_dir, strerror(errno));
|
||||||
return PAM_SERVICE_ERR;
|
return create_failure;
|
||||||
}
|
}
|
||||||
populate_homedir(pamh, pw, env);
|
populate_homedir(pamh, pw, env);
|
||||||
if (chown(pw->pw_dir, pw->pw_uid, pw->pw_gid) ||
|
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,
|
_pam_log(LOG_ERR,
|
||||||
"cannot change mode or ownership of %s: %s",
|
"cannot change mode or ownership of %s: %s",
|
||||||
pw->pw_dir, strerror(errno));
|
pw->pw_dir, strerror(errno));
|
||||||
return PAM_SERVICE_ERR;
|
return create_failure;
|
||||||
}
|
}
|
||||||
} else if (!S_ISDIR(st.st_mode)) {
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
_pam_log(LOG_ERR, "%s exists, but is not a directory",
|
_pam_log(LOG_ERR, "%s exists, but is not a directory",
|
||||||
pw->pw_dir);
|
pw->pw_dir);
|
||||||
return PAM_SERVICE_ERR;
|
return create_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PAM_SUCCESS;
|
return create_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
PAM_EXTERN int
|
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;
|
authorized_keys_file = val;
|
||||||
|
|
||||||
if (check_user_groups(pamh, env, &pw, &retval) == 0) {
|
if (check_user_groups(pamh, env, &pw, &retval) == 0) {
|
||||||
retval = create_home_dir(pamh, pw, env);
|
switch (create_home_dir(pamh, pw, env)) {
|
||||||
if (retval == PAM_SUCCESS)
|
case create_ok:
|
||||||
retval = import_public_key(pamh, pw, env);
|
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);
|
gray_env_free(env);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue