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>
31 #include "path-util.h"
32 #include "cgroup-util.h"
33 #include "logind-session.h"
35 #define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
37 Session* session_new(Manager *m, User *u, const char *id) {
47 s->state_file = strappend("/run/systemd/sessions/", id);
53 s->id = path_get_file_name(s->state_file);
55 if (hashmap_put(m->sessions, s->id, s) < 0) {
65 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
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_cgroups, s->cgroup_path);
94 strv_free(s->controllers);
102 hashmap_remove(s->manager->sessions, s->id);
103 session_remove_fifo(s);
109 int session_save(Session *s) {
119 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
123 r = fopen_temporary(s->state_file, &f, &temp_path);
129 fchmod(fileno(f), 0644);
132 "# This is private data. Do not parse.\n"
138 "KILL_PROCESSES=%i\n",
139 (unsigned long) s->user->uid,
141 session_is_active(s),
142 session_state_to_string(session_get_state(s)),
149 session_type_to_string(s->type));
154 session_class_to_string(s->class));
196 if (s->seat && seat_can_multi_session(s->seat))
204 (unsigned long) s->leader);
209 (unsigned long long) s->audit_id);
213 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
215 unlink(s->state_file);
224 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
229 int session_load(Session *s) {
231 *kill_processes = NULL,
243 r = parse_env_file(s->state_file, NEWLINE,
245 "KILL_PROCESSES", &kill_processes,
246 "CGROUP", &s->cgroup_path,
247 "FIFO", &s->fifo_path,
250 "DISPLAY", &s->display,
251 "REMOTE_HOST", &s->remote_host,
252 "REMOTE_USER", &s->remote_user,
253 "SERVICE", &s->service,
264 k = parse_boolean(remote);
269 if (kill_processes) {
270 k = parse_boolean(kill_processes);
272 s->kill_processes = k;
275 if (seat && !s->seat) {
278 o = hashmap_get(s->manager->seats, seat);
280 seat_attach_session(o, s);
283 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
286 k = safe_atoi(vtnr, &v);
287 if (k >= 0 && v >= 1)
292 k = parse_pid(leader, &s->leader);
294 audit_session_from_pid(s->leader, &s->audit_id);
300 t = session_type_from_string(type);
308 c = session_class_from_string(class);
316 /* If we open an unopened pipe for reading we will not
317 get an EOF. to trigger an EOF we hence open it for
318 reading, but close it right-away which then will
321 fd = session_create_fifo(s);
323 close_nointr_nofail(fd);
328 free(kill_processes);
338 int session_activate(Session *s) {
349 if (s->seat->active == s)
352 assert(seat_is_vtconsole(s->seat));
358 return seat_set_active(s->seat, s);
361 static int session_link_x11_socket(Session *s) {
367 assert(s->user->runtime_path);
369 if (s->user->display)
372 if (!s->display || !display_is_local(s->display))
375 k = strspn(s->display+1, "0123456789");
376 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
380 c = stpcpy(f, "/tmp/.X11-unix/X");
381 memcpy(c, s->display+1, k);
384 if (access(f, F_OK) < 0) {
385 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
390 /* Note that this cannot be in a subdir to avoid
391 * vulnerabilities since we are privileged but the runtime
392 * path is owned by the user */
394 t = strappend(s->user->runtime_path, "/X11-display");
400 if (link(f, t) < 0) {
401 if (errno == EEXIST) {
408 if (symlink(f, t) < 0) {
410 if (errno == EEXIST) {
413 if (symlink(f, t) >= 0)
417 log_error("Failed to link %s to %s: %m", f, t);
425 log_info("Linked %s to %s.", f, t);
429 s->user->display = s;
434 static int session_create_one_group(Session *s, const char *controller, const char *path) {
442 r = cg_create_and_attach(controller, path, s->leader);
444 r = cg_create(controller, path);
446 r = cg_create(controller, path);
451 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
453 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
458 static int session_create_cgroup(Session *s) {
465 assert(s->user->cgroup_path);
467 if (!s->cgroup_path) {
468 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0)
473 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
475 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
477 s->cgroup_path = NULL;
483 STRV_FOREACH(k, s->controllers) {
485 if (strv_contains(s->reset_controllers, *k))
488 r = session_create_one_group(s, *k, p);
490 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
493 STRV_FOREACH(k, s->manager->controllers) {
495 if (strv_contains(s->reset_controllers, *k) ||
496 strv_contains(s->manager->reset_controllers, *k) ||
497 strv_contains(s->controllers, *k))
500 r = session_create_one_group(s, *k, p);
502 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
507 STRV_FOREACH(k, s->reset_controllers) {
508 r = cg_attach(*k, "/", s->leader);
510 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
514 STRV_FOREACH(k, s->manager->reset_controllers) {
516 if (strv_contains(s->reset_controllers, *k) ||
517 strv_contains(s->controllers, *k))
520 r = cg_attach(*k, "/", s->leader);
522 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
527 hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
532 int session_start(Session *s) {
541 r = user_start(s->user);
545 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
546 "New session %s of user %s.", s->id, s->user->name);
549 r = session_create_cgroup(s);
553 /* Create X11 symlink */
554 session_link_x11_socket(s);
556 dual_timestamp_get(&s->timestamp);
559 seat_read_active_vt(s->seat);
563 /* Save session data */
567 session_send_signal(s, true);
572 if (s->seat->active == s)
573 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
575 seat_send_changed(s->seat, "Sessions\0");
578 user_send_changed(s->user, "Sessions\0");
583 static bool session_shall_kill(Session *s) {
586 if (!s->kill_processes)
589 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
592 if (strv_isempty(s->manager->kill_only_users))
595 return strv_contains(s->manager->kill_only_users, s->user->name);
598 static int session_terminate_cgroup(Session *s) {
607 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
609 if (session_shall_kill(s)) {
611 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
613 log_error("Failed to kill session cgroup: %s", strerror(-r));
619 /* We still send a HUP to the leader process,
620 * even if we are not supposed to kill the
621 * whole cgroup. But let's first check the
622 * leader still exists and belongs to our
625 r = manager_get_session_by_pid(s->manager, s->leader, &t);
626 if (r > 0 && t == s) {
627 kill(s->leader, SIGTERM); /* for normal processes */
628 kill(s->leader, SIGHUP); /* for shells */
629 kill(s->leader, SIGCONT); /* in case they are stopped */
633 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
635 log_error("Failed to check session cgroup: %s", strerror(-r));
637 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
639 log_error("Failed to delete session cgroup: %s", strerror(-r));
643 STRV_FOREACH(k, s->user->manager->controllers)
644 cg_trim(*k, s->cgroup_path, true);
646 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
648 free(s->cgroup_path);
649 s->cgroup_path = NULL;
654 static int session_unlink_x11_socket(Session *s) {
661 if (s->user->display != s)
664 s->user->display = NULL;
666 t = strappend(s->user->runtime_path, "/X11-display");
673 return r < 0 ? -errno : 0;
676 int session_stop(Session *s) {
682 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
683 "Removed session %s.", s->id);
686 k = session_terminate_cgroup(s);
690 /* Remove X11 symlink */
691 session_unlink_x11_socket(s);
693 unlink(s->state_file);
694 session_add_to_gc_queue(s);
695 user_add_to_gc_queue(s->user);
698 session_send_signal(s, false);
701 if (s->seat->active == s)
702 seat_set_active(s->seat, NULL);
704 seat_send_changed(s->seat, "Sessions\0");
707 user_send_changed(s->user, "Sessions\0");
714 bool session_is_active(Session *s) {
720 return s->seat->active == s;
723 int session_get_idle_hint(Session *s, dual_timestamp *t) {
734 *t = s->idle_hint_timestamp;
742 if (s->tty[0] != '/') {
743 p = strappend("/dev/", s->tty);
749 if (!startswith(p ? p : s->tty, "/dev/")) {
754 k = lstat(p ? p : s->tty, &st);
760 u = timespec_load(&st.st_atim);
761 n = now(CLOCK_REALTIME);
762 b = u + IDLE_THRESHOLD_USEC < n;
765 dual_timestamp_from_realtime(t, u + b*IDLE_THRESHOLD_USEC);
771 *t = s->idle_hint_timestamp;
776 void session_set_idle_hint(Session *s, bool b) {
779 if (s->idle_hint == b)
783 dual_timestamp_get(&s->idle_hint_timestamp);
785 session_send_changed(s,
788 "IdleSinceHintMonotonic\0");
791 seat_send_changed(s->seat,
794 "IdleSinceHintMonotonic\0");
796 user_send_changed(s->user,
799 "IdleSinceHintMonotonic\0");
801 manager_send_changed(s->manager,
804 "IdleSinceHintMonotonic\0");
807 int session_create_fifo(Session *s) {
814 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
818 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
821 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
825 /* Open reading side */
826 if (s->fifo_fd < 0) {
827 struct epoll_event ev;
829 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
833 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
839 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
841 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
845 /* Open writing side */
846 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
853 void session_remove_fifo(Session *s) {
856 if (s->fifo_fd >= 0) {
857 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
858 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
859 close_nointr_nofail(s->fifo_fd);
864 unlink(s->fifo_path);
870 int session_check_gc(Session *s, bool drop_not_started) {
875 if (drop_not_started && !s->started)
878 if (s->fifo_fd >= 0) {
880 r = pipe_eof(s->fifo_fd);
888 if (s->cgroup_path) {
890 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
901 void session_add_to_gc_queue(Session *s) {
907 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
908 s->in_gc_queue = true;
911 SessionState session_get_state(Session *s) {
915 return SESSION_CLOSING;
917 if (session_is_active(s))
918 return SESSION_ACTIVE;
920 return SESSION_ONLINE;
923 int session_kill(Session *s, KillWho who, int signo) {
932 if (s->leader <= 0 && who == KILL_LEADER)
936 if (kill(s->leader, signo) < 0)
939 if (who == KILL_ALL) {
942 pid_set = set_new(trivial_hash_func, trivial_compare_func);
947 q = set_put(pid_set, LONG_TO_PTR(s->leader));
952 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
954 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
964 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
965 [SESSION_ONLINE] = "online",
966 [SESSION_ACTIVE] = "active",
967 [SESSION_CLOSING] = "closing"
970 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
972 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
973 [SESSION_TTY] = "tty",
974 [SESSION_X11] = "x11",
975 [SESSION_UNSPECIFIED] = "unspecified"
978 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
980 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
981 [SESSION_USER] = "user",
982 [SESSION_GREETER] = "greeter",
983 [SESSION_LOCK_SCREEN] = "lock-screen"
986 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
988 static const char* const kill_who_table[_KILL_WHO_MAX] = {
989 [KILL_LEADER] = "leader",
993 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);