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 "logind-session.h"
32 #include "cgroup-util.h"
34 #define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
36 Session* session_new(Manager *m, User *u, const char *id) {
46 s->state_file = strappend("/run/systemd/sessions/", id);
52 s->id = file_name_from_path(s->state_file);
54 if (hashmap_put(m->sessions, s->id, s) < 0) {
64 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
69 void session_free(Session *s) {
73 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
76 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
78 if (s->user->display == s)
79 s->user->display = NULL;
83 if (s->seat->active == s)
84 s->seat->active = NULL;
86 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
90 hashmap_remove(s->manager->cgroups, s->cgroup_path);
93 strv_free(s->controllers);
101 hashmap_remove(s->manager->sessions, s->id);
103 session_remove_fifo(s);
109 int session_save(Session *s) {
119 r = safe_mkdir("/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"
137 "KILL_PROCESSES=%i\n",
138 (unsigned long) s->user->uid,
140 session_is_active(s),
147 session_type_to_string(s->type));
152 session_class_to_string(s->class));
194 if (s->seat && seat_can_multi_session(s->seat))
202 (unsigned long) s->leader);
207 (unsigned long long) s->audit_id);
211 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
213 unlink(s->state_file);
222 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
227 int session_load(Session *s) {
229 *kill_processes = NULL,
241 r = parse_env_file(s->state_file, NEWLINE,
243 "KILL_PROCESSES", &kill_processes,
244 "CGROUP", &s->cgroup_path,
245 "FIFO", &s->fifo_path,
248 "DISPLAY", &s->display,
249 "REMOTE_HOST", &s->remote_host,
250 "REMOTE_USER", &s->remote_user,
251 "SERVICE", &s->service,
262 k = parse_boolean(remote);
267 if (kill_processes) {
268 k = parse_boolean(kill_processes);
270 s->kill_processes = k;
273 if (seat && !s->seat) {
276 o = hashmap_get(s->manager->seats, seat);
278 seat_attach_session(o, s);
281 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
284 k = safe_atoi(vtnr, &v);
285 if (k >= 0 && v >= 1)
292 k = parse_pid(leader, &pid);
293 if (k >= 0 && pid >= 1) {
296 audit_session_from_pid(pid, &s->audit_id);
303 t = session_type_from_string(type);
311 c = session_class_from_string(class);
319 /* If we open an unopened pipe for reading we will not
320 get an EOF. to trigger an EOF we hence open it for
321 reading, but close it right-away which then will
324 fd = session_create_fifo(s);
326 close_nointr_nofail(fd);
332 free(kill_processes);
341 int session_activate(Session *s) {
352 if (s->seat->active == s)
355 assert(seat_is_vtconsole(s->seat));
361 return seat_set_active(s->seat, s);
364 static int session_link_x11_socket(Session *s) {
370 assert(s->user->runtime_path);
372 if (s->user->display)
375 if (!s->display || !display_is_local(s->display))
378 k = strspn(s->display+1, "0123456789");
379 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
381 log_error("Out of memory");
385 c = stpcpy(f, "/tmp/.X11-unix/X");
386 memcpy(c, s->display+1, k);
389 if (access(f, F_OK) < 0) {
390 log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
395 /* Note that this cannot be in a subdir to avoid
396 * vulnerabilities since we are privileged but the runtime
397 * path is owned by the user */
399 t = strappend(s->user->runtime_path, "/X11-display");
401 log_error("Out of memory");
406 if (link(f, t) < 0) {
407 if (errno == EEXIST) {
414 if (symlink(f, t) < 0) {
416 if (errno == EEXIST) {
419 if (symlink(f, t) >= 0)
423 log_error("Failed to link %s to %s: %m", f, t);
431 log_info("Linked %s to %s.", f, t);
435 s->user->display = s;
440 static int session_create_one_group(Session *s, const char *controller, const char *path) {
448 r = cg_create_and_attach(controller, path, s->leader);
450 r = cg_create(controller, path);
452 r = cg_create(controller, path);
457 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
459 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
464 static int session_create_cgroup(Session *s) {
471 assert(s->user->cgroup_path);
473 if (!s->cgroup_path) {
474 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
475 log_error("Out of memory");
481 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
483 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
485 s->cgroup_path = NULL;
491 STRV_FOREACH(k, s->controllers) {
493 if (strv_contains(s->reset_controllers, *k))
496 r = session_create_one_group(s, *k, p);
498 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
501 STRV_FOREACH(k, s->manager->controllers) {
503 if (strv_contains(s->reset_controllers, *k) ||
504 strv_contains(s->manager->reset_controllers, *k) ||
505 strv_contains(s->controllers, *k))
508 r = session_create_one_group(s, *k, p);
510 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
515 STRV_FOREACH(k, s->reset_controllers) {
516 r = cg_attach(*k, "/", s->leader);
518 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
522 STRV_FOREACH(k, s->manager->reset_controllers) {
524 if (strv_contains(s->reset_controllers, *k) ||
525 strv_contains(s->controllers, *k))
528 r = cg_attach(*k, "/", s->leader);
530 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
535 hashmap_put(s->manager->cgroups, s->cgroup_path, s);
540 int session_start(Session *s) {
549 r = user_start(s->user);
553 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
554 "New session %s of user %s.", s->id, s->user->name);
557 r = session_create_cgroup(s);
561 /* Create X11 symlink */
562 session_link_x11_socket(s);
564 dual_timestamp_get(&s->timestamp);
567 seat_read_active_vt(s->seat);
571 /* Save session data */
575 session_send_signal(s, true);
580 if (s->seat->active == s)
581 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
583 seat_send_changed(s->seat, "Sessions\0");
586 user_send_changed(s->user, "Sessions\0");
591 static bool session_shall_kill(Session *s) {
594 if (!s->kill_processes)
597 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
600 if (strv_isempty(s->manager->kill_only_users))
603 return strv_contains(s->manager->kill_only_users, s->user->name);
606 static int session_terminate_cgroup(Session *s) {
615 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
617 if (session_shall_kill(s)) {
619 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
621 log_error("Failed to kill session cgroup: %s", strerror(-r));
627 /* We still send a HUP to the leader process,
628 * even if we are not supposed to kill the
629 * whole cgroup. But let's first check the
630 * leader still exists and belongs to our
633 r = manager_get_session_by_pid(s->manager, s->leader, &t);
634 if (r > 0 && t == s) {
635 kill(s->leader, SIGTERM); /* for normal processes */
636 kill(s->leader, SIGHUP); /* for shells */
637 kill(s->leader, SIGCONT); /* in case they are stopped */
641 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
643 log_error("Failed to check session cgroup: %s", strerror(-r));
645 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
647 log_error("Failed to delete session cgroup: %s", strerror(-r));
651 STRV_FOREACH(k, s->user->manager->controllers)
652 cg_trim(*k, s->cgroup_path, true);
654 hashmap_remove(s->manager->cgroups, s->cgroup_path);
656 free(s->cgroup_path);
657 s->cgroup_path = NULL;
662 static int session_unlink_x11_socket(Session *s) {
669 if (s->user->display != s)
672 s->user->display = NULL;
674 t = strappend(s->user->runtime_path, "/X11-display");
676 log_error("Out of memory");
683 return r < 0 ? -errno : 0;
686 int session_stop(Session *s) {
692 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
693 "Removed session %s.", s->id);
696 k = session_terminate_cgroup(s);
700 /* Remove X11 symlink */
701 session_unlink_x11_socket(s);
703 unlink(s->state_file);
704 session_add_to_gc_queue(s);
705 user_add_to_gc_queue(s->user);
708 session_send_signal(s, false);
711 if (s->seat->active == s)
712 seat_set_active(s->seat, NULL);
714 seat_send_changed(s->seat, "Sessions\0");
717 user_send_changed(s->user, "Sessions\0");
724 bool session_is_active(Session *s) {
730 return s->seat->active == s;
733 int session_get_idle_hint(Session *s, dual_timestamp *t) {
744 *t = s->idle_hint_timestamp;
752 if (s->tty[0] != '/') {
753 p = strappend("/dev/", s->tty);
759 if (!startswith(p ? p : s->tty, "/dev/")) {
764 k = lstat(p ? p : s->tty, &st);
770 u = timespec_load(&st.st_atim);
771 n = now(CLOCK_REALTIME);
772 b = u + IDLE_THRESHOLD_USEC < n;
775 dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
781 *t = s->idle_hint_timestamp;
786 void session_set_idle_hint(Session *s, bool b) {
789 if (s->idle_hint == b)
793 dual_timestamp_get(&s->idle_hint_timestamp);
795 session_send_changed(s,
798 "IdleSinceHintMonotonic\0");
801 seat_send_changed(s->seat,
804 "IdleSinceHintMonotonic\0");
806 user_send_changed(s->user,
809 "IdleSinceHintMonotonic\0");
811 manager_send_changed(s->manager,
814 "IdleSinceHintMonotonic\0");
817 int session_create_fifo(Session *s) {
824 r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
828 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
831 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
835 /* Open reading side */
836 if (s->fifo_fd < 0) {
837 struct epoll_event ev;
839 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
843 r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
849 ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
851 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
855 /* Open writing side */
856 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
863 void session_remove_fifo(Session *s) {
866 if (s->fifo_fd >= 0) {
867 assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
868 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
869 close_nointr_nofail(s->fifo_fd);
874 unlink(s->fifo_path);
880 int session_check_gc(Session *s, bool drop_not_started) {
885 if (drop_not_started && !s->started)
888 if (s->fifo_fd >= 0) {
890 r = pipe_eof(s->fifo_fd);
898 if (s->cgroup_path) {
900 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
911 void session_add_to_gc_queue(Session *s) {
917 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
918 s->in_gc_queue = true;
921 int session_kill(Session *s, KillWho who, int signo) {
930 if (s->leader <= 0 && who == KILL_LEADER)
934 if (kill(s->leader, signo) < 0)
937 if (who == KILL_ALL) {
940 pid_set = set_new(trivial_hash_func, trivial_compare_func);
945 q = set_put(pid_set, LONG_TO_PTR(s->leader));
950 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
952 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
962 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
963 [SESSION_TTY] = "tty",
964 [SESSION_X11] = "x11",
965 [SESSION_UNSPECIFIED] = "unspecified"
968 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
970 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
971 [SESSION_USER] = "user",
972 [SESSION_GREETER] = "greeter",
973 [SESSION_LOCK_SCREEN] = "lock-screen"
976 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
978 static const char* const kill_who_table[_KILL_WHO_MAX] = {
979 [KILL_LEADER] = "leader",
983 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);