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