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