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) {
111 _cleanup_fclose_ FILE *f = NULL;
112 _cleanup_free_ char *temp_path = NULL;
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)),
148 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
151 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
154 fprintf(f, "CGROUP=%s\n", s->cgroup_path);
157 fprintf(f, "FIFO=%s\n", s->fifo_path);
160 fprintf(f, "SEAT=%s\n", s->seat->id);
163 fprintf(f, "TTY=%s\n", s->tty);
166 fprintf(f, "DISPLAY=%s\n", s->display);
169 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
172 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
175 fprintf(f, "SERVICE=%s\n", s->service);
177 if (s->seat && seat_can_multi_session(s->seat))
178 fprintf(f, "VTNR=%i\n", s->vtnr);
181 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
184 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
188 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
190 unlink(s->state_file);
196 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
201 int session_load(Session *s) {
203 *kill_processes = NULL,
215 r = parse_env_file(s->state_file, NEWLINE,
217 "KILL_PROCESSES", &kill_processes,
218 "CGROUP", &s->cgroup_path,
219 "FIFO", &s->fifo_path,
222 "DISPLAY", &s->display,
223 "REMOTE_HOST", &s->remote_host,
224 "REMOTE_USER", &s->remote_user,
225 "SERVICE", &s->service,
236 k = parse_boolean(remote);
241 if (kill_processes) {
242 k = parse_boolean(kill_processes);
244 s->kill_processes = k;
247 if (seat && !s->seat) {
250 o = hashmap_get(s->manager->seats, seat);
252 seat_attach_session(o, s);
255 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
258 k = safe_atoi(vtnr, &v);
259 if (k >= 0 && v >= 1)
264 k = parse_pid(leader, &s->leader);
266 audit_session_from_pid(s->leader, &s->audit_id);
272 t = session_type_from_string(type);
280 c = session_class_from_string(class);
288 /* If we open an unopened pipe for reading we will not
289 get an EOF. to trigger an EOF we hence open it for
290 reading, but close it right-away which then will
293 fd = session_create_fifo(s);
295 close_nointr_nofail(fd);
300 free(kill_processes);
310 int session_activate(Session *s) {
321 if (s->seat->active == s)
324 assert(seat_is_vtconsole(s->seat));
330 return seat_set_active(s->seat, s);
333 static int session_link_x11_socket(Session *s) {
339 assert(s->user->runtime_path);
341 if (s->user->display)
344 if (!s->display || !display_is_local(s->display))
347 k = strspn(s->display+1, "0123456789");
348 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
352 c = stpcpy(f, "/tmp/.X11-unix/X");
353 memcpy(c, s->display+1, k);
356 if (access(f, F_OK) < 0) {
357 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
362 /* Note that this cannot be in a subdir to avoid
363 * vulnerabilities since we are privileged but the runtime
364 * path is owned by the user */
366 t = strappend(s->user->runtime_path, "/X11-display");
372 if (link(f, t) < 0) {
373 if (errno == EEXIST) {
380 if (symlink(f, t) < 0) {
382 if (errno == EEXIST) {
385 if (symlink(f, t) >= 0)
389 log_error("Failed to link %s to %s: %m", f, t);
397 log_info("Linked %s to %s.", f, t);
401 s->user->display = s;
406 static int session_create_one_group(Session *s, const char *controller, const char *path) {
413 r = cg_create_and_attach(controller, path, s->leader);
415 r = cg_create(controller, path, NULL);
417 r = cg_create(controller, path, NULL);
422 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
424 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
429 static int session_create_cgroup(Session *s) {
436 assert(s->user->cgroup_path);
438 if (!s->cgroup_path) {
439 _cleanup_free_ char *name = NULL, *escaped = NULL;
441 name = strappend(s->id, ".session");
445 escaped = cg_escape(name);
449 p = strjoin(s->user->cgroup_path, "/", escaped, NULL);
455 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
457 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
459 s->cgroup_path = NULL;
465 STRV_FOREACH(k, s->controllers) {
467 if (strv_contains(s->reset_controllers, *k))
470 r = session_create_one_group(s, *k, p);
472 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
475 STRV_FOREACH(k, s->manager->controllers) {
477 if (strv_contains(s->reset_controllers, *k) ||
478 strv_contains(s->manager->reset_controllers, *k) ||
479 strv_contains(s->controllers, *k))
482 r = session_create_one_group(s, *k, p);
484 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
489 STRV_FOREACH(k, s->reset_controllers) {
490 r = cg_attach(*k, "/", s->leader);
492 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
496 STRV_FOREACH(k, s->manager->reset_controllers) {
498 if (strv_contains(s->reset_controllers, *k) ||
499 strv_contains(s->controllers, *k))
502 r = cg_attach(*k, "/", s->leader);
504 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
509 r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
511 log_warning("Failed to create mapping between cgroup and session");
516 int session_start(Session *s) {
525 r = user_start(s->user);
529 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
530 MESSAGE_ID(SD_MESSAGE_SESSION_START),
531 "SESSION_ID=%s", s->id,
532 "USER_ID=%s", s->user->name,
533 "LEADER=%lu", (unsigned long) s->leader,
534 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
538 r = session_create_cgroup(s);
542 /* Create X11 symlink */
543 session_link_x11_socket(s);
545 dual_timestamp_get(&s->timestamp);
548 seat_read_active_vt(s->seat);
552 /* Save session data */
556 session_send_signal(s, true);
561 if (s->seat->active == s)
562 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
564 seat_send_changed(s->seat, "Sessions\0");
567 user_send_changed(s->user, "Sessions\0");
572 static bool session_shall_kill(Session *s) {
575 if (!s->kill_processes)
578 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
581 if (strv_isempty(s->manager->kill_only_users))
584 return strv_contains(s->manager->kill_only_users, s->user->name);
587 static int session_terminate_cgroup(Session *s) {
596 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
598 if (session_shall_kill(s)) {
600 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
602 log_error("Failed to kill session cgroup: %s", strerror(-r));
608 /* We still send a HUP to the leader process,
609 * even if we are not supposed to kill the
610 * whole cgroup. But let's first check the
611 * leader still exists and belongs to our
614 r = manager_get_session_by_pid(s->manager, s->leader, &t);
615 if (r > 0 && t == s) {
616 kill(s->leader, SIGTERM); /* for normal processes */
617 kill(s->leader, SIGHUP); /* for shells */
618 kill(s->leader, SIGCONT); /* in case they are stopped */
622 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
624 log_error("Failed to check session cgroup: %s", strerror(-r));
626 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
628 log_error("Failed to delete session cgroup: %s", strerror(-r));
632 STRV_FOREACH(k, s->user->manager->controllers)
633 cg_trim(*k, s->cgroup_path, true);
635 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
637 free(s->cgroup_path);
638 s->cgroup_path = NULL;
643 static int session_unlink_x11_socket(Session *s) {
650 if (s->user->display != s)
653 s->user->display = NULL;
655 t = strappend(s->user->runtime_path, "/X11-display");
662 return r < 0 ? -errno : 0;
665 int session_stop(Session *s) {
671 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
672 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
673 "SESSION_ID=%s", s->id,
674 "USER_ID=%s", s->user->name,
675 "LEADER=%lu", (unsigned long) s->leader,
676 "MESSAGE=Removed session %s.", s->id,
680 k = session_terminate_cgroup(s);
684 /* Remove X11 symlink */
685 session_unlink_x11_socket(s);
687 unlink(s->state_file);
688 session_add_to_gc_queue(s);
689 user_add_to_gc_queue(s->user);
692 session_send_signal(s, false);
697 if (s->seat->active == s)
698 seat_set_active(s->seat, NULL);
700 seat_send_changed(s->seat, "Sessions\0");
704 user_send_changed(s->user, "Sessions\0");
710 bool session_is_active(Session *s) {
716 return s->seat->active == s;
719 static int get_tty_atime(const char *tty, usec_t *atime) {
720 _cleanup_free_ char *p = NULL;
726 if (!path_is_absolute(tty)) {
727 p = strappend("/dev/", tty);
732 } else if (!path_startswith(tty, "/dev/"))
735 if (lstat(tty, &st) < 0)
738 *atime = timespec_load(&st.st_atim);
742 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
743 _cleanup_free_ char *p = NULL;
749 r = get_ctty(pid, NULL, &p);
753 return get_tty_atime(p, atime);
756 int session_get_idle_hint(Session *s, dual_timestamp *t) {
762 /* Explicit idle hint is set */
765 *t = s->idle_hint_timestamp;
770 /* Graphical sessions should really implement a real
775 /* For sessions with an explicitly configured tty, let's check
778 r = get_tty_atime(s->tty, &atime);
783 /* For sessions with a leader but no explicitly configured
784 * tty, let's check the controlling tty of the leader */
786 r = get_process_ctty_atime(s->leader, &atime);
791 /* For other TTY sessions, let's find the most recent atime of
792 * the ttys of any of the processes of the session */
793 if (s->cgroup_path) {
794 _cleanup_fclose_ FILE *f = NULL;
796 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
800 while (cg_read_pid(f, &pid) > 0) {
803 if (get_process_ctty_atime(pid, &a) >= 0)
804 if (atime == 0 || atime < a)
815 *t = s->idle_hint_timestamp;
821 dual_timestamp_from_realtime(t, atime);
823 n = now(CLOCK_REALTIME);
825 if (s->manager->idle_action_usec <= 0)
828 return atime + s->manager->idle_action_usec <= n;
831 void session_set_idle_hint(Session *s, bool b) {
834 if (s->idle_hint == b)
838 dual_timestamp_get(&s->idle_hint_timestamp);
840 session_send_changed(s,
843 "IdleSinceHintMonotonic\0");
846 seat_send_changed(s->seat,
849 "IdleSinceHintMonotonic\0");
851 user_send_changed(s->user,
854 "IdleSinceHintMonotonic\0");
856 manager_send_changed(s->manager,
859 "IdleSinceHintMonotonic\0");
862 int session_create_fifo(Session *s) {
869 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
873 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
876 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
880 /* Open reading side */
881 if (s->fifo_fd < 0) {
882 struct epoll_event ev = {};
884 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
888 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
893 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
895 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
899 /* Open writing side */
900 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
907 void session_remove_fifo(Session *s) {
910 if (s->fifo_fd >= 0) {
911 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
912 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
913 close_nointr_nofail(s->fifo_fd);
921 unlink(s->fifo_path);
927 int session_check_gc(Session *s, bool drop_not_started) {
932 if (drop_not_started && !s->started)
935 if (s->fifo_fd >= 0) {
937 r = pipe_eof(s->fifo_fd);
945 if (s->cgroup_path) {
947 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
958 void session_add_to_gc_queue(Session *s) {
964 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
965 s->in_gc_queue = true;
968 SessionState session_get_state(Session *s) {
972 return SESSION_CLOSING;
974 if (session_is_active(s))
975 return SESSION_ACTIVE;
977 return SESSION_ONLINE;
980 int session_kill(Session *s, KillWho who, int signo) {
989 if (s->leader <= 0 && who == KILL_LEADER)
993 if (kill(s->leader, signo) < 0)
996 if (who == KILL_ALL) {
999 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1003 if (s->leader > 0) {
1004 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1009 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1011 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1021 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1022 [SESSION_ONLINE] = "online",
1023 [SESSION_ACTIVE] = "active",
1024 [SESSION_CLOSING] = "closing"
1027 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1029 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1030 [SESSION_TTY] = "tty",
1031 [SESSION_X11] = "x11",
1032 [SESSION_UNSPECIFIED] = "unspecified"
1035 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1037 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1038 [SESSION_USER] = "user",
1039 [SESSION_GREETER] = "greeter",
1040 [SESSION_LOCK_SCREEN] = "lock-screen",
1041 [SESSION_BACKGROUND] = "background"
1044 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1046 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1047 [KILL_LEADER] = "leader",
1051 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);