]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / login / logind-session.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6 ***/
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <linux/kd.h>
11 #include <linux/vt.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <sys/ioctl.h>
15 #include <unistd.h>
16
17 #include "sd-messages.h"
18
19 #include "alloc-util.h"
20 #include "audit-util.h"
21 #include "bus-error.h"
22 #include "bus-util.h"
23 #include "escape.h"
24 #include "fd-util.h"
25 #include "fileio.h"
26 #include "format-util.h"
27 #include "io-util.h"
28 #include "logind-session.h"
29 #include "mkdir.h"
30 #include "parse-util.h"
31 #include "path-util.h"
32 #include "string-table.h"
33 #include "terminal-util.h"
34 #include "user-util.h"
35 #include "util.h"
36 #include "process-util.h"
37
38 #define RELEASE_USEC (20*USEC_PER_SEC)
39
40 static void session_remove_fifo(Session *s);
41
42 Session* session_new(Manager *m, const char *id) {
43 Session *s;
44
45 assert(m);
46 assert(id);
47 assert(session_id_valid(id));
48
49 s = new0(Session, 1);
50 if (!s)
51 return NULL;
52
53 s->state_file = strappend("/run/systemd/sessions/", id);
54 if (!s->state_file)
55 return mfree(s);
56
57 s->devices = hashmap_new(&devt_hash_ops);
58 if (!s->devices) {
59 free(s->state_file);
60 return mfree(s);
61 }
62
63 s->id = basename(s->state_file);
64
65 if (hashmap_put(m->sessions, s->id, s) < 0) {
66 hashmap_free(s->devices);
67 free(s->state_file);
68 return mfree(s);
69 }
70
71 s->manager = m;
72 s->fifo_fd = -1;
73 s->vtfd = -1;
74 s->audit_id = AUDIT_SESSION_INVALID;
75
76 return s;
77 }
78
79 void session_free(Session *s) {
80 SessionDevice *sd;
81
82 assert(s);
83
84 if (s->in_gc_queue)
85 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
86
87 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
88
89 session_remove_fifo(s);
90
91 session_drop_controller(s);
92
93 while ((sd = hashmap_first(s->devices)))
94 session_device_free(sd);
95
96 hashmap_free(s->devices);
97
98 if (s->user) {
99 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
100
101 if (s->user->display == s)
102 s->user->display = NULL;
103 }
104
105 if (s->seat) {
106 if (s->seat->active == s)
107 s->seat->active = NULL;
108 if (s->seat->pending_switch == s)
109 s->seat->pending_switch = NULL;
110
111 seat_evict_position(s->seat, s);
112 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
113 }
114
115 if (s->scope) {
116 hashmap_remove(s->manager->session_units, s->scope);
117 free(s->scope);
118 }
119
120 free(s->scope_job);
121
122 sd_bus_message_unref(s->create_message);
123
124 free(s->tty);
125 free(s->display);
126 free(s->remote_host);
127 free(s->remote_user);
128 free(s->service);
129 free(s->desktop);
130
131 hashmap_remove(s->manager->sessions, s->id);
132
133 free(s->state_file);
134 free(s);
135 }
136
137 void session_set_user(Session *s, User *u) {
138 assert(s);
139 assert(!s->user);
140
141 s->user = u;
142 LIST_PREPEND(sessions_by_user, u->sessions, s);
143 }
144
145 static void session_save_devices(Session *s, FILE *f) {
146 SessionDevice *sd;
147 Iterator i;
148
149 if (!hashmap_isempty(s->devices)) {
150 fprintf(f, "DEVICES=");
151 HASHMAP_FOREACH(sd, s->devices, i)
152 fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
153 fprintf(f, "\n");
154 }
155 }
156
157 int session_save(Session *s) {
158 _cleanup_free_ char *temp_path = NULL;
159 _cleanup_fclose_ FILE *f = NULL;
160 int r = 0;
161
162 assert(s);
163
164 if (!s->user)
165 return -ESTALE;
166
167 if (!s->started)
168 return 0;
169
170 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
171 if (r < 0)
172 goto fail;
173
174 r = fopen_temporary(s->state_file, &f, &temp_path);
175 if (r < 0)
176 goto fail;
177
178 assert(s->user);
179
180 fchmod(fileno(f), 0644);
181
182 fprintf(f,
183 "# This is private data. Do not parse.\n"
184 "UID="UID_FMT"\n"
185 "USER=%s\n"
186 "ACTIVE=%i\n"
187 "STATE=%s\n"
188 "REMOTE=%i\n",
189 s->user->uid,
190 s->user->name,
191 session_is_active(s),
192 session_state_to_string(session_get_state(s)),
193 s->remote);
194
195 if (s->type >= 0)
196 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
197
198 if (s->class >= 0)
199 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
200
201 if (s->scope)
202 fprintf(f, "SCOPE=%s\n", s->scope);
203 if (s->scope_job)
204 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
205
206 if (s->fifo_path)
207 fprintf(f, "FIFO=%s\n", s->fifo_path);
208
209 if (s->seat)
210 fprintf(f, "SEAT=%s\n", s->seat->id);
211
212 if (s->tty)
213 fprintf(f, "TTY=%s\n", s->tty);
214
215 if (s->display)
216 fprintf(f, "DISPLAY=%s\n", s->display);
217
218 if (s->remote_host) {
219 _cleanup_free_ char *escaped;
220
221 escaped = cescape(s->remote_host);
222 if (!escaped) {
223 r = -ENOMEM;
224 goto fail;
225 }
226
227 fprintf(f, "REMOTE_HOST=%s\n", escaped);
228 }
229
230 if (s->remote_user) {
231 _cleanup_free_ char *escaped;
232
233 escaped = cescape(s->remote_user);
234 if (!escaped) {
235 r = -ENOMEM;
236 goto fail;
237 }
238
239 fprintf(f, "REMOTE_USER=%s\n", escaped);
240 }
241
242 if (s->service) {
243 _cleanup_free_ char *escaped;
244
245 escaped = cescape(s->service);
246 if (!escaped) {
247 r = -ENOMEM;
248 goto fail;
249 }
250
251 fprintf(f, "SERVICE=%s\n", escaped);
252 }
253
254 if (s->desktop) {
255 _cleanup_free_ char *escaped;
256
257
258 escaped = cescape(s->desktop);
259 if (!escaped) {
260 r = -ENOMEM;
261 goto fail;
262 }
263
264 fprintf(f, "DESKTOP=%s\n", escaped);
265 }
266
267 if (s->seat && seat_has_vts(s->seat))
268 fprintf(f, "VTNR=%u\n", s->vtnr);
269
270 if (!s->vtnr)
271 fprintf(f, "POSITION=%u\n", s->position);
272
273 if (pid_is_valid(s->leader))
274 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
275
276 if (audit_session_is_valid(s->audit_id))
277 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
278
279 if (dual_timestamp_is_set(&s->timestamp))
280 fprintf(f,
281 "REALTIME="USEC_FMT"\n"
282 "MONOTONIC="USEC_FMT"\n",
283 s->timestamp.realtime,
284 s->timestamp.monotonic);
285
286 if (s->controller) {
287 fprintf(f, "CONTROLLER=%s\n", s->controller);
288 session_save_devices(s, f);
289 }
290
291 r = fflush_and_check(f);
292 if (r < 0)
293 goto fail;
294
295 if (rename(temp_path, s->state_file) < 0) {
296 r = -errno;
297 goto fail;
298 }
299
300 return 0;
301
302 fail:
303 (void) unlink(s->state_file);
304
305 if (temp_path)
306 (void) unlink(temp_path);
307
308 return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
309 }
310
311 static int session_load_devices(Session *s, const char *devices) {
312 const char *p;
313 int r = 0;
314
315 assert(s);
316
317 for (p = devices;;) {
318 _cleanup_free_ char *word = NULL;
319 SessionDevice *sd;
320 dev_t dev;
321 int k;
322
323 k = extract_first_word(&p, &word, NULL, 0);
324 if (k == 0)
325 break;
326 if (k < 0) {
327 r = k;
328 break;
329 }
330
331 k = parse_dev(word, &dev);
332 if (k < 0) {
333 r = k;
334 continue;
335 }
336
337 /* The file descriptors for loaded devices will be reattached later. */
338 k = session_device_new(s, dev, false, &sd);
339 if (k < 0)
340 r = k;
341 }
342
343 if (r < 0)
344 log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
345
346 return r;
347 }
348
349 int session_load(Session *s) {
350 _cleanup_free_ char *remote = NULL,
351 *seat = NULL,
352 *vtnr = NULL,
353 *state = NULL,
354 *position = NULL,
355 *leader = NULL,
356 *type = NULL,
357 *class = NULL,
358 *uid = NULL,
359 *realtime = NULL,
360 *monotonic = NULL,
361 *controller = NULL,
362 *active = NULL,
363 *devices = NULL;
364
365 int k, r;
366
367 assert(s);
368
369 r = parse_env_file(s->state_file, NEWLINE,
370 "REMOTE", &remote,
371 "SCOPE", &s->scope,
372 "SCOPE_JOB", &s->scope_job,
373 "FIFO", &s->fifo_path,
374 "SEAT", &seat,
375 "TTY", &s->tty,
376 "DISPLAY", &s->display,
377 "REMOTE_HOST", &s->remote_host,
378 "REMOTE_USER", &s->remote_user,
379 "SERVICE", &s->service,
380 "DESKTOP", &s->desktop,
381 "VTNR", &vtnr,
382 "STATE", &state,
383 "POSITION", &position,
384 "LEADER", &leader,
385 "TYPE", &type,
386 "CLASS", &class,
387 "UID", &uid,
388 "REALTIME", &realtime,
389 "MONOTONIC", &monotonic,
390 "CONTROLLER", &controller,
391 "ACTIVE", &active,
392 "DEVICES", &devices,
393 NULL);
394
395 if (r < 0)
396 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
397
398 if (!s->user) {
399 uid_t u;
400 User *user;
401
402 if (!uid) {
403 log_error("UID not specified for session %s", s->id);
404 return -ENOENT;
405 }
406
407 r = parse_uid(uid, &u);
408 if (r < 0) {
409 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
410 return r;
411 }
412
413 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
414 if (!user) {
415 log_error("User of session %s not known.", s->id);
416 return -ENOENT;
417 }
418
419 session_set_user(s, user);
420 }
421
422 if (remote) {
423 k = parse_boolean(remote);
424 if (k >= 0)
425 s->remote = k;
426 }
427
428 if (vtnr)
429 safe_atou(vtnr, &s->vtnr);
430
431 if (seat && !s->seat) {
432 Seat *o;
433
434 o = hashmap_get(s->manager->seats, seat);
435 if (o)
436 r = seat_attach_session(o, s);
437 if (!o || r < 0)
438 log_error("Cannot attach session %s to seat %s", s->id, seat);
439 }
440
441 if (!s->seat || !seat_has_vts(s->seat))
442 s->vtnr = 0;
443
444 if (position && s->seat) {
445 unsigned int npos;
446
447 safe_atou(position, &npos);
448 seat_claim_position(s->seat, s, npos);
449 }
450
451 if (leader) {
452 if (parse_pid(leader, &s->leader) >= 0)
453 (void) audit_session_from_pid(s->leader, &s->audit_id);
454 }
455
456 if (type) {
457 SessionType t;
458
459 t = session_type_from_string(type);
460 if (t >= 0)
461 s->type = t;
462 }
463
464 if (class) {
465 SessionClass c;
466
467 c = session_class_from_string(class);
468 if (c >= 0)
469 s->class = c;
470 }
471
472 if (state && streq(state, "closing"))
473 s->stopping = true;
474
475 if (s->fifo_path) {
476 int fd;
477
478 /* If we open an unopened pipe for reading we will not
479 get an EOF. to trigger an EOF we hence open it for
480 writing, but close it right away which then will
481 trigger the EOF. This will happen immediately if no
482 other process has the FIFO open for writing, i. e.
483 when the session died before logind (re)started. */
484
485 fd = session_create_fifo(s);
486 safe_close(fd);
487 }
488
489 if (realtime)
490 timestamp_deserialize(realtime, &s->timestamp.realtime);
491 if (monotonic)
492 timestamp_deserialize(monotonic, &s->timestamp.monotonic);
493
494 if (active) {
495 k = parse_boolean(active);
496 if (k >= 0)
497 s->was_active = k;
498 }
499
500 if (controller) {
501 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) {
502 session_set_controller(s, controller, false, false);
503 session_load_devices(s, devices);
504 } else
505 session_restore_vt(s);
506 }
507
508 return r;
509 }
510
511 int session_activate(Session *s) {
512 unsigned int num_pending;
513
514 assert(s);
515 assert(s->user);
516
517 if (!s->seat)
518 return -EOPNOTSUPP;
519
520 if (s->seat->active == s)
521 return 0;
522
523 /* on seats with VTs, we let VTs manage session-switching */
524 if (seat_has_vts(s->seat)) {
525 if (!s->vtnr)
526 return -EOPNOTSUPP;
527
528 return chvt(s->vtnr);
529 }
530
531 /* On seats without VTs, we implement session-switching in logind. We
532 * try to pause all session-devices and wait until the session
533 * controller acknowledged them. Once all devices are asleep, we simply
534 * switch the active session and be done.
535 * We save the session we want to switch to in seat->pending_switch and
536 * seat_complete_switch() will perform the final switch. */
537
538 s->seat->pending_switch = s;
539
540 /* if no devices are running, immediately perform the session switch */
541 num_pending = session_device_try_pause_all(s);
542 if (!num_pending)
543 seat_complete_switch(s->seat);
544
545 return 0;
546 }
547
548 static int session_start_scope(Session *s) {
549 int r;
550
551 assert(s);
552 assert(s->user);
553
554 if (!s->scope) {
555 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
556 char *scope, *job = NULL;
557 const char *description;
558
559 scope = strjoin("session-", s->id, ".scope");
560 if (!scope)
561 return log_oom();
562
563 description = strjoina("Session ", s->id, " of user ", s->user->name);
564
565 r = manager_start_scope(
566 s->manager,
567 scope,
568 s->leader,
569 s->user->slice,
570 description,
571 "systemd-logind.service",
572 "systemd-user-sessions.service",
573 (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
574 &error,
575 &job);
576 if (r < 0) {
577 log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r));
578 free(scope);
579 return r;
580 } else {
581 s->scope = scope;
582
583 free(s->scope_job);
584 s->scope_job = job;
585 }
586 }
587
588 if (s->scope)
589 (void) hashmap_put(s->manager->session_units, s->scope, s);
590
591 return 0;
592 }
593
594 int session_start(Session *s) {
595 int r;
596
597 assert(s);
598
599 if (!s->user)
600 return -ESTALE;
601
602 if (s->started)
603 return 0;
604
605 r = user_start(s->user);
606 if (r < 0)
607 return r;
608
609 /* Create cgroup */
610 r = session_start_scope(s);
611 if (r < 0)
612 return r;
613
614 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
615 "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
616 "SESSION_ID=%s", s->id,
617 "USER_ID=%s", s->user->name,
618 "LEADER="PID_FMT, s->leader,
619 LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name),
620 NULL);
621
622 if (!dual_timestamp_is_set(&s->timestamp))
623 dual_timestamp_get(&s->timestamp);
624
625 if (s->seat)
626 seat_read_active_vt(s->seat);
627
628 s->started = true;
629
630 user_elect_display(s->user);
631
632 /* Save data */
633 session_save(s);
634 user_save(s->user);
635 if (s->seat)
636 seat_save(s->seat);
637
638 /* Send signals */
639 session_send_signal(s, true);
640 user_send_changed(s->user, "Display", NULL);
641 if (s->seat) {
642 if (s->seat->active == s)
643 seat_send_changed(s->seat, "ActiveSession", NULL);
644 }
645
646 return 0;
647 }
648
649 static int session_stop_scope(Session *s, bool force) {
650 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
651 int r;
652
653 assert(s);
654
655 if (!s->scope)
656 return 0;
657
658 /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
659 * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
660 * when killing any processes left after this point. */
661 r = manager_abandon_scope(s->manager, s->scope, &error);
662 if (r < 0)
663 log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r));
664
665 /* Optionally, let's kill everything that's left now. */
666 if (force || manager_shall_kill(s->manager, s->user->name)) {
667 char *job = NULL;
668
669 r = manager_stop_unit(s->manager, s->scope, &error, &job);
670 if (r < 0)
671 return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r));
672
673 free(s->scope_job);
674 s->scope_job = job;
675 } else
676 s->scope_job = mfree(s->scope_job);
677
678 return 0;
679 }
680
681 int session_stop(Session *s, bool force) {
682 int r;
683
684 assert(s);
685
686 if (!s->user)
687 return -ESTALE;
688
689 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
690
691 if (s->seat)
692 seat_evict_position(s->seat, s);
693
694 /* We are going down, don't care about FIFOs anymore */
695 session_remove_fifo(s);
696
697 /* Kill cgroup */
698 r = session_stop_scope(s, force);
699
700 s->stopping = true;
701
702 user_elect_display(s->user);
703
704 session_save(s);
705 user_save(s->user);
706
707 return r;
708 }
709
710 int session_finalize(Session *s) {
711 SessionDevice *sd;
712
713 assert(s);
714
715 if (!s->user)
716 return -ESTALE;
717
718 if (s->started)
719 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
720 "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
721 "SESSION_ID=%s", s->id,
722 "USER_ID=%s", s->user->name,
723 "LEADER="PID_FMT, s->leader,
724 LOG_MESSAGE("Removed session %s.", s->id),
725 NULL);
726
727 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
728
729 if (s->seat)
730 seat_evict_position(s->seat, s);
731
732 /* Kill session devices */
733 while ((sd = hashmap_first(s->devices)))
734 session_device_free(sd);
735
736 (void) unlink(s->state_file);
737 session_add_to_gc_queue(s);
738 user_add_to_gc_queue(s->user);
739
740 if (s->started) {
741 session_send_signal(s, false);
742 s->started = false;
743 }
744
745 if (s->seat) {
746 if (s->seat->active == s)
747 seat_set_active(s->seat, NULL);
748
749 seat_save(s->seat);
750 }
751
752 user_save(s->user);
753 user_send_changed(s->user, "Display", NULL);
754
755 return 0;
756 }
757
758 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
759 Session *s = userdata;
760
761 assert(es);
762 assert(s);
763
764 session_stop(s, false);
765 return 0;
766 }
767
768 int session_release(Session *s) {
769 assert(s);
770
771 if (!s->started || s->stopping)
772 return 0;
773
774 if (s->timer_event_source)
775 return 0;
776
777 return sd_event_add_time(s->manager->event,
778 &s->timer_event_source,
779 CLOCK_MONOTONIC,
780 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
781 release_timeout_callback, s);
782 }
783
784 bool session_is_active(Session *s) {
785 assert(s);
786
787 if (!s->seat)
788 return true;
789
790 return s->seat->active == s;
791 }
792
793 static int get_tty_atime(const char *tty, usec_t *atime) {
794 _cleanup_free_ char *p = NULL;
795 struct stat st;
796
797 assert(tty);
798 assert(atime);
799
800 if (!path_is_absolute(tty)) {
801 p = strappend("/dev/", tty);
802 if (!p)
803 return -ENOMEM;
804
805 tty = p;
806 } else if (!path_startswith(tty, "/dev/"))
807 return -ENOENT;
808
809 if (lstat(tty, &st) < 0)
810 return -errno;
811
812 *atime = timespec_load(&st.st_atim);
813 return 0;
814 }
815
816 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
817 _cleanup_free_ char *p = NULL;
818 int r;
819
820 assert(pid > 0);
821 assert(atime);
822
823 r = get_ctty(pid, NULL, &p);
824 if (r < 0)
825 return r;
826
827 return get_tty_atime(p, atime);
828 }
829
830 int session_get_idle_hint(Session *s, dual_timestamp *t) {
831 usec_t atime = 0, n;
832 int r;
833
834 assert(s);
835
836 /* Explicit idle hint is set */
837 if (s->idle_hint) {
838 if (t)
839 *t = s->idle_hint_timestamp;
840
841 return s->idle_hint;
842 }
843
844 /* Graphical sessions should really implement a real
845 * idle hint logic */
846 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
847 goto dont_know;
848
849 /* For sessions with an explicitly configured tty, let's check
850 * its atime */
851 if (s->tty) {
852 r = get_tty_atime(s->tty, &atime);
853 if (r >= 0)
854 goto found_atime;
855 }
856
857 /* For sessions with a leader but no explicitly configured
858 * tty, let's check the controlling tty of the leader */
859 if (s->leader > 0) {
860 r = get_process_ctty_atime(s->leader, &atime);
861 if (r >= 0)
862 goto found_atime;
863 }
864
865 dont_know:
866 if (t)
867 *t = s->idle_hint_timestamp;
868
869 return 0;
870
871 found_atime:
872 if (t)
873 dual_timestamp_from_realtime(t, atime);
874
875 n = now(CLOCK_REALTIME);
876
877 if (s->manager->idle_action_usec <= 0)
878 return 0;
879
880 return atime + s->manager->idle_action_usec <= n;
881 }
882
883 void session_set_idle_hint(Session *s, bool b) {
884 assert(s);
885
886 if (s->idle_hint == b)
887 return;
888
889 s->idle_hint = b;
890 dual_timestamp_get(&s->idle_hint_timestamp);
891
892 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
893
894 if (s->seat)
895 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
896
897 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
898 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
899 }
900
901 int session_get_locked_hint(Session *s) {
902 assert(s);
903
904 return s->locked_hint;
905 }
906
907 void session_set_locked_hint(Session *s, bool b) {
908 assert(s);
909
910 if (s->locked_hint == b)
911 return;
912
913 s->locked_hint = b;
914
915 session_send_changed(s, "LockedHint", NULL);
916 }
917
918 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
919 Session *s = userdata;
920
921 assert(s);
922 assert(s->fifo_fd == fd);
923
924 /* EOF on the FIFO means the session died abnormally. */
925
926 session_remove_fifo(s);
927 session_stop(s, false);
928
929 return 1;
930 }
931
932 int session_create_fifo(Session *s) {
933 int r;
934
935 assert(s);
936
937 /* Create FIFO */
938 if (!s->fifo_path) {
939 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
940 if (r < 0)
941 return r;
942
943 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
944 return -ENOMEM;
945
946 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
947 return -errno;
948 }
949
950 /* Open reading side */
951 if (s->fifo_fd < 0) {
952 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
953 if (s->fifo_fd < 0)
954 return -errno;
955
956 }
957
958 if (!s->fifo_event_source) {
959 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
960 if (r < 0)
961 return r;
962
963 /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
964 * sessions). */
965 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
966 if (r < 0)
967 return r;
968 }
969
970 /* Open writing side */
971 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK);
972 if (r < 0)
973 return -errno;
974
975 return r;
976 }
977
978 static void session_remove_fifo(Session *s) {
979 assert(s);
980
981 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
982 s->fifo_fd = safe_close(s->fifo_fd);
983
984 if (s->fifo_path) {
985 unlink(s->fifo_path);
986 s->fifo_path = mfree(s->fifo_path);
987 }
988 }
989
990 bool session_may_gc(Session *s, bool drop_not_started) {
991 assert(s);
992
993 if (drop_not_started && !s->started)
994 return true;
995
996 if (!s->user)
997 return true;
998
999 if (s->fifo_fd >= 0) {
1000 if (pipe_eof(s->fifo_fd) <= 0)
1001 return false;
1002 }
1003
1004 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
1005 return false;
1006
1007 if (s->scope && manager_unit_is_active(s->manager, s->scope))
1008 return false;
1009
1010 return true;
1011 }
1012
1013 void session_add_to_gc_queue(Session *s) {
1014 assert(s);
1015
1016 if (s->in_gc_queue)
1017 return;
1018
1019 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
1020 s->in_gc_queue = true;
1021 }
1022
1023 SessionState session_get_state(Session *s) {
1024 assert(s);
1025
1026 /* always check closing first */
1027 if (s->stopping || s->timer_event_source)
1028 return SESSION_CLOSING;
1029
1030 if (s->scope_job || s->fifo_fd < 0)
1031 return SESSION_OPENING;
1032
1033 if (session_is_active(s))
1034 return SESSION_ACTIVE;
1035
1036 return SESSION_ONLINE;
1037 }
1038
1039 int session_kill(Session *s, KillWho who, int signo) {
1040 assert(s);
1041
1042 if (!s->scope)
1043 return -ESRCH;
1044
1045 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
1046 }
1047
1048 static int session_open_vt(Session *s) {
1049 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
1050
1051 if (s->vtnr < 1)
1052 return -ENODEV;
1053
1054 if (s->vtfd >= 0)
1055 return s->vtfd;
1056
1057 sprintf(path, "/dev/tty%u", s->vtnr);
1058 s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
1059 if (s->vtfd < 0)
1060 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
1061
1062 return s->vtfd;
1063 }
1064
1065 int session_prepare_vt(Session *s) {
1066 int vt, r;
1067 struct vt_mode mode = { 0 };
1068
1069 if (s->vtnr < 1)
1070 return 0;
1071
1072 vt = session_open_vt(s);
1073 if (vt < 0)
1074 return vt;
1075
1076 r = fchown(vt, s->user->uid, -1);
1077 if (r < 0) {
1078 r = log_error_errno(errno,
1079 "Cannot change owner of /dev/tty%u: %m",
1080 s->vtnr);
1081 goto error;
1082 }
1083
1084 r = ioctl(vt, KDSKBMODE, K_OFF);
1085 if (r < 0) {
1086 r = log_error_errno(errno,
1087 "Cannot set K_OFF on /dev/tty%u: %m",
1088 s->vtnr);
1089 goto error;
1090 }
1091
1092 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1093 if (r < 0) {
1094 r = log_error_errno(errno,
1095 "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1096 s->vtnr);
1097 goto error;
1098 }
1099
1100 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1101 * So we need a dummy handler here which just acknowledges *all* VT
1102 * switch requests. */
1103 mode.mode = VT_PROCESS;
1104 mode.relsig = SIGRTMIN;
1105 mode.acqsig = SIGRTMIN + 1;
1106 r = ioctl(vt, VT_SETMODE, &mode);
1107 if (r < 0) {
1108 r = log_error_errno(errno,
1109 "Cannot set VT_PROCESS on /dev/tty%u: %m",
1110 s->vtnr);
1111 goto error;
1112 }
1113
1114 return 0;
1115
1116 error:
1117 session_restore_vt(s);
1118 return r;
1119 }
1120
1121 void session_restore_vt(Session *s) {
1122
1123 static const struct vt_mode mode = {
1124 .mode = VT_AUTO,
1125 };
1126
1127 int vt, old_fd;
1128
1129 /* We need to get a fresh handle to the virtual terminal,
1130 * since the old file-descriptor is potentially in a hung-up
1131 * state after the controlling process exited; we do a
1132 * little dance to avoid having the terminal be available
1133 * for reuse before we've cleaned it up.
1134 */
1135 old_fd = TAKE_FD(s->vtfd);
1136
1137 vt = session_open_vt(s);
1138 safe_close(old_fd);
1139
1140 if (vt < 0)
1141 return;
1142
1143 (void) ioctl(vt, KDSETMODE, KD_TEXT);
1144
1145 (void) vt_reset_keyboard(vt);
1146
1147 (void) ioctl(vt, VT_SETMODE, &mode);
1148 (void) fchown(vt, 0, (gid_t) -1);
1149
1150 s->vtfd = safe_close(s->vtfd);
1151 }
1152
1153 void session_leave_vt(Session *s) {
1154 int r;
1155
1156 assert(s);
1157
1158 /* This is called whenever we get a VT-switch signal from the kernel.
1159 * We acknowledge all of them unconditionally. Note that session are
1160 * free to overwrite those handlers and we only register them for
1161 * sessions with controllers. Legacy sessions are not affected.
1162 * However, if we switch from a non-legacy to a legacy session, we must
1163 * make sure to pause all device before acknowledging the switch. We
1164 * process the real switch only after we are notified via sysfs, so the
1165 * legacy session might have already started using the devices. If we
1166 * don't pause the devices before the switch, we might confuse the
1167 * session we switch to. */
1168
1169 if (s->vtfd < 0)
1170 return;
1171
1172 session_device_pause_all(s);
1173 r = ioctl(s->vtfd, VT_RELDISP, 1);
1174 if (r < 0)
1175 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
1176 }
1177
1178 bool session_is_controller(Session *s, const char *sender) {
1179 assert(s);
1180
1181 return streq_ptr(s->controller, sender);
1182 }
1183
1184 static void session_release_controller(Session *s, bool notify) {
1185 _cleanup_free_ char *name = NULL;
1186 SessionDevice *sd;
1187
1188 if (!s->controller)
1189 return;
1190
1191 name = s->controller;
1192
1193 /* By resetting the controller before releasing the devices, we won't
1194 * send notification signals. This avoids sending useless notifications
1195 * if the controller is released on disconnects. */
1196 if (!notify)
1197 s->controller = NULL;
1198
1199 while ((sd = hashmap_first(s->devices)))
1200 session_device_free(sd);
1201
1202 s->controller = NULL;
1203 s->track = sd_bus_track_unref(s->track);
1204 }
1205
1206 static int on_bus_track(sd_bus_track *track, void *userdata) {
1207 Session *s = userdata;
1208
1209 assert(track);
1210 assert(s);
1211
1212 session_drop_controller(s);
1213
1214 return 0;
1215 }
1216
1217 int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
1218 _cleanup_free_ char *name = NULL;
1219 int r;
1220
1221 assert(s);
1222 assert(sender);
1223
1224 if (session_is_controller(s, sender))
1225 return 0;
1226 if (s->controller && !force)
1227 return -EBUSY;
1228
1229 name = strdup(sender);
1230 if (!name)
1231 return -ENOMEM;
1232
1233 s->track = sd_bus_track_unref(s->track);
1234 r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1235 if (r < 0)
1236 return r;
1237
1238 r = sd_bus_track_add_name(s->track, name);
1239 if (r < 0)
1240 return r;
1241
1242 /* When setting a session controller, we forcibly mute the VT and set
1243 * it into graphics-mode. Applications can override that by changing
1244 * VT state after calling TakeControl(). However, this serves as a good
1245 * default and well-behaving controllers can now ignore VTs entirely.
1246 * Note that we reset the VT on ReleaseControl() and if the controller
1247 * exits.
1248 * If logind crashes/restarts, we restore the controller during restart
1249 * (without preparing the VT since the controller has probably overridden
1250 * VT state by now) or reset the VT in case it crashed/exited, too. */
1251 if (prepare) {
1252 r = session_prepare_vt(s);
1253 if (r < 0) {
1254 s->track = sd_bus_track_unref(s->track);
1255 return r;
1256 }
1257 }
1258
1259 session_release_controller(s, true);
1260 s->controller = TAKE_PTR(name);
1261 session_save(s);
1262
1263 return 0;
1264 }
1265
1266 void session_drop_controller(Session *s) {
1267 assert(s);
1268
1269 if (!s->controller)
1270 return;
1271
1272 s->track = sd_bus_track_unref(s->track);
1273 session_release_controller(s, false);
1274 session_save(s);
1275 session_restore_vt(s);
1276 }
1277
1278 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1279 [SESSION_OPENING] = "opening",
1280 [SESSION_ONLINE] = "online",
1281 [SESSION_ACTIVE] = "active",
1282 [SESSION_CLOSING] = "closing"
1283 };
1284
1285 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1286
1287 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1288 [SESSION_UNSPECIFIED] = "unspecified",
1289 [SESSION_TTY] = "tty",
1290 [SESSION_X11] = "x11",
1291 [SESSION_WAYLAND] = "wayland",
1292 [SESSION_MIR] = "mir",
1293 [SESSION_WEB] = "web",
1294 };
1295
1296 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1297
1298 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1299 [SESSION_USER] = "user",
1300 [SESSION_GREETER] = "greeter",
1301 [SESSION_LOCK_SCREEN] = "lock-screen",
1302 [SESSION_BACKGROUND] = "background"
1303 };
1304
1305 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1306
1307 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1308 [KILL_LEADER] = "leader",
1309 [KILL_ALL] = "all"
1310 };
1311
1312 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);