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) {
44 assert(session_id_valid(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) {
385 _cleanup_free_ char *t = NULL, *f = NULL;
391 assert(s->user->runtime_path);
393 if (s->user->display)
396 if (!s->display || !display_is_local(s->display))
399 k = strspn(s->display+1, "0123456789");
400 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
404 c = stpcpy(f, "/tmp/.X11-unix/X");
405 memcpy(c, s->display+1, k);
408 if (access(f, F_OK) < 0) {
409 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");
421 if (link(f, t) < 0) {
422 if (errno == EEXIST) {
429 if (symlink(f, t) < 0) {
431 if (errno == EEXIST) {
434 if (symlink(f, t) >= 0)
438 log_error("Failed to link %s to %s: %m", f, t);
444 log_info("Linked %s to %s.", f, t);
445 s->user->display = s;
450 static int session_start_scope(Session *s) {
456 assert(s->user->slice);
458 dbus_error_init(&error);
461 _cleanup_free_ char *description = NULL;
462 const char *kill_mode;
465 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
469 scope = strjoin("session-", s->id, ".scope", NULL);
473 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
475 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
477 log_error("Failed to start session scope %s: %s %s",
478 scope, bus_error(&error, r), error.name);
479 dbus_error_free(&error);
492 hashmap_put(s->manager->session_units, s->scope, s);
497 int session_start(Session *s) {
508 r = user_start(s->user);
513 r = session_start_scope(s);
517 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
518 MESSAGE_ID(SD_MESSAGE_SESSION_START),
519 "SESSION_ID=%s", s->id,
520 "USER_ID=%s", s->user->name,
521 "LEADER=%lu", (unsigned long) s->leader,
522 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
525 /* Create X11 symlink */
526 session_link_x11_socket(s);
528 if (!dual_timestamp_is_set(&s->timestamp))
529 dual_timestamp_get(&s->timestamp);
532 seat_read_active_vt(s->seat);
536 /* Save session data */
540 session_send_signal(s, true);
545 if (s->seat->active == s)
546 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
548 seat_send_changed(s->seat, "Sessions\0");
551 user_send_changed(s->user, "Sessions\0");
556 static int session_stop_scope(Session *s) {
563 dbus_error_init(&error);
568 r = manager_stop_unit(s->manager, s->scope, &error, &job);
570 log_error("Failed to stop session scope: %s", bus_error(&error, r));
571 dbus_error_free(&error);
581 static int session_unlink_x11_socket(Session *s) {
582 _cleanup_free_ char *t = NULL;
588 if (s->user->display != s)
591 s->user->display = NULL;
593 t = strappend(s->user->runtime_path, "/X11-display");
598 return r < 0 ? -errno : 0;
601 int session_stop(Session *s) {
610 r = session_stop_scope(s);
617 int session_finalize(Session *s) {
626 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
627 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
628 "SESSION_ID=%s", s->id,
629 "USER_ID=%s", s->user->name,
630 "LEADER=%lu", (unsigned long) s->leader,
631 "MESSAGE=Removed session %s.", s->id,
634 /* Remove X11 symlink */
635 session_unlink_x11_socket(s);
637 unlink(s->state_file);
638 session_add_to_gc_queue(s);
639 user_add_to_gc_queue(s->user);
642 session_send_signal(s, false);
647 if (s->seat->active == s)
648 seat_set_active(s->seat, NULL);
650 seat_send_changed(s->seat, "Sessions\0");
654 user_send_changed(s->user, "Sessions\0");
660 bool session_is_active(Session *s) {
666 return s->seat->active == s;
669 static int get_tty_atime(const char *tty, usec_t *atime) {
670 _cleanup_free_ char *p = NULL;
676 if (!path_is_absolute(tty)) {
677 p = strappend("/dev/", tty);
682 } else if (!path_startswith(tty, "/dev/"))
685 if (lstat(tty, &st) < 0)
688 *atime = timespec_load(&st.st_atim);
692 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
693 _cleanup_free_ char *p = NULL;
699 r = get_ctty(pid, NULL, &p);
703 return get_tty_atime(p, atime);
706 int session_get_idle_hint(Session *s, dual_timestamp *t) {
712 /* Explicit idle hint is set */
715 *t = s->idle_hint_timestamp;
720 /* Graphical sessions should really implement a real
725 /* For sessions with an explicitly configured tty, let's check
728 r = get_tty_atime(s->tty, &atime);
733 /* For sessions with a leader but no explicitly configured
734 * tty, let's check the controlling tty of the leader */
736 r = get_process_ctty_atime(s->leader, &atime);
743 *t = s->idle_hint_timestamp;
749 dual_timestamp_from_realtime(t, atime);
751 n = now(CLOCK_REALTIME);
753 if (s->manager->idle_action_usec <= 0)
756 return atime + s->manager->idle_action_usec <= n;
759 void session_set_idle_hint(Session *s, bool b) {
762 if (s->idle_hint == b)
766 dual_timestamp_get(&s->idle_hint_timestamp);
768 session_send_changed(s,
771 "IdleSinceHintMonotonic\0");
774 seat_send_changed(s->seat,
777 "IdleSinceHintMonotonic\0");
779 user_send_changed(s->user,
782 "IdleSinceHintMonotonic\0");
784 manager_send_changed(s->manager,
787 "IdleSinceHintMonotonic\0");
790 int session_create_fifo(Session *s) {
797 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
801 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
804 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
808 /* Open reading side */
809 if (s->fifo_fd < 0) {
810 struct epoll_event ev = {};
812 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
816 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
821 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
823 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
827 /* Open writing side */
828 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
835 void session_remove_fifo(Session *s) {
838 if (s->fifo_fd >= 0) {
839 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
840 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
841 close_nointr_nofail(s->fifo_fd);
849 unlink(s->fifo_path);
855 int session_check_gc(Session *s, bool drop_not_started) {
860 if (drop_not_started && !s->started)
866 if (s->fifo_fd >= 0) {
867 r = pipe_eof(s->fifo_fd);
879 return manager_unit_is_active(s->manager, s->scope) != 0;
884 void session_add_to_gc_queue(Session *s) {
890 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
891 s->in_gc_queue = true;
894 SessionState session_get_state(Session *s) {
898 return SESSION_CLOSING;
901 return SESSION_OPENING;
904 return SESSION_CLOSING;
906 if (session_is_active(s))
907 return SESSION_ACTIVE;
909 return SESSION_ONLINE;
912 int session_kill(Session *s, KillWho who, int signo) {
918 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
921 static const char* const session_state_table[_SESSION_STATE_MAX] = {
922 [SESSION_OPENING] = "opening",
923 [SESSION_ONLINE] = "online",
924 [SESSION_ACTIVE] = "active",
925 [SESSION_CLOSING] = "closing"
928 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
930 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
931 [SESSION_TTY] = "tty",
932 [SESSION_X11] = "x11",
933 [SESSION_UNSPECIFIED] = "unspecified"
936 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
938 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
939 [SESSION_USER] = "user",
940 [SESSION_GREETER] = "greeter",
941 [SESSION_LOCK_SCREEN] = "lock-screen",
942 [SESSION_BACKGROUND] = "background"
945 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
947 static const char* const kill_who_table[_KILL_WHO_MAX] = {
948 [KILL_LEADER] = "leader",
952 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);