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 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 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);
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 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) {
775 _cleanup_free_ char *p = NULL;
781 /* Explicit idle hint is set */
784 *t = s->idle_hint_timestamp;
789 /* Graphical sessions really should really implement a real
794 /* For sessions with an explicitly configured tty, let's check
797 r = get_tty_atime(s->tty, &atime);
802 /* For sessions with a leader but no explicitly configured
803 * tty, let's check the controlling tty of the leader */
805 r = get_process_ctty_atime(s->leader, &atime);
810 /* For other TTY sessions, let's find the most recent atime of
811 * the ttys of any of the processes of the session */
812 if (s->cgroup_path) {
813 _cleanup_fclose_ FILE *f = NULL;
815 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
819 while (cg_read_pid(f, &pid) > 0) {
822 if (get_process_ctty_atime(pid, &a) >= 0)
823 if (atime == 0 || atime < a)
834 *t = s->idle_hint_timestamp;
840 dual_timestamp_from_realtime(t, atime);
842 n = now(CLOCK_REALTIME);
844 if (s->manager->idle_action_usec <= 0)
847 return atime + s->manager->idle_action_usec <= n;
850 void session_set_idle_hint(Session *s, bool b) {
853 if (s->idle_hint == b)
857 dual_timestamp_get(&s->idle_hint_timestamp);
859 session_send_changed(s,
862 "IdleSinceHintMonotonic\0");
865 seat_send_changed(s->seat,
868 "IdleSinceHintMonotonic\0");
870 user_send_changed(s->user,
873 "IdleSinceHintMonotonic\0");
875 manager_send_changed(s->manager,
878 "IdleSinceHintMonotonic\0");
881 int session_create_fifo(Session *s) {
888 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
892 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
895 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
899 /* Open reading side */
900 if (s->fifo_fd < 0) {
901 struct epoll_event ev;
903 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
907 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
913 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
915 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
919 /* Open writing side */
920 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
927 void session_remove_fifo(Session *s) {
930 if (s->fifo_fd >= 0) {
931 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
932 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
933 close_nointr_nofail(s->fifo_fd);
941 unlink(s->fifo_path);
947 int session_check_gc(Session *s, bool drop_not_started) {
952 if (drop_not_started && !s->started)
955 if (s->fifo_fd >= 0) {
957 r = pipe_eof(s->fifo_fd);
965 if (s->cgroup_path) {
967 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
978 void session_add_to_gc_queue(Session *s) {
984 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
985 s->in_gc_queue = true;
988 SessionState session_get_state(Session *s) {
992 return SESSION_CLOSING;
994 if (session_is_active(s))
995 return SESSION_ACTIVE;
997 return SESSION_ONLINE;
1000 int session_kill(Session *s, KillWho who, int signo) {
1002 Set *pid_set = NULL;
1006 if (!s->cgroup_path)
1009 if (s->leader <= 0 && who == KILL_LEADER)
1013 if (kill(s->leader, signo) < 0)
1016 if (who == KILL_ALL) {
1019 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1023 if (s->leader > 0) {
1024 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1029 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1031 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1041 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1042 [SESSION_ONLINE] = "online",
1043 [SESSION_ACTIVE] = "active",
1044 [SESSION_CLOSING] = "closing"
1047 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1049 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1050 [SESSION_TTY] = "tty",
1051 [SESSION_X11] = "x11",
1052 [SESSION_UNSPECIFIED] = "unspecified"
1055 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1057 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1058 [SESSION_USER] = "user",
1059 [SESSION_GREETER] = "greeter",
1060 [SESSION_LOCK_SCREEN] = "lock-screen"
1063 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1065 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1066 [KILL_LEADER] = "leader",
1070 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);