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