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) {
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);
912 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
914 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
918 /* Open writing side */
919 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
926 void session_remove_fifo(Session *s) {
929 if (s->fifo_fd >= 0) {
930 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
931 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
932 close_nointr_nofail(s->fifo_fd);
940 unlink(s->fifo_path);
946 int session_check_gc(Session *s, bool drop_not_started) {
951 if (drop_not_started && !s->started)
954 if (s->fifo_fd >= 0) {
956 r = pipe_eof(s->fifo_fd);
964 if (s->cgroup_path) {
966 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
977 void session_add_to_gc_queue(Session *s) {
983 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
984 s->in_gc_queue = true;
987 SessionState session_get_state(Session *s) {
991 return SESSION_CLOSING;
993 if (session_is_active(s))
994 return SESSION_ACTIVE;
996 return SESSION_ONLINE;
999 int session_kill(Session *s, KillWho who, int signo) {
1001 Set *pid_set = NULL;
1005 if (!s->cgroup_path)
1008 if (s->leader <= 0 && who == KILL_LEADER)
1012 if (kill(s->leader, signo) < 0)
1015 if (who == KILL_ALL) {
1018 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1022 if (s->leader > 0) {
1023 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1028 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1030 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1040 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1041 [SESSION_ONLINE] = "online",
1042 [SESSION_ACTIVE] = "active",
1043 [SESSION_CLOSING] = "closing"
1046 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1048 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1049 [SESSION_TTY] = "tty",
1050 [SESSION_X11] = "x11",
1051 [SESSION_UNSPECIFIED] = "unspecified"
1054 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1056 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1057 [SESSION_USER] = "user",
1058 [SESSION_GREETER] = "greeter",
1059 [SESSION_LOCK_SCREEN] = "lock-screen"
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);