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