]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/login/logind-user.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / login / logind-user.c
... / ...
CommitLineData
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 <sys/mount.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
26
27#include "util.h"
28#include "mkdir.h"
29#include "hashmap.h"
30#include "strv.h"
31#include "fileio.h"
32#include "path-util.h"
33#include "special.h"
34#include "unit-name.h"
35#include "bus-util.h"
36#include "bus-error.h"
37#include "conf-parser.h"
38#include "clean-ipc.h"
39#include "logind-user.h"
40#include "smack-util.h"
41
42User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
43 User *u;
44
45 assert(m);
46 assert(name);
47
48 u = new0(User, 1);
49 if (!u)
50 return NULL;
51
52 u->name = strdup(name);
53 if (!u->name)
54 goto fail;
55
56 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
57 goto fail;
58
59 if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0)
60 goto fail;
61
62 u->manager = m;
63 u->uid = uid;
64 u->gid = gid;
65
66 return u;
67
68fail:
69 free(u->state_file);
70 free(u->name);
71 free(u);
72
73 return NULL;
74}
75
76void user_free(User *u) {
77 assert(u);
78
79 if (u->in_gc_queue)
80 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
81
82 while (u->sessions)
83 session_free(u->sessions);
84
85 if (u->slice) {
86 hashmap_remove(u->manager->user_units, u->slice);
87 free(u->slice);
88 }
89
90 if (u->service) {
91 hashmap_remove(u->manager->user_units, u->service);
92 free(u->service);
93 }
94
95 free(u->slice_job);
96 free(u->service_job);
97
98 free(u->runtime_path);
99
100 hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
101
102 free(u->name);
103 free(u->state_file);
104 free(u);
105}
106
107int user_save(User *u) {
108 _cleanup_free_ char *temp_path = NULL;
109 _cleanup_fclose_ FILE *f = NULL;
110 int r;
111
112 assert(u);
113 assert(u->state_file);
114
115 if (!u->started)
116 return 0;
117
118 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
119 if (r < 0)
120 goto finish;
121
122 r = fopen_temporary(u->state_file, &f, &temp_path);
123 if (r < 0)
124 goto finish;
125
126 fchmod(fileno(f), 0644);
127
128 fprintf(f,
129 "# This is private data. Do not parse.\n"
130 "NAME=%s\n"
131 "STATE=%s\n",
132 u->name,
133 user_state_to_string(user_get_state(u)));
134
135 if (u->runtime_path)
136 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
137
138 if (u->service)
139 fprintf(f, "SERVICE=%s\n", u->service);
140 if (u->service_job)
141 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
142
143 if (u->slice)
144 fprintf(f, "SLICE=%s\n", u->slice);
145 if (u->slice_job)
146 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
147
148 if (u->display)
149 fprintf(f, "DISPLAY=%s\n", u->display->id);
150
151 if (dual_timestamp_is_set(&u->timestamp))
152 fprintf(f,
153 "REALTIME="USEC_FMT"\n"
154 "MONOTONIC="USEC_FMT"\n",
155 u->timestamp.realtime,
156 u->timestamp.monotonic);
157
158 if (u->sessions) {
159 Session *i;
160 bool first;
161
162 fputs("SESSIONS=", f);
163 first = true;
164 LIST_FOREACH(sessions_by_user, i, u->sessions) {
165 if (first)
166 first = false;
167 else
168 fputc(' ', f);
169
170 fputs(i->id, f);
171 }
172
173 fputs("\nSEATS=", f);
174 first = true;
175 LIST_FOREACH(sessions_by_user, i, u->sessions) {
176 if (!i->seat)
177 continue;
178
179 if (first)
180 first = false;
181 else
182 fputc(' ', f);
183
184 fputs(i->seat->id, f);
185 }
186
187 fputs("\nACTIVE_SESSIONS=", f);
188 first = true;
189 LIST_FOREACH(sessions_by_user, i, u->sessions) {
190 if (!session_is_active(i))
191 continue;
192
193 if (first)
194 first = false;
195 else
196 fputc(' ', f);
197
198 fputs(i->id, f);
199 }
200
201 fputs("\nONLINE_SESSIONS=", f);
202 first = true;
203 LIST_FOREACH(sessions_by_user, i, u->sessions) {
204 if (session_get_state(i) == SESSION_CLOSING)
205 continue;
206
207 if (first)
208 first = false;
209 else
210 fputc(' ', f);
211
212 fputs(i->id, f);
213 }
214
215 fputs("\nACTIVE_SEATS=", f);
216 first = true;
217 LIST_FOREACH(sessions_by_user, i, u->sessions) {
218 if (!session_is_active(i) || !i->seat)
219 continue;
220
221 if (first)
222 first = false;
223 else
224 fputc(' ', f);
225
226 fputs(i->seat->id, f);
227 }
228
229 fputs("\nONLINE_SEATS=", f);
230 first = true;
231 LIST_FOREACH(sessions_by_user, i, u->sessions) {
232 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
233 continue;
234
235 if (first)
236 first = false;
237 else
238 fputc(' ', f);
239
240 fputs(i->seat->id, f);
241 }
242 fputc('\n', f);
243 }
244
245 fflush(f);
246
247 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
248 r = -errno;
249 unlink(u->state_file);
250 unlink(temp_path);
251 }
252
253finish:
254 if (r < 0)
255 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
256
257 return r;
258}
259
260int user_load(User *u) {
261 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
262 Session *s = NULL;
263 int r;
264
265 assert(u);
266
267 r = parse_env_file(u->state_file, NEWLINE,
268 "RUNTIME", &u->runtime_path,
269 "SERVICE", &u->service,
270 "SERVICE_JOB", &u->service_job,
271 "SLICE", &u->slice,
272 "SLICE_JOB", &u->slice_job,
273 "DISPLAY", &display,
274 "REALTIME", &realtime,
275 "MONOTONIC", &monotonic,
276 NULL);
277 if (r < 0) {
278 if (r == -ENOENT)
279 return 0;
280
281 log_error_errno(r, "Failed to read %s: %m", u->state_file);
282 return r;
283 }
284
285 if (display)
286 s = hashmap_get(u->manager->sessions, display);
287
288 if (s && s->display && display_is_local(s->display))
289 u->display = s;
290
291 if (realtime) {
292 unsigned long long l;
293 if (sscanf(realtime, "%llu", &l) > 0)
294 u->timestamp.realtime = l;
295 }
296
297 if (monotonic) {
298 unsigned long long l;
299 if (sscanf(monotonic, "%llu", &l) > 0)
300 u->timestamp.monotonic = l;
301 }
302
303 return r;
304}
305
306static int user_mkdir_runtime_path(User *u) {
307 char *p;
308 int r;
309
310 assert(u);
311
312 r = mkdir_safe_label("/run/user", 0755, 0, 0);
313 if (r < 0)
314 return log_error_errno(r, "Failed to create /run/user: %m");
315
316 if (!u->runtime_path) {
317 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
318 return log_oom();
319 } else
320 p = u->runtime_path;
321
322 if (path_is_mount_point(p, false) <= 0) {
323 _cleanup_free_ char *t = NULL;
324
325 mkdir(p, 0700);
326
327 if (mac_smack_use())
328 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
329 else
330 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
331
332 if (r < 0) {
333 r = log_oom();
334 goto fail;
335 }
336
337 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
338 if (r < 0) {
339 log_error_errno(r, "Failed to mount per-user tmpfs directory %s: %m", p);
340 goto fail;
341 }
342 }
343
344 u->runtime_path = p;
345 return 0;
346
347fail:
348 free(p);
349 u->runtime_path = NULL;
350 return r;
351}
352
353static int user_start_slice(User *u) {
354 char *job;
355 int r;
356
357 assert(u);
358
359 if (!u->slice) {
360 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
361 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
362 sprintf(lu, UID_FMT, u->uid);
363
364 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
365 if (r < 0)
366 return r;
367
368 r = manager_start_unit(u->manager, slice, &error, &job);
369 if (r < 0) {
370 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
371 free(slice);
372 } else {
373 u->slice = slice;
374
375 free(u->slice_job);
376 u->slice_job = job;
377 }
378 }
379
380 if (u->slice)
381 hashmap_put(u->manager->user_units, u->slice, u);
382
383 return 0;
384}
385
386static int user_start_service(User *u) {
387 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
388 char *job;
389 int r;
390
391 assert(u);
392
393 if (!u->service) {
394 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
395 sprintf(lu, UID_FMT, u->uid);
396
397 service = unit_name_build("user", lu, ".service");
398 if (!service)
399 return log_oom();
400
401 r = manager_start_unit(u->manager, service, &error, &job);
402 if (r < 0) {
403 log_error("Failed to start user service: %s", bus_error_message(&error, r));
404 free(service);
405 } else {
406 u->service = service;
407
408 free(u->service_job);
409 u->service_job = job;
410 }
411 }
412
413 if (u->service)
414 hashmap_put(u->manager->user_units, u->service, u);
415
416 return 0;
417}
418
419int user_start(User *u) {
420 int r;
421
422 assert(u);
423
424 if (u->started)
425 return 0;
426
427 log_debug("New user %s logged in.", u->name);
428
429 /* Make XDG_RUNTIME_DIR */
430 r = user_mkdir_runtime_path(u);
431 if (r < 0)
432 return r;
433
434 /* Create cgroup */
435 r = user_start_slice(u);
436 if (r < 0)
437 return r;
438
439 /* Spawn user systemd */
440 r = user_start_service(u);
441 if (r < 0)
442 return r;
443
444 if (!dual_timestamp_is_set(&u->timestamp))
445 dual_timestamp_get(&u->timestamp);
446
447 u->started = true;
448
449 /* Save new user data */
450 user_save(u);
451
452 user_send_signal(u, true);
453
454 return 0;
455}
456
457static int user_stop_slice(User *u) {
458 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
459 char *job;
460 int r;
461
462 assert(u);
463
464 if (!u->slice)
465 return 0;
466
467 r = manager_stop_unit(u->manager, u->slice, &error, &job);
468 if (r < 0) {
469 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
470 return r;
471 }
472
473 free(u->slice_job);
474 u->slice_job = job;
475
476 return r;
477}
478
479static int user_stop_service(User *u) {
480 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
481 char *job;
482 int r;
483
484 assert(u);
485
486 if (!u->service)
487 return 0;
488
489 r = manager_stop_unit(u->manager, u->service, &error, &job);
490 if (r < 0) {
491 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
492 return r;
493 }
494
495 free(u->service_job);
496 u->service_job = job;
497
498 return r;
499}
500
501static int user_remove_runtime_path(User *u) {
502 int r;
503
504 assert(u);
505
506 if (!u->runtime_path)
507 return 0;
508
509 r = rm_rf(u->runtime_path, false, false, false);
510 if (r < 0)
511 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
512
513 if (umount2(u->runtime_path, MNT_DETACH) < 0)
514 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
515
516 r = rm_rf(u->runtime_path, false, true, false);
517 if (r < 0)
518 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
519
520 free(u->runtime_path);
521 u->runtime_path = NULL;
522
523 return r;
524}
525
526int user_stop(User *u, bool force) {
527 Session *s;
528 int r = 0, k;
529 assert(u);
530
531 /* Stop jobs have already been queued */
532 if (u->stopping) {
533 user_save(u);
534 return r;
535 }
536
537 LIST_FOREACH(sessions_by_user, s, u->sessions) {
538 k = session_stop(s, force);
539 if (k < 0)
540 r = k;
541 }
542
543 /* Kill systemd */
544 k = user_stop_service(u);
545 if (k < 0)
546 r = k;
547
548 /* Kill cgroup */
549 k = user_stop_slice(u);
550 if (k < 0)
551 r = k;
552
553 u->stopping = true;
554
555 user_save(u);
556
557 return r;
558}
559
560int user_finalize(User *u) {
561 Session *s;
562 int r = 0, k;
563
564 assert(u);
565
566 if (u->started)
567 log_debug("User %s logged out.", u->name);
568
569 LIST_FOREACH(sessions_by_user, s, u->sessions) {
570 k = session_finalize(s);
571 if (k < 0)
572 r = k;
573 }
574
575 /* Kill XDG_RUNTIME_DIR */
576 k = user_remove_runtime_path(u);
577 if (k < 0)
578 r = k;
579
580 /* Clean SysV + POSIX IPC objects */
581 if (u->manager->remove_ipc) {
582 k = clean_ipc(u->uid);
583 if (k < 0)
584 r = k;
585 }
586
587 unlink(u->state_file);
588 user_add_to_gc_queue(u);
589
590 if (u->started) {
591 user_send_signal(u, false);
592 u->started = false;
593 }
594
595 return r;
596}
597
598int user_get_idle_hint(User *u, dual_timestamp *t) {
599 Session *s;
600 bool idle_hint = true;
601 dual_timestamp ts = { 0, 0 };
602
603 assert(u);
604
605 LIST_FOREACH(sessions_by_user, s, u->sessions) {
606 dual_timestamp k;
607 int ih;
608
609 ih = session_get_idle_hint(s, &k);
610 if (ih < 0)
611 return ih;
612
613 if (!ih) {
614 if (!idle_hint) {
615 if (k.monotonic < ts.monotonic)
616 ts = k;
617 } else {
618 idle_hint = false;
619 ts = k;
620 }
621 } else if (idle_hint) {
622
623 if (k.monotonic > ts.monotonic)
624 ts = k;
625 }
626 }
627
628 if (t)
629 *t = ts;
630
631 return idle_hint;
632}
633
634int user_check_linger_file(User *u) {
635 _cleanup_free_ char *cc = NULL;
636 char *p = NULL;
637
638 cc = cescape(u->name);
639 if (!cc)
640 return -ENOMEM;
641
642 p = strappenda("/var/lib/systemd/linger/", cc);
643
644 return access(p, F_OK) >= 0;
645}
646
647bool user_check_gc(User *u, bool drop_not_started) {
648 assert(u);
649
650 if (drop_not_started && !u->started)
651 return false;
652
653 if (u->sessions)
654 return true;
655
656 if (user_check_linger_file(u) > 0)
657 return true;
658
659 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
660 return true;
661
662 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
663 return true;
664
665 return false;
666}
667
668void user_add_to_gc_queue(User *u) {
669 assert(u);
670
671 if (u->in_gc_queue)
672 return;
673
674 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
675 u->in_gc_queue = true;
676}
677
678UserState user_get_state(User *u) {
679 Session *i;
680
681 assert(u);
682
683 if (u->stopping)
684 return USER_CLOSING;
685
686 if (u->slice_job || u->service_job)
687 return USER_OPENING;
688
689 if (u->sessions) {
690 bool all_closing = true;
691
692 LIST_FOREACH(sessions_by_user, i, u->sessions) {
693 SessionState state;
694
695 state = session_get_state(i);
696 if (state == SESSION_ACTIVE)
697 return USER_ACTIVE;
698 if (state != SESSION_CLOSING)
699 all_closing = false;
700 }
701
702 return all_closing ? USER_CLOSING : USER_ONLINE;
703 }
704
705 if (user_check_linger_file(u) > 0)
706 return USER_LINGERING;
707
708 return USER_CLOSING;
709}
710
711int user_kill(User *u, int signo) {
712 assert(u);
713
714 if (!u->slice)
715 return -ESRCH;
716
717 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
718}
719
720void user_elect_display(User *u) {
721 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
722
723 assert(u);
724
725 /* This elects a primary session for each user, which we call
726 * the "display". We try to keep the assignment stable, but we
727 * "upgrade" to better choices. */
728
729 LIST_FOREACH(sessions_by_user, s, u->sessions) {
730
731 if (s->class != SESSION_USER)
732 continue;
733
734 if (s->stopping)
735 continue;
736
737 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
738 graphical = s;
739 else if (s->type == SESSION_TTY)
740 text = s;
741 else
742 other = s;
743 }
744
745 if (graphical &&
746 (!u->display ||
747 u->display->class != SESSION_USER ||
748 u->display->stopping ||
749 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
750 u->display = graphical;
751 return;
752 }
753
754 if (text &&
755 (!u->display ||
756 u->display->class != SESSION_USER ||
757 u->display->stopping ||
758 u->display->type != SESSION_TTY)) {
759 u->display = text;
760 return;
761 }
762
763 if (other &&
764 (!u->display ||
765 u->display->class != SESSION_USER ||
766 u->display->stopping))
767 u->display = other;
768}
769
770static const char* const user_state_table[_USER_STATE_MAX] = {
771 [USER_OFFLINE] = "offline",
772 [USER_OPENING] = "opening",
773 [USER_LINGERING] = "lingering",
774 [USER_ONLINE] = "online",
775 [USER_ACTIVE] = "active",
776 [USER_CLOSING] = "closing"
777};
778
779DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
780
781int config_parse_tmpfs_size(
782 const char* unit,
783 const char *filename,
784 unsigned line,
785 const char *section,
786 unsigned section_line,
787 const char *lvalue,
788 int ltype,
789 const char *rvalue,
790 void *data,
791 void *userdata) {
792
793 size_t *sz = data;
794 const char *e;
795 int r;
796
797 assert(filename);
798 assert(lvalue);
799 assert(rvalue);
800 assert(data);
801
802 e = endswith(rvalue, "%");
803 if (e) {
804 unsigned long ul;
805 char *f;
806
807 errno = 0;
808 ul = strtoul(rvalue, &f, 10);
809 if (errno != 0 || f != e) {
810 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
811 return 0;
812 }
813
814 if (ul <= 0 || ul >= 100) {
815 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
816 return 0;
817 }
818
819 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
820 } else {
821 off_t o;
822
823 r = parse_size(rvalue, 1024, &o);
824 if (r < 0 || (off_t) (size_t) o != o) {
825 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
826 return 0;
827 }
828
829 *sz = PAGE_ALIGN((size_t) o);
830 }
831
832 return 0;
833}