From 98a28fef2618e54a644614c759f371f297381b70 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jun 2011 18:50:50 +0200 Subject: [PATCH] logind: hook up PAM module with logind --- Makefile.am | 11 +- src/dbus-common.c | 31 +- src/dbus-common.h | 2 + src/logind-dbus.c | 295 +++++++++++++++++- src/logind-seat.c | 12 +- src/logind-session-dbus.c | 2 + src/logind-session.c | 92 ++++-- src/logind-session.h | 3 + src/logind-user.c | 12 +- src/logind.h | 6 +- src/pam-module.c | 616 +++++++++++--------------------------- src/uaccess.c | 2 +- src/util.c | 59 +++- src/util.h | 3 + 14 files changed, 652 insertions(+), 494 deletions(-) diff --git a/Makefile.am b/Makefile.am index a2d739756..bfc107950 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1248,10 +1248,12 @@ systemd_tty_ask_password_agent_LDADD = \ pam_systemd_la_SOURCES = \ src/pam-module.c \ - src/cgroup-util.c + src/dbus-common.c pam_systemd_la_CFLAGS = \ - $(AM_CFLAGS) + $(AM_CFLAGS) \ + $(PAM_CFLAGS) \ + $(DBUS_CFLAGS) \ -fvisibility=hidden pam_systemd_la_LDFLAGS = \ @@ -1264,7 +1266,8 @@ pam_systemd_la_LDFLAGS = \ pam_systemd_la_LIBADD = \ libsystemd-basic.la \ libsystemd-daemon.la \ - $(PAM_LIBS) + $(PAM_LIBS) \ + $(DBUS_LIBS) SED_PROCESS = \ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ @@ -1510,7 +1513,7 @@ endif $(LN_S) graphical.target runlevel5.target && \ $(LN_S) reboot.target runlevel6.target ) ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f default.target ctrl-alt-del.target dbus-org.freedesktop.hostname1.service && \ + rm -f default.target ctrl-alt-del.target dbus-org.freedesktop.hostname1.service dbus-org.freedesktop.locale1.service dbus-org.freedesktop.timedate1.service dbus-org.freedesktop.login1.service && \ $(LN_S) graphical.target default.target && \ $(LN_S) reboot.target ctrl-alt-del.target && \ $(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service && \ diff --git a/src/dbus-common.c b/src/dbus-common.c index e439a4248..73f9e87ee 100644 --- a/src/dbus-common.c +++ b/src/dbus-common.c @@ -463,23 +463,12 @@ int bus_property_append_string(DBusMessageIter *i, const char *property, void *d } int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub; char **t = data; assert(i); assert(property); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; - - STRV_FOREACH(t, t) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return bus_append_strv_iter(i, t); } int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) { @@ -796,3 +785,21 @@ int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) { return 0; } + +int bus_append_strv_iter(DBusMessageIter *iter, char **l) { + DBusMessageIter sub; + + assert(iter); + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub)) + return -ENOMEM; + + STRV_FOREACH(l, l) + if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l)) + return -ENOMEM; + + if (!dbus_message_iter_close_container(iter, &sub)) + return -ENOMEM; + + return 0; +} diff --git a/src/dbus-common.h b/src/dbus-common.h index 9368f7512..04485e50e 100644 --- a/src/dbus-common.h +++ b/src/dbus-common.h @@ -161,4 +161,6 @@ unsigned bus_events_to_flags(uint32_t events); int bus_parse_strv(DBusMessage *m, char ***_l); int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l); +int bus_append_strv_iter(DBusMessageIter *iter, char **l); + #endif diff --git a/src/logind-dbus.c b/src/logind-dbus.c index 662ffd0be..10a826bc9 100644 --- a/src/logind-dbus.c +++ b/src/logind-dbus.c @@ -21,9 +21,11 @@ #include #include +#include #include "logind.h" #include "dbus-common.h" +#include "strv.h" #define BUS_MANAGER_INTERFACE \ " \n" \ @@ -51,6 +53,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -60,9 +63,10 @@ " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -161,6 +165,285 @@ static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *pr return 0; } +static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) { + Session *session = NULL; + User *user = NULL; + const char *type, *seat, *tty, *display, *remote_user, *remote_host, *service; + uint32_t uid, leader, audit_id = 0; + dbus_bool_t remote, kill_processes; + char **controllers = NULL, **reset_controllers = NULL; + SessionType t; + Seat *s; + DBusMessageIter iter; + int r; + char *id, *p; + int vtnr = -1; + int pipe_fds[2] = { -1, -1 }; + DBusMessage *reply = NULL; + bool b; + + assert(m); + assert(message); + assert(_reply); + + if (!dbus_message_iter_init(message, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &uid); + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &leader); + + if (leader <= 0 || + !dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &service); + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &type); + t = session_type_from_string(type); + + if (t < 0 || + !dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &seat); + + if (isempty(seat)) + s = NULL; + else { + s = hashmap_get(m->seats, seat); + if (!s) + return -ENOENT; + } + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &tty); + + if (tty_is_vc(tty)) { + + if (!s) + s = m->vtconsole; + else if (s != m->vtconsole) + return -EINVAL; + + vtnr = vtnr_from_tty(tty); + + if (vtnr <= 0) + return vtnr < 0 ? vtnr : -EINVAL; + + } else if (s == m->vtconsole) + return -EINVAL; + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &display); + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &remote); + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &remote_user); + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &remote_host); + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + r = bus_parse_strv_iter(&iter, &controllers); + if (r < 0) + return -EINVAL; + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) { + r = -EINVAL; + goto fail; + } + + r = bus_parse_strv_iter(&iter, &reset_controllers); + if (r < 0) + goto fail; + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) { + r = -EINVAL; + goto fail; + } + + dbus_message_iter_get_basic(&iter, &kill_processes); + + r = manager_add_user_by_uid(m, uid, &user); + if (r < 0) + goto fail; + + audit_session_from_pid(leader, &audit_id); + + if (audit_id > 0) + asprintf(&id, "%lu", (unsigned long) audit_id); + else + asprintf(&id, "c%lu", ++m->session_counter); + + if (!id) { + r = -ENOMEM; + goto fail; + } + + if (hashmap_get(m->sessions, id)) { + r = -EEXIST; + goto fail; + } + + r = manager_add_session(m, user, id, &session); + free(id); + if (r < 0) + goto fail; + + session->leader = leader; + session->audit_id = audit_id; + session->type = t; + session->remote = remote; + session->controllers = controllers; + session->reset_controllers = reset_controllers; + session->kill_processes = kill_processes; + session->vtnr = vtnr; + + controllers = reset_controllers = NULL; + + if (!isempty(tty)) { + session->tty = strdup(tty); + if (!session->tty) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(display)) { + session->display = strdup(display); + if (!session->display) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(remote_user)) { + session->remote_user = strdup(remote_user); + if (!session->remote_user) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(remote_host)) { + session->remote_host = strdup(remote_host); + if (!session->remote_host) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(service)) { + session->service = strdup(service); + if (!session->service) { + r = -ENOMEM; + goto fail; + } + } + + if (pipe(pipe_fds) < 0) { + r = -errno; + goto fail; + } + + session->pipe_fd = pipe_fds[1]; + pipe_fds[1] = -1; + + if (s) { + r = seat_attach_session(s, session); + if (r < 0) + goto fail; + } + + r = session_start(session); + if (r < 0) + goto fail; + + reply = dbus_message_new_method_return(message); + if (!reply) { + r = -ENOMEM; + goto fail; + } + + p = session_bus_path(session); + if (!p) { + r = -ENOMEM; + goto fail; + } + + b = dbus_message_append_args( + reply, + DBUS_TYPE_STRING, &session->id, + DBUS_TYPE_OBJECT_PATH, &p, + DBUS_TYPE_STRING, &session->user->runtime_path, + DBUS_TYPE_UNIX_FD, &pipe_fds[0], + DBUS_TYPE_INVALID); + free(p); + + if (!b) { + r = -ENOMEM; + goto fail; + } + + close_nointr_nofail(pipe_fds[0]); + *_reply = reply; + + return 0; + +fail: + strv_free(controllers); + strv_free(reset_controllers); + + if (session) + session_add_to_gc_queue(session); + + if (user) + user_add_to_gc_queue(user); + + close_pipe(pipe_fds); + + if (reply) + dbus_message_unref(reply); + + return r; +} + static DBusHandlerResult manager_message_handler( DBusConnection *connection, DBusMessage *message, @@ -171,7 +454,6 @@ static DBusHandlerResult manager_message_handler( const BusProperty properties[] = { { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path }, { "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers }, - { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers }, { "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts }, { "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users }, { "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users }, @@ -425,6 +707,15 @@ static DBusHandlerResult manager_message_handler( if (!dbus_message_iter_close_container(&iter, &sub)) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) { + + r = bus_manager_create_session(m, message, &reply); + if (r == -ENOMEM) + goto oom; + + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) { const char *name; Session *session; diff --git a/src/logind-seat.c b/src/logind-seat.c index 12a1b8064..26c2bd4f5 100644 --- a/src/logind-seat.c +++ b/src/logind-seat.c @@ -41,7 +41,7 @@ Seat *seat_new(Manager *m, const char *id) { if (!s) return NULL; - s->state_file = strappend("/run/systemd/seat/", id); + s->state_file = strappend("/run/systemd/seats/", id); if (!s->state_file) { free(s); return NULL; @@ -86,7 +86,7 @@ int seat_save(Seat *s) { assert(s); - r = safe_mkdir("/run/systemd/seat", 0755, 0, 0); + r = safe_mkdir("/run/systemd/seats", 0755, 0, 0); if (r < 0) goto finish; @@ -246,6 +246,14 @@ int seat_set_active(Seat *s, Session *session) { if (!session || session->started) seat_send_changed(s, "ActiveSession\0"); + seat_save(s); + + if (session) + session_save(session); + + if (old_active) + session_save(old_active); + return 0; } diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c index b0e592d21..8d1e607e6 100644 --- a/src/logind-session-dbus.c +++ b/src/logind-session-dbus.c @@ -49,6 +49,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -236,6 +237,7 @@ static DBusHandlerResult session_message_dispatch( { "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote }, { "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user }, { "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host }, + { "org.freedesktop.login1.Session", "Service", bus_property_append_string, "s", s->service }, { "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader }, { "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id }, { "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type }, diff --git a/src/logind-session.c b/src/logind-session.c index 5ba6b21ee..42d28016d 100644 --- a/src/logind-session.c +++ b/src/logind-session.c @@ -40,7 +40,7 @@ Session* session_new(Manager *m, User *u, const char *id) { if (!s) return NULL; - s->state_file = strappend("/run/systemd/session/", id); + s->state_file = strappend("/run/systemd/sessions/", id); if (!s->state_file) { free(s); return NULL; @@ -90,9 +90,13 @@ void session_free(Session *s) { free(s->display); free(s->remote_host); free(s->remote_user); + free(s->service); hashmap_remove(s->manager->sessions, s->id); + if (s->pipe_fd >= 0) + close_nointr_nofail(s->pipe_fd); + free(s->state_file); free(s); } @@ -104,7 +108,7 @@ int session_save(Session *s) { assert(s); - r = safe_mkdir("/run/systemd/session", 0755, 0, 0); + r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0); if (r < 0) goto finish; @@ -159,6 +163,11 @@ int session_save(Session *s) { "REMOTE_USER=%s\n", s->remote_user); + if (s->service) + fprintf(f, + "SERVICE=%s\n", + s->service); + if (s->seat && seat_is_vtconsole(s->seat)) fprintf(f, "VTNR=%i\n", @@ -213,9 +222,9 @@ int session_load(Session *s) { "DISPLAY", &s->display, "REMOTE_HOST", &s->remote_host, "REMOTE_USER", &s->remote_user, + "SERVICE", &s->service, "VTNR", &vtnr, "LEADER", &leader, - "AUDIT_ID", &audit_id, NULL); if (r < 0) @@ -253,16 +262,11 @@ int session_load(Session *s) { pid_t pid; k = parse_pid(leader, &pid); - if (k >= 0 && pid >= 1) + if (k >= 0 && pid >= 1) { s->leader = pid; - } - - if (audit_id) { - uint32_t l; - k = safe_atou32(audit_id, &l); - if (k >= 0 && l >= l) - s->audit_id = l; + audit_session_from_pid(pid, &s->audit_id); + } } finish: @@ -384,6 +388,28 @@ done: return 0; } +static int session_create_one_group(Session *s, const char *controller, const char *path) { + int r; + + assert(s); + assert(controller); + assert(path); + + if (s->leader > 0) + r = cg_create_and_attach(controller, path, s->leader); + else + r = cg_create(controller, path); + + if (r < 0) + return r; + + r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid); + if (r >= 0) + r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid); + + return r; +} + static int session_create_cgroup(Session *s) { char **k; char *p; @@ -401,11 +427,7 @@ static int session_create_cgroup(Session *s) { } else p = s->cgroup_path; - if (s->leader > 0) - r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, p, s->leader); - else - r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p); - + r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p); if (r < 0) { free(p); s->cgroup_path = NULL; @@ -415,14 +437,35 @@ static int session_create_cgroup(Session *s) { s->cgroup_path = p; + STRV_FOREACH(k, s->controllers) { + + if (strv_contains(s->reset_controllers, *k)) + continue; + + r = session_create_one_group(s, *k, p); + if (r < 0) + log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r)); + } + STRV_FOREACH(k, s->manager->controllers) { - if (s->leader > 0) - r = cg_create_and_attach(*k, p, s->leader); - else - r = cg_create(*k, p); + if (strv_contains(s->reset_controllers, *k) || + strv_contains(s->controllers, *k)) + continue; + + r = session_create_one_group(s, *k, p); if (r < 0) - log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r)); + log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r)); + } + + if (s->leader > 0) { + + STRV_FOREACH(k, s->reset_controllers) { + r = cg_attach(*k, "/", s->leader); + if (r < 0) + log_warning("Failed to reset controller %s: %s", *k, strerror(-r)); + + } } return 0; @@ -437,6 +480,8 @@ int session_start(Session *s) { if (s->started) return 0; + log_info("New session %s of user %s.", s->id, s->user->name); + /* Create cgroup */ r = session_create_cgroup(s); if (r < 0) @@ -542,6 +587,8 @@ int session_stop(Session *s) { if (!s->started) return 0; + log_info("Removed session %s.", s->id); + /* Kill cgroup */ k = session_kill_cgroup(s); if (k < 0) @@ -702,7 +749,8 @@ void session_add_to_gc_queue(Session *s) { static const char* const session_type_table[_SESSION_TYPE_MAX] = { [SESSION_TTY] = "tty", - [SESSION_X11] = "x11" + [SESSION_X11] = "x11", + [SESSION_OTHER] = "other" }; DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType); diff --git a/src/logind-session.h b/src/logind-session.h index d2f25523e..01c9504dd 100644 --- a/src/logind-session.h +++ b/src/logind-session.h @@ -33,6 +33,7 @@ typedef struct Session Session; typedef enum SessionType { SESSION_TTY, SESSION_X11, + SESSION_OTHER, _SESSION_TYPE_MAX, _SESSION_TYPE_INVALID = -1 } SessionType; @@ -56,6 +57,8 @@ struct Session { char *remote_user; char *remote_host; + char *service; + int vtnr; Seat *seat; diff --git a/src/logind-user.c b/src/logind-user.c index cb3e44197..8ebd6eca2 100644 --- a/src/logind-user.c +++ b/src/logind-user.c @@ -45,7 +45,7 @@ User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) { return NULL; } - if (asprintf(&u->state_file, "/run/systemd/user/%lu", (unsigned long) uid) < 0) { + if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) { free(u->name); free(u); return NULL; @@ -94,7 +94,7 @@ int user_save(User *u) { assert(u); assert(u->state_file); - r = safe_mkdir("/run/systemd/user", 0755, 0, 0); + r = safe_mkdir("/run/systemd/users", 0755, 0, 0); if (r < 0) goto finish; @@ -152,7 +152,7 @@ finish: int user_load(User *u) { int r; char *display = NULL; - Session *s; + Session *s = NULL; assert(u); @@ -172,8 +172,10 @@ int user_load(User *u) { return r; } - s = hashmap_get(u->manager->sessions, display); - free(display); + if (display) { + s = hashmap_get(u->manager->sessions, display); + free(display); + } if (s && s->display && x11_display_is_local(s->display)) u->display = s; diff --git a/src/logind.h b/src/logind.h index 1b7a2b239..7de8e3bcf 100644 --- a/src/logind.h +++ b/src/logind.h @@ -37,8 +37,8 @@ * recreate VTs when disallocated * PAM rewrite * spawn user systemd - * dbus API * direct client API + * subscribe to cgroup changes, fd HUP * * non-local X11 server * reboot/shutdown halt management @@ -76,11 +76,13 @@ struct Manager { Seat *vtconsole; char *cgroup_path; - char **controllers, **reset_controllers; + char **controllers; char **kill_only_users, **kill_exclude_users; bool kill_user_processes; + + unsigned long session_counter; }; Manager *manager_new(void); diff --git a/src/pam-module.c b/src/pam-module.c index bdf61334e..b742d649d 100644 --- a/src/pam-module.c +++ b/src/pam-module.c @@ -33,18 +33,17 @@ #include #include "util.h" -#include "cgroup-util.h" #include "macro.h" #include "sd-daemon.h" #include "strv.h" +#include "dbus-common.h" +#include "def.h" static int parse_argv(pam_handle_t *handle, int argc, const char **argv, - bool *create_session, - bool *kill_session, - bool *kill_user, char ***controllers, char ***reset_controllers, + bool *kill_processes, char ***kill_only_users, char ***kill_exclude_users, bool *debug) { @@ -59,32 +58,25 @@ static int parse_argv(pam_handle_t *handle, for (i = 0; i < (unsigned) argc; i++) { int k; - if (startswith(argv[i], "create-session=")) { + if (startswith(argv[i], "kill-processes=")) { if ((k = parse_boolean(argv[i] + 15)) < 0) { - pam_syslog(handle, LOG_ERR, "Failed to parse create-session= argument."); + pam_syslog(handle, LOG_ERR, "Failed to parse kill-session= argument."); return k; } - if (create_session) - *create_session = k; + if (kill_processes) + *kill_processes = k; } else if (startswith(argv[i], "kill-session=")) { + /* As compatibility for old versions */ + if ((k = parse_boolean(argv[i] + 13)) < 0) { pam_syslog(handle, LOG_ERR, "Failed to parse kill-session= argument."); return k; } - if (kill_session) - *kill_session = k; - - } else if (startswith(argv[i], "kill-user=")) { - if ((k = parse_boolean(argv[i] + 10)) < 0) { - pam_syslog(handle, LOG_ERR, "Failed to parse kill-user= argument."); - return k; - } - - if (kill_user) - *kill_user = k; + if (kill_processes) + *kill_processes = k; } else if (startswith(argv[i], "controllers=")) { @@ -155,6 +147,11 @@ static int parse_argv(pam_handle_t *handle, if (debug) *debug = k; + } else if (startswith(argv[i], "create-session=") || + startswith(argv[i], "kill-user=")) { + + pam_syslog(handle, LOG_WARNING, "Option %s not supported anymore, ignoring.", argv[i]); + } else { pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]); return -EINVAL; @@ -173,13 +170,10 @@ static int parse_argv(pam_handle_t *handle, } if (controllers) - strv_remove(*controllers, "name=systemd"); + strv_remove(*controllers, SYSTEMD_CGROUP_CONTROLLER); if (reset_controllers) - strv_remove(*reset_controllers, "name=systemd"); - - if (kill_session && *kill_session && kill_user) - *kill_user = true; + strv_remove(*reset_controllers, SYSTEMD_CGROUP_CONTROLLER); if (!kill_exclude_users_set && kill_exclude_users) { char **l; @@ -195,96 +189,6 @@ static int parse_argv(pam_handle_t *handle, return 0; } -static int open_file_and_lock(const char *fn) { - int fd; - - assert(fn); - - if ((fd = open(fn, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_CREAT, 0600)) < 0) - return -errno; - - /* The BSD socket semantics are a lot nicer than those of - * POSIX locks. Which is why we use flock() here. BSD locking - * does not work across NFS which however is not needed here - * as the filesystems in question should be local, and only - * locally accessible, and most likely even tmpfs. */ - - if (flock(fd, LOCK_EX) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - return fd; -} - -enum { - SESSION_ID_AUDIT = 'a', - SESSION_ID_COUNTER = 'c', - SESSION_ID_RANDOM = 'r' -}; - -static uint64_t get_session_id(int *mode) { - char *s; - int fd; - - assert(mode); - - /* First attempt: let's use the session ID of the audit - * system, if it is available. */ - if (have_effective_cap(CAP_AUDIT_CONTROL) > 0) - if (read_one_line_file("/proc/self/sessionid", &s) >= 0) { - uint32_t u; - int r; - - r = safe_atou32(s, &u); - free(s); - - if (r >= 0 && u != (uint32_t) -1 && u > 0) { - *mode = SESSION_ID_AUDIT; - return (uint64_t) u; - } - } - - /* Second attempt, use our own counter. */ - if ((fd = open_file_and_lock(RUNTIME_DIR "/user/.pam-systemd-session")) >= 0) { - uint64_t counter; - ssize_t r; - - /* We do a bit of endianess swapping here, just to be - * sure. /run should be machine specific anyway, and - * even mounted from tmpfs, so this byteswapping - * should really not be necessary. But then again, you - * never know, so let's avoid any risk. */ - - if (loop_read(fd, &counter, sizeof(counter), false) != sizeof(counter)) - counter = 1; - else - counter = le64toh(counter) + 1; - - if (lseek(fd, 0, SEEK_SET) == 0) { - uint64_t swapped = htole64(counter); - - r = loop_write(fd, &swapped, sizeof(swapped), false); - - if (r != sizeof(swapped)) - r = -EIO; - } else - r = -errno; - - close_nointr_nofail(fd); - - if (r >= 0) { - *mode = SESSION_ID_COUNTER; - return counter; - } - } - - *mode = SESSION_ID_RANDOM; - - /* Last attempt, pick a random value */ - return (uint64_t) random_ull(); -} - static int get_user_data( pam_handle_t *handle, const char **ret_username, @@ -346,232 +250,6 @@ static int get_user_data( return PAM_SUCCESS; } -static int create_user_group( - pam_handle_t *handle, - const char *controller, - const char *group, - struct passwd *pw, - bool attach, - bool remember) { - - int r; - - assert(handle); - assert(group); - - if (attach) - r = cg_create_and_attach(controller, group, 0); - else - r = cg_create(controller, group); - - if (r < 0) { - pam_syslog(handle, LOG_ERR, "Failed to create cgroup: %s", strerror(-r)); - return PAM_SESSION_ERR; - } - - if (r > 0 && remember) { - /* Remember that it was us who created this group, and - * that hence we need to remove it too. This is a - * protection against removing the cgroup when run - * recursively. */ - if ((r = pam_set_data(handle, "systemd.created", INT_TO_PTR(1), NULL)) != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to install created variable."); - return r; - } - } - - if ((r = cg_set_task_access(controller, group, 0644, pw->pw_uid, pw->pw_gid)) < 0 || - (r = cg_set_group_access(controller, group, 0755, pw->pw_uid, pw->pw_gid)) < 0) { - pam_syslog(handle, LOG_ERR, "Failed to change access modes: %s", strerror(-r)); - return PAM_SESSION_ERR; - } - - 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, - int argc, const char **argv) { - - const char *username = NULL; - struct passwd *pw; - int r; - char *buf = NULL; - int lock_fd = -1; - bool create_session = true; - bool debug = false; - char **controllers = NULL, **reset_controllers = NULL, **c; - char *cgroup_user_tree = NULL; - - assert(handle); - - /* pam_syslog(handle, LOG_DEBUG, "pam-systemd initializing"); */ - - /* Make this a NOP on non-systemd systems */ - if (sd_booted() <= 0) - return PAM_SUCCESS; - - if (parse_argv(handle, - argc, argv, - &create_session, NULL, NULL, - &controllers, &reset_controllers, - NULL, NULL, &debug) < 0) - return PAM_SESSION_ERR; - - 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; - 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; - goto finish; - } - - /* Create /run/user/$USER */ - free(buf); - if (asprintf(&buf, RUNTIME_DIR "/user/%s", username) < 0) { - r = PAM_BUF_ERR; - goto finish; - } - - if (safe_mkdir(buf, 0700, pw->pw_uid, pw->pw_gid) < 0) { - pam_syslog(handle, LOG_WARNING, "Failed to create runtime directory: %m"); - r = PAM_SYSTEM_ERR; - goto finish; - } else if ((r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", buf, 0)) != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); - goto finish; - } - - free(buf); - buf = NULL; - - if (create_session) { - const char *id; - - /* Reuse or create XDG session ID */ - if (!(id = pam_getenv(handle, "XDG_SESSION_ID"))) { - int mode; - - if (asprintf(&buf, "%llux", (unsigned long long) get_session_id(&mode)) < 0) { - r = PAM_BUF_ERR; - goto finish; - } - - /* To avoid id clashes we add the session id - * source to our session ids. Note that the - * session id source might change during - * runtime, because a filesystem became - * writable or the system reconfigured. */ - buf[strlen(buf)-1] = - mode != SESSION_ID_AUDIT ? (char) mode : 0; - - if ((r = pam_misc_setenv(handle, "XDG_SESSION_ID", buf, 0)) != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set session id."); - goto finish; - } - - if (!(id = pam_getenv(handle, "XDG_SESSION_ID"))) { - pam_syslog(handle, LOG_ERR, "Failed to get session id."); - r = PAM_SESSION_ERR; - goto finish; - } - } - - r = asprintf(&buf, "%s/%s/%s", cgroup_user_tree, username, id); - } else - r = asprintf(&buf, "%s/%s/master", cgroup_user_tree, username); - - if (r < 0) { - r = PAM_BUF_ERR; - goto finish; - } - - if (debug) - pam_syslog(handle, LOG_DEBUG, "Moving new user session for %s into control group %s.", username, buf); - - if ((r = create_user_group(handle, SYSTEMD_CGROUP_CONTROLLER, buf, pw, true, true)) != PAM_SUCCESS) - goto finish; - - /* The additional controllers don't really matter, so we - * ignore the return value */ - 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: - free(buf); - - if (lock_fd >= 0) - close_nointr_nofail(lock_fd); - - strv_free(controllers); - strv_free(reset_controllers); - - free(cgroup_user_tree); - - return r; -} - -static int session_remains(pam_handle_t *handle, const char *user_path) { - int r; - bool remains = false; - DIR *d; - char *subgroup; - - if ((r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, user_path, &d)) < 0) - return r; - - while ((r = cg_read_subgroup(d, &subgroup)) > 0) { - - remains = !streq(subgroup, "master"); - free(subgroup); - - if (remains) - break; - } - - closedir(d); - - if (r < 0) - return r; - - return !!remains; -} - static bool check_user_lists( pam_handle_t *handle, uid_t uid, @@ -588,7 +266,8 @@ static bool check_user_lists( else { struct passwd *pw; - if ((pw = pam_modutil_getpwuid(handle, uid))) + pw = pam_modutil_getpwuid(handle, uid); + if (pw) name = pw->pw_name; } @@ -620,158 +299,211 @@ static bool check_user_lists( return false; } -_public_ PAM_EXTERN int pam_sm_close_session( +_public_ PAM_EXTERN int pam_sm_open_session( pam_handle_t *handle, int flags, int argc, const char **argv) { const char *username = NULL; - bool kill_session = false; - bool kill_user = false; - bool debug = false; - 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, **kill_only_users = NULL, **kill_exclude_users = NULL; - char *cgroup_user_tree = NULL; + bool kill_processes = false, debug = false; + char **controllers = NULL, **reset_controllers = NULL, **kill_only_users = NULL, **kill_exclude_users = NULL; + int r; + DBusError error; + uint32_t uid, pid; + DBusMessageIter iter; + dbus_bool_t kp; + const char *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type; + int session_fd = -1; + DBusConnection *bus = NULL; + DBusMessage *m = NULL, *reply = NULL; + dbus_bool_t remote; assert(handle); + dbus_error_init(&error); + + pam_syslog(handle, LOG_ERR, "pam-systemd initializing"); + /* Make this a NOP on non-systemd systems */ if (sd_booted() <= 0) return PAM_SUCCESS; if (parse_argv(handle, argc, argv, - NULL, &kill_session, &kill_user, - &controllers, NULL, - &kill_only_users, &kill_exclude_users, &debug) < 0) + &controllers, &reset_controllers, + &kill_processes, &kill_only_users, &kill_exclude_users, + &debug) < 0) return PAM_SESSION_ERR; - if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS) + r = get_user_data(handle, &username, &pw); + if (r != 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 (kill_processes) + kill_processes = check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users); - 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; + bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); + if (!bus) { + pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", bus_error_message(&error)); + r = PAM_SESSION_ERR; goto finish; } - /* 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, 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, cgroup_user_tree, 0)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to move us away in %s hierarchy: %s", *c, strerror(-r)); + m = dbus_message_new_method_call( + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "CreateSession"); - if (asprintf(&user_path, "%s/%s", cgroup_user_tree, username) < 0) { + if (!m) { + pam_syslog(handle, LOG_ERR, "Could not allocate create session message."); r = PAM_BUF_ERR; goto finish; } - pam_get_data(handle, "systemd.created", &created); - - if ((id = pam_getenv(handle, "XDG_SESSION_ID")) && created) { + uid = pw->pw_uid; + pid = getpid(); + + pam_get_item(handle, PAM_SERVICE, (const void**) &service); + pam_get_item(handle, PAM_XDISPLAY, (const void**) &display); + pam_get_item(handle, PAM_TTY, (const void**) &tty); + pam_get_item(handle, PAM_RUSER, (const void**) &remote_user); + pam_get_item(handle, PAM_RHOST, (const void**) &remote_host); + + if (isempty(tty)) + service = ""; + if (isempty(tty)) + tty = ""; + if (isempty(display)) + display = ""; + if (isempty(remote_user)) + remote_user = ""; + if (isempty(remote_host)) + remote_host = ""; + seat = ""; + + type = !isempty(display) ? "x11" : + !isempty(tty) ? "tty" : "other"; + + remote = !isempty(remote_host) && !streq(remote_host, "localhost") && !streq(remote_host, "localhost.localdomain"); + + if (!dbus_message_append_args(m, + DBUS_TYPE_UINT32, &uid, + DBUS_TYPE_UINT32, &pid, + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &type, + DBUS_TYPE_STRING, &seat, + DBUS_TYPE_STRING, &tty, + DBUS_TYPE_STRING, &display, + DBUS_TYPE_BOOLEAN, &remote, + DBUS_TYPE_STRING, &remote_user, + DBUS_TYPE_STRING, &remote_host, + DBUS_TYPE_INVALID)) { + pam_syslog(handle, LOG_ERR, "Could not attach parameters to message."); + r = PAM_BUF_ERR; + goto finish; + } - 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; - } + dbus_message_iter_init_append(m, &iter); - if (kill_session && check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users)) { - if (debug) - pam_syslog(handle, LOG_DEBUG, "Killing remaining processes of user session %s of %s.", id, username); + r = bus_append_strv_iter(&iter, controllers); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Could not attach parameter to message."); + r = PAM_BUF_ERR; + goto finish; + } - /* Kill processes in session cgroup, and delete it */ - if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, session_path, true)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to kill session cgroup: %s", strerror(-r)); - } else { - if (debug) - pam_syslog(handle, LOG_DEBUG, "Moving remaining processes of user session %s of %s into control group %s.", id, username, nosession_path); + r = bus_append_strv_iter(&iter, reset_controllers); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Could not attach parameter to message."); + r = PAM_BUF_ERR; + goto finish; + } - /* Migrate processes from session to user - * cgroup. First, try to create the user group - * in case it doesn't exist yet. Also, delete - * the session group. */ - create_user_group(handle, SYSTEMD_CGROUP_CONTROLLER, nosession_path, pw, false, false); + kp = kill_processes; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &kp)) { + pam_syslog(handle, LOG_ERR, "Could not attach parameter to message."); + r = PAM_BUF_ERR; + goto finish; + } - if ((r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, session_path, nosession_path, false, true)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to migrate session cgroup: %s", strerror(-r)); - } + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); + if (!reply) { + pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error)); + r = PAM_SESSION_ERR; + goto finish; + } - STRV_FOREACH(c, controllers) { - create_user_group(handle, *c, nosession_path, pw, false, false); + if (!dbus_message_get_args(reply, &error, + DBUS_TYPE_STRING, &id, + DBUS_TYPE_OBJECT_PATH, &object_path, + DBUS_TYPE_STRING, &runtime_path, + DBUS_TYPE_UNIX_FD, &session_fd, + DBUS_TYPE_INVALID)) { + pam_syslog(handle, LOG_ERR, "Failed to parse message: %s", bus_error_message(&error)); + r = PAM_SESSION_ERR; + goto finish; + } - if ((r = cg_migrate_recursive(*c, session_path, nosession_path, false, true)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to migrate session cgroup in hierarchy %s: %s", *c, strerror(-r)); - } + r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set session id."); + goto finish; } - /* GC user tree */ - cg_trim(SYSTEMD_CGROUP_CONTROLLER, user_path, false); + r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", runtime_path, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); + goto finish; + } - if ((r = session_remains(handle, user_path)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to determine whether a session remains: %s", strerror(-r)); + r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to install session fd."); + return r; + } - /* Kill user processes not attached to any session */ - if (kill_user && r == 0 && check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users)) { + session_fd = -1; - /* Kill user cgroup */ - if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to kill user cgroup: %s", strerror(-r)); - } else { + r = PAM_SUCCESS; - if ((r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to check user cgroup: %s", strerror(-r)); +finish: + strv_free(controllers); + strv_free(reset_controllers); + strv_free(kill_only_users); + strv_free(kill_exclude_users); - /* Remove user cgroup */ - if (r > 0) { - if ((r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, user_path)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to delete user cgroup: %s", strerror(-r)); + dbus_error_free(&error); - /* If we managed to find somebody, don't cleanup the cgroup. */ - } else if (r == 0) - r = -EBUSY; + if (bus) { + dbus_connection_close(bus); + dbus_connection_unref(bus); } - STRV_FOREACH(c, controllers) - cg_trim(*c, user_path, true); - - if (r >= 0) { - const char *runtime_dir; + if (reply) + dbus_message_unref(reply); - if ((runtime_dir = pam_getenv(handle, "XDG_RUNTIME_DIR"))) - if ((r = rm_rf(runtime_dir, false, true)) < 0) - pam_syslog(handle, LOG_ERR, "Failed to remove runtime directory: %s", strerror(-r)); - } + if (m) + dbus_message_unref(m); - /* pam_syslog(handle, LOG_DEBUG, "pam-systemd done"); */ + if (session_fd >= 0) + close_nointr_nofail(session_fd); - r = PAM_SUCCESS; + return r; +} -finish: - if (lock_fd >= 0) - close_nointr_nofail(lock_fd); +_public_ PAM_EXTERN int pam_sm_close_session( + pam_handle_t *handle, + int flags, + int argc, const char **argv) { - free(session_path); - free(nosession_path); - free(user_path); + const void *p = NULL; - strv_free(controllers); - strv_free(kill_exclude_users); - strv_free(kill_only_users); + pam_get_data(handle, "systemd.session-fd", &p); - free(cgroup_user_tree); + if (p) + close_nointr(PTR_TO_INT(p) - 1); - return r; + return PAM_SUCCESS; } diff --git a/src/uaccess.c b/src/uaccess.c index e55ab51f3..524e4f003 100644 --- a/src/uaccess.c +++ b/src/uaccess.c @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) { path = argv[1]; seat = argv[2]; - p = strappend("/run/systemd/seat/", seat); + p = strappend("/run/systemd/seats/", seat); if (!p) { log_error("Out of memory."); goto finish; diff --git a/src/util.c b/src/util.c index 08529cc23..5d57d52dc 100644 --- a/src/util.c +++ b/src/util.c @@ -4040,8 +4040,31 @@ bool tty_is_vc(const char *tty) { if (startswith(tty, "/dev/")) tty += 5; - return startswith(tty, "tty") && - tty[3] >= '0' && tty[3] <= '9'; + return vtnr_from_tty(tty) >= 0; +} + +int vtnr_from_tty(const char *tty) { + int i, r; + + assert(tty); + + if (startswith(tty, "/dev/")) + tty += 5; + + if (!startswith(tty, "tty") ) + return -EINVAL; + + if (tty[3] < '0' || tty[3] > '9') + return -EINVAL; + + r = safe_atoi(tty+3, &i); + if (r < 0) + return r; + + if (i < 0 || i > 63) + return -EINVAL; + + return i; } const char *default_term_for_tty(const char *tty) { @@ -5068,6 +5091,38 @@ int symlink_or_copy_atomic(const char *from, const char *to) { return r; } +int audit_session_from_pid(pid_t pid, uint32_t *id) { + char *p, *s; + uint32_t u; + int r; + + assert(pid >= 1); + assert(id); + + if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0) + return -ENOENT; + + if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0) + return -ENOMEM; + + r = read_one_line_file(p, &s); + free(p); + if (r < 0) + return r; + + r = safe_atou32(s, &u); + free(s); + + if (r < 0) + return r; + + if (u == (uint32_t) -1 || u <= 0) + return -ENOENT; + + *id = u; + return 0; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/util.h b/src/util.h index 76e1d4faa..ceabe92cf 100644 --- a/src/util.h +++ b/src/util.h @@ -396,6 +396,7 @@ char *fstab_node_to_udev_node(const char *p); void filter_environ(const char *prefix); bool tty_is_vc(const char *tty); +int vtnr_from_tty(const char *tty); const char *default_term_for_tty(const char *tty); int detect_vm(const char **id); @@ -439,6 +440,8 @@ int hwclock_reset_localtime_delta(void); int hwclock_get_time(struct tm *tm); int hwclock_set_time(const struct tm *tm); +int audit_session_from_pid(pid_t pid, uint32_t *id); + #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) -- 2.30.2