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