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