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) {
463 assert(s->user->slice);
465 dbus_error_init(&error);
468 _cleanup_free_ char *description = NULL;
471 scope = strjoin("session-", s->id, ".scope", NULL);
475 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
477 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, &error, &job);
479 log_error("Failed to start session scope: %s %s", bus_error(&error, r), error.name);
480 dbus_error_free(&error);
492 hashmap_put(s->manager->session_units, s->scope, s);
497 int session_start(Session *s) {
508 r = user_start(s->user);
513 r = session_start_scope(s);
517 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
518 MESSAGE_ID(SD_MESSAGE_SESSION_START),
519 "SESSION_ID=%s", s->id,
520 "USER_ID=%s", s->user->name,
521 "LEADER=%lu", (unsigned long) s->leader,
522 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
525 /* Create X11 symlink */
526 session_link_x11_socket(s);
528 if (!dual_timestamp_is_set(&s->timestamp))
529 dual_timestamp_get(&s->timestamp);
532 seat_read_active_vt(s->seat);
536 /* Save session data */
540 session_send_signal(s, true);
545 if (s->seat->active == s)
546 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
548 seat_send_changed(s->seat, "Sessions\0");
551 user_send_changed(s->user, "Sessions\0");
556 /* static bool session_shall_kill(Session *s) { */
559 /* if (!s->kill_processes) */
562 /* if (strv_contains(s->manager->kill_exclude_users, s->user->name)) */
565 /* if (strv_isempty(s->manager->kill_only_users)) */
568 /* return strv_contains(s->manager->kill_only_users, s->user->name); */
571 static int session_stop_scope(Session *s) {
578 dbus_error_init(&error);
583 r = manager_stop_unit(s->manager, s->scope, &error, &job);
585 log_error("Failed to stop session scope: %s", bus_error(&error, r));
586 dbus_error_free(&error);
596 static int session_unlink_x11_socket(Session *s) {
603 if (s->user->display != s)
606 s->user->display = NULL;
608 t = strappend(s->user->runtime_path, "/X11-display");
615 return r < 0 ? -errno : 0;
618 int session_stop(Session *s) {
627 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
628 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
629 "SESSION_ID=%s", s->id,
630 "USER_ID=%s", s->user->name,
631 "LEADER=%lu", (unsigned long) s->leader,
632 "MESSAGE=Removed session %s.", s->id,
636 k = session_stop_scope(s);
640 /* Remove X11 symlink */
641 session_unlink_x11_socket(s);
643 unlink(s->state_file);
644 session_add_to_gc_queue(s);
645 user_add_to_gc_queue(s->user);
648 session_send_signal(s, false);
653 if (s->seat->active == s)
654 seat_set_active(s->seat, NULL);
656 seat_send_changed(s->seat, "Sessions\0");
660 user_send_changed(s->user, "Sessions\0");
666 bool session_is_active(Session *s) {
672 return s->seat->active == s;
675 static int get_tty_atime(const char *tty, usec_t *atime) {
676 _cleanup_free_ char *p = NULL;
682 if (!path_is_absolute(tty)) {
683 p = strappend("/dev/", tty);
688 } else if (!path_startswith(tty, "/dev/"))
691 if (lstat(tty, &st) < 0)
694 *atime = timespec_load(&st.st_atim);
698 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
699 _cleanup_free_ char *p = NULL;
705 r = get_ctty(pid, NULL, &p);
709 return get_tty_atime(p, atime);
712 int session_get_idle_hint(Session *s, dual_timestamp *t) {
718 /* Explicit idle hint is set */
721 *t = s->idle_hint_timestamp;
726 /* Graphical sessions should really implement a real
731 /* For sessions with an explicitly configured tty, let's check
734 r = get_tty_atime(s->tty, &atime);
739 /* For sessions with a leader but no explicitly configured
740 * tty, let's check the controlling tty of the leader */
742 r = get_process_ctty_atime(s->leader, &atime);
749 *t = s->idle_hint_timestamp;
755 dual_timestamp_from_realtime(t, atime);
757 n = now(CLOCK_REALTIME);
759 if (s->manager->idle_action_usec <= 0)
762 return atime + s->manager->idle_action_usec <= n;
765 void session_set_idle_hint(Session *s, bool b) {
768 if (s->idle_hint == b)
772 dual_timestamp_get(&s->idle_hint_timestamp);
774 session_send_changed(s,
777 "IdleSinceHintMonotonic\0");
780 seat_send_changed(s->seat,
783 "IdleSinceHintMonotonic\0");
785 user_send_changed(s->user,
788 "IdleSinceHintMonotonic\0");
790 manager_send_changed(s->manager,
793 "IdleSinceHintMonotonic\0");
796 int session_create_fifo(Session *s) {
803 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
807 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
810 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
814 /* Open reading side */
815 if (s->fifo_fd < 0) {
816 struct epoll_event ev = {};
818 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
822 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
827 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
829 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
833 /* Open writing side */
834 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
841 void session_remove_fifo(Session *s) {
844 if (s->fifo_fd >= 0) {
845 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
846 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
847 close_nointr_nofail(s->fifo_fd);
855 unlink(s->fifo_path);
861 int session_check_gc(Session *s, bool drop_not_started) {
866 if (drop_not_started && !s->started)
872 if (s->fifo_fd >= 0) {
874 r = pipe_eof(s->fifo_fd);
886 return manager_unit_is_active(s->manager, s->scope) != 0;
891 void session_add_to_gc_queue(Session *s) {
897 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
898 s->in_gc_queue = true;
901 SessionState session_get_state(Session *s) {
905 return s->started ? SESSION_OPENING : SESSION_CLOSING;
908 return SESSION_CLOSING;
910 if (session_is_active(s))
911 return SESSION_ACTIVE;
913 return SESSION_ONLINE;
916 int session_kill(Session *s, KillWho who, int signo) {
922 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
925 static const char* const session_state_table[_SESSION_STATE_MAX] = {
926 [SESSION_OPENING] = "opening",
927 [SESSION_ONLINE] = "online",
928 [SESSION_ACTIVE] = "active",
929 [SESSION_CLOSING] = "closing"
932 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
934 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
935 [SESSION_TTY] = "tty",
936 [SESSION_X11] = "x11",
937 [SESSION_UNSPECIFIED] = "unspecified"
940 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
942 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
943 [SESSION_USER] = "user",
944 [SESSION_GREETER] = "greeter",
945 [SESSION_LOCK_SCREEN] = "lock-screen",
946 [SESSION_BACKGROUND] = "background"
949 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
951 static const char* const kill_who_table[_KILL_WHO_MAX] = {
952 [KILL_LEADER] = "leader",
956 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);