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,
273 r = parse_env_file(s->state_file, NEWLINE,
276 "SCOPE_JOB", &s->scope_job,
277 "FIFO", &s->fifo_path,
280 "DISPLAY", &s->display,
281 "REMOTE_HOST", &s->remote_host,
282 "REMOTE_USER", &s->remote_user,
283 "SERVICE", &s->service,
289 "REALTIME", &realtime,
290 "MONOTONIC", &monotonic,
294 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
303 log_error("UID not specified for session %s", s->id);
307 r = parse_uid(uid, &u);
309 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
313 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
315 log_error("User of session %s not known.", s->id);
319 session_set_user(s, user);
323 k = parse_boolean(remote);
328 if (seat && !s->seat) {
331 o = hashmap_get(s->manager->seats, seat);
333 seat_attach_session(o, s);
336 if (vtnr && s->seat && seat_has_vts(s->seat)) {
339 k = safe_atoi(vtnr, &v);
340 if (k >= 0 && v >= 1)
345 k = parse_pid(leader, &s->leader);
347 audit_session_from_pid(s->leader, &s->audit_id);
353 t = session_type_from_string(type);
361 c = session_class_from_string(class);
369 /* If we open an unopened pipe for reading we will not
370 get an EOF. to trigger an EOF we hence open it for
371 reading, but close it right-away which then will
374 fd = session_create_fifo(s);
376 close_nointr_nofail(fd);
380 unsigned long long l;
381 if (sscanf(realtime, "%llu", &l) > 0)
382 s->timestamp.realtime = l;
386 unsigned long long l;
387 if (sscanf(monotonic, "%llu", &l) > 0)
388 s->timestamp.monotonic = l;
394 int session_activate(Session *s) {
395 unsigned int num_pending;
403 if (s->seat->active == s)
406 /* on seats with VTs, we let VTs manage session-switching */
407 if (seat_has_vts(s->seat)) {
411 return chvt(s->vtnr);
414 /* On seats without VTs, we implement session-switching in logind. We
415 * try to pause all session-devices and wait until the session
416 * controller acknowledged them. Once all devices are asleep, we simply
417 * switch the active session and be done.
418 * We save the session we want to switch to in seat->pending_switch and
419 * seat_complete_switch() will perform the final switch. */
421 s->seat->pending_switch = s;
423 /* if no devices are running, immediately perform the session switch */
424 num_pending = session_device_try_pause_all(s);
426 seat_complete_switch(s->seat);
431 static int session_link_x11_socket(Session *s) {
432 _cleanup_free_ char *t = NULL, *f = NULL;
438 assert(s->user->runtime_path);
440 if (s->user->display)
443 if (!s->display || !display_is_local(s->display))
446 k = strspn(s->display+1, "0123456789");
447 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
451 c = stpcpy(f, "/tmp/.X11-unix/X");
452 memcpy(c, s->display+1, k);
455 if (access(f, F_OK) < 0) {
456 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
460 /* Note that this cannot be in a subdir to avoid
461 * vulnerabilities since we are privileged but the runtime
462 * path is owned by the user */
464 t = strappend(s->user->runtime_path, "/X11-display");
468 if (link(f, t) < 0) {
469 if (errno == EEXIST) {
476 if (symlink(f, t) < 0) {
478 if (errno == EEXIST) {
481 if (symlink(f, t) >= 0)
485 log_error("Failed to link %s to %s: %m", f, t);
491 log_info("Linked %s to %s.", f, t);
492 s->user->display = s;
497 static int session_start_scope(Session *s) {
503 assert(s->user->slice);
505 dbus_error_init(&error);
508 _cleanup_free_ char *description = NULL;
509 const char *kill_mode;
512 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
516 scope = strjoin("session-", s->id, ".scope", NULL);
520 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
522 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
524 log_error("Failed to start session scope %s: %s %s",
525 scope, bus_error(&error, r), error.name);
526 dbus_error_free(&error);
539 hashmap_put(s->manager->session_units, s->scope, s);
544 int session_start(Session *s) {
555 r = user_start(s->user);
560 r = session_start_scope(s);
564 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
565 MESSAGE_ID(SD_MESSAGE_SESSION_START),
566 "SESSION_ID=%s", s->id,
567 "USER_ID=%s", s->user->name,
568 "LEADER=%lu", (unsigned long) s->leader,
569 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
572 /* Create X11 symlink */
573 session_link_x11_socket(s);
575 if (!dual_timestamp_is_set(&s->timestamp))
576 dual_timestamp_get(&s->timestamp);
579 seat_read_active_vt(s->seat);
583 /* Save session data */
587 session_send_signal(s, true);
592 if (s->seat->active == s)
593 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
595 seat_send_changed(s->seat, "Sessions\0");
598 user_send_changed(s->user, "Sessions\0");
603 static int session_stop_scope(Session *s) {
610 dbus_error_init(&error);
615 r = manager_stop_unit(s->manager, s->scope, &error, &job);
617 log_error("Failed to stop session scope: %s", bus_error(&error, r));
618 dbus_error_free(&error);
628 static int session_unlink_x11_socket(Session *s) {
629 _cleanup_free_ char *t = NULL;
635 if (s->user->display != s)
638 s->user->display = NULL;
640 t = strappend(s->user->runtime_path, "/X11-display");
645 return r < 0 ? -errno : 0;
648 int session_stop(Session *s) {
657 r = session_stop_scope(s);
664 int session_finalize(Session *s) {
674 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
675 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
676 "SESSION_ID=%s", s->id,
677 "USER_ID=%s", s->user->name,
678 "LEADER=%lu", (unsigned long) s->leader,
679 "MESSAGE=Removed session %s.", s->id,
682 /* Kill session devices */
683 while ((sd = hashmap_first(s->devices)))
684 session_device_free(sd);
686 /* Remove X11 symlink */
687 session_unlink_x11_socket(s);
689 unlink(s->state_file);
690 session_add_to_gc_queue(s);
691 user_add_to_gc_queue(s->user);
694 session_send_signal(s, false);
699 if (s->seat->active == s)
700 seat_set_active(s->seat, NULL);
702 seat_send_changed(s->seat, "Sessions\0");
706 user_send_changed(s->user, "Sessions\0");
712 bool session_is_active(Session *s) {
718 return s->seat->active == s;
721 static int get_tty_atime(const char *tty, usec_t *atime) {
722 _cleanup_free_ char *p = NULL;
728 if (!path_is_absolute(tty)) {
729 p = strappend("/dev/", tty);
734 } else if (!path_startswith(tty, "/dev/"))
737 if (lstat(tty, &st) < 0)
740 *atime = timespec_load(&st.st_atim);
744 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
745 _cleanup_free_ char *p = NULL;
751 r = get_ctty(pid, NULL, &p);
755 return get_tty_atime(p, atime);
758 int session_get_idle_hint(Session *s, dual_timestamp *t) {
764 /* Explicit idle hint is set */
767 *t = s->idle_hint_timestamp;
772 /* Graphical sessions should really implement a real
777 /* For sessions with an explicitly configured tty, let's check
780 r = get_tty_atime(s->tty, &atime);
785 /* For sessions with a leader but no explicitly configured
786 * tty, let's check the controlling tty of the leader */
788 r = get_process_ctty_atime(s->leader, &atime);
795 *t = s->idle_hint_timestamp;
801 dual_timestamp_from_realtime(t, atime);
803 n = now(CLOCK_REALTIME);
805 if (s->manager->idle_action_usec <= 0)
808 return atime + s->manager->idle_action_usec <= n;
811 void session_set_idle_hint(Session *s, bool b) {
814 if (s->idle_hint == b)
818 dual_timestamp_get(&s->idle_hint_timestamp);
820 session_send_changed(s,
823 "IdleSinceHintMonotonic\0");
826 seat_send_changed(s->seat,
829 "IdleSinceHintMonotonic\0");
831 user_send_changed(s->user,
834 "IdleSinceHintMonotonic\0");
836 manager_send_changed(s->manager,
839 "IdleSinceHintMonotonic\0");
842 int session_create_fifo(Session *s) {
849 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
853 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
856 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
860 /* Open reading side */
861 if (s->fifo_fd < 0) {
862 struct epoll_event ev = {};
864 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
868 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
873 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
875 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
879 /* Open writing side */
880 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
887 void session_remove_fifo(Session *s) {
890 if (s->fifo_fd >= 0) {
891 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
892 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
893 close_nointr_nofail(s->fifo_fd);
901 unlink(s->fifo_path);
907 int session_check_gc(Session *s, bool drop_not_started) {
912 if (drop_not_started && !s->started)
918 if (s->fifo_fd >= 0) {
919 r = pipe_eof(s->fifo_fd);
931 return manager_unit_is_active(s->manager, s->scope) != 0;
936 void session_add_to_gc_queue(Session *s) {
942 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
943 s->in_gc_queue = true;
946 SessionState session_get_state(Session *s) {
950 return SESSION_CLOSING;
953 return SESSION_OPENING;
956 return SESSION_CLOSING;
958 if (session_is_active(s))
959 return SESSION_ACTIVE;
961 return SESSION_ONLINE;
964 int session_kill(Session *s, KillWho who, int signo) {
970 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
973 bool session_is_controller(Session *s, const char *sender)
977 return streq_ptr(s->controller, sender);
980 int session_set_controller(Session *s, const char *sender, bool force) {
987 if (session_is_controller(s, sender))
989 if (s->controller && !force)
996 r = manager_watch_busname(s->manager, sender);
1002 session_drop_controller(s);
1008 void session_drop_controller(Session *s) {
1016 manager_drop_busname(s->manager, s->controller);
1017 free(s->controller);
1018 s->controller = NULL;
1020 /* Drop all devices as they're now unused. Do that after the controller
1021 * is released to avoid sending out useles dbus signals. */
1022 while ((sd = hashmap_first(s->devices)))
1023 session_device_free(sd);
1026 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1027 [SESSION_OPENING] = "opening",
1028 [SESSION_ONLINE] = "online",
1029 [SESSION_ACTIVE] = "active",
1030 [SESSION_CLOSING] = "closing"
1033 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1035 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1036 [SESSION_TTY] = "tty",
1037 [SESSION_X11] = "x11",
1038 [SESSION_UNSPECIFIED] = "unspecified"
1041 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1043 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1044 [SESSION_USER] = "user",
1045 [SESSION_GREETER] = "greeter",
1046 [SESSION_LOCK_SCREEN] = "lock-screen",
1047 [SESSION_BACKGROUND] = "background"
1050 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1052 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1053 [KILL_LEADER] = "leader",
1057 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);