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, User *u, 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) {
66 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
71 void session_free(Session *s) {
75 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
78 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
80 if (s->user->display == s)
81 s->user->display = NULL;
85 if (s->seat->active == s)
86 s->seat->active = NULL;
88 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
92 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
95 strv_free(s->controllers);
100 free(s->remote_user);
103 hashmap_remove(s->manager->sessions, s->id);
104 session_remove_fifo(s);
110 int session_save(Session *s) {
120 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
124 r = fopen_temporary(s->state_file, &f, &temp_path);
130 fchmod(fileno(f), 0644);
133 "# This is private data. Do not parse.\n"
139 "KILL_PROCESSES=%i\n",
140 (unsigned long) s->user->uid,
142 session_is_active(s),
143 session_state_to_string(session_get_state(s)),
150 session_type_to_string(s->type));
155 session_class_to_string(s->class));
197 if (s->seat && seat_can_multi_session(s->seat))
205 (unsigned long) s->leader);
210 (unsigned long long) s->audit_id);
214 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
216 unlink(s->state_file);
225 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
230 int session_load(Session *s) {
232 *kill_processes = NULL,
244 r = parse_env_file(s->state_file, NEWLINE,
246 "KILL_PROCESSES", &kill_processes,
247 "CGROUP", &s->cgroup_path,
248 "FIFO", &s->fifo_path,
251 "DISPLAY", &s->display,
252 "REMOTE_HOST", &s->remote_host,
253 "REMOTE_USER", &s->remote_user,
254 "SERVICE", &s->service,
265 k = parse_boolean(remote);
270 if (kill_processes) {
271 k = parse_boolean(kill_processes);
273 s->kill_processes = k;
276 if (seat && !s->seat) {
279 o = hashmap_get(s->manager->seats, seat);
281 seat_attach_session(o, s);
284 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
287 k = safe_atoi(vtnr, &v);
288 if (k >= 0 && v >= 1)
293 k = parse_pid(leader, &s->leader);
295 audit_session_from_pid(s->leader, &s->audit_id);
301 t = session_type_from_string(type);
309 c = session_class_from_string(class);
317 /* If we open an unopened pipe for reading we will not
318 get an EOF. to trigger an EOF we hence open it for
319 reading, but close it right-away which then will
322 fd = session_create_fifo(s);
324 close_nointr_nofail(fd);
329 free(kill_processes);
339 int session_activate(Session *s) {
350 if (s->seat->active == s)
353 assert(seat_is_vtconsole(s->seat));
359 return seat_set_active(s->seat, s);
362 static int session_link_x11_socket(Session *s) {
368 assert(s->user->runtime_path);
370 if (s->user->display)
373 if (!s->display || !display_is_local(s->display))
376 k = strspn(s->display+1, "0123456789");
377 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
381 c = stpcpy(f, "/tmp/.X11-unix/X");
382 memcpy(c, s->display+1, k);
385 if (access(f, F_OK) < 0) {
386 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
391 /* Note that this cannot be in a subdir to avoid
392 * vulnerabilities since we are privileged but the runtime
393 * path is owned by the user */
395 t = strappend(s->user->runtime_path, "/X11-display");
401 if (link(f, t) < 0) {
402 if (errno == EEXIST) {
409 if (symlink(f, t) < 0) {
411 if (errno == EEXIST) {
414 if (symlink(f, t) >= 0)
418 log_error("Failed to link %s to %s: %m", f, t);
426 log_info("Linked %s to %s.", f, t);
430 s->user->display = s;
435 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, NULL);
446 r = cg_create(controller, path, NULL);
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 r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
529 log_warning("Failed to create mapping between cgroup and session");
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_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_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);
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");
728 bool session_is_active(Session *s) {
734 return s->seat->active == s;
737 static int get_tty_atime(const char *tty, usec_t *atime) {
738 _cleanup_free_ char *p = NULL;
744 if (!path_is_absolute(tty)) {
745 p = strappend("/dev/", tty);
750 } else if (!path_startswith(tty, "/dev/"))
753 if (lstat(tty, &st) < 0)
756 *atime = timespec_load(&st.st_atim);
760 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
761 _cleanup_free_ char *p = NULL;
767 r = get_ctty(pid, NULL, &p);
771 return get_tty_atime(p, atime);
774 int session_get_idle_hint(Session *s, dual_timestamp *t) {
780 /* Explicit idle hint is set */
783 *t = s->idle_hint_timestamp;
788 /* Graphical sessions should really implement a real
793 /* For sessions with an explicitly configured tty, let's check
796 r = get_tty_atime(s->tty, &atime);
801 /* For sessions with a leader but no explicitly configured
802 * tty, let's check the controlling tty of the leader */
804 r = get_process_ctty_atime(s->leader, &atime);
809 /* For other TTY sessions, let's find the most recent atime of
810 * the ttys of any of the processes of the session */
811 if (s->cgroup_path) {
812 _cleanup_fclose_ FILE *f = NULL;
814 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
818 while (cg_read_pid(f, &pid) > 0) {
821 if (get_process_ctty_atime(pid, &a) >= 0)
822 if (atime == 0 || atime < a)
833 *t = s->idle_hint_timestamp;
839 dual_timestamp_from_realtime(t, atime);
841 n = now(CLOCK_REALTIME);
843 if (s->manager->idle_action_usec <= 0)
846 return atime + s->manager->idle_action_usec <= n;
849 void session_set_idle_hint(Session *s, bool b) {
852 if (s->idle_hint == b)
856 dual_timestamp_get(&s->idle_hint_timestamp);
858 session_send_changed(s,
861 "IdleSinceHintMonotonic\0");
864 seat_send_changed(s->seat,
867 "IdleSinceHintMonotonic\0");
869 user_send_changed(s->user,
872 "IdleSinceHintMonotonic\0");
874 manager_send_changed(s->manager,
877 "IdleSinceHintMonotonic\0");
880 int session_create_fifo(Session *s) {
887 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
891 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
894 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
898 /* Open reading side */
899 if (s->fifo_fd < 0) {
900 struct epoll_event ev = {};
902 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
906 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
911 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
913 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
917 /* Open writing side */
918 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
925 void session_remove_fifo(Session *s) {
928 if (s->fifo_fd >= 0) {
929 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
930 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
931 close_nointr_nofail(s->fifo_fd);
939 unlink(s->fifo_path);
945 int session_check_gc(Session *s, bool drop_not_started) {
950 if (drop_not_started && !s->started)
953 if (s->fifo_fd >= 0) {
955 r = pipe_eof(s->fifo_fd);
963 if (s->cgroup_path) {
965 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
976 void session_add_to_gc_queue(Session *s) {
982 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
983 s->in_gc_queue = true;
986 SessionState session_get_state(Session *s) {
990 return SESSION_CLOSING;
992 if (session_is_active(s))
993 return SESSION_ACTIVE;
995 return SESSION_ONLINE;
998 int session_kill(Session *s, KillWho who, int signo) {
1000 Set *pid_set = NULL;
1004 if (!s->cgroup_path)
1007 if (s->leader <= 0 && who == KILL_LEADER)
1011 if (kill(s->leader, signo) < 0)
1014 if (who == KILL_ALL) {
1017 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1021 if (s->leader > 0) {
1022 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1027 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1029 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1039 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1040 [SESSION_ONLINE] = "online",
1041 [SESSION_ACTIVE] = "active",
1042 [SESSION_CLOSING] = "closing"
1045 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1047 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1048 [SESSION_TTY] = "tty",
1049 [SESSION_X11] = "x11",
1050 [SESSION_UNSPECIFIED] = "unspecified"
1053 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1055 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1056 [SESSION_USER] = "user",
1057 [SESSION_GREETER] = "greeter",
1058 [SESSION_LOCK_SCREEN] = "lock-screen",
1059 [SESSION_BACKGROUND] = "background"
1062 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1064 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1065 [KILL_LEADER] = "leader",
1069 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);