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 static unsigned devt_hash_func(const void *p) {
40 uint64_t u = *(const dev_t*)p;
42 return uint64_hash_func(&u);
45 static int devt_compare_func(const void *_a, const void *_b) {
48 a = *(const dev_t*) _a;
49 b = *(const dev_t*) _b;
51 return a < b ? -1 : (a > b ? 1 : 0);
54 Session* session_new(Manager *m, const char *id) {
59 assert(session_id_valid(id));
65 s->state_file = strappend("/run/systemd/sessions/", id);
71 s->devices = hashmap_new(devt_hash_func, devt_compare_func);
78 s->id = path_get_file_name(s->state_file);
80 if (hashmap_put(m->sessions, s->id, s) < 0) {
81 hashmap_free(s->devices);
93 void session_free(Session *s) {
99 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
101 session_drop_controller(s);
103 while ((sd = hashmap_first(s->devices)))
104 session_device_free(sd);
106 hashmap_free(s->devices);
109 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
111 if (s->user->display == s)
112 s->user->display = NULL;
116 if (s->seat->active == s)
117 s->seat->active = NULL;
118 if (s->seat->pending_switch == s)
119 s->seat->pending_switch = NULL;
121 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
125 hashmap_remove(s->manager->session_units, s->scope);
131 if (s->create_message)
132 dbus_message_unref(s->create_message);
136 free(s->remote_host);
137 free(s->remote_user);
140 hashmap_remove(s->manager->sessions, s->id);
141 session_remove_fifo(s);
147 void session_set_user(Session *s, User *u) {
152 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
155 int session_save(Session *s) {
156 _cleanup_fclose_ FILE *f = NULL;
157 _cleanup_free_ char *temp_path = NULL;
168 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
172 r = fopen_temporary(s->state_file, &f, &temp_path);
178 fchmod(fileno(f), 0644);
181 "# This is private data. Do not parse.\n"
187 (unsigned long) s->user->uid,
189 session_is_active(s),
190 session_state_to_string(session_get_state(s)),
194 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
197 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
200 fprintf(f, "SCOPE=%s\n", s->scope);
203 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
206 fprintf(f, "FIFO=%s\n", s->fifo_path);
209 fprintf(f, "SEAT=%s\n", s->seat->id);
212 fprintf(f, "TTY=%s\n", s->tty);
215 fprintf(f, "DISPLAY=%s\n", s->display);
218 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
221 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
224 fprintf(f, "SERVICE=%s\n", s->service);
226 if (s->seat && seat_has_vts(s->seat))
227 fprintf(f, "VTNR=%i\n", s->vtnr);
230 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
233 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
235 if (dual_timestamp_is_set(&s->timestamp))
239 (unsigned long long) s->timestamp.realtime,
240 (unsigned long long) s->timestamp.monotonic);
244 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
246 unlink(s->state_file);
252 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
257 int session_load(Session *s) {
258 _cleanup_free_ char *remote = NULL,
272 r = parse_env_file(s->state_file, NEWLINE,
275 "SCOPE_JOB", &s->scope_job,
276 "FIFO", &s->fifo_path,
279 "DISPLAY", &s->display,
280 "REMOTE_HOST", &s->remote_host,
281 "REMOTE_USER", &s->remote_user,
282 "SERVICE", &s->service,
288 "REALTIME", &realtime,
289 "MONOTONIC", &monotonic,
293 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
302 log_error("UID not specified for session %s", s->id);
306 r = parse_uid(uid, &u);
308 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
312 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
314 log_error("User of session %s not known.", s->id);
318 session_set_user(s, user);
322 k = parse_boolean(remote);
327 if (seat && !s->seat) {
330 o = hashmap_get(s->manager->seats, seat);
332 seat_attach_session(o, s);
335 if (vtnr && s->seat && seat_has_vts(s->seat)) {
338 k = safe_atoi(vtnr, &v);
339 if (k >= 0 && v >= 1)
344 k = parse_pid(leader, &s->leader);
346 audit_session_from_pid(s->leader, &s->audit_id);
352 t = session_type_from_string(type);
360 c = session_class_from_string(class);
368 /* If we open an unopened pipe for reading we will not
369 get an EOF. to trigger an EOF we hence open it for
370 reading, but close it right-away which then will
373 fd = session_create_fifo(s);
375 close_nointr_nofail(fd);
379 unsigned long long l;
380 if (sscanf(realtime, "%llu", &l) > 0)
381 s->timestamp.realtime = l;
385 unsigned long long l;
386 if (sscanf(monotonic, "%llu", &l) > 0)
387 s->timestamp.monotonic = l;
393 int session_activate(Session *s) {
394 unsigned int num_pending;
402 if (s->seat->active == s)
405 /* on seats with VTs, we let VTs manage session-switching */
406 if (seat_has_vts(s->seat)) {
410 return chvt(s->vtnr);
413 /* On seats without VTs, we implement session-switching in logind. We
414 * try to pause all session-devices and wait until the session
415 * controller acknowledged them. Once all devices are asleep, we simply
416 * switch the active session and be done.
417 * We save the session we want to switch to in seat->pending_switch and
418 * seat_complete_switch() will perform the final switch. */
420 s->seat->pending_switch = s;
422 /* if no devices are running, immediately perform the session switch */
423 num_pending = session_device_try_pause_all(s);
425 seat_complete_switch(s->seat);
430 static int session_link_x11_socket(Session *s) {
431 _cleanup_free_ char *t = NULL, *f = NULL;
437 assert(s->user->runtime_path);
439 if (s->user->display)
442 if (!s->display || !display_is_local(s->display))
445 k = strspn(s->display+1, "0123456789");
446 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
450 c = stpcpy(f, "/tmp/.X11-unix/X");
451 memcpy(c, s->display+1, k);
454 if (access(f, F_OK) < 0) {
455 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
459 /* Note that this cannot be in a subdir to avoid
460 * vulnerabilities since we are privileged but the runtime
461 * path is owned by the user */
463 t = strappend(s->user->runtime_path, "/X11-display");
467 if (link(f, t) < 0) {
468 if (errno == EEXIST) {
475 if (symlink(f, t) < 0) {
477 if (errno == EEXIST) {
480 if (symlink(f, t) >= 0)
484 log_error("Failed to link %s to %s: %m", f, t);
490 log_info("Linked %s to %s.", f, t);
491 s->user->display = s;
496 static int session_start_scope(Session *s) {
502 assert(s->user->slice);
504 dbus_error_init(&error);
507 _cleanup_free_ char *description = NULL;
508 const char *kill_mode;
511 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
515 scope = strjoin("session-", s->id, ".scope", NULL);
519 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
521 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
523 log_error("Failed to start session scope %s: %s %s",
524 scope, bus_error(&error, r), error.name);
525 dbus_error_free(&error);
538 hashmap_put(s->manager->session_units, s->scope, s);
543 int session_start(Session *s) {
554 r = user_start(s->user);
559 r = session_start_scope(s);
563 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
564 MESSAGE_ID(SD_MESSAGE_SESSION_START),
565 "SESSION_ID=%s", s->id,
566 "USER_ID=%s", s->user->name,
567 "LEADER=%lu", (unsigned long) s->leader,
568 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
571 /* Create X11 symlink */
572 session_link_x11_socket(s);
574 if (!dual_timestamp_is_set(&s->timestamp))
575 dual_timestamp_get(&s->timestamp);
578 seat_read_active_vt(s->seat);
582 /* Save session data */
586 session_send_signal(s, true);
591 if (s->seat->active == s)
592 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
594 seat_send_changed(s->seat, "Sessions\0");
597 user_send_changed(s->user, "Sessions\0");
602 static int session_stop_scope(Session *s) {
609 dbus_error_init(&error);
614 r = manager_stop_unit(s->manager, s->scope, &error, &job);
616 log_error("Failed to stop session scope: %s", bus_error(&error, r));
617 dbus_error_free(&error);
627 static int session_unlink_x11_socket(Session *s) {
628 _cleanup_free_ char *t = NULL;
634 if (s->user->display != s)
637 s->user->display = NULL;
639 t = strappend(s->user->runtime_path, "/X11-display");
644 return r < 0 ? -errno : 0;
647 int session_stop(Session *s) {
656 r = session_stop_scope(s);
663 int session_finalize(Session *s) {
673 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
674 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
675 "SESSION_ID=%s", s->id,
676 "USER_ID=%s", s->user->name,
677 "LEADER=%lu", (unsigned long) s->leader,
678 "MESSAGE=Removed session %s.", s->id,
681 /* Kill session devices */
682 while ((sd = hashmap_first(s->devices)))
683 session_device_free(sd);
685 /* Remove X11 symlink */
686 session_unlink_x11_socket(s);
688 unlink(s->state_file);
689 session_add_to_gc_queue(s);
690 user_add_to_gc_queue(s->user);
693 session_send_signal(s, false);
698 if (s->seat->active == s)
699 seat_set_active(s->seat, NULL);
701 seat_send_changed(s->seat, "Sessions\0");
705 user_send_changed(s->user, "Sessions\0");
711 bool session_is_active(Session *s) {
717 return s->seat->active == s;
720 static int get_tty_atime(const char *tty, usec_t *atime) {
721 _cleanup_free_ char *p = NULL;
727 if (!path_is_absolute(tty)) {
728 p = strappend("/dev/", tty);
733 } else if (!path_startswith(tty, "/dev/"))
736 if (lstat(tty, &st) < 0)
739 *atime = timespec_load(&st.st_atim);
743 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
744 _cleanup_free_ char *p = NULL;
750 r = get_ctty(pid, NULL, &p);
754 return get_tty_atime(p, atime);
757 int session_get_idle_hint(Session *s, dual_timestamp *t) {
763 /* Explicit idle hint is set */
766 *t = s->idle_hint_timestamp;
771 /* Graphical sessions should really implement a real
776 /* For sessions with an explicitly configured tty, let's check
779 r = get_tty_atime(s->tty, &atime);
784 /* For sessions with a leader but no explicitly configured
785 * tty, let's check the controlling tty of the leader */
787 r = get_process_ctty_atime(s->leader, &atime);
794 *t = s->idle_hint_timestamp;
800 dual_timestamp_from_realtime(t, atime);
802 n = now(CLOCK_REALTIME);
804 if (s->manager->idle_action_usec <= 0)
807 return atime + s->manager->idle_action_usec <= n;
810 void session_set_idle_hint(Session *s, bool b) {
813 if (s->idle_hint == b)
817 dual_timestamp_get(&s->idle_hint_timestamp);
819 session_send_changed(s,
822 "IdleSinceHintMonotonic\0");
825 seat_send_changed(s->seat,
828 "IdleSinceHintMonotonic\0");
830 user_send_changed(s->user,
833 "IdleSinceHintMonotonic\0");
835 manager_send_changed(s->manager,
838 "IdleSinceHintMonotonic\0");
841 int session_create_fifo(Session *s) {
848 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
852 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
855 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
859 /* Open reading side */
860 if (s->fifo_fd < 0) {
861 struct epoll_event ev = {};
863 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
867 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
872 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
874 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
878 /* Open writing side */
879 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
886 void session_remove_fifo(Session *s) {
889 if (s->fifo_fd >= 0) {
890 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
891 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
892 close_nointr_nofail(s->fifo_fd);
900 unlink(s->fifo_path);
906 int session_check_gc(Session *s, bool drop_not_started) {
911 if (drop_not_started && !s->started)
917 if (s->fifo_fd >= 0) {
918 r = pipe_eof(s->fifo_fd);
930 return manager_unit_is_active(s->manager, s->scope) != 0;
935 void session_add_to_gc_queue(Session *s) {
941 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
942 s->in_gc_queue = true;
945 SessionState session_get_state(Session *s) {
949 return SESSION_CLOSING;
952 return SESSION_OPENING;
955 return SESSION_CLOSING;
957 if (session_is_active(s))
958 return SESSION_ACTIVE;
960 return SESSION_ONLINE;
963 int session_kill(Session *s, KillWho who, int signo) {
969 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
972 bool session_is_controller(Session *s, const char *sender)
976 return streq_ptr(s->controller, sender);
979 int session_set_controller(Session *s, const char *sender, bool force) {
986 if (session_is_controller(s, sender))
988 if (s->controller && !force)
995 r = manager_watch_busname(s->manager, sender);
1001 session_drop_controller(s);
1007 void session_drop_controller(Session *s) {
1015 manager_drop_busname(s->manager, s->controller);
1016 free(s->controller);
1017 s->controller = NULL;
1019 /* Drop all devices as they're now unused. Do that after the controller
1020 * is released to avoid sending out useles dbus signals. */
1021 while ((sd = hashmap_first(s->devices)))
1022 session_device_free(sd);
1025 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1026 [SESSION_OPENING] = "opening",
1027 [SESSION_ONLINE] = "online",
1028 [SESSION_ACTIVE] = "active",
1029 [SESSION_CLOSING] = "closing"
1032 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1034 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1035 [SESSION_TTY] = "tty",
1036 [SESSION_X11] = "x11",
1037 [SESSION_UNSPECIFIED] = "unspecified"
1040 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1042 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1043 [SESSION_USER] = "user",
1044 [SESSION_GREETER] = "greeter",
1045 [SESSION_LOCK_SCREEN] = "lock-screen",
1046 [SESSION_BACKGROUND] = "background"
1049 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1051 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1052 [KILL_LEADER] = "leader",
1056 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);