]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dynamic-user.c
Merge pull request #7123 from keszybz/date-formatting
[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 lockfp(int fd, int *fd_lock) {
425 if (lockf(fd, F_LOCK, 0) < 0)
426 return -errno;
427 *fd_lock = fd;
428 return 0;
429 }
430
431 static void unlockfp(int *fd_lock) {
432 if (*fd_lock < 0)
433 return;
434 lockf(*fd_lock, F_ULOCK, 0);
435 *fd_lock = -1;
436 }
437
438 static int dynamic_user_realize(
439 DynamicUser *d,
440 char **suggested_dirs,
441 uid_t *ret_uid, gid_t *ret_gid,
442 bool is_user) {
443
444 _cleanup_(unlockfp) int storage_socket0_lock = -1;
445 _cleanup_close_ int uid_lock_fd = -1;
446 _cleanup_close_ int etc_passwd_lock_fd = -1;
447 uid_t num = UID_INVALID; /* a uid if is_user, and a gid otherwise */
448 gid_t gid = GID_INVALID; /* a gid if is_user, ignored otherwise */
449 int r;
450
451 assert(d);
452 assert(is_user == !!ret_uid);
453 assert(ret_gid);
454
455 /* Acquire a UID for the user name. This will allocate a UID for the user name if the user doesn't exist
456 * yet. If it already exists its existing UID/GID will be reused. */
457
458 r = lockfp(d->storage_socket[0], &storage_socket0_lock);
459 if (r < 0)
460 return r;
461
462 r = dynamic_user_pop(d, &num, &uid_lock_fd);
463 if (r < 0) {
464 int new_uid_lock_fd;
465 uid_t new_uid;
466
467 if (r != -EAGAIN)
468 return r;
469
470 /* OK, nothing stored yet, let's try to find something useful. While we are working on this release the
471 * lock however, so that nobody else blocks on our NSS lookups. */
472 unlockfp(&storage_socket0_lock);
473
474 /* Let's see if a proper, static user or group by this name exists. Try to take the lock on
475 * /etc/passwd, if that fails with EROFS then /etc is read-only. In that case it's fine if we don't
476 * take the lock, given that users can't be added there anyway in this case. */
477 etc_passwd_lock_fd = take_etc_passwd_lock(NULL);
478 if (etc_passwd_lock_fd < 0 && etc_passwd_lock_fd != -EROFS)
479 return etc_passwd_lock_fd;
480
481 /* First, let's parse this as numeric UID */
482 r = parse_uid(d->name, &num);
483 if (r < 0) {
484 struct passwd *p;
485 struct group *g;
486
487 if (is_user) {
488 /* OK, this is not a numeric UID. Let's see if there's a user by this name */
489 p = getpwnam(d->name);
490 if (p) {
491 num = p->pw_uid;
492 gid = p->pw_gid;
493 } else {
494 /* if the user does not exist but the group with the same name exists, refuse operation */
495 g = getgrnam(d->name);
496 if (g)
497 return -EILSEQ;
498 }
499 } else {
500 /* Let's see if there's a group by this name */
501 g = getgrnam(d->name);
502 if (g)
503 num = (uid_t) g->gr_gid;
504 else {
505 /* if the group does not exist but the user with the same name exists, refuse operation */
506 p = getpwnam(d->name);
507 if (p)
508 return -EILSEQ;
509 }
510 }
511 }
512
513 if (num == UID_INVALID) {
514 /* No static UID assigned yet, excellent. Let's pick a new dynamic one, and lock it. */
515
516 uid_lock_fd = pick_uid(suggested_dirs, d->name, &num);
517 if (uid_lock_fd < 0)
518 return uid_lock_fd;
519 }
520
521 /* So, we found a working UID/lock combination. Let's see if we actually still need it. */
522 r = lockfp(d->storage_socket[0], &storage_socket0_lock);
523 if (r < 0) {
524 unlink_uid_lock(uid_lock_fd, num, d->name);
525 return r;
526 }
527
528 r = dynamic_user_pop(d, &new_uid, &new_uid_lock_fd);
529 if (r < 0) {
530 if (r != -EAGAIN) {
531 /* OK, something bad happened, let's get rid of the bits we acquired. */
532 unlink_uid_lock(uid_lock_fd, num, d->name);
533 return r;
534 }
535
536 /* Great! Nothing is stored here, still. Store our newly acquired data. */
537 } else {
538 /* Hmm, so as it appears there's now something stored in the storage socket. Throw away what we
539 * acquired, and use what's stored now. */
540
541 unlink_uid_lock(uid_lock_fd, num, d->name);
542 safe_close(uid_lock_fd);
543
544 num = new_uid;
545 uid_lock_fd = new_uid_lock_fd;
546 }
547 }
548
549 /* If the UID/GID was already allocated dynamically, push the data we popped out back in. If it was already
550 * allocated statically, push the UID back too, but do not push the lock fd in. If we allocated the UID
551 * dynamically right here, push that in along with the lock fd for it. */
552 r = dynamic_user_push(d, num, uid_lock_fd);
553 if (r < 0)
554 return r;
555
556 if (is_user) {
557 *ret_uid = num;
558 *ret_gid = gid != GID_INVALID ? gid : num;
559 } else
560 *ret_gid = num;
561
562 return 0;
563 }
564
565 static int dynamic_user_current(DynamicUser *d, uid_t *ret) {
566 _cleanup_(unlockfp) int storage_socket0_lock = -1;
567 _cleanup_close_ int lock_fd = -1;
568 uid_t uid;
569 int r;
570
571 assert(d);
572 assert(ret);
573
574 /* 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. */
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 < 0)
582 return r;
583
584 r = dynamic_user_push(d, uid, lock_fd);
585 if (r < 0)
586 return r;
587
588 *ret = uid;
589 return 0;
590 }
591
592 static DynamicUser* dynamic_user_ref(DynamicUser *d) {
593 if (!d)
594 return NULL;
595
596 assert(d->n_ref > 0);
597 d->n_ref++;
598
599 return d;
600 }
601
602 static DynamicUser* dynamic_user_unref(DynamicUser *d) {
603 if (!d)
604 return NULL;
605
606 /* Note that this doesn't actually release any resources itself. If a dynamic user should be fully destroyed
607 * and its UID released, use dynamic_user_destroy() instead. NB: the dynamic user table may contain entries
608 * with no references, which is commonly the case right before a daemon reload. */
609
610 assert(d->n_ref > 0);
611 d->n_ref--;
612
613 return NULL;
614 }
615
616 static int dynamic_user_close(DynamicUser *d) {
617 _cleanup_(unlockfp) int storage_socket0_lock = -1;
618 _cleanup_close_ int lock_fd = -1;
619 uid_t uid;
620 int r;
621
622 /* Release the user ID, by releasing the lock on it, and emptying the storage socket. After this the user is
623 * unrealized again, much like it was after it the DynamicUser object was first allocated. */
624
625 r = lockfp(d->storage_socket[0], &storage_socket0_lock);
626 if (r < 0)
627 return r;
628
629 r = dynamic_user_pop(d, &uid, &lock_fd);
630 if (r == -EAGAIN)
631 /* User wasn't realized yet, nothing to do. */
632 return 0;
633 if (r < 0)
634 return r;
635
636 /* This dynamic user was realized and dynamically allocated. In this case, let's remove the lock file. */
637 unlink_uid_lock(lock_fd, uid, d->name);
638 return 1;
639 }
640
641 static DynamicUser* dynamic_user_destroy(DynamicUser *d) {
642 if (!d)
643 return NULL;
644
645 /* Drop a reference to a DynamicUser object, and destroy the user completely if this was the last
646 * reference. This is called whenever a service is shut down and wants its dynamic UID gone. Note that
647 * dynamic_user_unref() is what is called whenever a service is simply freed, for example during a reload
648 * cycle, where the dynamic users should not be destroyed, but our datastructures should. */
649
650 dynamic_user_unref(d);
651
652 if (d->n_ref > 0)
653 return NULL;
654
655 (void) dynamic_user_close(d);
656 return dynamic_user_free(d);
657 }
658
659 int dynamic_user_serialize(Manager *m, FILE *f, FDSet *fds) {
660 DynamicUser *d;
661 Iterator i;
662
663 assert(m);
664 assert(f);
665 assert(fds);
666
667 /* Dump the dynamic user database into the manager serialization, to deal with daemon reloads. */
668
669 HASHMAP_FOREACH(d, m->dynamic_users, i) {
670 int copy0, copy1;
671
672 copy0 = fdset_put_dup(fds, d->storage_socket[0]);
673 if (copy0 < 0)
674 return copy0;
675
676 copy1 = fdset_put_dup(fds, d->storage_socket[1]);
677 if (copy1 < 0)
678 return copy1;
679
680 fprintf(f, "dynamic-user=%s %i %i\n", d->name, copy0, copy1);
681 }
682
683 return 0;
684 }
685
686 void dynamic_user_deserialize_one(Manager *m, const char *value, FDSet *fds) {
687 _cleanup_free_ char *name = NULL, *s0 = NULL, *s1 = NULL;
688 int r, fd0, fd1;
689
690 assert(m);
691 assert(value);
692 assert(fds);
693
694 /* Parse the serialization again, after a daemon reload */
695
696 r = extract_many_words(&value, NULL, 0, &name, &s0, &s1, NULL);
697 if (r != 3 || !isempty(value)) {
698 log_debug("Unable to parse dynamic user line.");
699 return;
700 }
701
702 if (safe_atoi(s0, &fd0) < 0 || !fdset_contains(fds, fd0)) {
703 log_debug("Unable to process dynamic user fd specification.");
704 return;
705 }
706
707 if (safe_atoi(s1, &fd1) < 0 || !fdset_contains(fds, fd1)) {
708 log_debug("Unable to process dynamic user fd specification.");
709 return;
710 }
711
712 r = dynamic_user_add(m, name, (int[]) { fd0, fd1 }, NULL);
713 if (r < 0) {
714 log_debug_errno(r, "Failed to add dynamic user: %m");
715 return;
716 }
717
718 (void) fdset_remove(fds, fd0);
719 (void) fdset_remove(fds, fd1);
720 }
721
722 void dynamic_user_vacuum(Manager *m, bool close_user) {
723 DynamicUser *d;
724 Iterator i;
725
726 assert(m);
727
728 /* Empty the dynamic user database, optionally cleaning up orphaned dynamic users, i.e. destroy and free users
729 * to which no reference exist. This is called after a daemon reload finished, in order to destroy users which
730 * might not be referenced anymore. */
731
732 HASHMAP_FOREACH(d, m->dynamic_users, i) {
733 if (d->n_ref > 0)
734 continue;
735
736 if (close_user) {
737 log_debug("Removing orphaned dynamic user %s", d->name);
738 (void) dynamic_user_close(d);
739 }
740
741 dynamic_user_free(d);
742 }
743 }
744
745 int dynamic_user_lookup_uid(Manager *m, uid_t uid, char **ret) {
746 char lock_path[strlen("/run/systemd/dynamic-uid/") + DECIMAL_STR_MAX(uid_t) + 1];
747 _cleanup_free_ char *user = NULL;
748 uid_t check_uid;
749 int r;
750
751 assert(m);
752 assert(ret);
753
754 /* A friendly way to translate a dynamic user's UID into a name. */
755 if (!uid_is_dynamic(uid))
756 return -ESRCH;
757
758 xsprintf(lock_path, "/run/systemd/dynamic-uid/" UID_FMT, uid);
759 r = read_one_line_file(lock_path, &user);
760 if (r == -ENOENT)
761 return -ESRCH;
762 if (r < 0)
763 return r;
764
765 /* The lock file might be stale, hence let's verify the data before we return it */
766 r = dynamic_user_lookup_name(m, user, &check_uid);
767 if (r < 0)
768 return r;
769 if (check_uid != uid) /* lock file doesn't match our own idea */
770 return -ESRCH;
771
772 *ret = user;
773 user = NULL;
774
775 return 0;
776 }
777
778 int dynamic_user_lookup_name(Manager *m, const char *name, uid_t *ret) {
779 DynamicUser *d;
780 int r;
781
782 assert(m);
783 assert(name);
784 assert(ret);
785
786 /* A friendly call for translating a dynamic user's name into its UID */
787
788 d = hashmap_get(m->dynamic_users, name);
789 if (!d)
790 return -ESRCH;
791
792 r = dynamic_user_current(d, ret);
793 if (r == -EAGAIN) /* not realized yet? */
794 return -ESRCH;
795
796 return r;
797 }
798
799 int dynamic_creds_acquire(DynamicCreds *creds, Manager *m, const char *user, const char *group) {
800 bool acquired = false;
801 int r;
802
803 assert(creds);
804 assert(m);
805
806 /* A DynamicUser object encapsulates an allocation of both a UID and a GID for a specific name. However, some
807 * services use different user and groups. For cases like that there's DynamicCreds containing a pair of user
808 * and group. This call allocates a pair. */
809
810 if (!creds->user && user) {
811 r = dynamic_user_acquire(m, user, &creds->user);
812 if (r < 0)
813 return r;
814
815 acquired = true;
816 }
817
818 if (!creds->group) {
819
820 if (creds->user && (!group || streq_ptr(user, group)))
821 creds->group = dynamic_user_ref(creds->user);
822 else {
823 r = dynamic_user_acquire(m, group, &creds->group);
824 if (r < 0) {
825 if (acquired)
826 creds->user = dynamic_user_unref(creds->user);
827 return r;
828 }
829 }
830 }
831
832 return 0;
833 }
834
835 int dynamic_creds_realize(DynamicCreds *creds, char **suggested_paths, uid_t *uid, gid_t *gid) {
836 uid_t u = UID_INVALID;
837 gid_t g = GID_INVALID;
838 int r;
839
840 assert(creds);
841 assert(uid);
842 assert(gid);
843
844 /* Realize both the referenced user and group */
845
846 if (creds->user) {
847 r = dynamic_user_realize(creds->user, suggested_paths, &u, &g, true);
848 if (r < 0)
849 return r;
850 }
851
852 if (creds->group && creds->group != creds->user) {
853 r = dynamic_user_realize(creds->group, suggested_paths, NULL, &g, false);
854 if (r < 0)
855 return r;
856 }
857
858 *uid = u;
859 *gid = g;
860 return 0;
861 }
862
863 void dynamic_creds_unref(DynamicCreds *creds) {
864 assert(creds);
865
866 creds->user = dynamic_user_unref(creds->user);
867 creds->group = dynamic_user_unref(creds->group);
868 }
869
870 void dynamic_creds_destroy(DynamicCreds *creds) {
871 assert(creds);
872
873 creds->user = dynamic_user_destroy(creds->user);
874 creds->group = dynamic_user_destroy(creds->group);
875 }