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