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