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 _cleanup_free_ char *name = NULL, *escaped = NULL;
470 name = strappend(s->id, ".session");
474 escaped = cg_escape(name);
478 p = strjoin(s->user->cgroup_path, "/", escaped, NULL);
484 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
486 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
488 s->cgroup_path = NULL;
494 STRV_FOREACH(k, s->controllers) {
496 if (strv_contains(s->reset_controllers, *k))
499 r = session_create_one_group(s, *k, p);
501 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
504 STRV_FOREACH(k, s->manager->controllers) {
506 if (strv_contains(s->reset_controllers, *k) ||
507 strv_contains(s->manager->reset_controllers, *k) ||
508 strv_contains(s->controllers, *k))
511 r = session_create_one_group(s, *k, p);
513 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
518 STRV_FOREACH(k, s->reset_controllers) {
519 r = cg_attach(*k, "/", s->leader);
521 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
525 STRV_FOREACH(k, s->manager->reset_controllers) {
527 if (strv_contains(s->reset_controllers, *k) ||
528 strv_contains(s->controllers, *k))
531 r = cg_attach(*k, "/", s->leader);
533 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
538 r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
540 log_warning("Failed to create mapping between cgroup and session");
545 int session_start(Session *s) {
554 r = user_start(s->user);
558 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
559 MESSAGE_ID(SD_MESSAGE_SESSION_START),
560 "SESSION_ID=%s", s->id,
561 "USER_ID=%s", s->user->name,
562 "LEADER=%lu", (unsigned long) s->leader,
563 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
567 r = session_create_cgroup(s);
571 /* Create X11 symlink */
572 session_link_x11_socket(s);
574 dual_timestamp_get(&s->timestamp);
577 seat_read_active_vt(s->seat);
581 /* Save session data */
585 session_send_signal(s, true);
590 if (s->seat->active == s)
591 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
593 seat_send_changed(s->seat, "Sessions\0");
596 user_send_changed(s->user, "Sessions\0");
601 static bool session_shall_kill(Session *s) {
604 if (!s->kill_processes)
607 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
610 if (strv_isempty(s->manager->kill_only_users))
613 return strv_contains(s->manager->kill_only_users, s->user->name);
616 static int session_terminate_cgroup(Session *s) {
625 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
627 if (session_shall_kill(s)) {
629 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
631 log_error("Failed to kill session cgroup: %s", strerror(-r));
637 /* We still send a HUP to the leader process,
638 * even if we are not supposed to kill the
639 * whole cgroup. But let's first check the
640 * leader still exists and belongs to our
643 r = manager_get_session_by_pid(s->manager, s->leader, &t);
644 if (r > 0 && t == s) {
645 kill(s->leader, SIGTERM); /* for normal processes */
646 kill(s->leader, SIGHUP); /* for shells */
647 kill(s->leader, SIGCONT); /* in case they are stopped */
651 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
653 log_error("Failed to check session cgroup: %s", strerror(-r));
655 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
657 log_error("Failed to delete session cgroup: %s", strerror(-r));
661 STRV_FOREACH(k, s->user->manager->controllers)
662 cg_trim(*k, s->cgroup_path, true);
664 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
666 free(s->cgroup_path);
667 s->cgroup_path = NULL;
672 static int session_unlink_x11_socket(Session *s) {
679 if (s->user->display != s)
682 s->user->display = NULL;
684 t = strappend(s->user->runtime_path, "/X11-display");
691 return r < 0 ? -errno : 0;
694 int session_stop(Session *s) {
700 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
701 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
702 "SESSION_ID=%s", s->id,
703 "USER_ID=%s", s->user->name,
704 "LEADER=%lu", (unsigned long) s->leader,
705 "MESSAGE=Removed session %s.", s->id,
709 k = session_terminate_cgroup(s);
713 /* Remove X11 symlink */
714 session_unlink_x11_socket(s);
716 unlink(s->state_file);
717 session_add_to_gc_queue(s);
718 user_add_to_gc_queue(s->user);
721 session_send_signal(s, false);
726 if (s->seat->active == s)
727 seat_set_active(s->seat, NULL);
729 seat_send_changed(s->seat, "Sessions\0");
733 user_send_changed(s->user, "Sessions\0");
739 bool session_is_active(Session *s) {
745 return s->seat->active == s;
748 static int get_tty_atime(const char *tty, usec_t *atime) {
749 _cleanup_free_ char *p = NULL;
755 if (!path_is_absolute(tty)) {
756 p = strappend("/dev/", tty);
761 } else if (!path_startswith(tty, "/dev/"))
764 if (lstat(tty, &st) < 0)
767 *atime = timespec_load(&st.st_atim);
771 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
772 _cleanup_free_ char *p = NULL;
778 r = get_ctty(pid, NULL, &p);
782 return get_tty_atime(p, atime);
785 int session_get_idle_hint(Session *s, dual_timestamp *t) {
791 /* Explicit idle hint is set */
794 *t = s->idle_hint_timestamp;
799 /* Graphical sessions should really implement a real
804 /* For sessions with an explicitly configured tty, let's check
807 r = get_tty_atime(s->tty, &atime);
812 /* For sessions with a leader but no explicitly configured
813 * tty, let's check the controlling tty of the leader */
815 r = get_process_ctty_atime(s->leader, &atime);
820 /* For other TTY sessions, let's find the most recent atime of
821 * the ttys of any of the processes of the session */
822 if (s->cgroup_path) {
823 _cleanup_fclose_ FILE *f = NULL;
825 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
829 while (cg_read_pid(f, &pid) > 0) {
832 if (get_process_ctty_atime(pid, &a) >= 0)
833 if (atime == 0 || atime < a)
844 *t = s->idle_hint_timestamp;
850 dual_timestamp_from_realtime(t, atime);
852 n = now(CLOCK_REALTIME);
854 if (s->manager->idle_action_usec <= 0)
857 return atime + s->manager->idle_action_usec <= n;
860 void session_set_idle_hint(Session *s, bool b) {
863 if (s->idle_hint == b)
867 dual_timestamp_get(&s->idle_hint_timestamp);
869 session_send_changed(s,
872 "IdleSinceHintMonotonic\0");
875 seat_send_changed(s->seat,
878 "IdleSinceHintMonotonic\0");
880 user_send_changed(s->user,
883 "IdleSinceHintMonotonic\0");
885 manager_send_changed(s->manager,
888 "IdleSinceHintMonotonic\0");
891 int session_create_fifo(Session *s) {
898 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
902 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
905 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
909 /* Open reading side */
910 if (s->fifo_fd < 0) {
911 struct epoll_event ev = {};
913 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
917 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
922 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
924 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
928 /* Open writing side */
929 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
936 void session_remove_fifo(Session *s) {
939 if (s->fifo_fd >= 0) {
940 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
941 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
942 close_nointr_nofail(s->fifo_fd);
950 unlink(s->fifo_path);
956 int session_check_gc(Session *s, bool drop_not_started) {
961 if (drop_not_started && !s->started)
964 if (s->fifo_fd >= 0) {
966 r = pipe_eof(s->fifo_fd);
974 if (s->cgroup_path) {
976 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
987 void session_add_to_gc_queue(Session *s) {
993 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
994 s->in_gc_queue = true;
997 SessionState session_get_state(Session *s) {
1001 return SESSION_CLOSING;
1003 if (session_is_active(s))
1004 return SESSION_ACTIVE;
1006 return SESSION_ONLINE;
1009 int session_kill(Session *s, KillWho who, int signo) {
1011 Set *pid_set = NULL;
1015 if (!s->cgroup_path)
1018 if (s->leader <= 0 && who == KILL_LEADER)
1022 if (kill(s->leader, signo) < 0)
1025 if (who == KILL_ALL) {
1028 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1032 if (s->leader > 0) {
1033 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1038 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1040 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1050 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1051 [SESSION_ONLINE] = "online",
1052 [SESSION_ACTIVE] = "active",
1053 [SESSION_CLOSING] = "closing"
1056 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1058 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1059 [SESSION_TTY] = "tty",
1060 [SESSION_X11] = "x11",
1061 [SESSION_UNSPECIFIED] = "unspecified"
1064 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1066 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1067 [SESSION_USER] = "user",
1068 [SESSION_GREETER] = "greeter",
1069 [SESSION_LOCK_SCREEN] = "lock-screen",
1070 [SESSION_BACKGROUND] = "background"
1073 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1075 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1076 [KILL_LEADER] = "leader",
1080 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);