chiark / gitweb /
Prep v234.2: Apply upstream fixes in src/login (5/6)
[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 "extract-word.h"
37 #include "fd-util.h"
38 #include "fileio.h"
39 #include "format-util.h"
40 #include "io-util.h"
41 #include "logind-session.h"
42 #include "mkdir.h"
43 #include "parse-util.h"
44 #include "path-util.h"
45 #include "string-table.h"
46 #include "terminal-util.h"
47 #include "user-util.h"
48 #include "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
87         return s;
88 }
89
90 void session_free(Session *s) {
91         SessionDevice *sd;
92
93         assert(s);
94
95         if (s->in_gc_queue)
96                 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
97
98         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
99
100         session_remove_fifo(s);
101
102         session_drop_controller(s);
103
104         while ((sd = hashmap_first(s->devices)))
105                 session_device_free(sd);
106
107         hashmap_free(s->devices);
108
109         if (s->user) {
110                 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
111
112                 if (s->user->display == s)
113                         s->user->display = NULL;
114         }
115
116         if (s->seat) {
117                 if (s->seat->active == s)
118                         s->seat->active = NULL;
119                 if (s->seat->pending_switch == s)
120                         s->seat->pending_switch = NULL;
121
122                 seat_evict_position(s->seat, s);
123                 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
124         }
125
126         if (s->scope) {
127                 hashmap_remove(s->manager->session_units, s->scope);
128                 free(s->scope);
129         }
130
131 #if 0 /// elogind does not support systemd scope_jobs
132         free(s->scope_job);
133 #endif // 0
134
135         sd_bus_message_unref(s->create_message);
136
137         free(s->tty);
138         free(s->display);
139         free(s->remote_host);
140         free(s->remote_user);
141         free(s->service);
142         free(s->desktop);
143
144         hashmap_remove(s->manager->sessions, s->id);
145
146         free(s->state_file);
147         free(s);
148 }
149
150 void session_set_user(Session *s, User *u) {
151         assert(s);
152         assert(!s->user);
153
154         s->user = u;
155         LIST_PREPEND(sessions_by_user, u->sessions, s);
156 }
157
158 static void session_save_devices(Session *s, FILE *f) {
159         SessionDevice *sd;
160         Iterator i;
161
162         if (!hashmap_isempty(s->devices)) {
163                 fprintf(f, "DEVICES=");
164                 HASHMAP_FOREACH(sd, s->devices, i)
165                         fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
166                 fprintf(f, "\n");
167         }
168 }
169
170 int session_save(Session *s) {
171         _cleanup_free_ char *temp_path = NULL;
172         _cleanup_fclose_ FILE *f = NULL;
173         int r = 0;
174
175         assert(s);
176
177         if (!s->user)
178                 return -ESTALE;
179
180         if (!s->started)
181                 return 0;
182
183         r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
184         if (r < 0)
185                 goto fail;
186
187         r = fopen_temporary(s->state_file, &f, &temp_path);
188         if (r < 0)
189                 goto fail;
190
191         assert(s->user);
192
193         fchmod(fileno(f), 0644);
194
195         fprintf(f,
196                 "# This is private data. Do not parse.\n"
197                 "UID="UID_FMT"\n"
198                 "USER=%s\n"
199                 "ACTIVE=%i\n"
200                 "STATE=%s\n"
201                 "REMOTE=%i\n",
202                 s->user->uid,
203                 s->user->name,
204                 session_is_active(s),
205                 session_state_to_string(session_get_state(s)),
206                 s->remote);
207
208         if (s->type >= 0)
209                 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
210
211         if (s->class >= 0)
212                 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
213
214         if (s->scope)
215                 fprintf(f, "SCOPE=%s\n", s->scope);
216 #if 0 /// elogind does not support systemd scope_jobs
217         if (s->scope_job)
218                 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
219 #endif // 0
220
221         if (s->fifo_path)
222                 fprintf(f, "FIFO=%s\n", s->fifo_path);
223
224         if (s->seat)
225                 fprintf(f, "SEAT=%s\n", s->seat->id);
226
227         if (s->tty)
228                 fprintf(f, "TTY=%s\n", s->tty);
229
230         if (s->display)
231                 fprintf(f, "DISPLAY=%s\n", s->display);
232
233         if (s->remote_host) {
234                 _cleanup_free_ char *escaped;
235
236                 escaped = cescape(s->remote_host);
237                 if (!escaped) {
238                         r = -ENOMEM;
239                         goto fail;
240                 }
241
242                 fprintf(f, "REMOTE_HOST=%s\n", escaped);
243         }
244
245         if (s->remote_user) {
246                 _cleanup_free_ char *escaped;
247
248                 escaped = cescape(s->remote_user);
249                 if (!escaped) {
250                         r = -ENOMEM;
251                         goto fail;
252                 }
253
254                 fprintf(f, "REMOTE_USER=%s\n", escaped);
255         }
256
257         if (s->service) {
258                 _cleanup_free_ char *escaped;
259
260                 escaped = cescape(s->service);
261                 if (!escaped) {
262                         r = -ENOMEM;
263                         goto fail;
264                 }
265
266                 fprintf(f, "SERVICE=%s\n", escaped);
267         }
268
269         if (s->desktop) {
270                 _cleanup_free_ char *escaped;
271
272
273                 escaped = cescape(s->desktop);
274                 if (!escaped) {
275                         r = -ENOMEM;
276                         goto fail;
277                 }
278
279                 fprintf(f, "DESKTOP=%s\n", escaped);
280         }
281
282         if (s->seat && seat_has_vts(s->seat))
283                 fprintf(f, "VTNR=%u\n", s->vtnr);
284
285         if (!s->vtnr)
286                 fprintf(f, "POSITION=%u\n", s->position);
287
288         if (s->leader > 0)
289                 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
290
291         if (s->audit_id > 0)
292                 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
293
294         if (dual_timestamp_is_set(&s->timestamp))
295                 fprintf(f,
296                         "REALTIME="USEC_FMT"\n"
297                         "MONOTONIC="USEC_FMT"\n",
298                         s->timestamp.realtime,
299                         s->timestamp.monotonic);
300
301         if (s->controller) {
302                 fprintf(f, "CONTROLLER=%s\n", s->controller);
303                 session_save_devices(s, f);
304         }
305
306         r = fflush_and_check(f);
307         if (r < 0)
308                 goto fail;
309
310         if (rename(temp_path, s->state_file) < 0) {
311                 r = -errno;
312                 goto fail;
313         }
314
315         return 0;
316
317 fail:
318         (void) unlink(s->state_file);
319
320         if (temp_path)
321                 (void) unlink(temp_path);
322
323         return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
324 }
325
326 static int session_load_devices(Session *s, const char *devices) {
327         const char *p;
328         int r = 0;
329
330         assert(s);
331
332         for (p = devices;;) {
333                 _cleanup_free_ char *word = NULL;
334                 SessionDevice *sd;
335                 dev_t dev;
336                 int k;
337
338                 k = extract_first_word(&p, &word, NULL, 0);
339                 if (k == 0)
340                         break;
341                 if (k < 0) {
342                         r = k;
343                         break;
344                 }
345
346                 k = parse_dev(word, &dev);
347                 if (k < 0) {
348                         r = k;
349                         continue;
350                 }
351
352                 /* The file descriptors for loaded devices will be reattached later. */
353                 k = session_device_new(s, dev, false, &sd);
354                 if (k < 0)
355                         r = k;
356         }
357
358         if (r < 0)
359                 log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
360
361         return r;
362 }
363
364 int session_load(Session *s) {
365         _cleanup_free_ char *remote = NULL,
366                 *seat = NULL,
367                 *vtnr = NULL,
368                 *state = NULL,
369                 *position = NULL,
370                 *leader = NULL,
371                 *type = NULL,
372                 *class = NULL,
373                 *uid = NULL,
374                 *realtime = NULL,
375                 *monotonic = NULL,
376                 *controller = NULL,
377                 *active = NULL,
378                 *devices = NULL;
379
380         int k, r;
381
382         assert(s);
383
384         r = parse_env_file(s->state_file, NEWLINE,
385                            "REMOTE",         &remote,
386                            "SCOPE",          &s->scope,
387 #if 0 /// elogind does not support systemd scope_jobs
388                            "SCOPE_JOB",      &s->scope_job,
389 #endif // 0
390                            "FIFO",           &s->fifo_path,
391                            "SEAT",           &seat,
392                            "TTY",            &s->tty,
393                            "DISPLAY",        &s->display,
394                            "REMOTE_HOST",    &s->remote_host,
395                            "REMOTE_USER",    &s->remote_user,
396                            "SERVICE",        &s->service,
397                            "DESKTOP",        &s->desktop,
398                            "VTNR",           &vtnr,
399                            "STATE",          &state,
400                            "POSITION",       &position,
401                            "LEADER",         &leader,
402                            "TYPE",           &type,
403                            "CLASS",          &class,
404                            "UID",            &uid,
405                            "REALTIME",       &realtime,
406                            "MONOTONIC",      &monotonic,
407                            "CONTROLLER",     &controller,
408                            "ACTIVE",         &active,
409                            "DEVICES",        &devices,
410                            NULL);
411
412         if (r < 0)
413                 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
414
415         if (!s->user) {
416                 uid_t u;
417                 User *user;
418
419                 if (!uid) {
420                         log_error("UID not specified for session %s", s->id);
421                         return -ENOENT;
422                 }
423
424                 r = parse_uid(uid, &u);
425                 if (r < 0)  {
426                         log_error("Failed to parse UID value %s for session %s.", uid, s->id);
427                         return r;
428                 }
429
430                 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
431                 if (!user) {
432                         log_error("User of session %s not known.", s->id);
433                         return -ENOENT;
434                 }
435
436                 session_set_user(s, user);
437         }
438
439         if (remote) {
440                 k = parse_boolean(remote);
441                 if (k >= 0)
442                         s->remote = k;
443         }
444
445         if (vtnr)
446                 safe_atou(vtnr, &s->vtnr);
447
448         if (seat && !s->seat) {
449                 Seat *o;
450
451                 o = hashmap_get(s->manager->seats, seat);
452                 if (o)
453                         r = seat_attach_session(o, s);
454                 if (!o || r < 0)
455                         log_error("Cannot attach session %s to seat %s", s->id, seat);
456         }
457
458         if (!s->seat || !seat_has_vts(s->seat))
459                 s->vtnr = 0;
460
461         if (position && s->seat) {
462                 unsigned int npos;
463
464                 safe_atou(position, &npos);
465                 seat_claim_position(s->seat, s, npos);
466         }
467
468         if (leader) {
469                 k = parse_pid(leader, &s->leader);
470                 if (k >= 0)
471                         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, kb, 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         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1238                 kb = K_UNICODE;
1239         else
1240                 kb = K_XLATE;
1241
1242         (void) ioctl(vt, KDSKBMODE, kb);
1243
1244         (void) ioctl(vt, VT_SETMODE, &mode);
1245         (void) fchown(vt, 0, (gid_t) -1);
1246
1247         s->vtfd = safe_close(s->vtfd);
1248 }
1249
1250 void session_leave_vt(Session *s) {
1251         int r;
1252
1253         assert(s);
1254
1255         /* This is called whenever we get a VT-switch signal from the kernel.
1256          * We acknowledge all of them unconditionally. Note that session are
1257          * free to overwrite those handlers and we only register them for
1258          * sessions with controllers. Legacy sessions are not affected.
1259          * However, if we switch from a non-legacy to a legacy session, we must
1260          * make sure to pause all device before acknowledging the switch. We
1261          * process the real switch only after we are notified via sysfs, so the
1262          * legacy session might have already started using the devices. If we
1263          * don't pause the devices before the switch, we might confuse the
1264          * session we switch to. */
1265
1266         if (s->vtfd < 0)
1267                 return;
1268
1269         session_device_pause_all(s);
1270         r = ioctl(s->vtfd, VT_RELDISP, 1);
1271         if (r < 0)
1272                 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
1273 }
1274
1275 bool session_is_controller(Session *s, const char *sender) {
1276         assert(s);
1277
1278         return streq_ptr(s->controller, sender);
1279 }
1280
1281 static void session_release_controller(Session *s, bool notify) {
1282         _cleanup_free_ char *name = NULL;
1283         SessionDevice *sd;
1284
1285         if (!s->controller)
1286                 return;
1287
1288         name = s->controller;
1289
1290         /* By resetting the controller before releasing the devices, we won't
1291          * send notification signals. This avoids sending useless notifications
1292          * if the controller is released on disconnects. */
1293         if (!notify)
1294                 s->controller = NULL;
1295
1296         while ((sd = hashmap_first(s->devices)))
1297                 session_device_free(sd);
1298
1299         s->controller = NULL;
1300         s->track = sd_bus_track_unref(s->track);
1301 }
1302
1303 static int on_bus_track(sd_bus_track *track, void *userdata) {
1304         Session *s = userdata;
1305
1306         assert(track);
1307         assert(s);
1308
1309         session_drop_controller(s);
1310
1311         return 0;
1312 }
1313
1314 int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
1315         _cleanup_free_ char *name = NULL;
1316         int r;
1317
1318         assert(s);
1319         assert(sender);
1320
1321         if (session_is_controller(s, sender))
1322                 return 0;
1323         if (s->controller && !force)
1324                 return -EBUSY;
1325
1326         name = strdup(sender);
1327         if (!name)
1328                 return -ENOMEM;
1329
1330         s->track = sd_bus_track_unref(s->track);
1331         r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1332         if (r < 0)
1333                 return r;
1334
1335         r = sd_bus_track_add_name(s->track, name);
1336         if (r < 0)
1337                 return r;
1338
1339         /* When setting a session controller, we forcibly mute the VT and set
1340          * it into graphics-mode. Applications can override that by changing
1341          * VT state after calling TakeControl(). However, this serves as a good
1342          * default and well-behaving controllers can now ignore VTs entirely.
1343          * Note that we reset the VT on ReleaseControl() and if the controller
1344          * exits.
1345          * If logind crashes/restarts, we restore the controller during restart
1346          * (without preparing the VT since the controller has probably overridden
1347          * VT state by now) or reset the VT in case it crashed/exited, too. */
1348         if (prepare) {
1349                 r = session_prepare_vt(s);
1350                 if (r < 0) {
1351                         s->track = sd_bus_track_unref(s->track);
1352                         return r;
1353                 }
1354         }
1355
1356         session_release_controller(s, true);
1357         s->controller = name;
1358         name = NULL;
1359         session_save(s);
1360
1361         return 0;
1362 }
1363
1364 void session_drop_controller(Session *s) {
1365         assert(s);
1366
1367         if (!s->controller)
1368                 return;
1369
1370         s->track = sd_bus_track_unref(s->track);
1371         session_release_controller(s, false);
1372         session_save(s);
1373         session_restore_vt(s);
1374 }
1375
1376 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1377         [SESSION_OPENING] = "opening",
1378         [SESSION_ONLINE] = "online",
1379         [SESSION_ACTIVE] = "active",
1380         [SESSION_CLOSING] = "closing"
1381 };
1382
1383 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1384
1385 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1386         [SESSION_UNSPECIFIED] = "unspecified",
1387         [SESSION_TTY] = "tty",
1388         [SESSION_X11] = "x11",
1389         [SESSION_WAYLAND] = "wayland",
1390         [SESSION_MIR] = "mir",
1391         [SESSION_WEB] = "web",
1392 };
1393
1394 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1395
1396 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1397         [SESSION_USER] = "user",
1398         [SESSION_GREETER] = "greeter",
1399         [SESSION_LOCK_SCREEN] = "lock-screen",
1400         [SESSION_BACKGROUND] = "background"
1401 };
1402
1403 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1404
1405 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1406         [KILL_LEADER] = "leader",
1407         [KILL_ALL] = "all"
1408 };
1409
1410 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);