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