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