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 %s",
484 scope, bus_error(&error, r), error.name);
485 dbus_error_free(&error);
498 hashmap_put(s->manager->session_units, s->scope, s);
503 int session_start(Session *s) {
514 r = user_start(s->user);
519 r = session_start_scope(s);
523 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
524 MESSAGE_ID(SD_MESSAGE_SESSION_START),
525 "SESSION_ID=%s", s->id,
526 "USER_ID=%s", s->user->name,
527 "LEADER=%lu", (unsigned long) s->leader,
528 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
531 /* Create X11 symlink */
532 session_link_x11_socket(s);
534 if (!dual_timestamp_is_set(&s->timestamp))
535 dual_timestamp_get(&s->timestamp);
538 seat_read_active_vt(s->seat);
542 /* Save session data */
546 session_send_signal(s, true);
551 if (s->seat->active == s)
552 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
554 seat_send_changed(s->seat, "Sessions\0");
557 user_send_changed(s->user, "Sessions\0");
562 static int session_stop_scope(Session *s) {
569 dbus_error_init(&error);
574 r = manager_stop_unit(s->manager, s->scope, &error, &job);
576 log_error("Failed to stop session scope: %s", bus_error(&error, r));
577 dbus_error_free(&error);
587 static int session_unlink_x11_socket(Session *s) {
594 if (s->user->display != s)
597 s->user->display = NULL;
599 t = strappend(s->user->runtime_path, "/X11-display");
606 return r < 0 ? -errno : 0;
609 int session_stop(Session *s) {
618 r = session_stop_scope(s);
625 int session_finalize(Session *s) {
634 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
635 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
636 "SESSION_ID=%s", s->id,
637 "USER_ID=%s", s->user->name,
638 "LEADER=%lu", (unsigned long) s->leader,
639 "MESSAGE=Removed session %s.", s->id,
642 /* Remove X11 symlink */
643 session_unlink_x11_socket(s);
645 unlink(s->state_file);
646 session_add_to_gc_queue(s);
647 user_add_to_gc_queue(s->user);
650 session_send_signal(s, false);
655 if (s->seat->active == s)
656 seat_set_active(s->seat, NULL);
658 seat_send_changed(s->seat, "Sessions\0");
662 user_send_changed(s->user, "Sessions\0");
668 bool session_is_active(Session *s) {
674 return s->seat->active == s;
677 static int get_tty_atime(const char *tty, usec_t *atime) {
678 _cleanup_free_ char *p = NULL;
684 if (!path_is_absolute(tty)) {
685 p = strappend("/dev/", tty);
690 } else if (!path_startswith(tty, "/dev/"))
693 if (lstat(tty, &st) < 0)
696 *atime = timespec_load(&st.st_atim);
700 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
701 _cleanup_free_ char *p = NULL;
707 r = get_ctty(pid, NULL, &p);
711 return get_tty_atime(p, atime);
714 int session_get_idle_hint(Session *s, dual_timestamp *t) {
720 /* Explicit idle hint is set */
723 *t = s->idle_hint_timestamp;
728 /* Graphical sessions should really implement a real
733 /* For sessions with an explicitly configured tty, let's check
736 r = get_tty_atime(s->tty, &atime);
741 /* For sessions with a leader but no explicitly configured
742 * tty, let's check the controlling tty of the leader */
744 r = get_process_ctty_atime(s->leader, &atime);
751 *t = s->idle_hint_timestamp;
757 dual_timestamp_from_realtime(t, atime);
759 n = now(CLOCK_REALTIME);
761 if (s->manager->idle_action_usec <= 0)
764 return atime + s->manager->idle_action_usec <= n;
767 void session_set_idle_hint(Session *s, bool b) {
770 if (s->idle_hint == b)
774 dual_timestamp_get(&s->idle_hint_timestamp);
776 session_send_changed(s,
779 "IdleSinceHintMonotonic\0");
782 seat_send_changed(s->seat,
785 "IdleSinceHintMonotonic\0");
787 user_send_changed(s->user,
790 "IdleSinceHintMonotonic\0");
792 manager_send_changed(s->manager,
795 "IdleSinceHintMonotonic\0");
798 int session_create_fifo(Session *s) {
805 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
809 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
812 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
816 /* Open reading side */
817 if (s->fifo_fd < 0) {
818 struct epoll_event ev = {};
820 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
824 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
829 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
831 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
835 /* Open writing side */
836 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
843 void session_remove_fifo(Session *s) {
846 if (s->fifo_fd >= 0) {
847 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
848 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
849 close_nointr_nofail(s->fifo_fd);
857 unlink(s->fifo_path);
863 int session_check_gc(Session *s, bool drop_not_started) {
868 if (drop_not_started && !s->started)
874 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 SESSION_CLOSING;
909 return SESSION_OPENING;
912 return SESSION_CLOSING;
914 if (session_is_active(s))
915 return SESSION_ACTIVE;
917 return SESSION_ONLINE;
920 int session_kill(Session *s, KillWho who, int signo) {
926 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
929 static const char* const session_state_table[_SESSION_STATE_MAX] = {
930 [SESSION_OPENING] = "opening",
931 [SESSION_ONLINE] = "online",
932 [SESSION_ACTIVE] = "active",
933 [SESSION_CLOSING] = "closing"
936 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
938 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
939 [SESSION_TTY] = "tty",
940 [SESSION_X11] = "x11",
941 [SESSION_UNSPECIFIED] = "unspecified"
944 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
946 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
947 [SESSION_USER] = "user",
948 [SESSION_GREETER] = "greeter",
949 [SESSION_LOCK_SCREEN] = "lock-screen",
950 [SESSION_BACKGROUND] = "background"
953 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
955 static const char* const kill_who_table[_KILL_WHO_MAX] = {
956 [KILL_LEADER] = "leader",
960 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);