Bug Summary

File:build-scan/../src/sysusers/sysusers.c
Warning:line 84, column 23
Null pointer passed to 1st parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sysusers.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-sysusers.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/sysusers/sysusers.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <getopt.h>
4#include <utmp.h>
5
6#include "alloc-util.h"
7#include "conf-files.h"
8#include "copy.h"
9#include "def.h"
10#include "fd-util.h"
11#include "fileio-label.h"
12#include "format-util.h"
13#include "fs-util.h"
14#include "hashmap.h"
15#include "pager.h"
16#include "path-util.h"
17#include "selinux-util.h"
18#include "smack-util.h"
19#include "specifier.h"
20#include "string-util.h"
21#include "strv.h"
22#include "terminal-util.h"
23#include "uid-range.h"
24#include "user-util.h"
25#include "utf8.h"
26#include "util.h"
27
28typedef enum ItemType {
29 ADD_USER = 'u',
30 ADD_GROUP = 'g',
31 ADD_MEMBER = 'm',
32 ADD_RANGE = 'r',
33} ItemType;
34
35typedef struct Item {
36 ItemType type;
37
38 char *name;
39 char *uid_path;
40 char *gid_path;
41 char *description;
42 char *home;
43 char *shell;
44
45 gid_t gid;
46 uid_t uid;
47
48 bool_Bool gid_set:1;
49
50 /* When set the group with the specified gid must exist
51 * and the check if a uid clashes with the gid is skipped.
52 */
53 bool_Bool id_set_strict:1;
54
55 bool_Bool uid_set:1;
56
57 bool_Bool todo_user:1;
58 bool_Bool todo_group:1;
59} Item;
60
61static char *arg_root = NULL((void*)0);
62static bool_Bool arg_cat_config = false0;
63static const char *arg_replace = NULL((void*)0);
64static bool_Bool arg_inline = false0;
65static bool_Bool arg_no_pager = false0;
66
67static OrderedHashmap *users = NULL((void*)0), *groups = NULL((void*)0);
68static OrderedHashmap *todo_uids = NULL((void*)0), *todo_gids = NULL((void*)0);
69static OrderedHashmap *members = NULL((void*)0);
70
71static Hashmap *database_uid = NULL((void*)0), *database_user = NULL((void*)0);
72static Hashmap *database_gid = NULL((void*)0), *database_group = NULL((void*)0);
73
74static uid_t search_uid = UID_INVALID((uid_t) -1);
75static UidRange *uid_range = NULL((void*)0);
76static unsigned n_uid_range = 0;
77
78static int load_user_database(void) {
79 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
80 const char *passwd_path;
81 struct passwd *pw;
82 int r;
83
84 passwd_path = prefix_roota(arg_root, "/etc/passwd")({ const char* _path = ("/etc/passwd"), *_root = (arg_root), *
_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' &&
_path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path
; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
17
'_root' initialized to a null pointer value
18
Loop condition is false. Execution continues on line 84
19
Assuming the condition is false
20
Taking false branch
21
Null pointer passed to 1st parameter expecting 'nonnull'
85 f = fopen(passwd_path, "re");
86 if (!f)
87 return errno(*__errno_location ()) == ENOENT2 ? 0 : -errno(*__errno_location ());
88
89 r = hashmap_ensure_allocated(&database_user, &string_hash_ops)internal_hashmap_ensure_allocated(&database_user, &string_hash_ops
)
;
90 if (r < 0)
91 return r;
92
93 r = hashmap_ensure_allocated(&database_uid, NULL)internal_hashmap_ensure_allocated(&database_uid, ((void*)
0) )
;
94 if (r < 0)
95 return r;
96
97 while ((r = fgetpwent_sane(f, &pw)) > 0) {
98 char *n;
99 int k, q;
100
101 n = strdup(pw->pw_name);
102 if (!n)
103 return -ENOMEM12;
104
105 k = hashmap_put(database_user, n, UID_TO_PTR(pw->pw_uid)((void*) (((uintptr_t) (pw->pw_uid))+1)));
106 if (k < 0 && k != -EEXIST17) {
107 free(n);
108 return k;
109 }
110
111 q = hashmap_put(database_uid, UID_TO_PTR(pw->pw_uid)((void*) (((uintptr_t) (pw->pw_uid))+1)), n);
112 if (q < 0 && q != -EEXIST17) {
113 if (k <= 0)
114 free(n);
115 return q;
116 }
117
118 if (k <= 0 && q <= 0)
119 free(n);
120 }
121 return r;
122}
123
124static int load_group_database(void) {
125 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
126 const char *group_path;
127 struct group *gr;
128 int r;
129
130 group_path = prefix_roota(arg_root, "/etc/group")({ const char* _path = ("/etc/group"), *_root = (arg_root), *
_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' &&
_path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path
; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
131 f = fopen(group_path, "re");
132 if (!f)
133 return errno(*__errno_location ()) == ENOENT2 ? 0 : -errno(*__errno_location ());
134
135 r = hashmap_ensure_allocated(&database_group, &string_hash_ops)internal_hashmap_ensure_allocated(&database_group, &string_hash_ops
)
;
136 if (r < 0)
137 return r;
138
139 r = hashmap_ensure_allocated(&database_gid, NULL)internal_hashmap_ensure_allocated(&database_gid, ((void*)
0) )
;
140 if (r < 0)
141 return r;
142
143 errno(*__errno_location ()) = 0;
144 while ((gr = fgetgrent(f))) {
145 char *n;
146 int k, q;
147
148 n = strdup(gr->gr_name);
149 if (!n)
150 return -ENOMEM12;
151
152 k = hashmap_put(database_group, n, GID_TO_PTR(gr->gr_gid)((void*) (((uintptr_t) (gr->gr_gid))+1)));
153 if (k < 0 && k != -EEXIST17) {
154 free(n);
155 return k;
156 }
157
158 q = hashmap_put(database_gid, GID_TO_PTR(gr->gr_gid)((void*) (((uintptr_t) (gr->gr_gid))+1)), n);
159 if (q < 0 && q != -EEXIST17) {
160 if (k <= 0)
161 free(n);
162 return q;
163 }
164
165 if (k <= 0 && q <= 0)
166 free(n);
167
168 errno(*__errno_location ()) = 0;
169 }
170 if (!IN_SET(errno, 0, ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 2})/sizeof(int)]; switch((*__errno_location
())) { case 0: case 2: _found = 1; break; default: break; } _found
; })
)
171 return -errno(*__errno_location ());
172
173 return 0;
174}
175
176static int make_backup(const char *target, const char *x) {
177 _cleanup_close___attribute__((cleanup(closep))) int src = -1;
178 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *dst = NULL((void*)0);
179 _cleanup_free___attribute__((cleanup(freep))) char *temp = NULL((void*)0);
180 char *backup;
181 struct timespec ts[2];
182 struct stat st;
183 int r;
184
185 src = open(x, O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400);
186 if (src < 0) {
187 if (errno(*__errno_location ()) == ENOENT2) /* No backup necessary... */
188 return 0;
189
190 return -errno(*__errno_location ());
191 }
192
193 if (fstat(src, &st) < 0)
194 return -errno(*__errno_location ());
195
196 r = fopen_temporary_label(target, x, &dst, &temp);
197 if (r < 0)
198 return r;
199
200 r = copy_bytes(src, fileno(dst), (uint64_t) -1, COPY_REFLINK);
201 if (r < 0)
202 goto fail;
203
204 /* Don't fail on chmod() or chown(). If it stays owned by us
205 * and/or unreadable by others, then it isn't too bad... */
206
207 backup = strjoina(x, "-")({ const char *_appendees_[] = { x, "-" }; char *_d_, *_p_; size_t
_len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (
__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_
), typeof(&*(_appendees_))), sizeof(_appendees_)/sizeof((
_appendees_)[0]), ((void)0))) && _appendees_[_i_]; _i_
++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
208
209 /* Copy over the access mask */
210 r = fchmod_and_chown(fileno(dst), st.st_mode & 07777, st.st_uid, st.st_gid);
211 if (r < 0)
212 log_warning_errno(r, "Failed to change access mode or ownership of %s: %m", backup)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 212, __func__, "Failed to change access mode or ownership of %s: %m"
, backup) : -abs(_e); })
;
213
214 ts[0] = st.st_atim;
215 ts[1] = st.st_mtim;
216 if (futimens(fileno(dst), ts) < 0)
217 log_warning_errno(errno, "Failed to fix access and modification time of %s: %m", backup)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/sysusers/sysusers.c", 217, __func__
, "Failed to fix access and modification time of %s: %m", backup
) : -abs(_e); })
;
218
219 r = fflush_sync_and_check(dst);
220 if (r < 0)
221 goto fail;
222
223 if (rename(temp, backup) < 0) {
224 r = -errno(*__errno_location ());
225 goto fail;
226 }
227
228 return 0;
229
230fail:
231 unlink(temp);
232 return r;
233}
234
235static int putgrent_with_members(const struct group *gr, FILE *group) {
236 char **a;
237
238 assert(gr)do { if ((__builtin_expect(!!(!(gr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("gr"), "../src/sysusers/sysusers.c", 238
, __PRETTY_FUNCTION__); } while (0)
;
239 assert(group)do { if ((__builtin_expect(!!(!(group)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("group"), "../src/sysusers/sysusers.c", 239
, __PRETTY_FUNCTION__); } while (0)
;
240
241 a = ordered_hashmap_get(members, gr->gr_name);
242 if (a) {
243 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0);
244 bool_Bool added = false0;
245 char **i;
246
247 l = strv_copy(gr->gr_mem);
248 if (!l)
249 return -ENOMEM12;
250
251 STRV_FOREACH(i, a)for ((i) = (a); (i) && *(i); (i)++) {
252 if (strv_find(l, *i))
253 continue;
254
255 if (strv_extend(&l, *i) < 0)
256 return -ENOMEM12;
257
258 added = true1;
259 }
260
261 if (added) {
262 struct group t;
263 int r;
264
265 strv_uniq(l);
266 strv_sort(l);
267
268 t = *gr;
269 t.gr_mem = l;
270
271 r = putgrent_sane(&t, group);
272 return r < 0 ? r : 1;
273 }
274 }
275
276 return putgrent_sane(gr, group);
277}
278
279#if ENABLE_GSHADOW1
280static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
281 char **a;
282
283 assert(sg)do { if ((__builtin_expect(!!(!(sg)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("sg"), "../src/sysusers/sysusers.c", 283
, __PRETTY_FUNCTION__); } while (0)
;
284 assert(gshadow)do { if ((__builtin_expect(!!(!(gshadow)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("gshadow"), "../src/sysusers/sysusers.c"
, 284, __PRETTY_FUNCTION__); } while (0)
;
285
286 a = ordered_hashmap_get(members, sg->sg_namp);
287 if (a) {
288 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0);
289 bool_Bool added = false0;
290 char **i;
291
292 l = strv_copy(sg->sg_mem);
293 if (!l)
294 return -ENOMEM12;
295
296 STRV_FOREACH(i, a)for ((i) = (a); (i) && *(i); (i)++) {
297 if (strv_find(l, *i))
298 continue;
299
300 if (strv_extend(&l, *i) < 0)
301 return -ENOMEM12;
302
303 added = true1;
304 }
305
306 if (added) {
307 struct sgrp t;
308 int r;
309
310 strv_uniq(l);
311 strv_sort(l);
312
313 t = *sg;
314 t.sg_mem = l;
315
316 r = putsgent_sane(&t, gshadow);
317 return r < 0 ? r : 1;
318 }
319 }
320
321 return putsgent_sane(sg, gshadow);
322}
323#endif
324
325static int sync_rights(FILE *from, FILE *to) {
326 struct stat st;
327
328 if (fstat(fileno(from), &st) < 0)
329 return -errno(*__errno_location ());
330
331 return fchmod_and_chown(fileno(to), st.st_mode & 07777, st.st_uid, st.st_gid);
332}
333
334static int rename_and_apply_smack(const char *temp_path, const char *dest_path) {
335 int r = 0;
336 if (rename(temp_path, dest_path) < 0)
337 return -errno(*__errno_location ());
338
339#ifdef SMACK_RUN_LABEL
340 r = mac_smack_apply(dest_path, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL"_");
341 if (r < 0)
342 return r;
343#endif
344 return r;
345}
346
347static const char* default_shell(uid_t uid) {
348 return uid == 0 ? "/bin/sh" : "/sbin/nologin";
349}
350
351static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) {
352 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *original = NULL((void*)0), *passwd = NULL((void*)0);
353 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *passwd_tmp = NULL((void*)0);
354 struct passwd *pw = NULL((void*)0);
355 Iterator iterator;
356 Item *i;
357 int r;
358
359 if (ordered_hashmap_size(todo_uids) == 0)
360 return 0;
361
362 r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
363 if (r < 0)
364 return r;
365
366 original = fopen(passwd_path, "re");
367 if (original) {
368
369 r = sync_rights(original, passwd);
370 if (r < 0)
371 return r;
372
373 while ((r = fgetpwent_sane(original, &pw)) > 0) {
374
375 i = ordered_hashmap_get(users, pw->pw_name);
376 if (i && i->todo_user) {
377 log_error("%s: User \"%s\" already exists.", passwd_path, pw->pw_name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 377, __func__, "%s: User \"%s\" already exists."
, passwd_path, pw->pw_name) : -abs(_e); })
;
378 return -EEXIST17;
379 }
380
381 if (ordered_hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid)((void*) (((uintptr_t) (pw->pw_uid))+1)))) {
382 log_error("%s: Detected collision for UID " UID_FMT ".", passwd_path, pw->pw_uid)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 382, __func__, "%s: Detected collision for UID "
"%" "u" ".", passwd_path, pw->pw_uid) : -abs(_e); })
;
383 return -EEXIST17;
384 }
385
386 /* Make sure we keep the NIS entries (if any) at the end. */
387 if (IN_SET(pw->pw_name[0], '+', '-')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'+', '-'})/sizeof(int)]; switch(pw->pw_name
[0]) { case '+': case '-': _found = 1; break; default: break;
} _found; })
)
388 break;
389
390 r = putpwent_sane(pw, passwd);
391 if (r < 0)
392 return r;
393 }
394 if (r < 0)
395 return r;
396
397 } else {
398 if (errno(*__errno_location ()) != ENOENT2)
399 return -errno(*__errno_location ());
400 if (fchmod(fileno(passwd), 0644) < 0)
401 return -errno(*__errno_location ());
402 }
403
404 ORDERED_HASHMAP_FOREACH(i, todo_uids, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); ordered_hashmap_iterate((todo_uids
), &(iterator), (void**)&(i), ((void*)0)); )
{
405 struct passwd n = {
406 .pw_name = i->name,
407 .pw_uid = i->uid,
408 .pw_gid = i->gid,
409 .pw_gecos = i->description,
410
411 /* "x" means the password is stored in the shadow file */
412 .pw_passwd = (char*) "x",
413
414 /* We default to the root directory as home */
415 .pw_dir = i->home ? i->home : (char*) "/",
416
417 /* Initialize the shell to nologin, with one exception:
418 * for root we patch in something special */
419 .pw_shell = i->shell ?: (char*) default_shell(i->uid),
420 };
421
422 r = putpwent_sane(&n, passwd);
423 if (r < 0)
424 return r;
425 }
426
427 /* Append the remaining NIS entries if any */
428 while (pw) {
429 r = putpwent_sane(pw, passwd);
430 if (r < 0)
431 return r;
432
433 r = fgetpwent_sane(original, &pw);
434 if (r < 0)
435 return r;
436 if (r == 0)
437 break;
438 }
439
440 r = fflush_and_check(passwd);
441 if (r < 0)
442 return r;
443
444 *tmpfile = TAKE_PTR(passwd)({ typeof(passwd) _ptr_ = (passwd); (passwd) = ((void*)0); _ptr_
; })
;
445 *tmpfile_path = TAKE_PTR(passwd_tmp)({ typeof(passwd_tmp) _ptr_ = (passwd_tmp); (passwd_tmp) = ((
void*)0); _ptr_; })
;
446
447 return 0;
448}
449
450static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char **tmpfile_path) {
451 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *original = NULL((void*)0), *shadow = NULL((void*)0);
452 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *shadow_tmp = NULL((void*)0);
453 struct spwd *sp = NULL((void*)0);
454 Iterator iterator;
455 long lstchg;
456 Item *i;
457 int r;
458
459 if (ordered_hashmap_size(todo_uids) == 0)
460 return 0;
461
462 r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
463 if (r < 0)
464 return r;
465
466 lstchg = (long) (now(CLOCK_REALTIME0) / USEC_PER_DAY((usec_t) (24ULL*((usec_t) (60ULL*((usec_t) (60ULL*((usec_t) 1000000ULL
)))))))
);
467
468 original = fopen(shadow_path, "re");
469 if (original) {
470
471 r = sync_rights(original, shadow);
472 if (r < 0)
473 return r;
474
475 while ((r = fgetspent_sane(original, &sp)) > 0) {
476
477 i = ordered_hashmap_get(users, sp->sp_namp);
478 if (i && i->todo_user) {
479 /* we will update the existing entry */
480 sp->sp_lstchg = lstchg;
481
482 /* only the /etc/shadow stage is left, so we can
483 * safely remove the item from the todo set */
484 i->todo_user = false0;
485 ordered_hashmap_remove(todo_uids, UID_TO_PTR(i->uid)((void*) (((uintptr_t) (i->uid))+1)));
486 }
487
488 /* Make sure we keep the NIS entries (if any) at the end. */
489 if (IN_SET(sp->sp_namp[0], '+', '-')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'+', '-'})/sizeof(int)]; switch(sp->sp_namp
[0]) { case '+': case '-': _found = 1; break; default: break;
} _found; })
)
490 break;
491
492 r = putspent_sane(sp, shadow);
493 if (r < 0)
494 return r;
495 }
496 if (r < 0)
497 return r;
498
499 } else {
500 if (errno(*__errno_location ()) != ENOENT2)
501 return -errno(*__errno_location ());
502 if (fchmod(fileno(shadow), 0000) < 0)
503 return -errno(*__errno_location ());
504 }
505
506 ORDERED_HASHMAP_FOREACH(i, todo_uids, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); ordered_hashmap_iterate((todo_uids
), &(iterator), (void**)&(i), ((void*)0)); )
{
507 struct spwd n = {
508 .sp_namp = i->name,
509 .sp_pwdp = (char*) "!!",
510 .sp_lstchg = lstchg,
511 .sp_min = -1,
512 .sp_max = -1,
513 .sp_warn = -1,
514 .sp_inact = -1,
515 .sp_expire = -1,
516 .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
517 };
518
519 r = putspent_sane(&n, shadow);
520 if (r < 0)
521 return r;
522 }
523
524 /* Append the remaining NIS entries if any */
525 while (sp) {
526 r = putspent_sane(sp, shadow);
527 if (r < 0)
528 return r;
529
530 r = fgetspent_sane(original, &sp);
531 if (r < 0)
532 return r;
533 if (r == 0)
534 break;
535 }
536 if (!IN_SET(errno, 0, ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 2})/sizeof(int)]; switch((*__errno_location
())) { case 0: case 2: _found = 1; break; default: break; } _found
; })
)
537 return -errno(*__errno_location ());
538
539 r = fflush_sync_and_check(shadow);
540 if (r < 0)
541 return r;
542
543 *tmpfile = TAKE_PTR(shadow)({ typeof(shadow) _ptr_ = (shadow); (shadow) = ((void*)0); _ptr_
; })
;
544 *tmpfile_path = TAKE_PTR(shadow_tmp)({ typeof(shadow_tmp) _ptr_ = (shadow_tmp); (shadow_tmp) = ((
void*)0); _ptr_; })
;
545
546 return 0;
547}
548
549static int write_temporary_group(const char *group_path, FILE **tmpfile, char **tmpfile_path) {
550 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *original = NULL((void*)0), *group = NULL((void*)0);
551 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *group_tmp = NULL((void*)0);
552 bool_Bool group_changed = false0;
553 struct group *gr = NULL((void*)0);
554 Iterator iterator;
555 Item *i;
556 int r;
557
558 if (ordered_hashmap_size(todo_gids) == 0 && ordered_hashmap_size(members) == 0)
559 return 0;
560
561 r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
562 if (r < 0)
563 return r;
564
565 original = fopen(group_path, "re");
566 if (original) {
567
568 r = sync_rights(original, group);
569 if (r < 0)
570 return r;
571
572 while ((r = fgetgrent_sane(original, &gr)) > 0) {
573 /* Safety checks against name and GID collisions. Normally,
574 * this should be unnecessary, but given that we look at the
575 * entries anyway here, let's make an extra verification
576 * step that we don't generate duplicate entries. */
577
578 i = ordered_hashmap_get(groups, gr->gr_name);
579 if (i && i->todo_group) {
580 log_error("%s: Group \"%s\" already exists.", group_path, gr->gr_name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 580, __func__, "%s: Group \"%s\" already exists."
, group_path, gr->gr_name) : -abs(_e); })
;
581 return -EEXIST17;
582 }
583
584 if (ordered_hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid)((void*) (((uintptr_t) (gr->gr_gid))+1)))) {
585 log_error("%s: Detected collision for GID " GID_FMT ".", group_path, gr->gr_gid)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 585, __func__, "%s: Detected collision for GID "
"%" "u" ".", group_path, gr->gr_gid) : -abs(_e); })
;
586 return -EEXIST17;
587 }
588
589 /* Make sure we keep the NIS entries (if any) at the end. */
590 if (IN_SET(gr->gr_name[0], '+', '-')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'+', '-'})/sizeof(int)]; switch(gr->gr_name
[0]) { case '+': case '-': _found = 1; break; default: break;
} _found; })
)
591 break;
592
593 r = putgrent_with_members(gr, group);
594 if (r < 0)
595 return r;
596 if (r > 0)
597 group_changed = true1;
598 }
599 if (r < 0)
600 return r;
601
602 } else {
603 if (errno(*__errno_location ()) != ENOENT2)
604 return -errno(*__errno_location ());
605 if (fchmod(fileno(group), 0644) < 0)
606 return -errno(*__errno_location ());
607 }
608
609 ORDERED_HASHMAP_FOREACH(i, todo_gids, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); ordered_hashmap_iterate((todo_gids
), &(iterator), (void**)&(i), ((void*)0)); )
{
610 struct group n = {
611 .gr_name = i->name,
612 .gr_gid = i->gid,
613 .gr_passwd = (char*) "x",
614 };
615
616 r = putgrent_with_members(&n, group);
617 if (r < 0)
618 return r;
619
620 group_changed = true1;
621 }
622
623 /* Append the remaining NIS entries if any */
624 while (gr) {
625 r = putgrent_sane(gr, group);
626 if (r < 0)
627 return r;
628
629 r = fgetgrent_sane(original, &gr);
630 if (r < 0)
631 return r;
632 if (r == 0)
633 break;
634 }
635
636 r = fflush_sync_and_check(group);
637 if (r < 0)
638 return r;
639
640 if (group_changed) {
641 *tmpfile = TAKE_PTR(group)({ typeof(group) _ptr_ = (group); (group) = ((void*)0); _ptr_
; })
;
642 *tmpfile_path = TAKE_PTR(group_tmp)({ typeof(group_tmp) _ptr_ = (group_tmp); (group_tmp) = ((void
*)0); _ptr_; })
;
643 }
644 return 0;
645}
646
647static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, char **tmpfile_path) {
648#if ENABLE_GSHADOW1
649 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *original = NULL((void*)0), *gshadow = NULL((void*)0);
650 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *gshadow_tmp = NULL((void*)0);
651 bool_Bool group_changed = false0;
652 Iterator iterator;
653 Item *i;
654 int r;
655
656 if (ordered_hashmap_size(todo_gids) == 0 && ordered_hashmap_size(members) == 0)
657 return 0;
658
659 r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
660 if (r < 0)
661 return r;
662
663 original = fopen(gshadow_path, "re");
664 if (original) {
665 struct sgrp *sg;
666
667 r = sync_rights(original, gshadow);
668 if (r < 0)
669 return r;
670
671 while ((r = fgetsgent_sane(original, &sg)) > 0) {
672
673 i = ordered_hashmap_get(groups, sg->sg_namp);
674 if (i && i->todo_group) {
675 log_error("%s: Group \"%s\" already exists.", gshadow_path, sg->sg_namp)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 675, __func__, "%s: Group \"%s\" already exists."
, gshadow_path, sg->sg_namp) : -abs(_e); })
;
676 return -EEXIST17;
677 }
678
679 r = putsgent_with_members(sg, gshadow);
680 if (r < 0)
681 return r;
682 if (r > 0)
683 group_changed = true1;
684 }
685 if (r < 0)
686 return r;
687
688 } else {
689 if (errno(*__errno_location ()) != ENOENT2)
690 return -errno(*__errno_location ());
691 if (fchmod(fileno(gshadow), 0000) < 0)
692 return -errno(*__errno_location ());
693 }
694
695 ORDERED_HASHMAP_FOREACH(i, todo_gids, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); ordered_hashmap_iterate((todo_gids
), &(iterator), (void**)&(i), ((void*)0)); )
{
696 struct sgrp n = {
697 .sg_namp = i->name,
698 .sg_passwd = (char*) "!!",
699 };
700
701 r = putsgent_with_members(&n, gshadow);
702 if (r < 0)
703 return r;
704
705 group_changed = true1;
706 }
707
708 r = fflush_sync_and_check(gshadow);
709 if (r < 0)
710 return r;
711
712 if (group_changed) {
713 *tmpfile = TAKE_PTR(gshadow)({ typeof(gshadow) _ptr_ = (gshadow); (gshadow) = ((void*)0);
_ptr_; })
;
714 *tmpfile_path = TAKE_PTR(gshadow_tmp)({ typeof(gshadow_tmp) _ptr_ = (gshadow_tmp); (gshadow_tmp) =
((void*)0); _ptr_; })
;
715 }
716 return 0;
717#else
718 return 0;
719#endif
720}
721
722static int write_files(void) {
723 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *passwd = NULL((void*)0), *group = NULL((void*)0), *shadow = NULL((void*)0), *gshadow = NULL((void*)0);
724 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *passwd_tmp = NULL((void*)0), *group_tmp = NULL((void*)0), *shadow_tmp = NULL((void*)0), *gshadow_tmp = NULL((void*)0);
725 const char *passwd_path = NULL((void*)0), *group_path = NULL((void*)0), *shadow_path = NULL((void*)0), *gshadow_path = NULL((void*)0);
726 int r;
727
728 passwd_path = prefix_roota(arg_root, "/etc/passwd")({ const char* _path = ("/etc/passwd"), *_root = (arg_root), *
_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' &&
_path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path
; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
729 shadow_path = prefix_roota(arg_root, "/etc/shadow")({ const char* _path = ("/etc/shadow"), *_root = (arg_root), *
_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' &&
_path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path
; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
730 group_path = prefix_roota(arg_root, "/etc/group")({ const char* _path = ("/etc/group"), *_root = (arg_root), *
_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' &&
_path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path
; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
731 gshadow_path = prefix_roota(arg_root, "/etc/gshadow")({ const char* _path = ("/etc/gshadow"), *_root = (arg_root),
*_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' &&
_path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path
; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
732
733 r = write_temporary_group(group_path, &group, &group_tmp);
734 if (r < 0)
735 return r;
736
737 r = write_temporary_gshadow(gshadow_path, &gshadow, &gshadow_tmp);
738 if (r < 0)
739 return r;
740
741 r = write_temporary_passwd(passwd_path, &passwd, &passwd_tmp);
742 if (r < 0)
743 return r;
744
745 r = write_temporary_shadow(shadow_path, &shadow, &shadow_tmp);
746 if (r < 0)
747 return r;
748
749 /* Make a backup of the old files */
750 if (group) {
751 r = make_backup("/etc/group", group_path);
752 if (r < 0)
753 return r;
754 }
755 if (gshadow) {
756 r = make_backup("/etc/gshadow", gshadow_path);
757 if (r < 0)
758 return r;
759 }
760
761 if (passwd) {
762 r = make_backup("/etc/passwd", passwd_path);
763 if (r < 0)
764 return r;
765 }
766 if (shadow) {
767 r = make_backup("/etc/shadow", shadow_path);
768 if (r < 0)
769 return r;
770 }
771
772 /* And make the new files count */
773 if (group) {
774 r = rename_and_apply_smack(group_tmp, group_path);
775 if (r < 0)
776 return r;
777
778 group_tmp = mfree(group_tmp);
779 }
780 if (gshadow) {
781 r = rename_and_apply_smack(gshadow_tmp, gshadow_path);
782 if (r < 0)
783 return r;
784
785 gshadow_tmp = mfree(gshadow_tmp);
786 }
787
788 if (passwd) {
789 r = rename_and_apply_smack(passwd_tmp, passwd_path);
790 if (r < 0)
791 return r;
792
793 passwd_tmp = mfree(passwd_tmp);
794 }
795 if (shadow) {
796 r = rename_and_apply_smack(shadow_tmp, shadow_path);
797 if (r < 0)
798 return r;
799
800 shadow_tmp = mfree(shadow_tmp);
801 }
802
803 return 0;
804}
805
806static int uid_is_ok(uid_t uid, const char *name, bool_Bool check_with_gid) {
807 struct passwd *p;
808 struct group *g;
809 const char *n;
810 Item *i;
811
812 /* Let's see if we already have assigned the UID a second time */
813 if (ordered_hashmap_get(todo_uids, UID_TO_PTR(uid)((void*) (((uintptr_t) (uid))+1))))
814 return 0;
815
816 /* Try to avoid using uids that are already used by a group
817 * that doesn't have the same name as our new user. */
818 if (check_with_gid) {
819 i = ordered_hashmap_get(todo_gids, GID_TO_PTR(uid)((void*) (((uintptr_t) (uid))+1)));
820 if (i && !streq(i->name, name)(strcmp((i->name),(name)) == 0))
821 return 0;
822 }
823
824 /* Let's check the files directly */
825 if (hashmap_contains(database_uid, UID_TO_PTR(uid)((void*) (((uintptr_t) (uid))+1))))
826 return 0;
827
828 if (check_with_gid) {
829 n = hashmap_get(database_gid, GID_TO_PTR(uid)((void*) (((uintptr_t) (uid))+1)));
830 if (n && !streq(n, name)(strcmp((n),(name)) == 0))
831 return 0;
832 }
833
834 /* Let's also check via NSS, to avoid UID clashes over LDAP and such, just in case */
835 if (!arg_root) {
836 errno(*__errno_location ()) = 0;
837 p = getpwuid(uid);
838 if (p)
839 return 0;
840 if (!IN_SET(errno, 0, ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 2})/sizeof(int)]; switch((*__errno_location
())) { case 0: case 2: _found = 1; break; default: break; } _found
; })
)
841 return -errno(*__errno_location ());
842
843 if (check_with_gid) {
844 errno(*__errno_location ()) = 0;
845 g = getgrgid((gid_t) uid);
846 if (g) {
847 if (!streq(g->gr_name, name)(strcmp((g->gr_name),(name)) == 0))
848 return 0;
849 } else if (!IN_SET(errno, 0, ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 2})/sizeof(int)]; switch((*__errno_location
())) { case 0: case 2: _found = 1; break; default: break; } _found
; })
)
850 return -errno(*__errno_location ());
851 }
852 }
853
854 return 1;
855}
856
857static int root_stat(const char *p, struct stat *st) {
858 const char *fix;
859
860 fix = prefix_roota(arg_root, p)({ const char* _path = (p), *_root = (arg_root), *_ret; char *
_p, *_n; size_t _l; while (_path[0] == '/' && _path[1
] == '/') _path ++; if (empty_or_root(_root)) _ret = _path; else
{ _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
861 if (stat(fix, st) < 0)
862 return -errno(*__errno_location ());
863
864 return 0;
865}
866
867static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
868 struct stat st;
869 bool_Bool found_uid = false0, found_gid = false0;
870 uid_t uid = 0;
871 gid_t gid = 0;
872
873 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/sysusers/sysusers.c", 873,
__PRETTY_FUNCTION__); } while (0)
;
874
875 /* First, try to get the gid directly */
876 if (_gid && i->gid_path && root_stat(i->gid_path, &st) >= 0) {
877 gid = st.st_gid;
878 found_gid = true1;
879 }
880
881 /* Then, try to get the uid directly */
882 if ((_uid || (_gid && !found_gid))
883 && i->uid_path
884 && root_stat(i->uid_path, &st) >= 0) {
885
886 uid = st.st_uid;
887 found_uid = true1;
888
889 /* If we need the gid, but had no success yet, also derive it from the uid path */
890 if (_gid && !found_gid) {
891 gid = st.st_gid;
892 found_gid = true1;
893 }
894 }
895
896 /* If that didn't work yet, then let's reuse the gid as uid */
897 if (_uid && !found_uid && i->gid_path) {
898
899 if (found_gid) {
900 uid = (uid_t) gid;
901 found_uid = true1;
902 } else if (root_stat(i->gid_path, &st) >= 0) {
903 uid = (uid_t) st.st_gid;
904 found_uid = true1;
905 }
906 }
907
908 if (_uid) {
909 if (!found_uid)
910 return 0;
911
912 *_uid = uid;
913 }
914
915 if (_gid) {
916 if (!found_gid)
917 return 0;
918
919 *_gid = gid;
920 }
921
922 return 1;
923}
924
925static int add_user(Item *i) {
926 void *z;
927 int r;
928
929 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/sysusers/sysusers.c", 929,
__PRETTY_FUNCTION__); } while (0)
;
930
931 /* Check the database directly */
932 z = hashmap_get(database_user, i->name);
933 if (z) {
934 log_debug("User %s already exists.", i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 934, __func__, "User %s already exists."
, i->name) : -abs(_e); })
;
935 i->uid = PTR_TO_UID(z)((uid_t) (((uintptr_t) (z))-1));
936 i->uid_set = true1;
937 return 0;
938 }
939
940 if (!arg_root) {
941 struct passwd *p;
942
943 /* Also check NSS */
944 errno(*__errno_location ()) = 0;
945 p = getpwnam(i->name);
946 if (p) {
947 log_debug("User %s already exists.", i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 947, __func__, "User %s already exists."
, i->name) : -abs(_e); })
;
948 i->uid = p->pw_uid;
949 i->uid_set = true1;
950
951 r = free_and_strdup(&i->description, p->pw_gecos);
952 if (r < 0)
953 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 953, __func__)
;
954
955 return 0;
956 }
957 if (!IN_SET(errno, 0, ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 2})/sizeof(int)]; switch((*__errno_location
())) { case 0: case 2: _found = 1; break; default: break; } _found
; })
)
958 return log_error_errno(errno, "Failed to check if user %s already exists: %m", i->name)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/sysusers/sysusers.c", 958, __func__
, "Failed to check if user %s already exists: %m", i->name
) : -abs(_e); })
;
959 }
960
961 /* Try to use the suggested numeric uid */
962 if (i->uid_set) {
963 r = uid_is_ok(i->uid, i->name, !i->id_set_strict);
964 if (r < 0)
965 return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 965, __func__, "Failed to verify uid "
"%" "u" ": %m", i->uid) : -abs(_e); })
;
966 if (r == 0) {
967 log_debug("Suggested user ID " UID_FMT " for %s already used.", i->uid, i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 967, __func__, "Suggested user ID "
"%" "u" " for %s already used.", i->uid, i->name) : -abs
(_e); })
;
968 i->uid_set = false0;
969 }
970 }
971
972 /* If that didn't work, try to read it from the specified path */
973 if (!i->uid_set) {
974 uid_t c;
975
976 if (read_id_from_file(i, &c, NULL((void*)0)) > 0) {
977
978 if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
979 log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 979, __func__, "User ID " "%"
"u" " of file not suitable for %s.", c, i->name) : -abs(_e
); })
;
980 else {
981 r = uid_is_ok(c, i->name, true1);
982 if (r < 0)
983 return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 983, __func__, "Failed to verify uid "
"%" "u" ": %m", i->uid) : -abs(_e); })
;
984 else if (r > 0) {
985 i->uid = c;
986 i->uid_set = true1;
987 } else
988 log_debug("User ID " UID_FMT " of file for %s is already used.", c, i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 988, __func__, "User ID " "%"
"u" " of file for %s is already used.", c, i->name) : -abs
(_e); })
;
989 }
990 }
991 }
992
993 /* Otherwise, try to reuse the group ID */
994 if (!i->uid_set && i->gid_set) {
995 r = uid_is_ok((uid_t) i->gid, i->name, true1);
996 if (r < 0)
997 return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 997, __func__, "Failed to verify uid "
"%" "u" ": %m", i->uid) : -abs(_e); })
;
998 if (r > 0) {
999 i->uid = (uid_t) i->gid;
1000 i->uid_set = true1;
1001 }
1002 }
1003
1004 /* And if that didn't work either, let's try to find a free one */
1005 if (!i->uid_set) {
1006 for (;;) {
1007 r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
1008 if (r < 0) {
1009 log_error("No free user ID available for %s.", i->name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1009, __func__, "No free user ID available for %s."
, i->name) : -abs(_e); })
;
1010 return r;
1011 }
1012
1013 r = uid_is_ok(search_uid, i->name, true1);
1014 if (r < 0)
1015 return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1015, __func__, "Failed to verify uid "
"%" "u" ": %m", i->uid) : -abs(_e); })
;
1016 else if (r > 0)
1017 break;
1018 }
1019
1020 i->uid_set = true1;
1021 i->uid = search_uid;
1022 }
1023
1024 r = ordered_hashmap_ensure_allocated(&todo_uids, NULL)internal_ordered_hashmap_ensure_allocated(&todo_uids, ((void
*)0) )
;
1025 if (r < 0)
1026 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1026, __func__)
;
1027
1028 r = ordered_hashmap_put(todo_uids, UID_TO_PTR(i->uid)((void*) (((uintptr_t) (i->uid))+1)), i);
1029 if (r < 0)
1030 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1030, __func__)
;
1031
1032 i->todo_user = true1;
1033 log_info("Creating user %s (%s) with uid " UID_FMT " and gid " GID_FMT ".", i->name, strna(i->description), i->uid, i->gid)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1033, __func__, "Creating user %s (%s) with uid "
"%" "u" " and gid " "%" "u" ".", i->name, strna(i->description
), i->uid, i->gid) : -abs(_e); })
;
1034
1035 return 0;
1036}
1037
1038static int gid_is_ok(gid_t gid) {
1039 struct group *g;
1040 struct passwd *p;
1041
1042 if (ordered_hashmap_get(todo_gids, GID_TO_PTR(gid)((void*) (((uintptr_t) (gid))+1))))
1043 return 0;
1044
1045 /* Avoid reusing gids that are already used by a different user */
1046 if (ordered_hashmap_get(todo_uids, UID_TO_PTR(gid)((void*) (((uintptr_t) (gid))+1))))
1047 return 0;
1048
1049 if (hashmap_contains(database_gid, GID_TO_PTR(gid)((void*) (((uintptr_t) (gid))+1))))
1050 return 0;
1051
1052 if (hashmap_contains(database_uid, UID_TO_PTR(gid)((void*) (((uintptr_t) (gid))+1))))
1053 return 0;
1054
1055 if (!arg_root) {
1056 errno(*__errno_location ()) = 0;
1057 g = getgrgid(gid);
1058 if (g)
1059 return 0;
1060 if (!IN_SET(errno, 0, ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 2})/sizeof(int)]; switch((*__errno_location
())) { case 0: case 2: _found = 1; break; default: break; } _found
; })
)
1061 return -errno(*__errno_location ());
1062
1063 errno(*__errno_location ()) = 0;
1064 p = getpwuid((uid_t) gid);
1065 if (p)
1066 return 0;
1067 if (!IN_SET(errno, 0, ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 2})/sizeof(int)]; switch((*__errno_location
())) { case 0: case 2: _found = 1; break; default: break; } _found
; })
)
1068 return -errno(*__errno_location ());
1069 }
1070
1071 return 1;
1072}
1073
1074static int add_group(Item *i) {
1075 void *z;
1076 int r;
1077
1078 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/sysusers/sysusers.c", 1078
, __PRETTY_FUNCTION__); } while (0)
;
1079
1080 /* Check the database directly */
1081 z = hashmap_get(database_group, i->name);
1082 if (z) {
1083 log_debug("Group %s already exists.", i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1083, __func__, "Group %s already exists."
, i->name) : -abs(_e); })
;
1084 i->gid = PTR_TO_GID(z)((gid_t) (((uintptr_t) (z))-1));
1085 i->gid_set = true1;
1086 return 0;
1087 }
1088
1089 /* Also check NSS */
1090 if (!arg_root) {
1091 struct group *g;
1092
1093 errno(*__errno_location ()) = 0;
1094 g = getgrnam(i->name);
1095 if (g) {
1096 log_debug("Group %s already exists.", i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1096, __func__, "Group %s already exists."
, i->name) : -abs(_e); })
;
1097 i->gid = g->gr_gid;
1098 i->gid_set = true1;
1099 return 0;
1100 }
1101 if (!IN_SET(errno, 0, ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, 2})/sizeof(int)]; switch((*__errno_location
())) { case 0: case 2: _found = 1; break; default: break; } _found
; })
)
1102 return log_error_errno(errno, "Failed to check if group %s already exists: %m", i->name)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/sysusers/sysusers.c", 1102, __func__
, "Failed to check if group %s already exists: %m", i->name
) : -abs(_e); })
;
1103 }
1104
1105 /* Try to use the suggested numeric gid */
1106 if (i->gid_set) {
1107 r = gid_is_ok(i->gid);
1108 if (r < 0)
1109 return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1109, __func__, "Failed to verify gid "
"%" "u" ": %m", i->gid) : -abs(_e); })
;
1110 if (i->id_set_strict) {
1111 /* If we require the gid to already exist we can return here:
1112 * r > 0: means the gid does not exist -> fail
1113 * r == 0: means the gid exists -> nothing more to do.
1114 */
1115 if (r > 0) {
1116 log_error("Failed to create %s: please create GID %d", i->name, i->gid)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1116, __func__, "Failed to create %s: please create GID %d"
, i->name, i->gid) : -abs(_e); })
;
1117 return -EINVAL22;
1118 }
1119 if (r == 0)
1120 return 0;
1121 }
1122 if (r == 0) {
1123 log_debug("Suggested group ID " GID_FMT " for %s already used.", i->gid, i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1123, __func__, "Suggested group ID "
"%" "u" " for %s already used.", i->gid, i->name) : -abs
(_e); })
;
1124 i->gid_set = false0;
1125 }
1126 }
1127
1128 /* Try to reuse the numeric uid, if there's one */
1129 if (!i->gid_set && i->uid_set) {
1130 r = gid_is_ok((gid_t) i->uid);
1131 if (r < 0)
1132 return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1132, __func__, "Failed to verify gid "
"%" "u" ": %m", i->gid) : -abs(_e); })
;
1133 if (r > 0) {
1134 i->gid = (gid_t) i->uid;
1135 i->gid_set = true1;
1136 }
1137 }
1138
1139 /* If that didn't work, try to read it from the specified path */
1140 if (!i->gid_set) {
1141 gid_t c;
1142
1143 if (read_id_from_file(i, NULL((void*)0), &c) > 0) {
1144
1145 if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
1146 log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1146, __func__, "Group ID " "%"
"u" " of file not suitable for %s.", c, i->name) : -abs(_e
); })
;
1147 else {
1148 r = gid_is_ok(c);
1149 if (r < 0)
1150 return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1150, __func__, "Failed to verify gid "
"%" "u" ": %m", i->gid) : -abs(_e); })
;
1151 else if (r > 0) {
1152 i->gid = c;
1153 i->gid_set = true1;
1154 } else
1155 log_debug("Group ID " GID_FMT " of file for %s already used.", c, i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1155, __func__, "Group ID " "%"
"u" " of file for %s already used.", c, i->name) : -abs(_e
); })
;
1156 }
1157 }
1158 }
1159
1160 /* And if that didn't work either, let's try to find a free one */
1161 if (!i->gid_set) {
1162 for (;;) {
1163 /* We look for new GIDs in the UID pool! */
1164 r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
1165 if (r < 0) {
1166 log_error("No free group ID available for %s.", i->name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1166, __func__, "No free group ID available for %s."
, i->name) : -abs(_e); })
;
1167 return r;
1168 }
1169
1170 r = gid_is_ok(search_uid);
1171 if (r < 0)
1172 return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1172, __func__, "Failed to verify gid "
"%" "u" ": %m", i->gid) : -abs(_e); })
;
1173 else if (r > 0)
1174 break;
1175 }
1176
1177 i->gid_set = true1;
1178 i->gid = search_uid;
1179 }
1180
1181 r = ordered_hashmap_ensure_allocated(&todo_gids, NULL)internal_ordered_hashmap_ensure_allocated(&todo_gids, ((void
*)0) )
;
1182 if (r < 0)
1183 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1183, __func__)
;
1184
1185 r = ordered_hashmap_put(todo_gids, GID_TO_PTR(i->gid)((void*) (((uintptr_t) (i->gid))+1)), i);
1186 if (r < 0)
1187 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1187, __func__)
;
1188
1189 i->todo_group = true1;
1190 log_info("Creating group %s with gid " GID_FMT ".", i->name, i->gid)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1190, __func__, "Creating group %s with gid "
"%" "u" ".", i->name, i->gid) : -abs(_e); })
;
1191
1192 return 0;
1193}
1194
1195static int process_item(Item *i) {
1196 int r;
1197
1198 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/sysusers/sysusers.c", 1198
, __PRETTY_FUNCTION__); } while (0)
;
1199
1200 switch (i->type) {
1201
1202 case ADD_USER: {
1203 Item *j;
1204
1205 j = ordered_hashmap_get(groups, i->name);
1206 if (j && j->todo_group) {
1207 /* When the group with the same name is already in queue,
1208 * use the information about the group and do not create
1209 * duplicated group entry. */
1210 i->gid_set = j->gid_set;
1211 i->gid = j->gid;
1212 i->id_set_strict = true1;
1213 } else {
1214 r = add_group(i);
1215 if (r < 0)
1216 return r;
1217 }
1218
1219 return add_user(i);
1220 }
1221
1222 case ADD_GROUP:
1223 return add_group(i);
1224
1225 default:
1226 assert_not_reached("Unknown item type")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unknown item type"), "../src/sysusers/sysusers.c", 1226, __PRETTY_FUNCTION__
); } while (0)
;
1227 }
1228}
1229
1230static void item_free(Item *i) {
1231
1232 if (!i)
1233 return;
1234
1235 free(i->name);
1236 free(i->uid_path);
1237 free(i->gid_path);
1238 free(i->description);
1239 free(i->home);
1240 free(i->shell);
1241 free(i);
1242}
1243
1244DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free)static inline void item_freep(Item* *p) { if (*p) item_free(*
p); }
;
1245
1246static int add_implicit(void) {
1247 char *g, **l;
1248 Iterator iterator;
1249 int r;
1250
1251 /* Implicitly create additional users and groups, if they were listed in "m" lines */
1252 ORDERED_HASHMAP_FOREACH_KEY(l, g, members, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); ordered_hashmap_iterate((members
), &(iterator), (void**)&(l), (const void**) &(g)
); )
{
1253 char **m;
1254
1255 STRV_FOREACH(m, l)for ((m) = (l); (m) && *(m); (m)++)
1256 if (!ordered_hashmap_get(users, *m)) {
1257 _cleanup_(item_freep)__attribute__((cleanup(item_freep))) Item *j = NULL((void*)0);
1258
1259 r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&users, &string_hash_ops
)
;
1260 if (r < 0)
1261 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1261, __func__)
;
1262
1263 j = new0(Item, 1)((Item*) calloc((1), sizeof(Item)));
1264 if (!j)
1265 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1265, __func__)
;
1266
1267 j->type = ADD_USER;
1268 j->name = strdup(*m);
1269 if (!j->name)
1270 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1270, __func__)
;
1271
1272 r = ordered_hashmap_put(users, j->name, j);
1273 if (r < 0)
1274 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1274, __func__)
;
1275
1276 log_debug("Adding implicit user '%s' due to m line", j->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1276, __func__, "Adding implicit user '%s' due to m line"
, j->name) : -abs(_e); })
;
1277 j = NULL((void*)0);
1278 }
1279
1280 if (!(ordered_hashmap_get(users, g) ||
1281 ordered_hashmap_get(groups, g))) {
1282 _cleanup_(item_freep)__attribute__((cleanup(item_freep))) Item *j = NULL((void*)0);
1283
1284 r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&groups, &string_hash_ops
)
;
1285 if (r < 0)
1286 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1286, __func__)
;
1287
1288 j = new0(Item, 1)((Item*) calloc((1), sizeof(Item)));
1289 if (!j)
1290 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1290, __func__)
;
1291
1292 j->type = ADD_GROUP;
1293 j->name = strdup(g);
1294 if (!j->name)
1295 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1295, __func__)
;
1296
1297 r = ordered_hashmap_put(groups, j->name, j);
1298 if (r < 0)
1299 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1299, __func__)
;
1300
1301 log_debug("Adding implicit group '%s' due to m line", j->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1301, __func__, "Adding implicit group '%s' due to m line"
, j->name) : -abs(_e); })
;
1302 j = NULL((void*)0);
1303 }
1304 }
1305
1306 return 0;
1307}
1308
1309static bool_Bool item_equal(Item *a, Item *b) {
1310 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/sysusers/sysusers.c", 1310
, __PRETTY_FUNCTION__); } while (0)
;
1311 assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("b"), "../src/sysusers/sysusers.c", 1311
, __PRETTY_FUNCTION__); } while (0)
;
1312
1313 if (a->type != b->type)
1314 return false0;
1315
1316 if (!streq_ptr(a->name, b->name))
1317 return false0;
1318
1319 if (!streq_ptr(a->uid_path, b->uid_path))
1320 return false0;
1321
1322 if (!streq_ptr(a->gid_path, b->gid_path))
1323 return false0;
1324
1325 if (!streq_ptr(a->description, b->description))
1326 return false0;
1327
1328 if (a->uid_set != b->uid_set)
1329 return false0;
1330
1331 if (a->uid_set && a->uid != b->uid)
1332 return false0;
1333
1334 if (a->gid_set != b->gid_set)
1335 return false0;
1336
1337 if (a->gid_set && a->gid != b->gid)
1338 return false0;
1339
1340 if (!streq_ptr(a->home, b->home))
1341 return false0;
1342
1343 if (!streq_ptr(a->shell, b->shell))
1344 return false0;
1345
1346 return true1;
1347}
1348
1349static int parse_line(const char *fname, unsigned line, const char *buffer) {
1350
1351 static const Specifier specifier_table[] = {
1352 { 'm', specifier_machine_id, NULL((void*)0) },
1353 { 'b', specifier_boot_id, NULL((void*)0) },
1354 { 'H', specifier_host_name, NULL((void*)0) },
1355 { 'v', specifier_kernel_release, NULL((void*)0) },
1356 { 'T', specifier_tmp_dir, NULL((void*)0) },
1357 { 'V', specifier_var_tmp_dir, NULL((void*)0) },
1358 {}
1359 };
1360
1361 _cleanup_free___attribute__((cleanup(freep))) char *action = NULL((void*)0),
1362 *name = NULL((void*)0), *resolved_name = NULL((void*)0),
1363 *id = NULL((void*)0), *resolved_id = NULL((void*)0),
1364 *description = NULL((void*)0), *resolved_description = NULL((void*)0),
1365 *home = NULL((void*)0), *resolved_home = NULL((void*)0),
1366 *shell, *resolved_shell = NULL((void*)0);
1367 _cleanup_(item_freep)__attribute__((cleanup(item_freep))) Item *i = NULL((void*)0);
1368 Item *existing;
1369 OrderedHashmap *h;
1370 int r;
1371 const char *p;
1372
1373 assert(fname)do { if ((__builtin_expect(!!(!(fname)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fname"), "../src/sysusers/sysusers.c", 1373
, __PRETTY_FUNCTION__); } while (0)
;
1374 assert(line >= 1)do { if ((__builtin_expect(!!(!(line >= 1)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("line >= 1"), "../src/sysusers/sysusers.c"
, 1374, __PRETTY_FUNCTION__); } while (0)
;
1375 assert(buffer)do { if ((__builtin_expect(!!(!(buffer)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("buffer"), "../src/sysusers/sysusers.c",
1375, __PRETTY_FUNCTION__); } while (0)
;
1376
1377 /* Parse columns */
1378 p = buffer;
1379 r = extract_many_words(&p, NULL((void*)0), EXTRACT_QUOTES,
1380 &action, &name, &id, &description, &home, &shell, NULL((void*)0));
1381 if (r < 0) {
1382 log_error("[%s:%u] Syntax error.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1382, __func__, "[%s:%u] Syntax error."
, fname, line) : -abs(_e); })
;
1383 return r;
1384 }
1385 if (r < 2) {
1386 log_error("[%s:%u] Missing action and name columns.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1386, __func__, "[%s:%u] Missing action and name columns."
, fname, line) : -abs(_e); })
;
1387 return -EINVAL22;
1388 }
1389 if (!isempty(p)) {
1390 log_error("[%s:%u] Trailing garbage.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1390, __func__, "[%s:%u] Trailing garbage."
, fname, line) : -abs(_e); })
;
1391 return -EINVAL22;
1392 }
1393
1394 /* Verify action */
1395 if (strlen(action) != 1) {
1396 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1396, __func__, "[%s:%u] Unknown modifier '%s'"
, fname, line, action) : -abs(_e); })
;
1397 return -EINVAL22;
1398 }
1399
1400 if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE
})/sizeof(int)]; switch(action[0]) { case ADD_USER: case ADD_GROUP
: case ADD_MEMBER: case ADD_RANGE: _found = 1; break; default
: break; } _found; })
) {
1401 log_error("[%s:%u] Unknown command type '%c'.", fname, line, action[0])({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1401, __func__, "[%s:%u] Unknown command type '%c'."
, fname, line, action[0]) : -abs(_e); })
;
1402 return -EBADMSG74;
1403 }
1404
1405 /* Verify name */
1406 if (isempty(name) || streq(name, "-")(strcmp((name),("-")) == 0))
1407 name = mfree(name);
1408
1409 if (name) {
1410 r = specifier_printf(name, specifier_table, NULL((void*)0), &resolved_name);
1411 if (r < 0) {
1412 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1412, __func__, "[%s:%u] Failed to replace specifiers: %s"
, fname, line, name) : -abs(_e); })
;
1413 return r;
1414 }
1415
1416 if (!valid_user_group_name(resolved_name, 0)) {
1417 log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1417, __func__, "[%s:%u] '%s' is not a valid user or group name."
, fname, line, resolved_name) : -abs(_e); })
;
1418 return -EINVAL22;
1419 }
1420 }
1421
1422 /* Verify id */
1423 if (isempty(id) || streq(id, "-")(strcmp((id),("-")) == 0))
1424 id = mfree(id);
1425
1426 if (id) {
1427 r = specifier_printf(id, specifier_table, NULL((void*)0), &resolved_id);
1428 if (r < 0) {
1429 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1429, __func__, "[%s:%u] Failed to replace specifiers: %s"
, fname, line, name) : -abs(_e); })
;
1430 return r;
1431 }
1432 }
1433
1434 /* Verify description */
1435 if (isempty(description) || streq(description, "-")(strcmp((description),("-")) == 0))
1436 description = mfree(description);
1437
1438 if (description) {
1439 r = specifier_printf(description, specifier_table, NULL((void*)0), &resolved_description);
1440 if (r < 0) {
1441 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, description)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1441, __func__, "[%s:%u] Failed to replace specifiers: %s"
, fname, line, description) : -abs(_e); })
;
1442 return r;
1443 }
1444
1445 if (!valid_gecos(resolved_description)) {
1446 log_error("[%s:%u] '%s' is not a valid GECOS field.", fname, line, resolved_description)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1446, __func__, "[%s:%u] '%s' is not a valid GECOS field."
, fname, line, resolved_description) : -abs(_e); })
;
1447 return -EINVAL22;
1448 }
1449 }
1450
1451 /* Verify home */
1452 if (isempty(home) || streq(home, "-")(strcmp((home),("-")) == 0))
1453 home = mfree(home);
1454
1455 if (home) {
1456 r = specifier_printf(home, specifier_table, NULL((void*)0), &resolved_home);
1457 if (r < 0) {
1458 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, home)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1458, __func__, "[%s:%u] Failed to replace specifiers: %s"
, fname, line, home) : -abs(_e); })
;
1459 return r;
1460 }
1461
1462 if (!valid_home(resolved_home)) {
1463 log_error("[%s:%u] '%s' is not a valid home directory field.", fname, line, resolved_home)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1463, __func__, "[%s:%u] '%s' is not a valid home directory field."
, fname, line, resolved_home) : -abs(_e); })
;
1464 return -EINVAL22;
1465 }
1466 }
1467
1468 /* Verify shell */
1469 if (isempty(shell) || streq(shell, "-")(strcmp((shell),("-")) == 0))
1470 shell = mfree(shell);
1471
1472 if (shell) {
1473 r = specifier_printf(shell, specifier_table, NULL((void*)0), &resolved_shell);
1474 if (r < 0) {
1475 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, shell)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1475, __func__, "[%s:%u] Failed to replace specifiers: %s"
, fname, line, shell) : -abs(_e); })
;
1476 return r;
1477 }
1478
1479 if (!valid_shell(resolved_shell)) {
1480 log_error("[%s:%u] '%s' is not a valid login shell field.", fname, line, resolved_shell)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1480, __func__, "[%s:%u] '%s' is not a valid login shell field."
, fname, line, resolved_shell) : -abs(_e); })
;
1481 return -EINVAL22;
1482 }
1483 }
1484
1485 switch (action[0]) {
1486
1487 case ADD_RANGE:
1488 if (resolved_name) {
1489 log_error("[%s:%u] Lines of type 'r' don't take a name field.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1489, __func__, "[%s:%u] Lines of type 'r' don't take a name field."
, fname, line) : -abs(_e); })
;
1490 return -EINVAL22;
1491 }
1492
1493 if (!resolved_id) {
1494 log_error("[%s:%u] Lines of type 'r' require a ID range in the third field.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1494, __func__, "[%s:%u] Lines of type 'r' require a ID range in the third field."
, fname, line) : -abs(_e); })
;
1495 return -EINVAL22;
1496 }
1497
1498 if (description || home || shell) {
1499 log_error("[%s:%u] Lines of type '%c' don't take a %s field.",({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1501, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
1500 fname, line, action[0],({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1501, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
1501 description ? "GECOS" : home ? "home directory" : "login shell")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1501, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
;
1502 return -EINVAL22;
1503 }
1504
1505 r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
1506 if (r < 0) {
1507 log_error("[%s:%u] Invalid UID range %s.", fname, line, resolved_id)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1507, __func__, "[%s:%u] Invalid UID range %s."
, fname, line, resolved_id) : -abs(_e); })
;
1508 return -EINVAL22;
1509 }
1510
1511 return 0;
1512
1513 case ADD_MEMBER: {
1514 char **l;
1515
1516 /* Try to extend an existing member or group item */
1517 if (!name) {
1518 log_error("[%s:%u] Lines of type 'm' require a user name in the second field.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1518, __func__, "[%s:%u] Lines of type 'm' require a user name in the second field."
, fname, line) : -abs(_e); })
;
1519 return -EINVAL22;
1520 }
1521
1522 if (!resolved_id) {
1523 log_error("[%s:%u] Lines of type 'm' require a group name in the third field.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1523, __func__, "[%s:%u] Lines of type 'm' require a group name in the third field."
, fname, line) : -abs(_e); })
;
1524 return -EINVAL22;
1525 }
1526
1527 if (!valid_user_group_name(resolved_id, 0)) {
1528 log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_id)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1528, __func__, "[%s:%u] '%s' is not a valid user or group name."
, fname, line, resolved_id) : -abs(_e); })
;
1529 return -EINVAL22;
1530 }
1531
1532 if (description || home || shell) {
1533 log_error("[%s:%u] Lines of type '%c' don't take a %s field.",({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1535, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
1534 fname, line, action[0],({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1535, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
1535 description ? "GECOS" : home ? "home directory" : "login shell")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1535, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
;
1536 return -EINVAL22;
1537 }
1538
1539 r = ordered_hashmap_ensure_allocated(&members, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&members, &
string_hash_ops )
;
1540 if (r < 0)
1541 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1541, __func__)
;
1542
1543 l = ordered_hashmap_get(members, resolved_id);
1544 if (l) {
1545 /* A list for this group name already exists, let's append to it */
1546 r = strv_push(&l, resolved_name);
1547 if (r < 0)
1548 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1548, __func__)
;
1549
1550 resolved_name = NULL((void*)0);
1551
1552 assert_se(ordered_hashmap_update(members, resolved_id, l) >= 0)do { if ((__builtin_expect(!!(!(ordered_hashmap_update(members
, resolved_id, l) >= 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("ordered_hashmap_update(members, resolved_id, l) >= 0")
, "../src/sysusers/sysusers.c", 1552, __PRETTY_FUNCTION__); }
while (0)
;
1553 } else {
1554 /* No list for this group name exists yet, create one */
1555
1556 l = new0(char *, 2)((char **) calloc((2), sizeof(char *)));
1557 if (!l)
1558 return -ENOMEM12;
1559
1560 l[0] = resolved_name;
1561 l[1] = NULL((void*)0);
1562
1563 r = ordered_hashmap_put(members, resolved_id, l);
1564 if (r < 0) {
1565 free(l);
1566 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1566, __func__)
;
1567 }
1568
1569 resolved_id = resolved_name = NULL((void*)0);
1570 }
1571
1572 return 0;
1573 }
1574
1575 case ADD_USER:
1576 if (!name) {
1577 log_error("[%s:%u] Lines of type 'u' require a user name in the second field.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1577, __func__, "[%s:%u] Lines of type 'u' require a user name in the second field."
, fname, line) : -abs(_e); })
;
1578 return -EINVAL22;
1579 }
1580
1581 r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&users, &string_hash_ops
)
;
1582 if (r < 0)
1583 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1583, __func__)
;
1584
1585 i = new0(Item, 1)((Item*) calloc((1), sizeof(Item)));
1586 if (!i)
1587 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1587, __func__)
;
1588
1589 if (resolved_id) {
1590 if (path_is_absolute(resolved_id)) {
1591 i->uid_path = TAKE_PTR(resolved_id)({ typeof(resolved_id) _ptr_ = (resolved_id); (resolved_id) =
((void*)0); _ptr_; })
;
1592 path_simplify(i->uid_path, false0);
1593 } else {
1594 _cleanup_free___attribute__((cleanup(freep))) char *uid = NULL((void*)0), *gid = NULL((void*)0);
1595 if (split_pair(resolved_id, ":", &uid, &gid) == 0) {
1596 r = parse_gid(gid, &i->gid);
1597 if (r < 0)
1598 return log_error_errno(r, "Failed to parse GID: '%s': %m", id)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1598, __func__, "Failed to parse GID: '%s': %m"
, id) : -abs(_e); })
;
1599 i->gid_set = true1;
1600 i->id_set_strict = true1;
1601 free_and_replace(resolved_id, uid)({ free(resolved_id); (resolved_id) = (uid); (uid) = ((void*)
0); 0; })
;
1602 }
1603 if (!streq(resolved_id, "-")(strcmp((resolved_id),("-")) == 0)) {
1604 r = parse_uid(resolved_id, &i->uid);
1605 if (r < 0)
1606 return log_error_errno(r, "Failed to parse UID: '%s': %m", id)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1606, __func__, "Failed to parse UID: '%s': %m"
, id) : -abs(_e); })
;
1607 i->uid_set = true1;
1608 }
1609 }
1610 }
1611
1612 i->description = TAKE_PTR(resolved_description)({ typeof(resolved_description) _ptr_ = (resolved_description
); (resolved_description) = ((void*)0); _ptr_; })
;
1613 i->home = TAKE_PTR(resolved_home)({ typeof(resolved_home) _ptr_ = (resolved_home); (resolved_home
) = ((void*)0); _ptr_; })
;
1614 i->shell = TAKE_PTR(resolved_shell)({ typeof(resolved_shell) _ptr_ = (resolved_shell); (resolved_shell
) = ((void*)0); _ptr_; })
;
1615
1616 h = users;
1617 break;
1618
1619 case ADD_GROUP:
1620 if (!name) {
1621 log_error("[%s:%u] Lines of type 'g' require a user name in the second field.", fname, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1621, __func__, "[%s:%u] Lines of type 'g' require a user name in the second field."
, fname, line) : -abs(_e); })
;
1622 return -EINVAL22;
1623 }
1624
1625 if (description || home || shell) {
1626 log_error("[%s:%u] Lines of type '%c' don't take a %s field.",({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1628, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
1627 fname, line, action[0],({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1628, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
1628 description ? "GECOS" : home ? "home directory" : "login shell")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1628, __func__, "[%s:%u] Lines of type '%c' don't take a %s field."
, fname, line, action[0], description ? "GECOS" : home ? "home directory"
: "login shell") : -abs(_e); })
;
1629 return -EINVAL22;
1630 }
1631
1632 r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&groups, &string_hash_ops
)
;
1633 if (r < 0)
1634 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1634, __func__)
;
1635
1636 i = new0(Item, 1)((Item*) calloc((1), sizeof(Item)));
1637 if (!i)
1638 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1638, __func__)
;
1639
1640 if (resolved_id) {
1641 if (path_is_absolute(resolved_id)) {
1642 i->gid_path = TAKE_PTR(resolved_id)({ typeof(resolved_id) _ptr_ = (resolved_id); (resolved_id) =
((void*)0); _ptr_; })
;
1643 path_simplify(i->gid_path, false0);
1644 } else {
1645 r = parse_gid(resolved_id, &i->gid);
1646 if (r < 0)
1647 return log_error_errno(r, "Failed to parse GID: '%s': %m", id)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1647, __func__, "Failed to parse GID: '%s': %m"
, id) : -abs(_e); })
;
1648
1649 i->gid_set = true1;
1650 }
1651 }
1652
1653 h = groups;
1654 break;
1655
1656 default:
1657 return -EBADMSG74;
1658 }
1659
1660 i->type = action[0];
1661 i->name = TAKE_PTR(resolved_name)({ typeof(resolved_name) _ptr_ = (resolved_name); (resolved_name
) = ((void*)0); _ptr_; })
;
1662
1663 existing = ordered_hashmap_get(h, i->name);
1664 if (existing) {
1665
1666 /* Two identical items are fine */
1667 if (!item_equal(existing, i))
1668 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->name)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1668, __func__, "Two or more conflicting lines for %s configured, ignoring."
, i->name) : -abs(_e); })
;
1669
1670 return 0;
1671 }
1672
1673 r = ordered_hashmap_put(h, i->name, i);
1674 if (r < 0)
1675 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1675, __func__)
;
1676
1677 i = NULL((void*)0);
1678 return 0;
1679}
1680
1681static int read_config_file(const char *fn, bool_Bool ignore_enoent) {
1682 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *rf = NULL((void*)0);
1683 FILE *f = NULL((void*)0);
1684 char line[LINE_MAX2048];
1685 unsigned v = 0;
1686 int r = 0;
1687
1688 assert(fn)do { if ((__builtin_expect(!!(!(fn)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fn"), "../src/sysusers/sysusers.c", 1688
, __PRETTY_FUNCTION__); } while (0)
;
1689
1690 if (streq(fn, "-")(strcmp((fn),("-")) == 0))
1691 f = stdinstdin;
1692 else {
1693 r = search_and_fopen(fn, "re", arg_root, (const char**) CONF_PATHS_STRV("sysusers.d")((char**) ((const char*[]) { "/etc/" "sysusers.d", "/run/" "sysusers.d"
, "/usr/local/lib/" "sysusers.d", "/usr/lib/" "sysusers.d", (
(void*)0) }))
, &rf);
1694 if (r < 0) {
1695 if (ignore_enoent && r == -ENOENT2)
1696 return 0;
1697
1698 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1698, __func__, "Failed to open '%s', ignoring: %m"
, fn) : -abs(_e); })
;
1699 }
1700
1701 f = rf;
1702 }
1703
1704 FOREACH_LINE(line, f, break)for (;;) if (!fgets(line, sizeof(line), f)) { if (ferror(f)) {
break; } break; } else
{
1705 char *l;
1706 int k;
1707
1708 v++;
1709
1710 l = strstrip(line);
1711 if (IN_SET(*l, 0, '#')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, '#'})/sizeof(int)]; switch(*l) { case
0: case '#': _found = 1; break; default: break; } _found; })
)
1712 continue;
1713
1714 k = parse_line(fn, v, l);
1715 if (k < 0 && r == 0)
1716 r = k;
1717 }
1718
1719 if (ferror(f)) {
1720 log_error_errno(errno, "Failed to read from file %s: %m", fn)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/sysusers/sysusers.c", 1720, __func__
, "Failed to read from file %s: %m", fn) : -abs(_e); })
;
1721 if (r == 0)
1722 r = -EIO5;
1723 }
1724
1725 return r;
1726}
1727
1728static void free_database(Hashmap *by_name, Hashmap *by_id) {
1729 char *name;
1730
1731 for (;;) {
1732 name = hashmap_first(by_id);
1733 if (!name)
1734 break;
1735
1736 hashmap_remove(by_name, name);
1737
1738 hashmap_steal_first_key(by_id);
1739 free(name);
1740 }
1741
1742 while ((name = hashmap_steal_first_key(by_name)))
1743 free(name);
1744
1745 hashmap_free(by_name);
1746 hashmap_free(by_id);
1747}
1748
1749static int cat_config(void) {
1750 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **files = NULL((void*)0);
1751 int r;
1752
1753 r = conf_files_list_with_replacement(arg_root, CONF_PATHS_STRV("sysusers.d")((char**) ((const char*[]) { "/etc/" "sysusers.d", "/run/" "sysusers.d"
, "/usr/local/lib/" "sysusers.d", "/usr/lib/" "sysusers.d", (
(void*)0) }))
, arg_replace, &files, NULL((void*)0));
1754 if (r < 0)
1755 return r;
1756
1757 (void) pager_open(arg_no_pager, false0);
1758
1759 return cat_files(NULL((void*)0), files, 0);
1760}
1761
1762static void help(void) {
1763 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1764 "Creates system user accounts.\n\n"
1765 " -h --help Show this help\n"
1766 " --version Show package version\n"
1767 " --cat-config Show configuration files\n"
1768 " --root=PATH Operate on an alternate filesystem root\n"
1769 " --replace=PATH Treat arguments as replacement for PATH\n"
1770 " --inline Treat arguments as configuration lines\n"
1771 " --no-pager Do not pipe output into a pager\n"
1772 , program_invocation_short_name);
1773}
1774
1775static int parse_argv(int argc, char *argv[]) {
1776
1777 enum {
1778 ARG_VERSION = 0x100,
1779 ARG_CAT_CONFIG,
1780 ARG_ROOT,
1781 ARG_REPLACE,
1782 ARG_INLINE,
1783 ARG_NO_PAGER,
1784 };
1785
1786 static const struct option options[] = {
1787 { "help", no_argument0, NULL((void*)0), 'h' },
1788 { "version", no_argument0, NULL((void*)0), ARG_VERSION },
1789 { "cat-config", no_argument0, NULL((void*)0), ARG_CAT_CONFIG },
1790 { "root", required_argument1, NULL((void*)0), ARG_ROOT },
1791 { "replace", required_argument1, NULL((void*)0), ARG_REPLACE },
1792 { "inline", no_argument0, NULL((void*)0), ARG_INLINE },
1793 { "no-pager", no_argument0, NULL((void*)0), ARG_NO_PAGER },
1794 {}
1795 };
1796
1797 int c, r;
1798
1799 assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/sysusers/sysusers.c"
, 1799, __PRETTY_FUNCTION__); } while (0)
;
1800 assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("argv"), "../src/sysusers/sysusers.c", 1800
, __PRETTY_FUNCTION__); } while (0)
;
1801
1802 while ((c = getopt_long(argc, argv, "h", options, NULL((void*)0))) >= 0)
1803
1804 switch (c) {
1805
1806 case 'h':
1807 help();
1808 return 0;
1809
1810 case ARG_VERSION:
1811 return version();
1812
1813 case ARG_CAT_CONFIG:
1814 arg_cat_config = true1;
1815 break;
1816
1817 case ARG_ROOT:
1818 r = parse_path_argument_and_warn(optarg, true1, &arg_root);
1819 if (r < 0)
1820 return r;
1821 break;
1822
1823 case ARG_REPLACE:
1824 if (!path_is_absolute(optarg) ||
1825 !endswith(optarg, ".conf")) {
1826 log_error("The argument to --replace= must an absolute path to a config file")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1826, __func__, "The argument to --replace= must an absolute path to a config file"
) : -abs(_e); })
;
1827 return -EINVAL22;
1828 }
1829
1830 arg_replace = optarg;
1831 break;
1832
1833 case ARG_INLINE:
1834 arg_inline = true1;
1835 break;
1836
1837 case ARG_NO_PAGER:
1838 arg_no_pager = true1;
1839 break;
1840
1841 case '?':
1842 return -EINVAL22;
1843
1844 default:
1845 assert_not_reached("Unhandled option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unhandled option"), "../src/sysusers/sysusers.c", 1845, __PRETTY_FUNCTION__
); } while (0)
;
1846 }
1847
1848 if (arg_replace && arg_cat_config) {
1849 log_error("Option --replace= is not supported with --cat-config")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1849, __func__, "Option --replace= is not supported with --cat-config"
) : -abs(_e); })
;
1850 return -EINVAL22;
1851 }
1852
1853 if (arg_replace && optind >= argc) {
1854 log_error("When --replace= is given, some configuration items must be specified")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1854, __func__, "When --replace= is given, some configuration items must be specified"
) : -abs(_e); })
;
1855 return -EINVAL22;
1856 }
1857
1858 return 1;
1859}
1860
1861static int parse_arguments(char **args) {
1862 char **arg;
1863 unsigned pos = 1;
1864 int r;
1865
1866 STRV_FOREACH(arg, args)for ((arg) = (args); (arg) && *(arg); (arg)++) {
1867 if (arg_inline)
1868 /* Use (argument):n, where n==1 for the first positional arg */
1869 r = parse_line("(argument)", pos, *arg);
1870 else
1871 r = read_config_file(*arg, false0);
1872 if (r < 0)
1873 return r;
1874
1875 pos++;
1876 }
1877
1878 return 0;
1879}
1880
1881static int read_config_files(char **args) {
1882 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **files = NULL((void*)0);
1883 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0);
1884 char **f;
1885 int r;
1886
1887 r = conf_files_list_with_replacement(arg_root, CONF_PATHS_STRV("sysusers.d")((char**) ((const char*[]) { "/etc/" "sysusers.d", "/run/" "sysusers.d"
, "/usr/local/lib/" "sysusers.d", "/usr/lib/" "sysusers.d", (
(void*)0) }))
, arg_replace, &files, &p);
1888 if (r < 0)
1889 return r;
1890
1891 STRV_FOREACH(f, files)for ((f) = (files); (f) && *(f); (f)++)
1892 if (p && path_equal(*f, p)) {
1893 log_debug("Parsing arguments at position \"%s\"…", *f)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1893, __func__, "Parsing arguments at position \"%s\"…"
, *f) : -abs(_e); })
;
1894
1895 r = parse_arguments(args);
1896 if (r < 0)
1897 return r;
1898 } else {
1899 log_debug("Reading config file \"%s\"…", *f)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1899, __func__, "Reading config file \"%s\"…"
, *f) : -abs(_e); })
;
1900
1901 /* Just warn, ignore result otherwise */
1902 (void) read_config_file(*f, true1);
1903 }
1904
1905 return 0;
1906}
1907
1908int main(int argc, char *argv[]) {
1909 _cleanup_close___attribute__((cleanup(closep))) int lock = -1;
1910 Iterator iterator;
1911 int r;
1912 Item *i;
1913 char *n;
1914
1915 r = parse_argv(argc, argv);
1916 if (r
0.1
'r' is > 0
<= 0)
1
Taking false branch
1917 goto finish;
1918
1919 log_set_target(LOG_TARGET_AUTO);
1920 log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD);
1921 log_open();
1922
1923 if (arg_cat_config
1.1
'arg_cat_config' is false
) {
2
Taking false branch
1924 r = cat_config();
1925 goto finish;
1926 }
1927
1928 umask(0022);
1929
1930 r = mac_selinux_init();
1931 if (r < 0) {
3
Assuming 'r' is >= 0
4
Taking false branch
1932 log_error_errno(r, "SELinux setup failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1932, __func__, "SELinux setup failed: %m"
) : -abs(_e); })
;
1933 goto finish;
1934 }
1935
1936 /* If command line arguments are specified along with --replace, read all
1937 * configuration files and insert the positional arguments at the specified
1938 * place. Otherwise, if command line arguments are specified, execute just
1939 * them, and finally, without --replace= or any positional arguments, just
1940 * read configuration and execute it.
1941 */
1942 if (arg_replace
4.1
'arg_replace' is null
|| optind >= argc)
5
Assuming 'optind' is < 'argc'
6
Taking false branch
1943 r = read_config_files(argv + optind);
1944 else
1945 r = parse_arguments(argv + optind);
1946 if (r
6.1
'r' is >= 0
< 0)
7
Taking false branch
1947 goto finish;
1948
1949 /* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our detection
1950 * whether the names or UID/GID area already used otherwise doesn't get confused. After all, even though
1951 * nss-systemd synthesizes these users/groups, they should still appear in /etc/passwd and /etc/group, as the
1952 * synthesizing logic is merely supposed to be fallback for cases where we run with a completely unpopulated
1953 * /etc. */
1954 if (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0) {
8
Assuming the condition is false
9
Taking false branch
1955 r = log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/sysusers/sysusers.c", 1955, __func__
, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m"
) : -abs(_e); })
;
1956 goto finish;
1957 }
1958
1959 if (!uid_range
9.1
'uid_range' is null
) {
10
Taking true branch
1960 /* Default to default range of 1..SYSTEM_UID_MAX */
1961 r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX999);
1962 if (r < 0) {
11
Assuming 'r' is >= 0
12
Taking false branch
1963 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysusers/sysusers.c"
, 1963, __func__)
;
1964 goto finish;
1965 }
1966 }
1967
1968 r = add_implicit();
1969 if (r
12.1
'r' is >= 0
< 0)
13
Taking false branch
1970 goto finish;
1971
1972 lock = take_etc_passwd_lock(arg_root);
1973 if (lock < 0) {
14
Assuming 'lock' is >= 0
15
Taking false branch
1974 log_error_errno(lock, "Failed to take /etc/passwd lock: %m")({ int _level = ((3)), _e = ((lock)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1974, __func__, "Failed to take /etc/passwd lock: %m"
) : -abs(_e); })
;
1975 goto finish;
1976 }
1977
1978 r = load_user_database();
16
Calling 'load_user_database'
1979 if (r < 0) {
1980 log_error_errno(r, "Failed to load user database: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1980, __func__, "Failed to load user database: %m"
) : -abs(_e); })
;
1981 goto finish;
1982 }
1983
1984 r = load_group_database();
1985 if (r < 0) {
1986 log_error_errno(r, "Failed to read group database: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1986, __func__, "Failed to read group database: %m"
) : -abs(_e); })
;
1987 goto finish;
1988 }
1989
1990 ORDERED_HASHMAP_FOREACH(i, groups, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); ordered_hashmap_iterate((groups
), &(iterator), (void**)&(i), ((void*)0)); )
1991 (void) process_item(i);
1992
1993 ORDERED_HASHMAP_FOREACH(i, users, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); ordered_hashmap_iterate((users
), &(iterator), (void**)&(i), ((void*)0)); )
1994 (void) process_item(i);
1995
1996 r = write_files();
1997 if (r < 0)
1998 log_error_errno(r, "Failed to write files: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/sysusers/sysusers.c", 1998, __func__, "Failed to write files: %m"
) : -abs(_e); })
;
1999
2000finish:
2001 pager_close();
2002
2003 ordered_hashmap_free_with_destructor(groups, item_free)({ ({ void *_item; while ((_item = ordered_hashmap_steal_first
(groups))) item_free(_item); }); ordered_hashmap_free(groups)
; })
;
2004 ordered_hashmap_free_with_destructor(users, item_free)({ ({ void *_item; while ((_item = ordered_hashmap_steal_first
(users))) item_free(_item); }); ordered_hashmap_free(users); }
)
;
2005
2006 while ((n = ordered_hashmap_first_key(members))) {
2007 strv_free(ordered_hashmap_steal_first(members));
2008 free(n);
2009 }
2010 ordered_hashmap_free(members);
2011
2012 ordered_hashmap_free(todo_uids);
2013 ordered_hashmap_free(todo_gids);
2014
2015 free_database(database_user, database_uid);
2016 free_database(database_group, database_gid);
2017
2018 free(uid_range);
2019
2020 free(arg_root);
2021
2022 return r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0;
2023}