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);
76 session_drop_controller(s);
79 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
81 if (s->user->display == s)
82 s->user->display = NULL;
86 if (s->seat->active == s)
87 s->seat->active = NULL;
89 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
93 hashmap_remove(s->manager->session_units, s->scope);
99 if (s->create_message)
100 dbus_message_unref(s->create_message);
104 free(s->remote_host);
105 free(s->remote_user);
108 hashmap_remove(s->manager->sessions, s->id);
109 session_remove_fifo(s);
115 void session_set_user(Session *s, User *u) {
120 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
123 int session_save(Session *s) {
124 _cleanup_fclose_ FILE *f = NULL;
125 _cleanup_free_ char *temp_path = NULL;
136 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
140 r = fopen_temporary(s->state_file, &f, &temp_path);
146 fchmod(fileno(f), 0644);
149 "# This is private data. Do not parse.\n"
155 (unsigned long) s->user->uid,
157 session_is_active(s),
158 session_state_to_string(session_get_state(s)),
162 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
165 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
168 fprintf(f, "SCOPE=%s\n", s->scope);
171 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
174 fprintf(f, "FIFO=%s\n", s->fifo_path);
177 fprintf(f, "SEAT=%s\n", s->seat->id);
180 fprintf(f, "TTY=%s\n", s->tty);
183 fprintf(f, "DISPLAY=%s\n", s->display);
186 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
189 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
192 fprintf(f, "SERVICE=%s\n", s->service);
194 if (s->seat && seat_can_multi_session(s->seat))
195 fprintf(f, "VTNR=%i\n", s->vtnr);
198 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
201 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
203 if (dual_timestamp_is_set(&s->timestamp))
207 (unsigned long long) s->timestamp.realtime,
208 (unsigned long long) s->timestamp.monotonic);
212 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
214 unlink(s->state_file);
220 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
225 int session_load(Session *s) {
226 _cleanup_free_ char *remote = NULL,
241 r = parse_env_file(s->state_file, NEWLINE,
244 "SCOPE_JOB", &s->scope_job,
245 "FIFO", &s->fifo_path,
248 "DISPLAY", &s->display,
249 "REMOTE_HOST", &s->remote_host,
250 "REMOTE_USER", &s->remote_user,
251 "SERVICE", &s->service,
257 "REALTIME", &realtime,
258 "MONOTONIC", &monotonic,
262 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
271 log_error("UID not specified for session %s", s->id);
275 r = parse_uid(uid, &u);
277 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
281 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
283 log_error("User of session %s not known.", s->id);
287 session_set_user(s, user);
291 k = parse_boolean(remote);
296 if (seat && !s->seat) {
299 o = hashmap_get(s->manager->seats, seat);
301 seat_attach_session(o, s);
304 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
307 k = safe_atoi(vtnr, &v);
308 if (k >= 0 && v >= 1)
313 k = parse_pid(leader, &s->leader);
315 audit_session_from_pid(s->leader, &s->audit_id);
321 t = session_type_from_string(type);
329 c = session_class_from_string(class);
337 /* If we open an unopened pipe for reading we will not
338 get an EOF. to trigger an EOF we hence open it for
339 reading, but close it right-away which then will
342 fd = session_create_fifo(s);
344 close_nointr_nofail(fd);
348 unsigned long long l;
349 if (sscanf(realtime, "%llu", &l) > 0)
350 s->timestamp.realtime = l;
354 unsigned long long l;
355 if (sscanf(monotonic, "%llu", &l) > 0)
356 s->timestamp.monotonic = l;
362 int session_activate(Session *s) {
374 if (s->seat->active == s)
377 assert(seat_is_vtconsole(s->seat));
383 return seat_set_active(s->seat, s);
386 static int session_link_x11_socket(Session *s) {
387 _cleanup_free_ char *t = NULL, *f = NULL;
393 assert(s->user->runtime_path);
395 if (s->user->display)
398 if (!s->display || !display_is_local(s->display))
401 k = strspn(s->display+1, "0123456789");
402 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
406 c = stpcpy(f, "/tmp/.X11-unix/X");
407 memcpy(c, s->display+1, k);
410 if (access(f, F_OK) < 0) {
411 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
415 /* Note that this cannot be in a subdir to avoid
416 * vulnerabilities since we are privileged but the runtime
417 * path is owned by the user */
419 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);
446 log_info("Linked %s to %s.", f, t);
447 s->user->display = s;
452 static int session_start_scope(Session *s) {
458 assert(s->user->slice);
460 dbus_error_init(&error);
463 _cleanup_free_ char *description = NULL;
464 const char *kill_mode;
467 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
471 scope = strjoin("session-", s->id, ".scope", NULL);
475 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
477 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
479 log_error("Failed to start session scope %s: %s %s",
480 scope, bus_error(&error, r), error.name);
481 dbus_error_free(&error);
494 hashmap_put(s->manager->session_units, s->scope, s);
499 int session_start(Session *s) {
510 r = user_start(s->user);
515 r = session_start_scope(s);
519 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
520 MESSAGE_ID(SD_MESSAGE_SESSION_START),
521 "SESSION_ID=%s", s->id,
522 "USER_ID=%s", s->user->name,
523 "LEADER=%lu", (unsigned long) s->leader,
524 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
527 /* Create X11 symlink */
528 session_link_x11_socket(s);
530 if (!dual_timestamp_is_set(&s->timestamp))
531 dual_timestamp_get(&s->timestamp);
534 seat_read_active_vt(s->seat);
538 /* Save session data */
542 session_send_signal(s, true);
547 if (s->seat->active == s)
548 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
550 seat_send_changed(s->seat, "Sessions\0");
553 user_send_changed(s->user, "Sessions\0");
558 static int session_stop_scope(Session *s) {
565 dbus_error_init(&error);
570 r = manager_stop_unit(s->manager, s->scope, &error, &job);
572 log_error("Failed to stop session scope: %s", bus_error(&error, r));
573 dbus_error_free(&error);
583 static int session_unlink_x11_socket(Session *s) {
584 _cleanup_free_ char *t = NULL;
590 if (s->user->display != s)
593 s->user->display = NULL;
595 t = strappend(s->user->runtime_path, "/X11-display");
600 return r < 0 ? -errno : 0;
603 int session_stop(Session *s) {
612 r = session_stop_scope(s);
619 int session_finalize(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,
636 /* Remove X11 symlink */
637 session_unlink_x11_socket(s);
639 unlink(s->state_file);
640 session_add_to_gc_queue(s);
641 user_add_to_gc_queue(s->user);
644 session_send_signal(s, false);
649 if (s->seat->active == s)
650 seat_set_active(s->seat, NULL);
652 seat_send_changed(s->seat, "Sessions\0");
656 user_send_changed(s->user, "Sessions\0");
662 bool session_is_active(Session *s) {
668 return s->seat->active == s;
671 static int get_tty_atime(const char *tty, usec_t *atime) {
672 _cleanup_free_ char *p = NULL;
678 if (!path_is_absolute(tty)) {
679 p = strappend("/dev/", tty);
684 } else if (!path_startswith(tty, "/dev/"))
687 if (lstat(tty, &st) < 0)
690 *atime = timespec_load(&st.st_atim);
694 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
695 _cleanup_free_ char *p = NULL;
701 r = get_ctty(pid, NULL, &p);
705 return get_tty_atime(p, atime);
708 int session_get_idle_hint(Session *s, dual_timestamp *t) {
714 /* Explicit idle hint is set */
717 *t = s->idle_hint_timestamp;
722 /* Graphical sessions should really implement a real
727 /* For sessions with an explicitly configured tty, let's check
730 r = get_tty_atime(s->tty, &atime);
735 /* For sessions with a leader but no explicitly configured
736 * tty, let's check the controlling tty of the leader */
738 r = get_process_ctty_atime(s->leader, &atime);
745 *t = s->idle_hint_timestamp;
751 dual_timestamp_from_realtime(t, atime);
753 n = now(CLOCK_REALTIME);
755 if (s->manager->idle_action_usec <= 0)
758 return atime + s->manager->idle_action_usec <= n;
761 void session_set_idle_hint(Session *s, bool b) {
764 if (s->idle_hint == b)
768 dual_timestamp_get(&s->idle_hint_timestamp);
770 session_send_changed(s,
773 "IdleSinceHintMonotonic\0");
776 seat_send_changed(s->seat,
779 "IdleSinceHintMonotonic\0");
781 user_send_changed(s->user,
784 "IdleSinceHintMonotonic\0");
786 manager_send_changed(s->manager,
789 "IdleSinceHintMonotonic\0");
792 int session_create_fifo(Session *s) {
799 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
803 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
806 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
810 /* Open reading side */
811 if (s->fifo_fd < 0) {
812 struct epoll_event ev = {};
814 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
818 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
823 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
825 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
829 /* Open writing side */
830 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
837 void session_remove_fifo(Session *s) {
840 if (s->fifo_fd >= 0) {
841 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
842 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
843 close_nointr_nofail(s->fifo_fd);
851 unlink(s->fifo_path);
857 int session_check_gc(Session *s, bool drop_not_started) {
862 if (drop_not_started && !s->started)
868 if (s->fifo_fd >= 0) {
869 r = pipe_eof(s->fifo_fd);
881 return manager_unit_is_active(s->manager, s->scope) != 0;
886 void session_add_to_gc_queue(Session *s) {
892 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
893 s->in_gc_queue = true;
896 SessionState session_get_state(Session *s) {
900 return SESSION_CLOSING;
903 return SESSION_OPENING;
906 return SESSION_CLOSING;
908 if (session_is_active(s))
909 return SESSION_ACTIVE;
911 return SESSION_ONLINE;
914 int session_kill(Session *s, KillWho who, int signo) {
920 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
923 bool session_is_controller(Session *s, const char *sender)
927 return streq_ptr(s->controller, sender);
930 int session_set_controller(Session *s, const char *sender, bool force) {
937 if (session_is_controller(s, sender))
939 if (s->controller && !force)
946 r = manager_watch_busname(s->manager, sender);
952 session_drop_controller(s);
958 void session_drop_controller(Session *s) {
964 manager_drop_busname(s->manager, s->controller);
966 s->controller = NULL;
969 static const char* const session_state_table[_SESSION_STATE_MAX] = {
970 [SESSION_OPENING] = "opening",
971 [SESSION_ONLINE] = "online",
972 [SESSION_ACTIVE] = "active",
973 [SESSION_CLOSING] = "closing"
976 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
978 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
979 [SESSION_TTY] = "tty",
980 [SESSION_X11] = "x11",
981 [SESSION_UNSPECIFIED] = "unspecified"
984 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
986 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
987 [SESSION_USER] = "user",
988 [SESSION_GREETER] = "greeter",
989 [SESSION_LOCK_SCREEN] = "lock-screen",
990 [SESSION_BACKGROUND] = "background"
993 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
995 static const char* const kill_who_table[_KILL_WHO_MAX] = {
996 [KILL_LEADER] = "leader",
1000 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);