]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
Merge pull request #31173 from yuwata/network-route-check-conflict
[thirdparty/systemd.git] / src / login / logind-session.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <linux/kd.h>
6 #include <linux/vt.h>
7 #include <signal.h>
8 #include <sys/ioctl.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11
12 #include "sd-messages.h"
13
14 #include "alloc-util.h"
15 #include "audit-util.h"
16 #include "bus-error.h"
17 #include "bus-util.h"
18 #include "daemon-util.h"
19 #include "devnum-util.h"
20 #include "env-file.h"
21 #include "escape.h"
22 #include "fd-util.h"
23 #include "fileio.h"
24 #include "format-util.h"
25 #include "fs-util.h"
26 #include "io-util.h"
27 #include "logind-dbus.h"
28 #include "logind-seat-dbus.h"
29 #include "logind-session-dbus.h"
30 #include "logind-session.h"
31 #include "logind-user-dbus.h"
32 #include "mkdir-label.h"
33 #include "parse-util.h"
34 #include "path-util.h"
35 #include "process-util.h"
36 #include "serialize.h"
37 #include "string-table.h"
38 #include "strv.h"
39 #include "terminal-util.h"
40 #include "tmpfile-util.h"
41 #include "uid-classification.h"
42 #include "user-util.h"
43
44 #define RELEASE_USEC (20*USEC_PER_SEC)
45
46 static void session_remove_fifo(Session *s);
47 static void session_restore_vt(Session *s);
48
49 int session_new(Session **ret, Manager *m, const char *id) {
50 _cleanup_(session_freep) Session *s = NULL;
51 int r;
52
53 assert(ret);
54 assert(m);
55 assert(id);
56
57 if (!session_id_valid(id))
58 return -EINVAL;
59
60 s = new(Session, 1);
61 if (!s)
62 return -ENOMEM;
63
64 *s = (Session) {
65 .manager = m,
66 .fifo_fd = -EBADF,
67 .vtfd = -EBADF,
68 .audit_id = AUDIT_SESSION_INVALID,
69 .tty_validity = _TTY_VALIDITY_INVALID,
70 .leader = PIDREF_NULL,
71 };
72
73 s->state_file = path_join("/run/systemd/sessions", id);
74 if (!s->state_file)
75 return -ENOMEM;
76
77 s->id = basename(s->state_file);
78
79 s->devices = hashmap_new(&devt_hash_ops);
80 if (!s->devices)
81 return -ENOMEM;
82
83 r = hashmap_put(m->sessions, s->id, s);
84 if (r < 0)
85 return r;
86
87 *ret = TAKE_PTR(s);
88 return 0;
89 }
90
91 static int session_dispatch_leader_pidfd(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
92 Session *s = ASSERT_PTR(userdata);
93
94 assert(s->leader.fd == fd);
95 session_stop(s, /* force= */ false);
96
97 return 1;
98 }
99
100 static int session_watch_pidfd(Session *s) {
101 int r;
102
103 assert(s);
104 assert(s->manager);
105 assert(pidref_is_set(&s->leader));
106
107 if (s->leader.fd < 0)
108 return 0;
109
110 r = sd_event_add_io(s->manager->event, &s->leader_pidfd_event_source, s->leader.fd, EPOLLIN, session_dispatch_leader_pidfd, s);
111 if (r < 0)
112 return r;
113
114 r = sd_event_source_set_priority(s->leader_pidfd_event_source, SD_EVENT_PRIORITY_IMPORTANT);
115 if (r < 0)
116 return r;
117
118 (void) sd_event_source_set_description(s->leader_pidfd_event_source, "session-pidfd");
119
120 return 0;
121 }
122
123 static void session_reset_leader(Session *s, bool keep_fdstore) {
124 assert(s);
125
126 if (!keep_fdstore) {
127 /* Clear fdstore if we're asked to, no matter if s->leader is set or not, so that when
128 * initially deserializing leader fd we clear the old fd too. */
129 (void) notify_remove_fd_warnf("session-%s-leader-fd", s->id);
130 s->leader_fd_saved = false;
131 }
132
133 if (!pidref_is_set(&s->leader))
134 return;
135
136 s->leader_pidfd_event_source = sd_event_source_disable_unref(s->leader_pidfd_event_source);
137
138 (void) hashmap_remove_value(s->manager->sessions_by_leader, &s->leader, s);
139
140 return pidref_done(&s->leader);
141 }
142
143 Session* session_free(Session *s) {
144 SessionDevice *sd;
145
146 if (!s)
147 return NULL;
148
149 if (s->in_gc_queue)
150 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
151
152 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
153
154 session_drop_controller(s);
155
156 while ((sd = hashmap_first(s->devices)))
157 session_device_free(sd);
158
159 hashmap_free(s->devices);
160
161 if (s->user) {
162 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
163
164 if (s->user->display == s)
165 s->user->display = NULL;
166
167 user_update_last_session_timer(s->user);
168 }
169
170 if (s->seat) {
171 if (s->seat->active == s)
172 s->seat->active = NULL;
173 if (s->seat->pending_switch == s)
174 s->seat->pending_switch = NULL;
175
176 seat_evict_position(s->seat, s);
177 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
178 }
179
180 if (s->scope) {
181 hashmap_remove(s->manager->session_units, s->scope);
182 free(s->scope);
183 }
184
185 free(s->scope_job);
186
187 session_reset_leader(s, /* keep_fdstore = */ true);
188
189 sd_bus_message_unref(s->create_message);
190 sd_bus_message_unref(s->upgrade_message);
191
192 free(s->tty);
193 free(s->display);
194 free(s->remote_host);
195 free(s->remote_user);
196 free(s->service);
197 free(s->desktop);
198
199 hashmap_remove(s->manager->sessions, s->id);
200
201 sd_event_source_unref(s->fifo_event_source);
202 safe_close(s->fifo_fd);
203
204 /* Note that we remove neither the state file nor the fifo path here, since we want both to survive
205 * daemon restarts */
206 free(s->state_file);
207 free(s->fifo_path);
208
209 sd_event_source_unref(s->stop_on_idle_event_source);
210
211 return mfree(s);
212 }
213
214 void session_set_user(Session *s, User *u) {
215 assert(s);
216 assert(!s->user);
217
218 s->user = u;
219 LIST_PREPEND(sessions_by_user, u->sessions, s);
220
221 user_update_last_session_timer(u);
222 }
223
224 int session_set_leader_consume(Session *s, PidRef _leader) {
225 _cleanup_(pidref_done) PidRef pidref = _leader;
226 int r;
227
228 assert(s);
229 assert(pidref_is_set(&pidref));
230
231 if (pidref_equal(&s->leader, &pidref))
232 return 0;
233
234 session_reset_leader(s, /* keep_fdstore = */ false);
235
236 s->leader = TAKE_PIDREF(pidref);
237
238 r = session_watch_pidfd(s);
239 if (r < 0)
240 return log_error_errno(r, "Failed to watch leader pidfd for session '%s': %m", s->id);
241
242 r = hashmap_ensure_put(&s->manager->sessions_by_leader, &pidref_hash_ops, &s->leader, s);
243 if (r < 0)
244 return r;
245 assert(r > 0);
246
247 if (s->leader.fd >= 0) {
248 r = notify_push_fdf(s->leader.fd, "session-%s-leader-fd", s->id);
249 if (r < 0)
250 log_warning_errno(r, "Failed to push leader pidfd for session '%s', ignoring: %m", s->id);
251 else
252 s->leader_fd_saved = true;
253 }
254
255 (void) audit_session_from_pid(s->leader.pid, &s->audit_id);
256
257 return 1;
258 }
259
260 static void session_save_devices(Session *s, FILE *f) {
261 SessionDevice *sd;
262
263 if (!hashmap_isempty(s->devices)) {
264 fprintf(f, "DEVICES=");
265 HASHMAP_FOREACH(sd, s->devices)
266 fprintf(f, DEVNUM_FORMAT_STR " ", DEVNUM_FORMAT_VAL(sd->dev));
267 fprintf(f, "\n");
268 }
269 }
270
271 int session_save(Session *s) {
272 _cleanup_(unlink_and_freep) char *temp_path = NULL;
273 _cleanup_fclose_ FILE *f = NULL;
274 int r;
275
276 assert(s);
277
278 if (!s->user)
279 return -ESTALE;
280
281 if (!s->started)
282 return 0;
283
284 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
285 if (r < 0)
286 goto fail;
287
288 r = fopen_temporary(s->state_file, &f, &temp_path);
289 if (r < 0)
290 goto fail;
291
292 (void) fchmod(fileno(f), 0644);
293
294 fprintf(f,
295 "# This is private data. Do not parse.\n"
296 "UID="UID_FMT"\n"
297 "USER=%s\n"
298 "ACTIVE=%s\n"
299 "IS_DISPLAY=%s\n"
300 "STATE=%s\n"
301 "REMOTE=%s\n"
302 "LEADER_FD_SAVED=%s\n",
303 s->user->user_record->uid,
304 s->user->user_record->user_name,
305 one_zero(session_is_active(s)),
306 one_zero(s->user->display == s),
307 session_state_to_string(session_get_state(s)),
308 one_zero(s->remote),
309 one_zero(s->leader_fd_saved));
310
311 if (s->type >= 0)
312 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
313
314 if (s->original_type >= 0)
315 fprintf(f, "ORIGINAL_TYPE=%s\n", session_type_to_string(s->original_type));
316
317 if (s->class >= 0)
318 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
319
320 if (s->scope)
321 fprintf(f, "SCOPE=%s\n", s->scope);
322 if (s->scope_job)
323 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
324
325 if (s->fifo_path)
326 fprintf(f, "FIFO=%s\n", s->fifo_path);
327
328 if (s->seat)
329 fprintf(f, "SEAT=%s\n", s->seat->id);
330
331 if (s->tty)
332 fprintf(f, "TTY=%s\n", s->tty);
333
334 if (s->tty_validity >= 0)
335 fprintf(f, "TTY_VALIDITY=%s\n", tty_validity_to_string(s->tty_validity));
336
337 if (s->display)
338 fprintf(f, "DISPLAY=%s\n", s->display);
339
340 if (s->remote_host) {
341 _cleanup_free_ char *escaped = NULL;
342
343 escaped = cescape(s->remote_host);
344 if (!escaped) {
345 r = -ENOMEM;
346 goto fail;
347 }
348
349 fprintf(f, "REMOTE_HOST=%s\n", escaped);
350 }
351
352 if (s->remote_user) {
353 _cleanup_free_ char *escaped = NULL;
354
355 escaped = cescape(s->remote_user);
356 if (!escaped) {
357 r = -ENOMEM;
358 goto fail;
359 }
360
361 fprintf(f, "REMOTE_USER=%s\n", escaped);
362 }
363
364 if (s->service) {
365 _cleanup_free_ char *escaped = NULL;
366
367 escaped = cescape(s->service);
368 if (!escaped) {
369 r = -ENOMEM;
370 goto fail;
371 }
372
373 fprintf(f, "SERVICE=%s\n", escaped);
374 }
375
376 if (s->desktop) {
377 _cleanup_free_ char *escaped = NULL;
378
379 escaped = cescape(s->desktop);
380 if (!escaped) {
381 r = -ENOMEM;
382 goto fail;
383 }
384
385 fprintf(f, "DESKTOP=%s\n", escaped);
386 }
387
388 if (s->seat && seat_has_vts(s->seat))
389 fprintf(f, "VTNR=%u\n", s->vtnr);
390
391 if (!s->vtnr)
392 fprintf(f, "POSITION=%u\n", s->position);
393
394 if (pidref_is_set(&s->leader))
395 fprintf(f, "LEADER="PID_FMT"\n", s->leader.pid);
396
397 if (audit_session_is_valid(s->audit_id))
398 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
399
400 if (dual_timestamp_is_set(&s->timestamp))
401 fprintf(f,
402 "REALTIME="USEC_FMT"\n"
403 "MONOTONIC="USEC_FMT"\n",
404 s->timestamp.realtime,
405 s->timestamp.monotonic);
406
407 if (s->controller) {
408 fprintf(f, "CONTROLLER=%s\n", s->controller);
409 session_save_devices(s, f);
410 }
411
412 r = fflush_and_check(f);
413 if (r < 0)
414 goto fail;
415
416 if (rename(temp_path, s->state_file) < 0) {
417 r = -errno;
418 goto fail;
419 }
420
421 temp_path = mfree(temp_path);
422 return 0;
423
424 fail:
425 (void) unlink(s->state_file);
426
427 return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
428 }
429
430 static int session_load_devices(Session *s, const char *devices) {
431 int r = 0;
432
433 assert(s);
434
435 for (const char *p = devices;;) {
436 _cleanup_free_ char *word = NULL;
437 dev_t dev;
438 int k;
439
440 k = extract_first_word(&p, &word, NULL, 0);
441 if (k <= 0) {
442 RET_GATHER(r, k);
443 break;
444 }
445
446 k = parse_devnum(word, &dev);
447 if (k < 0) {
448 RET_GATHER(r, k);
449 continue;
450 }
451
452 /* The file descriptors for loaded devices will be reattached later. */
453 RET_GATHER(r, session_device_new(s, dev, /* open_device = */ false, /* ret = */ NULL));
454 }
455
456 if (r < 0)
457 log_error_errno(r, "Failed to load some session devices for session '%s': %m", s->id);
458 return r;
459 }
460
461 int session_load(Session *s) {
462 _cleanup_free_ char *remote = NULL,
463 *seat = NULL,
464 *tty_validity = NULL,
465 *vtnr = NULL,
466 *state = NULL,
467 *position = NULL,
468 *leader_pid = NULL,
469 *leader_fd_saved = NULL,
470 *type = NULL,
471 *original_type = NULL,
472 *class = NULL,
473 *uid = NULL,
474 *realtime = NULL,
475 *monotonic = NULL,
476 *controller = NULL,
477 *active = NULL,
478 *devices = NULL,
479 *is_display = NULL;
480
481 int k, r;
482
483 assert(s);
484
485 r = parse_env_file(NULL, s->state_file,
486 "REMOTE", &remote,
487 "SCOPE", &s->scope,
488 "SCOPE_JOB", &s->scope_job,
489 "FIFO", &s->fifo_path,
490 "SEAT", &seat,
491 "TTY", &s->tty,
492 "TTY_VALIDITY", &tty_validity,
493 "DISPLAY", &s->display,
494 "REMOTE_HOST", &s->remote_host,
495 "REMOTE_USER", &s->remote_user,
496 "SERVICE", &s->service,
497 "DESKTOP", &s->desktop,
498 "VTNR", &vtnr,
499 "STATE", &state,
500 "POSITION", &position,
501 "LEADER", &leader_pid,
502 "LEADER_FD_SAVED", &leader_fd_saved,
503 "TYPE", &type,
504 "ORIGINAL_TYPE", &original_type,
505 "CLASS", &class,
506 "UID", &uid,
507 "REALTIME", &realtime,
508 "MONOTONIC", &monotonic,
509 "CONTROLLER", &controller,
510 "ACTIVE", &active,
511 "DEVICES", &devices,
512 "IS_DISPLAY", &is_display);
513 if (r < 0)
514 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
515
516 if (!s->user) {
517 uid_t u;
518 User *user;
519
520 if (!uid)
521 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
522 "UID not specified for session %s",
523 s->id);
524
525 r = parse_uid(uid, &u);
526 if (r < 0) {
527 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
528 return r;
529 }
530
531 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
532 if (!user)
533 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
534 "User of session %s not known.",
535 s->id);
536
537 session_set_user(s, user);
538 }
539
540 if (remote) {
541 k = parse_boolean(remote);
542 if (k >= 0)
543 s->remote = k;
544 }
545
546 if (vtnr)
547 safe_atou(vtnr, &s->vtnr);
548
549 if (seat && !s->seat) {
550 Seat *o;
551
552 o = hashmap_get(s->manager->seats, seat);
553 if (o)
554 r = seat_attach_session(o, s);
555 if (!o || r < 0)
556 log_error("Cannot attach session %s to seat %s", s->id, seat);
557 }
558
559 if (!s->seat || !seat_has_vts(s->seat))
560 s->vtnr = 0;
561
562 if (position && s->seat) {
563 unsigned npos;
564
565 safe_atou(position, &npos);
566 seat_claim_position(s->seat, s, npos);
567 }
568
569 if (tty_validity) {
570 TTYValidity v;
571
572 v = tty_validity_from_string(tty_validity);
573 if (v < 0)
574 log_debug("Failed to parse TTY validity: %s", tty_validity);
575 else
576 s->tty_validity = v;
577 }
578
579 if (type) {
580 SessionType t;
581
582 t = session_type_from_string(type);
583 if (t >= 0)
584 s->type = t;
585 }
586
587 if (original_type) {
588 SessionType ot;
589
590 ot = session_type_from_string(original_type);
591 if (ot >= 0)
592 s->original_type = ot;
593 } else
594 /* Pre-v246 compat: initialize original_type if not set in the state file */
595 s->original_type = s->type;
596
597 if (class) {
598 SessionClass c;
599
600 c = session_class_from_string(class);
601 if (c >= 0)
602 s->class = c;
603 }
604
605 if (streq_ptr(state, "closing"))
606 s->stopping = true;
607
608 if (s->fifo_path) {
609 int fd;
610
611 /* If we open an unopened pipe for reading we will not
612 get an EOF. to trigger an EOF we hence open it for
613 writing, but close it right away which then will
614 trigger the EOF. This will happen immediately if no
615 other process has the FIFO open for writing, i. e.
616 when the session died before logind (re)started. */
617
618 fd = session_create_fifo(s);
619 safe_close(fd);
620 }
621
622 if (realtime)
623 (void) deserialize_usec(realtime, &s->timestamp.realtime);
624 if (monotonic)
625 (void) deserialize_usec(monotonic, &s->timestamp.monotonic);
626
627 if (active) {
628 k = parse_boolean(active);
629 if (k >= 0)
630 s->was_active = k;
631 }
632
633 if (is_display) {
634 /* Note that when enumerating users are loaded before sessions, hence the display session to use is
635 * something we have to store along with the session and not the user, as in that case we couldn't
636 * apply it at the time we load the user. */
637
638 k = parse_boolean(is_display);
639 if (k < 0)
640 log_warning_errno(k, "Failed to parse IS_DISPLAY session property: %m");
641 else if (k > 0)
642 s->user->display = s;
643 }
644
645 if (controller) {
646 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) {
647 session_set_controller(s, controller, false, false);
648 session_load_devices(s, devices);
649 } else
650 session_restore_vt(s);
651 }
652
653 if (leader_pid) {
654 assert(!pidref_is_set(&s->leader));
655
656 r = parse_pid(leader_pid, &s->deserialized_pid);
657 if (r < 0)
658 return log_error_errno(r, "Failed to parse LEADER=%s: %m", leader_pid);
659
660 if (leader_fd_saved) {
661 r = parse_boolean(leader_fd_saved);
662 if (r < 0)
663 return log_error_errno(r, "Failed to parse LEADER_FD_SAVED=%s: %m", leader_fd_saved);
664 s->leader_fd_saved = r > 0;
665
666 if (s->leader_fd_saved)
667 /* The leader fd will be acquired from fdstore later */
668 return 0;
669 }
670
671 _cleanup_(pidref_done) PidRef p = PIDREF_NULL;
672
673 r = pidref_set_pid(&p, s->deserialized_pid);
674 if (r >= 0)
675 r = session_set_leader_consume(s, TAKE_PIDREF(p));
676 if (r < 0)
677 log_warning_errno(r, "Failed to set leader PID for session '%s': %m", s->id);
678 }
679
680 return r;
681 }
682
683 int session_activate(Session *s) {
684 unsigned num_pending;
685
686 assert(s);
687 assert(s->user);
688
689 if (!s->seat)
690 return -EOPNOTSUPP;
691
692 if (s->seat->active == s)
693 return 0;
694
695 /* on seats with VTs, we let VTs manage session-switching */
696 if (seat_has_vts(s->seat)) {
697 if (s->vtnr == 0)
698 return -EOPNOTSUPP;
699
700 return chvt(s->vtnr);
701 }
702
703 /* On seats without VTs, we implement session-switching in logind. We
704 * try to pause all session-devices and wait until the session
705 * controller acknowledged them. Once all devices are asleep, we simply
706 * switch the active session and be done.
707 * We save the session we want to switch to in seat->pending_switch and
708 * seat_complete_switch() will perform the final switch. */
709
710 s->seat->pending_switch = s;
711
712 /* if no devices are running, immediately perform the session switch */
713 num_pending = session_device_try_pause_all(s);
714 if (!num_pending)
715 seat_complete_switch(s->seat);
716
717 return 0;
718 }
719
720 static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_error *error) {
721 int r;
722
723 assert(s);
724 assert(s->user);
725
726 if (!SESSION_CLASS_WANTS_SCOPE(s->class))
727 return 0;
728
729 if (!s->scope) {
730 _cleanup_strv_free_ char **wants = NULL, **after = NULL;
731 _cleanup_free_ char *scope = NULL;
732 const char *description;
733
734 s->scope_job = mfree(s->scope_job);
735
736 scope = strjoin("session-", s->id, ".scope");
737 if (!scope)
738 return log_oom();
739
740 description = strjoina("Session ", s->id, " of User ", s->user->user_record->user_name);
741
742 /* These two have StopWhenUnneeded= set, hence add a dep towards them */
743 wants = strv_new(s->user->runtime_dir_service,
744 SESSION_CLASS_WANTS_SERVICE_MANAGER(s->class) ? s->user->service : STRV_IGNORE);
745 if (!wants)
746 return log_oom();
747
748 /* We usually want to order session scopes after systemd-user-sessions.service since the
749 * latter unit is used as login session barrier for unprivileged users. However the barrier
750 * doesn't apply for root as sysadmin should always be able to log in (and without waiting
751 * for any timeout to expire) in case something goes wrong during the boot process. Since
752 * ordering after systemd-user-sessions.service and the user instance is optional we make use
753 * of STRV_IGNORE with strv_new() to skip these order constraints when needed. */
754 after = strv_new("systemd-logind.service",
755 s->user->runtime_dir_service,
756 SESSION_CLASS_IS_EARLY(s->class) ? STRV_IGNORE : "systemd-user-sessions.service",
757 s->user->service);
758 if (!after)
759 return log_oom();
760
761 r = manager_start_scope(
762 s->manager,
763 scope,
764 &s->leader,
765 s->user->slice,
766 description,
767 wants,
768 after,
769 user_record_home_directory(s->user->user_record),
770 properties,
771 error,
772 &s->scope_job);
773 if (r < 0)
774 return log_error_errno(r, "Failed to start session scope %s: %s",
775 scope, bus_error_message(error, r));
776
777 s->scope = TAKE_PTR(scope);
778 }
779
780 (void) hashmap_put(s->manager->session_units, s->scope, s);
781
782 return 0;
783 }
784
785 static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, void *userdata) {
786 Session *s = userdata;
787 dual_timestamp ts;
788 int r, idle;
789
790 assert(s);
791
792 if (s->stopping)
793 return 0;
794
795 idle = session_get_idle_hint(s, &ts);
796 if (idle) {
797 log_info("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->user_record->user_name);
798
799 return session_stop(s, /* force */ true);
800 }
801
802 r = sd_event_source_set_time(
803 source,
804 usec_add(dual_timestamp_is_set(&ts) ? ts.monotonic : now(CLOCK_MONOTONIC),
805 s->manager->stop_idle_session_usec));
806 if (r < 0)
807 return log_error_errno(r, "Failed to configure stop on idle session event source: %m");
808
809 r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
810 if (r < 0)
811 return log_error_errno(r, "Failed to enable stop on idle session event source: %m");
812
813 return 1;
814 }
815
816 static int session_setup_stop_on_idle_timer(Session *s) {
817 int r;
818
819 assert(s);
820
821 if (s->manager->stop_idle_session_usec == USEC_INFINITY || !SESSION_CLASS_CAN_STOP_ON_IDLE(s->class))
822 return 0;
823
824 r = sd_event_add_time_relative(
825 s->manager->event,
826 &s->stop_on_idle_event_source,
827 CLOCK_MONOTONIC,
828 s->manager->stop_idle_session_usec,
829 0,
830 session_dispatch_stop_on_idle, s);
831 if (r < 0)
832 return log_error_errno(r, "Failed to add stop on idle session event source: %m");
833
834 return 0;
835 }
836
837 int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
838 int r;
839
840 assert(s);
841
842 if (!s->user)
843 return -ESTALE;
844
845 if (s->stopping)
846 return -EINVAL;
847
848 if (s->started)
849 return 0;
850
851 r = user_start(s->user);
852 if (r < 0)
853 return r;
854
855 r = session_start_scope(s, properties, error);
856 if (r < 0)
857 return r;
858
859 r = session_setup_stop_on_idle_timer(s);
860 if (r < 0)
861 return r;
862
863 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
864 "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
865 "SESSION_ID=%s", s->id,
866 "USER_ID=%s", s->user->user_record->user_name,
867 "LEADER="PID_FMT, s->leader.pid,
868 LOG_MESSAGE("New session %s of user %s.", s->id, s->user->user_record->user_name));
869
870 if (!dual_timestamp_is_set(&s->timestamp))
871 dual_timestamp_now(&s->timestamp);
872
873 if (s->seat)
874 seat_read_active_vt(s->seat);
875
876 s->started = true;
877
878 user_elect_display(s->user);
879
880 /* Save data */
881 (void) session_save(s);
882 (void) user_save(s->user);
883 if (s->seat)
884 (void) seat_save(s->seat);
885
886 /* Send signals */
887 session_send_signal(s, true);
888 user_send_changed(s->user, "Display", NULL);
889
890 if (s->seat && s->seat->active == s)
891 (void) seat_send_changed(s->seat, "ActiveSession", NULL);
892
893 return 0;
894 }
895
896 static int session_stop_scope(Session *s, bool force) {
897 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
898 int r;
899
900 assert(s);
901
902 if (!s->scope)
903 return 0;
904
905 /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
906 * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
907 * when killing any processes left after this point. */
908 r = manager_abandon_scope(s->manager, s->scope, &error);
909 if (r < 0) {
910 log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r));
911 sd_bus_error_free(&error);
912 }
913
914 s->scope_job = mfree(s->scope_job);
915
916 /* Optionally, let's kill everything that's left now. */
917 if (force ||
918 (s->user->user_record->kill_processes != 0 &&
919 (s->user->user_record->kill_processes > 0 ||
920 manager_shall_kill(s->manager, s->user->user_record->user_name)))) {
921
922 r = manager_stop_unit(s->manager, s->scope, force ? "replace" : "fail", &error, &s->scope_job);
923 if (r < 0) {
924 if (force)
925 return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r));
926
927 log_warning_errno(r, "Failed to stop session scope, ignoring: %s", bus_error_message(&error, r));
928 }
929 } else {
930
931 /* With no killing, this session is allowed to persist in "closing" state indefinitely.
932 * Therefore session stop and session removal may be two distinct events.
933 * Session stop is quite significant on its own, let's log it. */
934 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
935 "SESSION_ID=%s", s->id,
936 "USER_ID=%s", s->user->user_record->user_name,
937 "LEADER="PID_FMT, s->leader.pid,
938 LOG_MESSAGE("Session %s logged out. Waiting for processes to exit.", s->id));
939 }
940
941 return 0;
942 }
943
944 int session_stop(Session *s, bool force) {
945 int r;
946
947 assert(s);
948
949 /* This is called whenever we begin with tearing down a session record. It's called in four cases: explicit API
950 * request via the bus (either directly for the session object or for the seat or user object this session
951 * belongs to; 'force' is true), or due to automatic GC (i.e. scope vanished; 'force' is false), or because the
952 * session FIFO saw an EOF ('force' is false), or because the release timer hit ('force' is false). */
953
954 if (!s->user)
955 return -ESTALE;
956 if (!s->started)
957 return 0;
958 if (s->stopping)
959 return 0;
960
961 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
962 s->leader_pidfd_event_source = sd_event_source_unref(s->leader_pidfd_event_source);
963
964 if (s->seat)
965 seat_evict_position(s->seat, s);
966
967 /* We are going down, don't care about FIFOs anymore */
968 session_remove_fifo(s);
969
970 /* Kill cgroup */
971 r = session_stop_scope(s, force);
972
973 s->stopping = true;
974
975 user_elect_display(s->user);
976
977 (void) session_save(s);
978 (void) user_save(s->user);
979
980 return r;
981 }
982
983 int session_finalize(Session *s) {
984 SessionDevice *sd;
985
986 assert(s);
987
988 if (!s->user)
989 return -ESTALE;
990
991 if (s->started)
992 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
993 "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
994 "SESSION_ID=%s", s->id,
995 "USER_ID=%s", s->user->user_record->user_name,
996 "LEADER="PID_FMT, s->leader.pid,
997 LOG_MESSAGE("Removed session %s.", s->id));
998
999 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
1000
1001 if (s->seat)
1002 seat_evict_position(s->seat, s);
1003
1004 /* Kill session devices */
1005 while ((sd = hashmap_first(s->devices)))
1006 session_device_free(sd);
1007
1008 (void) unlink(s->state_file);
1009 session_add_to_gc_queue(s);
1010 user_add_to_gc_queue(s->user);
1011
1012 if (s->started) {
1013 session_send_signal(s, false);
1014 s->started = false;
1015 }
1016
1017 if (s->seat) {
1018 if (s->seat->active == s)
1019 seat_set_active(s->seat, NULL);
1020
1021 seat_save(s->seat);
1022 }
1023
1024 session_reset_leader(s, /* keep_fdstore = */ false);
1025
1026 (void) user_save(s->user);
1027 (void) user_send_changed(s->user, "Display", NULL);
1028
1029 return 0;
1030 }
1031
1032 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
1033 Session *s = ASSERT_PTR(userdata);
1034
1035 assert(es);
1036
1037 session_stop(s, /* force = */ false);
1038 return 0;
1039 }
1040
1041 int session_release(Session *s) {
1042 assert(s);
1043
1044 if (!s->started || s->stopping)
1045 return 0;
1046
1047 if (s->timer_event_source)
1048 return 0;
1049
1050 return sd_event_add_time_relative(
1051 s->manager->event,
1052 &s->timer_event_source,
1053 CLOCK_MONOTONIC,
1054 RELEASE_USEC, 0,
1055 release_timeout_callback, s);
1056 }
1057
1058 bool session_is_active(Session *s) {
1059 assert(s);
1060
1061 if (!s->seat)
1062 return true;
1063
1064 return s->seat->active == s;
1065 }
1066
1067 static int get_tty_atime(const char *tty, usec_t *atime) {
1068 _cleanup_free_ char *p = NULL;
1069 struct stat st;
1070
1071 assert(tty);
1072 assert(atime);
1073
1074 if (!path_is_absolute(tty)) {
1075 p = path_join("/dev", tty);
1076 if (!p)
1077 return -ENOMEM;
1078
1079 tty = p;
1080 } else if (!path_startswith(tty, "/dev/"))
1081 return -ENOENT;
1082
1083 if (lstat(tty, &st) < 0)
1084 return -errno;
1085
1086 *atime = timespec_load(&st.st_atim);
1087 return 0;
1088 }
1089
1090 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
1091 _cleanup_free_ char *p = NULL;
1092 int r;
1093
1094 assert(pid > 0);
1095 assert(atime);
1096
1097 r = get_ctty(pid, NULL, &p);
1098 if (r < 0)
1099 return r;
1100
1101 return get_tty_atime(p, atime);
1102 }
1103
1104 int session_get_idle_hint(Session *s, dual_timestamp *t) {
1105 usec_t atime = 0, dtime = 0;
1106 int r;
1107
1108 assert(s);
1109
1110 /* Graphical sessions have an explicit idle hint */
1111 if (SESSION_TYPE_IS_GRAPHICAL(s->type)) {
1112 if (t)
1113 *t = s->idle_hint_timestamp;
1114
1115 return s->idle_hint;
1116 }
1117
1118 if (s->type == SESSION_TTY) {
1119 /* For sessions with an explicitly configured tty, let's check its atime */
1120 if (s->tty) {
1121 r = get_tty_atime(s->tty, &atime);
1122 if (r >= 0)
1123 goto found_atime;
1124 }
1125
1126 /* For sessions with a leader but no explicitly configured tty, let's check the controlling tty of
1127 * the leader */
1128 if (pidref_is_set(&s->leader)) {
1129 r = get_process_ctty_atime(s->leader.pid, &atime);
1130 if (r >= 0)
1131 goto found_atime;
1132 }
1133 }
1134
1135 if (t)
1136 *t = DUAL_TIMESTAMP_NULL;
1137
1138 return false;
1139
1140 found_atime:
1141 if (t)
1142 dual_timestamp_from_realtime(t, atime);
1143
1144 if (s->manager->idle_action_usec > 0 && s->manager->stop_idle_session_usec != USEC_INFINITY)
1145 dtime = MIN(s->manager->idle_action_usec, s->manager->stop_idle_session_usec);
1146 else if (s->manager->idle_action_usec > 0)
1147 dtime = s->manager->idle_action_usec;
1148 else if (s->manager->stop_idle_session_usec != USEC_INFINITY)
1149 dtime = s->manager->stop_idle_session_usec;
1150 else
1151 return false;
1152
1153 return usec_add(atime, dtime) <= now(CLOCK_REALTIME);
1154 }
1155
1156 int session_set_idle_hint(Session *s, bool b) {
1157 assert(s);
1158
1159 if (!SESSION_CLASS_CAN_IDLE(s->class)) /* Only some session classes know the idle concept at all */
1160 return -ENOTTY;
1161 if (!SESSION_TYPE_IS_GRAPHICAL(s->type)) /* And only graphical session types can set the field explicitly */
1162 return -ENOTTY;
1163
1164 if (s->idle_hint == b)
1165 return 0;
1166
1167 s->idle_hint = b;
1168 dual_timestamp_now(&s->idle_hint_timestamp);
1169
1170 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1171
1172 if (s->seat)
1173 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1174
1175 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1176 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1177
1178 return 1;
1179 }
1180
1181 int session_get_locked_hint(Session *s) {
1182 assert(s);
1183
1184 return s->locked_hint;
1185 }
1186
1187 int session_set_locked_hint(Session *s, bool b) {
1188 assert(s);
1189
1190 if (!SESSION_CLASS_CAN_LOCK(s->class))
1191 return -ENOTTY;
1192
1193 if (s->locked_hint == b)
1194 return 0;
1195
1196 s->locked_hint = b;
1197 (void) session_save(s);
1198 (void) session_send_changed(s, "LockedHint", NULL);
1199
1200 return 1;
1201 }
1202
1203 void session_set_type(Session *s, SessionType t) {
1204 assert(s);
1205
1206 if (s->type == t)
1207 return;
1208
1209 s->type = t;
1210 (void) session_save(s);
1211 (void) session_send_changed(s, "Type", NULL);
1212 }
1213
1214 void session_set_class(Session *s, SessionClass c) {
1215 assert(s);
1216
1217 if (s->class == c)
1218 return;
1219
1220 s->class = c;
1221 (void) session_save(s);
1222 (void) session_send_changed(s, "Class", NULL);
1223
1224 /* This class change might mean we need the per-user session manager now. Try to start it */
1225 user_start_service_manager(s->user);
1226 }
1227
1228 int session_set_display(Session *s, const char *display) {
1229 int r;
1230
1231 assert(s);
1232 assert(display);
1233
1234 r = free_and_strdup(&s->display, display);
1235 if (r <= 0) /* 0 means the strings were equal */
1236 return r;
1237
1238 (void) session_save(s);
1239 (void) session_send_changed(s, "Display", NULL);
1240
1241 return 1;
1242 }
1243
1244 int session_set_tty(Session *s, const char *tty) {
1245 int r;
1246
1247 assert(s);
1248 assert(tty);
1249
1250 r = free_and_strdup(&s->tty, tty);
1251 if (r <= 0) /* 0 means the strings were equal */
1252 return r;
1253
1254 (void) session_save(s);
1255 (void) session_send_changed(s, "TTY", NULL);
1256
1257 return 1;
1258 }
1259
1260 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
1261 Session *s = ASSERT_PTR(userdata);
1262
1263 assert(s->fifo_fd == fd);
1264
1265 /* EOF on the FIFO means the session died abnormally. */
1266
1267 session_remove_fifo(s);
1268 session_stop(s, /* force = */ false);
1269
1270 return 1;
1271 }
1272
1273 int session_create_fifo(Session *s) {
1274 int r;
1275
1276 assert(s);
1277
1278 /* Create FIFO */
1279 if (!s->fifo_path) {
1280 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
1281 if (r < 0)
1282 return r;
1283
1284 s->fifo_path = strjoin("/run/systemd/sessions/", s->id, ".ref");
1285 if (!s->fifo_path)
1286 return -ENOMEM;
1287
1288 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
1289 return -errno;
1290 }
1291
1292 /* Open reading side */
1293 if (s->fifo_fd < 0) {
1294 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
1295 if (s->fifo_fd < 0)
1296 return -errno;
1297 }
1298
1299 if (!s->fifo_event_source) {
1300 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
1301 if (r < 0)
1302 return r;
1303
1304 /* Let's make sure we noticed dead sessions before we process new bus requests (which might
1305 * create new sessions). */
1306 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
1307 if (r < 0)
1308 return r;
1309 }
1310
1311 /* Open writing side */
1312 return RET_NERRNO(open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK));
1313 }
1314
1315 static void session_remove_fifo(Session *s) {
1316 assert(s);
1317
1318 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
1319 s->fifo_fd = safe_close(s->fifo_fd);
1320 s->fifo_path = unlink_and_free(s->fifo_path);
1321 }
1322
1323 bool session_may_gc(Session *s, bool drop_not_started) {
1324 int r;
1325
1326 assert(s);
1327
1328 if (drop_not_started && !s->started)
1329 return true;
1330
1331 if (!s->user)
1332 return true;
1333
1334 r = pidref_is_alive(&s->leader);
1335 if (r == -ESRCH)
1336 /* Session has no leader. This is probably because the leader vanished before deserializing
1337 * pidfd from FD store. */
1338 return true;
1339 if (r < 0)
1340 log_debug_errno(r, "Unable to determine if leader PID " PID_FMT " is still alive, assuming not: %m", s->leader.pid);
1341 if (r > 0)
1342 return false;
1343
1344 if (s->fifo_fd >= 0 && pipe_eof(s->fifo_fd) <= 0)
1345 return false;
1346
1347 if (s->scope_job) {
1348 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1349
1350 r = manager_job_is_active(s->manager, s->scope_job, &error);
1351 if (r < 0)
1352 log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", s->scope_job, bus_error_message(&error, r));
1353 if (r != 0)
1354 return false;
1355 }
1356
1357 if (s->scope) {
1358 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1359
1360 r = manager_unit_is_active(s->manager, s->scope, &error);
1361 if (r < 0)
1362 log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", s->scope, bus_error_message(&error, r));
1363 if (r != 0)
1364 return false;
1365 }
1366
1367 return true;
1368 }
1369
1370 void session_add_to_gc_queue(Session *s) {
1371 assert(s);
1372
1373 if (s->in_gc_queue)
1374 return;
1375
1376 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
1377 s->in_gc_queue = true;
1378 }
1379
1380 SessionState session_get_state(Session *s) {
1381 assert(s);
1382
1383 /* always check closing first */
1384 if (s->stopping || s->timer_event_source)
1385 return SESSION_CLOSING;
1386
1387 if (s->scope_job || (!pidref_is_set(&s->leader) && s->fifo_fd < 0))
1388 return SESSION_OPENING;
1389
1390 if (session_is_active(s))
1391 return SESSION_ACTIVE;
1392
1393 return SESSION_ONLINE;
1394 }
1395
1396 int session_kill(Session *s, KillWho who, int signo) {
1397 assert(s);
1398
1399 if (!s->scope)
1400 return -ESRCH;
1401
1402 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
1403 }
1404
1405 static int session_open_vt(Session *s, bool reopen) {
1406 _cleanup_close_ int fd = -EBADF;
1407 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
1408
1409 assert(s);
1410
1411 if (s->vtnr < 1)
1412 return -ENODEV;
1413
1414 if (!reopen && s->vtfd >= 0)
1415 return s->vtfd;
1416
1417 sprintf(path, "/dev/tty%u", s->vtnr);
1418
1419 fd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
1420 if (fd < 0)
1421 return log_error_errno(fd, "Cannot open VT %s of session %s: %m", path, s->id);
1422
1423 close_and_replace(s->vtfd, fd);
1424 return s->vtfd;
1425 }
1426
1427 static int session_prepare_vt(Session *s) {
1428 int vt, r;
1429 struct vt_mode mode = {};
1430
1431 assert(s);
1432
1433 if (s->vtnr < 1)
1434 return 0;
1435
1436 vt = session_open_vt(s, /* reopen = */ false);
1437 if (vt < 0)
1438 return vt;
1439
1440 r = fchown(vt, s->user->user_record->uid, -1);
1441 if (r < 0) {
1442 r = log_error_errno(errno,
1443 "Cannot change owner of /dev/tty%u: %m",
1444 s->vtnr);
1445 goto error;
1446 }
1447
1448 r = ioctl(vt, KDSKBMODE, K_OFF);
1449 if (r < 0) {
1450 r = log_error_errno(errno,
1451 "Cannot set K_OFF on /dev/tty%u: %m",
1452 s->vtnr);
1453 goto error;
1454 }
1455
1456 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1457 if (r < 0) {
1458 r = log_error_errno(errno,
1459 "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1460 s->vtnr);
1461 goto error;
1462 }
1463
1464 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1465 * So we need a dummy handler here which just acknowledges *all* VT
1466 * switch requests. */
1467 mode.mode = VT_PROCESS;
1468 mode.relsig = SIGRTMIN;
1469 mode.acqsig = SIGRTMIN + 1;
1470 r = ioctl(vt, VT_SETMODE, &mode);
1471 if (r < 0) {
1472 r = log_error_errno(errno,
1473 "Cannot set VT_PROCESS on /dev/tty%u: %m",
1474 s->vtnr);
1475 goto error;
1476 }
1477
1478 return 0;
1479
1480 error:
1481 session_restore_vt(s);
1482 return r;
1483 }
1484
1485 static void session_restore_vt(Session *s) {
1486 int r;
1487
1488 assert(s);
1489
1490 if (s->vtfd < 0)
1491 return;
1492
1493 r = vt_restore(s->vtfd);
1494 if (r == -EIO) {
1495 /* It might happen if the controlling process exited before or while we were
1496 * restoring the VT as it would leave the old file-descriptor in a hung-up
1497 * state. In this case let's retry with a fresh handle to the virtual terminal. */
1498
1499 /* We do a little dance to avoid having the terminal be available
1500 * for reuse before we've cleaned it up. */
1501
1502 int fd = session_open_vt(s, /* reopen = */ true);
1503 if (fd >= 0)
1504 r = vt_restore(fd);
1505 }
1506 if (r < 0)
1507 log_warning_errno(r, "Failed to restore VT, ignoring: %m");
1508
1509 s->vtfd = safe_close(s->vtfd);
1510 }
1511
1512 void session_leave_vt(Session *s) {
1513 int r;
1514
1515 assert(s);
1516
1517 /* This is called whenever we get a VT-switch signal from the kernel.
1518 * We acknowledge all of them unconditionally. Note that session are
1519 * free to overwrite those handlers and we only register them for
1520 * sessions with controllers. Legacy sessions are not affected.
1521 * However, if we switch from a non-legacy to a legacy session, we must
1522 * make sure to pause all device before acknowledging the switch. We
1523 * process the real switch only after we are notified via sysfs, so the
1524 * legacy session might have already started using the devices. If we
1525 * don't pause the devices before the switch, we might confuse the
1526 * session we switch to. */
1527
1528 if (s->vtfd < 0)
1529 return;
1530
1531 session_device_pause_all(s);
1532 r = vt_release(s->vtfd, /* restore = */ false);
1533 if (r == -EIO) {
1534 /* Handle the same VT hung-up case as in session_restore_vt */
1535
1536 int fd = session_open_vt(s, /* reopen = */ true);
1537 if (fd >= 0)
1538 r = vt_release(fd, /* restore = */ false);
1539 }
1540 if (r < 0)
1541 log_debug_errno(r, "Cannot release VT of session %s: %m", s->id);
1542 }
1543
1544 bool session_is_controller(Session *s, const char *sender) {
1545 return streq_ptr(ASSERT_PTR(s)->controller, sender);
1546 }
1547
1548 static void session_release_controller(Session *s, bool notify) {
1549 _unused_ _cleanup_free_ char *name = NULL;
1550 SessionDevice *sd;
1551
1552 assert(s);
1553
1554 if (!s->controller)
1555 return;
1556
1557 name = s->controller;
1558
1559 /* By resetting the controller before releasing the devices, we won't send notification signals.
1560 * This avoids sending useless notifications if the controller is released on disconnects. */
1561 if (!notify)
1562 s->controller = NULL;
1563
1564 while ((sd = hashmap_first(s->devices)))
1565 session_device_free(sd);
1566
1567 s->controller = NULL;
1568 s->track = sd_bus_track_unref(s->track);
1569 }
1570
1571 static int on_bus_track(sd_bus_track *track, void *userdata) {
1572 Session *s = ASSERT_PTR(userdata);
1573
1574 assert(track);
1575
1576 session_drop_controller(s);
1577
1578 return 0;
1579 }
1580
1581 int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
1582 _cleanup_free_ char *name = NULL;
1583 int r;
1584
1585 assert(s);
1586 assert(sender);
1587
1588 if (session_is_controller(s, sender))
1589 return 0;
1590 if (s->controller && !force)
1591 return -EBUSY;
1592
1593 name = strdup(sender);
1594 if (!name)
1595 return -ENOMEM;
1596
1597 s->track = sd_bus_track_unref(s->track);
1598 r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1599 if (r < 0)
1600 return r;
1601
1602 r = sd_bus_track_add_name(s->track, name);
1603 if (r < 0)
1604 return r;
1605
1606 /* When setting a session controller, we forcibly mute the VT and set
1607 * it into graphics-mode. Applications can override that by changing
1608 * VT state after calling TakeControl(). However, this serves as a good
1609 * default and well-behaving controllers can now ignore VTs entirely.
1610 * Note that we reset the VT on ReleaseControl() and if the controller
1611 * exits.
1612 * If logind crashes/restarts, we restore the controller during restart
1613 * (without preparing the VT since the controller has probably overridden
1614 * VT state by now) or reset the VT in case it crashed/exited, too. */
1615 if (prepare) {
1616 r = session_prepare_vt(s);
1617 if (r < 0) {
1618 s->track = sd_bus_track_unref(s->track);
1619 return r;
1620 }
1621 }
1622
1623 session_release_controller(s, true);
1624 s->controller = TAKE_PTR(name);
1625 (void) session_save(s);
1626
1627 return 0;
1628 }
1629
1630 void session_drop_controller(Session *s) {
1631 assert(s);
1632
1633 if (!s->controller)
1634 return;
1635
1636 s->track = sd_bus_track_unref(s->track);
1637 session_set_type(s, s->original_type);
1638 session_release_controller(s, false);
1639 (void) session_save(s);
1640 session_restore_vt(s);
1641 }
1642
1643 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1644 [SESSION_OPENING] = "opening",
1645 [SESSION_ONLINE] = "online",
1646 [SESSION_ACTIVE] = "active",
1647 [SESSION_CLOSING] = "closing",
1648 };
1649
1650 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1651
1652 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1653 [SESSION_UNSPECIFIED] = "unspecified",
1654 [SESSION_TTY] = "tty",
1655 [SESSION_X11] = "x11",
1656 [SESSION_WAYLAND] = "wayland",
1657 [SESSION_MIR] = "mir",
1658 [SESSION_WEB] = "web",
1659 };
1660
1661 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1662
1663 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1664 [SESSION_USER] = "user",
1665 [SESSION_USER_EARLY] = "user-early",
1666 [SESSION_USER_INCOMPLETE] = "user-incomplete",
1667 [SESSION_GREETER] = "greeter",
1668 [SESSION_LOCK_SCREEN] = "lock-screen",
1669 [SESSION_BACKGROUND] = "background",
1670 [SESSION_BACKGROUND_LIGHT] = "background-light",
1671 [SESSION_MANAGER] = "manager",
1672 [SESSION_MANAGER_EARLY] = "manager-early",
1673 };
1674
1675 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1676
1677 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1678 [KILL_LEADER] = "leader",
1679 [KILL_ALL] = "all",
1680 };
1681
1682 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
1683
1684 static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = {
1685 [TTY_FROM_PAM] = "from-pam",
1686 [TTY_FROM_UTMP] = "from-utmp",
1687 [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent",
1688 };
1689
1690 DEFINE_STRING_TABLE_LOOKUP(tty_validity, TTYValidity);