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