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