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