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"
33 #include "path-util.h"
34 #include "cgroup-util.h"
35 #include "logind-session.h"
38 Session* session_new(Manager *m, const char *id) {
48 s->state_file = strappend("/run/systemd/sessions/", id);
54 s->id = path_get_file_name(s->state_file);
56 if (hashmap_put(m->sessions, s->id, s) < 0) {
68 void session_free(Session *s) {
72 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
75 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
77 if (s->user->display == s)
78 s->user->display = NULL;
82 if (s->seat->active == s)
83 s->seat->active = NULL;
85 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
89 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
92 strv_free(s->controllers);
101 hashmap_remove(s->manager->sessions, s->id);
102 session_remove_fifo(s);
108 void session_set_user(Session *s, User *u) {
113 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
116 int session_save(Session *s) {
117 _cleanup_fclose_ FILE *f = NULL;
118 _cleanup_free_ char *temp_path = NULL;
129 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
133 r = fopen_temporary(s->state_file, &f, &temp_path);
139 fchmod(fileno(f), 0644);
142 "# This is private data. Do not parse.\n"
148 "KILL_PROCESSES=%i\n",
149 (unsigned long) s->user->uid,
151 session_is_active(s),
152 session_state_to_string(session_get_state(s)),
157 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
160 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
163 fprintf(f, "CGROUP=%s\n", s->cgroup_path);
166 fprintf(f, "FIFO=%s\n", s->fifo_path);
169 fprintf(f, "SEAT=%s\n", s->seat->id);
172 fprintf(f, "TTY=%s\n", s->tty);
175 fprintf(f, "DISPLAY=%s\n", s->display);
178 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
181 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
184 fprintf(f, "SERVICE=%s\n", s->service);
187 fprintf(f, "SLICE=%s\n", s->slice);
189 if (s->seat && seat_can_multi_session(s->seat))
190 fprintf(f, "VTNR=%i\n", s->vtnr);
193 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
196 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
198 if (dual_timestamp_is_set(&s->timestamp))
202 (unsigned long long) s->timestamp.realtime,
203 (unsigned long long) s->timestamp.monotonic);
207 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
209 unlink(s->state_file);
215 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
220 int session_load(Session *s) {
221 _cleanup_free_ char *remote = NULL,
222 *kill_processes = NULL,
237 r = parse_env_file(s->state_file, NEWLINE,
239 "KILL_PROCESSES", &kill_processes,
240 "CGROUP", &s->cgroup_path,
241 "FIFO", &s->fifo_path,
244 "DISPLAY", &s->display,
245 "REMOTE_HOST", &s->remote_host,
246 "REMOTE_USER", &s->remote_user,
247 "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 (kill_processes) {
294 k = parse_boolean(kill_processes);
296 s->kill_processes = k;
299 if (seat && !s->seat) {
302 o = hashmap_get(s->manager->seats, seat);
304 seat_attach_session(o, s);
307 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
310 k = safe_atoi(vtnr, &v);
311 if (k >= 0 && v >= 1)
316 k = parse_pid(leader, &s->leader);
318 audit_session_from_pid(s->leader, &s->audit_id);
324 t = session_type_from_string(type);
332 c = session_class_from_string(class);
340 /* If we open an unopened pipe for reading we will not
341 get an EOF. to trigger an EOF we hence open it for
342 reading, but close it right-away which then will
345 fd = session_create_fifo(s);
347 close_nointr_nofail(fd);
351 unsigned long long l;
352 if (sscanf(realtime, "%llu", &l) > 0)
353 s->timestamp.realtime = l;
357 unsigned long long l;
358 if (sscanf(monotonic, "%llu", &l) > 0)
359 s->timestamp.monotonic = l;
365 int session_activate(Session *s) {
377 if (s->seat->active == s)
380 assert(seat_is_vtconsole(s->seat));
386 return seat_set_active(s->seat, s);
389 static int session_link_x11_socket(Session *s) {
395 assert(s->user->runtime_path);
397 if (s->user->display)
400 if (!s->display || !display_is_local(s->display))
403 k = strspn(s->display+1, "0123456789");
404 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
408 c = stpcpy(f, "/tmp/.X11-unix/X");
409 memcpy(c, s->display+1, k);
412 if (access(f, F_OK) < 0) {
413 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
418 /* Note that this cannot be in a subdir to avoid
419 * vulnerabilities since we are privileged but the runtime
420 * path is owned by the user */
422 t = strappend(s->user->runtime_path, "/X11-display");
428 if (link(f, t) < 0) {
429 if (errno == EEXIST) {
436 if (symlink(f, t) < 0) {
438 if (errno == EEXIST) {
441 if (symlink(f, t) >= 0)
445 log_error("Failed to link %s to %s: %m", f, t);
453 log_info("Linked %s to %s.", f, t);
457 s->user->display = s;
462 static int session_create_one_group(Session *s, const char *controller, const char *path) {
470 r = cg_create_and_attach(controller, path, s->leader);
475 r = cg_create(controller, path);
480 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid);
482 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
487 static int session_create_cgroup(Session *s) {
493 assert(s->user->cgroup_path);
495 if (!s->cgroup_path) {
496 _cleanup_free_ char *name = NULL, *escaped = NULL;
498 name = strappend(s->id, ".session");
502 escaped = cg_escape(name);
507 _cleanup_free_ char *slice = NULL;
509 r = cg_slice_to_path(s->slice, &slice);
513 s->cgroup_path = strjoin(s->manager->cgroup_root, "/", slice, "/", escaped, NULL);
515 s->cgroup_path = strjoin(s->user->cgroup_path, "/", escaped, NULL);
522 s->slice = strdup(s->user->slice);
527 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
529 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", s->cgroup_path, strerror(-r));
533 STRV_FOREACH(k, s->controllers) {
535 if (strv_contains(s->reset_controllers, *k))
538 r = session_create_one_group(s, *k, s->cgroup_path);
540 log_warning("Failed to create %s:%s: %s", *k, s->cgroup_path, strerror(-r));
543 STRV_FOREACH(k, s->manager->controllers) {
545 if (strv_contains(s->reset_controllers, *k) ||
546 strv_contains(s->manager->reset_controllers, *k) ||
547 strv_contains(s->controllers, *k))
550 r = session_create_one_group(s, *k, s->cgroup_path);
552 log_warning("Failed to create %s:%s: %s", *k, s->cgroup_path, strerror(-r));
557 STRV_FOREACH(k, s->reset_controllers) {
558 r = cg_attach(*k, "/", s->leader);
560 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
564 STRV_FOREACH(k, s->manager->reset_controllers) {
566 if (strv_contains(s->reset_controllers, *k) ||
567 strv_contains(s->controllers, *k))
570 r = cg_attach(*k, "/", s->leader);
572 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
576 r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
578 log_warning("Failed to create mapping between cgroup and session");
583 int session_start(Session *s) {
594 r = user_start(s->user);
598 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
599 MESSAGE_ID(SD_MESSAGE_SESSION_START),
600 "SESSION_ID=%s", s->id,
601 "USER_ID=%s", s->user->name,
602 "LEADER=%lu", (unsigned long) s->leader,
603 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
607 r = session_create_cgroup(s);
611 /* Create X11 symlink */
612 session_link_x11_socket(s);
614 if (!dual_timestamp_is_set(&s->timestamp))
615 dual_timestamp_get(&s->timestamp);
618 seat_read_active_vt(s->seat);
622 /* Save session data */
626 session_send_signal(s, true);
631 if (s->seat->active == s)
632 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
634 seat_send_changed(s->seat, "Sessions\0");
637 user_send_changed(s->user, "Sessions\0");
642 static bool session_shall_kill(Session *s) {
645 if (!s->kill_processes)
648 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
651 if (strv_isempty(s->manager->kill_only_users))
654 return strv_contains(s->manager->kill_only_users, s->user->name);
657 static int session_terminate_cgroup(Session *s) {
666 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
668 if (session_shall_kill(s)) {
670 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
672 log_error("Failed to kill session cgroup: %s", strerror(-r));
678 /* We still send a HUP to the leader process,
679 * even if we are not supposed to kill the
680 * whole cgroup. But let's first check the
681 * leader still exists and belongs to our
684 r = manager_get_session_by_pid(s->manager, s->leader, &t);
685 if (r > 0 && t == s) {
686 kill(s->leader, SIGTERM); /* for normal processes */
687 kill(s->leader, SIGHUP); /* for shells */
688 kill(s->leader, SIGCONT); /* in case they are stopped */
692 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
694 log_error("Failed to check session cgroup: %s", strerror(-r));
696 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
698 log_error("Failed to delete session cgroup: %s", strerror(-r));
702 STRV_FOREACH(k, s->user->manager->controllers)
703 cg_trim(*k, s->cgroup_path, true);
705 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
707 free(s->cgroup_path);
708 s->cgroup_path = NULL;
713 static int session_unlink_x11_socket(Session *s) {
720 if (s->user->display != s)
723 s->user->display = NULL;
725 t = strappend(s->user->runtime_path, "/X11-display");
732 return r < 0 ? -errno : 0;
735 int session_stop(Session *s) {
744 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
745 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
746 "SESSION_ID=%s", s->id,
747 "USER_ID=%s", s->user->name,
748 "LEADER=%lu", (unsigned long) s->leader,
749 "MESSAGE=Removed session %s.", s->id,
753 k = session_terminate_cgroup(s);
757 /* Remove X11 symlink */
758 session_unlink_x11_socket(s);
760 unlink(s->state_file);
761 session_add_to_gc_queue(s);
762 user_add_to_gc_queue(s->user);
765 session_send_signal(s, false);
770 if (s->seat->active == s)
771 seat_set_active(s->seat, NULL);
773 seat_send_changed(s->seat, "Sessions\0");
777 user_send_changed(s->user, "Sessions\0");
783 bool session_is_active(Session *s) {
789 return s->seat->active == s;
792 static int get_tty_atime(const char *tty, usec_t *atime) {
793 _cleanup_free_ char *p = NULL;
799 if (!path_is_absolute(tty)) {
800 p = strappend("/dev/", tty);
805 } else if (!path_startswith(tty, "/dev/"))
808 if (lstat(tty, &st) < 0)
811 *atime = timespec_load(&st.st_atim);
815 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
816 _cleanup_free_ char *p = NULL;
822 r = get_ctty(pid, NULL, &p);
826 return get_tty_atime(p, atime);
829 int session_get_idle_hint(Session *s, dual_timestamp *t) {
835 /* Explicit idle hint is set */
838 *t = s->idle_hint_timestamp;
843 /* Graphical sessions should really implement a real
848 /* For sessions with an explicitly configured tty, let's check
851 r = get_tty_atime(s->tty, &atime);
856 /* For sessions with a leader but no explicitly configured
857 * tty, let's check the controlling tty of the leader */
859 r = get_process_ctty_atime(s->leader, &atime);
864 /* For other TTY sessions, let's find the most recent atime of
865 * the ttys of any of the processes of the session */
866 if (s->cgroup_path) {
867 _cleanup_fclose_ FILE *f = NULL;
869 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
873 while (cg_read_pid(f, &pid) > 0) {
876 if (get_process_ctty_atime(pid, &a) >= 0)
877 if (atime == 0 || atime < a)
888 *t = s->idle_hint_timestamp;
894 dual_timestamp_from_realtime(t, atime);
896 n = now(CLOCK_REALTIME);
898 if (s->manager->idle_action_usec <= 0)
901 return atime + s->manager->idle_action_usec <= n;
904 void session_set_idle_hint(Session *s, bool b) {
907 if (s->idle_hint == b)
911 dual_timestamp_get(&s->idle_hint_timestamp);
913 session_send_changed(s,
916 "IdleSinceHintMonotonic\0");
919 seat_send_changed(s->seat,
922 "IdleSinceHintMonotonic\0");
924 user_send_changed(s->user,
927 "IdleSinceHintMonotonic\0");
929 manager_send_changed(s->manager,
932 "IdleSinceHintMonotonic\0");
935 int session_create_fifo(Session *s) {
942 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
946 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
949 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
953 /* Open reading side */
954 if (s->fifo_fd < 0) {
955 struct epoll_event ev = {};
957 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
961 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
966 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
968 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
972 /* Open writing side */
973 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
980 void session_remove_fifo(Session *s) {
983 if (s->fifo_fd >= 0) {
984 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
985 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
986 close_nointr_nofail(s->fifo_fd);
994 unlink(s->fifo_path);
1000 int session_check_gc(Session *s, bool drop_not_started) {
1005 if (drop_not_started && !s->started)
1011 if (s->fifo_fd >= 0) {
1013 r = pipe_eof(s->fifo_fd);
1021 if (s->cgroup_path) {
1023 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
1034 void session_add_to_gc_queue(Session *s) {
1040 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
1041 s->in_gc_queue = true;
1044 SessionState session_get_state(Session *s) {
1048 return SESSION_CLOSING;
1050 if (session_is_active(s))
1051 return SESSION_ACTIVE;
1053 return SESSION_ONLINE;
1056 int session_kill(Session *s, KillWho who, int signo) {
1057 _cleanup_set_free_ Set *pid_set = NULL;
1062 if (!s->cgroup_path)
1065 if (s->leader <= 0 && who == KILL_LEADER)
1069 if (kill(s->leader, signo) < 0)
1072 if (who == KILL_ALL) {
1075 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1079 if (s->leader > 0) {
1080 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1085 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1087 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1094 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1095 [SESSION_ONLINE] = "online",
1096 [SESSION_ACTIVE] = "active",
1097 [SESSION_CLOSING] = "closing"
1100 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1102 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1103 [SESSION_TTY] = "tty",
1104 [SESSION_X11] = "x11",
1105 [SESSION_UNSPECIFIED] = "unspecified"
1108 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1110 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1111 [SESSION_USER] = "user",
1112 [SESSION_GREETER] = "greeter",
1113 [SESSION_LOCK_SCREEN] = "lock-screen",
1114 [SESSION_BACKGROUND] = "background"
1117 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1119 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1120 [KILL_LEADER] = "leader",
1124 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);