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