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>
31 #include "path-util.h"
32 #include "cgroup-util.h"
33 #include "logind-session.h"
35 #define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
37 Session
* session_new(Manager
*m
, User
*u
, const char *id
) {
47 s
->state_file
= strappend("/run/systemd/sessions/", id
);
53 s
->id
= path_get_file_name(s
->state_file
);
55 if (hashmap_put(m
->sessions
, s
->id
, s
) < 0) {
65 LIST_PREPEND(Session
, sessions_by_user
, u
->sessions
, s
);
70 void session_free(Session
*s
) {
74 LIST_REMOVE(Session
, gc_queue
, s
->manager
->session_gc_queue
, s
);
77 LIST_REMOVE(Session
, sessions_by_user
, s
->user
->sessions
, s
);
79 if (s
->user
->display
== s
)
80 s
->user
->display
= NULL
;
84 if (s
->seat
->active
== s
)
85 s
->seat
->active
= NULL
;
87 LIST_REMOVE(Session
, sessions_by_seat
, s
->seat
->sessions
, s
);
91 hashmap_remove(s
->manager
->cgroups
, s
->cgroup_path
);
94 strv_free(s
->controllers
);
102 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)
290 k
= parse_pid(leader
, &s
->leader
);
292 audit_session_from_pid(s
->leader
, &s
->audit_id
);
298 t
= session_type_from_string(type
);
306 c
= session_class_from_string(class);
314 /* If we open an unopened pipe for reading we will not
315 get an EOF. to trigger an EOF we hence open it for
316 reading, but close it right-away which then will
319 fd
= session_create_fifo(s
);
321 close_nointr_nofail(fd
);
326 free(kill_processes
);
336 int session_activate(Session
*s
) {
347 if (s
->seat
->active
== s
)
350 assert(seat_is_vtconsole(s
->seat
));
356 return seat_set_active(s
->seat
, s
);
359 static int session_link_x11_socket(Session
*s
) {
365 assert(s
->user
->runtime_path
);
367 if (s
->user
->display
)
370 if (!s
->display
|| !display_is_local(s
->display
))
373 k
= strspn(s
->display
+1, "0123456789");
374 f
= new(char, sizeof("/tmp/.X11-unix/X") + k
);
376 log_error("Out of memory");
380 c
= stpcpy(f
, "/tmp/.X11-unix/X");
381 memcpy(c
, s
->display
+1, k
);
384 if (access(f
, F_OK
) < 0) {
385 log_warning("Session %s has display %s with non-existing socket %s.", s
->id
, s
->display
, f
);
390 /* Note that this cannot be in a subdir to avoid
391 * vulnerabilities since we are privileged but the runtime
392 * path is owned by the user */
394 t
= strappend(s
->user
->runtime_path
, "/X11-display");
396 log_error("Out of memory");
401 if (link(f
, t
) < 0) {
402 if (errno
== EEXIST
) {
409 if (symlink(f
, t
) < 0) {
411 if (errno
== EEXIST
) {
414 if (symlink(f
, t
) >= 0)
418 log_error("Failed to link %s to %s: %m", f
, t
);
426 log_info("Linked %s to %s.", f
, t
);
430 s
->user
->display
= s
;
435 static int session_create_one_group(Session
*s
, const char *controller
, const char *path
) {
443 r
= cg_create_and_attach(controller
, path
, s
->leader
);
445 r
= cg_create(controller
, path
);
447 r
= cg_create(controller
, path
);
452 r
= cg_set_task_access(controller
, path
, 0644, s
->user
->uid
, s
->user
->gid
, -1);
454 r
= cg_set_group_access(controller
, path
, 0755, s
->user
->uid
, s
->user
->gid
);
459 static int session_create_cgroup(Session
*s
) {
466 assert(s
->user
->cgroup_path
);
468 if (!s
->cgroup_path
) {
469 if (asprintf(&p
, "%s/%s", s
->user
->cgroup_path
, s
->id
) < 0) {
470 log_error("Out of memory");
476 r
= session_create_one_group(s
, SYSTEMD_CGROUP_CONTROLLER
, p
);
478 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER
":%s: %s", p
, strerror(-r
));
480 s
->cgroup_path
= NULL
;
486 STRV_FOREACH(k
, s
->controllers
) {
488 if (strv_contains(s
->reset_controllers
, *k
))
491 r
= session_create_one_group(s
, *k
, p
);
493 log_warning("Failed to create %s:%s: %s", *k
, p
, strerror(-r
));
496 STRV_FOREACH(k
, s
->manager
->controllers
) {
498 if (strv_contains(s
->reset_controllers
, *k
) ||
499 strv_contains(s
->manager
->reset_controllers
, *k
) ||
500 strv_contains(s
->controllers
, *k
))
503 r
= session_create_one_group(s
, *k
, p
);
505 log_warning("Failed to create %s:%s: %s", *k
, p
, strerror(-r
));
510 STRV_FOREACH(k
, s
->reset_controllers
) {
511 r
= cg_attach(*k
, "/", s
->leader
);
513 log_warning("Failed to reset controller %s: %s", *k
, strerror(-r
));
517 STRV_FOREACH(k
, s
->manager
->reset_controllers
) {
519 if (strv_contains(s
->reset_controllers
, *k
) ||
520 strv_contains(s
->controllers
, *k
))
523 r
= cg_attach(*k
, "/", s
->leader
);
525 log_warning("Failed to reset controller %s: %s", *k
, strerror(-r
));
530 hashmap_put(s
->manager
->cgroups
, s
->cgroup_path
, s
);
535 int session_start(Session
*s
) {
544 r
= user_start(s
->user
);
548 log_full(s
->type
== SESSION_TTY
|| s
->type
== SESSION_X11
? LOG_INFO
: LOG_DEBUG
,
549 "New session %s of user %s.", s
->id
, s
->user
->name
);
552 r
= session_create_cgroup(s
);
556 /* Create X11 symlink */
557 session_link_x11_socket(s
);
559 dual_timestamp_get(&s
->timestamp
);
562 seat_read_active_vt(s
->seat
);
566 /* Save session data */
570 session_send_signal(s
, true);
575 if (s
->seat
->active
== s
)
576 seat_send_changed(s
->seat
, "Sessions\0ActiveSession\0");
578 seat_send_changed(s
->seat
, "Sessions\0");
581 user_send_changed(s
->user
, "Sessions\0");
586 static bool session_shall_kill(Session
*s
) {
589 if (!s
->kill_processes
)
592 if (strv_contains(s
->manager
->kill_exclude_users
, s
->user
->name
))
595 if (strv_isempty(s
->manager
->kill_only_users
))
598 return strv_contains(s
->manager
->kill_only_users
, s
->user
->name
);
601 static int session_terminate_cgroup(Session
*s
) {
610 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, false);
612 if (session_shall_kill(s
)) {
614 r
= cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, true);
616 log_error("Failed to kill session cgroup: %s", strerror(-r
));
622 /* We still send a HUP to the leader process,
623 * even if we are not supposed to kill the
624 * whole cgroup. But let's first check the
625 * leader still exists and belongs to our
628 r
= manager_get_session_by_pid(s
->manager
, s
->leader
, &t
);
629 if (r
> 0 && t
== s
) {
630 kill(s
->leader
, SIGTERM
); /* for normal processes */
631 kill(s
->leader
, SIGHUP
); /* for shells */
632 kill(s
->leader
, SIGCONT
); /* in case they are stopped */
636 r
= cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, true);
638 log_error("Failed to check session cgroup: %s", strerror(-r
));
640 r
= cg_delete(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
);
642 log_error("Failed to delete session cgroup: %s", strerror(-r
));
646 STRV_FOREACH(k
, s
->user
->manager
->controllers
)
647 cg_trim(*k
, s
->cgroup_path
, true);
649 hashmap_remove(s
->manager
->cgroups
, s
->cgroup_path
);
651 free(s
->cgroup_path
);
652 s
->cgroup_path
= NULL
;
657 static int session_unlink_x11_socket(Session
*s
) {
664 if (s
->user
->display
!= s
)
667 s
->user
->display
= NULL
;
669 t
= strappend(s
->user
->runtime_path
, "/X11-display");
671 log_error("Out of memory");
678 return r
< 0 ? -errno
: 0;
681 int session_stop(Session
*s
) {
687 log_full(s
->type
== SESSION_TTY
|| s
->type
== SESSION_X11
? LOG_INFO
: LOG_DEBUG
,
688 "Removed session %s.", s
->id
);
691 k
= session_terminate_cgroup(s
);
695 /* Remove X11 symlink */
696 session_unlink_x11_socket(s
);
698 unlink(s
->state_file
);
699 session_add_to_gc_queue(s
);
700 user_add_to_gc_queue(s
->user
);
703 session_send_signal(s
, false);
706 if (s
->seat
->active
== s
)
707 seat_set_active(s
->seat
, NULL
);
709 seat_send_changed(s
->seat
, "Sessions\0");
712 user_send_changed(s
->user
, "Sessions\0");
719 bool session_is_active(Session
*s
) {
725 return s
->seat
->active
== s
;
728 int session_get_idle_hint(Session
*s
, dual_timestamp
*t
) {
739 *t
= s
->idle_hint_timestamp
;
747 if (s
->tty
[0] != '/') {
748 p
= strappend("/dev/", s
->tty
);
754 if (!startswith(p
? p
: s
->tty
, "/dev/")) {
759 k
= lstat(p
? p
: s
->tty
, &st
);
765 u
= timespec_load(&st
.st_atim
);
766 n
= now(CLOCK_REALTIME
);
767 b
= u
+ IDLE_THRESHOLD_USEC
< n
;
770 dual_timestamp_from_realtime(t
, u
+ b
? IDLE_THRESHOLD_USEC
: 0);
776 *t
= s
->idle_hint_timestamp
;
781 void session_set_idle_hint(Session
*s
, bool b
) {
784 if (s
->idle_hint
== b
)
788 dual_timestamp_get(&s
->idle_hint_timestamp
);
790 session_send_changed(s
,
793 "IdleSinceHintMonotonic\0");
796 seat_send_changed(s
->seat
,
799 "IdleSinceHintMonotonic\0");
801 user_send_changed(s
->user
,
804 "IdleSinceHintMonotonic\0");
806 manager_send_changed(s
->manager
,
809 "IdleSinceHintMonotonic\0");
812 int session_create_fifo(Session
*s
) {
819 r
= safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
823 if (asprintf(&s
->fifo_path
, "/run/systemd/sessions/%s.ref", s
->id
) < 0)
826 if (mkfifo(s
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
830 /* Open reading side */
831 if (s
->fifo_fd
< 0) {
832 struct epoll_event ev
;
834 s
->fifo_fd
= open(s
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NDELAY
);
838 r
= hashmap_put(s
->manager
->session_fds
, INT_TO_PTR(s
->fifo_fd
+ 1), s
);
844 ev
.data
.u32
= FD_FIFO_BASE
+ s
->fifo_fd
;
846 if (epoll_ctl(s
->manager
->epoll_fd
, EPOLL_CTL_ADD
, s
->fifo_fd
, &ev
) < 0)
850 /* Open writing side */
851 r
= open(s
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NDELAY
);
858 void session_remove_fifo(Session
*s
) {
861 if (s
->fifo_fd
>= 0) {
862 assert_se(hashmap_remove(s
->manager
->session_fds
, INT_TO_PTR(s
->fifo_fd
+ 1)) == s
);
863 assert_se(epoll_ctl(s
->manager
->epoll_fd
, EPOLL_CTL_DEL
, s
->fifo_fd
, NULL
) == 0);
864 close_nointr_nofail(s
->fifo_fd
);
869 unlink(s
->fifo_path
);
875 int session_check_gc(Session
*s
, bool drop_not_started
) {
880 if (drop_not_started
&& !s
->started
)
883 if (s
->fifo_fd
>= 0) {
885 r
= pipe_eof(s
->fifo_fd
);
893 if (s
->cgroup_path
) {
895 r
= cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, false);
906 void session_add_to_gc_queue(Session
*s
) {
912 LIST_PREPEND(Session
, gc_queue
, s
->manager
->session_gc_queue
, s
);
913 s
->in_gc_queue
= true;
916 int session_kill(Session
*s
, KillWho who
, int signo
) {
925 if (s
->leader
<= 0 && who
== KILL_LEADER
)
929 if (kill(s
->leader
, signo
) < 0)
932 if (who
== KILL_ALL
) {
935 pid_set
= set_new(trivial_hash_func
, trivial_compare_func
);
940 q
= set_put(pid_set
, LONG_TO_PTR(s
->leader
));
945 q
= cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, signo
, false, true, false, pid_set
);
947 if (q
!= -EAGAIN
&& q
!= -ESRCH
&& q
!= -ENOENT
)
957 static const char* const session_type_table
[_SESSION_TYPE_MAX
] = {
958 [SESSION_TTY
] = "tty",
959 [SESSION_X11
] = "x11",
960 [SESSION_UNSPECIFIED
] = "unspecified"
963 DEFINE_STRING_TABLE_LOOKUP(session_type
, SessionType
);
965 static const char* const session_class_table
[_SESSION_CLASS_MAX
] = {
966 [SESSION_USER
] = "user",
967 [SESSION_GREETER
] = "greeter",
968 [SESSION_LOCK_SCREEN
] = "lock-screen"
971 DEFINE_STRING_TABLE_LOOKUP(session_class
, SessionClass
);
973 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
974 [KILL_LEADER
] = "leader",
978 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);