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/...
|
* 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
|
||||||
|
@ -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>
|
||||||
|
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 *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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user