1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/epoll.h>
28 #include <systemd/sd-id128.h>
29 #include <systemd/sd-messages.h>
34 #include "path-util.h"
35 #include "cgroup-util.h"
37 #include "dbus-common.h"
38 #include "logind-session.h"
40 Session* session_new(Manager *m, const char *id) {
50 s->state_file = strappend("/run/systemd/sessions/", id);
56 s->id = path_get_file_name(s->state_file);
58 if (hashmap_put(m->sessions, s->id, s) < 0) {
70 void session_free(Session *s) {
74 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
77 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
79 if (s->user->display == s)
80 s->user->display = NULL;
84 if (s->seat->active == s)
85 s->seat->active = NULL;
87 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
91 hashmap_remove(s->manager->session_units, s->scope);
97 if (s->create_message)
98 dbus_message_unref(s->create_message);
102 free(s->remote_host);
103 free(s->remote_user);
106 hashmap_remove(s->manager->sessions, s->id);
107 session_remove_fifo(s);
113 void session_set_user(Session *s, User *u) {
118 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
121 int session_save(Session *s) {
122 _cleanup_fclose_ FILE *f = NULL;
123 _cleanup_free_ char *temp_path = NULL;
134 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
138 r = fopen_temporary(s->state_file, &f, &temp_path);
144 fchmod(fileno(f), 0644);
147 "# This is private data. Do not parse.\n"
153 (unsigned long) s->user->uid,
155 session_is_active(s),
156 session_state_to_string(session_get_state(s)),
160 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
163 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
166 fprintf(f, "SCOPE=%s\n", s->scope);
169 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
172 fprintf(f, "FIFO=%s\n", s->fifo_path);
175 fprintf(f, "SEAT=%s\n", s->seat->id);
178 fprintf(f, "TTY=%s\n", s->tty);
181 fprintf(f, "DISPLAY=%s\n", s->display);
184 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
187 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
190 fprintf(f, "SERVICE=%s\n", s->service);
192 if (s->seat && seat_can_multi_session(s->seat))
193 fprintf(f, "VTNR=%i\n", s->vtnr);
196 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
199 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
201 if (dual_timestamp_is_set(&s->timestamp))
205 (unsigned long long) s->timestamp.realtime,
206 (unsigned long long) s->timestamp.monotonic);
210 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
212 unlink(s->state_file);
218 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
223 int session_load(Session *s) {
224 _cleanup_free_ char *remote = NULL,
239 r = parse_env_file(s->state_file, NEWLINE,
242 "SCOPE_JOB", &s->scope_job,
243 "FIFO", &s->fifo_path,
246 "DISPLAY", &s->display,
247 "REMOTE_HOST", &s->remote_host,
248 "REMOTE_USER", &s->remote_user,
249 "SERVICE", &s->service,
255 "REALTIME", &realtime,
256 "MONOTONIC", &monotonic,
260 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
269 log_error("UID not specified for session %s", s->id);
273 r = parse_uid(uid, &u);
275 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
279 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
281 log_error("User of session %s not known.", s->id);
285 session_set_user(s, user);
289 k = parse_boolean(remote);
294 if (seat && !s->seat) {
297 o = hashmap_get(s->manager->seats, seat);
299 seat_attach_session(o, s);
302 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
305 k = safe_atoi(vtnr, &v);
306 if (k >= 0 && v >= 1)
311 k = parse_pid(leader, &s->leader);
313 audit_session_from_pid(s->leader, &s->audit_id);
319 t = session_type_from_string(type);
327 c = session_class_from_string(class);
335 /* If we open an unopened pipe for reading we will not
336 get an EOF. to trigger an EOF we hence open it for
337 reading, but close it right-away which then will
340 fd = session_create_fifo(s);
342 close_nointr_nofail(fd);
346 unsigned long long l;
347 if (sscanf(realtime, "%llu", &l) > 0)
348 s->timestamp.realtime = l;
352 unsigned long long l;
353 if (sscanf(monotonic, "%llu", &l) > 0)
354 s->timestamp.monotonic = l;
360 int session_activate(Session *s) {
372 if (s->seat->active == s)
375 assert(seat_is_vtconsole(s->seat));
381 return seat_set_active(s->seat, s);
384 static int session_link_x11_socket(Session *s) {
390 assert(s->user->runtime_path);
392 if (s->user->display)
395 if (!s->display || !display_is_local(s->display))
398 k = strspn(s->display+1, "0123456789");
399 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
403 c = stpcpy(f, "/tmp/.X11-unix/X");
404 memcpy(c, s->display+1, k);
407 if (access(f, F_OK) < 0) {
408 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
413 /* Note that this cannot be in a subdir to avoid
414 * vulnerabilities since we are privileged but the runtime
415 * path is owned by the user */
417 t = strappend(s->user->runtime_path, "/X11-display");
423 if (link(f, t) < 0) {
424 if (errno == EEXIST) {
431 if (symlink(f, t) < 0) {
433 if (errno == EEXIST) {
436 if (symlink(f, t) >= 0)
440 log_error("Failed to link %s to %s: %m", f, t);
448 log_info("Linked %s to %s.", f, t);
452 s->user->display = s;
457 static int session_start_scope(Session *s) {
463 assert(s->user->slice);
465 dbus_error_init(&error);
468 _cleanup_free_ char *description = NULL;
471 scope = strjoin("session-", s->id, ".scope", NULL);
475 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
477 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", &error, &job);
479 log_error("Failed to start session scope: %s %s", bus_error(&error, r), error.name);
480 dbus_error_free(&error);
493 hashmap_put(s->manager->session_units, s->scope, s);
498 int session_start(Session *s) {
509 r = user_start(s->user);
514 r = session_start_scope(s);
518 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
519 MESSAGE_ID(SD_MESSAGE_SESSION_START),
520 "SESSION_ID=%s", s->id,
521 "USER_ID=%s", s->user->name,
522 "LEADER=%lu", (unsigned long) s->leader,
523 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
526 /* Create X11 symlink */
527 session_link_x11_socket(s);
529 if (!dual_timestamp_is_set(&s->timestamp))
530 dual_timestamp_get(&s->timestamp);
533 seat_read_active_vt(s->seat);
537 /* Save session data */
541 session_send_signal(s, true);
546 if (s->seat->active == s)
547 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
549 seat_send_changed(s->seat, "Sessions\0");
552 user_send_changed(s->user, "Sessions\0");
557 /* static bool session_shall_kill(Session *s) { */
560 /* if (!s->kill_processes) */
563 /* if (strv_contains(s->manager->kill_exclude_users, s->user->name)) */
566 /* if (strv_isempty(s->manager->kill_only_users)) */
569 /* return strv_contains(s->manager->kill_only_users, s->user->name); */
572 static int session_stop_scope(Session *s) {
579 dbus_error_init(&error);
584 r = manager_stop_unit(s->manager, s->scope, &error, &job);
586 log_error("Failed to stop session scope: %s", bus_error(&error, r));
587 dbus_error_free(&error);
597 static int session_unlink_x11_socket(Session *s) {
604 if (s->user->display != s)
607 s->user->display = NULL;
609 t = strappend(s->user->runtime_path, "/X11-display");
616 return r < 0 ? -errno : 0;
619 int session_stop(Session *s) {
628 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
629 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
630 "SESSION_ID=%s", s->id,
631 "USER_ID=%s", s->user->name,
632 "LEADER=%lu", (unsigned long) s->leader,
633 "MESSAGE=Removed session %s.", s->id,
637 k = session_stop_scope(s);
641 /* Remove X11 symlink */
642 session_unlink_x11_socket(s);
644 unlink(s->state_file);
645 session_add_to_gc_queue(s);
646 user_add_to_gc_queue(s->user);
649 session_send_signal(s, false);
654 if (s->seat->active == s)
655 seat_set_active(s->seat, NULL);
657 seat_send_changed(s->seat, "Sessions\0");
661 user_send_changed(s->user, "Sessions\0");
667 bool session_is_active(Session *s) {
673 return s->seat->active == s;
676 static int get_tty_atime(const char *tty, usec_t *atime) {
677 _cleanup_free_ char *p = NULL;
683 if (!path_is_absolute(tty)) {
684 p = strappend("/dev/", tty);
689 } else if (!path_startswith(tty, "/dev/"))
692 if (lstat(tty, &st) < 0)
695 *atime = timespec_load(&st.st_atim);
699 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
700 _cleanup_free_ char *p = NULL;
706 r = get_ctty(pid, NULL, &p);
710 return get_tty_atime(p, atime);
713 int session_get_idle_hint(Session *s, dual_timestamp *t) {
719 /* Explicit idle hint is set */
722 *t = s->idle_hint_timestamp;
727 /* Graphical sessions should really implement a real
732 /* For sessions with an explicitly configured tty, let's check
735 r = get_tty_atime(s->tty, &atime);
740 /* For sessions with a leader but no explicitly configured
741 * tty, let's check the controlling tty of the leader */
743 r = get_process_ctty_atime(s->leader, &atime);
750 *t = s->idle_hint_timestamp;
756 dual_timestamp_from_realtime(t, atime);
758 n = now(CLOCK_REALTIME);
760 if (s->manager->idle_action_usec <= 0)
763 return atime + s->manager->idle_action_usec <= n;
766 void session_set_idle_hint(Session *s, bool b) {
769 if (s->idle_hint == b)
773 dual_timestamp_get(&s->idle_hint_timestamp);
775 session_send_changed(s,
778 "IdleSinceHintMonotonic\0");
781 seat_send_changed(s->seat,
784 "IdleSinceHintMonotonic\0");
786 user_send_changed(s->user,
789 "IdleSinceHintMonotonic\0");
791 manager_send_changed(s->manager,
794 "IdleSinceHintMonotonic\0");
797 int session_create_fifo(Session *s) {
804 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
808 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
811 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
815 /* Open reading side */
816 if (s->fifo_fd < 0) {
817 struct epoll_event ev = {};
819 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
823 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
828 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
830 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
834 /* Open writing side */
835 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
842 void session_remove_fifo(Session *s) {
845 if (s->fifo_fd >= 0) {
846 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
847 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
848 close_nointr_nofail(s->fifo_fd);
856 unlink(s->fifo_path);
862 int session_check_gc(Session *s, bool drop_not_started) {
867 if (drop_not_started && !s->started)
873 if (s->fifo_fd >= 0) {
875 r = pipe_eof(s->fifo_fd);
887 return manager_unit_is_active(s->manager, s->scope) != 0;
892 void session_add_to_gc_queue(Session *s) {
898 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
899 s->in_gc_queue = true;
902 SessionState session_get_state(Session *s) {
906 return s->started ? SESSION_OPENING : SESSION_CLOSING;
909 return SESSION_CLOSING;
911 if (session_is_active(s))
912 return SESSION_ACTIVE;
914 return SESSION_ONLINE;
917 int session_kill(Session *s, KillWho who, int signo) {
923 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
926 static const char* const session_state_table[_SESSION_STATE_MAX] = {
927 [SESSION_OPENING] = "opening",
928 [SESSION_ONLINE] = "online",
929 [SESSION_ACTIVE] = "active",
930 [SESSION_CLOSING] = "closing"
933 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
935 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
936 [SESSION_TTY] = "tty",
937 [SESSION_X11] = "x11",
938 [SESSION_UNSPECIFIED] = "unspecified"
941 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
943 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
944 [SESSION_USER] = "user",
945 [SESSION_GREETER] = "greeter",
946 [SESSION_LOCK_SCREEN] = "lock-screen",
947 [SESSION_BACKGROUND] = "background"
950 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
952 static const char* const kill_who_table[_KILL_WHO_MAX] = {
953 [KILL_LEADER] = "leader",
957 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);