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 r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
531 log_warning("Failed to create mapping between cgroup and session");
536 int session_start(Session *s) {
545 r = user_start(s->user);
549 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
550 MESSAGE_ID(SD_MESSAGE_SESSION_START),
551 "SESSION_ID=%s", s->id,
552 "USER_ID=%s", s->user->name,
553 "LEADER=%lu", (unsigned long) s->leader,
554 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
558 r = session_create_cgroup(s);
562 /* Create X11 symlink */
563 session_link_x11_socket(s);
565 dual_timestamp_get(&s->timestamp);
568 seat_read_active_vt(s->seat);
572 /* Save session data */
576 session_send_signal(s, true);
581 if (s->seat->active == s)
582 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
584 seat_send_changed(s->seat, "Sessions\0");
587 user_send_changed(s->user, "Sessions\0");
592 static bool session_shall_kill(Session *s) {
595 if (!s->kill_processes)
598 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
601 if (strv_isempty(s->manager->kill_only_users))
604 return strv_contains(s->manager->kill_only_users, s->user->name);
607 static int session_terminate_cgroup(Session *s) {
616 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
618 if (session_shall_kill(s)) {
620 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
622 log_error("Failed to kill session cgroup: %s", strerror(-r));
628 /* We still send a HUP to the leader process,
629 * even if we are not supposed to kill the
630 * whole cgroup. But let's first check the
631 * leader still exists and belongs to our
634 r = manager_get_session_by_pid(s->manager, s->leader, &t);
635 if (r > 0 && t == s) {
636 kill(s->leader, SIGTERM); /* for normal processes */
637 kill(s->leader, SIGHUP); /* for shells */
638 kill(s->leader, SIGCONT); /* in case they are stopped */
642 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
644 log_error("Failed to check session cgroup: %s", strerror(-r));
646 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
648 log_error("Failed to delete session cgroup: %s", strerror(-r));
652 STRV_FOREACH(k, s->user->manager->controllers)
653 cg_trim(*k, s->cgroup_path, true);
655 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
657 free(s->cgroup_path);
658 s->cgroup_path = NULL;
663 static int session_unlink_x11_socket(Session *s) {
670 if (s->user->display != s)
673 s->user->display = NULL;
675 t = strappend(s->user->runtime_path, "/X11-display");
682 return r < 0 ? -errno : 0;
685 int session_stop(Session *s) {
691 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
692 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
693 "SESSION_ID=%s", s->id,
694 "USER_ID=%s", s->user->name,
695 "LEADER=%lu", (unsigned long) s->leader,
696 "MESSAGE=Removed session %s.", s->id,
700 k = session_terminate_cgroup(s);
704 /* Remove X11 symlink */
705 session_unlink_x11_socket(s);
707 unlink(s->state_file);
708 session_add_to_gc_queue(s);
709 user_add_to_gc_queue(s->user);
712 session_send_signal(s, false);
715 if (s->seat->active == s)
716 seat_set_active(s->seat, NULL);
718 seat_send_changed(s->seat, "Sessions\0");
722 user_send_changed(s->user, "Sessions\0");
730 bool session_is_active(Session *s) {
736 return s->seat->active == s;
739 int session_get_idle_hint(Session *s, dual_timestamp *t) {
749 *t = s->idle_hint_timestamp;
757 if (s->tty[0] != '/') {
758 p = strappend("/dev/", s->tty);
764 if (!startswith(p ? p : s->tty, "/dev/")) {
769 k = lstat(p ? p : s->tty, &st);
775 u = timespec_load(&st.st_atim);
776 n = now(CLOCK_REALTIME);
779 dual_timestamp_from_realtime(t, u);
781 return u + IDLE_THRESHOLD_USEC < n;
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);