]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
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
->devices
= hashmap_new(trivial_hash_func
, trivial_compare_func
);
63 s
->id
= path_get_file_name(s
->state_file
);
65 if (hashmap_put(m
->sessions
, s
->id
, s
) < 0) {
66 hashmap_free(s
->devices
);
78 void session_free(Session
*s
) {
84 LIST_REMOVE(Session
, gc_queue
, s
->manager
->session_gc_queue
, s
);
86 session_drop_controller(s
);
88 while ((sd
= hashmap_first(s
->devices
)))
89 session_device_free(sd
);
91 hashmap_free(s
->devices
);
94 LIST_REMOVE(Session
, sessions_by_user
, s
->user
->sessions
, s
);
96 if (s
->user
->display
== s
)
97 s
->user
->display
= NULL
;
101 if (s
->seat
->active
== s
)
102 s
->seat
->active
= NULL
;
103 if (s
->seat
->pending_switch
== s
)
104 s
->seat
->pending_switch
= NULL
;
106 LIST_REMOVE(Session
, sessions_by_seat
, s
->seat
->sessions
, s
);
110 hashmap_remove(s
->manager
->session_units
, s
->scope
);
116 if (s
->create_message
)
117 dbus_message_unref(s
->create_message
);
121 free(s
->remote_host
);
122 free(s
->remote_user
);
125 hashmap_remove(s
->manager
->sessions
, s
->id
);
126 session_remove_fifo(s
);
132 void session_set_user(Session
*s
, User
*u
) {
137 LIST_PREPEND(Session
, sessions_by_user
, u
->sessions
, s
);
140 int session_save(Session
*s
) {
141 _cleanup_fclose_
FILE *f
= NULL
;
142 _cleanup_free_
char *temp_path
= NULL
;
153 r
= mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
157 r
= fopen_temporary(s
->state_file
, &f
, &temp_path
);
163 fchmod(fileno(f
), 0644);
166 "# This is private data. Do not parse.\n"
172 (unsigned long) s
->user
->uid
,
174 session_is_active(s
),
175 session_state_to_string(session_get_state(s
)),
179 fprintf(f
, "TYPE=%s\n", session_type_to_string(s
->type
));
182 fprintf(f
, "CLASS=%s\n", session_class_to_string(s
->class));
185 fprintf(f
, "SCOPE=%s\n", s
->scope
);
188 fprintf(f
, "SCOPE_JOB=%s\n", s
->scope_job
);
191 fprintf(f
, "FIFO=%s\n", s
->fifo_path
);
194 fprintf(f
, "SEAT=%s\n", s
->seat
->id
);
197 fprintf(f
, "TTY=%s\n", s
->tty
);
200 fprintf(f
, "DISPLAY=%s\n", s
->display
);
203 fprintf(f
, "REMOTE_HOST=%s\n", s
->remote_host
);
206 fprintf(f
, "REMOTE_USER=%s\n", s
->remote_user
);
209 fprintf(f
, "SERVICE=%s\n", s
->service
);
211 if (s
->seat
&& seat_has_vts(s
->seat
))
212 fprintf(f
, "VTNR=%i\n", s
->vtnr
);
215 fprintf(f
, "LEADER=%lu\n", (unsigned long) s
->leader
);
218 fprintf(f
, "AUDIT=%"PRIu32
"\n", s
->audit_id
);
220 if (dual_timestamp_is_set(&s
->timestamp
))
224 (unsigned long long) s
->timestamp
.realtime
,
225 (unsigned long long) s
->timestamp
.monotonic
);
229 if (ferror(f
) || rename(temp_path
, s
->state_file
) < 0) {
231 unlink(s
->state_file
);
237 log_error("Failed to save session data for %s: %s", s
->id
, strerror(-r
));
242 int session_load(Session
*s
) {
243 _cleanup_free_
char *remote
= NULL
,
258 r
= parse_env_file(s
->state_file
, NEWLINE
,
261 "SCOPE_JOB", &s
->scope_job
,
262 "FIFO", &s
->fifo_path
,
265 "DISPLAY", &s
->display
,
266 "REMOTE_HOST", &s
->remote_host
,
267 "REMOTE_USER", &s
->remote_user
,
268 "SERVICE", &s
->service
,
274 "REALTIME", &realtime
,
275 "MONOTONIC", &monotonic
,
279 log_error("Failed to read %s: %s", s
->state_file
, strerror(-r
));
288 log_error("UID not specified for session %s", s
->id
);
292 r
= parse_uid(uid
, &u
);
294 log_error("Failed to parse UID value %s for session %s.", uid
, s
->id
);
298 user
= hashmap_get(s
->manager
->users
, ULONG_TO_PTR((unsigned long) u
));
300 log_error("User of session %s not known.", s
->id
);
304 session_set_user(s
, user
);
308 k
= parse_boolean(remote
);
313 if (seat
&& !s
->seat
) {
316 o
= hashmap_get(s
->manager
->seats
, seat
);
318 seat_attach_session(o
, s
);
321 if (vtnr
&& s
->seat
&& seat_has_vts(s
->seat
)) {
324 k
= safe_atoi(vtnr
, &v
);
325 if (k
>= 0 && v
>= 1)
330 k
= parse_pid(leader
, &s
->leader
);
332 audit_session_from_pid(s
->leader
, &s
->audit_id
);
338 t
= session_type_from_string(type
);
346 c
= session_class_from_string(class);
354 /* If we open an unopened pipe for reading we will not
355 get an EOF. to trigger an EOF we hence open it for
356 reading, but close it right-away which then will
359 fd
= session_create_fifo(s
);
361 close_nointr_nofail(fd
);
365 unsigned long long l
;
366 if (sscanf(realtime
, "%llu", &l
) > 0)
367 s
->timestamp
.realtime
= l
;
371 unsigned long long l
;
372 if (sscanf(monotonic
, "%llu", &l
) > 0)
373 s
->timestamp
.monotonic
= l
;
379 int session_activate(Session
*s
) {
380 unsigned int num_pending
;
388 if (s
->seat
->active
== s
)
391 /* on seats with VTs, we let VTs manage session-switching */
392 if (seat_has_vts(s
->seat
)) {
396 return chvt(s
->vtnr
);
399 /* On seats without VTs, we implement session-switching in logind. We
400 * try to pause all session-devices and wait until the session
401 * controller acknowledged them. Once all devices are asleep, we simply
402 * switch the active session and be done.
403 * We save the session we want to switch to in seat->pending_switch and
404 * seat_complete_switch() will perform the final switch. */
406 s
->seat
->pending_switch
= s
;
408 /* if no devices are running, immediately perform the session switch */
409 num_pending
= session_device_try_pause_all(s
);
411 seat_complete_switch(s
->seat
);
416 static int session_link_x11_socket(Session
*s
) {
417 _cleanup_free_
char *t
= NULL
, *f
= NULL
;
423 assert(s
->user
->runtime_path
);
425 if (s
->user
->display
)
428 if (!s
->display
|| !display_is_local(s
->display
))
431 k
= strspn(s
->display
+1, "0123456789");
432 f
= new(char, sizeof("/tmp/.X11-unix/X") + k
);
436 c
= stpcpy(f
, "/tmp/.X11-unix/X");
437 memcpy(c
, s
->display
+1, k
);
440 if (access(f
, F_OK
) < 0) {
441 log_warning("Session %s has display %s with non-existing socket %s.", s
->id
, s
->display
, f
);
445 /* Note that this cannot be in a subdir to avoid
446 * vulnerabilities since we are privileged but the runtime
447 * path is owned by the user */
449 t
= strappend(s
->user
->runtime_path
, "/X11-display");
453 if (link(f
, t
) < 0) {
454 if (errno
== EEXIST
) {
461 if (symlink(f
, t
) < 0) {
463 if (errno
== EEXIST
) {
466 if (symlink(f
, t
) >= 0)
470 log_error("Failed to link %s to %s: %m", f
, t
);
476 log_info("Linked %s to %s.", f
, t
);
477 s
->user
->display
= s
;
482 static int session_start_scope(Session
*s
) {
488 assert(s
->user
->slice
);
490 dbus_error_init(&error
);
493 _cleanup_free_
char *description
= NULL
;
494 const char *kill_mode
;
497 description
= strjoin("Session ", s
->id
, " of user ", s
->user
->name
, NULL
);
501 scope
= strjoin("session-", s
->id
, ".scope", NULL
);
505 kill_mode
= manager_shall_kill(s
->manager
, s
->user
->name
) ? "control-group" : "none";
507 r
= manager_start_scope(s
->manager
, scope
, s
->leader
, s
->user
->slice
, description
, "systemd-user-sessions.service", kill_mode
, &error
, &job
);
509 log_error("Failed to start session scope %s: %s %s",
510 scope
, bus_error(&error
, r
), error
.name
);
511 dbus_error_free(&error
);
524 hashmap_put(s
->manager
->session_units
, s
->scope
, s
);
529 int session_start(Session
*s
) {
540 r
= user_start(s
->user
);
545 r
= session_start_scope(s
);
549 log_struct(s
->type
== SESSION_TTY
|| s
->type
== SESSION_X11
? LOG_INFO
: LOG_DEBUG
,
550 MESSAGE_ID(SD_MESSAGE_SESSION_START
),
551 "SESSION_ID=%s", s
->id
,
552 "USER_ID=%s", s
->user
->name
,
553 "LEADER=%lu", (unsigned long) s
->leader
,
554 "MESSAGE=New session %s of user %s.", s
->id
, s
->user
->name
,
557 /* Create X11 symlink */
558 session_link_x11_socket(s
);
560 if (!dual_timestamp_is_set(&s
->timestamp
))
561 dual_timestamp_get(&s
->timestamp
);
564 seat_read_active_vt(s
->seat
);
568 /* Save session data */
572 session_send_signal(s
, true);
577 if (s
->seat
->active
== s
)
578 seat_send_changed(s
->seat
, "Sessions\0ActiveSession\0");
580 seat_send_changed(s
->seat
, "Sessions\0");
583 user_send_changed(s
->user
, "Sessions\0");
588 static int session_stop_scope(Session
*s
) {
595 dbus_error_init(&error
);
600 r
= manager_stop_unit(s
->manager
, s
->scope
, &error
, &job
);
602 log_error("Failed to stop session scope: %s", bus_error(&error
, r
));
603 dbus_error_free(&error
);
613 static int session_unlink_x11_socket(Session
*s
) {
614 _cleanup_free_
char *t
= NULL
;
620 if (s
->user
->display
!= s
)
623 s
->user
->display
= NULL
;
625 t
= strappend(s
->user
->runtime_path
, "/X11-display");
630 return r
< 0 ? -errno
: 0;
633 int session_stop(Session
*s
) {
642 r
= session_stop_scope(s
);
649 int session_finalize(Session
*s
) {
659 log_struct(s
->type
== SESSION_TTY
|| s
->type
== SESSION_X11
? LOG_INFO
: LOG_DEBUG
,
660 MESSAGE_ID(SD_MESSAGE_SESSION_STOP
),
661 "SESSION_ID=%s", s
->id
,
662 "USER_ID=%s", s
->user
->name
,
663 "LEADER=%lu", (unsigned long) s
->leader
,
664 "MESSAGE=Removed session %s.", s
->id
,
667 /* Kill session devices */
668 while ((sd
= hashmap_first(s
->devices
)))
669 session_device_free(sd
);
671 /* Remove X11 symlink */
672 session_unlink_x11_socket(s
);
674 unlink(s
->state_file
);
675 session_add_to_gc_queue(s
);
676 user_add_to_gc_queue(s
->user
);
679 session_send_signal(s
, false);
684 if (s
->seat
->active
== s
)
685 seat_set_active(s
->seat
, NULL
);
687 seat_send_changed(s
->seat
, "Sessions\0");
691 user_send_changed(s
->user
, "Sessions\0");
697 bool session_is_active(Session
*s
) {
703 return s
->seat
->active
== s
;
706 static int get_tty_atime(const char *tty
, usec_t
*atime
) {
707 _cleanup_free_
char *p
= NULL
;
713 if (!path_is_absolute(tty
)) {
714 p
= strappend("/dev/", tty
);
719 } else if (!path_startswith(tty
, "/dev/"))
722 if (lstat(tty
, &st
) < 0)
725 *atime
= timespec_load(&st
.st_atim
);
729 static int get_process_ctty_atime(pid_t pid
, usec_t
*atime
) {
730 _cleanup_free_
char *p
= NULL
;
736 r
= get_ctty(pid
, NULL
, &p
);
740 return get_tty_atime(p
, atime
);
743 int session_get_idle_hint(Session
*s
, dual_timestamp
*t
) {
749 /* Explicit idle hint is set */
752 *t
= s
->idle_hint_timestamp
;
757 /* Graphical sessions should really implement a real
762 /* For sessions with an explicitly configured tty, let's check
765 r
= get_tty_atime(s
->tty
, &atime
);
770 /* For sessions with a leader but no explicitly configured
771 * tty, let's check the controlling tty of the leader */
773 r
= get_process_ctty_atime(s
->leader
, &atime
);
780 *t
= s
->idle_hint_timestamp
;
786 dual_timestamp_from_realtime(t
, atime
);
788 n
= now(CLOCK_REALTIME
);
790 if (s
->manager
->idle_action_usec
<= 0)
793 return atime
+ s
->manager
->idle_action_usec
<= n
;
796 void session_set_idle_hint(Session
*s
, bool b
) {
799 if (s
->idle_hint
== b
)
803 dual_timestamp_get(&s
->idle_hint_timestamp
);
805 session_send_changed(s
,
808 "IdleSinceHintMonotonic\0");
811 seat_send_changed(s
->seat
,
814 "IdleSinceHintMonotonic\0");
816 user_send_changed(s
->user
,
819 "IdleSinceHintMonotonic\0");
821 manager_send_changed(s
->manager
,
824 "IdleSinceHintMonotonic\0");
827 int session_create_fifo(Session
*s
) {
834 r
= mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
838 if (asprintf(&s
->fifo_path
, "/run/systemd/sessions/%s.ref", s
->id
) < 0)
841 if (mkfifo(s
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
845 /* Open reading side */
846 if (s
->fifo_fd
< 0) {
847 struct epoll_event ev
= {};
849 s
->fifo_fd
= open(s
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NDELAY
);
853 r
= hashmap_put(s
->manager
->session_fds
, INT_TO_PTR(s
->fifo_fd
+ 1), s
);
858 ev
.data
.u32
= FD_OTHER_BASE
+ s
->fifo_fd
;
860 if (epoll_ctl(s
->manager
->epoll_fd
, EPOLL_CTL_ADD
, s
->fifo_fd
, &ev
) < 0)
864 /* Open writing side */
865 r
= open(s
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NDELAY
);
872 void session_remove_fifo(Session
*s
) {
875 if (s
->fifo_fd
>= 0) {
876 assert_se(hashmap_remove(s
->manager
->session_fds
, INT_TO_PTR(s
->fifo_fd
+ 1)) == s
);
877 assert_se(epoll_ctl(s
->manager
->epoll_fd
, EPOLL_CTL_DEL
, s
->fifo_fd
, NULL
) == 0);
878 close_nointr_nofail(s
->fifo_fd
);
886 unlink(s
->fifo_path
);
892 int session_check_gc(Session
*s
, bool drop_not_started
) {
897 if (drop_not_started
&& !s
->started
)
903 if (s
->fifo_fd
>= 0) {
904 r
= pipe_eof(s
->fifo_fd
);
916 return manager_unit_is_active(s
->manager
, s
->scope
) != 0;
921 void session_add_to_gc_queue(Session
*s
) {
927 LIST_PREPEND(Session
, gc_queue
, s
->manager
->session_gc_queue
, s
);
928 s
->in_gc_queue
= true;
931 SessionState
session_get_state(Session
*s
) {
935 return SESSION_CLOSING
;
938 return SESSION_OPENING
;
941 return SESSION_CLOSING
;
943 if (session_is_active(s
))
944 return SESSION_ACTIVE
;
946 return SESSION_ONLINE
;
949 int session_kill(Session
*s
, KillWho who
, int signo
) {
955 return manager_kill_unit(s
->manager
, s
->scope
, who
, signo
, NULL
);
958 bool session_is_controller(Session
*s
, const char *sender
)
962 return streq_ptr(s
->controller
, sender
);
965 int session_set_controller(Session
*s
, const char *sender
, bool force
) {
972 if (session_is_controller(s
, sender
))
974 if (s
->controller
&& !force
)
981 r
= manager_watch_busname(s
->manager
, sender
);
987 session_drop_controller(s
);
993 void session_drop_controller(Session
*s
) {
1001 manager_drop_busname(s
->manager
, s
->controller
);
1002 free(s
->controller
);
1003 s
->controller
= NULL
;
1005 /* Drop all devices as they're now unused. Do that after the controller
1006 * is released to avoid sending out useles dbus signals. */
1007 while ((sd
= hashmap_first(s
->devices
)))
1008 session_device_free(sd
);
1011 static const char* const session_state_table
[_SESSION_STATE_MAX
] = {
1012 [SESSION_OPENING
] = "opening",
1013 [SESSION_ONLINE
] = "online",
1014 [SESSION_ACTIVE
] = "active",
1015 [SESSION_CLOSING
] = "closing"
1018 DEFINE_STRING_TABLE_LOOKUP(session_state
, SessionState
);
1020 static const char* const session_type_table
[_SESSION_TYPE_MAX
] = {
1021 [SESSION_TTY
] = "tty",
1022 [SESSION_X11
] = "x11",
1023 [SESSION_UNSPECIFIED
] = "unspecified"
1026 DEFINE_STRING_TABLE_LOOKUP(session_type
, SessionType
);
1028 static const char* const session_class_table
[_SESSION_CLASS_MAX
] = {
1029 [SESSION_USER
] = "user",
1030 [SESSION_GREETER
] = "greeter",
1031 [SESSION_LOCK_SCREEN
] = "lock-screen",
1032 [SESSION_BACKGROUND
] = "background"
1035 DEFINE_STRING_TABLE_LOOKUP(session_class
, SessionClass
);
1037 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
1038 [KILL_LEADER
] = "leader",
1042 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);