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);
378 log_error("Out of memory");
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");
398 log_error("Out of memory");
403 if (link(f, t) < 0) {
404 if (errno == EEXIST) {
411 if (symlink(f, t) < 0) {
413 if (errno == EEXIST) {
416 if (symlink(f, t) >= 0)
420 log_error("Failed to link %s to %s: %m", f, t);
428 log_info("Linked %s to %s.", f, t);
432 s->user->display = s;
437 static int session_create_one_group(Session *s, const char *controller, const char *path) {
445 r = cg_create_and_attach(controller, path, s->leader);
447 r = cg_create(controller, path);
449 r = cg_create(controller, path);
454 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
456 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
461 static int session_create_cgroup(Session *s) {
468 assert(s->user->cgroup_path);
470 if (!s->cgroup_path) {
471 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
472 log_error("Out of memory");
478 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
480 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
482 s->cgroup_path = NULL;
488 STRV_FOREACH(k, s->controllers) {
490 if (strv_contains(s->reset_controllers, *k))
493 r = session_create_one_group(s, *k, p);
495 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
498 STRV_FOREACH(k, s->manager->controllers) {
500 if (strv_contains(s->reset_controllers, *k) ||
501 strv_contains(s->manager->reset_controllers, *k) ||
502 strv_contains(s->controllers, *k))
505 r = session_create_one_group(s, *k, p);
507 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
512 STRV_FOREACH(k, s->reset_controllers) {
513 r = cg_attach(*k, "/", s->leader);
515 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
519 STRV_FOREACH(k, s->manager->reset_controllers) {
521 if (strv_contains(s->reset_controllers, *k) ||
522 strv_contains(s->controllers, *k))
525 r = cg_attach(*k, "/", s->leader);
527 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
532 hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
537 int session_start(Session *s) {
546 r = user_start(s->user);
550 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
551 "New session %s of user %s.", s->id, s->user->name);
554 r = session_create_cgroup(s);
558 /* Create X11 symlink */
559 session_link_x11_socket(s);
561 dual_timestamp_get(&s->timestamp);
564 seat_read_active_vt(s->seat);
568 /* Save session data */
572 session_send_signal(s, true);
577 if (s->seat->active == s)
578 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
580 seat_send_changed(s->seat, "Sessions\0");
583 user_send_changed(s->user, "Sessions\0");
588 static bool session_shall_kill(Session *s) {
591 if (!s->kill_processes)
594 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
597 if (strv_isempty(s->manager->kill_only_users))
600 return strv_contains(s->manager->kill_only_users, s->user->name);
603 static int session_terminate_cgroup(Session *s) {
612 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
614 if (session_shall_kill(s)) {
616 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
618 log_error("Failed to kill session cgroup: %s", strerror(-r));
624 /* We still send a HUP to the leader process,
625 * even if we are not supposed to kill the
626 * whole cgroup. But let's first check the
627 * leader still exists and belongs to our
630 r = manager_get_session_by_pid(s->manager, s->leader, &t);
631 if (r > 0 && t == s) {
632 kill(s->leader, SIGTERM); /* for normal processes */
633 kill(s->leader, SIGHUP); /* for shells */
634 kill(s->leader, SIGCONT); /* in case they are stopped */
638 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
640 log_error("Failed to check session cgroup: %s", strerror(-r));
642 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
644 log_error("Failed to delete session cgroup: %s", strerror(-r));
648 STRV_FOREACH(k, s->user->manager->controllers)
649 cg_trim(*k, s->cgroup_path, true);
651 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
653 free(s->cgroup_path);
654 s->cgroup_path = NULL;
659 static int session_unlink_x11_socket(Session *s) {
666 if (s->user->display != s)
669 s->user->display = NULL;
671 t = strappend(s->user->runtime_path, "/X11-display");
673 log_error("Out of memory");
680 return r < 0 ? -errno : 0;
683 int session_stop(Session *s) {
689 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
690 "Removed session %s.", s->id);
693 k = session_terminate_cgroup(s);
697 /* Remove X11 symlink */
698 session_unlink_x11_socket(s);
700 unlink(s->state_file);
701 session_add_to_gc_queue(s);
702 user_add_to_gc_queue(s->user);
705 session_send_signal(s, false);
708 if (s->seat->active == s)
709 seat_set_active(s->seat, NULL);
711 seat_send_changed(s->seat, "Sessions\0");
714 user_send_changed(s->user, "Sessions\0");
721 bool session_is_active(Session *s) {
727 return s->seat->active == s;
730 int session_get_idle_hint(Session *s, dual_timestamp *t) {
741 *t = s->idle_hint_timestamp;
749 if (s->tty[0] != '/') {
750 p = strappend("/dev/", s->tty);
756 if (!startswith(p ? p : s->tty, "/dev/")) {
761 k = lstat(p ? p : s->tty, &st);
767 u = timespec_load(&st.st_atim);
768 n = now(CLOCK_REALTIME);
769 b = u + IDLE_THRESHOLD_USEC < n;
772 dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
778 *t = s->idle_hint_timestamp;
783 void session_set_idle_hint(Session *s, bool b) {
786 if (s->idle_hint == b)
790 dual_timestamp_get(&s->idle_hint_timestamp);
792 session_send_changed(s,
795 "IdleSinceHintMonotonic\0");
798 seat_send_changed(s->seat,
801 "IdleSinceHintMonotonic\0");
803 user_send_changed(s->user,
806 "IdleSinceHintMonotonic\0");
808 manager_send_changed(s->manager,
811 "IdleSinceHintMonotonic\0");
814 int session_create_fifo(Session *s) {
821 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
825 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
828 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
832 /* Open reading side */
833 if (s->fifo_fd < 0) {
834 struct epoll_event ev;
836 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
840 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
846 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
848 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
852 /* Open writing side */
853 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
860 void session_remove_fifo(Session *s) {
863 if (s->fifo_fd >= 0) {
864 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
865 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
866 close_nointr_nofail(s->fifo_fd);
871 unlink(s->fifo_path);
877 int session_check_gc(Session *s, bool drop_not_started) {
882 if (drop_not_started && !s->started)
885 if (s->fifo_fd >= 0) {
887 r = pipe_eof(s->fifo_fd);
895 if (s->cgroup_path) {
897 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
908 void session_add_to_gc_queue(Session *s) {
914 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
915 s->in_gc_queue = true;
918 SessionState session_get_state(Session *s) {
922 return SESSION_CLOSING;
924 if (session_is_active(s))
925 return SESSION_ACTIVE;
927 return SESSION_ONLINE;
930 int session_kill(Session *s, KillWho who, int signo) {
939 if (s->leader <= 0 && who == KILL_LEADER)
943 if (kill(s->leader, signo) < 0)
946 if (who == KILL_ALL) {
949 pid_set = set_new(trivial_hash_func, trivial_compare_func);
954 q = set_put(pid_set, LONG_TO_PTR(s->leader));
959 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
961 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
971 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
972 [SESSION_ONLINE] = "online",
973 [SESSION_ACTIVE] = "active",
974 [SESSION_CLOSING] = "closing"
977 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
979 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
980 [SESSION_TTY] = "tty",
981 [SESSION_X11] = "x11",
982 [SESSION_UNSPECIFIED] = "unspecified"
985 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
987 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
988 [SESSION_USER] = "user",
989 [SESSION_GREETER] = "greeter",
990 [SESSION_LOCK_SCREEN] = "lock-screen"
993 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
995 static const char* const kill_who_table[_KILL_WHO_MAX] = {
996 [KILL_LEADER] = "leader",
1000 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);