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