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