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