]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dynamic-user.c
Merge pull request #7059 from yuwata/dynamic-user-7013
[thirdparty/systemd.git] / src / core / dynamic-user.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2016 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <grp.h>
21 #include <pwd.h>
22 #include <sys/file.h>
23
24 #include "clean-ipc.h"
25 #include "dynamic-user.h"
26 #include "fd-util.h"
27 #include "fileio.h"
28 #include "fs-util.h"
29 #include "io-util.h"
30 #include "parse-util.h"
31 #include "random-util.h"
32 #include "stdio-util.h"
33 #include "string-util.h"
34 #include "user-util.h"
35
36 /* Takes a value generated randomly or by hashing and turns it into a UID in the right range */
37 #define UID_CLAMP_INTO_RANGE(rnd) (((uid_t) (rnd) % (DYNAMIC_UID_MAX - DYNAMIC_UID_MIN + 1)) + DYNAMIC_UID_MIN)
38
39 static DynamicUser* dynamic_user_free(DynamicUser *d) {
40 if (!d)
41 return NULL;
42
43 if (d->manager)
44 (void) hashmap_remove(d->manager->dynamic_users, d->name);
45
46 safe_close_pair(d->storage_socket);
47 return mfree(d);
48 }
49
50 static int dynamic_user_add(Manager *m, const char *name, int storage_socket[2], DynamicUser **ret) {
51 DynamicUser *d = NULL;
52 int r;
53
54 assert(m);
55 assert(name);
56 assert(storage_socket);
57
58 r = hashmap_ensure_allocated(&m->dynamic_users, &string_hash_ops);
59 if (r < 0)
60 return r;
61
62 d = malloc0(offsetof(DynamicUser, name) + strlen(name) + 1);
63 if (!d)
64 return -ENOMEM;
65
66 strcpy(d->name, name);
67
68 d->storage_socket[0] = storage_socket[0];
69 d->storage_socket[1] = storage_socket[1];
70
71 r = hashmap_put(m->dynamic_users, d->name, d);
72 if (r < 0) {
73 free(d);
74 return r;
75 }
76
77 d->manager = m;
78
79 if (ret)
80 *ret = d;
81
82 return 0;
83 }
84
85 static int dynamic_user_acquire(Manager *m, const char *name, DynamicUser** ret) {
86 _cleanup_close_pair_ int storage_socket[2] = { -1, -1 };
87 DynamicUser *d;
88 int r;
89
90 assert(m);
91 assert(name);
92
93 /* Return the DynamicUser structure for a specific user name. Note that this won't actually allocate a UID for
94 * it, but just prepare the data structure for it. The UID is allocated only on demand, when it's really
95 * needed, and in the child process we fork off, since allocation involves NSS checks which are not OK to do
96 * from PID 1. To allow the children and PID 1 share information about allocated UIDs we use an anonymous
97 * AF_UNIX/SOCK_DGRAM socket (called the "storage socket") that contains at most one datagram with the
98 * allocated UID number, plus an fd referencing the lock file for the UID
99 * (i.e. /run/systemd/dynamic-uid/$UID). Why involve the socket pair? So that PID 1 and all its children can
100 * share the same storage for the UID and lock fd, simply by inheriting the storage socket fds. The socket pair
101 * may exist in three different states:
102 *
103 * a) no datagram stored. This is the initial state. In this case the dynamic user was never realized.
104 *
105 * b) a datagram containing a UID stored, but no lock fd attached to it. In this case there was already a
106 * statically assigned UID by the same name, which we are reusing.
107 *
108 * c) a datagram containing a UID stored, and a lock fd is attached to it. In this case we allocated a dynamic
109 * UID and locked it in the file system, using the lock fd.
110 *
111 * As PID 1 and various children might access the socket pair simultaneously, and pop the datagram or push it
112 * back in any time, we also maintain a lock on the socket pair. Note one peculiarity regarding locking here:
113 * the UID lock on disk is protected via a BSD file lock (i.e. an fd-bound lock), so that the lock is kept in
114 * place as long as there's a reference to the fd open. The lock on the storage socket pair however is a POSIX
115 * file lock (i.e. a process-bound lock), as all users share the same fd of this (after all it is anonymous,
116 * nobody else could get any access to it except via our own fd) and we want to synchronize access between all
117 * processes that have access to it. */
118
119 d = hashmap_get(m->dynamic_users, name);
120 if (d) {
121 /* We already have a structure for the dynamic user, let's increase the ref count and reuse it */
122 d->n_ref++;
123 *ret = d;
124 return 0;
125 }
126
127 if (!valid_user_group_name_or_id(name))
128 return -EINVAL;
129
130 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, storage_socket) < 0)
131 return -errno;
132
133 r = dynamic_user_add(m, name, storage_socket, &d);
134 if (r < 0)
135 return r;
136
137 storage_socket[0] = storage_socket[1] = -1;
138
139 if (ret) {
140 d->n_ref++;
141 *ret = d;
142 }
143
144 return 1;
145 }
146
147 static int make_uid_symlinks(uid_t uid, const char *name, bool b) {
148
149 char path1[strlen("/run/systemd/dynamic-uid/direct:") + DECIMAL_STR_MAX(uid_t) + 1];
150 const char *path2;
151 int r = 0, k;
152
153 /* Add direct additional symlinks for direct lookups of dynamic UIDs and their names by userspace code. The
154 * only reason we have this is because dbus-daemon cannot use D-Bus for resolving users and groups (since it
155 * would be its own client then). We hence keep these world-readable symlinks in place, so that the
156 * unprivileged dbus user can read the mappings when it needs them via these symlinks instead of having to go
157 * via the bus. Ideally, we'd use the lock files we keep for this anyway, but we can't since we use BSD locks
158 * on them and as those may be taken by any user with read access we can't make them world-readable. */
159
160 xsprintf(path1, "/run/systemd/dynamic-uid/direct:" UID_FMT, uid);
161 if (unlink(path1) < 0 && errno != ENOENT)
162 r = -errno;
163
164 if (b && symlink(name, path1) < 0) {
165 k = log_warning_errno(errno, "Failed to symlink \"%s\": %m", path1);
166 if (r == 0)
167 r = k;
168 }
169
170 path2 = strjoina("/run/systemd/dynamic-uid/direct:", name);
171 if (unlink(path2) < 0 && errno != ENOENT) {
172 k = -errno;
173 if (r == 0)
174 r = k;
175 }
176
177 if (b && symlink(path1 + strlen("/run/systemd/dynamic-uid/direct:"), path2) < 0) {
178 k = log_warning_errno(errno, "Failed to symlink \"%s\": %m", path2);
179 if (r == 0)
180 r = k;
181 }
182
183 return r;
184 }
185
186 static int pick_uid(char **suggested_paths, const char *name, uid_t *ret_uid) {
187
188 /* Find a suitable free UID. We use the following strategy to find a suitable UID:
189 *
190 * 1. Initially, we try to read the UID of a number of specified paths. If any of these UIDs works, we use
191 * them. We use in order to increase the chance of UID reuse, if StateDirectory=, CacheDirectory= or
192 * LogDirectory= are used, as reusing the UID these directories are owned by saves us from having to
193 * recursively chown() them to new users.
194 *
195 * 2. If that didn't yield a currently unused UID, we hash the user name, and try to use that. This should be
196 * pretty good, as the use ris by default derived from the unit name, and hence the same service and same
197 * user should usually get the same UID as long as our hashing doesn't clash.
198 *
199 * 3. Finally, if that didn't work, we randomly pick UIDs, until we find one that is empty.
200 *
201 * Since the dynamic UID space is relatively small we'll stop trying after 100 iterations, giving up. */
202
203 enum {
204 PHASE_SUGGESTED, /* the first phase, reusing directory ownership UIDs */
205 PHASE_HASHED, /* the second phase, deriving a UID from the username by hashing */
206 PHASE_RANDOM, /* the last phase, randomly picking UIDs */
207 } phase = PHASE_SUGGESTED;
208
209 static const uint8_t hash_key[] = {
210 0x37, 0x53, 0x7e, 0x31, 0xcf, 0xce, 0x48, 0xf5,
211 0x8a, 0xbb, 0x39, 0x57, 0x8d, 0xd9, 0xec, 0x59
212 };
213
214 unsigned n_tries = 100, current_suggested = 0;
215 int r;
216
217 (void) mkdir("/run/systemd/dynamic-uid", 0755);
218
219 for (;;) {
220 char lock_path[strlen("/run/systemd/dynamic-uid/") + DECIMAL_STR_MAX(uid_t) + 1];
221 _cleanup_close_ int lock_fd = -1;
222 uid_t candidate;
223 ssize_t l;
224
225 if (--n_tries <= 0) /* Give up retrying eventually */
226 return -EBUSY;
227
228 switch (phase) {
229
230 case PHASE_SUGGESTED: {
231 struct stat st;
232
233 if (!suggested_paths || !suggested_paths[current_suggested]) {
234 /* We reached the end of the suggested paths list, let's try by hashing the name */
235 phase = PHASE_HASHED;
236 continue;
237 }
238
239 if (stat(suggested_paths[current_suggested++], &st) < 0)
240 continue; /* We can't read the UID of this path, but that doesn't matter, just try the next */
241
242 candidate = st.st_uid;
243 break;
244 }
245
246 case PHASE_HASHED:
247 /* A static user by this name does not exist yet. Let's find a free ID then, and use that. We
248 * start with a UID generated as hash from the user name. */
249 candidate = UID_CLAMP_INTO_RANGE(siphash24(name, strlen(name), hash_key));
250
251 /* If this one fails, we should proceed with random tries */
252 phase = PHASE_RANDOM;
253 break;
254
255 case PHASE_RANDOM:
256
257 /* Pick another random UID, and see if that works for us. */
258 random_bytes(&candidate, sizeof(candidate));
259 candidate = UID_CLAMP_INTO_RANGE(candidate);
260 break;
261
262 default:
263 assert_not_reached("unknown phase");
264 }
265
266 /* Make sure whatever we picked here actually is in the right range */
267 if (!uid_is_dynamic(candidate))
268 continue;
269
270 xsprintf(lock_path, "/run/systemd/dynamic-uid/" UID_FMT, candidate);
271
272 for (;;) {
273 struct stat st;
274
275 lock_fd = open(lock_path, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
276 if (lock_fd < 0)
277 return -errno;
278
279 r = flock(lock_fd, LOCK_EX|LOCK_NB); /* Try to get a BSD file lock on the UID lock file */
280 if (r < 0) {
281 if (IN_SET(errno, EBUSY, EAGAIN))
282 goto next; /* already in use */
283
284 return -errno;
285 }
286
287 if (fstat(lock_fd, &st) < 0)
288 return -errno;
289 if (st.st_nlink > 0)
290 break;
291
292 /* Oh, bummer, we got the lock, but the file was unlinked between the time we opened it and
293 * got the lock. Close it, and try again. */
294 lock_fd = safe_close(lock_fd);
295 }
296
297 /* Some superficial check whether this UID/GID might already be taken by some static user */
298 if (getpwuid(candidate) ||
299 getgrgid((gid_t) candidate) ||
300 search_ipc(candidate, (gid_t) candidate) != 0) {
301 (void) unlink(lock_path);
302 continue;
303 }
304
305 /* Let's store the user name in the lock file, so that we can use it for looking up the username for a UID */
306 l = pwritev(lock_fd,
307 (struct iovec[2]) {
308 IOVEC_INIT_STRING(name),
309 IOVEC_INIT((char[1]) { '\n' }, 1),
310 }, 2, 0);
311 if (l < 0) {
312 r = -errno;
313 (void) unlink(lock_path);
314 return r;
315 }
316
317 (void) ftruncate(lock_fd, l);
318 (void) make_uid_symlinks(candidate, name, true); /* also add direct lookup symlinks */
319
320 *ret_uid = candidate;
321 r = lock_fd;
322 lock_fd = -1;
323
324 return r;
325
326 next:
327 ;
328 }
329 }
330
331 static int dynamic_user_pop(DynamicUser *d, uid_t *ret_uid, int *ret_lock_fd) {
332 uid_t uid = UID_INVALID;
333 struct iovec iov = IOVEC_INIT(&uid, sizeof(uid));
334 union {
335 struct cmsghdr cmsghdr;
336 uint8_t buf[CMSG_SPACE(sizeof(int))];
337 } control = {};
338 struct msghdr mh = {
339 .msg_control = &control,
340 .msg_controllen = sizeof(control),
341 .msg_iov = &iov,
342 .msg_iovlen = 1,
343 };
344 struct cmsghdr *cmsg;
345
346 ssize_t k;
347 int lock_fd = -1;
348
349 assert(d);
350 assert(ret_uid);
351 assert(ret_lock_fd);
352
353 /* Read the UID and lock fd that is stored in the storage AF_UNIX socket. This should be called with the lock
354 * on the socket taken. */
355
356 k = recvmsg(d->storage_socket[0], &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
357 if (k < 0)
358 return -errno;
359
360 cmsg = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
361 if (cmsg)
362 lock_fd = *(int*) CMSG_DATA(cmsg);
363 else
364 cmsg_close_all(&mh); /* just in case... */
365
366 *ret_uid = uid;
367 *ret_lock_fd = lock_fd;
368
369 return 0;
370 }
371
372 static int dynamic_user_push(DynamicUser *d, uid_t uid, int lock_fd) {
373 struct iovec iov = IOVEC_INIT(&uid, sizeof(uid));
374 union {
375 struct cmsghdr cmsghdr;
376 uint8_t buf[CMSG_SPACE(sizeof(int))];
377 } control = {};
378 struct msghdr mh = {
379 .msg_control = &control,
380 .msg_controllen = sizeof(control),
381 .msg_iov = &iov,
382 .msg_iovlen = 1,
383 };
384 ssize_t k;
385
386 assert(d);
387
388 /* Store the UID and lock_fd in the storage socket. This should be called with the socket pair lock taken. */
389
390 if (lock_fd >= 0) {
391 struct cmsghdr *cmsg;
392
393 cmsg = CMSG_FIRSTHDR(&mh);
394 cmsg->cmsg_level = SOL_SOCKET;
395 cmsg->cmsg_type = SCM_RIGHTS;
396 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
397 memcpy(CMSG_DATA(cmsg), &lock_fd, sizeof(int));
398
399 mh.msg_controllen = CMSG_SPACE(sizeof(int));
400 } else {
401 mh.msg_control = NULL;
402 mh.msg_controllen = 0;
403 }
404
405 k = sendmsg(d->storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
406 if (k < 0)
407 return -errno;
408
409 return 0;
410 }
411
412 static void unlink_uid_lock(int lock_fd, uid_t uid, const char *name) {
413 char lock_path[strlen("/run/systemd/dynamic-uid/") + DECIMAL_STR_MAX(uid_t) + 1];
414
415 if (lock_fd < 0)
416 return;
417
418 xsprintf(lock_path, "/run/systemd/dynamic-uid/" UID_FMT, uid);
419 (void) unlink(lock_path);
420
421 (void) make_uid_symlinks(uid, name, false); /* remove direct lookup symlinks */
422 }
423
424 static int dynamic_user_realize(DynamicUser *d, char **suggested_dirs, uid_t *ret, bool is_user) {
425
426 _cleanup_close_ int etc_passwd_lock_fd = -1, uid_lock_fd = -1;
427 uid_t uid = UID_INVALID;
428 int r;
429
430 assert(d);
431
432 /* Acquire a UID for the user name. This will allocate a UID for the user name if the user doesn't exist
433 * yet. If it already exists its existing UID/GID will be reused. */
434
435 if (lockf(d->storage_socket[0], F_LOCK, 0) < 0)
436 return -errno;
437
438 r = dynamic_user_pop(d, &uid, &uid_lock_fd);
439 if (r < 0) {
440 int new_uid_lock_fd;
441 uid_t new_uid;
442
443 if (r != -EAGAIN)
444 goto finish;
445
446 /* OK, nothing stored yet, let's try to find something useful. While we are working on this release the
447 * lock however, so that nobody else blocks on our NSS lookups. */
448 (void) lockf(d->storage_socket[0], F_ULOCK, 0);
449
450 /* Let's see if a proper, static user or group by this name exists. Try to take the lock on
451 * /etc/passwd, if that fails with EROFS then /etc is read-only. In that case it's fine if we don't
452 * take the lock, given that users can't be added there anyway in this case. */
453 etc_passwd_lock_fd = take_etc_passwd_lock(NULL);
454 if (etc_passwd_lock_fd < 0 && etc_passwd_lock_fd != -EROFS)
455 return etc_passwd_lock_fd;
456
457 /* First, let's parse this as numeric UID */
458 r = parse_uid(d->name, &uid);
459 if (r < 0) {
460 struct passwd *p;
461 struct group *g;
462
463 if (is_user) {
464 /* OK, this is not a numeric UID. Let's see if there's a user by this name */
465 p = getpwnam(d->name);
466 if (p)
467 uid = p->pw_uid;
468 else {
469 /* if the user does not exist but the group with the same name exists, refuse operation */
470 g = getgrnam(d->name);
471 if (g)
472 return -EILSEQ;
473 }
474 } else {
475 /* Let's see if there's a group by this name */
476 g = getgrnam(d->name);
477 if (g)
478 uid = (uid_t) g->gr_gid;
479 else {
480 /* if the group does not exist but the user with the same name exists, refuse operation */
481 p = getpwnam(d->name);
482 if (p)
483 return -EILSEQ;
484 }
485 }
486 }
487
488 if (uid == UID_INVALID) {
489 /* No static UID assigned yet, excellent. Let's pick a new dynamic one, and lock it. */
490
491 uid_lock_fd = pick_uid(suggested_dirs, d->name, &uid);
492 if (uid_lock_fd < 0)
493 return uid_lock_fd;
494 }
495
496 /* So, we found a working UID/lock combination. Let's see if we actually still need it. */
497 if (lockf(d->storage_socket[0], F_LOCK, 0) < 0) {
498 unlink_uid_lock(uid_lock_fd, uid, d->name);
499 return -errno;
500 }
501
502 r = dynamic_user_pop(d, &new_uid, &new_uid_lock_fd);
503 if (r < 0) {
504 if (r != -EAGAIN) {
505 /* OK, something bad happened, let's get rid of the bits we acquired. */
506 unlink_uid_lock(uid_lock_fd, uid, d->name);
507 goto finish;
508 }
509
510 /* Great! Nothing is stored here, still. Store our newly acquired data. */
511 } else {
512 /* Hmm, so as it appears there's now something stored in the storage socket. Throw away what we
513 * acquired, and use what's stored now. */
514
515 unlink_uid_lock(uid_lock_fd, uid, d->name);
516 safe_close(uid_lock_fd);
517
518 uid = new_uid;
519 uid_lock_fd = new_uid_lock_fd;
520 }
521 }
522
523 /* If the UID/GID was already allocated dynamically, push the data we popped out back in. If it was already
524 * allocated statically, push the UID back too, but do not push the lock fd in. If we allocated the UID
525 * dynamically right here, push that in along with the lock fd for it. */
526 r = dynamic_user_push(d, uid, uid_lock_fd);
527 if (r < 0)
528 goto finish;
529
530 *ret = uid;
531 r = 0;
532
533 finish:
534 (void) lockf(d->storage_socket[0], F_ULOCK, 0);
535 return r;
536 }
537
538 static int dynamic_user_current(DynamicUser *d, uid_t *ret) {
539 _cleanup_close_ int lock_fd = -1;
540 uid_t uid;
541 int r;
542
543 assert(d);
544 assert(ret);
545
546 /* Get the currently assigned UID for the user, if there's any. This simply pops the data from the storage socket, and pushes it back in right-away. */
547
548 if (lockf(d->storage_socket[0], F_LOCK, 0) < 0)
549 return -errno;
550
551 r = dynamic_user_pop(d, &uid, &lock_fd);
552 if (r < 0)
553 goto finish;
554
555 r = dynamic_user_push(d, uid, lock_fd);
556 if (r < 0)
557 goto finish;
558
559 *ret = uid;
560 r = 0;
561
562 finish:
563 (void) lockf(d->storage_socket[0], F_ULOCK, 0);
564 return r;
565 }
566
567 static DynamicUser* dynamic_user_ref(DynamicUser *d) {
568 if (!d)
569 return NULL;
570
571 assert(d->n_ref > 0);
572 d->n_ref++;
573
574 return d;
575 }
576
577 static DynamicUser* dynamic_user_unref(DynamicUser *d) {
578 if (!d)
579 return NULL;
580
581 /* Note that this doesn't actually release any resources itself. If a dynamic user should be fully destroyed
582 * and its UID released, use dynamic_user_destroy() instead. NB: the dynamic user table may contain entries
583 * with no references, which is commonly the case right before a daemon reload. */
584
585 assert(d->n_ref > 0);
586 d->n_ref--;
587
588 return NULL;
589 }
590
591 static int dynamic_user_close(DynamicUser *d) {
592 _cleanup_close_ int lock_fd = -1;
593 uid_t uid;
594 int r;
595
596 /* Release the user ID, by releasing the lock on it, and emptying the storage socket. After this the user is
597 * unrealized again, much like it was after it the DynamicUser object was first allocated. */
598
599 if (lockf(d->storage_socket[0], F_LOCK, 0) < 0)
600 return -errno;
601
602 r = dynamic_user_pop(d, &uid, &lock_fd);
603 if (r == -EAGAIN) {
604 /* User wasn't realized yet, nothing to do. */
605 r = 0;
606 goto finish;
607 }
608 if (r < 0)
609 goto finish;
610
611 /* This dynamic user was realized and dynamically allocated. In this case, let's remove the lock file. */
612 unlink_uid_lock(lock_fd, uid, d->name);
613 r = 1;
614
615 finish:
616 (void) lockf(d->storage_socket[0], F_ULOCK, 0);
617 return r;
618 }
619
620 static DynamicUser* dynamic_user_destroy(DynamicUser *d) {
621 if (!d)
622 return NULL;
623
624 /* Drop a reference to a DynamicUser object, and destroy the user completely if this was the last
625 * reference. This is called whenever a service is shut down and wants its dynamic UID gone. Note that
626 * dynamic_user_unref() is what is called whenever a service is simply freed, for example during a reload
627 * cycle, where the dynamic users should not be destroyed, but our datastructures should. */
628
629 dynamic_user_unref(d);
630
631 if (d->n_ref > 0)
632 return NULL;
633
634 (void) dynamic_user_close(d);
635 return dynamic_user_free(d);
636 }
637
638 int dynamic_user_serialize(Manager *m, FILE *f, FDSet *fds) {
639 DynamicUser *d;
640 Iterator i;
641
642 assert(m);
643 assert(f);
644 assert(fds);
645
646 /* Dump the dynamic user database into the manager serialization, to deal with daemon reloads. */
647
648 HASHMAP_FOREACH(d, m->dynamic_users, i) {
649 int copy0, copy1;
650
651 copy0 = fdset_put_dup(fds, d->storage_socket[0]);
652 if (copy0 < 0)
653 return copy0;
654
655 copy1 = fdset_put_dup(fds, d->storage_socket[1]);
656 if (copy1 < 0)
657 return copy1;
658
659 fprintf(f, "dynamic-user=%s %i %i\n", d->name, copy0, copy1);
660 }
661
662 return 0;
663 }
664
665 void dynamic_user_deserialize_one(Manager *m, const char *value, FDSet *fds) {
666 _cleanup_free_ char *name = NULL, *s0 = NULL, *s1 = NULL;
667 int r, fd0, fd1;
668
669 assert(m);
670 assert(value);
671 assert(fds);
672
673 /* Parse the serialization again, after a daemon reload */
674
675 r = extract_many_words(&value, NULL, 0, &name, &s0, &s1, NULL);
676 if (r != 3 || !isempty(value)) {
677 log_debug("Unable to parse dynamic user line.");
678 return;
679 }
680
681 if (safe_atoi(s0, &fd0) < 0 || !fdset_contains(fds, fd0)) {
682 log_debug("Unable to process dynamic user fd specification.");
683 return;
684 }
685
686 if (safe_atoi(s1, &fd1) < 0 || !fdset_contains(fds, fd1)) {
687 log_debug("Unable to process dynamic user fd specification.");
688 return;
689 }
690
691 r = dynamic_user_add(m, name, (int[]) { fd0, fd1 }, NULL);
692 if (r < 0) {
693 log_debug_errno(r, "Failed to add dynamic user: %m");
694 return;
695 }
696
697 (void) fdset_remove(fds, fd0);
698 (void) fdset_remove(fds, fd1);
699 }
700
701 void dynamic_user_vacuum(Manager *m, bool close_user) {
702 DynamicUser *d;
703 Iterator i;
704
705 assert(m);
706
707 /* Empty the dynamic user database, optionally cleaning up orphaned dynamic users, i.e. destroy and free users
708 * to which no reference exist. This is called after a daemon reload finished, in order to destroy users which
709 * might not be referenced anymore. */
710
711 HASHMAP_FOREACH(d, m->dynamic_users, i) {
712 if (d->n_ref > 0)
713 continue;
714
715 if (close_user) {
716 log_debug("Removing orphaned dynamic user %s", d->name);
717 (void) dynamic_user_close(d);
718 }
719
720 dynamic_user_free(d);
721 }
722 }
723
724 int dynamic_user_lookup_uid(Manager *m, uid_t uid, char **ret) {
725 char lock_path[strlen("/run/systemd/dynamic-uid/") + DECIMAL_STR_MAX(uid_t) + 1];
726 _cleanup_free_ char *user = NULL;
727 uid_t check_uid;
728 int r;
729
730 assert(m);
731 assert(ret);
732
733 /* A friendly way to translate a dynamic user's UID into a name. */
734 if (!uid_is_dynamic(uid))
735 return -ESRCH;
736
737 xsprintf(lock_path, "/run/systemd/dynamic-uid/" UID_FMT, uid);
738 r = read_one_line_file(lock_path, &user);
739 if (r == -ENOENT)
740 return -ESRCH;
741 if (r < 0)
742 return r;
743
744 /* The lock file might be stale, hence let's verify the data before we return it */
745 r = dynamic_user_lookup_name(m, user, &check_uid);
746 if (r < 0)
747 return r;
748 if (check_uid != uid) /* lock file doesn't match our own idea */
749 return -ESRCH;
750
751 *ret = user;
752 user = NULL;
753
754 return 0;
755 }
756
757 int dynamic_user_lookup_name(Manager *m, const char *name, uid_t *ret) {
758 DynamicUser *d;
759 int r;
760
761 assert(m);
762 assert(name);
763 assert(ret);
764
765 /* A friendly call for translating a dynamic user's name into its UID */
766
767 d = hashmap_get(m->dynamic_users, name);
768 if (!d)
769 return -ESRCH;
770
771 r = dynamic_user_current(d, ret);
772 if (r == -EAGAIN) /* not realized yet? */
773 return -ESRCH;
774
775 return r;
776 }
777
778 int dynamic_creds_acquire(DynamicCreds *creds, Manager *m, const char *user, const char *group) {
779 bool acquired = false;
780 int r;
781
782 assert(creds);
783 assert(m);
784
785 /* A DynamicUser object encapsulates an allocation of both a UID and a GID for a specific name. However, some
786 * services use different user and groups. For cases like that there's DynamicCreds containing a pair of user
787 * and group. This call allocates a pair. */
788
789 if (!creds->user && user) {
790 r = dynamic_user_acquire(m, user, &creds->user);
791 if (r < 0)
792 return r;
793
794 acquired = true;
795 }
796
797 if (!creds->group) {
798
799 if (creds->user && (!group || streq_ptr(user, group)))
800 creds->group = dynamic_user_ref(creds->user);
801 else {
802 r = dynamic_user_acquire(m, group, &creds->group);
803 if (r < 0) {
804 if (acquired)
805 creds->user = dynamic_user_unref(creds->user);
806 return r;
807 }
808 }
809 }
810
811 return 0;
812 }
813
814 int dynamic_creds_realize(DynamicCreds *creds, char **suggested_paths, uid_t *uid, gid_t *gid) {
815 uid_t u = UID_INVALID;
816 gid_t g = GID_INVALID;
817 int r;
818
819 assert(creds);
820 assert(uid);
821 assert(gid);
822
823 /* Realize both the referenced user and group */
824
825 if (creds->user) {
826 r = dynamic_user_realize(creds->user, suggested_paths, &u, true);
827 if (r < 0)
828 return r;
829 }
830
831 if (creds->group && creds->group != creds->user) {
832 r = dynamic_user_realize(creds->group, suggested_paths, &g, false);
833 if (r < 0)
834 return r;
835 } else
836 g = u;
837
838 *uid = u;
839 *gid = g;
840
841 return 0;
842 }
843
844 void dynamic_creds_unref(DynamicCreds *creds) {
845 assert(creds);
846
847 creds->user = dynamic_user_unref(creds->user);
848 creds->group = dynamic_user_unref(creds->group);
849 }
850
851 void dynamic_creds_destroy(DynamicCreds *creds) {
852 assert(creds);
853
854 creds->user = dynamic_user_destroy(creds->user);
855 creds->group = dynamic_user_destroy(creds->group);
856 }