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>
34 #include "path-util.h"
36 #include "dbus-common.h"
37 #include "logind-session.h"
39 Session* session_new(Manager *m, const char *id) {
44 assert(session_id_valid(id));
50 s->state_file = strappend("/run/systemd/sessions/", id);
56 s->id = path_get_file_name(s->state_file);
58 if (hashmap_put(m->sessions, s->id, s) < 0) {
70 void session_free(Session *s) {
74 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
76 session_drop_controller(s);
79 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
81 if (s->user->display == s)
82 s->user->display = NULL;
86 if (s->seat->active == s)
87 s->seat->active = NULL;
89 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
93 hashmap_remove(s->manager->session_units, s->scope);
99 if (s->create_message)
100 dbus_message_unref(s->create_message);
104 free(s->remote_host);
105 free(s->remote_user);
108 hashmap_remove(s->manager->sessions, s->id);
109 session_remove_fifo(s);
115 void session_set_user(Session *s, User *u) {
120 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
123 int session_save(Session *s) {
124 _cleanup_fclose_ FILE *f = NULL;
125 _cleanup_free_ char *temp_path = NULL;
136 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
140 r = fopen_temporary(s->state_file, &f, &temp_path);
146 fchmod(fileno(f), 0644);
149 "# This is private data. Do not parse.\n"
155 (unsigned long) s->user->uid,
157 session_is_active(s),
158 session_state_to_string(session_get_state(s)),
162 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
165 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
168 fprintf(f, "SCOPE=%s\n", s->scope);
171 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
174 fprintf(f, "FIFO=%s\n", s->fifo_path);
177 fprintf(f, "SEAT=%s\n", s->seat->id);
180 fprintf(f, "TTY=%s\n", s->tty);
183 fprintf(f, "DISPLAY=%s\n", s->display);
186 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
189 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
192 fprintf(f, "SERVICE=%s\n", s->service);
194 if (s->seat && seat_can_multi_session(s->seat))
195 fprintf(f, "VTNR=%i\n", s->vtnr);
198 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
201 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
203 if (dual_timestamp_is_set(&s->timestamp))
207 (unsigned long long) s->timestamp.realtime,
208 (unsigned long long) s->timestamp.monotonic);
212 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
214 unlink(s->state_file);
220 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
225 int session_load(Session *s) {
226 _cleanup_free_ char *remote = NULL,
241 r = parse_env_file(s->state_file, NEWLINE,
244 "SCOPE_JOB", &s->scope_job,
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,
257 "REALTIME", &realtime,
258 "MONOTONIC", &monotonic,
262 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
271 log_error("UID not specified for session %s", s->id);
275 r = parse_uid(uid, &u);
277 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
281 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
283 log_error("User of session %s not known.", s->id);
287 session_set_user(s, user);
291 k = parse_boolean(remote);
296 if (seat && !s->seat) {
299 o = hashmap_get(s->manager->seats, seat);
301 seat_attach_session(o, s);
304 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
307 k = safe_atoi(vtnr, &v);
308 if (k >= 0 && v >= 1)
313 k = parse_pid(leader, &s->leader);
315 audit_session_from_pid(s->leader, &s->audit_id);
321 t = session_type_from_string(type);
329 c = session_class_from_string(class);
337 /* If we open an unopened pipe for reading we will not
338 get an EOF. to trigger an EOF we hence open it for
339 reading, but close it right-away which then will
342 fd = session_create_fifo(s);
344 close_nointr_nofail(fd);
348 unsigned long long l;
349 if (sscanf(realtime, "%llu", &l) > 0)
350 s->timestamp.realtime = l;
354 unsigned long long l;
355 if (sscanf(monotonic, "%llu", &l) > 0)
356 s->timestamp.monotonic = l;
362 int session_activate(Session *s) {
372 if (s->seat->active == s)
375 assert(seat_is_seat0(s->seat));
377 return chvt(s->vtnr);
380 static int session_link_x11_socket(Session *s) {
381 _cleanup_free_ char *t = NULL, *f = NULL;
387 assert(s->user->runtime_path);
389 if (s->user->display)
392 if (!s->display || !display_is_local(s->display))
395 k = strspn(s->display+1, "0123456789");
396 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
400 c = stpcpy(f, "/tmp/.X11-unix/X");
401 memcpy(c, s->display+1, k);
404 if (access(f, F_OK) < 0) {
405 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
409 /* Note that this cannot be in a subdir to avoid
410 * vulnerabilities since we are privileged but the runtime
411 * path is owned by the user */
413 t = strappend(s->user->runtime_path, "/X11-display");
417 if (link(f, t) < 0) {
418 if (errno == EEXIST) {
425 if (symlink(f, t) < 0) {
427 if (errno == EEXIST) {
430 if (symlink(f, t) >= 0)
434 log_error("Failed to link %s to %s: %m", f, t);
440 log_info("Linked %s to %s.", f, t);
441 s->user->display = s;
446 static int session_start_scope(Session *s) {
452 assert(s->user->slice);
454 dbus_error_init(&error);
457 _cleanup_free_ char *description = NULL;
458 const char *kill_mode;
461 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
465 scope = strjoin("session-", s->id, ".scope", NULL);
469 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
471 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
473 log_error("Failed to start session scope %s: %s %s",
474 scope, bus_error(&error, r), error.name);
475 dbus_error_free(&error);
488 hashmap_put(s->manager->session_units, s->scope, s);
493 int session_start(Session *s) {
504 r = user_start(s->user);
509 r = session_start_scope(s);
513 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
514 MESSAGE_ID(SD_MESSAGE_SESSION_START),
515 "SESSION_ID=%s", s->id,
516 "USER_ID=%s", s->user->name,
517 "LEADER=%lu", (unsigned long) s->leader,
518 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
521 /* Create X11 symlink */
522 session_link_x11_socket(s);
524 if (!dual_timestamp_is_set(&s->timestamp))
525 dual_timestamp_get(&s->timestamp);
528 seat_read_active_vt(s->seat);
532 /* Save session data */
536 session_send_signal(s, true);
541 if (s->seat->active == s)
542 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
544 seat_send_changed(s->seat, "Sessions\0");
547 user_send_changed(s->user, "Sessions\0");
552 static int session_stop_scope(Session *s) {
559 dbus_error_init(&error);
564 r = manager_stop_unit(s->manager, s->scope, &error, &job);
566 log_error("Failed to stop session scope: %s", bus_error(&error, r));
567 dbus_error_free(&error);
577 static int session_unlink_x11_socket(Session *s) {
578 _cleanup_free_ char *t = NULL;
584 if (s->user->display != s)
587 s->user->display = NULL;
589 t = strappend(s->user->runtime_path, "/X11-display");
594 return r < 0 ? -errno : 0;
597 int session_stop(Session *s) {
606 r = session_stop_scope(s);
613 int session_finalize(Session *s) {
622 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
623 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
624 "SESSION_ID=%s", s->id,
625 "USER_ID=%s", s->user->name,
626 "LEADER=%lu", (unsigned long) s->leader,
627 "MESSAGE=Removed session %s.", s->id,
630 /* Remove X11 symlink */
631 session_unlink_x11_socket(s);
633 unlink(s->state_file);
634 session_add_to_gc_queue(s);
635 user_add_to_gc_queue(s->user);
638 session_send_signal(s, false);
643 if (s->seat->active == s)
644 seat_set_active(s->seat, NULL);
646 seat_send_changed(s->seat, "Sessions\0");
650 user_send_changed(s->user, "Sessions\0");
656 bool session_is_active(Session *s) {
662 return s->seat->active == s;
665 static int get_tty_atime(const char *tty, usec_t *atime) {
666 _cleanup_free_ char *p = NULL;
672 if (!path_is_absolute(tty)) {
673 p = strappend("/dev/", tty);
678 } else if (!path_startswith(tty, "/dev/"))
681 if (lstat(tty, &st) < 0)
684 *atime = timespec_load(&st.st_atim);
688 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
689 _cleanup_free_ char *p = NULL;
695 r = get_ctty(pid, NULL, &p);
699 return get_tty_atime(p, atime);
702 int session_get_idle_hint(Session *s, dual_timestamp *t) {
708 /* Explicit idle hint is set */
711 *t = s->idle_hint_timestamp;
716 /* Graphical sessions should really implement a real
721 /* For sessions with an explicitly configured tty, let's check
724 r = get_tty_atime(s->tty, &atime);
729 /* For sessions with a leader but no explicitly configured
730 * tty, let's check the controlling tty of the leader */
732 r = get_process_ctty_atime(s->leader, &atime);
739 *t = s->idle_hint_timestamp;
745 dual_timestamp_from_realtime(t, atime);
747 n = now(CLOCK_REALTIME);
749 if (s->manager->idle_action_usec <= 0)
752 return atime + s->manager->idle_action_usec <= n;
755 void session_set_idle_hint(Session *s, bool b) {
758 if (s->idle_hint == b)
762 dual_timestamp_get(&s->idle_hint_timestamp);
764 session_send_changed(s,
767 "IdleSinceHintMonotonic\0");
770 seat_send_changed(s->seat,
773 "IdleSinceHintMonotonic\0");
775 user_send_changed(s->user,
778 "IdleSinceHintMonotonic\0");
780 manager_send_changed(s->manager,
783 "IdleSinceHintMonotonic\0");
786 int session_create_fifo(Session *s) {
793 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
797 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
800 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
804 /* Open reading side */
805 if (s->fifo_fd < 0) {
806 struct epoll_event ev = {};
808 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
812 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
817 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
819 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
823 /* Open writing side */
824 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
831 void session_remove_fifo(Session *s) {
834 if (s->fifo_fd >= 0) {
835 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
836 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
837 close_nointr_nofail(s->fifo_fd);
845 unlink(s->fifo_path);
851 int session_check_gc(Session *s, bool drop_not_started) {
856 if (drop_not_started && !s->started)
862 if (s->fifo_fd >= 0) {
863 r = pipe_eof(s->fifo_fd);
875 return manager_unit_is_active(s->manager, s->scope) != 0;
880 void session_add_to_gc_queue(Session *s) {
886 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
887 s->in_gc_queue = true;
890 SessionState session_get_state(Session *s) {
894 return SESSION_CLOSING;
897 return SESSION_OPENING;
900 return SESSION_CLOSING;
902 if (session_is_active(s))
903 return SESSION_ACTIVE;
905 return SESSION_ONLINE;
908 int session_kill(Session *s, KillWho who, int signo) {
914 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
917 bool session_is_controller(Session *s, const char *sender)
921 return streq_ptr(s->controller, sender);
924 int session_set_controller(Session *s, const char *sender, bool force) {
931 if (session_is_controller(s, sender))
933 if (s->controller && !force)
940 r = manager_watch_busname(s->manager, sender);
946 session_drop_controller(s);
952 void session_drop_controller(Session *s) {
958 manager_drop_busname(s->manager, s->controller);
960 s->controller = NULL;
963 static const char* const session_state_table[_SESSION_STATE_MAX] = {
964 [SESSION_OPENING] = "opening",
965 [SESSION_ONLINE] = "online",
966 [SESSION_ACTIVE] = "active",
967 [SESSION_CLOSING] = "closing"
970 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
972 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
973 [SESSION_TTY] = "tty",
974 [SESSION_X11] = "x11",
975 [SESSION_UNSPECIFIED] = "unspecified"
978 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
980 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
981 [SESSION_USER] = "user",
982 [SESSION_GREETER] = "greeter",
983 [SESSION_LOCK_SCREEN] = "lock-screen",
984 [SESSION_BACKGROUND] = "background"
987 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
989 static const char* const kill_who_table[_KILL_WHO_MAX] = {
990 [KILL_LEADER] = "leader",
994 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);