1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
32 #include "specifier.h"
33 #include "path-util.h"
36 #include "conf-files.h"
40 #include "fileio-label.h"
41 #include "uid-range.h"
43 typedef enum ItemType {
68 static char *arg_root = NULL;
70 static const char conf_file_dirs[] =
73 "/usr/local/lib/sysusers.d\0"
74 "/usr/lib/sysusers.d\0"
80 static Hashmap *users = NULL, *groups = NULL;
81 static Hashmap *todo_uids = NULL, *todo_gids = NULL;
82 static Hashmap *members = NULL;
84 static Hashmap *database_uid = NULL, *database_user = NULL;
85 static Hashmap *database_gid = NULL, *database_group = NULL;
87 static uid_t search_uid = (uid_t) -1;
88 static UidRange *uid_range = NULL;
89 static unsigned n_uid_range = 0;
91 #define UID_TO_PTR(u) (ULONG_TO_PTR(u+1))
92 #define PTR_TO_UID(u) ((uid_t) (PTR_TO_ULONG(u)-1))
94 #define GID_TO_PTR(g) (ULONG_TO_PTR(g+1))
95 #define PTR_TO_GID(g) ((gid_t) (PTR_TO_ULONG(g)-1))
97 #define fix_root(x) (arg_root ? strappenda(arg_root, x) : x)
99 static int load_user_database(void) {
100 _cleanup_fclose_ FILE *f = NULL;
101 const char *passwd_path;
105 passwd_path = fix_root("/etc/passwd");
106 f = fopen(passwd_path, "re");
108 return errno == ENOENT ? 0 : -errno;
110 r = hashmap_ensure_allocated(&database_user, &string_hash_ops);
114 r = hashmap_ensure_allocated(&database_uid, NULL);
119 while ((pw = fgetpwent(f))) {
123 n = strdup(pw->pw_name);
127 k = hashmap_put(database_user, n, UID_TO_PTR(pw->pw_uid));
128 if (k < 0 && k != -EEXIST) {
133 q = hashmap_put(database_uid, UID_TO_PTR(pw->pw_uid), n);
134 if (q < 0 && q != -EEXIST) {
145 if (!IN_SET(errno, 0, ENOENT))
151 static int load_group_database(void) {
152 _cleanup_fclose_ FILE *f = NULL;
153 const char *group_path;
157 group_path = fix_root("/etc/group");
158 f = fopen(group_path, "re");
160 return errno == ENOENT ? 0 : -errno;
162 r = hashmap_ensure_allocated(&database_group, &string_hash_ops);
166 r = hashmap_ensure_allocated(&database_gid, NULL);
171 while ((gr = fgetgrent(f))) {
175 n = strdup(gr->gr_name);
179 k = hashmap_put(database_group, n, GID_TO_PTR(gr->gr_gid));
180 if (k < 0 && k != -EEXIST) {
185 q = hashmap_put(database_gid, GID_TO_PTR(gr->gr_gid), n);
186 if (q < 0 && q != -EEXIST) {
197 if (!IN_SET(errno, 0, ENOENT))
203 static int make_backup(const char *target, const char *x) {
204 _cleanup_close_ int src = -1;
205 _cleanup_fclose_ FILE *dst = NULL;
207 struct timespec ts[2];
211 src = open(x, O_RDONLY|O_CLOEXEC|O_NOCTTY);
213 if (errno == ENOENT) /* No backup necessary... */
219 if (fstat(src, &st) < 0)
222 r = fopen_temporary_label(target, x, &dst, &temp);
226 r = copy_bytes(src, fileno(dst), (off_t) -1);
230 /* Don't fail on chmod() or chown(). If it stays owned by us
231 * and/or unreadable by others, then it isn't too bad... */
233 backup = strappenda(x, "-");
235 /* Copy over the access mask */
236 if (fchmod(fileno(dst), st.st_mode & 07777) < 0)
237 log_warning("Failed to change mode on %s: %m", backup);
239 if (fchown(fileno(dst), st.st_uid, st.st_gid)< 0)
240 log_warning("Failed to change ownership of %s: %m", backup);
244 futimens(fileno(dst), ts);
246 if (rename(temp, backup) < 0)
256 static int putgrent_with_members(const struct group *gr, FILE *group) {
262 a = hashmap_get(members, gr->gr_name);
264 _cleanup_strv_free_ char **l = NULL;
268 l = strv_copy(gr->gr_mem);
273 if (strv_find(l, *i))
276 if (strv_extend(&l, *i) < 0)
292 if (putgrent(&t, group) != 0)
293 return errno ? -errno : -EIO;
300 if (putgrent(gr, group) != 0)
301 return errno ? -errno : -EIO;
306 static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
312 a = hashmap_get(members, sg->sg_namp);
314 _cleanup_strv_free_ char **l = NULL;
318 l = strv_copy(sg->sg_mem);
323 if (strv_find(l, *i))
326 if (strv_extend(&l, *i) < 0)
342 if (putsgent(&t, gshadow) != 0)
343 return errno ? -errno : -EIO;
350 if (putsgent(sg, gshadow) != 0)
351 return errno ? -errno : -EIO;
356 static int write_files(void) {
358 _cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL;
359 _cleanup_free_ char *passwd_tmp = NULL, *group_tmp = NULL, *shadow_tmp = NULL, *gshadow_tmp = NULL;
360 const char *passwd_path = NULL, *group_path = NULL, *shadow_path = NULL, *gshadow_path = NULL;
362 bool group_changed = false;
367 if (hashmap_size(todo_gids) > 0 || hashmap_size(members) > 0) {
368 _cleanup_fclose_ FILE *original = NULL;
370 /* First we update the actual group list file */
371 group_path = fix_root("/etc/group");
372 r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
376 original = fopen(group_path, "re");
380 if (fstat(fileno(original), &st) < 0 ||
381 fchmod(fileno(group), st.st_mode & 07777) < 0 ||
382 fchown(fileno(group), st.st_uid, st.st_gid) < 0) {
388 while ((gr = fgetgrent(original))) {
389 /* Safety checks against name and GID
390 * collisions. Normally, this should
391 * be unnecessary, but given that we
392 * look at the entries anyway here,
393 * let's make an extra verification
394 * step that we don't generate
395 * duplicate entries. */
397 i = hashmap_get(groups, gr->gr_name);
398 if (i && i->todo_group) {
403 if (hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) {
408 r = putgrent_with_members(gr, group);
412 group_changed = true;
416 if (!IN_SET(errno, 0, ENOENT)) {
421 } else if (errno != ENOENT) {
424 } else if (fchmod(fileno(group), 0644) < 0) {
429 HASHMAP_FOREACH(i, todo_gids, iterator) {
433 .gr_passwd = (char*) "x",
436 r = putgrent_with_members(&n, group);
440 group_changed = true;
443 r = fflush_and_check(group);
452 /* OK, now also update the shadow file for the group list */
453 gshadow_path = fix_root("/etc/gshadow");
454 r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
458 original = fopen(gshadow_path, "re");
462 if (fstat(fileno(original), &st) < 0 ||
463 fchmod(fileno(gshadow), st.st_mode & 07777) < 0 ||
464 fchown(fileno(gshadow), st.st_uid, st.st_gid) < 0) {
470 while ((sg = fgetsgent(original))) {
472 i = hashmap_get(groups, sg->sg_namp);
473 if (i && i->todo_group) {
478 r = putsgent_with_members(sg, gshadow);
482 group_changed = true;
486 if (!IN_SET(errno, 0, ENOENT)) {
491 } else if (errno != ENOENT) {
494 } else if (fchmod(fileno(gshadow), 0000) < 0) {
499 HASHMAP_FOREACH(i, todo_gids, iterator) {
502 .sg_passwd = (char*) "!!",
505 r = putsgent_with_members(&n, gshadow);
509 group_changed = true;
512 r = fflush_and_check(gshadow);
517 if (hashmap_size(todo_uids) > 0) {
518 _cleanup_fclose_ FILE *original = NULL;
521 /* First we update the user database itself */
522 passwd_path = fix_root("/etc/passwd");
523 r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
527 original = fopen(passwd_path, "re");
531 if (fstat(fileno(original), &st) < 0 ||
532 fchmod(fileno(passwd), st.st_mode & 07777) < 0 ||
533 fchown(fileno(passwd), st.st_uid, st.st_gid) < 0) {
539 while ((pw = fgetpwent(original))) {
541 i = hashmap_get(users, pw->pw_name);
542 if (i && i->todo_user) {
547 if (hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) {
553 if (putpwent(pw, passwd) < 0) {
554 r = errno ? -errno : -EIO;
560 if (!IN_SET(errno, 0, ENOENT)) {
565 } else if (errno != ENOENT) {
568 } else if (fchmod(fileno(passwd), 0644) < 0) {
573 HASHMAP_FOREACH(i, todo_uids, iterator) {
578 .pw_gecos = i->description,
580 /* "x" means the password is stored in
582 .pw_passwd = (char*) "x",
584 /* We default to the root directory as home */
585 .pw_dir = i->home ? i->home : (char*) "/",
587 /* Initialize the shell to nologin,
588 * with one exception: for root we
589 * patch in something special */
590 .pw_shell = i->uid == 0 ? (char*) "/bin/sh" : (char*) "/sbin/nologin",
594 if (putpwent(&n, passwd) != 0) {
595 r = errno ? -errno : -EIO;
600 r = fflush_and_check(passwd);
609 /* The we update the shadow database */
610 shadow_path = fix_root("/etc/shadow");
611 r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
615 original = fopen(shadow_path, "re");
619 if (fstat(fileno(original), &st) < 0 ||
620 fchmod(fileno(shadow), st.st_mode & 07777) < 0 ||
621 fchown(fileno(shadow), st.st_uid, st.st_gid) < 0) {
627 while ((sp = fgetspent(original))) {
629 i = hashmap_get(users, sp->sp_namp);
630 if (i && i->todo_user) {
636 if (putspent(sp, shadow) < 0) {
637 r = errno ? -errno : -EIO;
643 if (!IN_SET(errno, 0, ENOENT)) {
647 } else if (errno != ENOENT) {
650 } else if (fchmod(fileno(shadow), 0000) < 0) {
655 lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
656 HASHMAP_FOREACH(i, todo_uids, iterator) {
659 .sp_pwdp = (char*) "!!",
666 .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
670 if (putspent(&n, shadow) != 0) {
671 r = errno ? -errno : -EIO;
676 r = fflush_and_check(shadow);
681 /* Make a backup of the old files */
684 r = make_backup("/etc/group", group_path);
689 r = make_backup("/etc/gshadow", gshadow_path);
696 r = make_backup("/etc/passwd", passwd_path);
701 r = make_backup("/etc/shadow", shadow_path);
706 /* And make the new files count */
709 if (rename(group_tmp, group_path) < 0) {
718 if (rename(gshadow_tmp, gshadow_path) < 0) {
729 if (rename(passwd_tmp, passwd_path) < 0) {
738 if (rename(shadow_tmp, shadow_path) < 0) {
762 static int uid_is_ok(uid_t uid, const char *name) {
768 /* Let's see if we already have assigned the UID a second time */
769 if (hashmap_get(todo_uids, UID_TO_PTR(uid)))
772 /* Try to avoid using uids that are already used by a group
773 * that doesn't have the same name as our new user. */
774 i = hashmap_get(todo_gids, GID_TO_PTR(uid));
775 if (i && !streq(i->name, name))
778 /* Let's check the files directly */
779 if (hashmap_contains(database_uid, UID_TO_PTR(uid)))
782 n = hashmap_get(database_gid, GID_TO_PTR(uid));
783 if (n && !streq(n, name))
786 /* Let's also check via NSS, to avoid UID clashes over LDAP and such, just in case */
792 if (!IN_SET(errno, 0, ENOENT))
796 g = getgrgid((gid_t) uid);
798 if (!streq(g->gr_name, name))
800 } else if (!IN_SET(errno, 0, ENOENT))
807 static int root_stat(const char *p, struct stat *st) {
811 if (stat(fix, st) < 0)
817 static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
819 bool found_uid = false, found_gid = false;
825 /* First, try to get the gid directly */
826 if (_gid && i->gid_path && root_stat(i->gid_path, &st) >= 0) {
831 /* Then, try to get the uid directly */
832 if ((_uid || (_gid && !found_gid))
834 && root_stat(i->uid_path, &st) >= 0) {
839 /* If we need the gid, but had no success yet, also derive it from the uid path */
840 if (_gid && !found_gid) {
846 /* If that didn't work yet, then let's reuse the gid as uid */
847 if (_uid && !found_uid && i->gid_path) {
852 } else if (root_stat(i->gid_path, &st) >= 0) {
853 uid = (uid_t) st.st_gid;
875 static int add_user(Item *i) {
881 /* Check the database directly */
882 z = hashmap_get(database_user, i->name);
884 log_debug("User %s already exists.", i->name);
885 i->uid = PTR_TO_UID(z);
896 p = getpwnam(i->name);
898 log_debug("User %s already exists.", i->name);
902 free(i->description);
903 i->description = strdup(p->pw_gecos);
906 if (!IN_SET(errno, 0, ENOENT)) {
907 log_error("Failed to check if user %s already exists: %m", i->name);
911 /* And shadow too, just to be sure */
913 sp = getspnam(i->name);
915 log_error("User %s already exists in shadow database, but not in user database.", i->name);
918 if (!IN_SET(errno, 0, ENOENT)) {
919 log_error("Failed to check if user %s already exists in shadow database: %m", i->name);
924 /* Try to use the suggested numeric uid */
926 r = uid_is_ok(i->uid, i->name);
928 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
932 log_debug("Suggested user ID " UID_FMT " for %s already used.", i->uid, i->name);
937 /* If that didn't work, try to read it from the specified path */
941 if (read_id_from_file(i, &c, NULL) > 0) {
943 if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
944 log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name);
946 r = uid_is_ok(c, i->name);
948 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
954 log_debug("User ID " UID_FMT " of file for %s is already used.", c, i->name);
959 /* Otherwise try to reuse the group ID */
960 if (!i->uid_set && i->gid_set) {
961 r = uid_is_ok((uid_t) i->gid, i->name);
963 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
967 i->uid = (uid_t) i->gid;
972 /* And if that didn't work either, let's try to find a free one */
975 r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
977 log_error("No free user ID available for %s.", i->name);
981 r = uid_is_ok(search_uid, i->name);
983 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
993 r = hashmap_ensure_allocated(&todo_uids, NULL);
997 r = hashmap_put(todo_uids, UID_TO_PTR(i->uid), i);
1001 i->todo_user = true;
1002 log_info("Creating user %s (%s) with uid " UID_FMT " and gid " GID_FMT ".", i->name, strna(i->description), i->uid, i->gid);
1007 static int gid_is_ok(gid_t gid) {
1011 if (hashmap_get(todo_gids, GID_TO_PTR(gid)))
1014 /* Avoid reusing gids that are already used by a different user */
1015 if (hashmap_get(todo_uids, UID_TO_PTR(gid)))
1018 if (hashmap_contains(database_gid, GID_TO_PTR(gid)))
1021 if (hashmap_contains(database_uid, UID_TO_PTR(gid)))
1029 if (!IN_SET(errno, 0, ENOENT))
1033 p = getpwuid((uid_t) gid);
1036 if (!IN_SET(errno, 0, ENOENT))
1043 static int add_group(Item *i) {
1049 /* Check the database directly */
1050 z = hashmap_get(database_group, i->name);
1052 log_debug("Group %s already exists.", i->name);
1053 i->gid = PTR_TO_GID(z);
1058 /* Also check NSS */
1063 g = getgrnam(i->name);
1065 log_debug("Group %s already exists.", i->name);
1070 if (!IN_SET(errno, 0, ENOENT)) {
1071 log_error("Failed to check if group %s already exists: %m", i->name);
1076 /* Try to use the suggested numeric gid */
1078 r = gid_is_ok(i->gid);
1080 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1084 log_debug("Suggested group ID " GID_FMT " for %s already used.", i->gid, i->name);
1089 /* Try to reuse the numeric uid, if there's one */
1090 if (!i->gid_set && i->uid_set) {
1091 r = gid_is_ok((gid_t) i->uid);
1093 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1097 i->gid = (gid_t) i->uid;
1102 /* If that didn't work, try to read it from the specified path */
1106 if (read_id_from_file(i, NULL, &c) > 0) {
1108 if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
1109 log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
1113 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1119 log_debug("Group ID " GID_FMT " of file for %s already used.", c, i->name);
1124 /* And if that didn't work either, let's try to find a free one */
1127 /* We look for new GIDs in the UID pool! */
1128 r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
1130 log_error("No free group ID available for %s.", i->name);
1134 r = gid_is_ok(search_uid);
1136 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1143 i->gid = search_uid;
1146 r = hashmap_ensure_allocated(&todo_gids, NULL);
1150 r = hashmap_put(todo_gids, GID_TO_PTR(i->gid), i);
1154 i->todo_group = true;
1155 log_info("Creating group %s with gid " GID_FMT ".", i->name, i->gid);
1160 static int process_item(Item *i) {
1177 j = hashmap_get(users, i->name);
1179 /* There's already user to be created for this
1180 * name, let's process that in one step */
1189 j->gid_path = strdup(i->gid_path);
1197 return add_group(i);
1201 assert_not_reached("Unknown item type");
1205 static void item_free(Item *i) {
1213 free(i->description);
1217 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1219 static int add_implicit(void) {
1224 /* Implicitly create additional users and groups, if they were listed in "m" lines */
1226 HASHMAP_FOREACH_KEY(l, g, members, iterator) {
1230 i = hashmap_get(groups, g);
1232 _cleanup_(item_freep) Item *j = NULL;
1234 r = hashmap_ensure_allocated(&groups, &string_hash_ops);
1242 j->type = ADD_GROUP;
1243 j->name = strdup(g);
1247 r = hashmap_put(groups, j->name, j);
1251 log_debug("Adding implicit group '%s' due to m line", j->name);
1255 STRV_FOREACH(m, l) {
1257 i = hashmap_get(users, *m);
1259 _cleanup_(item_freep) Item *j = NULL;
1261 r = hashmap_ensure_allocated(&users, &string_hash_ops);
1270 j->name = strdup(*m);
1274 r = hashmap_put(users, j->name, j);
1278 log_debug("Adding implicit user '%s' due to m line", j->name);
1287 static bool item_equal(Item *a, Item *b) {
1291 if (a->type != b->type)
1294 if (!streq_ptr(a->name, b->name))
1297 if (!streq_ptr(a->uid_path, b->uid_path))
1300 if (!streq_ptr(a->gid_path, b->gid_path))
1303 if (!streq_ptr(a->description, b->description))
1306 if (a->uid_set != b->uid_set)
1309 if (a->uid_set && a->uid != b->uid)
1312 if (a->gid_set != b->gid_set)
1315 if (a->gid_set && a->gid != b->gid)
1318 if (!streq_ptr(a->home, b->home))
1324 static bool valid_user_group_name(const char *u) {
1331 if (!(u[0] >= 'a' && u[0] <= 'z') &&
1332 !(u[0] >= 'A' && u[0] <= 'Z') &&
1336 for (i = u+1; *i; i++) {
1337 if (!(*i >= 'a' && *i <= 'z') &&
1338 !(*i >= 'A' && *i <= 'Z') &&
1339 !(*i >= '0' && *i <= '9') &&
1345 sz = sysconf(_SC_LOGIN_NAME_MAX);
1348 if ((size_t) (i-u) > (size_t) sz)
1351 if ((size_t) (i-u) > UT_NAMESIZE - 1)
1357 static bool valid_gecos(const char *d) {
1362 if (!utf8_is_valid(d))
1365 if (string_has_cc(d, NULL))
1368 /* Colons are used as field separators, and hence not OK */
1375 static bool valid_home(const char *p) {
1380 if (!utf8_is_valid(p))
1383 if (string_has_cc(p, NULL))
1386 if (!path_is_absolute(p))
1389 if (!path_is_safe(p))
1392 /* Colons are used as field separators, and hence not OK */
1399 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1401 static const Specifier specifier_table[] = {
1402 { 'm', specifier_machine_id, NULL },
1403 { 'b', specifier_boot_id, NULL },
1404 { 'H', specifier_host_name, NULL },
1405 { 'v', specifier_kernel_release, NULL },
1409 _cleanup_free_ char *action = NULL, *name = NULL, *id = NULL, *resolved_name = NULL, *resolved_id = NULL, *description = NULL, *home = NULL;
1410 _cleanup_(item_freep) Item *i = NULL;
1422 r = unquote_many_words(&p, &action, &name, &id, &description, &home, NULL);
1424 log_error("[%s:%u] Syntax error.", fname, line);
1428 log_error("[%s:%u] Missing action and name columns.", fname, line);
1432 log_error("[%s:%u] Trailing garbage.", fname, line);
1437 if (strlen(action) != 1) {
1438 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1442 if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)) {
1443 log_error("[%s:%u] Unknown command command type '%c'.", fname, line, action[0]);
1448 if (isempty(name) || streq(name, "-")) {
1454 r = specifier_printf(name, specifier_table, NULL, &resolved_name);
1456 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
1460 if (!valid_user_group_name(resolved_name)) {
1461 log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_name);
1467 if (isempty(id) || streq(id, "-")) {
1473 r = specifier_printf(id, specifier_table, NULL, &resolved_id);
1475 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
1480 /* Verify description */
1481 if (isempty(description) || streq(description, "-")) {
1487 if (!valid_gecos(description)) {
1488 log_error("[%s:%u] '%s' is not a valid GECOS field.", fname, line, description);
1494 if (isempty(home) || streq(home, "-")) {
1500 if (!valid_home(home)) {
1501 log_error("[%s:%u] '%s' is not a valid home directory field.", fname, line, home);
1506 switch (action[0]) {
1509 if (resolved_name) {
1510 log_error("[%s:%u] Lines of type 'r' don't take a name field.", fname, line);
1515 log_error("[%s:%u] Lines of type 'r' require a ID range in the third field.", fname, line);
1520 log_error("[%s:%u] Lines of type 'r' don't take a GECOS field.", fname, line);
1525 log_error("[%s:%u] Lines of type 'r' don't take a home directory field.", fname, line);
1529 r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
1531 log_error("[%s:%u] Invalid UID range %s.", fname, line, resolved_id);
1540 /* Try to extend an existing member or group item */
1542 log_error("[%s:%u] Lines of type 'm' require a user name in the second field.", fname, line);
1547 log_error("[%s:%u] Lines of type 'm' require a group name in the third field.", fname, line);
1551 if (!valid_user_group_name(resolved_id)) {
1552 log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_id);
1557 log_error("[%s:%u] Lines of type 'm' don't take a GECOS field.", fname, line);
1562 log_error("[%s:%u] Lines of type 'm' don't take a home directory field.", fname, line);
1566 r = hashmap_ensure_allocated(&members, &string_hash_ops);
1570 l = hashmap_get(members, resolved_id);
1572 /* A list for this group name already exists, let's append to it */
1573 r = strv_push(&l, resolved_name);
1577 resolved_name = NULL;
1579 assert_se(hashmap_update(members, resolved_id, l) >= 0);
1581 /* No list for this group name exists yet, create one */
1583 l = new0(char *, 2);
1587 l[0] = resolved_name;
1590 r = hashmap_put(members, resolved_id, l);
1596 resolved_id = resolved_name = NULL;
1604 log_error("[%s:%u] Lines of type 'u' require a user name in the second field.", fname, line);
1608 r = hashmap_ensure_allocated(&users, &string_hash_ops);
1617 if (path_is_absolute(resolved_id)) {
1618 i->uid_path = resolved_id;
1621 path_kill_slashes(i->uid_path);
1623 r = parse_uid(resolved_id, &i->uid);
1625 log_error("Failed to parse UID: %s", id);
1633 i->description = description;
1644 log_error("[%s:%u] Lines of type 'g' require a user name in the second field.", fname, line);
1649 log_error("[%s:%u] Lines of type 'g' don't take a GECOS field.", fname, line);
1654 log_error("[%s:%u] Lines of type 'g' don't take a home directory field.", fname, line);
1658 r = hashmap_ensure_allocated(&groups, &string_hash_ops);
1667 if (path_is_absolute(resolved_id)) {
1668 i->gid_path = resolved_id;
1671 path_kill_slashes(i->gid_path);
1673 r = parse_gid(resolved_id, &i->gid);
1675 log_error("Failed to parse GID: %s", id);
1690 i->type = action[0];
1691 i->name = resolved_name;
1692 resolved_name = NULL;
1694 existing = hashmap_get(h, i->name);
1697 /* Two identical items are fine */
1698 if (!item_equal(existing, i))
1699 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->name);
1704 r = hashmap_put(h, i->name, i);
1712 static int read_config_file(const char *fn, bool ignore_enoent) {
1713 _cleanup_fclose_ FILE *rf = NULL;
1715 char line[LINE_MAX];
1724 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &rf);
1726 if (ignore_enoent && r == -ENOENT)
1729 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1736 FOREACH_LINE(line, f, break) {
1743 if (*l == '#' || *l == 0)
1746 k = parse_line(fn, v, l);
1747 if (k < 0 && r == 0)
1752 log_error("Failed to read from file %s: %m", fn);
1760 static void free_database(Hashmap *by_name, Hashmap *by_id) {
1764 name = hashmap_first(by_id);
1768 hashmap_remove(by_name, name);
1770 hashmap_steal_first_key(by_id);
1774 while ((name = hashmap_steal_first_key(by_name)))
1777 hashmap_free(by_name);
1778 hashmap_free(by_id);
1781 static void help(void) {
1782 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1783 "Creates system user accounts.\n\n"
1784 " -h --help Show this help\n"
1785 " --version Show package version\n"
1786 " --root=PATH Operate on an alternate filesystem root\n"
1787 , program_invocation_short_name);
1790 static int parse_argv(int argc, char *argv[]) {
1793 ARG_VERSION = 0x100,
1797 static const struct option options[] = {
1798 { "help", no_argument, NULL, 'h' },
1799 { "version", no_argument, NULL, ARG_VERSION },
1800 { "root", required_argument, NULL, ARG_ROOT },
1809 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1818 puts(PACKAGE_STRING);
1819 puts(SYSTEMD_FEATURES);
1824 arg_root = path_make_absolute_cwd(optarg);
1828 path_kill_slashes(arg_root);
1835 assert_not_reached("Unhandled option");
1841 int main(int argc, char *argv[]) {
1843 _cleanup_close_ int lock = -1;
1849 r = parse_argv(argc, argv);
1853 log_set_target(LOG_TARGET_AUTO);
1854 log_parse_environment();
1859 r = mac_selinux_init(NULL);
1861 log_error("SELinux setup failed: %s", strerror(-r));
1865 if (optind < argc) {
1868 for (j = optind; j < argc; j++) {
1869 k = read_config_file(argv[j], false);
1870 if (k < 0 && r == 0)
1874 _cleanup_strv_free_ char **files = NULL;
1877 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1879 log_error("Failed to enumerate sysusers.d files: %s", strerror(-r));
1883 STRV_FOREACH(f, files) {
1884 k = read_config_file(*f, true);
1885 if (k < 0 && r == 0)
1891 /* Default to default range of 1..SYSTEMD_UID_MAX */
1892 r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX);
1903 lock = take_password_lock(arg_root);
1905 log_error("Failed to take lock: %s", strerror(-lock));
1909 r = load_user_database();
1911 log_error("Failed to load user database: %s", strerror(-r));
1915 r = load_group_database();
1917 log_error("Failed to read group database: %s", strerror(-r));
1921 HASHMAP_FOREACH(i, groups, iterator)
1924 HASHMAP_FOREACH(i, users, iterator)
1929 log_error("Failed to write files: %s", strerror(-r));
1932 while ((i = hashmap_steal_first(groups)))
1935 while ((i = hashmap_steal_first(users)))
1938 while ((n = hashmap_first_key(members))) {
1939 strv_free(hashmap_steal_first(members));
1943 hashmap_free(groups);
1944 hashmap_free(users);
1945 hashmap_free(members);
1946 hashmap_free(todo_uids);
1947 hashmap_free(todo_gids);
1949 free_database(database_user, database_uid);
1950 free_database(database_group, database_gid);
1954 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;