]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
Merge pull request #8135 from shawnl/arg_host
[thirdparty/systemd.git] / src / login / logind-session.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <linux/kd.h>
6 #include <linux/vt.h>
7 #include <signal.h>
8 #include <string.h>
9 #include <sys/ioctl.h>
10 #include <unistd.h>
11
12 #include "sd-messages.h"
13
14 #include "alloc-util.h"
15 #include "audit-util.h"
16 #include "bus-error.h"
17 #include "bus-util.h"
18 #include "escape.h"
19 #include "fd-util.h"
20 #include "fileio.h"
21 #include "format-util.h"
22 #include "io-util.h"
23 #include "logind-session.h"
24 #include "mkdir.h"
25 #include "parse-util.h"
26 #include "path-util.h"
27 #include "string-table.h"
28 #include "terminal-util.h"
29 #include "user-util.h"
30 #include "util.h"
31 #include "process-util.h"
32
33 #define RELEASE_USEC (20*USEC_PER_SEC)
34
35 static void session_remove_fifo(Session *s);
36
37 Session* session_new(Manager *m, const char *id) {
38 Session *s;
39
40 assert(m);
41 assert(id);
42 assert(session_id_valid(id));
43
44 s = new0(Session, 1);
45 if (!s)
46 return NULL;
47
48 s->state_file = strappend("/run/systemd/sessions/", id);
49 if (!s->state_file)
50 return mfree(s);
51
52 s->devices = hashmap_new(&devt_hash_ops);
53 if (!s->devices) {
54 free(s->state_file);
55 return mfree(s);
56 }
57
58 s->id = basename(s->state_file);
59
60 if (hashmap_put(m->sessions, s->id, s) < 0) {
61 hashmap_free(s->devices);
62 free(s->state_file);
63 return mfree(s);
64 }
65
66 s->manager = m;
67 s->fifo_fd = -1;
68 s->vtfd = -1;
69 s->audit_id = AUDIT_SESSION_INVALID;
70
71 return s;
72 }
73
74 void session_free(Session *s) {
75 SessionDevice *sd;
76
77 assert(s);
78
79 if (s->in_gc_queue)
80 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
81
82 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
83
84 session_remove_fifo(s);
85
86 session_drop_controller(s);
87
88 while ((sd = hashmap_first(s->devices)))
89 session_device_free(sd);
90
91 hashmap_free(s->devices);
92
93 if (s->user) {
94 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
95
96 if (s->user->display == s)
97 s->user->display = NULL;
98 }
99
100 if (s->seat) {
101 if (s->seat->active == s)
102 s->seat->active = NULL;
103 if (s->seat->pending_switch == s)
104 s->seat->pending_switch = NULL;
105
106 seat_evict_position(s->seat, s);
107 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
108 }
109
110 if (s->scope) {
111 hashmap_remove(s->manager->session_units, s->scope);
112 free(s->scope);
113 }
114
115 free(s->scope_job);
116
117 sd_bus_message_unref(s->create_message);
118
119 free(s->tty);
120 free(s->display);
121 free(s->remote_host);
122 free(s->remote_user);
123 free(s->service);
124 free(s->desktop);
125
126 hashmap_remove(s->manager->sessions, s->id);
127
128 free(s->state_file);
129 free(s);
130 }
131
132 void session_set_user(Session *s, User *u) {
133 assert(s);
134 assert(!s->user);
135
136 s->user = u;
137 LIST_PREPEND(sessions_by_user, u->sessions, s);
138 }
139
140 static void session_save_devices(Session *s, FILE *f) {
141 SessionDevice *sd;
142 Iterator i;
143
144 if (!hashmap_isempty(s->devices)) {
145 fprintf(f, "DEVICES=");
146 HASHMAP_FOREACH(sd, s->devices, i)
147 fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
148 fprintf(f, "\n");
149 }
150 }
151
152 int session_save(Session *s) {
153 _cleanup_free_ char *temp_path = NULL;
154 _cleanup_fclose_ FILE *f = NULL;
155 int r = 0;
156
157 assert(s);
158
159 if (!s->user)
160 return -ESTALE;
161
162 if (!s->started)
163 return 0;
164
165 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
166 if (r < 0)
167 goto fail;
168
169 r = fopen_temporary(s->state_file, &f, &temp_path);
170 if (r < 0)
171 goto fail;
172
173 assert(s->user);
174
175 fchmod(fileno(f), 0644);
176
177 fprintf(f,
178 "# This is private data. Do not parse.\n"
179 "UID="UID_FMT"\n"
180 "USER=%s\n"
181 "ACTIVE=%i\n"
182 "STATE=%s\n"
183 "REMOTE=%i\n",
184 s->user->uid,
185 s->user->name,
186 session_is_active(s),
187 session_state_to_string(session_get_state(s)),
188 s->remote);
189
190 if (s->type >= 0)
191 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
192
193 if (s->class >= 0)
194 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
195
196 if (s->scope)
197 fprintf(f, "SCOPE=%s\n", s->scope);
198 if (s->scope_job)
199 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
200
201 if (s->fifo_path)
202 fprintf(f, "FIFO=%s\n", s->fifo_path);
203
204 if (s->seat)
205 fprintf(f, "SEAT=%s\n", s->seat->id);
206
207 if (s->tty)
208 fprintf(f, "TTY=%s\n", s->tty);
209
210 if (s->display)
211 fprintf(f, "DISPLAY=%s\n", s->display);
212
213 if (s->remote_host) {
214 _cleanup_free_ char *escaped;
215
216 escaped = cescape(s->remote_host);
217 if (!escaped) {
218 r = -ENOMEM;
219 goto fail;
220 }
221
222 fprintf(f, "REMOTE_HOST=%s\n", escaped);
223 }
224
225 if (s->remote_user) {
226 _cleanup_free_ char *escaped;
227
228 escaped = cescape(s->remote_user);
229 if (!escaped) {
230 r = -ENOMEM;
231 goto fail;
232 }
233
234 fprintf(f, "REMOTE_USER=%s\n", escaped);
235 }
236
237 if (s->service) {
238 _cleanup_free_ char *escaped;
239
240 escaped = cescape(s->service);
241 if (!escaped) {
242 r = -ENOMEM;
243 goto fail;
244 }
245
246 fprintf(f, "SERVICE=%s\n", escaped);
247 }
248
249 if (s->desktop) {
250 _cleanup_free_ char *escaped;
251
252 escaped = cescape(s->desktop);
253 if (!escaped) {
254 r = -ENOMEM;
255 goto fail;
256 }
257
258 fprintf(f, "DESKTOP=%s\n", escaped);
259 }
260
261 if (s->seat && seat_has_vts(s->seat))
262 fprintf(f, "VTNR=%u\n", s->vtnr);
263
264 if (!s->vtnr)
265 fprintf(f, "POSITION=%u\n", s->position);
266
267 if (pid_is_valid(s->leader))
268 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
269
270 if (audit_session_is_valid(s->audit_id))
271 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
272
273 if (dual_timestamp_is_set(&s->timestamp))
274 fprintf(f,
275 "REALTIME="USEC_FMT"\n"
276 "MONOTONIC="USEC_FMT"\n",
277 s->timestamp.realtime,
278 s->timestamp.monotonic);
279
280 if (s->controller) {
281 fprintf(f, "CONTROLLER=%s\n", s->controller);
282 session_save_devices(s, f);
283 }
284
285 r = fflush_and_check(f);
286 if (r < 0)
287 goto fail;
288
289 if (rename(temp_path, s->state_file) < 0) {
290 r = -errno;
291 goto fail;
292 }
293
294 return 0;
295
296 fail:
297 (void) unlink(s->state_file);
298
299 if (temp_path)
300 (void) unlink(temp_path);
301
302 return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
303 }
304
305 static int session_load_devices(Session *s, const char *devices) {
306 const char *p;
307 int r = 0;
308
309 assert(s);
310
311 for (p = devices;;) {
312 _cleanup_free_ char *word = NULL;
313 SessionDevice *sd;
314 dev_t dev;
315 int k;
316
317 k = extract_first_word(&p, &word, NULL, 0);
318 if (k == 0)
319 break;
320 if (k < 0) {
321 r = k;
322 break;
323 }
324
325 k = parse_dev(word, &dev);
326 if (k < 0) {
327 r = k;
328 continue;
329 }
330
331 /* The file descriptors for loaded devices will be reattached later. */
332 k = session_device_new(s, dev, false, &sd);
333 if (k < 0)
334 r = k;
335 }
336
337 if (r < 0)
338 log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
339
340 return r;
341 }
342
343 int session_load(Session *s) {
344 _cleanup_free_ char *remote = NULL,
345 *seat = NULL,
346 *vtnr = NULL,
347 *state = NULL,
348 *position = NULL,
349 *leader = NULL,
350 *type = NULL,
351 *class = NULL,
352 *uid = NULL,
353 *realtime = NULL,
354 *monotonic = NULL,
355 *controller = NULL,
356 *active = NULL,
357 *devices = NULL;
358
359 int k, r;
360
361 assert(s);
362
363 r = parse_env_file(NULL, s->state_file, NEWLINE,
364 "REMOTE", &remote,
365 "SCOPE", &s->scope,
366 "SCOPE_JOB", &s->scope_job,
367 "FIFO", &s->fifo_path,
368 "SEAT", &seat,
369 "TTY", &s->tty,
370 "DISPLAY", &s->display,
371 "REMOTE_HOST", &s->remote_host,
372 "REMOTE_USER", &s->remote_user,
373 "SERVICE", &s->service,
374 "DESKTOP", &s->desktop,
375 "VTNR", &vtnr,
376 "STATE", &state,
377 "POSITION", &position,
378 "LEADER", &leader,
379 "TYPE", &type,
380 "CLASS", &class,
381 "UID", &uid,
382 "REALTIME", &realtime,
383 "MONOTONIC", &monotonic,
384 "CONTROLLER", &controller,
385 "ACTIVE", &active,
386 "DEVICES", &devices,
387 NULL);
388
389 if (r < 0)
390 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
391
392 if (!s->user) {
393 uid_t u;
394 User *user;
395
396 if (!uid) {
397 log_error("UID not specified for session %s", s->id);
398 return -ENOENT;
399 }
400
401 r = parse_uid(uid, &u);
402 if (r < 0) {
403 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
404 return r;
405 }
406
407 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
408 if (!user) {
409 log_error("User of session %s not known.", s->id);
410 return -ENOENT;
411 }
412
413 session_set_user(s, user);
414 }
415
416 if (remote) {
417 k = parse_boolean(remote);
418 if (k >= 0)
419 s->remote = k;
420 }
421
422 if (vtnr)
423 safe_atou(vtnr, &s->vtnr);
424
425 if (seat && !s->seat) {
426 Seat *o;
427
428 o = hashmap_get(s->manager->seats, seat);
429 if (o)
430 r = seat_attach_session(o, s);
431 if (!o || r < 0)
432 log_error("Cannot attach session %s to seat %s", s->id, seat);
433 }
434
435 if (!s->seat || !seat_has_vts(s->seat))
436 s->vtnr = 0;
437
438 if (position && s->seat) {
439 unsigned int npos;
440
441 safe_atou(position, &npos);
442 seat_claim_position(s->seat, s, npos);
443 }
444
445 if (leader) {
446 if (parse_pid(leader, &s->leader) >= 0)
447 (void) audit_session_from_pid(s->leader, &s->audit_id);
448 }
449
450 if (type) {
451 SessionType t;
452
453 t = session_type_from_string(type);
454 if (t >= 0)
455 s->type = t;
456 }
457
458 if (class) {
459 SessionClass c;
460
461 c = session_class_from_string(class);
462 if (c >= 0)
463 s->class = c;
464 }
465
466 if (state && streq(state, "closing"))
467 s->stopping = true;
468
469 if (s->fifo_path) {
470 int fd;
471
472 /* If we open an unopened pipe for reading we will not
473 get an EOF. to trigger an EOF we hence open it for
474 writing, but close it right away which then will
475 trigger the EOF. This will happen immediately if no
476 other process has the FIFO open for writing, i. e.
477 when the session died before logind (re)started. */
478
479 fd = session_create_fifo(s);
480 safe_close(fd);
481 }
482
483 if (realtime)
484 timestamp_deserialize(realtime, &s->timestamp.realtime);
485 if (monotonic)
486 timestamp_deserialize(monotonic, &s->timestamp.monotonic);
487
488 if (active) {
489 k = parse_boolean(active);
490 if (k >= 0)
491 s->was_active = k;
492 }
493
494 if (controller) {
495 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) {
496 session_set_controller(s, controller, false, false);
497 session_load_devices(s, devices);
498 } else
499 session_restore_vt(s);
500 }
501
502 return r;
503 }
504
505 int session_activate(Session *s) {
506 unsigned int num_pending;
507
508 assert(s);
509 assert(s->user);
510
511 if (!s->seat)
512 return -EOPNOTSUPP;
513
514 if (s->seat->active == s)
515 return 0;
516
517 /* on seats with VTs, we let VTs manage session-switching */
518 if (seat_has_vts(s->seat)) {
519 if (!s->vtnr)
520 return -EOPNOTSUPP;
521
522 return chvt(s->vtnr);
523 }
524
525 /* On seats without VTs, we implement session-switching in logind. We
526 * try to pause all session-devices and wait until the session
527 * controller acknowledged them. Once all devices are asleep, we simply
528 * switch the active session and be done.
529 * We save the session we want to switch to in seat->pending_switch and
530 * seat_complete_switch() will perform the final switch. */
531
532 s->seat->pending_switch = s;
533
534 /* if no devices are running, immediately perform the session switch */
535 num_pending = session_device_try_pause_all(s);
536 if (!num_pending)
537 seat_complete_switch(s->seat);
538
539 return 0;
540 }
541
542 static int session_start_scope(Session *s, sd_bus_message *properties) {
543 int r;
544
545 assert(s);
546 assert(s->user);
547
548 if (!s->scope) {
549 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
550 _cleanup_free_ char *scope = NULL;
551 char *job = NULL;
552 const char *description;
553
554 scope = strjoin("session-", s->id, ".scope");
555 if (!scope)
556 return log_oom();
557
558 description = strjoina("Session ", s->id, " of user ", s->user->name);
559
560 r = manager_start_scope(
561 s->manager,
562 scope,
563 s->leader,
564 s->user->slice,
565 description,
566 "systemd-logind.service",
567 "systemd-user-sessions.service",
568 properties,
569 &error,
570 &job);
571 if (r < 0)
572 return log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r));
573
574
575 s->scope = TAKE_PTR(scope);
576 free_and_replace(s->scope_job, job);
577 }
578
579 if (s->scope)
580 (void) hashmap_put(s->manager->session_units, s->scope, s);
581
582 return 0;
583 }
584
585 int session_start(Session *s, sd_bus_message *properties) {
586 int r;
587
588 assert(s);
589
590 if (!s->user)
591 return -ESTALE;
592
593 if (s->started)
594 return 0;
595
596 r = user_start(s->user);
597 if (r < 0)
598 return r;
599
600 /* Create cgroup */
601 r = session_start_scope(s, properties);
602 if (r < 0)
603 return r;
604
605 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
606 "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
607 "SESSION_ID=%s", s->id,
608 "USER_ID=%s", s->user->name,
609 "LEADER="PID_FMT, s->leader,
610 LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name));
611
612 if (!dual_timestamp_is_set(&s->timestamp))
613 dual_timestamp_get(&s->timestamp);
614
615 if (s->seat)
616 seat_read_active_vt(s->seat);
617
618 s->started = true;
619
620 user_elect_display(s->user);
621
622 /* Save data */
623 session_save(s);
624 user_save(s->user);
625 if (s->seat)
626 seat_save(s->seat);
627
628 /* Send signals */
629 session_send_signal(s, true);
630 user_send_changed(s->user, "Display", NULL);
631 if (s->seat) {
632 if (s->seat->active == s)
633 seat_send_changed(s->seat, "ActiveSession", NULL);
634 }
635
636 return 0;
637 }
638
639 static int session_stop_scope(Session *s, bool force) {
640 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
641 int r;
642
643 assert(s);
644
645 if (!s->scope)
646 return 0;
647
648 /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
649 * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
650 * when killing any processes left after this point. */
651 r = manager_abandon_scope(s->manager, s->scope, &error);
652 if (r < 0)
653 log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r));
654
655 /* Optionally, let's kill everything that's left now. */
656 if (force || manager_shall_kill(s->manager, s->user->name)) {
657 char *job = NULL;
658
659 r = manager_stop_unit(s->manager, s->scope, &error, &job);
660 if (r < 0)
661 return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r));
662
663 free(s->scope_job);
664 s->scope_job = job;
665 } else {
666 s->scope_job = mfree(s->scope_job);
667
668 /* With no killing, this session is allowed to persist in "closing" state indefinitely.
669 * Therefore session stop and session removal may be two distinct events.
670 * Session stop is quite significant on its own, let's log it. */
671 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
672 "SESSION_ID=%s", s->id,
673 "USER_ID=%s", s->user->name,
674 "LEADER="PID_FMT, s->leader,
675 LOG_MESSAGE("Session %s logged out. Waiting for processes to exit.", s->id));
676 }
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
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);