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) {
384 _cleanup_free_ char *t = NULL, *f = NULL;
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);
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");
420 if (link(f, t) < 0) {
421 if (errno == EEXIST) {
428 if (symlink(f, t) < 0) {
430 if (errno == EEXIST) {
433 if (symlink(f, t) >= 0)
437 log_error("Failed to link %s to %s: %m", f, t);
443 log_info("Linked %s to %s.", f, t);
444 s->user->display = s;
449 static int session_start_scope(Session *s) {
455 assert(s->user->slice);
457 dbus_error_init(&error);
460 _cleanup_free_ char *description = NULL;
461 const char *kill_mode;
464 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
468 scope = strjoin("session-", s->id, ".scope", NULL);
472 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
474 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
476 log_error("Failed to start session scope %s: %s %s",
477 scope, bus_error(&error, r), error.name);
478 dbus_error_free(&error);
491 hashmap_put(s->manager->session_units, s->scope, s);
496 int session_start(Session *s) {
507 r = user_start(s->user);
512 r = session_start_scope(s);
516 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
517 MESSAGE_ID(SD_MESSAGE_SESSION_START),
518 "SESSION_ID=%s", s->id,
519 "USER_ID=%s", s->user->name,
520 "LEADER=%lu", (unsigned long) s->leader,
521 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
524 /* Create X11 symlink */
525 session_link_x11_socket(s);
527 if (!dual_timestamp_is_set(&s->timestamp))
528 dual_timestamp_get(&s->timestamp);
531 seat_read_active_vt(s->seat);
535 /* Save session data */
539 session_send_signal(s, true);
544 if (s->seat->active == s)
545 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
547 seat_send_changed(s->seat, "Sessions\0");
550 user_send_changed(s->user, "Sessions\0");
555 static int session_stop_scope(Session *s) {
562 dbus_error_init(&error);
567 r = manager_stop_unit(s->manager, s->scope, &error, &job);
569 log_error("Failed to stop session scope: %s", bus_error(&error, r));
570 dbus_error_free(&error);
580 static int session_unlink_x11_socket(Session *s) {
581 _cleanup_free_ char *t = NULL;
587 if (s->user->display != s)
590 s->user->display = NULL;
592 t = strappend(s->user->runtime_path, "/X11-display");
597 return r < 0 ? -errno : 0;
600 int session_stop(Session *s) {
609 r = session_stop_scope(s);
616 int session_finalize(Session *s) {
625 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
626 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
627 "SESSION_ID=%s", s->id,
628 "USER_ID=%s", s->user->name,
629 "LEADER=%lu", (unsigned long) s->leader,
630 "MESSAGE=Removed session %s.", s->id,
633 /* Remove X11 symlink */
634 session_unlink_x11_socket(s);
636 unlink(s->state_file);
637 session_add_to_gc_queue(s);
638 user_add_to_gc_queue(s->user);
641 session_send_signal(s, false);
646 if (s->seat->active == s)
647 seat_set_active(s->seat, NULL);
649 seat_send_changed(s->seat, "Sessions\0");
653 user_send_changed(s->user, "Sessions\0");
659 bool session_is_active(Session *s) {
665 return s->seat->active == s;
668 static int get_tty_atime(const char *tty, usec_t *atime) {
669 _cleanup_free_ char *p = NULL;
675 if (!path_is_absolute(tty)) {
676 p = strappend("/dev/", tty);
681 } else if (!path_startswith(tty, "/dev/"))
684 if (lstat(tty, &st) < 0)
687 *atime = timespec_load(&st.st_atim);
691 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
692 _cleanup_free_ char *p = NULL;
698 r = get_ctty(pid, NULL, &p);
702 return get_tty_atime(p, atime);
705 int session_get_idle_hint(Session *s, dual_timestamp *t) {
711 /* Explicit idle hint is set */
714 *t = s->idle_hint_timestamp;
719 /* Graphical sessions should really implement a real
724 /* For sessions with an explicitly configured tty, let's check
727 r = get_tty_atime(s->tty, &atime);
732 /* For sessions with a leader but no explicitly configured
733 * tty, let's check the controlling tty of the leader */
735 r = get_process_ctty_atime(s->leader, &atime);
742 *t = s->idle_hint_timestamp;
748 dual_timestamp_from_realtime(t, atime);
750 n = now(CLOCK_REALTIME);
752 if (s->manager->idle_action_usec <= 0)
755 return atime + s->manager->idle_action_usec <= n;
758 void session_set_idle_hint(Session *s, bool b) {
761 if (s->idle_hint == b)
765 dual_timestamp_get(&s->idle_hint_timestamp);
767 session_send_changed(s,
770 "IdleSinceHintMonotonic\0");
773 seat_send_changed(s->seat,
776 "IdleSinceHintMonotonic\0");
778 user_send_changed(s->user,
781 "IdleSinceHintMonotonic\0");
783 manager_send_changed(s->manager,
786 "IdleSinceHintMonotonic\0");
789 int session_create_fifo(Session *s) {
796 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
800 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
803 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
807 /* Open reading side */
808 if (s->fifo_fd < 0) {
809 struct epoll_event ev = {};
811 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
815 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
820 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
822 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
826 /* Open writing side */
827 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
834 void session_remove_fifo(Session *s) {
837 if (s->fifo_fd >= 0) {
838 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
839 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
840 close_nointr_nofail(s->fifo_fd);
848 unlink(s->fifo_path);
854 int session_check_gc(Session *s, bool drop_not_started) {
859 if (drop_not_started && !s->started)
865 if (s->fifo_fd >= 0) {
866 r = pipe_eof(s->fifo_fd);
878 return manager_unit_is_active(s->manager, s->scope) != 0;
883 void session_add_to_gc_queue(Session *s) {
889 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
890 s->in_gc_queue = true;
893 SessionState session_get_state(Session *s) {
897 return SESSION_CLOSING;
900 return SESSION_OPENING;
903 return SESSION_CLOSING;
905 if (session_is_active(s))
906 return SESSION_ACTIVE;
908 return SESSION_ONLINE;
911 int session_kill(Session *s, KillWho who, int signo) {
917 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
920 static const char* const session_state_table[_SESSION_STATE_MAX] = {
921 [SESSION_OPENING] = "opening",
922 [SESSION_ONLINE] = "online",
923 [SESSION_ACTIVE] = "active",
924 [SESSION_CLOSING] = "closing"
927 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
929 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
930 [SESSION_TTY] = "tty",
931 [SESSION_X11] = "x11",
932 [SESSION_UNSPECIFIED] = "unspecified"
935 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
937 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
938 [SESSION_USER] = "user",
939 [SESSION_GREETER] = "greeter",
940 [SESSION_LOCK_SCREEN] = "lock-screen",
941 [SESSION_BACKGROUND] = "background"
944 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
946 static const char* const kill_who_table[_KILL_WHO_MAX] = {
947 [KILL_LEADER] = "leader",
951 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);