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