]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
Merge pull request #9193 from keszybz/coverity
[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(NULL, 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
620 if (!dual_timestamp_is_set(&s->timestamp))
621 dual_timestamp_get(&s->timestamp);
622
623 if (s->seat)
624 seat_read_active_vt(s->seat);
625
626 s->started = true;
627
628 user_elect_display(s->user);
629
630 /* Save data */
631 session_save(s);
632 user_save(s->user);
633 if (s->seat)
634 seat_save(s->seat);
635
636 /* Send signals */
637 session_send_signal(s, true);
638 user_send_changed(s->user, "Display", NULL);
639 if (s->seat) {
640 if (s->seat->active == s)
641 seat_send_changed(s->seat, "ActiveSession", NULL);
642 }
643
644 return 0;
645 }
646
647 static int session_stop_scope(Session *s, bool force) {
648 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
649 int r;
650
651 assert(s);
652
653 if (!s->scope)
654 return 0;
655
656 /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
657 * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
658 * when killing any processes left after this point. */
659 r = manager_abandon_scope(s->manager, s->scope, &error);
660 if (r < 0)
661 log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r));
662
663 /* Optionally, let's kill everything that's left now. */
664 if (force || manager_shall_kill(s->manager, s->user->name)) {
665 char *job = NULL;
666
667 r = manager_stop_unit(s->manager, s->scope, &error, &job);
668 if (r < 0)
669 return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r));
670
671 free(s->scope_job);
672 s->scope_job = job;
673 } else {
674 s->scope_job = mfree(s->scope_job);
675
676 /* With no killing, this session is allowed to persist in "closing" state indefinitely.
677 * Therefore session stop and session removal may be two distinct events.
678 * Session stop is quite significant on its own, let's log it. */
679 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
680 "SESSION_ID=%s", s->id,
681 "USER_ID=%s", s->user->name,
682 "LEADER="PID_FMT, s->leader,
683 LOG_MESSAGE("Session %s logged out. Waiting for processes to exit.", s->id));
684 }
685
686 return 0;
687 }
688
689 int session_stop(Session *s, bool force) {
690 int r;
691
692 assert(s);
693
694 if (!s->user)
695 return -ESTALE;
696
697 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
698
699 if (s->seat)
700 seat_evict_position(s->seat, s);
701
702 /* We are going down, don't care about FIFOs anymore */
703 session_remove_fifo(s);
704
705 /* Kill cgroup */
706 r = session_stop_scope(s, force);
707
708 s->stopping = true;
709
710 user_elect_display(s->user);
711
712 session_save(s);
713 user_save(s->user);
714
715 return r;
716 }
717
718 int session_finalize(Session *s) {
719 SessionDevice *sd;
720
721 assert(s);
722
723 if (!s->user)
724 return -ESTALE;
725
726 if (s->started)
727 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
728 "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
729 "SESSION_ID=%s", s->id,
730 "USER_ID=%s", s->user->name,
731 "LEADER="PID_FMT, s->leader,
732 LOG_MESSAGE("Removed session %s.", s->id));
733
734 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
735
736 if (s->seat)
737 seat_evict_position(s->seat, s);
738
739 /* Kill session devices */
740 while ((sd = hashmap_first(s->devices)))
741 session_device_free(sd);
742
743 (void) unlink(s->state_file);
744 session_add_to_gc_queue(s);
745 user_add_to_gc_queue(s->user);
746
747 if (s->started) {
748 session_send_signal(s, false);
749 s->started = false;
750 }
751
752 if (s->seat) {
753 if (s->seat->active == s)
754 seat_set_active(s->seat, NULL);
755
756 seat_save(s->seat);
757 }
758
759 user_save(s->user);
760 user_send_changed(s->user, "Display", NULL);
761
762 return 0;
763 }
764
765 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
766 Session *s = userdata;
767
768 assert(es);
769 assert(s);
770
771 session_stop(s, false);
772 return 0;
773 }
774
775 int session_release(Session *s) {
776 assert(s);
777
778 if (!s->started || s->stopping)
779 return 0;
780
781 if (s->timer_event_source)
782 return 0;
783
784 return sd_event_add_time(s->manager->event,
785 &s->timer_event_source,
786 CLOCK_MONOTONIC,
787 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
788 release_timeout_callback, s);
789 }
790
791 bool session_is_active(Session *s) {
792 assert(s);
793
794 if (!s->seat)
795 return true;
796
797 return s->seat->active == s;
798 }
799
800 static int get_tty_atime(const char *tty, usec_t *atime) {
801 _cleanup_free_ char *p = NULL;
802 struct stat st;
803
804 assert(tty);
805 assert(atime);
806
807 if (!path_is_absolute(tty)) {
808 p = strappend("/dev/", tty);
809 if (!p)
810 return -ENOMEM;
811
812 tty = p;
813 } else if (!path_startswith(tty, "/dev/"))
814 return -ENOENT;
815
816 if (lstat(tty, &st) < 0)
817 return -errno;
818
819 *atime = timespec_load(&st.st_atim);
820 return 0;
821 }
822
823 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
824 _cleanup_free_ char *p = NULL;
825 int r;
826
827 assert(pid > 0);
828 assert(atime);
829
830 r = get_ctty(pid, NULL, &p);
831 if (r < 0)
832 return r;
833
834 return get_tty_atime(p, atime);
835 }
836
837 int session_get_idle_hint(Session *s, dual_timestamp *t) {
838 usec_t atime = 0, n;
839 int r;
840
841 assert(s);
842
843 /* Explicit idle hint is set */
844 if (s->idle_hint) {
845 if (t)
846 *t = s->idle_hint_timestamp;
847
848 return s->idle_hint;
849 }
850
851 /* Graphical sessions should really implement a real
852 * idle hint logic */
853 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
854 goto dont_know;
855
856 /* For sessions with an explicitly configured tty, let's check
857 * its atime */
858 if (s->tty) {
859 r = get_tty_atime(s->tty, &atime);
860 if (r >= 0)
861 goto found_atime;
862 }
863
864 /* For sessions with a leader but no explicitly configured
865 * tty, let's check the controlling tty of the leader */
866 if (s->leader > 0) {
867 r = get_process_ctty_atime(s->leader, &atime);
868 if (r >= 0)
869 goto found_atime;
870 }
871
872 dont_know:
873 if (t)
874 *t = s->idle_hint_timestamp;
875
876 return 0;
877
878 found_atime:
879 if (t)
880 dual_timestamp_from_realtime(t, atime);
881
882 n = now(CLOCK_REALTIME);
883
884 if (s->manager->idle_action_usec <= 0)
885 return 0;
886
887 return atime + s->manager->idle_action_usec <= n;
888 }
889
890 void session_set_idle_hint(Session *s, bool b) {
891 assert(s);
892
893 if (s->idle_hint == b)
894 return;
895
896 s->idle_hint = b;
897 dual_timestamp_get(&s->idle_hint_timestamp);
898
899 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
900
901 if (s->seat)
902 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
903
904 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
905 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
906 }
907
908 int session_get_locked_hint(Session *s) {
909 assert(s);
910
911 return s->locked_hint;
912 }
913
914 void session_set_locked_hint(Session *s, bool b) {
915 assert(s);
916
917 if (s->locked_hint == b)
918 return;
919
920 s->locked_hint = b;
921
922 session_send_changed(s, "LockedHint", NULL);
923 }
924
925 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
926 Session *s = userdata;
927
928 assert(s);
929 assert(s->fifo_fd == fd);
930
931 /* EOF on the FIFO means the session died abnormally. */
932
933 session_remove_fifo(s);
934 session_stop(s, false);
935
936 return 1;
937 }
938
939 int session_create_fifo(Session *s) {
940 int r;
941
942 assert(s);
943
944 /* Create FIFO */
945 if (!s->fifo_path) {
946 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
947 if (r < 0)
948 return r;
949
950 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
951 return -ENOMEM;
952
953 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
954 return -errno;
955 }
956
957 /* Open reading side */
958 if (s->fifo_fd < 0) {
959 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
960 if (s->fifo_fd < 0)
961 return -errno;
962
963 }
964
965 if (!s->fifo_event_source) {
966 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
967 if (r < 0)
968 return r;
969
970 /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
971 * sessions). */
972 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
973 if (r < 0)
974 return r;
975 }
976
977 /* Open writing side */
978 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK);
979 if (r < 0)
980 return -errno;
981
982 return r;
983 }
984
985 static void session_remove_fifo(Session *s) {
986 assert(s);
987
988 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
989 s->fifo_fd = safe_close(s->fifo_fd);
990
991 if (s->fifo_path) {
992 unlink(s->fifo_path);
993 s->fifo_path = mfree(s->fifo_path);
994 }
995 }
996
997 bool session_may_gc(Session *s, bool drop_not_started) {
998 assert(s);
999
1000 if (drop_not_started && !s->started)
1001 return true;
1002
1003 if (!s->user)
1004 return true;
1005
1006 if (s->fifo_fd >= 0) {
1007 if (pipe_eof(s->fifo_fd) <= 0)
1008 return false;
1009 }
1010
1011 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
1012 return false;
1013
1014 if (s->scope && manager_unit_is_active(s->manager, s->scope))
1015 return false;
1016
1017 return true;
1018 }
1019
1020 void session_add_to_gc_queue(Session *s) {
1021 assert(s);
1022
1023 if (s->in_gc_queue)
1024 return;
1025
1026 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
1027 s->in_gc_queue = true;
1028 }
1029
1030 SessionState session_get_state(Session *s) {
1031 assert(s);
1032
1033 /* always check closing first */
1034 if (s->stopping || s->timer_event_source)
1035 return SESSION_CLOSING;
1036
1037 if (s->scope_job || s->fifo_fd < 0)
1038 return SESSION_OPENING;
1039
1040 if (session_is_active(s))
1041 return SESSION_ACTIVE;
1042
1043 return SESSION_ONLINE;
1044 }
1045
1046 int session_kill(Session *s, KillWho who, int signo) {
1047 assert(s);
1048
1049 if (!s->scope)
1050 return -ESRCH;
1051
1052 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
1053 }
1054
1055 static int session_open_vt(Session *s) {
1056 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
1057
1058 if (s->vtnr < 1)
1059 return -ENODEV;
1060
1061 if (s->vtfd >= 0)
1062 return s->vtfd;
1063
1064 sprintf(path, "/dev/tty%u", s->vtnr);
1065 s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
1066 if (s->vtfd < 0)
1067 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
1068
1069 return s->vtfd;
1070 }
1071
1072 int session_prepare_vt(Session *s) {
1073 int vt, r;
1074 struct vt_mode mode = { 0 };
1075
1076 if (s->vtnr < 1)
1077 return 0;
1078
1079 vt = session_open_vt(s);
1080 if (vt < 0)
1081 return vt;
1082
1083 r = fchown(vt, s->user->uid, -1);
1084 if (r < 0) {
1085 r = log_error_errno(errno,
1086 "Cannot change owner of /dev/tty%u: %m",
1087 s->vtnr);
1088 goto error;
1089 }
1090
1091 r = ioctl(vt, KDSKBMODE, K_OFF);
1092 if (r < 0) {
1093 r = log_error_errno(errno,
1094 "Cannot set K_OFF on /dev/tty%u: %m",
1095 s->vtnr);
1096 goto error;
1097 }
1098
1099 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1100 if (r < 0) {
1101 r = log_error_errno(errno,
1102 "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1103 s->vtnr);
1104 goto error;
1105 }
1106
1107 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1108 * So we need a dummy handler here which just acknowledges *all* VT
1109 * switch requests. */
1110 mode.mode = VT_PROCESS;
1111 mode.relsig = SIGRTMIN;
1112 mode.acqsig = SIGRTMIN + 1;
1113 r = ioctl(vt, VT_SETMODE, &mode);
1114 if (r < 0) {
1115 r = log_error_errno(errno,
1116 "Cannot set VT_PROCESS on /dev/tty%u: %m",
1117 s->vtnr);
1118 goto error;
1119 }
1120
1121 return 0;
1122
1123 error:
1124 session_restore_vt(s);
1125 return r;
1126 }
1127
1128 void session_restore_vt(Session *s) {
1129
1130 static const struct vt_mode mode = {
1131 .mode = VT_AUTO,
1132 };
1133
1134 int vt, old_fd;
1135
1136 /* We need to get a fresh handle to the virtual terminal,
1137 * since the old file-descriptor is potentially in a hung-up
1138 * state after the controlling process exited; we do a
1139 * little dance to avoid having the terminal be available
1140 * for reuse before we've cleaned it up.
1141 */
1142 old_fd = TAKE_FD(s->vtfd);
1143
1144 vt = session_open_vt(s);
1145 safe_close(old_fd);
1146
1147 if (vt < 0)
1148 return;
1149
1150 (void) ioctl(vt, KDSETMODE, KD_TEXT);
1151
1152 (void) vt_reset_keyboard(vt);
1153
1154 (void) ioctl(vt, VT_SETMODE, &mode);
1155 (void) fchown(vt, 0, (gid_t) -1);
1156
1157 s->vtfd = safe_close(s->vtfd);
1158 }
1159
1160 void session_leave_vt(Session *s) {
1161 int r;
1162
1163 assert(s);
1164
1165 /* This is called whenever we get a VT-switch signal from the kernel.
1166 * We acknowledge all of them unconditionally. Note that session are
1167 * free to overwrite those handlers and we only register them for
1168 * sessions with controllers. Legacy sessions are not affected.
1169 * However, if we switch from a non-legacy to a legacy session, we must
1170 * make sure to pause all device before acknowledging the switch. We
1171 * process the real switch only after we are notified via sysfs, so the
1172 * legacy session might have already started using the devices. If we
1173 * don't pause the devices before the switch, we might confuse the
1174 * session we switch to. */
1175
1176 if (s->vtfd < 0)
1177 return;
1178
1179 session_device_pause_all(s);
1180 r = ioctl(s->vtfd, VT_RELDISP, 1);
1181 if (r < 0)
1182 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
1183 }
1184
1185 bool session_is_controller(Session *s, const char *sender) {
1186 assert(s);
1187
1188 return streq_ptr(s->controller, sender);
1189 }
1190
1191 static void session_release_controller(Session *s, bool notify) {
1192 _cleanup_free_ char *name = NULL;
1193 SessionDevice *sd;
1194
1195 if (!s->controller)
1196 return;
1197
1198 name = s->controller;
1199
1200 /* By resetting the controller before releasing the devices, we won't
1201 * send notification signals. This avoids sending useless notifications
1202 * if the controller is released on disconnects. */
1203 if (!notify)
1204 s->controller = NULL;
1205
1206 while ((sd = hashmap_first(s->devices)))
1207 session_device_free(sd);
1208
1209 s->controller = NULL;
1210 s->track = sd_bus_track_unref(s->track);
1211 }
1212
1213 static int on_bus_track(sd_bus_track *track, void *userdata) {
1214 Session *s = userdata;
1215
1216 assert(track);
1217 assert(s);
1218
1219 session_drop_controller(s);
1220
1221 return 0;
1222 }
1223
1224 int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
1225 _cleanup_free_ char *name = NULL;
1226 int r;
1227
1228 assert(s);
1229 assert(sender);
1230
1231 if (session_is_controller(s, sender))
1232 return 0;
1233 if (s->controller && !force)
1234 return -EBUSY;
1235
1236 name = strdup(sender);
1237 if (!name)
1238 return -ENOMEM;
1239
1240 s->track = sd_bus_track_unref(s->track);
1241 r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1242 if (r < 0)
1243 return r;
1244
1245 r = sd_bus_track_add_name(s->track, name);
1246 if (r < 0)
1247 return r;
1248
1249 /* When setting a session controller, we forcibly mute the VT and set
1250 * it into graphics-mode. Applications can override that by changing
1251 * VT state after calling TakeControl(). However, this serves as a good
1252 * default and well-behaving controllers can now ignore VTs entirely.
1253 * Note that we reset the VT on ReleaseControl() and if the controller
1254 * exits.
1255 * If logind crashes/restarts, we restore the controller during restart
1256 * (without preparing the VT since the controller has probably overridden
1257 * VT state by now) or reset the VT in case it crashed/exited, too. */
1258 if (prepare) {
1259 r = session_prepare_vt(s);
1260 if (r < 0) {
1261 s->track = sd_bus_track_unref(s->track);
1262 return r;
1263 }
1264 }
1265
1266 session_release_controller(s, true);
1267 s->controller = TAKE_PTR(name);
1268 session_save(s);
1269
1270 return 0;
1271 }
1272
1273 void session_drop_controller(Session *s) {
1274 assert(s);
1275
1276 if (!s->controller)
1277 return;
1278
1279 s->track = sd_bus_track_unref(s->track);
1280 session_release_controller(s, false);
1281 session_save(s);
1282 session_restore_vt(s);
1283 }
1284
1285 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1286 [SESSION_OPENING] = "opening",
1287 [SESSION_ONLINE] = "online",
1288 [SESSION_ACTIVE] = "active",
1289 [SESSION_CLOSING] = "closing"
1290 };
1291
1292 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1293
1294 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1295 [SESSION_UNSPECIFIED] = "unspecified",
1296 [SESSION_TTY] = "tty",
1297 [SESSION_X11] = "x11",
1298 [SESSION_WAYLAND] = "wayland",
1299 [SESSION_MIR] = "mir",
1300 [SESSION_WEB] = "web",
1301 };
1302
1303 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1304
1305 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1306 [SESSION_USER] = "user",
1307 [SESSION_GREETER] = "greeter",
1308 [SESSION_LOCK_SCREEN] = "lock-screen",
1309 [SESSION_BACKGROUND] = "background"
1310 };
1311
1312 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1313
1314 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1315 [KILL_LEADER] = "leader",
1316 [KILL_ALL] = "all"
1317 };
1318
1319 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);