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