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