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