| File: | build-scan/../src/sysusers/sysusers.c |
| Warning: | line 728, column 23 Null pointer passed to 1st parameter expecting 'nonnull' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | ||||
| 28 | typedef enum ItemType { | |||
| 29 | ADD_USER = 'u', | |||
| 30 | ADD_GROUP = 'g', | |||
| 31 | ADD_MEMBER = 'm', | |||
| 32 | ADD_RANGE = 'r', | |||
| 33 | } ItemType; | |||
| 34 | ||||
| 35 | typedef 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 | ||||
| 61 | static char *arg_root = NULL((void*)0); | |||
| 62 | static bool_Bool arg_cat_config = false0; | |||
| 63 | static const char *arg_replace = NULL((void*)0); | |||
| 64 | static bool_Bool arg_inline = false0; | |||
| 65 | static bool_Bool arg_no_pager = false0; | |||
| 66 | ||||
| 67 | static OrderedHashmap *users = NULL((void*)0), *groups = NULL((void*)0); | |||
| 68 | static OrderedHashmap *todo_uids = NULL((void*)0), *todo_gids = NULL((void*)0); | |||
| 69 | static OrderedHashmap *members = NULL((void*)0); | |||
| 70 | ||||
| 71 | static Hashmap *database_uid = NULL((void*)0), *database_user = NULL((void*)0); | |||
| 72 | static Hashmap *database_gid = NULL((void*)0), *database_group = NULL((void*)0); | |||
| 73 | ||||
| 74 | static uid_t search_uid = UID_INVALID((uid_t) -1); | |||
| 75 | static UidRange *uid_range = NULL((void*)0); | |||
| 76 | static unsigned n_uid_range = 0; | |||
| 77 | ||||
| 78 | static 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; }); | |||
| 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 | ||||
| 124 | static 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 | ||||
| 176 | static 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 | ||||
| 230 | fail: | |||
| 231 | unlink(temp); | |||
| 232 | return r; | |||
| 233 | } | |||
| 234 | ||||
| 235 | static 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 | |||
| 280 | static 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 | ||||
| 325 | static 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 | ||||
| 334 | static 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 | ||||
| 347 | static const char* default_shell(uid_t uid) { | |||
| 348 | return uid == 0 ? "/bin/sh" : "/sbin/nologin"; | |||
| 349 | } | |||
| 350 | ||||
| 351 | static 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 | ||||
| 450 | static 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 | ||||
| 549 | static 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 | ||||
| 647 | static 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 | ||||
| 722 | static 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 | ||||
| 806 | static 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 | ||||
| 857 | static 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 | ||||
| 867 | static 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 | ||||
| 925 | static 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 | ||||
| 1038 | static 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 | ||||
| 1074 | static 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 | ||||
| 1195 | static 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 | ||||
| 1230 | static 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 | ||||
| 1244 | DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free)static inline void item_freep(Item* *p) { if (*p) item_free(* p); }; | |||
| 1245 | ||||
| 1246 | static 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 | ||||
| 1309 | static 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 | ||||
| 1349 | static 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 | ||||
| 1681 | static 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 | ||||
| 1728 | static 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 | ||||
| 1749 | static 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 | ||||
| 1762 | static 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 | ||||
| 1775 | static 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 | ||||
| 1861 | static 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 | ||||
| 1881 | static 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 | ||||
| 1908 | int 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
| |||
| ||||
| 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
| |||
| 1924 | r = cat_config(); | |||
| 1925 | goto finish; | |||
| 1926 | } | |||
| 1927 | ||||
| 1928 | umask(0022); | |||
| 1929 | ||||
| 1930 | r = mac_selinux_init(); | |||
| 1931 | if (r < 0) { | |||
| 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
| |||
| 1943 | r = read_config_files(argv + optind); | |||
| 1944 | else | |||
| 1945 | r = parse_arguments(argv + optind); | |||
| 1946 | if (r
| |||
| 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) { | |||
| 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
| |||
| 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) { | |||
| 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
| |||
| 1970 | goto finish; | |||
| 1971 | ||||
| 1972 | lock = take_etc_passwd_lock(arg_root); | |||
| 1973 | if (lock < 0) { | |||
| 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(); | |||
| 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 | ||||
| 2000 | finish: | |||
| 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 | } |