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:
parent
7fc01d3319
commit
e9fbc77c8f
2
TODO
2
TODO
@ -147,8 +147,6 @@ External:
|
||||
* 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
|
||||
|
||||
* place /etc/inittab with explaining blurb.
|
||||
|
||||
* procps, psmisc, sysvinit-tools, hostname → util-linux-ng
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=614245 -- plymouth
|
||||
|
@ -202,17 +202,43 @@
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>keep-root=</option></term>
|
||||
<term><option>kill-only-users=</option></term>
|
||||
|
||||
<listitem><para>Takes a boolean
|
||||
argument. If true, all processes
|
||||
created by the root user (UID 0) during his
|
||||
session and from his session will be
|
||||
kept around after he logged out. This
|
||||
option allows cancelling the effect of
|
||||
<option>kill-session=1</option> and
|
||||
<option>kill-user=1</option> for the
|
||||
root user.</para></listitem>
|
||||
<listitem><para>Takes a comma
|
||||
separated list of user names or
|
||||
numeric user ids as argument. If this
|
||||
option is used the effect of the
|
||||
<option>kill-session=</option> and
|
||||
<option>kill-user=</option> options
|
||||
will apply only to the listed
|
||||
users. If this option is not used the
|
||||
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>
|
||||
@ -259,7 +285,9 @@
|
||||
<option>kill-session=0</option>,
|
||||
<option>kill-user=0</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>
|
||||
|
125
src/pam-module.c
125
src/pam-module.c
@ -42,12 +42,14 @@ static int parse_argv(pam_handle_t *handle,
|
||||
bool *create_session,
|
||||
bool *kill_session,
|
||||
bool *kill_user,
|
||||
bool *keep_root,
|
||||
char ***controllers,
|
||||
char ***reset_controllers) {
|
||||
char ***reset_controllers,
|
||||
char ***kill_only_users,
|
||||
char ***kill_exclude_users) {
|
||||
|
||||
unsigned i;
|
||||
bool reset_controller_set = false;
|
||||
bool kill_exclude_users_set = false;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argc == 0 || argv);
|
||||
@ -82,15 +84,6 @@ static int parse_argv(pam_handle_t *handle,
|
||||
if (kill_user)
|
||||
*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=")) {
|
||||
|
||||
if (controllers) {
|
||||
@ -121,6 +114,36 @@ static int parse_argv(pam_handle_t *handle,
|
||||
|
||||
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 {
|
||||
pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]);
|
||||
return -EINVAL;
|
||||
@ -147,6 +170,17 @@ static int parse_argv(pam_handle_t *handle,
|
||||
if (kill_session && *kill_session && kill_user)
|
||||
*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;
|
||||
}
|
||||
|
||||
@ -369,7 +403,11 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
if (sd_booted() <= 0)
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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(
|
||||
pam_handle_t *handle,
|
||||
int flags,
|
||||
@ -508,13 +594,12 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
||||
const char *username = NULL;
|
||||
bool kill_session = false;
|
||||
bool kill_user = false;
|
||||
bool keep_root = true;
|
||||
int lock_fd = -1, r;
|
||||
char *session_path = NULL, *nosession_path = NULL, *user_path = NULL;
|
||||
const char *id;
|
||||
struct passwd *pw;
|
||||
const void *created = NULL;
|
||||
char **controllers = NULL, **c;
|
||||
char **controllers = NULL, **c, **kill_only_users = NULL, **kill_exclude_users = NULL;
|
||||
|
||||
assert(handle);
|
||||
|
||||
@ -522,7 +607,11 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
||||
if (sd_booted() <= 0)
|
||||
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;
|
||||
|
||||
if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
|
||||
@ -557,7 +646,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
||||
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);
|
||||
|
||||
/* 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));
|
||||
|
||||
/* 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 */
|
||||
if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0)
|
||||
@ -635,6 +724,8 @@ finish:
|
||||
free(user_path);
|
||||
|
||||
strv_free(controllers);
|
||||
strv_free(kill_exclude_users);
|
||||
strv_free(kill_only_users);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user