1
0
mirror of https://github.com/systemd/systemd.git synced 2024-11-14 15:21:37 +03:00

pam: introduce whitelist and blacklist user list feature

This is useful to exclude root from the session logout killings or to
limit killing to the selinux guest users.
This commit is contained in:
Lennart Poettering 2011-02-13 18:21:11 +01:00
parent 7fc01d3319
commit e9fbc77c8f
3 changed files with 147 additions and 30 deletions

2
TODO
View File

@ -147,8 +147,6 @@ External:
* patch kernel for cpu feature modalias for autoloading aes/kvm/... * patch kernel for cpu feature modalias for autoloading aes/kvm/...
http://git.kernel.org/?p=linux/kernel/git/ak/linux-misc-2.6.git;a=shortlog;h=refs/heads/cpuid-match http://git.kernel.org/?p=linux/kernel/git/ak/linux-misc-2.6.git;a=shortlog;h=refs/heads/cpuid-match
* place /etc/inittab with explaining blurb.
* procps, psmisc, sysvinit-tools, hostname → util-linux-ng * procps, psmisc, sysvinit-tools, hostname → util-linux-ng
https://bugzilla.redhat.com/show_bug.cgi?id=614245 -- plymouth https://bugzilla.redhat.com/show_bug.cgi?id=614245 -- plymouth

View File

@ -202,17 +202,43 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>keep-root=</option></term> <term><option>kill-only-users=</option></term>
<listitem><para>Takes a boolean <listitem><para>Takes a comma
argument. If true, all processes separated list of user names or
created by the root user (UID 0) during his numeric user ids as argument. If this
session and from his session will be option is used the effect of the
kept around after he logged out. This <option>kill-session=</option> and
option allows cancelling the effect of <option>kill-user=</option> options
<option>kill-session=1</option> and will apply only to the listed
<option>kill-user=1</option> for the users. If this option is not used the
root user.</para></listitem> option applies to all local
users. Note that
<option>kill-exclude-users=</option>
takes precedence over this list and is
hence subtracted from the list
specified here.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>kill-exclude-users=</option></term>
<listitem><para>Takes a comma
separated list of user names or
numeric user ids as argument. Users
listed in this argument will not be
subject to the effect of
<option>kill-session=</option> or
<option>kill-user=</option>. Note
that that this option takes precedence
over
<option>kill-only-users=</option>, and
hence whatever is listed for
<option>kill-exclude-users=</option>
is guaranteed to never be killed by
this PAM module, independent of any
other configuration
setting.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@ -259,7 +285,9 @@
<option>kill-session=0</option>, <option>kill-session=0</option>,
<option>kill-user=0</option>, <option>kill-user=0</option>,
<option>keep-root=1</option>, <option>keep-root=1</option>,
<option>reset-controllers=cpu</option>.</para> <option>reset-controllers=cpu</option>,
<option>kill-only-users=</option>,
<option>kill-exclude-users=root</option>.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -42,12 +42,14 @@ static int parse_argv(pam_handle_t *handle,
bool *create_session, bool *create_session,
bool *kill_session, bool *kill_session,
bool *kill_user, bool *kill_user,
bool *keep_root,
char ***controllers, char ***controllers,
char ***reset_controllers) { char ***reset_controllers,
char ***kill_only_users,
char ***kill_exclude_users) {
unsigned i; unsigned i;
bool reset_controller_set = false; bool reset_controller_set = false;
bool kill_exclude_users_set = false;
assert(argc >= 0); assert(argc >= 0);
assert(argc == 0 || argv); assert(argc == 0 || argv);
@ -82,15 +84,6 @@ static int parse_argv(pam_handle_t *handle,
if (kill_user) if (kill_user)
*kill_user = k; *kill_user = k;
} else if (startswith(argv[i], "keep-root=")) {
if ((k = parse_boolean(argv[i] + 10)) < 0) {
pam_syslog(handle, LOG_ERR, "Failed to parse keep-root= argument.");
return k;
}
if (keep_root)
*keep_root = k;
} else if (startswith(argv[i], "controllers=")) { } else if (startswith(argv[i], "controllers=")) {
if (controllers) { if (controllers) {
@ -121,6 +114,36 @@ static int parse_argv(pam_handle_t *handle,
reset_controller_set = true; reset_controller_set = true;
} else if (startswith(argv[i], "kill-only-users=")) {
if (kill_only_users) {
char **l;
if (!(l = strv_split(argv[i] + 16, ","))) {
pam_syslog(handle, LOG_ERR, "Out of memory.");
return -ENOMEM;
}
strv_free(*kill_only_users);
*kill_only_users = l;
}
} else if (startswith(argv[i], "kill-exclude-users=")) {
if (kill_exclude_users) {
char **l;
if (!(l = strv_split(argv[i] + 19, ","))) {
pam_syslog(handle, LOG_ERR, "Out of memory.");
return -ENOMEM;
}
strv_free(*kill_exclude_users);
*kill_exclude_users = l;
}
kill_exclude_users_set = true;
} else { } else {
pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]); pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]);
return -EINVAL; return -EINVAL;
@ -147,6 +170,17 @@ static int parse_argv(pam_handle_t *handle,
if (kill_session && *kill_session && kill_user) if (kill_session && *kill_session && kill_user)
*kill_user = true; *kill_user = true;
if (!kill_exclude_users_set && kill_exclude_users) {
char **l;
if (!(l = strv_new("root", NULL))) {
pam_syslog(handle, LOG_ERR, "Out of memory");
return -ENOMEM;
}
*kill_exclude_users = l;
}
return 0; return 0;
} }
@ -369,7 +403,11 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (sd_booted() <= 0) if (sd_booted() <= 0)
return PAM_SUCCESS; return PAM_SUCCESS;
if (parse_argv(handle, argc, argv, &create_session, NULL, NULL, NULL, &controllers, &reset_controllers) < 0) if (parse_argv(handle,
argc, argv,
&create_session, NULL, NULL,
&controllers, &reset_controllers,
NULL, NULL) < 0)
return PAM_SESSION_ERR; return PAM_SESSION_ERR;
if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS) if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
@ -500,6 +538,54 @@ static int session_remains(pam_handle_t *handle, const char *user_path) {
return !!remains; return !!remains;
} }
static bool check_user_lists(
pam_handle_t *handle,
uid_t uid,
char **kill_only_users,
char **kill_exclude_users) {
const char *name = NULL;
char **l;
assert(handle);
if (uid == 0)
name = "root"; /* Avoid obvious NSS requests, to suppress network traffic */
else {
struct passwd *pw;
if ((pw = pam_modutil_getpwuid(handle, uid)))
name = pw->pw_name;
}
STRV_FOREACH(l, kill_exclude_users) {
uint32_t id;
if (safe_atou32(*l, &id) >= 0)
if ((uid_t) id == uid)
return false;
if (name && streq(name, *l))
return false;
}
if (strv_isempty(kill_only_users))
return true;
STRV_FOREACH(l, kill_only_users) {
uint32_t id;
if (safe_atou32(*l, &id) >= 0)
if ((uid_t) id == uid)
return true;
if (name && streq(name, *l))
return true;
}
return false;
}
_public_ PAM_EXTERN int pam_sm_close_session( _public_ PAM_EXTERN int pam_sm_close_session(
pam_handle_t *handle, pam_handle_t *handle,
int flags, int flags,
@ -508,13 +594,12 @@ _public_ PAM_EXTERN int pam_sm_close_session(
const char *username = NULL; const char *username = NULL;
bool kill_session = false; bool kill_session = false;
bool kill_user = false; bool kill_user = false;
bool keep_root = true;
int lock_fd = -1, r; int lock_fd = -1, r;
char *session_path = NULL, *nosession_path = NULL, *user_path = NULL; char *session_path = NULL, *nosession_path = NULL, *user_path = NULL;
const char *id; const char *id;
struct passwd *pw; struct passwd *pw;
const void *created = NULL; const void *created = NULL;
char **controllers = NULL, **c; char **controllers = NULL, **c, **kill_only_users = NULL, **kill_exclude_users = NULL;
assert(handle); assert(handle);
@ -522,7 +607,11 @@ _public_ PAM_EXTERN int pam_sm_close_session(
if (sd_booted() <= 0) if (sd_booted() <= 0)
return PAM_SUCCESS; return PAM_SUCCESS;
if (parse_argv(handle, argc, argv, NULL, &kill_session, &kill_user, &keep_root, &controllers, NULL) < 0) if (parse_argv(handle,
argc, argv,
NULL, &kill_session, &kill_user,
&controllers, NULL,
&kill_only_users, &kill_exclude_users) < 0)
return PAM_SESSION_ERR; return PAM_SESSION_ERR;
if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS) if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
@ -557,7 +646,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
goto finish; goto finish;
} }
if (kill_session && (pw->pw_uid != 0 || !keep_root)) { if (kill_session && check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users)) {
pam_syslog(handle, LOG_INFO, "Killing remaining processes of user session %s of %s.", id, username); pam_syslog(handle, LOG_INFO, "Killing remaining processes of user session %s of %s.", id, username);
/* Kill processes in session cgroup, and delete it */ /* Kill processes in session cgroup, and delete it */
@ -591,7 +680,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
pam_syslog(handle, LOG_ERR, "Failed to determine whether a session remains: %s", strerror(-r)); pam_syslog(handle, LOG_ERR, "Failed to determine whether a session remains: %s", strerror(-r));
/* Kill user processes not attached to any session */ /* Kill user processes not attached to any session */
if (kill_user && r == 0 && (pw->pw_uid != 0 || !keep_root)) { if (kill_user && r == 0 && check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users)) {
/* Kill user cgroup */ /* Kill user cgroup */
if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0) if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0)
@ -635,6 +724,8 @@ finish:
free(user_path); free(user_path);
strv_free(controllers); strv_free(controllers);
strv_free(kill_exclude_users);
strv_free(kill_only_users);
return r; return r;
} }