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