chiark / gitweb /
28784a86759041c0276af423c26f786f35d21794
[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         return r;
772 }
773
774 int session_finalize(Session *s) {
775         SessionDevice *sd;
776
777         assert(s);
778
779         if (!s->user)
780                 return -ESTALE;
781
782         if (s->started)
783                 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
784                            "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
785                            "SESSION_ID=%s", s->id,
786                            "USER_ID=%s", s->user->name,
787                            "LEADER="PID_FMT, s->leader,
788                            LOG_MESSAGE("Removed session %s.", s->id),
789                            NULL);
790
791         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
792
793         if (s->seat)
794                 seat_evict_position(s->seat, s);
795
796         /* Kill session devices */
797         while ((sd = hashmap_first(s->devices)))
798                 session_device_free(sd);
799
800         (void) unlink(s->state_file);
801         session_add_to_gc_queue(s);
802         user_add_to_gc_queue(s->user);
803
804         if (s->started) {
805                 session_send_signal(s, false);
806                 s->started = false;
807         }
808
809         if (s->seat) {
810                 if (s->seat->active == s)
811                         seat_set_active(s->seat, NULL);
812
813                 seat_save(s->seat);
814         }
815
816         user_save(s->user);
817         user_send_changed(s->user, "Display", NULL);
818
819         return 0;
820 }
821
822 #if 0 /// UNNEEDED by elogind
823 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
824         Session *s = userdata;
825
826         assert(es);
827         assert(s);
828
829         session_stop(s, false);
830         return 0;
831 }
832 #endif // 0
833
834 int session_release(Session *s) {
835         assert(s);
836
837         if (!s->started || s->stopping)
838                 return 0;
839
840         if (s->timer_event_source)
841                 return 0;
842
843 #if 0 /// UNNEEDED by elogind
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 #else
850         /* In systemd, session release is triggered by user jobs
851            dying.  In elogind we don't have that so go ahead and stop
852            now.  */
853         return session_stop(s, false);
854 #endif // 0
855 }
856
857 bool session_is_active(Session *s) {
858         assert(s);
859
860         if (!s->seat)
861                 return true;
862
863         return s->seat->active == s;
864 }
865
866 static int get_tty_atime(const char *tty, usec_t *atime) {
867         _cleanup_free_ char *p = NULL;
868         struct stat st;
869
870         assert(tty);
871         assert(atime);
872
873         if (!path_is_absolute(tty)) {
874                 p = strappend("/dev/", tty);
875                 if (!p)
876                         return -ENOMEM;
877
878                 tty = p;
879         } else if (!path_startswith(tty, "/dev/"))
880                 return -ENOENT;
881
882         if (lstat(tty, &st) < 0)
883                 return -errno;
884
885         *atime = timespec_load(&st.st_atim);
886         return 0;
887 }
888
889 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
890         _cleanup_free_ char *p = NULL;
891         int r;
892
893         assert(pid > 0);
894         assert(atime);
895
896         r = get_ctty(pid, NULL, &p);
897         if (r < 0)
898                 return r;
899
900         return get_tty_atime(p, atime);
901 }
902
903 int session_get_idle_hint(Session *s, dual_timestamp *t) {
904         usec_t atime = 0, n;
905         int r;
906
907         assert(s);
908
909         /* Explicit idle hint is set */
910         if (s->idle_hint) {
911                 if (t)
912                         *t = s->idle_hint_timestamp;
913
914                 return s->idle_hint;
915         }
916
917         /* Graphical sessions should really implement a real
918          * idle hint logic */
919         if (SESSION_TYPE_IS_GRAPHICAL(s->type))
920                 goto dont_know;
921
922         /* For sessions with an explicitly configured tty, let's check
923          * its atime */
924         if (s->tty) {
925                 r = get_tty_atime(s->tty, &atime);
926                 if (r >= 0)
927                         goto found_atime;
928         }
929
930         /* For sessions with a leader but no explicitly configured
931          * tty, let's check the controlling tty of the leader */
932         if (s->leader > 0) {
933                 r = get_process_ctty_atime(s->leader, &atime);
934                 if (r >= 0)
935                         goto found_atime;
936         }
937
938 dont_know:
939         if (t)
940                 *t = s->idle_hint_timestamp;
941
942         return 0;
943
944 found_atime:
945         if (t)
946                 dual_timestamp_from_realtime(t, atime);
947
948         n = now(CLOCK_REALTIME);
949
950         if (s->manager->idle_action_usec <= 0)
951                 return 0;
952
953         return atime + s->manager->idle_action_usec <= n;
954 }
955
956 void session_set_idle_hint(Session *s, bool b) {
957         assert(s);
958
959         if (s->idle_hint == b)
960                 return;
961
962         s->idle_hint = b;
963         dual_timestamp_get(&s->idle_hint_timestamp);
964
965         session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
966
967         if (s->seat)
968                 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
969
970         user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
971         manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
972 }
973
974 int session_get_locked_hint(Session *s) {
975         assert(s);
976
977         return s->locked_hint;
978 }
979
980 void session_set_locked_hint(Session *s, bool b) {
981         assert(s);
982
983         if (s->locked_hint == b)
984                 return;
985
986         s->locked_hint = b;
987
988         session_send_changed(s, "LockedHint", NULL);
989 }
990
991 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
992         Session *s = userdata;
993
994         assert(s);
995         assert(s->fifo_fd == fd);
996
997         /* EOF on the FIFO means the session died abnormally. */
998
999         session_remove_fifo(s);
1000         session_stop(s, false);
1001
1002         return 1;
1003 }
1004
1005 int session_create_fifo(Session *s) {
1006         int r;
1007
1008         assert(s);
1009
1010         /* Create FIFO */
1011         if (!s->fifo_path) {
1012                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
1013                 if (r < 0)
1014                         return r;
1015
1016                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
1017                         return -ENOMEM;
1018
1019                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
1020                         return -errno;
1021         }
1022
1023         /* Open reading side */
1024         if (s->fifo_fd < 0) {
1025                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
1026                 if (s->fifo_fd < 0)
1027                         return -errno;
1028
1029         }
1030
1031         if (!s->fifo_event_source) {
1032                 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
1033                 if (r < 0)
1034                         return r;
1035
1036                 /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
1037                  * sessions). */
1038                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
1039                 if (r < 0)
1040                         return r;
1041         }
1042
1043         /* Open writing side */
1044         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
1045         if (r < 0)
1046                 return -errno;
1047
1048         return r;
1049 }
1050
1051 static void session_remove_fifo(Session *s) {
1052         assert(s);
1053
1054         s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
1055         s->fifo_fd = safe_close(s->fifo_fd);
1056
1057         if (s->fifo_path) {
1058                 unlink(s->fifo_path);
1059                 s->fifo_path = mfree(s->fifo_path);
1060         }
1061 }
1062
1063 bool session_check_gc(Session *s, bool drop_not_started) {
1064         assert(s);
1065
1066         if (drop_not_started && !s->started)
1067                 return false;
1068
1069         if (!s->user)
1070                 return false;
1071
1072         if (s->fifo_fd >= 0) {
1073                 if (pipe_eof(s->fifo_fd) <= 0)
1074                         return true;
1075         }
1076
1077 #if 0 /// elogind supports neither scopes nor jobs
1078         if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
1079                 return true;
1080
1081         if (s->scope && manager_unit_is_active(s->manager, s->scope))
1082                 return true;
1083 #endif // 0
1084
1085         return false;
1086 }
1087
1088 void session_add_to_gc_queue(Session *s) {
1089         assert(s);
1090
1091         if (s->in_gc_queue)
1092                 return;
1093
1094         LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
1095         s->in_gc_queue = true;
1096 }
1097
1098 SessionState session_get_state(Session *s) {
1099         assert(s);
1100
1101         /* always check closing first */
1102         if (s->stopping || s->timer_event_source)
1103                 return SESSION_CLOSING;
1104
1105 #if 0 /// elogind does not support systemd scope_jobs
1106         if (s->scope_job || s->fifo_fd < 0)
1107 #else
1108         if (s->fifo_fd < 0)
1109 #endif // 0
1110                 return SESSION_OPENING;
1111
1112         if (session_is_active(s))
1113                 return SESSION_ACTIVE;
1114
1115         return SESSION_ONLINE;
1116 }
1117
1118 int session_kill(Session *s, KillWho who, int signo) {
1119         assert(s);
1120
1121 #if 0 /// Without direct cgroup support, elogind can not kill sessions
1122         if (!s->scope)
1123                 return -ESRCH;
1124
1125         return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
1126 #else
1127         if (who == KILL_LEADER) {
1128                 if (s->leader <= 0)
1129                         return -ESRCH;
1130
1131                 /* FIXME: verify that leader is in cgroup?  */
1132
1133                 if (kill(s->leader, signo) < 0) {
1134                         return log_error_errno(errno, "Failed to kill process leader %d for session %s: %m", s->leader, s->id);
1135                 }
1136                 return 0;
1137         } else
1138                 return cg_kill_recursive (SYSTEMD_CGROUP_CONTROLLER, s->id, signo,
1139                                           CGROUP_IGNORE_SELF | CGROUP_REMOVE,
1140                                           NULL, NULL, NULL);
1141 #endif // 0
1142 }
1143
1144 static int session_open_vt(Session *s) {
1145         char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
1146
1147         if (s->vtnr < 1)
1148                 return -ENODEV;
1149
1150         if (s->vtfd >= 0)
1151                 return s->vtfd;
1152
1153         sprintf(path, "/dev/tty%u", s->vtnr);
1154         s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
1155         if (s->vtfd < 0)
1156                 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
1157
1158         return s->vtfd;
1159 }
1160
1161 int session_prepare_vt(Session *s) {
1162         int vt, r;
1163         struct vt_mode mode = { 0 };
1164
1165         if (s->vtnr < 1)
1166                 return 0;
1167
1168         vt = session_open_vt(s);
1169         if (vt < 0)
1170                 return vt;
1171
1172         r = fchown(vt, s->user->uid, -1);
1173         if (r < 0) {
1174                 r = log_error_errno(errno,
1175                                     "Cannot change owner of /dev/tty%u: %m",
1176                                     s->vtnr);
1177                 goto error;
1178         }
1179
1180         r = ioctl(vt, KDSKBMODE, K_OFF);
1181         if (r < 0) {
1182                 r = log_error_errno(errno,
1183                                     "Cannot set K_OFF on /dev/tty%u: %m",
1184                                     s->vtnr);
1185                 goto error;
1186         }
1187
1188         r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1189         if (r < 0) {
1190                 r = log_error_errno(errno,
1191                                     "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1192                                     s->vtnr);
1193                 goto error;
1194         }
1195
1196         /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1197          * So we need a dummy handler here which just acknowledges *all* VT
1198          * switch requests. */
1199         mode.mode = VT_PROCESS;
1200         mode.relsig = SIGRTMIN;
1201         mode.acqsig = SIGRTMIN + 1;
1202         r = ioctl(vt, VT_SETMODE, &mode);
1203         if (r < 0) {
1204                 r = log_error_errno(errno,
1205                                     "Cannot set VT_PROCESS on /dev/tty%u: %m",
1206                                     s->vtnr);
1207                 goto error;
1208         }
1209
1210         return 0;
1211
1212 error:
1213         session_restore_vt(s);
1214         return r;
1215 }
1216
1217 void session_restore_vt(Session *s) {
1218
1219         static const struct vt_mode mode = {
1220                 .mode = VT_AUTO,
1221         };
1222
1223         _cleanup_free_ char *utf8 = NULL;
1224         int vt, kb, old_fd;
1225
1226         /* We need to get a fresh handle to the virtual terminal,
1227          * since the old file-descriptor is potentially in a hung-up
1228          * state after the controlling process exited; we do a
1229          * little dance to avoid having the terminal be available
1230          * for reuse before we've cleaned it up.
1231          */
1232         old_fd = s->vtfd;
1233         s->vtfd = -1;
1234
1235         vt = session_open_vt(s);
1236         safe_close(old_fd);
1237
1238         if (vt < 0)
1239                 return;
1240
1241         (void) ioctl(vt, KDSETMODE, KD_TEXT);
1242
1243         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1244                 kb = K_UNICODE;
1245         else
1246                 kb = K_XLATE;
1247
1248         (void) ioctl(vt, KDSKBMODE, kb);
1249
1250         (void) ioctl(vt, VT_SETMODE, &mode);
1251         (void) fchown(vt, 0, (gid_t) -1);
1252
1253         s->vtfd = safe_close(s->vtfd);
1254 }
1255
1256 void session_leave_vt(Session *s) {
1257         int r;
1258
1259         assert(s);
1260
1261         /* This is called whenever we get a VT-switch signal from the kernel.
1262          * We acknowledge all of them unconditionally. Note that session are
1263          * free to overwrite those handlers and we only register them for
1264          * sessions with controllers. Legacy sessions are not affected.
1265          * However, if we switch from a non-legacy to a legacy session, we must
1266          * make sure to pause all device before acknowledging the switch. We
1267          * process the real switch only after we are notified via sysfs, so the
1268          * legacy session might have already started using the devices. If we
1269          * don't pause the devices before the switch, we might confuse the
1270          * session we switch to. */
1271
1272         if (s->vtfd < 0)
1273                 return;
1274
1275         session_device_pause_all(s);
1276         r = ioctl(s->vtfd, VT_RELDISP, 1);
1277         if (r < 0)
1278                 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
1279 }
1280
1281 bool session_is_controller(Session *s, const char *sender) {
1282         assert(s);
1283
1284         return streq_ptr(s->controller, sender);
1285 }
1286
1287 static void session_release_controller(Session *s, bool notify) {
1288         _cleanup_free_ char *name = NULL;
1289         SessionDevice *sd;
1290
1291         if (!s->controller)
1292                 return;
1293
1294         name = s->controller;
1295
1296         /* By resetting the controller before releasing the devices, we won't
1297          * send notification signals. This avoids sending useless notifications
1298          * if the controller is released on disconnects. */
1299         if (!notify)
1300                 s->controller = NULL;
1301
1302         while ((sd = hashmap_first(s->devices)))
1303                 session_device_free(sd);
1304
1305         s->controller = NULL;
1306         s->track = sd_bus_track_unref(s->track);
1307 }
1308
1309 static int on_bus_track(sd_bus_track *track, void *userdata) {
1310         Session *s = userdata;
1311
1312         assert(track);
1313         assert(s);
1314
1315         session_drop_controller(s);
1316
1317         return 0;
1318 }
1319
1320 int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
1321         _cleanup_free_ char *name = NULL;
1322         int r;
1323
1324         assert(s);
1325         assert(sender);
1326
1327         if (session_is_controller(s, sender))
1328                 return 0;
1329         if (s->controller && !force)
1330                 return -EBUSY;
1331
1332         name = strdup(sender);
1333         if (!name)
1334                 return -ENOMEM;
1335
1336         s->track = sd_bus_track_unref(s->track);
1337         r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1338         if (r < 0)
1339                 return r;
1340
1341         r = sd_bus_track_add_name(s->track, name);
1342         if (r < 0)
1343                 return r;
1344
1345         /* When setting a session controller, we forcibly mute the VT and set
1346          * it into graphics-mode. Applications can override that by changing
1347          * VT state after calling TakeControl(). However, this serves as a good
1348          * default and well-behaving controllers can now ignore VTs entirely.
1349          * Note that we reset the VT on ReleaseControl() and if the controller
1350          * exits.
1351          * If logind crashes/restarts, we restore the controller during restart
1352          * (without preparing the VT since the controller has probably overridden
1353          * VT state by now) or reset the VT in case it crashed/exited, too. */
1354         if (prepare) {
1355                 r = session_prepare_vt(s);
1356                 if (r < 0) {
1357                         s->track = sd_bus_track_unref(s->track);
1358                         return r;
1359                 }
1360         }
1361
1362         session_release_controller(s, true);
1363         s->controller = name;
1364         name = NULL;
1365         session_save(s);
1366
1367         return 0;
1368 }
1369
1370 void session_drop_controller(Session *s) {
1371         assert(s);
1372
1373         if (!s->controller)
1374                 return;
1375
1376         s->track = sd_bus_track_unref(s->track);
1377         session_release_controller(s, false);
1378         session_save(s);
1379         session_restore_vt(s);
1380 }
1381
1382 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1383         [SESSION_OPENING] = "opening",
1384         [SESSION_ONLINE] = "online",
1385         [SESSION_ACTIVE] = "active",
1386         [SESSION_CLOSING] = "closing"
1387 };
1388
1389 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1390
1391 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1392         [SESSION_UNSPECIFIED] = "unspecified",
1393         [SESSION_TTY] = "tty",
1394         [SESSION_X11] = "x11",
1395         [SESSION_WAYLAND] = "wayland",
1396         [SESSION_MIR] = "mir",
1397         [SESSION_WEB] = "web",
1398 };
1399
1400 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1401
1402 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1403         [SESSION_USER] = "user",
1404         [SESSION_GREETER] = "greeter",
1405         [SESSION_LOCK_SCREEN] = "lock-screen",
1406         [SESSION_BACKGROUND] = "background"
1407 };
1408
1409 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1410
1411 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1412         [KILL_LEADER] = "leader",
1413         [KILL_ALL] = "all"
1414 };
1415
1416 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);