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