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 if (futimens(fileno(dst), ts) < 0)
245 log_warning("Failed to fix access and modification time of %s: %m", backup);
247 if (rename(temp, backup) < 0)
257 static int putgrent_with_members(const struct group *gr, FILE *group) {
263 a = hashmap_get(members, gr->gr_name);
265 _cleanup_strv_free_ char **l = NULL;
269 l = strv_copy(gr->gr_mem);
274 if (strv_find(l, *i))
277 if (strv_extend(&l, *i) < 0)
293 if (putgrent(&t, group) != 0)
294 return errno ? -errno : -EIO;
301 if (putgrent(gr, group) != 0)
302 return errno ? -errno : -EIO;
307 static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
313 a = hashmap_get(members, sg->sg_namp);
315 _cleanup_strv_free_ char **l = NULL;
319 l = strv_copy(sg->sg_mem);
324 if (strv_find(l, *i))
327 if (strv_extend(&l, *i) < 0)
343 if (putsgent(&t, gshadow) != 0)
344 return errno ? -errno : -EIO;
351 if (putsgent(sg, gshadow) != 0)
352 return errno ? -errno : -EIO;
357 static int write_files(void) {
359 _cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL;
360 _cleanup_free_ char *passwd_tmp = NULL, *group_tmp = NULL, *shadow_tmp = NULL, *gshadow_tmp = NULL;
361 const char *passwd_path = NULL, *group_path = NULL, *shadow_path = NULL, *gshadow_path = NULL;
363 bool group_changed = false;
368 if (hashmap_size(todo_gids) > 0 || hashmap_size(members) > 0) {
369 _cleanup_fclose_ FILE *original = NULL;
371 /* First we update the actual group list file */
372 group_path = fix_root("/etc/group");
373 r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
377 original = fopen(group_path, "re");
381 if (fstat(fileno(original), &st) < 0 ||
382 fchmod(fileno(group), st.st_mode & 07777) < 0 ||
383 fchown(fileno(group), st.st_uid, st.st_gid) < 0) {
389 while ((gr = fgetgrent(original))) {
390 /* Safety checks against name and GID
391 * collisions. Normally, this should
392 * be unnecessary, but given that we
393 * look at the entries anyway here,
394 * let's make an extra verification
395 * step that we don't generate
396 * duplicate entries. */
398 i = hashmap_get(groups, gr->gr_name);
399 if (i && i->todo_group) {
404 if (hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) {
409 r = putgrent_with_members(gr, group);
413 group_changed = true;
417 if (!IN_SET(errno, 0, ENOENT)) {
422 } else if (errno != ENOENT) {
425 } else if (fchmod(fileno(group), 0644) < 0) {
430 HASHMAP_FOREACH(i, todo_gids, iterator) {
434 .gr_passwd = (char*) "x",
437 r = putgrent_with_members(&n, group);
441 group_changed = true;
444 r = fflush_and_check(group);
453 /* OK, now also update the shadow file for the group list */
454 gshadow_path = fix_root("/etc/gshadow");
455 r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
459 original = fopen(gshadow_path, "re");
463 if (fstat(fileno(original), &st) < 0 ||
464 fchmod(fileno(gshadow), st.st_mode & 07777) < 0 ||
465 fchown(fileno(gshadow), st.st_uid, st.st_gid) < 0) {
471 while ((sg = fgetsgent(original))) {
473 i = hashmap_get(groups, sg->sg_namp);
474 if (i && i->todo_group) {
479 r = putsgent_with_members(sg, gshadow);
483 group_changed = true;
487 if (!IN_SET(errno, 0, ENOENT)) {
492 } else if (errno != ENOENT) {
495 } else if (fchmod(fileno(gshadow), 0000) < 0) {
500 HASHMAP_FOREACH(i, todo_gids, iterator) {
503 .sg_passwd = (char*) "!!",
506 r = putsgent_with_members(&n, gshadow);
510 group_changed = true;
513 r = fflush_and_check(gshadow);
518 if (hashmap_size(todo_uids) > 0) {
519 _cleanup_fclose_ FILE *original = NULL;
522 /* First we update the user database itself */
523 passwd_path = fix_root("/etc/passwd");
524 r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
528 original = fopen(passwd_path, "re");
532 if (fstat(fileno(original), &st) < 0 ||
533 fchmod(fileno(passwd), st.st_mode & 07777) < 0 ||
534 fchown(fileno(passwd), st.st_uid, st.st_gid) < 0) {
540 while ((pw = fgetpwent(original))) {
542 i = hashmap_get(users, pw->pw_name);
543 if (i && i->todo_user) {
548 if (hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) {
554 if (putpwent(pw, passwd) < 0) {
555 r = errno ? -errno : -EIO;
561 if (!IN_SET(errno, 0, ENOENT)) {
566 } else if (errno != ENOENT) {
569 } else if (fchmod(fileno(passwd), 0644) < 0) {
574 HASHMAP_FOREACH(i, todo_uids, iterator) {
579 .pw_gecos = i->description,
581 /* "x" means the password is stored in
583 .pw_passwd = (char*) "x",
585 /* We default to the root directory as home */
586 .pw_dir = i->home ? i->home : (char*) "/",
588 /* Initialize the shell to nologin,
589 * with one exception: for root we
590 * patch in something special */
591 .pw_shell = i->uid == 0 ? (char*) "/bin/sh" : (char*) "/sbin/nologin",
595 if (putpwent(&n, passwd) != 0) {
596 r = errno ? -errno : -EIO;
601 r = fflush_and_check(passwd);
610 /* The we update the shadow database */
611 shadow_path = fix_root("/etc/shadow");
612 r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
616 original = fopen(shadow_path, "re");
620 if (fstat(fileno(original), &st) < 0 ||
621 fchmod(fileno(shadow), st.st_mode & 07777) < 0 ||
622 fchown(fileno(shadow), st.st_uid, st.st_gid) < 0) {
628 while ((sp = fgetspent(original))) {
630 i = hashmap_get(users, sp->sp_namp);
631 if (i && i->todo_user) {
637 if (putspent(sp, shadow) < 0) {
638 r = errno ? -errno : -EIO;
644 if (!IN_SET(errno, 0, ENOENT)) {
648 } else if (errno != ENOENT) {
651 } else if (fchmod(fileno(shadow), 0000) < 0) {
656 lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
657 HASHMAP_FOREACH(i, todo_uids, iterator) {
660 .sp_pwdp = (char*) "!!",
667 .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
671 if (putspent(&n, shadow) != 0) {
672 r = errno ? -errno : -EIO;
677 r = fflush_and_check(shadow);
682 /* Make a backup of the old files */
685 r = make_backup("/etc/group", group_path);
690 r = make_backup("/etc/gshadow", gshadow_path);
697 r = make_backup("/etc/passwd", passwd_path);
702 r = make_backup("/etc/shadow", shadow_path);
707 /* And make the new files count */
710 if (rename(group_tmp, group_path) < 0) {
719 if (rename(gshadow_tmp, gshadow_path) < 0) {
730 if (rename(passwd_tmp, passwd_path) < 0) {
739 if (rename(shadow_tmp, shadow_path) < 0) {
763 static int uid_is_ok(uid_t uid, const char *name) {
769 /* Let's see if we already have assigned the UID a second time */
770 if (hashmap_get(todo_uids, UID_TO_PTR(uid)))
773 /* Try to avoid using uids that are already used by a group
774 * that doesn't have the same name as our new user. */
775 i = hashmap_get(todo_gids, GID_TO_PTR(uid));
776 if (i && !streq(i->name, name))
779 /* Let's check the files directly */
780 if (hashmap_contains(database_uid, UID_TO_PTR(uid)))
783 n = hashmap_get(database_gid, GID_TO_PTR(uid));
784 if (n && !streq(n, name))
787 /* Let's also check via NSS, to avoid UID clashes over LDAP and such, just in case */
793 if (!IN_SET(errno, 0, ENOENT))
797 g = getgrgid((gid_t) uid);
799 if (!streq(g->gr_name, name))
801 } else if (!IN_SET(errno, 0, ENOENT))
808 static int root_stat(const char *p, struct stat *st) {
812 if (stat(fix, st) < 0)
818 static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
820 bool found_uid = false, found_gid = false;
826 /* First, try to get the gid directly */
827 if (_gid && i->gid_path && root_stat(i->gid_path, &st) >= 0) {
832 /* Then, try to get the uid directly */
833 if ((_uid || (_gid && !found_gid))
835 && root_stat(i->uid_path, &st) >= 0) {
840 /* If we need the gid, but had no success yet, also derive it from the uid path */
841 if (_gid && !found_gid) {
847 /* If that didn't work yet, then let's reuse the gid as uid */
848 if (_uid && !found_uid && i->gid_path) {
853 } else if (root_stat(i->gid_path, &st) >= 0) {
854 uid = (uid_t) st.st_gid;
876 static int add_user(Item *i) {
882 /* Check the database directly */
883 z = hashmap_get(database_user, i->name);
885 log_debug("User %s already exists.", i->name);
886 i->uid = PTR_TO_UID(z);
897 p = getpwnam(i->name);
899 log_debug("User %s already exists.", i->name);
903 free(i->description);
904 i->description = strdup(p->pw_gecos);
907 if (!IN_SET(errno, 0, ENOENT)) {
908 log_error("Failed to check if user %s already exists: %m", i->name);
912 /* And shadow too, just to be sure */
914 sp = getspnam(i->name);
916 log_error("User %s already exists in shadow database, but not in user database.", i->name);
919 if (!IN_SET(errno, 0, ENOENT)) {
920 log_error("Failed to check if user %s already exists in shadow database: %m", i->name);
925 /* Try to use the suggested numeric uid */
927 r = uid_is_ok(i->uid, i->name);
929 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
933 log_debug("Suggested user ID " UID_FMT " for %s already used.", i->uid, i->name);
938 /* If that didn't work, try to read it from the specified path */
942 if (read_id_from_file(i, &c, NULL) > 0) {
944 if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
945 log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name);
947 r = uid_is_ok(c, i->name);
949 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
955 log_debug("User ID " UID_FMT " of file for %s is already used.", c, i->name);
960 /* Otherwise try to reuse the group ID */
961 if (!i->uid_set && i->gid_set) {
962 r = uid_is_ok((uid_t) i->gid, i->name);
964 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
968 i->uid = (uid_t) i->gid;
973 /* And if that didn't work either, let's try to find a free one */
976 r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
978 log_error("No free user ID available for %s.", i->name);
982 r = uid_is_ok(search_uid, i->name);
984 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
994 r = hashmap_ensure_allocated(&todo_uids, NULL);
998 r = hashmap_put(todo_uids, UID_TO_PTR(i->uid), i);
1002 i->todo_user = true;
1003 log_info("Creating user %s (%s) with uid " UID_FMT " and gid " GID_FMT ".", i->name, strna(i->description), i->uid, i->gid);
1008 static int gid_is_ok(gid_t gid) {
1012 if (hashmap_get(todo_gids, GID_TO_PTR(gid)))
1015 /* Avoid reusing gids that are already used by a different user */
1016 if (hashmap_get(todo_uids, UID_TO_PTR(gid)))
1019 if (hashmap_contains(database_gid, GID_TO_PTR(gid)))
1022 if (hashmap_contains(database_uid, UID_TO_PTR(gid)))
1030 if (!IN_SET(errno, 0, ENOENT))
1034 p = getpwuid((uid_t) gid);
1037 if (!IN_SET(errno, 0, ENOENT))
1044 static int add_group(Item *i) {
1050 /* Check the database directly */
1051 z = hashmap_get(database_group, i->name);
1053 log_debug("Group %s already exists.", i->name);
1054 i->gid = PTR_TO_GID(z);
1059 /* Also check NSS */
1064 g = getgrnam(i->name);
1066 log_debug("Group %s already exists.", i->name);
1071 if (!IN_SET(errno, 0, ENOENT)) {
1072 log_error("Failed to check if group %s already exists: %m", i->name);
1077 /* Try to use the suggested numeric gid */
1079 r = gid_is_ok(i->gid);
1081 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1085 log_debug("Suggested group ID " GID_FMT " for %s already used.", i->gid, i->name);
1090 /* Try to reuse the numeric uid, if there's one */
1091 if (!i->gid_set && i->uid_set) {
1092 r = gid_is_ok((gid_t) i->uid);
1094 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1098 i->gid = (gid_t) i->uid;
1103 /* If that didn't work, try to read it from the specified path */
1107 if (read_id_from_file(i, NULL, &c) > 0) {
1109 if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
1110 log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
1114 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1120 log_debug("Group ID " GID_FMT " of file for %s already used.", c, i->name);
1125 /* And if that didn't work either, let's try to find a free one */
1128 /* We look for new GIDs in the UID pool! */
1129 r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
1131 log_error("No free group ID available for %s.", i->name);
1135 r = gid_is_ok(search_uid);
1137 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1144 i->gid = search_uid;
1147 r = hashmap_ensure_allocated(&todo_gids, NULL);
1151 r = hashmap_put(todo_gids, GID_TO_PTR(i->gid), i);
1155 i->todo_group = true;
1156 log_info("Creating group %s with gid " GID_FMT ".", i->name, i->gid);
1161 static int process_item(Item *i) {
1178 j = hashmap_get(users, i->name);
1180 /* There's already user to be created for this
1181 * name, let's process that in one step */
1190 j->gid_path = strdup(i->gid_path);
1198 return add_group(i);
1202 assert_not_reached("Unknown item type");
1206 static void item_free(Item *i) {
1214 free(i->description);
1218 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1220 static int add_implicit(void) {
1225 /* Implicitly create additional users and groups, if they were listed in "m" lines */
1227 HASHMAP_FOREACH_KEY(l, g, members, iterator) {
1231 i = hashmap_get(groups, g);
1233 _cleanup_(item_freep) Item *j = NULL;
1235 r = hashmap_ensure_allocated(&groups, &string_hash_ops);
1243 j->type = ADD_GROUP;
1244 j->name = strdup(g);
1248 r = hashmap_put(groups, j->name, j);
1252 log_debug("Adding implicit group '%s' due to m line", j->name);
1256 STRV_FOREACH(m, l) {
1258 i = hashmap_get(users, *m);
1260 _cleanup_(item_freep) Item *j = NULL;
1262 r = hashmap_ensure_allocated(&users, &string_hash_ops);
1271 j->name = strdup(*m);
1275 r = hashmap_put(users, j->name, j);
1279 log_debug("Adding implicit user '%s' due to m line", j->name);
1288 static bool item_equal(Item *a, Item *b) {
1292 if (a->type != b->type)
1295 if (!streq_ptr(a->name, b->name))
1298 if (!streq_ptr(a->uid_path, b->uid_path))
1301 if (!streq_ptr(a->gid_path, b->gid_path))
1304 if (!streq_ptr(a->description, b->description))
1307 if (a->uid_set != b->uid_set)
1310 if (a->uid_set && a->uid != b->uid)
1313 if (a->gid_set != b->gid_set)
1316 if (a->gid_set && a->gid != b->gid)
1319 if (!streq_ptr(a->home, b->home))
1325 static bool valid_user_group_name(const char *u) {
1332 if (!(u[0] >= 'a' && u[0] <= 'z') &&
1333 !(u[0] >= 'A' && u[0] <= 'Z') &&
1337 for (i = u+1; *i; i++) {
1338 if (!(*i >= 'a' && *i <= 'z') &&
1339 !(*i >= 'A' && *i <= 'Z') &&
1340 !(*i >= '0' && *i <= '9') &&
1346 sz = sysconf(_SC_LOGIN_NAME_MAX);
1349 if ((size_t) (i-u) > (size_t) sz)
1352 if ((size_t) (i-u) > UT_NAMESIZE - 1)
1358 static bool valid_gecos(const char *d) {
1363 if (!utf8_is_valid(d))
1366 if (string_has_cc(d, NULL))
1369 /* Colons are used as field separators, and hence not OK */
1376 static bool valid_home(const char *p) {
1381 if (!utf8_is_valid(p))
1384 if (string_has_cc(p, NULL))
1387 if (!path_is_absolute(p))
1390 if (!path_is_safe(p))
1393 /* Colons are used as field separators, and hence not OK */
1400 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1402 static const Specifier specifier_table[] = {
1403 { 'm', specifier_machine_id, NULL },
1404 { 'b', specifier_boot_id, NULL },
1405 { 'H', specifier_host_name, NULL },
1406 { 'v', specifier_kernel_release, NULL },
1410 _cleanup_free_ char *action = NULL, *name = NULL, *id = NULL, *resolved_name = NULL, *resolved_id = NULL, *description = NULL, *home = NULL;
1411 _cleanup_(item_freep) Item *i = NULL;
1423 r = unquote_many_words(&p, &action, &name, &id, &description, &home, NULL);
1425 log_error("[%s:%u] Syntax error.", fname, line);
1429 log_error("[%s:%u] Missing action and name columns.", fname, line);
1433 log_error("[%s:%u] Trailing garbage.", fname, line);
1438 if (strlen(action) != 1) {
1439 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1443 if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)) {
1444 log_error("[%s:%u] Unknown command command type '%c'.", fname, line, action[0]);
1449 if (isempty(name) || streq(name, "-")) {
1455 r = specifier_printf(name, specifier_table, NULL, &resolved_name);
1457 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
1461 if (!valid_user_group_name(resolved_name)) {
1462 log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_name);
1468 if (isempty(id) || streq(id, "-")) {
1474 r = specifier_printf(id, specifier_table, NULL, &resolved_id);
1476 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
1481 /* Verify description */
1482 if (isempty(description) || streq(description, "-")) {
1488 if (!valid_gecos(description)) {
1489 log_error("[%s:%u] '%s' is not a valid GECOS field.", fname, line, description);
1495 if (isempty(home) || streq(home, "-")) {
1501 if (!valid_home(home)) {
1502 log_error("[%s:%u] '%s' is not a valid home directory field.", fname, line, home);
1507 switch (action[0]) {
1510 if (resolved_name) {
1511 log_error("[%s:%u] Lines of type 'r' don't take a name field.", fname, line);
1516 log_error("[%s:%u] Lines of type 'r' require a ID range in the third field.", fname, line);
1521 log_error("[%s:%u] Lines of type 'r' don't take a GECOS field.", fname, line);
1526 log_error("[%s:%u] Lines of type 'r' don't take a home directory field.", fname, line);
1530 r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
1532 log_error("[%s:%u] Invalid UID range %s.", fname, line, resolved_id);
1541 /* Try to extend an existing member or group item */
1543 log_error("[%s:%u] Lines of type 'm' require a user name in the second field.", fname, line);
1548 log_error("[%s:%u] Lines of type 'm' require a group name in the third field.", fname, line);
1552 if (!valid_user_group_name(resolved_id)) {
1553 log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_id);
1558 log_error("[%s:%u] Lines of type 'm' don't take a GECOS field.", fname, line);
1563 log_error("[%s:%u] Lines of type 'm' don't take a home directory field.", fname, line);
1567 r = hashmap_ensure_allocated(&members, &string_hash_ops);
1571 l = hashmap_get(members, resolved_id);
1573 /* A list for this group name already exists, let's append to it */
1574 r = strv_push(&l, resolved_name);
1578 resolved_name = NULL;
1580 assert_se(hashmap_update(members, resolved_id, l) >= 0);
1582 /* No list for this group name exists yet, create one */
1584 l = new0(char *, 2);
1588 l[0] = resolved_name;
1591 r = hashmap_put(members, resolved_id, l);
1597 resolved_id = resolved_name = NULL;
1605 log_error("[%s:%u] Lines of type 'u' require a user name in the second field.", fname, line);
1609 r = hashmap_ensure_allocated(&users, &string_hash_ops);
1618 if (path_is_absolute(resolved_id)) {
1619 i->uid_path = resolved_id;
1622 path_kill_slashes(i->uid_path);
1624 r = parse_uid(resolved_id, &i->uid);
1626 log_error("Failed to parse UID: %s", id);
1634 i->description = description;
1645 log_error("[%s:%u] Lines of type 'g' require a user name in the second field.", fname, line);
1650 log_error("[%s:%u] Lines of type 'g' don't take a GECOS field.", fname, line);
1655 log_error("[%s:%u] Lines of type 'g' don't take a home directory field.", fname, line);
1659 r = hashmap_ensure_allocated(&groups, &string_hash_ops);
1668 if (path_is_absolute(resolved_id)) {
1669 i->gid_path = resolved_id;
1672 path_kill_slashes(i->gid_path);
1674 r = parse_gid(resolved_id, &i->gid);
1676 log_error("Failed to parse GID: %s", id);
1691 i->type = action[0];
1692 i->name = resolved_name;
1693 resolved_name = NULL;
1695 existing = hashmap_get(h, i->name);
1698 /* Two identical items are fine */
1699 if (!item_equal(existing, i))
1700 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->name);
1705 r = hashmap_put(h, i->name, i);
1713 static int read_config_file(const char *fn, bool ignore_enoent) {
1714 _cleanup_fclose_ FILE *rf = NULL;
1716 char line[LINE_MAX];
1725 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &rf);
1727 if (ignore_enoent && r == -ENOENT)
1730 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1737 FOREACH_LINE(line, f, break) {
1744 if (*l == '#' || *l == 0)
1747 k = parse_line(fn, v, l);
1748 if (k < 0 && r == 0)
1753 log_error("Failed to read from file %s: %m", fn);
1761 static void free_database(Hashmap *by_name, Hashmap *by_id) {
1765 name = hashmap_first(by_id);
1769 hashmap_remove(by_name, name);
1771 hashmap_steal_first_key(by_id);
1775 while ((name = hashmap_steal_first_key(by_name)))
1778 hashmap_free(by_name);
1779 hashmap_free(by_id);
1782 static void help(void) {
1783 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1784 "Creates system user accounts.\n\n"
1785 " -h --help Show this help\n"
1786 " --version Show package version\n"
1787 " --root=PATH Operate on an alternate filesystem root\n"
1788 , program_invocation_short_name);
1791 static int parse_argv(int argc, char *argv[]) {
1794 ARG_VERSION = 0x100,
1798 static const struct option options[] = {
1799 { "help", no_argument, NULL, 'h' },
1800 { "version", no_argument, NULL, ARG_VERSION },
1801 { "root", required_argument, NULL, ARG_ROOT },
1810 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1819 puts(PACKAGE_STRING);
1820 puts(SYSTEMD_FEATURES);
1825 arg_root = path_make_absolute_cwd(optarg);
1829 path_kill_slashes(arg_root);
1836 assert_not_reached("Unhandled option");
1842 int main(int argc, char *argv[]) {
1844 _cleanup_close_ int lock = -1;
1850 r = parse_argv(argc, argv);
1854 log_set_target(LOG_TARGET_AUTO);
1855 log_parse_environment();
1860 r = mac_selinux_init(NULL);
1862 log_error("SELinux setup failed: %s", strerror(-r));
1866 if (optind < argc) {
1869 for (j = optind; j < argc; j++) {
1870 k = read_config_file(argv[j], false);
1871 if (k < 0 && r == 0)
1875 _cleanup_strv_free_ char **files = NULL;
1878 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1880 log_error("Failed to enumerate sysusers.d files: %s", strerror(-r));
1884 STRV_FOREACH(f, files) {
1885 k = read_config_file(*f, true);
1886 if (k < 0 && r == 0)
1892 /* Default to default range of 1..SYSTEMD_UID_MAX */
1893 r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX);
1904 lock = take_password_lock(arg_root);
1906 log_error("Failed to take lock: %s", strerror(-lock));
1910 r = load_user_database();
1912 log_error("Failed to load user database: %s", strerror(-r));
1916 r = load_group_database();
1918 log_error("Failed to read group database: %s", strerror(-r));
1922 HASHMAP_FOREACH(i, groups, iterator)
1925 HASHMAP_FOREACH(i, users, iterator)
1930 log_error("Failed to write files: %s", strerror(-r));
1933 while ((i = hashmap_steal_first(groups)))
1936 while ((i = hashmap_steal_first(users)))
1939 while ((n = hashmap_first_key(members))) {
1940 strv_free(hashmap_steal_first(members));
1944 hashmap_free(groups);
1945 hashmap_free(users);
1946 hashmap_free(members);
1947 hashmap_free(todo_uids);
1948 hashmap_free(todo_gids);
1950 free_database(database_user, database_uid);
1951 free_database(database_group, database_gid);
1955 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;