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