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) {
458 _cleanup_free_ char *description = NULL;
465 assert(s->user->slice);
467 dbus_error_init(&error);
470 s->scope = strjoin("session.", s->id, ".scope", NULL);
474 r = hashmap_put(s->manager->session_units, s->scope, s);
476 log_warning("Failed to create mapping between unit and session");
479 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
481 r = manager_start_scope(s->manager, s->scope, s->leader, s->user->slice, description, &error, &job);
483 log_error("Failed to start session scope: %s %s", bus_error(&error, r), error.name);
484 dbus_error_free(&error);
493 int session_start(Session *s) {
504 r = user_start(s->user);
509 r = session_start_scope(s);
513 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
514 MESSAGE_ID(SD_MESSAGE_SESSION_START),
515 "SESSION_ID=%s", s->id,
516 "USER_ID=%s", s->user->name,
517 "LEADER=%lu", (unsigned long) s->leader,
518 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
521 /* Create X11 symlink */
522 session_link_x11_socket(s);
524 if (!dual_timestamp_is_set(&s->timestamp))
525 dual_timestamp_get(&s->timestamp);
528 seat_read_active_vt(s->seat);
532 /* Save session data */
536 session_send_signal(s, true);
541 if (s->seat->active == s)
542 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
544 seat_send_changed(s->seat, "Sessions\0");
547 user_send_changed(s->user, "Sessions\0");
552 /* static bool session_shall_kill(Session *s) { */
555 /* if (!s->kill_processes) */
558 /* if (strv_contains(s->manager->kill_exclude_users, s->user->name)) */
561 /* if (strv_isempty(s->manager->kill_only_users)) */
564 /* return strv_contains(s->manager->kill_only_users, s->user->name); */
567 static int session_stop_scope(Session *s) {
574 dbus_error_init(&error);
579 r = manager_stop_unit(s->manager, s->scope, &error, &job);
581 log_error("Failed to stop session scope: %s", bus_error(&error, r));
582 dbus_error_free(&error);
592 static int session_unlink_x11_socket(Session *s) {
599 if (s->user->display != s)
602 s->user->display = NULL;
604 t = strappend(s->user->runtime_path, "/X11-display");
611 return r < 0 ? -errno : 0;
614 int session_stop(Session *s) {
623 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
624 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
625 "SESSION_ID=%s", s->id,
626 "USER_ID=%s", s->user->name,
627 "LEADER=%lu", (unsigned long) s->leader,
628 "MESSAGE=Removed session %s.", s->id,
632 k = session_stop_scope(s);
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) {
870 r = pipe_eof(s->fifo_fd);
882 return manager_unit_is_active(s->manager, s->scope) != 0;
887 void session_add_to_gc_queue(Session *s) {
893 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
894 s->in_gc_queue = true;
897 SessionState session_get_state(Session *s) {
901 return s->started ? SESSION_OPENING : SESSION_CLOSING;
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);