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