diff --git a/SOURCES/0826-logind-optionally-watch-utmp-for-login-data.patch b/SOURCES/0826-logind-optionally-watch-utmp-for-login-data.patch new file mode 100644 index 0000000..dde4151 --- /dev/null +++ b/SOURCES/0826-logind-optionally-watch-utmp-for-login-data.patch @@ -0,0 +1,377 @@ +From d897789b4dc7d115c915842eabf33ed3de20110a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 7 Aug 2018 13:49:34 +0200 +Subject: [PATCH] logind: optionally watch utmp for login data + +This allows us to determine the TTY an ssh session is for, which is +useful to to proper idle detection for ssh sessions. + +Fixes: #9622 +(cherry picked from commit 3d0ef5c7e00155bc74f6f71c34cad518a4ff56ba) + +Related: #2122288 +--- + src/login/logind-core.c | 143 +++++++++++++++++++++++++++++++++++++ + src/login/logind-dbus.c | 5 ++ + src/login/logind-session.c | 24 +++++++ + src/login/logind-session.h | 14 +++- + src/login/logind.c | 10 +++ + src/login/logind.h | 8 +++ + 6 files changed, 203 insertions(+), 1 deletion(-) + +diff --git a/src/login/logind-core.c b/src/login/logind-core.c +index 0ed812a2c8..7e33f8e6aa 100644 +--- a/src/login/logind-core.c ++++ b/src/login/logind-core.c +@@ -5,6 +5,9 @@ + #include + #include + #include ++#if ENABLE_UTMP ++#include ++#endif + + #include "alloc-util.h" + #include "bus-error.h" +@@ -14,6 +17,7 @@ + #include "fd-util.h" + #include "logind.h" + #include "parse-util.h" ++#include "path-util.h" + #include "process-util.h" + #include "strv.h" + #include "terminal-util.h" +@@ -692,3 +696,142 @@ bool manager_all_buttons_ignored(Manager *m) { + + return true; + } ++ ++int manager_read_utmp(Manager *m) { ++#if ENABLE_UTMP ++ int r; ++ ++ assert(m); ++ ++ if (utmpxname(_PATH_UTMPX) < 0) ++ return log_error_errno(errno, "Failed to set utmp path to " _PATH_UTMPX ": %m"); ++ ++ setutxent(); ++ ++ for (;;) { ++ _cleanup_free_ char *t = NULL; ++ struct utmpx *u; ++ const char *c; ++ Session *s; ++ ++ errno = 0; ++ u = getutxent(); ++ if (!u) { ++ if (errno != 0) ++ log_warning_errno(errno, "Failed to read " _PATH_UTMPX ", ignoring: %m"); ++ r = 0; ++ break; ++ } ++ ++ if (u->ut_type != USER_PROCESS) ++ continue; ++ ++ if (!pid_is_valid(u->ut_pid)) ++ continue; ++ ++ t = strndup(u->ut_line, sizeof(u->ut_line)); ++ if (!t) { ++ r = log_oom(); ++ break; ++ } ++ ++ c = path_startswith(t, "/dev/"); ++ if (c) { ++ r = free_and_strdup(&t, c); ++ if (r < 0) { ++ log_oom(); ++ break; ++ } ++ } ++ ++ if (isempty(t)) ++ continue; ++ ++ s = hashmap_get(m->sessions_by_leader, PID_TO_PTR(u->ut_pid)); ++ if (!s) ++ continue; ++ ++ if (s->tty_validity == TTY_FROM_UTMP && !streq_ptr(s->tty, t)) { ++ /* This may happen on multiplexed SSH connection (i.e. 'SSH connection sharing'). In ++ * this case PAM and utmp sessions don't match. In such a case let's invalidate the TTY ++ * information and never acquire it again. */ ++ ++ s->tty = mfree(s->tty); ++ s->tty_validity = TTY_UTMP_INCONSISTENT; ++ log_debug("Session '%s' has inconsistent TTY information, dropping TTY information.", s->id); ++ continue; ++ } ++ ++ /* Never override what we figured out once */ ++ if (s->tty || s->tty_validity >= 0) ++ continue; ++ ++ s->tty = TAKE_PTR(t); ++ s->tty_validity = TTY_FROM_UTMP; ++ log_debug("Acquired TTY information '%s' from utmp for session '%s'.", s->tty, s->id); ++ } ++ ++ endutxent(); ++ return r; ++#else ++ return 0 ++#endif ++} ++ ++#if ENABLE_UTMP ++static int manager_dispatch_utmp(sd_event_source *s, const struct inotify_event *event, void *userdata) { ++ Manager *m = userdata; ++ ++ assert(m); ++ ++ /* If there's indication the file itself might have been removed or became otherwise unavailable, then let's ++ * reestablish the watch on whatever there's now. */ ++ if ((event->mask & (IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF|IN_Q_OVERFLOW|IN_UNMOUNT)) != 0) ++ manager_connect_utmp(m); ++ ++ (void) manager_read_utmp(m); ++ return 0; ++} ++#endif ++ ++void manager_connect_utmp(Manager *m) { ++#if ENABLE_UTMP ++ sd_event_source *s = NULL; ++ int r; ++ ++ assert(m); ++ ++ /* Watch utmp for changes via inotify. We do this to deal with tools such as ssh, which will register the PAM ++ * session early, and acquire a TTY only much later for the connection. Thus during PAM the TTY won't be known ++ * yet. ssh will register itself with utmp when it finally acquired the TTY. Hence, let's make use of this, and ++ * watch utmp for the TTY asynchronously. We use the PAM session's leader PID as key, to find the right entry. ++ * ++ * Yes, relying on utmp is pretty ugly, but it's good enough for informational purposes, as well as idle ++ * detection (which, for tty sessions, relies on the TTY used) */ ++ ++ r = sd_event_add_inotify(m->event, &s, _PATH_UTMPX, IN_MODIFY|IN_MOVE_SELF|IN_DELETE_SELF|IN_ATTRIB, manager_dispatch_utmp, m); ++ if (r < 0) ++ log_full_errno(r == -ENOENT ? LOG_DEBUG: LOG_WARNING, r, "Failed to create inotify watch on " _PATH_UTMPX ", ignoring: %m"); ++ else { ++ r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE); ++ if (r < 0) ++ log_warning_errno(r, "Failed to adjust utmp event source priority, ignoring: %m"); ++ ++ (void) sd_event_source_set_description(s, "utmp"); ++ } ++ ++ sd_event_source_unref(m->utmp_event_source); ++ m->utmp_event_source = s; ++#endif ++} ++ ++void manager_reconnect_utmp(Manager *m) { ++#if ENABLE_UTMP ++ assert(m); ++ ++ if (m->utmp_event_source) ++ return; ++ ++ manager_connect_utmp(m); ++#endif ++} +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 1bb152bc20..0248042308 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -772,6 +772,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus + } while (hashmap_get(m->sessions, id)); + } + ++ /* If we are not watching utmp aleady, try again */ ++ manager_reconnect_utmp(m); ++ + r = manager_add_user_by_uid(m, uid, &user); + if (r < 0) + goto fail; +@@ -795,6 +798,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus + r = -ENOMEM; + goto fail; + } ++ ++ session->tty_validity = TTY_FROM_PAM; + } + + if (!isempty(display)) { +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 1143a834a4..d666f86d3f 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -56,6 +56,7 @@ int session_new(Session **ret, Manager *m, const char *id) { + .fifo_fd = -1, + .vtfd = -1, + .audit_id = AUDIT_SESSION_INVALID, ++ .tty_validity = _TTY_VALIDITY_INVALID, + }; + + s->state_file = strappend("/run/systemd/sessions/", id); +@@ -219,6 +220,9 @@ int session_save(Session *s) { + if (s->tty) + fprintf(f, "TTY=%s\n", s->tty); + ++ if (s->tty_validity >= 0) ++ fprintf(f, "TTY_VALIDITY=%s\n", tty_validity_to_string(s->tty_validity)); ++ + if (s->display) + fprintf(f, "DISPLAY=%s\n", s->display); + +@@ -355,6 +359,7 @@ static int session_load_devices(Session *s, const char *devices) { + int session_load(Session *s) { + _cleanup_free_ char *remote = NULL, + *seat = NULL, ++ *tty_validity = NULL, + *vtnr = NULL, + *state = NULL, + *position = NULL, +@@ -380,6 +385,7 @@ int session_load(Session *s) { + "FIFO", &s->fifo_path, + "SEAT", &seat, + "TTY", &s->tty, ++ "TTY_VALIDITY", &tty_validity, + "DISPLAY", &s->display, + "REMOTE_HOST", &s->remote_host, + "REMOTE_USER", &s->remote_user, +@@ -456,6 +462,16 @@ int session_load(Session *s) { + seat_claim_position(s->seat, s, npos); + } + ++ if (tty_validity) { ++ TTYValidity v; ++ ++ v = tty_validity_from_string(tty_validity); ++ if (v < 0) ++ log_debug("Failed to parse TTY validity: %s", tty_validity); ++ else ++ s->tty_validity = v; ++ } ++ + if (leader) { + if (parse_pid(leader, &s->leader) >= 0) + (void) audit_session_from_pid(s->leader, &s->audit_id); +@@ -1368,3 +1384,11 @@ static const char* const kill_who_table[_KILL_WHO_MAX] = { + }; + + DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho); ++ ++static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = { ++ [TTY_FROM_PAM] = "from-pam", ++ [TTY_FROM_UTMP] = "from-utmp", ++ [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent", ++}; ++ ++DEFINE_STRING_TABLE_LOOKUP(tty_validity, TTYValidity); +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index 9bd0c96a03..7da845cea3 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -46,6 +46,14 @@ enum KillWho { + _KILL_WHO_INVALID = -1 + }; + ++typedef enum TTYValidity { ++ TTY_FROM_PAM, ++ TTY_FROM_UTMP, ++ TTY_UTMP_INCONSISTENT, /* may happen on ssh sessions with multiplexed TTYs */ ++ _TTY_VALIDITY_MAX, ++ _TTY_VALIDITY_INVALID = -1, ++} TTYValidity; ++ + struct Session { + Manager *manager; + +@@ -60,8 +68,9 @@ struct Session { + + dual_timestamp timestamp; + +- char *tty; + char *display; ++ char *tty; ++ TTYValidity tty_validity; + + bool remote; + char *remote_user; +@@ -159,6 +168,9 @@ SessionClass session_class_from_string(const char *s) _pure_; + const char *kill_who_to_string(KillWho k) _const_; + KillWho kill_who_from_string(const char *s) _pure_; + ++const char* tty_validity_to_string(TTYValidity t) _const_; ++TTYValidity tty_validity_from_string(const char *s) _pure_; ++ + int session_prepare_vt(Session *s); + void session_restore_vt(Session *s); + void session_leave_vt(Session *s); +diff --git a/src/login/logind.c b/src/login/logind.c +index 6c208c8e89..25de9a6ab2 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -132,6 +132,10 @@ static Manager* manager_unref(Manager *m) { + sd_event_source_unref(m->udev_button_event_source); + sd_event_source_unref(m->lid_switch_ignore_event_source); + ++#if ENABLE_UTMP ++ sd_event_source_unref(m->utmp_event_source); ++#endif ++ + safe_close(m->console_active_fd); + + udev_monitor_unref(m->udev_seat_monitor); +@@ -1095,6 +1099,9 @@ static int manager_startup(Manager *m) { + if (r < 0) + return log_error_errno(r, "Failed to register SIGHUP handler: %m"); + ++ /* Connect to utmp */ ++ manager_connect_utmp(m); ++ + /* Connect to console */ + r = manager_connect_console(m); + if (r < 0) +@@ -1150,6 +1157,9 @@ static int manager_startup(Manager *m) { + /* Reserve the special reserved VT */ + manager_reserve_vt(m); + ++ /* Read in utmp if it exists */ ++ manager_read_utmp(m); ++ + /* And start everything */ + HASHMAP_FOREACH(seat, m->seats, i) + seat_start(seat); +diff --git a/src/login/logind.h b/src/login/logind.h +index d29b01c75b..bb127bf4a5 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -43,6 +43,10 @@ struct Manager { + sd_event_source *udev_vcsa_event_source; + sd_event_source *udev_button_event_source; + ++#if ENABLE_UTMP ++ sd_event_source *utmp_event_source; ++#endif ++ + int console_active_fd; + + unsigned n_autovts; +@@ -150,6 +154,10 @@ bool manager_is_docked_or_external_displays(Manager *m); + bool manager_is_on_external_power(void); + bool manager_all_buttons_ignored(Manager *m); + ++int manager_read_utmp(Manager *m); ++void manager_connect_utmp(Manager *m); ++void manager_reconnect_utmp(Manager *m); ++ + extern const sd_bus_vtable manager_vtable[]; + + int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/SOURCES/0827-logind-add-hashtable-for-finding-session-by-leader-P.patch b/SOURCES/0827-logind-add-hashtable-for-finding-session-by-leader-P.patch new file mode 100644 index 0000000..c506df0 --- /dev/null +++ b/SOURCES/0827-logind-add-hashtable-for-finding-session-by-leader-P.patch @@ -0,0 +1,188 @@ +From fbc394252588325b6e7ecd1ab65ad40b51763c58 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 7 Aug 2018 12:08:24 +0200 +Subject: [PATCH] logind: add hashtable for finding session by leader PID + +This is useful later on, when we quickly want to find the session for a +leader PID. + +(cherry picked from commit 238794b15082e6f61d0ce2943d39205289fff7f0) + +Related: #2122288 +--- + src/login/logind-core.c | 15 ++++++++------ + src/login/logind-dbus.c | 3 +-- + src/login/logind-session.c | 41 +++++++++++++++++++++++++++++++++++--- + src/login/logind-session.h | 1 + + src/login/logind.c | 4 +++- + src/login/logind.h | 1 + + 6 files changed, 53 insertions(+), 12 deletions(-) + +diff --git a/src/login/logind-core.c b/src/login/logind-core.c +index 7e33f8e6aa..a1943b6f9d 100644 +--- a/src/login/logind-core.c ++++ b/src/login/logind-core.c +@@ -339,13 +339,16 @@ int manager_get_session_by_pid(Manager *m, pid_t pid, Session **ret) { + if (!pid_is_valid(pid)) + return -EINVAL; + +- r = cg_pid_get_unit(pid, &unit); +- if (r < 0) +- goto not_found; ++ s = hashmap_get(m->sessions_by_leader, PID_TO_PTR(pid)); ++ if (!s) { ++ r = cg_pid_get_unit(pid, &unit); ++ if (r < 0) ++ goto not_found; + +- s = hashmap_get(m->session_units, unit); +- if (!s) +- goto not_found; ++ s = hashmap_get(m->session_units, unit); ++ if (!s) ++ goto not_found; ++ } + + if (ret) + *ret = s; +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 0248042308..01bfef4ff7 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -784,9 +784,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus + goto fail; + + session_set_user(session, user); ++ session_set_leader(session, leader); + +- session->leader = leader; +- session->audit_id = audit_id; + session->type = t; + session->class = c; + session->remote = remote; +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index d666f86d3f..cc838ca383 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -121,6 +121,9 @@ Session* session_free(Session *s) { + free(s->scope); + } + ++ if (pid_is_valid(s->leader)) ++ (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s); ++ + free(s->scope_job); + + sd_bus_message_unref(s->create_message); +@@ -149,6 +152,30 @@ void session_set_user(Session *s, User *u) { + user_update_last_session_timer(u); + } + ++int session_set_leader(Session *s, pid_t pid) { ++ int r; ++ ++ assert(s); ++ ++ if (!pid_is_valid(pid)) ++ return -EINVAL; ++ ++ if (s->leader == pid) ++ return 0; ++ ++ r = hashmap_put(s->manager->sessions_by_leader, PID_TO_PTR(pid), s); ++ if (r < 0) ++ return r; ++ ++ if (pid_is_valid(s->leader)) ++ (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s); ++ ++ s->leader = pid; ++ (void) audit_session_from_pid(pid, &s->audit_id); ++ ++ return 1; ++} ++ + static void session_save_devices(Session *s, FILE *f) { + SessionDevice *sd; + Iterator i; +@@ -473,8 +500,16 @@ int session_load(Session *s) { + } + + if (leader) { +- if (parse_pid(leader, &s->leader) >= 0) +- (void) audit_session_from_pid(s->leader, &s->audit_id); ++ pid_t pid; ++ ++ r = parse_pid(leader, &pid); ++ if (r < 0) ++ log_debug_errno(r, "Failed to parse leader PID of session: %s", leader); ++ else { ++ r = session_set_leader(s, pid); ++ if (r < 0) ++ log_warning_errno(r, "Failed to set session leader PID, ignoring: %m"); ++ } + } + + if (type) { +@@ -910,7 +945,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) { + + /* For sessions with a leader but no explicitly configured + * tty, let's check the controlling tty of the leader */ +- if (s->leader > 0) { ++ if (pid_is_valid(s->leader)) { + r = get_process_ctty_atime(s->leader, &atime); + if (r >= 0) + goto found_atime; +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index 7da845cea3..8c7d0301f2 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -124,6 +124,7 @@ Session* session_free(Session *s); + DEFINE_TRIVIAL_CLEANUP_FUNC(Session *, session_free); + + void session_set_user(Session *s, User *u); ++int session_set_leader(Session *s, pid_t pid); + bool session_may_gc(Session *s, bool drop_not_started); + void session_add_to_gc_queue(Session *s); + int session_activate(Session *s); +diff --git a/src/login/logind.c b/src/login/logind.c +index 25de9a6ab2..6b576dad0d 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -46,6 +46,7 @@ static int manager_new(Manager **ret) { + m->devices = hashmap_new(&string_hash_ops); + m->seats = hashmap_new(&string_hash_ops); + m->sessions = hashmap_new(&string_hash_ops); ++ m->sessions_by_leader = hashmap_new(NULL); + m->users = hashmap_new(NULL); + m->inhibitors = hashmap_new(&string_hash_ops); + m->buttons = hashmap_new(&string_hash_ops); +@@ -53,7 +54,7 @@ static int manager_new(Manager **ret) { + m->user_units = hashmap_new(&string_hash_ops); + m->session_units = hashmap_new(&string_hash_ops); + +- if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units) ++ if (!m->devices || !m->seats || !m->sessions || !m->sessions_by_leader || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units) + return -ENOMEM; + + m->udev = udev_new(); +@@ -112,6 +113,7 @@ static Manager* manager_unref(Manager *m) { + hashmap_free(m->devices); + hashmap_free(m->seats); + hashmap_free(m->sessions); ++ hashmap_free(m->sessions_by_leader); + hashmap_free(m->users); + hashmap_free(m->inhibitors); + hashmap_free(m->buttons); +diff --git a/src/login/logind.h b/src/login/logind.h +index bb127bf4a5..7f94dea2f6 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -26,6 +26,7 @@ struct Manager { + Hashmap *devices; + Hashmap *seats; + Hashmap *sessions; ++ Hashmap *sessions_by_leader; + Hashmap *users; + Hashmap *inhibitors; + Hashmap *buttons; diff --git a/SOURCES/0828-core-load-fragment-move-config_parse_sec_fix_0-to-sr.patch b/SOURCES/0828-core-load-fragment-move-config_parse_sec_fix_0-to-sr.patch new file mode 100644 index 0000000..252084b --- /dev/null +++ b/SOURCES/0828-core-load-fragment-move-config_parse_sec_fix_0-to-sr.patch @@ -0,0 +1,93 @@ +From 69ec7c9170e29fdf745fa282448d051edd1f88b2 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 9 Aug 2022 11:41:04 +0200 +Subject: [PATCH] core/load-fragment: move config_parse_sec_fix_0 to src/shared + +(cherry picked from commit 4ee8176fe33bbcd0971c4583a0e7d1cc2a64ac06) + +Related: #2122288 +--- + src/core/load-fragment.c | 33 --------------------------------- + src/core/load-fragment.h | 1 - + src/shared/conf-parser.c | 2 ++ + src/shared/conf-parser.h | 1 + + 4 files changed, 3 insertions(+), 34 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index c0b1fd4f91..53de7ff5e9 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1865,39 +1865,6 @@ int config_parse_service_timeout( + return 0; + } + +-int config_parse_sec_fix_0( +- const char *unit, +- const char *filename, +- unsigned line, +- const char *section, +- unsigned section_line, +- const char *lvalue, +- int ltype, +- const char *rvalue, +- void *data, +- void *userdata) { +- +- usec_t *usec = data; +- int r; +- +- assert(filename); +- assert(lvalue); +- assert(rvalue); +- assert(usec); +- +- /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for +- * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a +- * timeout. */ +- +- r = parse_sec_fix_0(rvalue, usec); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue); +- return 0; +- } +- +- return 0; +-} +- + int config_parse_user_group_compat( + const char *unit, + const char *filename, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index f9d34d484d..b964737f9e 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -95,7 +95,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_bus_name); + CONFIG_PARSER_PROTOTYPE(config_parse_exec_utmp_mode); + CONFIG_PARSER_PROTOTYPE(config_parse_working_directory); + CONFIG_PARSER_PROTOTYPE(config_parse_fdname); +-CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0); + CONFIG_PARSER_PROTOTYPE(config_parse_user_group_compat); + CONFIG_PARSER_PROTOTYPE(config_parse_user_group_strv_compat); + CONFIG_PARSER_PROTOTYPE(config_parse_restrict_namespaces); +diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c +index 1f40f00c72..414dde2e3d 100644 +--- a/src/shared/conf-parser.c ++++ b/src/shared/conf-parser.c +@@ -1286,3 +1286,5 @@ int config_parse_permille(const char* unit, + + return 0; + } ++ ++DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0, parse_sec_fix_0, usec_t, "Failed to parse time value"); +diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h +index 375b2e5a74..56fd302db8 100644 +--- a/src/shared/conf-parser.h ++++ b/src/shared/conf-parser.h +@@ -142,6 +142,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ip_port); + CONFIG_PARSER_PROTOTYPE(config_parse_join_controllers); + CONFIG_PARSER_PROTOTYPE(config_parse_mtu); + CONFIG_PARSER_PROTOTYPE(config_parse_rlimit); ++CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0); + + typedef enum Disabled { + DISABLED_CONFIGURATION, diff --git a/SOURCES/0829-sd-event-add-relative-timer-calls.patch b/SOURCES/0829-sd-event-add-relative-timer-calls.patch new file mode 100644 index 0000000..ba40d6e --- /dev/null +++ b/SOURCES/0829-sd-event-add-relative-timer-calls.patch @@ -0,0 +1,123 @@ +From 30f5836253f820086caa24fc9283344615b8fc00 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 28 Jul 2020 11:17:00 +0200 +Subject: [PATCH] sd-event: add relative timer calls + +We frequently want to set a timer relative to the current time. Let's +add an explicit API for this. This not only saves us a few lines of code +everywhere and simplifies things, but also allows us to do correct +overflow checking. + +(cherry picked from commit d6a83dc48ad1981665ff427858ae8e59d4cfd6cb) + +Related: #2122288 +--- + src/libsystemd/libsystemd.sym | 8 +++++- + src/libsystemd/sd-event/sd-event.c | 42 ++++++++++++++++++++++++++++++ + src/systemd/sd-event.h | 2 ++ + 3 files changed, 51 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym +index 3b55fc6473..449918093c 100644 +--- a/src/libsystemd/libsystemd.sym ++++ b/src/libsystemd/libsystemd.sym +@@ -578,12 +578,18 @@ LIBSYSTEMD_240 { + sd_bus_get_method_call_timeout; + } LIBSYSTEMD_239; + ++LIBSYSTEMD_247 { ++global: ++ sd_event_add_time_relative; ++ sd_event_source_set_time_relative; ++} LIBSYSTEMD_240; ++ + LIBSYSTEMD_248 { + global: + sd_event_source_set_ratelimit; + sd_event_source_get_ratelimit; + sd_event_source_is_ratelimited; +-} LIBSYSTEMD_240; ++} LIBSYSTEMD_247; + + LIBSYSTEMD_250 { + global: +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 09d4584bf9..2c9d331bf2 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -1415,6 +1415,31 @@ fail: + return r; + } + ++_public_ int sd_event_add_time_relative( ++ sd_event *e, ++ sd_event_source **ret, ++ clockid_t clock, ++ uint64_t usec, ++ uint64_t accuracy, ++ sd_event_time_handler_t callback, ++ void *userdata) { ++ ++ usec_t t; ++ int r; ++ ++ /* Same as sd_event_add_time() but operates relative to the event loop's current point in time, and ++ * checks for overflow. */ ++ ++ r = sd_event_now(e, clock, &t); ++ if (r < 0) ++ return r; ++ ++ if (usec >= USEC_INFINITY - t) ++ return -EOVERFLOW; ++ ++ return sd_event_add_time(e, ret, clock, t + usec, accuracy, callback, userdata); ++} ++ + static int signal_exit_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + assert(s); + +@@ -2578,6 +2603,23 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { + return 0; + } + ++_public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec) { ++ usec_t t; ++ int r; ++ ++ assert_return(s, -EINVAL); ++ assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); ++ ++ r = sd_event_now(s->event, event_source_type_to_clock(s->type), &t); ++ if (r < 0) ++ return r; ++ ++ if (usec >= USEC_INFINITY - t) ++ return -EOVERFLOW; ++ ++ return sd_event_source_set_time(s, t + usec); ++} ++ + _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) { + assert_return(s, -EINVAL); + assert_return(usec, -EINVAL); +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index c2e9c9614d..960bea1ac4 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -87,6 +87,7 @@ sd_event* sd_event_unref(sd_event *e); + + int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata); + int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); ++int sd_event_add_time_relative(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); + int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata); + int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata); + int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata); +@@ -136,6 +137,7 @@ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events); + int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents); + int sd_event_source_get_time(sd_event_source *s, uint64_t *usec); + int sd_event_source_set_time(sd_event_source *s, uint64_t usec); ++int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec); + int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec); + int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec); + int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock); diff --git a/SOURCES/0830-logind-add-option-to-stop-idle-sessions-after-specif.patch b/SOURCES/0830-logind-add-option-to-stop-idle-sessions-after-specif.patch new file mode 100644 index 0000000..891a3da --- /dev/null +++ b/SOURCES/0830-logind-add-option-to-stop-idle-sessions-after-specif.patch @@ -0,0 +1,233 @@ +From 24439b08e3a3437b423553c385cde1d4cddf18f6 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 8 Aug 2022 09:13:50 +0200 +Subject: [PATCH] logind: add option to stop idle sessions after specified + timeout + +Thanks to Jan Pazdziora for providing a patch +which implemeted a PoC of this feature. + +(cherry picked from commit 82325af3ae41bc7efb3d5cd8f56a4652fef498c2) + +Resolves: #2122288 +--- + man/logind.conf.xml | 11 ++++++ + src/login/logind-core.c | 2 + + src/login/logind-dbus.c | 1 + + src/login/logind-gperf.gperf | 1 + + src/login/logind-session.c | 72 +++++++++++++++++++++++++++++++++--- + src/login/logind-session.h | 2 + + src/login/logind.conf.in | 1 + + src/login/logind.h | 2 + + 8 files changed, 86 insertions(+), 6 deletions(-) + +diff --git a/man/logind.conf.xml b/man/logind.conf.xml +index 0cf8a7d1f2..00b5b1f2e8 100644 +--- a/man/logind.conf.xml ++++ b/man/logind.conf.xml +@@ -333,6 +333,17 @@ + are excluded from the effect of this setting. Defaults to no. + + ++ ++ StopIdleSessionSec= ++ ++ Specifies a timeout in seconds, or a time span value after which ++ systemd-logind checks the idle state of all sessions. Every session that is idle for ++ longer then the timeout will be stopped. Defaults to infinity ++ (systemd-logind is not checking the idle state of sessions). For details about the syntax ++ of time spans, see ++ systemd.time7. ++ ++ + + + +diff --git a/src/login/logind-core.c b/src/login/logind-core.c +index a1943b6f9d..abe6eecffb 100644 +--- a/src/login/logind-core.c ++++ b/src/login/logind-core.c +@@ -58,6 +58,8 @@ void manager_reset_config(Manager *m) { + + m->kill_only_users = strv_free(m->kill_only_users); + m->kill_exclude_users = strv_free(m->kill_exclude_users); ++ ++ m->stop_idle_session_usec = USEC_INFINITY; + } + + int manager_parse_config_file(Manager *m) { +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 01bfef4ff7..81aacb4eed 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -2720,6 +2720,7 @@ const sd_bus_vtable manager_vtable[] = { + SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_hashmap_size, offsetof(Manager, sessions), 0), + SD_BUS_PROPERTY("UserTasksMax", "t", property_get_compat_user_tasks_max, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), ++ SD_BUS_PROPERTY("StopIdleSessionUSec", "t", NULL, offsetof(Manager, stop_idle_session_usec), SD_BUS_VTABLE_PROPERTY_CONST), + + SD_BUS_METHOD_WITH_NAMES("GetSession", + "s", +diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf +index 8829ce7d85..214ac5c4a3 100644 +--- a/src/login/logind-gperf.gperf ++++ b/src/login/logind-gperf.gperf +@@ -42,3 +42,4 @@ Login.RemoveIPC, config_parse_bool, 0, offse + Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max) + Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max) + Login.UserTasksMax, config_parse_compat_user_tasks_max, 0, offsetof(Manager, user_tasks_max) ++Login.StopIdleSessionSec, config_parse_sec_fix_0, 0, offsetof(Manager, stop_idle_session_usec) +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index cc838ca383..56f40fbec4 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -29,6 +29,7 @@ + #include "string-table.h" + #include "strv.h" + #include "terminal-util.h" ++#include "time-util.h" + #include "user-util.h" + #include "util.h" + +@@ -139,6 +140,8 @@ Session* session_free(Session *s) { + + free(s->state_file); + ++ sd_event_source_unref(s->stop_on_idle_event_source); ++ + return mfree(s); + } + +@@ -658,6 +661,55 @@ static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_er + return 0; + } + ++static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, void *userdata) { ++ Session *s = userdata; ++ dual_timestamp ts; ++ int r, idle; ++ ++ assert(s); ++ ++ if (s->stopping) ++ return 0; ++ ++ idle = session_get_idle_hint(s, &ts); ++ if (idle) { ++ log_debug("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->name); ++ ++ return session_stop(s, /* force */ true); ++ } ++ ++ r = sd_event_source_set_time(source, usec_add(ts.monotonic, s->manager->stop_idle_session_usec)); ++ if (r < 0) ++ return log_error_errno(r, "Failed to configure stop on idle session event source: %m"); ++ ++ r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); ++ if (r < 0) ++ return log_error_errno(r, "Failed to enable stop on idle session event source: %m"); ++ ++ return 1; ++} ++ ++static int session_setup_stop_on_idle_timer(Session *s) { ++ int r; ++ ++ assert(s); ++ ++ if (s->manager->stop_idle_session_usec == USEC_INFINITY) ++ return 0; ++ ++ r = sd_event_add_time_relative( ++ s->manager->event, ++ &s->stop_on_idle_event_source, ++ CLOCK_MONOTONIC, ++ s->manager->stop_idle_session_usec, ++ 0, ++ session_dispatch_stop_on_idle, s); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add stop on idle session event source: %m"); ++ ++ return 0; ++} ++ + int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) { + int r; + +@@ -680,6 +732,10 @@ int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) { + if (r < 0) + return r; + ++ r = session_setup_stop_on_idle_timer(s); ++ if (r < 0) ++ return r; ++ + log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, + "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR, + "SESSION_ID=%s", s->id, +@@ -917,7 +973,7 @@ static int get_process_ctty_atime(pid_t pid, usec_t *atime) { + } + + int session_get_idle_hint(Session *s, dual_timestamp *t) { +- usec_t atime = 0, n; ++ usec_t atime = 0, dtime = 0; + int r; + + assert(s); +@@ -961,12 +1017,16 @@ found_atime: + if (t) + dual_timestamp_from_realtime(t, atime); + +- n = now(CLOCK_REALTIME); +- +- if (s->manager->idle_action_usec <= 0) +- return 0; ++ if (s->manager->idle_action_usec > 0 && s->manager->stop_idle_session_usec != USEC_INFINITY) ++ dtime = MIN(s->manager->idle_action_usec, s->manager->stop_idle_session_usec); ++ else if (s->manager->idle_action_usec > 0) ++ dtime = s->manager->idle_action_usec; ++ else if (s->manager->stop_idle_session_usec != USEC_INFINITY) ++ dtime = s->manager->stop_idle_session_usec; ++ else ++ return false; + +- return atime + s->manager->idle_action_usec <= n; ++ return usec_add(atime, dtime) <= now(CLOCK_REALTIME); + } + + void session_set_idle_hint(Session *s, bool b) { +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index 8c7d0301f2..6678441bb9 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -112,6 +112,8 @@ struct Session { + Hashmap *devices; + sd_bus_track *track; + ++ sd_event_source *stop_on_idle_event_source; ++ + LIST_FIELDS(Session, sessions_by_user); + LIST_FIELDS(Session, sessions_by_seat); + +diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in +index c7346f9819..a62c2b0b57 100644 +--- a/src/login/logind.conf.in ++++ b/src/login/logind.conf.in +@@ -35,3 +35,4 @@ + #RemoveIPC=no + #InhibitorsMax=8192 + #SessionsMax=8192 ++#StopIdleSessionSec=infinity +diff --git a/src/login/logind.h b/src/login/logind.h +index 7f94dea2f6..606adf4fe6 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -102,6 +102,8 @@ struct Manager { + usec_t idle_action_not_before_usec; + HandleAction idle_action; + ++ usec_t stop_idle_session_usec; ++ + HandleAction handle_power_key; + HandleAction handle_suspend_key; + HandleAction handle_hibernate_key; diff --git a/SOURCES/0831-logind-schedule-idle-check-full-interval-from-now-if.patch b/SOURCES/0831-logind-schedule-idle-check-full-interval-from-now-if.patch new file mode 100644 index 0000000..8a10fc4 --- /dev/null +++ b/SOURCES/0831-logind-schedule-idle-check-full-interval-from-now-if.patch @@ -0,0 +1,29 @@ +From e48edc1b923267a5fcc808c3eb7151bf460a68ba Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 9 Sep 2022 13:38:58 +0200 +Subject: [PATCH] logind: schedule idle check full interval from now if we + couldn't figure out atime timestamp + +(cherry picked from commit 6edf707fd59347024fa6be0342b108527825db1f) + +Related: #2122288 +--- + src/login/logind-session.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 56f40fbec4..18a07efcdb 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -678,7 +678,10 @@ static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, vo + return session_stop(s, /* force */ true); + } + +- r = sd_event_source_set_time(source, usec_add(ts.monotonic, s->manager->stop_idle_session_usec)); ++ r = sd_event_source_set_time( ++ source, ++ usec_add(dual_timestamp_is_set(&ts) ? ts.monotonic : now(CLOCK_MONOTONIC), ++ s->manager->stop_idle_session_usec)); + if (r < 0) + return log_error_errno(r, "Failed to configure stop on idle session event source: %m"); + diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index 079c082..9692c92 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -13,7 +13,7 @@ Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd Version: 239 -Release: 67%{?dist} +Release: 68%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -875,6 +875,12 @@ Patch0822: 0822-shutdown-get-only-active-md-arrays.patch Patch0823: 0823-scope-allow-unprivileged-delegation-on-scopes.patch Patch0824: 0824-resolved-pin-stream-while-calling-callbacks-for-it.patch Patch0825: 0825-ci-functions-Add-useradd-and-userdel.patch +Patch0826: 0826-logind-optionally-watch-utmp-for-login-data.patch +Patch0827: 0827-logind-add-hashtable-for-finding-session-by-leader-P.patch +Patch0828: 0828-core-load-fragment-move-config_parse_sec_fix_0-to-sr.patch +Patch0829: 0829-sd-event-add-relative-timer-calls.patch +Patch0830: 0830-logind-add-option-to-stop-idle-sessions-after-specif.patch +Patch0831: 0831-logind-schedule-idle-check-full-interval-from-now-if.patch %ifarch %{ix86} x86_64 aarch64 %global have_gnu_efi 1 @@ -1504,6 +1510,14 @@ fi %files tests -f .file-list-tests %changelog +* Tue Sep 27 2022 systemd maintenance team - 239-68 +- logind: optionally watch utmp for login data (#2122288) +- logind: add hashtable for finding session by leader PID (#2122288) +- core/load-fragment: move config_parse_sec_fix_0 to src/shared (#2122288) +- sd-event: add relative timer calls (#2122288) +- logind: add option to stop idle sessions after specified timeout (#2122288) +- logind: schedule idle check full interval from now if we couldn't figure out atime timestamp (#2122288) + * Fri Aug 26 2022 systemd maintenance team - 239-67 - resolved: pin stream while calling callbacks for it (#2110549) - ci(functions): Add `useradd` and `userdel` (#2110549)