]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
sd-journal: fix build with older glibc
[thirdparty/systemd.git] / src / login / logind-session.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
20263082
LP
2
3#include <errno.h>
90a18413 4#include <fcntl.h>
90a18413 5#include <linux/kd.h>
4f5dd394 6#include <linux/vt.h>
90a18413 7#include <signal.h>
90a18413 8#include <sys/ioctl.h>
ca78ad1d 9#include <sys/stat.h>
20263082
LP
10#include <unistd.h>
11
cc377381 12#include "sd-messages.h"
4f5dd394 13
b5efdb8a 14#include "alloc-util.h"
430f0182 15#include "audit-util.h"
cc377381 16#include "bus-error.h"
4f5dd394 17#include "bus-util.h"
7176f06c 18#include "devnum-util.h"
686d13b9 19#include "env-file.h"
4f5dd394 20#include "escape.h"
3ffd4af2 21#include "fd-util.h"
4f5dd394 22#include "fileio.h"
f97b34a6 23#include "format-util.h"
c004493c 24#include "io-util.h"
6ecda0fb
LP
25#include "logind-dbus.h"
26#include "logind-seat-dbus.h"
27#include "logind-session-dbus.h"
3ffd4af2 28#include "logind-session.h"
6ecda0fb 29#include "logind-user-dbus.h"
35cd0ba5 30#include "mkdir-label.h"
6bedfcbb 31#include "parse-util.h"
4f5dd394 32#include "path-util.h"
8c29a457 33#include "process-util.h"
d68c645b 34#include "serialize.h"
8b43440b 35#include "string-table.h"
25a1ab4e 36#include "strv.h"
288a74cc 37#include "terminal-util.h"
e4de7287 38#include "tmpfile-util.h"
278e815b 39#include "uid-alloc-range.h"
b1d4f8e1 40#include "user-util.h"
20263082 41
5f41d1f1
LP
42#define RELEASE_USEC (20*USEC_PER_SEC)
43
44static void session_remove_fifo(Session *s);
0212126c 45static void session_restore_vt(Session *s);
5f41d1f1 46
8c29a457
LP
47int session_new(Session **ret, Manager *m, const char *id) {
48 _cleanup_(session_freep) Session *s = NULL;
49 int r;
20263082 50
8c29a457 51 assert(ret);
20263082
LP
52 assert(m);
53 assert(id);
54
8c29a457
LP
55 if (!session_id_valid(id))
56 return -EINVAL;
57
58 s = new(Session, 1);
20263082 59 if (!s)
8c29a457
LP
60 return -ENOMEM;
61
62 *s = (Session) {
63 .manager = m,
254d1313
ZJS
64 .fifo_fd = -EBADF,
65 .vtfd = -EBADF,
8c29a457 66 .audit_id = AUDIT_SESSION_INVALID,
3d0ef5c7 67 .tty_validity = _TTY_VALIDITY_INVALID,
8c29a457 68 };
20263082 69
b910cc72 70 s->state_file = path_join("/run/systemd/sessions", id);
6b430fdb 71 if (!s->state_file)
8c29a457 72 return -ENOMEM;
118ecf32 73
2b6bf07d 74 s->id = basename(s->state_file);
20263082 75
8c29a457
LP
76 s->devices = hashmap_new(&devt_hash_ops);
77 if (!s->devices)
78 return -ENOMEM;
20263082 79
8c29a457
LP
80 r = hashmap_put(m->sessions, s->id, s);
81 if (r < 0)
82 return r;
20263082 83
8c29a457
LP
84 *ret = TAKE_PTR(s);
85 return 0;
20263082
LP
86}
87
8c29a457 88Session* session_free(Session *s) {
118ecf32
DH
89 SessionDevice *sd;
90
8c29a457
LP
91 if (!s)
92 return NULL;
20263082 93
14c3baca 94 if (s->in_gc_queue)
71fda00f 95 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
14c3baca 96
5f41d1f1
LP
97 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
98
ae5e06bd
DH
99 session_drop_controller(s);
100
118ecf32
DH
101 while ((sd = hashmap_first(s->devices)))
102 session_device_free(sd);
103
104 hashmap_free(s->devices);
105
20263082 106 if (s->user) {
71fda00f 107 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
20263082
LP
108
109 if (s->user->display == s)
110 s->user->display = NULL;
9afe9efb
LP
111
112 user_update_last_session_timer(s->user);
20263082
LP
113 }
114
9418f147
LP
115 if (s->seat) {
116 if (s->seat->active == s)
117 s->seat->active = NULL;
d7bd01b5
DH
118 if (s->seat->pending_switch == s)
119 s->seat->pending_switch = NULL;
9418f147 120
49e6fdbf 121 seat_evict_position(s->seat, s);
71fda00f 122 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
9418f147 123 }
20263082 124
fb6becb4
LP
125 if (s->scope) {
126 hashmap_remove(s->manager->session_units, s->scope);
127 free(s->scope);
128 }
129
238794b1
LP
130 if (pid_is_valid(s->leader))
131 (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
132
fb6becb4 133 free(s->scope_job);
1713813d 134
cc377381 135 sd_bus_message_unref(s->create_message);
20263082
LP
136
137 free(s->tty);
138 free(s->display);
139 free(s->remote_host);
3f49d45a 140 free(s->remote_user);
98a28fef 141 free(s->service);
a4cd87e9 142 free(s->desktop);
20263082
LP
143
144 hashmap_remove(s->manager->sessions, s->id);
98a28fef 145
c20b8dad
LP
146 sd_event_source_unref(s->fifo_event_source);
147 safe_close(s->fifo_fd);
148
149 /* Note that we remove neither the state file nor the fifo path here, since we want both to survive
150 * daemon restarts */
d2f92cdf 151 free(s->state_file);
c20b8dad 152 free(s->fifo_path);
8c29a457 153
82325af3
MS
154 sd_event_source_unref(s->stop_on_idle_event_source);
155
8c29a457 156 return mfree(s);
20263082
LP
157}
158
9444b1f2
LP
159void session_set_user(Session *s, User *u) {
160 assert(s);
161 assert(!s->user);
162
163 s->user = u;
71fda00f 164 LIST_PREPEND(sessions_by_user, u->sessions, s);
9afe9efb
LP
165
166 user_update_last_session_timer(u);
9444b1f2
LP
167}
168
238794b1
LP
169int session_set_leader(Session *s, pid_t pid) {
170 int r;
171
172 assert(s);
173
174 if (!pid_is_valid(pid))
175 return -EINVAL;
176
177 if (s->leader == pid)
178 return 0;
179
180 r = hashmap_put(s->manager->sessions_by_leader, PID_TO_PTR(pid), s);
181 if (r < 0)
182 return r;
183
184 if (pid_is_valid(s->leader))
185 (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
186
187 s->leader = pid;
188 (void) audit_session_from_pid(pid, &s->audit_id);
189
190 return 1;
191}
192
aed24c4c
FB
193static void session_save_devices(Session *s, FILE *f) {
194 SessionDevice *sd;
aed24c4c
FB
195
196 if (!hashmap_isempty(s->devices)) {
197 fprintf(f, "DEVICES=");
90e74a66 198 HASHMAP_FOREACH(sd, s->devices)
aed24c4c
FB
199 fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
200 fprintf(f, "\n");
201 }
202}
203
20263082 204int session_save(Session *s) {
507f22bd 205 _cleanup_free_ char *temp_path = NULL;
cc377381 206 _cleanup_fclose_ FILE *f = NULL;
6d95e7d9 207 int r;
20263082
LP
208
209 assert(s);
210
9444b1f2
LP
211 if (!s->user)
212 return -ESTALE;
213
accaeded
LP
214 if (!s->started)
215 return 0;
216
37c1d5e9 217 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
20263082 218 if (r < 0)
dacd6cee 219 goto fail;
20263082 220
14c3baca
LP
221 r = fopen_temporary(s->state_file, &f, &temp_path);
222 if (r < 0)
dacd6cee 223 goto fail;
20263082 224
44176400 225 (void) fchmod(fileno(f), 0644);
14c3baca 226
20263082
LP
227 fprintf(f,
228 "# This is private data. Do not parse.\n"
90b2de37 229 "UID="UID_FMT"\n"
20263082
LP
230 "USER=%s\n"
231 "ACTIVE=%i\n"
1c8280fd 232 "IS_DISPLAY=%i\n"
0604381b 233 "STATE=%s\n"
fb6becb4 234 "REMOTE=%i\n",
22c902fa
LP
235 s->user->user_record->uid,
236 s->user->user_record->user_name,
20263082 237 session_is_active(s),
1c8280fd 238 s->user->display == s,
0604381b 239 session_state_to_string(session_get_state(s)),
fb6becb4 240 s->remote);
20263082 241
a91e4e53 242 if (s->type >= 0)
507f22bd 243 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
a91e4e53 244
db72aea4
CH
245 if (s->original_type >= 0)
246 fprintf(f, "ORIGINAL_TYPE=%s\n", session_type_to_string(s->original_type));
247
55efac6c 248 if (s->class >= 0)
507f22bd 249 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
55efac6c 250
fb6becb4
LP
251 if (s->scope)
252 fprintf(f, "SCOPE=%s\n", s->scope);
fb6becb4
LP
253 if (s->scope_job)
254 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
20263082 255
932e3ee7 256 if (s->fifo_path)
507f22bd 257 fprintf(f, "FIFO=%s\n", s->fifo_path);
932e3ee7 258
20263082 259 if (s->seat)
507f22bd 260 fprintf(f, "SEAT=%s\n", s->seat->id);
20263082
LP
261
262 if (s->tty)
507f22bd 263 fprintf(f, "TTY=%s\n", s->tty);
20263082 264
3d0ef5c7
LP
265 if (s->tty_validity >= 0)
266 fprintf(f, "TTY_VALIDITY=%s\n", tty_validity_to_string(s->tty_validity));
267
20263082 268 if (s->display)
507f22bd 269 fprintf(f, "DISPLAY=%s\n", s->display);
20263082 270
558c6490 271 if (s->remote_host) {
c2b2df60 272 _cleanup_free_ char *escaped = NULL;
558c6490
LP
273
274 escaped = cescape(s->remote_host);
275 if (!escaped) {
276 r = -ENOMEM;
dacd6cee 277 goto fail;
558c6490
LP
278 }
279
280 fprintf(f, "REMOTE_HOST=%s\n", escaped);
281 }
282
283 if (s->remote_user) {
c2b2df60 284 _cleanup_free_ char *escaped = NULL;
558c6490
LP
285
286 escaped = cescape(s->remote_user);
287 if (!escaped) {
288 r = -ENOMEM;
dacd6cee 289 goto fail;
558c6490
LP
290 }
291
292 fprintf(f, "REMOTE_USER=%s\n", escaped);
293 }
294
295 if (s->service) {
c2b2df60 296 _cleanup_free_ char *escaped = NULL;
20263082 297
558c6490
LP
298 escaped = cescape(s->service);
299 if (!escaped) {
300 r = -ENOMEM;
dacd6cee 301 goto fail;
558c6490
LP
302 }
303
304 fprintf(f, "SERVICE=%s\n", escaped);
305 }
3f49d45a 306
558c6490 307 if (s->desktop) {
c2b2df60 308 _cleanup_free_ char *escaped = NULL;
98a28fef 309
558c6490
LP
310 escaped = cescape(s->desktop);
311 if (!escaped) {
312 r = -ENOMEM;
dacd6cee 313 goto fail;
558c6490
LP
314 }
315
316 fprintf(f, "DESKTOP=%s\n", escaped);
317 }
a4cd87e9 318
bf7825ae 319 if (s->seat && seat_has_vts(s->seat))
92bd5ff3 320 fprintf(f, "VTNR=%u\n", s->vtnr);
20263082 321
49e6fdbf 322 if (!s->vtnr)
e6494a07 323 fprintf(f, "POSITION=%u\n", s->position);
49e6fdbf 324
54191eb3 325 if (pid_is_valid(s->leader))
90b2de37 326 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
20263082 327
3a87a86e 328 if (audit_session_is_valid(s->audit_id))
507f22bd 329 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
20263082 330
9444b1f2
LP
331 if (dual_timestamp_is_set(&s->timestamp))
332 fprintf(f,
90b2de37
ZJS
333 "REALTIME="USEC_FMT"\n"
334 "MONOTONIC="USEC_FMT"\n",
335 s->timestamp.realtime,
336 s->timestamp.monotonic);
9444b1f2 337
aed24c4c 338 if (s->controller) {
6d33772f 339 fprintf(f, "CONTROLLER=%s\n", s->controller);
aed24c4c
FB
340 session_save_devices(s, f);
341 }
6d33772f 342
dacd6cee
LP
343 r = fflush_and_check(f);
344 if (r < 0)
345 goto fail;
14c3baca 346
dacd6cee 347 if (rename(temp_path, s->state_file) < 0) {
20263082 348 r = -errno;
dacd6cee 349 goto fail;
20263082
LP
350 }
351
dacd6cee
LP
352 return 0;
353
354fail:
355 (void) unlink(s->state_file);
14c3baca 356
dacd6cee
LP
357 if (temp_path)
358 (void) unlink(temp_path);
359
360 return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
20263082
LP
361}
362
aed24c4c 363static int session_load_devices(Session *s, const char *devices) {
aed24c4c
FB
364 int r = 0;
365
366 assert(s);
367
e5c09aad 368 for (const char *p = devices;;) {
aed24c4c
FB
369 _cleanup_free_ char *word = NULL;
370 SessionDevice *sd;
371 dev_t dev;
372 int k;
373
374 k = extract_first_word(&p, &word, NULL, 0);
375 if (k == 0)
376 break;
377 if (k < 0) {
378 r = k;
379 break;
380 }
381
7176f06c 382 k = parse_devnum(word, &dev);
aed24c4c
FB
383 if (k < 0) {
384 r = k;
385 continue;
386 }
387
388 /* The file descriptors for loaded devices will be reattached later. */
389 k = session_device_new(s, dev, false, &sd);
390 if (k < 0)
391 r = k;
392 }
393
394 if (r < 0)
395 log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
396
397 return r;
398}
dacd6cee 399
20263082 400int session_load(Session *s) {
9444b1f2 401 _cleanup_free_ char *remote = NULL,
a185c5aa 402 *seat = NULL,
3d0ef5c7 403 *tty_validity = NULL,
a185c5aa 404 *vtnr = NULL,
be94d954 405 *state = NULL,
e6494a07 406 *position = NULL,
a185c5aa 407 *leader = NULL,
55efac6c 408 *type = NULL,
db72aea4 409 *original_type = NULL,
9444b1f2
LP
410 *class = NULL,
411 *uid = NULL,
412 *realtime = NULL,
6d33772f 413 *monotonic = NULL,
aed24c4c
FB
414 *controller = NULL,
415 *active = NULL,
1c8280fd
LP
416 *devices = NULL,
417 *is_display = NULL;
a185c5aa
LP
418
419 int k, r;
420
20263082
LP
421 assert(s);
422
aa8fbc74 423 r = parse_env_file(NULL, s->state_file,
a185c5aa 424 "REMOTE", &remote,
fb6becb4
LP
425 "SCOPE", &s->scope,
426 "SCOPE_JOB", &s->scope_job,
932e3ee7 427 "FIFO", &s->fifo_path,
a185c5aa
LP
428 "SEAT", &seat,
429 "TTY", &s->tty,
3d0ef5c7 430 "TTY_VALIDITY", &tty_validity,
a185c5aa
LP
431 "DISPLAY", &s->display,
432 "REMOTE_HOST", &s->remote_host,
433 "REMOTE_USER", &s->remote_user,
98a28fef 434 "SERVICE", &s->service,
a4cd87e9 435 "DESKTOP", &s->desktop,
a185c5aa 436 "VTNR", &vtnr,
be94d954 437 "STATE", &state,
e6494a07 438 "POSITION", &position,
a185c5aa 439 "LEADER", &leader,
a91e4e53 440 "TYPE", &type,
db72aea4 441 "ORIGINAL_TYPE", &original_type,
55efac6c 442 "CLASS", &class,
9444b1f2
LP
443 "UID", &uid,
444 "REALTIME", &realtime,
445 "MONOTONIC", &monotonic,
6d33772f 446 "CONTROLLER", &controller,
aed24c4c
FB
447 "ACTIVE", &active,
448 "DEVICES", &devices,
13df9c39 449 "IS_DISPLAY", &is_display);
f647962d
MS
450 if (r < 0)
451 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
9444b1f2
LP
452
453 if (!s->user) {
454 uid_t u;
455 User *user;
456
baaa35ad
ZJS
457 if (!uid)
458 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
459 "UID not specified for session %s",
460 s->id);
9444b1f2
LP
461
462 r = parse_uid(uid, &u);
463 if (r < 0) {
464 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
465 return r;
466 }
467
8cb4ab00 468 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
baaa35ad
ZJS
469 if (!user)
470 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
471 "User of session %s not known.",
472 s->id);
9444b1f2
LP
473
474 session_set_user(s, user);
475 }
a185c5aa
LP
476
477 if (remote) {
478 k = parse_boolean(remote);
479 if (k >= 0)
480 s->remote = k;
481 }
482
c506027a
DH
483 if (vtnr)
484 safe_atou(vtnr, &s->vtnr);
485
9418f147 486 if (seat && !s->seat) {
a185c5aa
LP
487 Seat *o;
488
489 o = hashmap_get(s->manager->seats, seat);
490 if (o)
c506027a
DH
491 r = seat_attach_session(o, s);
492 if (!o || r < 0)
493 log_error("Cannot attach session %s to seat %s", s->id, seat);
a185c5aa
LP
494 }
495
c506027a
DH
496 if (!s->seat || !seat_has_vts(s->seat))
497 s->vtnr = 0;
a185c5aa 498
e6494a07 499 if (position && s->seat) {
14cb109d 500 unsigned npos;
49e6fdbf 501
e6494a07 502 safe_atou(position, &npos);
49e6fdbf
DH
503 seat_claim_position(s->seat, s, npos);
504 }
505
3d0ef5c7
LP
506 if (tty_validity) {
507 TTYValidity v;
508
509 v = tty_validity_from_string(tty_validity);
510 if (v < 0)
511 log_debug("Failed to parse TTY validity: %s", tty_validity);
512 else
513 s->tty_validity = v;
514 }
515
a185c5aa 516 if (leader) {
238794b1
LP
517 pid_t pid;
518
519 r = parse_pid(leader, &pid);
520 if (r < 0)
521 log_debug_errno(r, "Failed to parse leader PID of session: %s", leader);
522 else {
523 r = session_set_leader(s, pid);
524 if (r < 0)
525 log_warning_errno(r, "Failed to set session leader PID, ignoring: %m");
526 }
a185c5aa
LP
527 }
528
a91e4e53
LP
529 if (type) {
530 SessionType t;
531
532 t = session_type_from_string(type);
533 if (t >= 0)
534 s->type = t;
535 }
536
db72aea4
CH
537 if (original_type) {
538 SessionType ot;
539
540 ot = session_type_from_string(original_type);
541 if (ot >= 0)
542 s->original_type = ot;
543 } else
544 /* Pre-v246 compat: initialize original_type if not set in the state file */
545 s->original_type = s->type;
546
55efac6c
LP
547 if (class) {
548 SessionClass c;
549
550 c = session_class_from_string(class);
551 if (c >= 0)
552 s->class = c;
553 }
554
e5c09aad 555 if (streq_ptr(state, "closing"))
be94d954
MP
556 s->stopping = true;
557
b4f78aea
LP
558 if (s->fifo_path) {
559 int fd;
560
561 /* If we open an unopened pipe for reading we will not
562 get an EOF. to trigger an EOF we hence open it for
be94d954
MP
563 writing, but close it right away which then will
564 trigger the EOF. This will happen immediately if no
565 other process has the FIFO open for writing, i. e.
566 when the session died before logind (re)started. */
b4f78aea
LP
567
568 fd = session_create_fifo(s);
03e334a1 569 safe_close(fd);
b4f78aea
LP
570 }
571
b895a735 572 if (realtime)
d68c645b 573 (void) deserialize_usec(realtime, &s->timestamp.realtime);
b895a735 574 if (monotonic)
d68c645b 575 (void) deserialize_usec(monotonic, &s->timestamp.monotonic);
a185c5aa 576
aed24c4c
FB
577 if (active) {
578 k = parse_boolean(active);
579 if (k >= 0)
580 s->was_active = k;
581 }
582
1c8280fd
LP
583 if (is_display) {
584 /* Note that when enumerating users are loaded before sessions, hence the display session to use is
585 * something we have to store along with the session and not the user, as in that case we couldn't
586 * apply it at the time we load the user. */
587
588 k = parse_boolean(is_display);
589 if (k < 0)
590 log_warning_errno(k, "Failed to parse IS_DISPLAY session property: %m");
591 else if (k > 0)
592 s->user->display = s;
593 }
594
6d33772f 595 if (controller) {
aed24c4c 596 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) {
dc6284e9 597 session_set_controller(s, controller, false, false);
aed24c4c
FB
598 session_load_devices(s, devices);
599 } else
90a18413 600 session_restore_vt(s);
6d33772f
DH
601 }
602
a185c5aa 603 return r;
20263082
LP
604}
605
606int session_activate(Session *s) {
14cb109d 607 unsigned num_pending;
d7bd01b5 608
20263082 609 assert(s);
9444b1f2 610 assert(s->user);
20263082 611
20263082 612 if (!s->seat)
15411c0c 613 return -EOPNOTSUPP;
20263082
LP
614
615 if (s->seat->active == s)
616 return 0;
617
d7bd01b5
DH
618 /* on seats with VTs, we let VTs manage session-switching */
619 if (seat_has_vts(s->seat)) {
709d0587 620 if (s->vtnr == 0)
15411c0c 621 return -EOPNOTSUPP;
d7bd01b5
DH
622
623 return chvt(s->vtnr);
624 }
625
626 /* On seats without VTs, we implement session-switching in logind. We
627 * try to pause all session-devices and wait until the session
628 * controller acknowledged them. Once all devices are asleep, we simply
629 * switch the active session and be done.
630 * We save the session we want to switch to in seat->pending_switch and
631 * seat_complete_switch() will perform the final switch. */
632
633 s->seat->pending_switch = s;
634
635 /* if no devices are running, immediately perform the session switch */
636 num_pending = session_device_try_pause_all(s);
637 if (!num_pending)
638 seat_complete_switch(s->seat);
20263082 639
d7bd01b5 640 return 0;
20263082
LP
641}
642
25a1ab4e 643static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_error *error) {
98a28fef
LP
644 int r;
645
646 assert(s);
9444b1f2 647 assert(s->user);
98a28fef 648
fb6becb4 649 if (!s->scope) {
278e815b 650 _cleanup_strv_free_ char **after = NULL;
fb2367ed 651 _cleanup_free_ char *scope = NULL;
90558f31 652 const char *description;
405e0255 653
25a1ab4e
LP
654 s->scope_job = mfree(s->scope_job);
655
605405c6 656 scope = strjoin("session-", s->id, ".scope");
d0af76e6 657 if (!scope)
ae018d9b
LP
658 return log_oom();
659
0a59216c 660 description = strjoina("Session ", s->id, " of User ", s->user->user_record->user_name);
90558f31 661
278e815b
FB
662 /* We usually want to order session scopes after systemd-user-sessions.service since the
663 * latter unit is used as login session barrier for unprivileged users. However the barrier
664 * doesn't apply for root as sysadmin should always be able to log in (and without waiting
665 * for any timeout to expire) in case something goes wrong during the boot process. Since
666 * ordering after systemd-user-sessions.service and the user instance is optional we make use
667 * of STRV_IGNORE with strv_new() to skip these order constraints when needed. */
668 after = strv_new("systemd-logind.service",
669 s->user->runtime_dir_service,
670 !uid_is_system(s->user->user_record->uid) ? "systemd-user-sessions.service" : STRV_IGNORE,
513cf7da 671 s->user->service);
278e815b
FB
672 if (!after)
673 return log_oom();
674
90558f31
LP
675 r = manager_start_scope(
676 s->manager,
677 scope,
678 s->leader,
679 s->user->slice,
680 description,
124d7cb2
ZJS
681 /* These two have StopWhenUnneeded= set, hence add a dep towards them */
682 STRV_MAKE(s->user->runtime_dir_service,
513cf7da 683 s->user->service),
278e815b 684 after,
22c902fa 685 user_record_home_directory(s->user->user_record),
22f93314 686 properties,
25a1ab4e
LP
687 error,
688 &s->scope_job);
fb2367ed 689 if (r < 0)
124d7cb2
ZJS
690 return log_error_errno(r, "Failed to start session scope %s: %s",
691 scope, bus_error_message(error, r));
fb2367ed
YW
692
693 s->scope = TAKE_PTR(scope);
20263082
LP
694 }
695
124d7cb2 696 (void) hashmap_put(s->manager->session_units, s->scope, s);
d0af76e6 697
20263082
LP
698 return 0;
699}
700
82325af3
MS
701static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, void *userdata) {
702 Session *s = userdata;
703 dual_timestamp ts;
704 int r, idle;
705
706 assert(s);
707
708 if (s->stopping)
709 return 0;
710
711 idle = session_get_idle_hint(s, &ts);
712 if (idle) {
6269ffe7 713 log_info("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->user_record->user_name);
82325af3
MS
714
715 return session_stop(s, /* force */ true);
716 }
717
ab7ae746
MS
718 r = sd_event_source_set_time(
719 source,
720 usec_add(dual_timestamp_is_set(&ts) ? ts.monotonic : now(CLOCK_MONOTONIC),
721 s->manager->stop_idle_session_usec));
82325af3
MS
722 if (r < 0)
723 return log_error_errno(r, "Failed to configure stop on idle session event source: %m");
724
725 r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
726 if (r < 0)
727 return log_error_errno(r, "Failed to enable stop on idle session event source: %m");
728
729 return 1;
730}
731
732static int session_setup_stop_on_idle_timer(Session *s) {
733 int r;
734
735 assert(s);
736
737 if (s->manager->stop_idle_session_usec == USEC_INFINITY)
738 return 0;
739
740 r = sd_event_add_time_relative(
741 s->manager->event,
742 &s->stop_on_idle_event_source,
743 CLOCK_MONOTONIC,
744 s->manager->stop_idle_session_usec,
745 0,
746 session_dispatch_stop_on_idle, s);
747 if (r < 0)
748 return log_error_errno(r, "Failed to add stop on idle session event source: %m");
749
750 return 0;
751}
752
25a1ab4e 753int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
20263082
LP
754 int r;
755
756 assert(s);
9444b1f2
LP
757
758 if (!s->user)
759 return -ESTALE;
20263082 760
25a1ab4e
LP
761 if (s->stopping)
762 return -EINVAL;
763
9418f147
LP
764 if (s->started)
765 return 0;
766
513cf7da 767 r = user_start(s->user);
ed18b08b
LP
768 if (r < 0)
769 return r;
770
25a1ab4e 771 r = session_start_scope(s, properties, error);
fb6becb4
LP
772 if (r < 0)
773 return r;
774
82325af3
MS
775 r = session_setup_stop_on_idle_timer(s);
776 if (r < 0)
777 return r;
778
d9eb81f9 779 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
2b044526 780 "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
877d54e9 781 "SESSION_ID=%s", s->id,
22c902fa 782 "USER_ID=%s", s->user->user_record->user_name,
de0671ee 783 "LEADER="PID_FMT, s->leader,
22c902fa 784 LOG_MESSAGE("New session %s of user %s.", s->id, s->user->user_record->user_name));
98a28fef 785
9444b1f2
LP
786 if (!dual_timestamp_is_set(&s->timestamp))
787 dual_timestamp_get(&s->timestamp);
14c3baca 788
e9816c48
LP
789 if (s->seat)
790 seat_read_active_vt(s->seat);
791
9418f147
LP
792 s->started = true;
793
952d3260
LP
794 user_elect_display(s->user);
795
5f41d1f1 796 /* Save data */
e9816c48 797 session_save(s);
7f7bb946 798 user_save(s->user);
5f41d1f1
LP
799 if (s->seat)
800 seat_save(s->seat);
e9816c48 801
5f41d1f1 802 /* Send signals */
da119395 803 session_send_signal(s, true);
7d049e30 804 user_send_changed(s->user, "Display", NULL);
40771cf5
LP
805
806 if (s->seat && s->seat->active == s)
807 seat_send_changed(s->seat, "ActiveSession", NULL);
9418f147 808
20263082
LP
809 return 0;
810}
811
9bb69af4 812static int session_stop_scope(Session *s, bool force) {
4afd3348 813 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
20263082 814 int r;
20263082
LP
815
816 assert(s);
817
fb6becb4
LP
818 if (!s->scope)
819 return 0;
9b221b63 820
756ed0e2 821 /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
629ff674 822 * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
756ed0e2
LP
823 * when killing any processes left after this point. */
824 r = manager_abandon_scope(s->manager, s->scope, &error);
25a1ab4e 825 if (r < 0) {
756ed0e2 826 log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r));
25a1ab4e
LP
827 sd_bus_error_free(&error);
828 }
829
830 s->scope_job = mfree(s->scope_job);
756ed0e2
LP
831
832 /* Optionally, let's kill everything that's left now. */
156a3637
LP
833 if (force ||
834 (s->user->user_record->kill_processes != 0 &&
835 (s->user->user_record->kill_processes > 0 ||
836 manager_shall_kill(s->manager, s->user->user_record->user_name)))) {
801a884d 837
1a42ce09 838 r = manager_stop_unit(s->manager, s->scope, force ? "replace" : "fail", &error, &s->scope_job);
25a1ab4e
LP
839 if (r < 0) {
840 if (force)
841 return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r));
20263082 842
25a1ab4e
LP
843 log_warning_errno(r, "Failed to stop session scope, ignoring: %s", bus_error_message(&error, r));
844 }
8150acb1 845 } else {
20263082 846
8150acb1
AJ
847 /* With no killing, this session is allowed to persist in "closing" state indefinitely.
848 * Therefore session stop and session removal may be two distinct events.
849 * Session stop is quite significant on its own, let's log it. */
850 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
851 "SESSION_ID=%s", s->id,
22c902fa 852 "USER_ID=%s", s->user->user_record->user_name,
8150acb1 853 "LEADER="PID_FMT, s->leader,
f4cf1d66 854 LOG_MESSAGE("Session %s logged out. Waiting for processes to exit.", s->id));
8150acb1
AJ
855 }
856
9b221b63 857 return 0;
20263082
LP
858}
859
9bb69af4 860int session_stop(Session *s, bool force) {
405e0255
LP
861 int r;
862
863 assert(s);
864
25a1ab4e
LP
865 /* This is called whenever we begin with tearing down a session record. It's called in four cases: explicit API
866 * request via the bus (either directly for the session object or for the seat or user object this session
867 * belongs to; 'force' is true), or due to automatic GC (i.e. scope vanished; 'force' is false), or because the
868 * session FIFO saw an EOF ('force' is false), or because the release timer hit ('force' is false). */
869
405e0255
LP
870 if (!s->user)
871 return -ESTALE;
25a1ab4e
LP
872 if (!s->started)
873 return 0;
874 if (s->stopping)
875 return 0;
405e0255 876
5f41d1f1
LP
877 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
878
10189fd6
DH
879 if (s->seat)
880 seat_evict_position(s->seat, s);
881
5f41d1f1
LP
882 /* We are going down, don't care about FIFOs anymore */
883 session_remove_fifo(s);
884
405e0255 885 /* Kill cgroup */
9bb69af4 886 r = session_stop_scope(s, force);
405e0255 887
5f41d1f1
LP
888 s->stopping = true;
889
952d3260
LP
890 user_elect_display(s->user);
891
405e0255 892 session_save(s);
cc377381 893 user_save(s->user);
405e0255
LP
894
895 return r;
896}
897
898int session_finalize(Session *s) {
118ecf32 899 SessionDevice *sd;
20263082
LP
900
901 assert(s);
902
9444b1f2
LP
903 if (!s->user)
904 return -ESTALE;
905
ed18b08b 906 if (s->started)
d9eb81f9 907 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
2b044526 908 "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
877d54e9 909 "SESSION_ID=%s", s->id,
22c902fa 910 "USER_ID=%s", s->user->user_record->user_name,
de0671ee 911 "LEADER="PID_FMT, s->leader,
a1230ff9 912 LOG_MESSAGE("Removed session %s.", s->id));
98a28fef 913
5f41d1f1
LP
914 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
915
10189fd6
DH
916 if (s->seat)
917 seat_evict_position(s->seat, s);
918
118ecf32
DH
919 /* Kill session devices */
920 while ((sd = hashmap_first(s->devices)))
921 session_device_free(sd);
922
491ac9f2 923 (void) unlink(s->state_file);
d2f92cdf 924 session_add_to_gc_queue(s);
ed18b08b 925 user_add_to_gc_queue(s->user);
14c3baca 926
405e0255 927 if (s->started) {
ed18b08b 928 session_send_signal(s, false);
405e0255
LP
929 s->started = false;
930 }
50fb9793 931
9418f147
LP
932 if (s->seat) {
933 if (s->seat->active == s)
934 seat_set_active(s->seat, NULL);
935
23bd3b62 936 seat_save(s->seat);
9418f147
LP
937 }
938
23bd3b62 939 user_save(s->user);
7d049e30 940 user_send_changed(s->user, "Display", NULL);
9418f147 941
491ac9f2 942 return 0;
20263082
LP
943}
944
5f41d1f1 945static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
99534007 946 Session *s = ASSERT_PTR(userdata);
5f41d1f1
LP
947
948 assert(es);
5f41d1f1 949
bda62573 950 session_stop(s, /* force = */ false);
5f41d1f1
LP
951 return 0;
952}
953
ad8780c9 954int session_release(Session *s) {
5f41d1f1
LP
955 assert(s);
956
957 if (!s->started || s->stopping)
ad8780c9
ZJS
958 return 0;
959
960 if (s->timer_event_source)
961 return 0;
962
39cf0351
LP
963 return sd_event_add_time_relative(
964 s->manager->event,
965 &s->timer_event_source,
966 CLOCK_MONOTONIC,
967 RELEASE_USEC, 0,
968 release_timeout_callback, s);
5f41d1f1
LP
969}
970
20263082
LP
971bool session_is_active(Session *s) {
972 assert(s);
973
974 if (!s->seat)
975 return true;
976
977 return s->seat->active == s;
978}
979
23406ce5
LP
980static int get_tty_atime(const char *tty, usec_t *atime) {
981 _cleanup_free_ char *p = NULL;
a185c5aa 982 struct stat st;
23406ce5
LP
983
984 assert(tty);
985 assert(atime);
986
987 if (!path_is_absolute(tty)) {
b910cc72 988 p = path_join("/dev", tty);
23406ce5
LP
989 if (!p)
990 return -ENOMEM;
991
992 tty = p;
993 } else if (!path_startswith(tty, "/dev/"))
994 return -ENOENT;
995
996 if (lstat(tty, &st) < 0)
997 return -errno;
998
999 *atime = timespec_load(&st.st_atim);
1000 return 0;
1001}
1002
1003static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
1004 _cleanup_free_ char *p = NULL;
1005 int r;
1006
1007 assert(pid > 0);
1008 assert(atime);
1009
1010 r = get_ctty(pid, NULL, &p);
1011 if (r < 0)
1012 return r;
1013
1014 return get_tty_atime(p, atime);
1015}
1016
1017int session_get_idle_hint(Session *s, dual_timestamp *t) {
82325af3 1018 usec_t atime = 0, dtime = 0;
23406ce5 1019 int r;
a185c5aa
LP
1020
1021 assert(s);
1022
be2bb14f
LP
1023 /* Graphical sessions have an explicit idle hint */
1024 if (SESSION_TYPE_IS_GRAPHICAL(s->type)) {
a185c5aa
LP
1025 if (t)
1026 *t = s->idle_hint_timestamp;
1027
1028 return s->idle_hint;
1029 }
1030
be2bb14f 1031 /* For sessions with an explicitly configured tty, let's check its atime */
23406ce5
LP
1032 if (s->tty) {
1033 r = get_tty_atime(s->tty, &atime);
1034 if (r >= 0)
1035 goto found_atime;
1036 }
a185c5aa 1037
be2bb14f
LP
1038 /* For sessions with a leader but no explicitly configured tty, let's check the controlling tty of
1039 * the leader */
238794b1 1040 if (pid_is_valid(s->leader)) {
23406ce5
LP
1041 r = get_process_ctty_atime(s->leader, &atime);
1042 if (r >= 0)
1043 goto found_atime;
a185c5aa
LP
1044 }
1045
a185c5aa 1046 if (t)
be2bb14f 1047 *t = DUAL_TIMESTAMP_NULL;
a185c5aa 1048
be2bb14f 1049 return false;
23406ce5
LP
1050
1051found_atime:
1052 if (t)
1053 dual_timestamp_from_realtime(t, atime);
1054
82325af3
MS
1055 if (s->manager->idle_action_usec > 0 && s->manager->stop_idle_session_usec != USEC_INFINITY)
1056 dtime = MIN(s->manager->idle_action_usec, s->manager->stop_idle_session_usec);
1057 else if (s->manager->idle_action_usec > 0)
1058 dtime = s->manager->idle_action_usec;
1059 else if (s->manager->stop_idle_session_usec != USEC_INFINITY)
1060 dtime = s->manager->stop_idle_session_usec;
1061 else
be2bb14f 1062 return false;
23406ce5 1063
82325af3 1064 return usec_add(atime, dtime) <= now(CLOCK_REALTIME);
a185c5aa
LP
1065}
1066
be2bb14f 1067int session_set_idle_hint(Session *s, bool b) {
bef422ae
LP
1068 assert(s);
1069
be2bb14f
LP
1070 if (!SESSION_TYPE_IS_GRAPHICAL(s->type))
1071 return -ENOTTY;
1072
bef422ae 1073 if (s->idle_hint == b)
be2bb14f 1074 return 0;
bef422ae
LP
1075
1076 s->idle_hint = b;
1077 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147 1078
cc377381 1079 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
9418f147
LP
1080
1081 if (s->seat)
cc377381
LP
1082 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1083
1084 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
1085 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
be2bb14f
LP
1086
1087 return 1;
cc377381
LP
1088}
1089
42d35e13
VT
1090int session_get_locked_hint(Session *s) {
1091 assert(s);
1092
1093 return s->locked_hint;
1094}
1095
1096void session_set_locked_hint(Session *s, bool b) {
1097 assert(s);
1098
1099 if (s->locked_hint == b)
1100 return;
1101
1102 s->locked_hint = b;
1103
1104 session_send_changed(s, "LockedHint", NULL);
1105}
1106
db72aea4
CH
1107void session_set_type(Session *s, SessionType t) {
1108 assert(s);
1109
1110 if (s->type == t)
1111 return;
1112
1113 s->type = t;
1114 session_save(s);
1115
1116 session_send_changed(s, "Type", NULL);
1117}
1118
4885d749
DT
1119int session_set_display(Session *s, const char *display) {
1120 int r;
1121
1122 assert(s);
1123 assert(display);
1124
4885d749 1125 r = free_and_strdup(&s->display, display);
e5c09aad 1126 if (r <= 0) /* 0 means the strings were equal */
4885d749
DT
1127 return r;
1128
1129 session_save(s);
1130
1131 session_send_changed(s, "Display", NULL);
1132
1133 return 1;
1134}
1135
cc377381 1136static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
99534007 1137 Session *s = ASSERT_PTR(userdata);
cc377381 1138
cc377381
LP
1139 assert(s->fifo_fd == fd);
1140
1141 /* EOF on the FIFO means the session died abnormally. */
1142
1143 session_remove_fifo(s);
bda62573 1144 session_stop(s, /* force = */ false);
cc377381
LP
1145
1146 return 1;
bef422ae
LP
1147}
1148
932e3ee7
LP
1149int session_create_fifo(Session *s) {
1150 int r;
1151
31b79c2b
LP
1152 assert(s);
1153
b4f78aea 1154 /* Create FIFO */
932e3ee7 1155 if (!s->fifo_path) {
37c1d5e9 1156 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
e6061ab2
LP
1157 if (r < 0)
1158 return r;
1159
d5ddc930
LP
1160 s->fifo_path = strjoin("/run/systemd/sessions/", s->id, ".ref");
1161 if (!s->fifo_path)
932e3ee7 1162 return -ENOMEM;
31b79c2b 1163
932e3ee7
LP
1164 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
1165 return -errno;
1166 }
31b79c2b 1167
932e3ee7 1168 /* Open reading side */
b4f78aea 1169 if (s->fifo_fd < 0) {
db4a47e9 1170 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
b4f78aea
LP
1171 if (s->fifo_fd < 0)
1172 return -errno;
cc377381
LP
1173 }
1174
1175 if (!s->fifo_event_source) {
151b9b96 1176 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
b4f78aea
LP
1177 if (r < 0)
1178 return r;
1179
6c75e317
ZJS
1180 /* Let's make sure we noticed dead sessions before we process new bus requests (which might
1181 * create new sessions). */
e11544a8 1182 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
cc377381
LP
1183 if (r < 0)
1184 return r;
b4f78aea 1185 }
932e3ee7
LP
1186
1187 /* Open writing side */
7c248223 1188 return RET_NERRNO(open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK));
932e3ee7
LP
1189}
1190
5f41d1f1 1191static void session_remove_fifo(Session *s) {
932e3ee7
LP
1192 assert(s);
1193
03e334a1
LP
1194 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
1195 s->fifo_fd = safe_close(s->fifo_fd);
932e3ee7
LP
1196
1197 if (s->fifo_path) {
75bbdf47 1198 (void) unlink(s->fifo_path);
a1e58e8e 1199 s->fifo_path = mfree(s->fifo_path);
932e3ee7 1200 }
31b79c2b
LP
1201}
1202
5c093a23 1203bool session_may_gc(Session *s, bool drop_not_started) {
bd26aee1
LP
1204 int r;
1205
20263082
LP
1206 assert(s);
1207
4a4b033f 1208 if (drop_not_started && !s->started)
5c093a23 1209 return true;
932e3ee7 1210
9444b1f2 1211 if (!s->user)
5c093a23 1212 return true;
9444b1f2 1213
932e3ee7 1214 if (s->fifo_fd >= 0) {
5f41d1f1 1215 if (pipe_eof(s->fifo_fd) <= 0)
5c093a23 1216 return false;
20263082
LP
1217 }
1218
bd26aee1
LP
1219 if (s->scope_job) {
1220 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1221
1222 r = manager_job_is_active(s->manager, s->scope_job, &error);
1223 if (r < 0)
1224 log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", s->scope_job, bus_error_message(&error, r));
1225 if (r != 0)
1226 return false;
1227 }
20263082 1228
bd26aee1
LP
1229 if (s->scope) {
1230 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1231
1232 r = manager_unit_is_active(s->manager, s->scope, &error);
1233 if (r < 0)
1234 log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", s->scope, bus_error_message(&error, r));
1235 if (r != 0)
1236 return false;
1237 }
20263082 1238
5c093a23 1239 return true;
20263082
LP
1240}
1241
14c3baca
LP
1242void session_add_to_gc_queue(Session *s) {
1243 assert(s);
1244
1245 if (s->in_gc_queue)
1246 return;
1247
71fda00f 1248 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
1249 s->in_gc_queue = true;
1250}
1251
0604381b
LP
1252SessionState session_get_state(Session *s) {
1253 assert(s);
1254
8fe63cd4 1255 /* always check closing first */
5f41d1f1
LP
1256 if (s->stopping || s->timer_event_source)
1257 return SESSION_CLOSING;
1258
8fe63cd4 1259 if (s->scope_job || s->fifo_fd < 0)
405e0255 1260 return SESSION_OPENING;
fb6becb4 1261
0604381b
LP
1262 if (session_is_active(s))
1263 return SESSION_ACTIVE;
1264
1265 return SESSION_ONLINE;
1266}
1267
de07ab16 1268int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
1269 assert(s);
1270
fb6becb4 1271 if (!s->scope)
de07ab16
LP
1272 return -ESRCH;
1273
fb6becb4 1274 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
1275}
1276
90a18413 1277static int session_open_vt(Session *s) {
5f41d1f1 1278 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
90a18413 1279
baccf3e4
OB
1280 if (s->vtnr < 1)
1281 return -ENODEV;
90a18413
DH
1282
1283 if (s->vtfd >= 0)
1284 return s->vtfd;
1285
92bd5ff3 1286 sprintf(path, "/dev/tty%u", s->vtnr);
22356953 1287 s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
4a62c710 1288 if (s->vtfd < 0)
709f6e46 1289 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
90a18413
DH
1290
1291 return s->vtfd;
1292}
1293
a03cdb17 1294static int session_prepare_vt(Session *s) {
90a18413 1295 int vt, r;
9fb2c8b8 1296 struct vt_mode mode = {};
90a18413 1297
baccf3e4
OB
1298 if (s->vtnr < 1)
1299 return 0;
1300
90a18413
DH
1301 vt = session_open_vt(s);
1302 if (vt < 0)
baccf3e4 1303 return vt;
90a18413 1304
22c902fa 1305 r = fchown(vt, s->user->user_record->uid, -1);
baccf3e4 1306 if (r < 0) {
94c156cd
LP
1307 r = log_error_errno(errno,
1308 "Cannot change owner of /dev/tty%u: %m",
1309 s->vtnr);
d6176c6c 1310 goto error;
baccf3e4 1311 }
d6176c6c 1312
90a18413 1313 r = ioctl(vt, KDSKBMODE, K_OFF);
baccf3e4 1314 if (r < 0) {
94c156cd
LP
1315 r = log_error_errno(errno,
1316 "Cannot set K_OFF on /dev/tty%u: %m",
1317 s->vtnr);
90a18413 1318 goto error;
baccf3e4 1319 }
90a18413
DH
1320
1321 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
baccf3e4 1322 if (r < 0) {
94c156cd
LP
1323 r = log_error_errno(errno,
1324 "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1325 s->vtnr);
90a18413 1326 goto error;
baccf3e4 1327 }
90a18413 1328
90a18413
DH
1329 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1330 * So we need a dummy handler here which just acknowledges *all* VT
1331 * switch requests. */
1332 mode.mode = VT_PROCESS;
92683ad2
DH
1333 mode.relsig = SIGRTMIN;
1334 mode.acqsig = SIGRTMIN + 1;
90a18413 1335 r = ioctl(vt, VT_SETMODE, &mode);
baccf3e4 1336 if (r < 0) {
94c156cd
LP
1337 r = log_error_errno(errno,
1338 "Cannot set VT_PROCESS on /dev/tty%u: %m",
1339 s->vtnr);
90a18413 1340 goto error;
baccf3e4 1341 }
90a18413 1342
baccf3e4 1343 return 0;
90a18413
DH
1344
1345error:
90a18413 1346 session_restore_vt(s);
baccf3e4 1347 return r;
90a18413
DH
1348}
1349
0212126c 1350static void session_restore_vt(Session *s) {
8246905a 1351 int r;
128df4cf 1352
8246905a
FB
1353 r = vt_restore(s->vtfd);
1354 if (r == -EIO) {
1355 int vt, old_fd;
ad96887a 1356
8246905a
FB
1357 /* It might happen if the controlling process exited before or while we were
1358 * restoring the VT as it would leave the old file-descriptor in a hung-up
1359 * state. In this case let's retry with a fresh handle to the virtual terminal. */
ad96887a 1360
8246905a
FB
1361 /* We do a little dance to avoid having the terminal be available
1362 * for reuse before we've cleaned it up. */
1363 old_fd = TAKE_FD(s->vtfd);
1364
1365 vt = session_open_vt(s);
1366 safe_close(old_fd);
1367
1368 if (vt >= 0)
1369 r = vt_restore(vt);
1370 }
ad96887a 1371
c0f34168
FB
1372 if (r < 0)
1373 log_warning_errno(r, "Failed to restore VT, ignoring: %m");
d6176c6c 1374
03e334a1 1375 s->vtfd = safe_close(s->vtfd);
90a18413
DH
1376}
1377
2ec3ff66 1378void session_leave_vt(Session *s) {
ce540a24
DH
1379 int r;
1380
2ec3ff66
DH
1381 assert(s);
1382
1383 /* This is called whenever we get a VT-switch signal from the kernel.
1384 * We acknowledge all of them unconditionally. Note that session are
1385 * free to overwrite those handlers and we only register them for
1386 * sessions with controllers. Legacy sessions are not affected.
1387 * However, if we switch from a non-legacy to a legacy session, we must
1388 * make sure to pause all device before acknowledging the switch. We
1389 * process the real switch only after we are notified via sysfs, so the
1390 * legacy session might have already started using the devices. If we
1391 * don't pause the devices before the switch, we might confuse the
1392 * session we switch to. */
1393
1394 if (s->vtfd < 0)
1395 return;
1396
1397 session_device_pause_all(s);
27dafac9 1398 r = vt_release(s->vtfd, false);
ce540a24 1399 if (r < 0)
27dafac9 1400 log_debug_errno(r, "Cannot release VT of session %s: %m", s->id);
2ec3ff66
DH
1401}
1402
cc377381 1403bool session_is_controller(Session *s, const char *sender) {
e5c09aad 1404 return streq_ptr(ASSERT_PTR(s)->controller, sender);
ae5e06bd
DH
1405}
1406
b12e5615 1407static void session_release_controller(Session *s, bool notify) {
d7ac0952 1408 _unused_ _cleanup_free_ char *name = NULL;
6d33772f
DH
1409 SessionDevice *sd;
1410
b12e5615
DH
1411 if (!s->controller)
1412 return;
6d33772f 1413
b12e5615 1414 name = s->controller;
90a18413 1415
6c75e317
ZJS
1416 /* By resetting the controller before releasing the devices, we won't send notification signals.
1417 * This avoids sending useless notifications if the controller is released on disconnects. */
b12e5615
DH
1418 if (!notify)
1419 s->controller = NULL;
6d33772f 1420
b12e5615
DH
1421 while ((sd = hashmap_first(s->devices)))
1422 session_device_free(sd);
1423
1424 s->controller = NULL;
3cde9e8f
DM
1425 s->track = sd_bus_track_unref(s->track);
1426}
1427
1428static int on_bus_track(sd_bus_track *track, void *userdata) {
99534007 1429 Session *s = ASSERT_PTR(userdata);
3cde9e8f
DM
1430
1431 assert(track);
3cde9e8f
DM
1432
1433 session_drop_controller(s);
1434
1435 return 0;
6d33772f
DH
1436}
1437
dc6284e9 1438int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
b12e5615 1439 _cleanup_free_ char *name = NULL;
ae5e06bd
DH
1440 int r;
1441
1442 assert(s);
1443 assert(sender);
1444
1445 if (session_is_controller(s, sender))
1446 return 0;
1447 if (s->controller && !force)
1448 return -EBUSY;
1449
b12e5615
DH
1450 name = strdup(sender);
1451 if (!name)
ae5e06bd
DH
1452 return -ENOMEM;
1453
3cde9e8f
DM
1454 s->track = sd_bus_track_unref(s->track);
1455 r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1456 if (r < 0)
1457 return r;
1458
1459 r = sd_bus_track_add_name(s->track, name);
1460 if (r < 0)
ae5e06bd 1461 return r;
ae5e06bd 1462
90a18413
DH
1463 /* When setting a session controller, we forcibly mute the VT and set
1464 * it into graphics-mode. Applications can override that by changing
1465 * VT state after calling TakeControl(). However, this serves as a good
1466 * default and well-behaving controllers can now ignore VTs entirely.
1467 * Note that we reset the VT on ReleaseControl() and if the controller
1468 * exits.
1469 * If logind crashes/restarts, we restore the controller during restart
dc6284e9
FB
1470 * (without preparing the VT since the controller has probably overridden
1471 * VT state by now) or reset the VT in case it crashed/exited, too. */
1472 if (prepare) {
1473 r = session_prepare_vt(s);
1474 if (r < 0) {
1475 s->track = sd_bus_track_unref(s->track);
1476 return r;
1477 }
13f493dc 1478 }
baccf3e4 1479
b12e5615 1480 session_release_controller(s, true);
ae2a15bc 1481 s->controller = TAKE_PTR(name);
b12e5615 1482 session_save(s);
90a18413 1483
ae5e06bd
DH
1484 return 0;
1485}
1486
1487void session_drop_controller(Session *s) {
1488 assert(s);
1489
1490 if (!s->controller)
1491 return;
1492
3cde9e8f 1493 s->track = sd_bus_track_unref(s->track);
db72aea4 1494 session_set_type(s, s->original_type);
b12e5615
DH
1495 session_release_controller(s, false);
1496 session_save(s);
1497 session_restore_vt(s);
ae5e06bd
DH
1498}
1499
fb6becb4
LP
1500static const char* const session_state_table[_SESSION_STATE_MAX] = {
1501 [SESSION_OPENING] = "opening",
6c75e317
ZJS
1502 [SESSION_ONLINE] = "online",
1503 [SESSION_ACTIVE] = "active",
1504 [SESSION_CLOSING] = "closing",
0604381b
LP
1505};
1506
1507DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1508
20263082 1509static const char* const session_type_table[_SESSION_TYPE_MAX] = {
2c5859af 1510 [SESSION_UNSPECIFIED] = "unspecified",
6c75e317
ZJS
1511 [SESSION_TTY] = "tty",
1512 [SESSION_X11] = "x11",
1513 [SESSION_WAYLAND] = "wayland",
1514 [SESSION_MIR] = "mir",
1515 [SESSION_WEB] = "web",
20263082
LP
1516};
1517
1518DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1519
55efac6c 1520static const char* const session_class_table[_SESSION_CLASS_MAX] = {
6c75e317
ZJS
1521 [SESSION_USER] = "user",
1522 [SESSION_GREETER] = "greeter",
e2acb67b 1523 [SESSION_LOCK_SCREEN] = "lock-screen",
6c75e317 1524 [SESSION_BACKGROUND] = "background",
55efac6c
LP
1525};
1526
1527DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1528
de07ab16
LP
1529static const char* const kill_who_table[_KILL_WHO_MAX] = {
1530 [KILL_LEADER] = "leader",
6c75e317 1531 [KILL_ALL] = "all",
de07ab16
LP
1532};
1533
1534DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
3d0ef5c7
LP
1535
1536static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = {
6c75e317
ZJS
1537 [TTY_FROM_PAM] = "from-pam",
1538 [TTY_FROM_UTMP] = "from-utmp",
3d0ef5c7
LP
1539 [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent",
1540};
1541
1542DEFINE_STRING_TABLE_LOOKUP(tty_validity, TTYValidity);