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"
37 #define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
39 Session* session_new(Manager *m, User *u, 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) {
67 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
72 void session_free(Session *s) {
76 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
79 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
81 if (s->user->display == s)
82 s->user->display = NULL;
86 if (s->seat->active == s)
87 s->seat->active = NULL;
89 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
93 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
96 strv_free(s->controllers);
100 free(s->remote_host);
101 free(s->remote_user);
104 hashmap_remove(s->manager->sessions, s->id);
105 session_remove_fifo(s);
111 int session_save(Session *s) {
121 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
125 r = fopen_temporary(s->state_file, &f, &temp_path);
131 fchmod(fileno(f), 0644);
134 "# This is private data. Do not parse.\n"
140 "KILL_PROCESSES=%i\n",
141 (unsigned long) s->user->uid,
143 session_is_active(s),
144 session_state_to_string(session_get_state(s)),
151 session_type_to_string(s->type));
156 session_class_to_string(s->class));
198 if (s->seat && seat_can_multi_session(s->seat))
206 (unsigned long) s->leader);
211 (unsigned long long) s->audit_id);
215 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
217 unlink(s->state_file);
226 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
231 int session_load(Session *s) {
233 *kill_processes = NULL,
245 r = parse_env_file(s->state_file, NEWLINE,
247 "KILL_PROCESSES", &kill_processes,
248 "CGROUP", &s->cgroup_path,
249 "FIFO", &s->fifo_path,
252 "DISPLAY", &s->display,
253 "REMOTE_HOST", &s->remote_host,
254 "REMOTE_USER", &s->remote_user,
255 "SERVICE", &s->service,
266 k = parse_boolean(remote);
271 if (kill_processes) {
272 k = parse_boolean(kill_processes);
274 s->kill_processes = k;
277 if (seat && !s->seat) {
280 o = hashmap_get(s->manager->seats, seat);
282 seat_attach_session(o, s);
285 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
288 k = safe_atoi(vtnr, &v);
289 if (k >= 0 && v >= 1)
294 k = parse_pid(leader, &s->leader);
296 audit_session_from_pid(s->leader, &s->audit_id);
302 t = session_type_from_string(type);
310 c = session_class_from_string(class);
318 /* If we open an unopened pipe for reading we will not
319 get an EOF. to trigger an EOF we hence open it for
320 reading, but close it right-away which then will
323 fd = session_create_fifo(s);
325 close_nointr_nofail(fd);
330 free(kill_processes);
340 int session_activate(Session *s) {
351 if (s->seat->active == s)
354 assert(seat_is_vtconsole(s->seat));
360 return seat_set_active(s->seat, s);
363 static int session_link_x11_socket(Session *s) {
369 assert(s->user->runtime_path);
371 if (s->user->display)
374 if (!s->display || !display_is_local(s->display))
377 k = strspn(s->display+1, "0123456789");
378 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
382 c = stpcpy(f, "/tmp/.X11-unix/X");
383 memcpy(c, s->display+1, k);
386 if (access(f, F_OK) < 0) {
387 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
392 /* Note that this cannot be in a subdir to avoid
393 * vulnerabilities since we are privileged but the runtime
394 * path is owned by the user */
396 t = strappend(s->user->runtime_path, "/X11-display");
402 if (link(f, t) < 0) {
403 if (errno == EEXIST) {
410 if (symlink(f, t) < 0) {
412 if (errno == EEXIST) {
415 if (symlink(f, t) >= 0)
419 log_error("Failed to link %s to %s: %m", f, t);
427 log_info("Linked %s to %s.", f, t);
431 s->user->display = s;
436 static int session_create_one_group(Session *s, const char *controller, const char *path) {
444 r = cg_create_and_attach(controller, path, s->leader);
446 r = cg_create(controller, path);
448 r = cg_create(controller, path);
453 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
455 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
460 static int session_create_cgroup(Session *s) {
467 assert(s->user->cgroup_path);
469 if (!s->cgroup_path) {
470 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0)
475 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
477 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
479 s->cgroup_path = NULL;
485 STRV_FOREACH(k, s->controllers) {
487 if (strv_contains(s->reset_controllers, *k))
490 r = session_create_one_group(s, *k, p);
492 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
495 STRV_FOREACH(k, s->manager->controllers) {
497 if (strv_contains(s->reset_controllers, *k) ||
498 strv_contains(s->manager->reset_controllers, *k) ||
499 strv_contains(s->controllers, *k))
502 r = session_create_one_group(s, *k, p);
504 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
509 STRV_FOREACH(k, s->reset_controllers) {
510 r = cg_attach(*k, "/", s->leader);
512 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
516 STRV_FOREACH(k, s->manager->reset_controllers) {
518 if (strv_contains(s->reset_controllers, *k) ||
519 strv_contains(s->controllers, *k))
522 r = cg_attach(*k, "/", s->leader);
524 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
529 hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
534 int session_start(Session *s) {
543 r = user_start(s->user);
547 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
548 "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SESSION_START),
549 "SESSION_ID=%s", s->id,
550 "USER_ID=%s", s->user->name,
551 "LEADER=%lu", (unsigned long) s->leader,
552 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
556 r = session_create_cgroup(s);
560 /* Create X11 symlink */
561 session_link_x11_socket(s);
563 dual_timestamp_get(&s->timestamp);
566 seat_read_active_vt(s->seat);
570 /* Save session data */
574 session_send_signal(s, true);
579 if (s->seat->active == s)
580 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
582 seat_send_changed(s->seat, "Sessions\0");
585 user_send_changed(s->user, "Sessions\0");
590 static bool session_shall_kill(Session *s) {
593 if (!s->kill_processes)
596 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
599 if (strv_isempty(s->manager->kill_only_users))
602 return strv_contains(s->manager->kill_only_users, s->user->name);
605 static int session_terminate_cgroup(Session *s) {
614 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
616 if (session_shall_kill(s)) {
618 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
620 log_error("Failed to kill session cgroup: %s", strerror(-r));
626 /* We still send a HUP to the leader process,
627 * even if we are not supposed to kill the
628 * whole cgroup. But let's first check the
629 * leader still exists and belongs to our
632 r = manager_get_session_by_pid(s->manager, s->leader, &t);
633 if (r > 0 && t == s) {
634 kill(s->leader, SIGTERM); /* for normal processes */
635 kill(s->leader, SIGHUP); /* for shells */
636 kill(s->leader, SIGCONT); /* in case they are stopped */
640 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
642 log_error("Failed to check session cgroup: %s", strerror(-r));
644 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
646 log_error("Failed to delete session cgroup: %s", strerror(-r));
650 STRV_FOREACH(k, s->user->manager->controllers)
651 cg_trim(*k, s->cgroup_path, true);
653 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
655 free(s->cgroup_path);
656 s->cgroup_path = NULL;
661 static int session_unlink_x11_socket(Session *s) {
668 if (s->user->display != s)
671 s->user->display = NULL;
673 t = strappend(s->user->runtime_path, "/X11-display");
680 return r < 0 ? -errno : 0;
683 int session_stop(Session *s) {
689 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
690 "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SESSION_STOP),
691 "SESSION_ID=%s", s->id,
692 "USER_ID=%s", s->user->name,
693 "LEADER=%lu", (unsigned long) s->leader,
694 "MESSAGE=Removed session %s.", s->id,
698 k = session_terminate_cgroup(s);
702 /* Remove X11 symlink */
703 session_unlink_x11_socket(s);
705 unlink(s->state_file);
706 session_add_to_gc_queue(s);
707 user_add_to_gc_queue(s->user);
710 session_send_signal(s, false);
713 if (s->seat->active == s)
714 seat_set_active(s->seat, NULL);
716 seat_send_changed(s->seat, "Sessions\0");
720 user_send_changed(s->user, "Sessions\0");
728 bool session_is_active(Session *s) {
734 return s->seat->active == s;
737 int session_get_idle_hint(Session *s, dual_timestamp *t) {
748 *t = s->idle_hint_timestamp;
756 if (s->tty[0] != '/') {
757 p = strappend("/dev/", s->tty);
763 if (!startswith(p ? p : s->tty, "/dev/")) {
768 k = lstat(p ? p : s->tty, &st);
774 u = timespec_load(&st.st_atim);
775 n = now(CLOCK_REALTIME);
776 b = u + IDLE_THRESHOLD_USEC < n;
779 dual_timestamp_from_realtime(t, u + b*IDLE_THRESHOLD_USEC);
785 *t = s->idle_hint_timestamp;
790 void session_set_idle_hint(Session *s, bool b) {
793 if (s->idle_hint == b)
797 dual_timestamp_get(&s->idle_hint_timestamp);
799 session_send_changed(s,
802 "IdleSinceHintMonotonic\0");
805 seat_send_changed(s->seat,
808 "IdleSinceHintMonotonic\0");
810 user_send_changed(s->user,
813 "IdleSinceHintMonotonic\0");
815 manager_send_changed(s->manager,
818 "IdleSinceHintMonotonic\0");
821 int session_create_fifo(Session *s) {
828 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
832 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
835 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
839 /* Open reading side */
840 if (s->fifo_fd < 0) {
841 struct epoll_event ev;
843 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
847 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
853 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
855 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
859 /* Open writing side */
860 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
867 void session_remove_fifo(Session *s) {
870 if (s->fifo_fd >= 0) {
871 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
872 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
873 close_nointr_nofail(s->fifo_fd);
881 unlink(s->fifo_path);
887 int session_check_gc(Session *s, bool drop_not_started) {
892 if (drop_not_started && !s->started)
895 if (s->fifo_fd >= 0) {
897 r = pipe_eof(s->fifo_fd);
905 if (s->cgroup_path) {
907 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
918 void session_add_to_gc_queue(Session *s) {
924 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
925 s->in_gc_queue = true;
928 SessionState session_get_state(Session *s) {
932 return SESSION_CLOSING;
934 if (session_is_active(s))
935 return SESSION_ACTIVE;
937 return SESSION_ONLINE;
940 int session_kill(Session *s, KillWho who, int signo) {
949 if (s->leader <= 0 && who == KILL_LEADER)
953 if (kill(s->leader, signo) < 0)
956 if (who == KILL_ALL) {
959 pid_set = set_new(trivial_hash_func, trivial_compare_func);
964 q = set_put(pid_set, LONG_TO_PTR(s->leader));
969 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
971 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
981 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
982 [SESSION_ONLINE] = "online",
983 [SESSION_ACTIVE] = "active",
984 [SESSION_CLOSING] = "closing"
987 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
989 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
990 [SESSION_TTY] = "tty",
991 [SESSION_X11] = "x11",
992 [SESSION_UNSPECIFIED] = "unspecified"
995 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
997 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
998 [SESSION_USER] = "user",
999 [SESSION_GREETER] = "greeter",
1000 [SESSION_LOCK_SCREEN] = "lock-screen"
1003 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1005 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1006 [KILL_LEADER] = "leader",
1010 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);