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