From 1f73f0f163eeb8a889e3799c0c63bcb437e531ac Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 14 Mar 2011 23:13:57 +0100 Subject: pam: determine user cgroup tree from cgroup of PID 1 --- src/cgroup-util.c | 28 ++++++++++++++++++++++++++++ src/cgroup-util.h | 2 ++ src/pam-module.c | 37 +++++++++++++++++++++++++++---------- src/user-sessions.c | 15 +++++++++++++-- 4 files changed, 70 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/cgroup-util.c b/src/cgroup-util.c index 055c906106..bbadc789a1 100644 --- a/src/cgroup-util.c +++ b/src/cgroup-util.c @@ -967,3 +967,31 @@ int cg_fix_path(const char *path, char **result) { return r; } + +int cg_get_user_path(char **path) { + char *root, *p; + + assert(path); + + /* Figure out the place to put user cgroups below. We use the + * same as PID 1 has but with the "/system" suffix replaced by + * "/user" */ + + if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0) + p = strdup("/user"); + else { + if (endswith(root, "/system")) + root[strlen(root) - 7] = 0; + else if (streq(root, "/")) + root[0] = 0; + + p = strappend(root, "/user"); + free(root); + } + + if (!p) + return -ENOMEM; + + *path = p; + return 0; +} diff --git a/src/cgroup-util.h b/src/cgroup-util.h index 73df9697ed..1eccbc9fd7 100644 --- a/src/cgroup-util.h +++ b/src/cgroup-util.h @@ -68,4 +68,6 @@ int cg_install_release_agent(const char *controller, const char *agent); int cg_is_empty(const char *controller, const char *path, bool ignore_self); int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self); +int cg_get_user_path(char **path); + #endif diff --git a/src/pam-module.c b/src/pam-module.c index e1a1a5001c..3a5404db4d 100644 --- a/src/pam-module.c +++ b/src/pam-module.c @@ -199,10 +199,8 @@ static int open_file_and_lock(const char *fn) { * locally accessible, and most likely even tmpfs. */ if (flock(fd, LOCK_EX) < 0) { - int r = -errno; - close_nointr_nofail(fd); - return r; + return -errno; } return fd; @@ -275,6 +273,7 @@ static uint64_t get_session_id(int *mode) { /* Last attempt, pick a random value */ return (uint64_t) random_ull(); } + static int get_user_data( pam_handle_t *handle, const char **ret_username, @@ -398,6 +397,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( int lock_fd = -1; bool create_session = true; char **controllers = NULL, **reset_controllers = NULL, **c; + char *cgroup_user_tree = NULL; assert(handle); @@ -417,6 +417,12 @@ _public_ PAM_EXTERN int pam_sm_open_session( if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS) goto finish; + if ((r = cg_get_user_path(&cgroup_user_tree)) < 0) { + pam_syslog(handle, LOG_ERR, "Failed to determine user cgroup tree: %s", strerror(-r)); + r = PAM_SYSTEM_ERR; + goto finish; + } + if (safe_mkdir(RUNTIME_DIR "/user", 0755, 0, 0) < 0) { pam_syslog(handle, LOG_ERR, "Failed to create runtime directory: %m"); r = PAM_SYSTEM_ERR; @@ -480,9 +486,9 @@ _public_ PAM_EXTERN int pam_sm_open_session( } } - r = asprintf(&buf, "/user/%s/%s", username, id); + r = asprintf(&buf, "%s/%s/%s", cgroup_user_tree, username, id); } else - r = asprintf(&buf, "/user/%s/master", username); + r = asprintf(&buf, "%s/%s/master", cgroup_user_tree, username); if (r < 0) { r = PAM_BUF_ERR; @@ -513,6 +519,8 @@ finish: strv_free(controllers); strv_free(reset_controllers); + free(cgroup_user_tree); + return r; } @@ -604,6 +612,7 @@ _public_ PAM_EXTERN int pam_sm_close_session( struct passwd *pw; const void *created = NULL; char **controllers = NULL, **c, **kill_only_users = NULL, **kill_exclude_users = NULL; + char *cgroup_user_tree = NULL; assert(handle); @@ -621,6 +630,12 @@ _public_ PAM_EXTERN int pam_sm_close_session( if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS) goto finish; + if ((r = cg_get_user_path(&cgroup_user_tree)) < 0) { + pam_syslog(handle, LOG_ERR, "Failed to determine user cgroup tree: %s", strerror(-r)); + r = PAM_SYSTEM_ERR; + goto finish; + } + if ((lock_fd = open_file_and_lock(RUNTIME_DIR "/user/.pam-systemd-lock")) < 0) { pam_syslog(handle, LOG_ERR, "Failed to lock runtime directory: %m"); r = PAM_SYSTEM_ERR; @@ -628,14 +643,14 @@ _public_ PAM_EXTERN int pam_sm_close_session( } /* We are probably still in some session/user dir. Move ourselves out of the way as first step */ - if ((r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, "/user", 0)) < 0) + if ((r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup_user_tree, 0)) < 0) pam_syslog(handle, LOG_ERR, "Failed to move us away: %s", strerror(-r)); STRV_FOREACH(c, controllers) - if ((r = cg_attach(*c, "/user", 0)) < 0) + if ((r = cg_attach(*c, cgroup_user_tree, 0)) < 0) pam_syslog(handle, LOG_ERR, "Failed to move us away in %s hierarchy: %s", *c, strerror(-r)); - if (asprintf(&user_path, "/user/%s", username) < 0) { + if (asprintf(&user_path, "%s/%s", cgroup_user_tree, username) < 0) { r = PAM_BUF_ERR; goto finish; } @@ -644,8 +659,8 @@ _public_ PAM_EXTERN int pam_sm_close_session( if ((id = pam_getenv(handle, "XDG_SESSION_ID")) && created) { - if (asprintf(&session_path, "/user/%s/%s", username, id) < 0 || - asprintf(&nosession_path, "/user/%s/master", username) < 0) { + if (asprintf(&session_path, "%s/%s/%s", cgroup_user_tree, username, id) < 0 || + asprintf(&nosession_path, "%s/%s/master", cgroup_user_tree, username) < 0) { r = PAM_BUF_ERR; goto finish; } @@ -731,5 +746,7 @@ finish: strv_free(kill_exclude_users); strv_free(kill_only_users); + free(cgroup_user_tree); + return r; } diff --git a/src/user-sessions.c b/src/user-sessions.c index 8026961560..d3faad0cd6 100644 --- a/src/user-sessions.c +++ b/src/user-sessions.c @@ -57,14 +57,25 @@ int main(int argc, char*argv[]) { } else if (streq(argv[1], "stop")) { int r, q; + char *cgroup_user_tree = NULL; if ((r = write_one_line_file("/var/run/nologin", "System is going down.")) < 0) log_error("Failed to create /var/run/nologin: %s", strerror(-r)); - if ((q = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, "/user", true)) < 0) + if ((q = cg_get_user_path(&cgroup_user_tree)) < 0) { + log_error("Failed to determine use path: %s", strerror(-q)); + goto finish; + } + + q = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, cgroup_user_tree, true); + free(cgroup_user_tree); + + if (q < 0) { log_error("Failed to kill sessions: %s", strerror(-q)); + goto finish; + } - if (r < 0 || q < 0) + if (r < 0) goto finish; } else { -- cgit v1.2.3-54-g00ecf