]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
networkd: fix several Address entries in [Network] section
[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
DH
23#include <fcntl.h>
24#include <linux/vt.h>
25#include <linux/kd.h>
26#include <signal.h>
20263082 27#include <string.h>
90a18413 28#include <sys/ioctl.h>
20263082
LP
29#include <unistd.h>
30
cc377381
LP
31#include "sd-id128.h"
32#include "sd-messages.h"
20263082
LP
33#include "strv.h"
34#include "util.h"
49e942b2 35#include "mkdir.h"
9eb977db 36#include "path-util.h"
a5c32cff 37#include "fileio.h"
cc377381
LP
38#include "audit.h"
39#include "bus-util.h"
40#include "bus-error.h"
fb6becb4 41#include "logind-session.h"
20263082 42
831dedef
DH
43static unsigned devt_hash_func(const void *p) {
44 uint64_t u = *(const dev_t*)p;
45
46 return uint64_hash_func(&u);
47}
48
49static int devt_compare_func(const void *_a, const void *_b) {
50 dev_t a, b;
51
52 a = *(const dev_t*) _a;
53 b = *(const dev_t*) _b;
54
55 return a < b ? -1 : (a > b ? 1 : 0);
56}
57
9444b1f2 58Session* session_new(Manager *m, const char *id) {
20263082
LP
59 Session *s;
60
61 assert(m);
62 assert(id);
4b549144 63 assert(session_id_valid(id));
20263082 64
14c3baca 65 s = new0(Session, 1);
20263082
LP
66 if (!s)
67 return NULL;
68
98a28fef 69 s->state_file = strappend("/run/systemd/sessions/", id);
20263082
LP
70 if (!s->state_file) {
71 free(s);
72 return NULL;
73 }
74
831dedef 75 s->devices = hashmap_new(devt_hash_func, devt_compare_func);
118ecf32
DH
76 if (!s->devices) {
77 free(s->state_file);
78 free(s);
79 return NULL;
80 }
81
9eb977db 82 s->id = path_get_file_name(s->state_file);
20263082
LP
83
84 if (hashmap_put(m->sessions, s->id, s) < 0) {
118ecf32 85 hashmap_free(s->devices);
f8e2fb7b 86 free(s->state_file);
20263082
LP
87 free(s);
88 return NULL;
89 }
90
91 s->manager = m;
932e3ee7 92 s->fifo_fd = -1;
90a18413 93 s->vtfd = -1;
20263082
LP
94
95 return s;
96}
97
98void session_free(Session *s) {
118ecf32
DH
99 SessionDevice *sd;
100
20263082
LP
101 assert(s);
102
14c3baca 103 if (s->in_gc_queue)
71fda00f 104 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
14c3baca 105
cc377381
LP
106 session_remove_fifo(s);
107
ae5e06bd
DH
108 session_drop_controller(s);
109
118ecf32
DH
110 while ((sd = hashmap_first(s->devices)))
111 session_device_free(sd);
112
113 hashmap_free(s->devices);
114
20263082 115 if (s->user) {
71fda00f 116 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
20263082
LP
117
118 if (s->user->display == s)
119 s->user->display = NULL;
120 }
121
9418f147
LP
122 if (s->seat) {
123 if (s->seat->active == s)
124 s->seat->active = NULL;
d7bd01b5
DH
125 if (s->seat->pending_switch == s)
126 s->seat->pending_switch = NULL;
9418f147 127
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);
20263082
LP
145
146 hashmap_remove(s->manager->sessions, s->id);
98a28fef 147
d2f92cdf 148 free(s->state_file);
20263082
LP
149 free(s);
150}
151
9444b1f2
LP
152void session_set_user(Session *s, User *u) {
153 assert(s);
154 assert(!s->user);
155
156 s->user = u;
71fda00f 157 LIST_PREPEND(sessions_by_user, u->sessions, s);
9444b1f2
LP
158}
159
20263082 160int session_save(Session *s) {
507f22bd 161 _cleanup_free_ char *temp_path = NULL;
cc377381 162 _cleanup_fclose_ FILE *f = NULL;
20263082
LP
163 int r = 0;
164
165 assert(s);
166
9444b1f2
LP
167 if (!s->user)
168 return -ESTALE;
169
accaeded
LP
170 if (!s->started)
171 return 0;
172
d2e54fae 173 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
20263082 174 if (r < 0)
14c3baca 175 goto finish;
20263082 176
14c3baca
LP
177 r = fopen_temporary(s->state_file, &f, &temp_path);
178 if (r < 0)
179 goto finish;
20263082
LP
180
181 assert(s->user);
182
14c3baca
LP
183 fchmod(fileno(f), 0644);
184
20263082
LP
185 fprintf(f,
186 "# This is private data. Do not parse.\n"
187 "UID=%lu\n"
188 "USER=%s\n"
189 "ACTIVE=%i\n"
0604381b 190 "STATE=%s\n"
fb6becb4 191 "REMOTE=%i\n",
20263082
LP
192 (unsigned long) s->user->uid,
193 s->user->name,
194 session_is_active(s),
0604381b 195 session_state_to_string(session_get_state(s)),
fb6becb4 196 s->remote);
20263082 197
a91e4e53 198 if (s->type >= 0)
507f22bd 199 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
a91e4e53 200
55efac6c 201 if (s->class >= 0)
507f22bd 202 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
55efac6c 203
fb6becb4
LP
204 if (s->scope)
205 fprintf(f, "SCOPE=%s\n", s->scope);
206
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
LP
221
222 if (s->remote_host)
507f22bd 223 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
20263082 224
3f49d45a 225 if (s->remote_user)
507f22bd 226 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
3f49d45a 227
98a28fef 228 if (s->service)
507f22bd 229 fprintf(f, "SERVICE=%s\n", s->service);
98a28fef 230
bf7825ae 231 if (s->seat && seat_has_vts(s->seat))
507f22bd 232 fprintf(f, "VTNR=%i\n", s->vtnr);
20263082
LP
233
234 if (s->leader > 0)
507f22bd 235 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
20263082
LP
236
237 if (s->audit_id > 0)
507f22bd 238 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
20263082 239
9444b1f2
LP
240 if (dual_timestamp_is_set(&s->timestamp))
241 fprintf(f,
242 "REALTIME=%llu\n"
243 "MONOTONIC=%llu\n",
244 (unsigned long long) s->timestamp.realtime,
245 (unsigned long long) s->timestamp.monotonic);
246
6d33772f
DH
247 if (s->controller)
248 fprintf(f, "CONTROLLER=%s\n", s->controller);
249
20263082 250 fflush(f);
14c3baca
LP
251
252 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
20263082
LP
253 r = -errno;
254 unlink(s->state_file);
14c3baca 255 unlink(temp_path);
20263082
LP
256 }
257
14c3baca
LP
258finish:
259 if (r < 0)
260 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
261
20263082
LP
262 return r;
263}
264
265int session_load(Session *s) {
9444b1f2 266 _cleanup_free_ char *remote = NULL,
a185c5aa
LP
267 *seat = NULL,
268 *vtnr = NULL,
269 *leader = NULL,
55efac6c 270 *type = NULL,
9444b1f2
LP
271 *class = NULL,
272 *uid = NULL,
273 *realtime = NULL,
6d33772f
DH
274 *monotonic = NULL,
275 *controller = NULL;
a185c5aa
LP
276
277 int k, r;
278
20263082
LP
279 assert(s);
280
a185c5aa
LP
281 r = parse_env_file(s->state_file, NEWLINE,
282 "REMOTE", &remote,
fb6becb4
LP
283 "SCOPE", &s->scope,
284 "SCOPE_JOB", &s->scope_job,
932e3ee7 285 "FIFO", &s->fifo_path,
a185c5aa
LP
286 "SEAT", &seat,
287 "TTY", &s->tty,
288 "DISPLAY", &s->display,
289 "REMOTE_HOST", &s->remote_host,
290 "REMOTE_USER", &s->remote_user,
98a28fef 291 "SERVICE", &s->service,
a185c5aa
LP
292 "VTNR", &vtnr,
293 "LEADER", &leader,
a91e4e53 294 "TYPE", &type,
55efac6c 295 "CLASS", &class,
9444b1f2
LP
296 "UID", &uid,
297 "REALTIME", &realtime,
298 "MONOTONIC", &monotonic,
6d33772f 299 "CONTROLLER", &controller,
a185c5aa
LP
300 NULL);
301
9444b1f2
LP
302 if (r < 0) {
303 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
304 return r;
305 }
306
307 if (!s->user) {
308 uid_t u;
309 User *user;
310
311 if (!uid) {
312 log_error("UID not specified for session %s", s->id);
313 return -ENOENT;
314 }
315
316 r = parse_uid(uid, &u);
317 if (r < 0) {
318 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
319 return r;
320 }
321
322 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
323 if (!user) {
324 log_error("User of session %s not known.", s->id);
325 return -ENOENT;
326 }
327
328 session_set_user(s, user);
329 }
a185c5aa
LP
330
331 if (remote) {
332 k = parse_boolean(remote);
333 if (k >= 0)
334 s->remote = k;
335 }
336
9418f147 337 if (seat && !s->seat) {
a185c5aa
LP
338 Seat *o;
339
340 o = hashmap_get(s->manager->seats, seat);
341 if (o)
342 seat_attach_session(o, s);
343 }
344
bf7825ae 345 if (vtnr && s->seat && seat_has_vts(s->seat)) {
a185c5aa
LP
346 int v;
347
348 k = safe_atoi(vtnr, &v);
349 if (k >= 0 && v >= 1)
350 s->vtnr = v;
351 }
352
353 if (leader) {
f8e2fb7b
LP
354 k = parse_pid(leader, &s->leader);
355 if (k >= 0)
356 audit_session_from_pid(s->leader, &s->audit_id);
a185c5aa
LP
357 }
358
a91e4e53
LP
359 if (type) {
360 SessionType t;
361
362 t = session_type_from_string(type);
363 if (t >= 0)
364 s->type = t;
365 }
366
55efac6c
LP
367 if (class) {
368 SessionClass c;
369
370 c = session_class_from_string(class);
371 if (c >= 0)
372 s->class = c;
373 }
374
b4f78aea
LP
375 if (s->fifo_path) {
376 int fd;
377
378 /* If we open an unopened pipe for reading we will not
379 get an EOF. to trigger an EOF we hence open it for
380 reading, but close it right-away which then will
381 trigger the EOF. */
382
383 fd = session_create_fifo(s);
384 if (fd >= 0)
385 close_nointr_nofail(fd);
386 }
387
9444b1f2
LP
388 if (realtime) {
389 unsigned long long l;
390 if (sscanf(realtime, "%llu", &l) > 0)
391 s->timestamp.realtime = l;
392 }
393
394 if (monotonic) {
395 unsigned long long l;
396 if (sscanf(monotonic, "%llu", &l) > 0)
397 s->timestamp.monotonic = l;
398 }
a185c5aa 399
6d33772f
DH
400 if (controller) {
401 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
402 session_set_controller(s, controller, false);
90a18413
DH
403 else
404 session_restore_vt(s);
6d33772f
DH
405 }
406
a185c5aa 407 return r;
20263082
LP
408}
409
410int session_activate(Session *s) {
d7bd01b5
DH
411 unsigned int num_pending;
412
20263082 413 assert(s);
9444b1f2 414 assert(s->user);
20263082 415
20263082
LP
416 if (!s->seat)
417 return -ENOTSUP;
418
419 if (s->seat->active == s)
420 return 0;
421
d7bd01b5
DH
422 /* on seats with VTs, we let VTs manage session-switching */
423 if (seat_has_vts(s->seat)) {
424 if (s->vtnr <= 0)
425 return -ENOTSUP;
426
427 return chvt(s->vtnr);
428 }
429
430 /* On seats without VTs, we implement session-switching in logind. We
431 * try to pause all session-devices and wait until the session
432 * controller acknowledged them. Once all devices are asleep, we simply
433 * switch the active session and be done.
434 * We save the session we want to switch to in seat->pending_switch and
435 * seat_complete_switch() will perform the final switch. */
436
437 s->seat->pending_switch = s;
438
439 /* if no devices are running, immediately perform the session switch */
440 num_pending = session_device_try_pause_all(s);
441 if (!num_pending)
442 seat_complete_switch(s->seat);
20263082 443
d7bd01b5 444 return 0;
20263082
LP
445}
446
20263082 447static int session_link_x11_socket(Session *s) {
5af726cc
ZJS
448 _cleanup_free_ char *t = NULL, *f = NULL;
449 char *c;
20263082
LP
450 size_t k;
451
452 assert(s);
453 assert(s->user);
454 assert(s->user->runtime_path);
455
456 if (s->user->display)
457 return 0;
458
4d6d6518 459 if (!s->display || !display_is_local(s->display))
20263082
LP
460 return 0;
461
462 k = strspn(s->display+1, "0123456789");
463 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
0d0f0c50
SL
464 if (!f)
465 return log_oom();
20263082
LP
466
467 c = stpcpy(f, "/tmp/.X11-unix/X");
468 memcpy(c, s->display+1, k);
469 c[k] = 0;
470
471 if (access(f, F_OK) < 0) {
6ccf7562 472 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
20263082
LP
473 return -ENOENT;
474 }
475
c9d8629b
LP
476 /* Note that this cannot be in a subdir to avoid
477 * vulnerabilities since we are privileged but the runtime
478 * path is owned by the user */
479
fc3c1c6e 480 t = strappend(s->user->runtime_path, "/X11-display");
5af726cc 481 if (!t)
0d0f0c50 482 return log_oom();
20263082
LP
483
484 if (link(f, t) < 0) {
485 if (errno == EEXIST) {
486 unlink(t);
487
488 if (link(f, t) >= 0)
489 goto done;
490 }
491
492 if (symlink(f, t) < 0) {
493
494 if (errno == EEXIST) {
495 unlink(t);
496
497 if (symlink(f, t) >= 0)
498 goto done;
499 }
500
501 log_error("Failed to link %s to %s: %m", f, t);
20263082
LP
502 return -errno;
503 }
504 }
505
506done:
507 log_info("Linked %s to %s.", f, t);
20263082
LP
508 s->user->display = s;
509
510 return 0;
511}
512
fb6becb4 513static int session_start_scope(Session *s) {
98a28fef
LP
514 int r;
515
516 assert(s);
9444b1f2 517 assert(s->user);
fb6becb4 518 assert(s->user->slice);
98a28fef 519
fb6becb4 520 if (!s->scope) {
cc377381 521 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d0af76e6 522 _cleanup_free_ char *description = NULL;
405e0255 523 const char *kill_mode;
d0af76e6
LP
524 char *scope, *job;
525
405e0255
LP
526 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
527 if (!description)
528 return log_oom();
529
d0af76e6
LP
530 scope = strjoin("session-", s->id, ".scope", NULL);
531 if (!scope)
ae018d9b
LP
532 return log_oom();
533
405e0255 534 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
98a28fef 535
405e0255 536 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
d0af76e6 537 if (r < 0) {
042f5988 538 log_error("Failed to start session scope %s: %s %s",
cc377381 539 scope, bus_error_message(&error, r), error.name);
d0af76e6 540 free(scope);
f2d4f98d 541 return r;
d0af76e6
LP
542 } else {
543 s->scope = scope;
544
545 free(s->scope_job);
546 s->scope_job = job;
547 }
20263082
LP
548 }
549
d0af76e6
LP
550 if (s->scope)
551 hashmap_put(s->manager->session_units, s->scope, s);
552
20263082
LP
553 return 0;
554}
555
556int session_start(Session *s) {
557 int r;
558
559 assert(s);
9444b1f2
LP
560
561 if (!s->user)
562 return -ESTALE;
20263082 563
9418f147
LP
564 if (s->started)
565 return 0;
566
ed18b08b
LP
567 r = user_start(s->user);
568 if (r < 0)
569 return r;
570
fb6becb4
LP
571 /* Create cgroup */
572 r = session_start_scope(s);
573 if (r < 0)
574 return r;
575
877d54e9 576 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
1ca6783f 577 MESSAGE_ID(SD_MESSAGE_SESSION_START),
877d54e9
LP
578 "SESSION_ID=%s", s->id,
579 "USER_ID=%s", s->user->name,
580 "LEADER=%lu", (unsigned long) s->leader,
581 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
582 NULL);
98a28fef 583
20263082
LP
584 /* Create X11 symlink */
585 session_link_x11_socket(s);
14c3baca 586
9444b1f2
LP
587 if (!dual_timestamp_is_set(&s->timestamp))
588 dual_timestamp_get(&s->timestamp);
14c3baca 589
e9816c48
LP
590 if (s->seat)
591 seat_read_active_vt(s->seat);
592
9418f147
LP
593 s->started = true;
594
e9816c48
LP
595 /* Save session data */
596 session_save(s);
7f7bb946 597 user_save(s->user);
e9816c48 598
da119395
LP
599 session_send_signal(s, true);
600
9418f147 601 if (s->seat) {
7f7bb946
LP
602 seat_save(s->seat);
603
9418f147 604 if (s->seat->active == s)
cc377381 605 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
9418f147 606 else
cc377381 607 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
608 }
609
cc377381 610 user_send_changed(s->user, "Sessions", NULL);
9418f147 611
20263082
LP
612 return 0;
613}
614
fb6becb4 615static int session_stop_scope(Session *s) {
cc377381 616 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
fb6becb4 617 char *job;
20263082 618 int r;
20263082
LP
619
620 assert(s);
621
fb6becb4
LP
622 if (!s->scope)
623 return 0;
9b221b63 624
fb6becb4
LP
625 r = manager_stop_unit(s->manager, s->scope, &error, &job);
626 if (r < 0) {
cc377381 627 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
fb6becb4 628 return r;
20263082
LP
629 }
630
fb6becb4
LP
631 free(s->scope_job);
632 s->scope_job = job;
20263082 633
9b221b63 634 return 0;
20263082
LP
635}
636
637static int session_unlink_x11_socket(Session *s) {
5af726cc 638 _cleanup_free_ char *t = NULL;
20263082
LP
639 int r;
640
641 assert(s);
642 assert(s->user);
643
644 if (s->user->display != s)
645 return 0;
646
647 s->user->display = NULL;
648
fc3c1c6e 649 t = strappend(s->user->runtime_path, "/X11-display");
0d0f0c50
SL
650 if (!t)
651 return log_oom();
20263082
LP
652
653 r = unlink(t);
20263082
LP
654 return r < 0 ? -errno : 0;
655}
656
657int session_stop(Session *s) {
405e0255
LP
658 int r;
659
660 assert(s);
661
662 if (!s->user)
663 return -ESTALE;
664
665 /* Kill cgroup */
666 r = session_stop_scope(s);
667
668 session_save(s);
cc377381 669 user_save(s->user);
405e0255
LP
670
671 return r;
672}
673
674int session_finalize(Session *s) {
675 int r = 0;
118ecf32 676 SessionDevice *sd;
20263082
LP
677
678 assert(s);
679
9444b1f2
LP
680 if (!s->user)
681 return -ESTALE;
682
ed18b08b 683 if (s->started)
877d54e9 684 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
1ca6783f 685 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
877d54e9
LP
686 "SESSION_ID=%s", s->id,
687 "USER_ID=%s", s->user->name,
688 "LEADER=%lu", (unsigned long) s->leader,
689 "MESSAGE=Removed session %s.", s->id,
690 NULL);
98a28fef 691
118ecf32
DH
692 /* Kill session devices */
693 while ((sd = hashmap_first(s->devices)))
694 session_device_free(sd);
695
20263082
LP
696 /* Remove X11 symlink */
697 session_unlink_x11_socket(s);
698
d2f92cdf
LP
699 unlink(s->state_file);
700 session_add_to_gc_queue(s);
ed18b08b 701 user_add_to_gc_queue(s->user);
14c3baca 702
405e0255 703 if (s->started) {
ed18b08b 704 session_send_signal(s, false);
405e0255
LP
705 s->started = false;
706 }
50fb9793 707
9418f147
LP
708 if (s->seat) {
709 if (s->seat->active == s)
710 seat_set_active(s->seat, NULL);
711
cc377381 712 seat_send_changed(s->seat, "Sessions", NULL);
23bd3b62 713 seat_save(s->seat);
9418f147
LP
714 }
715
cc377381 716 user_send_changed(s->user, "Sessions", NULL);
23bd3b62 717 user_save(s->user);
9418f147 718
20263082
LP
719 return r;
720}
721
722bool session_is_active(Session *s) {
723 assert(s);
724
725 if (!s->seat)
726 return true;
727
728 return s->seat->active == s;
729}
730
23406ce5
LP
731static int get_tty_atime(const char *tty, usec_t *atime) {
732 _cleanup_free_ char *p = NULL;
a185c5aa 733 struct stat st;
23406ce5
LP
734
735 assert(tty);
736 assert(atime);
737
738 if (!path_is_absolute(tty)) {
739 p = strappend("/dev/", tty);
740 if (!p)
741 return -ENOMEM;
742
743 tty = p;
744 } else if (!path_startswith(tty, "/dev/"))
745 return -ENOENT;
746
747 if (lstat(tty, &st) < 0)
748 return -errno;
749
750 *atime = timespec_load(&st.st_atim);
751 return 0;
752}
753
754static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
755 _cleanup_free_ char *p = NULL;
756 int r;
757
758 assert(pid > 0);
759 assert(atime);
760
761 r = get_ctty(pid, NULL, &p);
762 if (r < 0)
763 return r;
764
765 return get_tty_atime(p, atime);
766}
767
768int session_get_idle_hint(Session *s, dual_timestamp *t) {
23406ce5
LP
769 usec_t atime = 0, n;
770 int r;
a185c5aa
LP
771
772 assert(s);
773
23406ce5 774 /* Explicit idle hint is set */
a185c5aa
LP
775 if (s->idle_hint) {
776 if (t)
777 *t = s->idle_hint_timestamp;
778
779 return s->idle_hint;
780 }
781
0762eaa3 782 /* Graphical sessions should really implement a real
23406ce5
LP
783 * idle hint logic */
784 if (s->display)
a185c5aa
LP
785 goto dont_know;
786
23406ce5
LP
787 /* For sessions with an explicitly configured tty, let's check
788 * its atime */
789 if (s->tty) {
790 r = get_tty_atime(s->tty, &atime);
791 if (r >= 0)
792 goto found_atime;
793 }
a185c5aa 794
23406ce5
LP
795 /* For sessions with a leader but no explicitly configured
796 * tty, let's check the controlling tty of the leader */
797 if (s->leader > 0) {
798 r = get_process_ctty_atime(s->leader, &atime);
799 if (r >= 0)
800 goto found_atime;
a185c5aa
LP
801 }
802
a185c5aa
LP
803dont_know:
804 if (t)
805 *t = s->idle_hint_timestamp;
806
807 return 0;
23406ce5
LP
808
809found_atime:
810 if (t)
811 dual_timestamp_from_realtime(t, atime);
812
813 n = now(CLOCK_REALTIME);
814
815 if (s->manager->idle_action_usec <= 0)
816 return 0;
817
818 return atime + s->manager->idle_action_usec <= n;
a185c5aa
LP
819}
820
bef422ae
LP
821void session_set_idle_hint(Session *s, bool b) {
822 assert(s);
823
824 if (s->idle_hint == b)
825 return;
826
827 s->idle_hint = b;
828 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147 829
cc377381 830 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
9418f147
LP
831
832 if (s->seat)
cc377381
LP
833 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
834
835 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
836 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
837}
838
839static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
840 Session *s = userdata;
841
842 assert(s);
843 assert(s->fifo_fd == fd);
844
845 /* EOF on the FIFO means the session died abnormally. */
846
847 session_remove_fifo(s);
848 session_stop(s);
849
850 return 1;
bef422ae
LP
851}
852
932e3ee7
LP
853int session_create_fifo(Session *s) {
854 int r;
855
31b79c2b
LP
856 assert(s);
857
b4f78aea 858 /* Create FIFO */
932e3ee7 859 if (!s->fifo_path) {
d2e54fae 860 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e6061ab2
LP
861 if (r < 0)
862 return r;
863
932e3ee7
LP
864 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
865 return -ENOMEM;
31b79c2b 866
932e3ee7
LP
867 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
868 return -errno;
869 }
31b79c2b 870
932e3ee7 871 /* Open reading side */
b4f78aea 872 if (s->fifo_fd < 0) {
b4f78aea
LP
873 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
874 if (s->fifo_fd < 0)
875 return -errno;
876
cc377381
LP
877 }
878
879 if (!s->fifo_event_source) {
880 r = sd_event_add_io(s->manager->event, s->fifo_fd, 0, session_dispatch_fifo, s, &s->fifo_event_source);
b4f78aea
LP
881 if (r < 0)
882 return r;
883
718db961 884 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
cc377381
LP
885 if (r < 0)
886 return r;
b4f78aea 887 }
932e3ee7
LP
888
889 /* Open writing side */
890 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
891 if (r < 0)
892 return -errno;
31b79c2b 893
932e3ee7
LP
894 return r;
895}
896
897void session_remove_fifo(Session *s) {
898 assert(s);
899
cc377381
LP
900 if (s->fifo_event_source)
901 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
902
932e3ee7 903 if (s->fifo_fd >= 0) {
932e3ee7
LP
904 close_nointr_nofail(s->fifo_fd);
905 s->fifo_fd = -1;
906 }
907
908 if (s->fifo_path) {
909 unlink(s->fifo_path);
910 free(s->fifo_path);
911 s->fifo_path = NULL;
912 }
31b79c2b
LP
913}
914
cc377381 915bool session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
916 int r;
917
918 assert(s);
919
4a4b033f 920 if (drop_not_started && !s->started)
cc377381 921 return false;
932e3ee7 922
9444b1f2 923 if (!s->user)
cc377381 924 return false;
9444b1f2 925
932e3ee7 926 if (s->fifo_fd >= 0) {
932e3ee7 927 r = pipe_eof(s->fifo_fd);
20263082 928 if (r < 0)
cc377381 929 return true;
20263082 930
14c3baca 931 if (r == 0)
cc377381 932 return true;
20263082
LP
933 }
934
cc377381
LP
935 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
936 return true;
20263082 937
cc377381
LP
938 if (s->scope && manager_unit_is_active(s->manager, s->scope))
939 return true;
20263082 940
cc377381 941 return false;
20263082
LP
942}
943
14c3baca
LP
944void session_add_to_gc_queue(Session *s) {
945 assert(s);
946
947 if (s->in_gc_queue)
948 return;
949
71fda00f 950 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
951 s->in_gc_queue = true;
952}
953
0604381b
LP
954SessionState session_get_state(Session *s) {
955 assert(s);
956
405e0255
LP
957 if (s->closing)
958 return SESSION_CLOSING;
959
fb6becb4 960 if (s->scope_job)
405e0255 961 return SESSION_OPENING;
fb6becb4 962
0604381b
LP
963 if (s->fifo_fd < 0)
964 return SESSION_CLOSING;
965
966 if (session_is_active(s))
967 return SESSION_ACTIVE;
968
969 return SESSION_ONLINE;
970}
971
de07ab16 972int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
973 assert(s);
974
fb6becb4 975 if (!s->scope)
de07ab16
LP
976 return -ESRCH;
977
fb6becb4 978 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
979}
980
90a18413
DH
981static int session_open_vt(Session *s) {
982 char path[128];
983
984 if (s->vtnr <= 0)
985 return -1;
986
987 if (s->vtfd >= 0)
988 return s->vtfd;
989
990 sprintf(path, "/dev/tty%d", s->vtnr);
991 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
992 if (s->vtfd < 0) {
993 log_error("cannot open VT %s of session %s: %m", path, s->id);
994 return -1;
995 }
996
997 return s->vtfd;
998}
999
1000static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) {
1001 Session *s = data;
1002
1003 if (s->vtfd >= 0)
1004 ioctl(s->vtfd, VT_RELDISP, 1);
1005
1006 return 0;
1007}
1008
1009void session_mute_vt(Session *s) {
1010 int vt, r;
1011 struct vt_mode mode = { 0 };
1012 sigset_t mask;
1013
1014 vt = session_open_vt(s);
1015 if (vt < 0)
1016 return;
1017
1018 r = ioctl(vt, KDSKBMODE, K_OFF);
1019 if (r < 0)
1020 goto error;
1021
1022 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1023 if (r < 0)
1024 goto error;
1025
1026 sigemptyset(&mask);
1027 sigaddset(&mask, SIGUSR1);
1028 sigprocmask(SIG_BLOCK, &mask, NULL);
1029
1030 r = sd_event_add_signal(s->manager->event, SIGUSR1, session_vt_fn, s, &s->vt_source);
1031 if (r < 0)
1032 goto error;
1033
1034 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1035 * So we need a dummy handler here which just acknowledges *all* VT
1036 * switch requests. */
1037 mode.mode = VT_PROCESS;
1038 mode.relsig = SIGUSR1;
1039 mode.acqsig = SIGUSR1;
1040 r = ioctl(vt, VT_SETMODE, &mode);
1041 if (r < 0)
1042 goto error;
1043
1044 return;
1045
1046error:
1047 log_error("cannot mute VT %d for session %s (%d/%d)", s->vtnr, s->id, r, errno);
1048 session_restore_vt(s);
1049}
1050
1051void session_restore_vt(Session *s) {
1052 _cleanup_free_ char *utf8;
1053 int vt, kb = K_XLATE;
1054 struct vt_mode mode = { 0 };
1055
1056 vt = session_open_vt(s);
1057 if (vt < 0)
1058 return;
1059
1060 sd_event_source_unref(s->vt_source);
1061 s->vt_source = NULL;
1062
1063 ioctl(vt, KDSETMODE, KD_TEXT);
1064
1065 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1066 kb = K_UNICODE;
1067 ioctl(vt, KDSKBMODE, kb);
1068
1069 mode.mode = VT_AUTO;
1070 ioctl(vt, VT_SETMODE, &mode);
1071
1072 close_nointr_nofail(vt);
1073 s->vtfd = -1;
1074}
1075
cc377381 1076bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1077 assert(s);
1078
1079 return streq_ptr(s->controller, sender);
1080}
1081
6d33772f
DH
1082static void session_swap_controller(Session *s, char *name) {
1083 SessionDevice *sd;
1084
1085 if (s->controller) {
1086 manager_drop_busname(s->manager, s->controller);
1087 free(s->controller);
1088 s->controller = NULL;
1089
1090 /* Drop all devices as they're now unused. Do that after the
1091 * controller is released to avoid sending out useles
1092 * dbus signals. */
1093 while ((sd = hashmap_first(s->devices)))
1094 session_device_free(sd);
90a18413
DH
1095
1096 if (!name)
1097 session_restore_vt(s);
6d33772f
DH
1098 }
1099
1100 s->controller = name;
1101 session_save(s);
1102}
1103
ae5e06bd
DH
1104int session_set_controller(Session *s, const char *sender, bool force) {
1105 char *t;
1106 int r;
1107
1108 assert(s);
1109 assert(sender);
1110
1111 if (session_is_controller(s, sender))
1112 return 0;
1113 if (s->controller && !force)
1114 return -EBUSY;
1115
1116 t = strdup(sender);
1117 if (!t)
1118 return -ENOMEM;
1119
1120 r = manager_watch_busname(s->manager, sender);
1121 if (r) {
1122 free(t);
1123 return r;
1124 }
1125
6d33772f 1126 session_swap_controller(s, t);
ae5e06bd 1127
90a18413
DH
1128 /* When setting a session controller, we forcibly mute the VT and set
1129 * it into graphics-mode. Applications can override that by changing
1130 * VT state after calling TakeControl(). However, this serves as a good
1131 * default and well-behaving controllers can now ignore VTs entirely.
1132 * Note that we reset the VT on ReleaseControl() and if the controller
1133 * exits.
1134 * If logind crashes/restarts, we restore the controller during restart
1135 * or reset the VT in case it crashed/exited, too. */
1136 session_mute_vt(s);
1137
ae5e06bd
DH
1138 return 0;
1139}
1140
1141void session_drop_controller(Session *s) {
1142 assert(s);
1143
1144 if (!s->controller)
1145 return;
1146
6d33772f 1147 session_swap_controller(s, NULL);
ae5e06bd
DH
1148}
1149
fb6becb4
LP
1150static const char* const session_state_table[_SESSION_STATE_MAX] = {
1151 [SESSION_OPENING] = "opening",
0604381b
LP
1152 [SESSION_ONLINE] = "online",
1153 [SESSION_ACTIVE] = "active",
1154 [SESSION_CLOSING] = "closing"
1155};
1156
1157DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1158
20263082 1159static const char* const session_type_table[_SESSION_TYPE_MAX] = {
3f49d45a 1160 [SESSION_TTY] = "tty",
98a28fef 1161 [SESSION_X11] = "x11",
a91e4e53 1162 [SESSION_UNSPECIFIED] = "unspecified"
20263082
LP
1163};
1164
1165DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1166
55efac6c
LP
1167static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1168 [SESSION_USER] = "user",
1169 [SESSION_GREETER] = "greeter",
e2acb67b
LP
1170 [SESSION_LOCK_SCREEN] = "lock-screen",
1171 [SESSION_BACKGROUND] = "background"
55efac6c
LP
1172};
1173
1174DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1175
de07ab16
LP
1176static const char* const kill_who_table[_KILL_WHO_MAX] = {
1177 [KILL_LEADER] = "leader",
1178 [KILL_ALL] = "all"
1179};
1180
1181DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);