]>
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
;
104 LIST_REMOVE(Session
, sessions_by_seat
, s
->seat
->sessions
, s
);
108 hashmap_remove(s
->manager
->session_units
, s
->scope
);
114 if (s
->create_message
)
115 dbus_message_unref(s
->create_message
);
119 free(s
->remote_host
);
120 free(s
->remote_user
);
123 hashmap_remove(s
->manager
->sessions
, s
->id
);
124 session_remove_fifo(s
);
130 void session_set_user(Session
*s
, User
*u
) {
135 LIST_PREPEND(Session
, sessions_by_user
, u
->sessions
, s
);
138 int session_save(Session
*s
) {
139 _cleanup_fclose_
FILE *f
= NULL
;
140 _cleanup_free_
char *temp_path
= NULL
;
151 r
= mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
155 r
= fopen_temporary(s
->state_file
, &f
, &temp_path
);
161 fchmod(fileno(f
), 0644);
164 "# This is private data. Do not parse.\n"
170 (unsigned long) s
->user
->uid
,
172 session_is_active(s
),
173 session_state_to_string(session_get_state(s
)),
177 fprintf(f
, "TYPE=%s\n", session_type_to_string(s
->type
));
180 fprintf(f
, "CLASS=%s\n", session_class_to_string(s
->class));
183 fprintf(f
, "SCOPE=%s\n", s
->scope
);
186 fprintf(f
, "SCOPE_JOB=%s\n", s
->scope_job
);
189 fprintf(f
, "FIFO=%s\n", s
->fifo_path
);
192 fprintf(f
, "SEAT=%s\n", s
->seat
->id
);
195 fprintf(f
, "TTY=%s\n", s
->tty
);
198 fprintf(f
, "DISPLAY=%s\n", s
->display
);
201 fprintf(f
, "REMOTE_HOST=%s\n", s
->remote_host
);
204 fprintf(f
, "REMOTE_USER=%s\n", s
->remote_user
);
207 fprintf(f
, "SERVICE=%s\n", s
->service
);
209 if (s
->seat
&& seat_has_vts(s
->seat
))
210 fprintf(f
, "VTNR=%i\n", s
->vtnr
);
213 fprintf(f
, "LEADER=%lu\n", (unsigned long) s
->leader
);
216 fprintf(f
, "AUDIT=%"PRIu32
"\n", s
->audit_id
);
218 if (dual_timestamp_is_set(&s
->timestamp
))
222 (unsigned long long) s
->timestamp
.realtime
,
223 (unsigned long long) s
->timestamp
.monotonic
);
227 if (ferror(f
) || rename(temp_path
, s
->state_file
) < 0) {
229 unlink(s
->state_file
);
235 log_error("Failed to save session data for %s: %s", s
->id
, strerror(-r
));
240 int session_load(Session
*s
) {
241 _cleanup_free_
char *remote
= NULL
,
256 r
= parse_env_file(s
->state_file
, NEWLINE
,
259 "SCOPE_JOB", &s
->scope_job
,
260 "FIFO", &s
->fifo_path
,
263 "DISPLAY", &s
->display
,
264 "REMOTE_HOST", &s
->remote_host
,
265 "REMOTE_USER", &s
->remote_user
,
266 "SERVICE", &s
->service
,
272 "REALTIME", &realtime
,
273 "MONOTONIC", &monotonic
,
277 log_error("Failed to read %s: %s", s
->state_file
, strerror(-r
));
286 log_error("UID not specified for session %s", s
->id
);
290 r
= parse_uid(uid
, &u
);
292 log_error("Failed to parse UID value %s for session %s.", uid
, s
->id
);
296 user
= hashmap_get(s
->manager
->users
, ULONG_TO_PTR((unsigned long) u
));
298 log_error("User of session %s not known.", s
->id
);
302 session_set_user(s
, user
);
306 k
= parse_boolean(remote
);
311 if (seat
&& !s
->seat
) {
314 o
= hashmap_get(s
->manager
->seats
, seat
);
316 seat_attach_session(o
, s
);
319 if (vtnr
&& s
->seat
&& seat_has_vts(s
->seat
)) {
322 k
= safe_atoi(vtnr
, &v
);
323 if (k
>= 0 && v
>= 1)
328 k
= parse_pid(leader
, &s
->leader
);
330 audit_session_from_pid(s
->leader
, &s
->audit_id
);
336 t
= session_type_from_string(type
);
344 c
= session_class_from_string(class);
352 /* If we open an unopened pipe for reading we will not
353 get an EOF. to trigger an EOF we hence open it for
354 reading, but close it right-away which then will
357 fd
= session_create_fifo(s
);
359 close_nointr_nofail(fd
);
363 unsigned long long l
;
364 if (sscanf(realtime
, "%llu", &l
) > 0)
365 s
->timestamp
.realtime
= l
;
369 unsigned long long l
;
370 if (sscanf(monotonic
, "%llu", &l
) > 0)
371 s
->timestamp
.monotonic
= l
;
377 int session_activate(Session
*s
) {
387 if (s
->seat
->active
== s
)
390 assert(seat_has_vts(s
->seat
));
392 return chvt(s
->vtnr
);
395 static int session_link_x11_socket(Session
*s
) {
396 _cleanup_free_
char *t
= NULL
, *f
= NULL
;
402 assert(s
->user
->runtime_path
);
404 if (s
->user
->display
)
407 if (!s
->display
|| !display_is_local(s
->display
))
410 k
= strspn(s
->display
+1, "0123456789");
411 f
= new(char, sizeof("/tmp/.X11-unix/X") + k
);
415 c
= stpcpy(f
, "/tmp/.X11-unix/X");
416 memcpy(c
, s
->display
+1, k
);
419 if (access(f
, F_OK
) < 0) {
420 log_warning("Session %s has display %s with non-existing socket %s.", s
->id
, s
->display
, f
);
424 /* Note that this cannot be in a subdir to avoid
425 * vulnerabilities since we are privileged but the runtime
426 * path is owned by the user */
428 t
= strappend(s
->user
->runtime_path
, "/X11-display");
432 if (link(f
, t
) < 0) {
433 if (errno
== EEXIST
) {
440 if (symlink(f
, t
) < 0) {
442 if (errno
== EEXIST
) {
445 if (symlink(f
, t
) >= 0)
449 log_error("Failed to link %s to %s: %m", f
, t
);
455 log_info("Linked %s to %s.", f
, t
);
456 s
->user
->display
= s
;
461 static int session_start_scope(Session
*s
) {
467 assert(s
->user
->slice
);
469 dbus_error_init(&error
);
472 _cleanup_free_
char *description
= NULL
;
473 const char *kill_mode
;
476 description
= strjoin("Session ", s
->id
, " of user ", s
->user
->name
, NULL
);
480 scope
= strjoin("session-", s
->id
, ".scope", NULL
);
484 kill_mode
= manager_shall_kill(s
->manager
, s
->user
->name
) ? "control-group" : "none";
486 r
= manager_start_scope(s
->manager
, scope
, s
->leader
, s
->user
->slice
, description
, "systemd-user-sessions.service", kill_mode
, &error
, &job
);
488 log_error("Failed to start session scope %s: %s %s",
489 scope
, bus_error(&error
, r
), error
.name
);
490 dbus_error_free(&error
);
503 hashmap_put(s
->manager
->session_units
, s
->scope
, s
);
508 int session_start(Session
*s
) {
519 r
= user_start(s
->user
);
524 r
= session_start_scope(s
);
528 log_struct(s
->type
== SESSION_TTY
|| s
->type
== SESSION_X11
? LOG_INFO
: LOG_DEBUG
,
529 MESSAGE_ID(SD_MESSAGE_SESSION_START
),
530 "SESSION_ID=%s", s
->id
,
531 "USER_ID=%s", s
->user
->name
,
532 "LEADER=%lu", (unsigned long) s
->leader
,
533 "MESSAGE=New session %s of user %s.", s
->id
, s
->user
->name
,
536 /* Create X11 symlink */
537 session_link_x11_socket(s
);
539 if (!dual_timestamp_is_set(&s
->timestamp
))
540 dual_timestamp_get(&s
->timestamp
);
543 seat_read_active_vt(s
->seat
);
547 /* Save session data */
551 session_send_signal(s
, true);
556 if (s
->seat
->active
== s
)
557 seat_send_changed(s
->seat
, "Sessions\0ActiveSession\0");
559 seat_send_changed(s
->seat
, "Sessions\0");
562 user_send_changed(s
->user
, "Sessions\0");
567 static int session_stop_scope(Session
*s
) {
574 dbus_error_init(&error
);
579 r
= manager_stop_unit(s
->manager
, s
->scope
, &error
, &job
);
581 log_error("Failed to stop session scope: %s", bus_error(&error
, r
));
582 dbus_error_free(&error
);
592 static int session_unlink_x11_socket(Session
*s
) {
593 _cleanup_free_
char *t
= NULL
;
599 if (s
->user
->display
!= s
)
602 s
->user
->display
= NULL
;
604 t
= strappend(s
->user
->runtime_path
, "/X11-display");
609 return r
< 0 ? -errno
: 0;
612 int session_stop(Session
*s
) {
621 r
= session_stop_scope(s
);
628 int session_finalize(Session
*s
) {
638 log_struct(s
->type
== SESSION_TTY
|| s
->type
== SESSION_X11
? LOG_INFO
: LOG_DEBUG
,
639 MESSAGE_ID(SD_MESSAGE_SESSION_STOP
),
640 "SESSION_ID=%s", s
->id
,
641 "USER_ID=%s", s
->user
->name
,
642 "LEADER=%lu", (unsigned long) s
->leader
,
643 "MESSAGE=Removed session %s.", s
->id
,
646 /* Kill session devices */
647 while ((sd
= hashmap_first(s
->devices
)))
648 session_device_free(sd
);
650 /* Remove X11 symlink */
651 session_unlink_x11_socket(s
);
653 unlink(s
->state_file
);
654 session_add_to_gc_queue(s
);
655 user_add_to_gc_queue(s
->user
);
658 session_send_signal(s
, false);
663 if (s
->seat
->active
== s
)
664 seat_set_active(s
->seat
, NULL
);
666 seat_send_changed(s
->seat
, "Sessions\0");
670 user_send_changed(s
->user
, "Sessions\0");
676 bool session_is_active(Session
*s
) {
682 return s
->seat
->active
== s
;
685 static int get_tty_atime(const char *tty
, usec_t
*atime
) {
686 _cleanup_free_
char *p
= NULL
;
692 if (!path_is_absolute(tty
)) {
693 p
= strappend("/dev/", tty
);
698 } else if (!path_startswith(tty
, "/dev/"))
701 if (lstat(tty
, &st
) < 0)
704 *atime
= timespec_load(&st
.st_atim
);
708 static int get_process_ctty_atime(pid_t pid
, usec_t
*atime
) {
709 _cleanup_free_
char *p
= NULL
;
715 r
= get_ctty(pid
, NULL
, &p
);
719 return get_tty_atime(p
, atime
);
722 int session_get_idle_hint(Session
*s
, dual_timestamp
*t
) {
728 /* Explicit idle hint is set */
731 *t
= s
->idle_hint_timestamp
;
736 /* Graphical sessions should really implement a real
741 /* For sessions with an explicitly configured tty, let's check
744 r
= get_tty_atime(s
->tty
, &atime
);
749 /* For sessions with a leader but no explicitly configured
750 * tty, let's check the controlling tty of the leader */
752 r
= get_process_ctty_atime(s
->leader
, &atime
);
759 *t
= s
->idle_hint_timestamp
;
765 dual_timestamp_from_realtime(t
, atime
);
767 n
= now(CLOCK_REALTIME
);
769 if (s
->manager
->idle_action_usec
<= 0)
772 return atime
+ s
->manager
->idle_action_usec
<= n
;
775 void session_set_idle_hint(Session
*s
, bool b
) {
778 if (s
->idle_hint
== b
)
782 dual_timestamp_get(&s
->idle_hint_timestamp
);
784 session_send_changed(s
,
787 "IdleSinceHintMonotonic\0");
790 seat_send_changed(s
->seat
,
793 "IdleSinceHintMonotonic\0");
795 user_send_changed(s
->user
,
798 "IdleSinceHintMonotonic\0");
800 manager_send_changed(s
->manager
,
803 "IdleSinceHintMonotonic\0");
806 int session_create_fifo(Session
*s
) {
813 r
= mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
817 if (asprintf(&s
->fifo_path
, "/run/systemd/sessions/%s.ref", s
->id
) < 0)
820 if (mkfifo(s
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
824 /* Open reading side */
825 if (s
->fifo_fd
< 0) {
826 struct epoll_event ev
= {};
828 s
->fifo_fd
= open(s
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NDELAY
);
832 r
= hashmap_put(s
->manager
->session_fds
, INT_TO_PTR(s
->fifo_fd
+ 1), s
);
837 ev
.data
.u32
= FD_OTHER_BASE
+ s
->fifo_fd
;
839 if (epoll_ctl(s
->manager
->epoll_fd
, EPOLL_CTL_ADD
, s
->fifo_fd
, &ev
) < 0)
843 /* Open writing side */
844 r
= open(s
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NDELAY
);
851 void session_remove_fifo(Session
*s
) {
854 if (s
->fifo_fd
>= 0) {
855 assert_se(hashmap_remove(s
->manager
->session_fds
, INT_TO_PTR(s
->fifo_fd
+ 1)) == s
);
856 assert_se(epoll_ctl(s
->manager
->epoll_fd
, EPOLL_CTL_DEL
, s
->fifo_fd
, NULL
) == 0);
857 close_nointr_nofail(s
->fifo_fd
);
865 unlink(s
->fifo_path
);
871 int session_check_gc(Session
*s
, bool drop_not_started
) {
876 if (drop_not_started
&& !s
->started
)
882 if (s
->fifo_fd
>= 0) {
883 r
= pipe_eof(s
->fifo_fd
);
895 return manager_unit_is_active(s
->manager
, s
->scope
) != 0;
900 void session_add_to_gc_queue(Session
*s
) {
906 LIST_PREPEND(Session
, gc_queue
, s
->manager
->session_gc_queue
, s
);
907 s
->in_gc_queue
= true;
910 SessionState
session_get_state(Session
*s
) {
914 return SESSION_CLOSING
;
917 return SESSION_OPENING
;
920 return SESSION_CLOSING
;
922 if (session_is_active(s
))
923 return SESSION_ACTIVE
;
925 return SESSION_ONLINE
;
928 int session_kill(Session
*s
, KillWho who
, int signo
) {
934 return manager_kill_unit(s
->manager
, s
->scope
, who
, signo
, NULL
);
937 bool session_is_controller(Session
*s
, const char *sender
)
941 return streq_ptr(s
->controller
, sender
);
944 int session_set_controller(Session
*s
, const char *sender
, bool force
) {
951 if (session_is_controller(s
, sender
))
953 if (s
->controller
&& !force
)
960 r
= manager_watch_busname(s
->manager
, sender
);
966 session_drop_controller(s
);
972 void session_drop_controller(Session
*s
) {
980 manager_drop_busname(s
->manager
, s
->controller
);
982 s
->controller
= NULL
;
984 /* Drop all devices as they're now unused. Do that after the controller
985 * is released to avoid sending out useles dbus signals. */
986 while ((sd
= hashmap_first(s
->devices
)))
987 session_device_free(sd
);
990 static const char* const session_state_table
[_SESSION_STATE_MAX
] = {
991 [SESSION_OPENING
] = "opening",
992 [SESSION_ONLINE
] = "online",
993 [SESSION_ACTIVE
] = "active",
994 [SESSION_CLOSING
] = "closing"
997 DEFINE_STRING_TABLE_LOOKUP(session_state
, SessionState
);
999 static const char* const session_type_table
[_SESSION_TYPE_MAX
] = {
1000 [SESSION_TTY
] = "tty",
1001 [SESSION_X11
] = "x11",
1002 [SESSION_UNSPECIFIED
] = "unspecified"
1005 DEFINE_STRING_TABLE_LOOKUP(session_type
, SessionType
);
1007 static const char* const session_class_table
[_SESSION_CLASS_MAX
] = {
1008 [SESSION_USER
] = "user",
1009 [SESSION_GREETER
] = "greeter",
1010 [SESSION_LOCK_SCREEN
] = "lock-screen",
1011 [SESSION_BACKGROUND
] = "background"
1014 DEFINE_STRING_TABLE_LOOKUP(session_class
, SessionClass
);
1016 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
1017 [KILL_LEADER
] = "leader",
1021 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);