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"
36 #include "dbus-common.h"
37 #include "logind-session.h"
39 Session* session_new(Manager *m, const char *id) {
49 s->state_file = strappend("/run/systemd/sessions/", id);
55 s->id = path_get_file_name(s->state_file);
57 if (hashmap_put(m->sessions, s->id, s) < 0) {
69 void session_free(Session *s) {
73 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
76 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
78 if (s->user->display == s)
79 s->user->display = NULL;
83 if (s->seat->active == s)
84 s->seat->active = NULL;
86 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
90 hashmap_remove(s->manager->session_units, s->scope);
96 if (s->create_message)
97 dbus_message_unref(s->create_message);
101 free(s->remote_host);
102 free(s->remote_user);
105 hashmap_remove(s->manager->sessions, s->id);
106 session_remove_fifo(s);
112 void session_set_user(Session *s, User *u) {
117 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
120 int session_save(Session *s) {
121 _cleanup_fclose_ FILE *f = NULL;
122 _cleanup_free_ char *temp_path = NULL;
133 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
137 r = fopen_temporary(s->state_file, &f, &temp_path);
143 fchmod(fileno(f), 0644);
146 "# This is private data. Do not parse.\n"
152 (unsigned long) s->user->uid,
154 session_is_active(s),
155 session_state_to_string(session_get_state(s)),
159 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
162 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
165 fprintf(f, "SCOPE=%s\n", s->scope);
168 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
171 fprintf(f, "FIFO=%s\n", s->fifo_path);
174 fprintf(f, "SEAT=%s\n", s->seat->id);
177 fprintf(f, "TTY=%s\n", s->tty);
180 fprintf(f, "DISPLAY=%s\n", s->display);
183 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
186 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
189 fprintf(f, "SERVICE=%s\n", s->service);
191 if (s->seat && seat_can_multi_session(s->seat))
192 fprintf(f, "VTNR=%i\n", s->vtnr);
195 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
198 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
200 if (dual_timestamp_is_set(&s->timestamp))
204 (unsigned long long) s->timestamp.realtime,
205 (unsigned long long) s->timestamp.monotonic);
209 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
211 unlink(s->state_file);
217 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
222 int session_load(Session *s) {
223 _cleanup_free_ char *remote = NULL,
238 r = parse_env_file(s->state_file, NEWLINE,
241 "SCOPE_JOB", &s->scope_job,
242 "FIFO", &s->fifo_path,
245 "DISPLAY", &s->display,
246 "REMOTE_HOST", &s->remote_host,
247 "REMOTE_USER", &s->remote_user,
248 "SERVICE", &s->service,
254 "REALTIME", &realtime,
255 "MONOTONIC", &monotonic,
259 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
268 log_error("UID not specified for session %s", s->id);
272 r = parse_uid(uid, &u);
274 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
278 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
280 log_error("User of session %s not known.", s->id);
284 session_set_user(s, user);
288 k = parse_boolean(remote);
293 if (seat && !s->seat) {
296 o = hashmap_get(s->manager->seats, seat);
298 seat_attach_session(o, s);
301 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
304 k = safe_atoi(vtnr, &v);
305 if (k >= 0 && v >= 1)
310 k = parse_pid(leader, &s->leader);
312 audit_session_from_pid(s->leader, &s->audit_id);
318 t = session_type_from_string(type);
326 c = session_class_from_string(class);
334 /* If we open an unopened pipe for reading we will not
335 get an EOF. to trigger an EOF we hence open it for
336 reading, but close it right-away which then will
339 fd = session_create_fifo(s);
341 close_nointr_nofail(fd);
345 unsigned long long l;
346 if (sscanf(realtime, "%llu", &l) > 0)
347 s->timestamp.realtime = l;
351 unsigned long long l;
352 if (sscanf(monotonic, "%llu", &l) > 0)
353 s->timestamp.monotonic = l;
359 int session_activate(Session *s) {
371 if (s->seat->active == s)
374 assert(seat_is_vtconsole(s->seat));
380 return seat_set_active(s->seat, s);
383 static int session_link_x11_socket(Session *s) {
389 assert(s->user->runtime_path);
391 if (s->user->display)
394 if (!s->display || !display_is_local(s->display))
397 k = strspn(s->display+1, "0123456789");
398 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
402 c = stpcpy(f, "/tmp/.X11-unix/X");
403 memcpy(c, s->display+1, k);
406 if (access(f, F_OK) < 0) {
407 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
412 /* Note that this cannot be in a subdir to avoid
413 * vulnerabilities since we are privileged but the runtime
414 * path is owned by the user */
416 t = strappend(s->user->runtime_path, "/X11-display");
422 if (link(f, t) < 0) {
423 if (errno == EEXIST) {
430 if (symlink(f, t) < 0) {
432 if (errno == EEXIST) {
435 if (symlink(f, t) >= 0)
439 log_error("Failed to link %s to %s: %m", f, t);
447 log_info("Linked %s to %s.", f, t);
451 s->user->display = s;
456 static int session_start_scope(Session *s) {
462 assert(s->user->slice);
464 dbus_error_init(&error);
467 _cleanup_free_ char *description = NULL;
468 const char *kill_mode;
471 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
475 scope = strjoin("session-", s->id, ".scope", NULL);
479 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
481 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
483 log_error("Failed to start session scope: %s %s", bus_error(&error, r), error.name);
484 dbus_error_free(&error);
497 hashmap_put(s->manager->session_units, s->scope, s);
502 int session_start(Session *s) {
513 r = user_start(s->user);
518 r = session_start_scope(s);
522 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
523 MESSAGE_ID(SD_MESSAGE_SESSION_START),
524 "SESSION_ID=%s", s->id,
525 "USER_ID=%s", s->user->name,
526 "LEADER=%lu", (unsigned long) s->leader,
527 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
530 /* Create X11 symlink */
531 session_link_x11_socket(s);
533 if (!dual_timestamp_is_set(&s->timestamp))
534 dual_timestamp_get(&s->timestamp);
537 seat_read_active_vt(s->seat);
541 /* Save session data */
545 session_send_signal(s, true);
550 if (s->seat->active == s)
551 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
553 seat_send_changed(s->seat, "Sessions\0");
556 user_send_changed(s->user, "Sessions\0");
561 static int session_stop_scope(Session *s) {
568 dbus_error_init(&error);
573 r = manager_stop_unit(s->manager, s->scope, &error, &job);
575 log_error("Failed to stop session scope: %s", bus_error(&error, r));
576 dbus_error_free(&error);
586 static int session_unlink_x11_socket(Session *s) {
593 if (s->user->display != s)
596 s->user->display = NULL;
598 t = strappend(s->user->runtime_path, "/X11-display");
605 return r < 0 ? -errno : 0;
608 int session_stop(Session *s) {
617 r = session_stop_scope(s);
624 int session_finalize(Session *s) {
633 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
634 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
635 "SESSION_ID=%s", s->id,
636 "USER_ID=%s", s->user->name,
637 "LEADER=%lu", (unsigned long) s->leader,
638 "MESSAGE=Removed session %s.", s->id,
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) {
874 r = pipe_eof(s->fifo_fd);
886 return manager_unit_is_active(s->manager, s->scope) != 0;
891 void session_add_to_gc_queue(Session *s) {
897 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
898 s->in_gc_queue = true;
901 SessionState session_get_state(Session *s) {
905 return SESSION_CLOSING;
908 return SESSION_OPENING;
911 return SESSION_CLOSING;
913 if (session_is_active(s))
914 return SESSION_ACTIVE;
916 return SESSION_ONLINE;
919 int session_kill(Session *s, KillWho who, int signo) {
925 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
928 static const char* const session_state_table[_SESSION_STATE_MAX] = {
929 [SESSION_OPENING] = "opening",
930 [SESSION_ONLINE] = "online",
931 [SESSION_ACTIVE] = "active",
932 [SESSION_CLOSING] = "closing"
935 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
937 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
938 [SESSION_TTY] = "tty",
939 [SESSION_X11] = "x11",
940 [SESSION_UNSPECIFIED] = "unspecified"
943 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
945 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
946 [SESSION_USER] = "user",
947 [SESSION_GREETER] = "greeter",
948 [SESSION_LOCK_SCREEN] = "lock-screen",
949 [SESSION_BACKGROUND] = "background"
952 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
954 static const char* const kill_who_table[_KILL_WHO_MAX] = {
955 [KILL_LEADER] = "leader",
959 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);