bool *create_session,
bool *kill_session,
bool *kill_user,
- char ***controllers) {
+ bool *keep_root,
+ char ***controllers,
+ char ***reset_controllers) {
unsigned i;
- bool controller_set = false;
+ bool reset_controller_set = false;
assert(argc >= 0);
assert(argc == 0 || argv);
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) {
*controllers = l;
}
- controller_set = true;
+ } else if (startswith(argv[i], "reset-controllers=")) {
+
+ if (reset_controllers) {
+ char **l;
+
+ if (!(l = strv_split(argv[i] + 18, ","))) {
+ pam_syslog(handle, LOG_ERR, "Out of memory.");
+ return -ENOMEM;
+ }
+
+ strv_free(*reset_controllers);
+ *reset_controllers = l;
+ }
+
+ reset_controller_set = true;
} else {
pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]);
}
}
- if (!controller_set && controllers) {
+ if (!reset_controller_set && reset_controllers) {
char **l;
if (!(l = strv_new("cpu", NULL))) {
return -ENOMEM;
}
- *controllers = l;
+ *reset_controllers = l;
}
if (controllers)
strv_remove(*controllers, "name=systemd");
+ if (reset_controllers)
+ strv_remove(*reset_controllers, "name=systemd");
+
if (kill_session && *kill_session && kill_user)
*kill_user = true;
return PAM_SUCCESS;
}
+static int reset_group(
+ pam_handle_t *handle,
+ const char *controller) {
+
+ int r;
+
+ assert(handle);
+
+ if ((r = cg_attach(controller, "/", 0)) < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to reset cgroup for controller %s: %s", controller, strerror(-r));
+ return PAM_SESSION_ERR;
+ }
+
+ return PAM_SUCCESS;
+}
+
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
char *buf = NULL;
int lock_fd = -1;
bool create_session = true;
- char **controllers = NULL, **c;
+ char **controllers = NULL, **reset_controllers = NULL, **c;
assert(handle);
if (sd_booted() <= 0)
return PAM_SUCCESS;
- if (parse_argv(handle, argc, argv, &create_session, NULL, NULL, &controllers) < 0)
+ if (parse_argv(handle, argc, argv, &create_session, NULL, NULL, NULL, &controllers, &reset_controllers) < 0)
return PAM_SESSION_ERR;
if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
STRV_FOREACH(c, controllers)
create_user_group(handle, *c, buf, pw, true, false);
+ STRV_FOREACH(c, reset_controllers)
+ reset_group(handle, *c);
+
r = PAM_SUCCESS;
finish:
close_nointr_nofail(lock_fd);
strv_free(controllers);
+ strv_free(reset_controllers);
return r;
}
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;
if (sd_booted() <= 0)
return PAM_SUCCESS;
- if (parse_argv(handle, argc, argv, NULL, &kill_session, &kill_user, &controllers) < 0)
+ if (parse_argv(handle, argc, argv, NULL, &kill_session, &kill_user, &keep_root, &controllers, NULL) < 0)
return PAM_SESSION_ERR;
if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
goto finish;
}
- if (kill_session) {
+ if (kill_session && (pw->pw_uid != 0 || !keep_root)) {
pam_syslog(handle, LOG_INFO, "Killing remaining processes of user session %s of %s.", id, username);
/* Kill processes in session cgroup, and delete it */
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) {
+ if (kill_user && r == 0 && (pw->pw_uid != 0 || !keep_root)) {
/* Kill user cgroup */
if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0)