diff options
author | Michael Biebl <biebl@debian.org> | 2018-12-21 22:06:22 +0100 |
---|---|---|
committer | Michael Biebl <biebl@debian.org> | 2018-12-21 22:06:22 +0100 |
commit | 6e866b331d7cd4a5e0759dd160dea6edabd3678e (patch) | |
tree | 4d24c1ffe4ae946f04d8910956090e8d13aecd9a /src/sysusers/sysusers.c | |
parent | b012e92123bdc9fa10c2f079ec5bd9313b23e21a (diff) | |
download | systemd-6e866b331d7cd4a5e0759dd160dea6edabd3678e.tar.gz |
New upstream version 240
Diffstat (limited to 'src/sysusers/sysusers.c')
-rw-r--r-- | src/sysusers/sysusers.c | 290 |
1 files changed, 132 insertions, 158 deletions
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 33959d3c11..df28bcfd72 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -8,18 +8,21 @@ #include "copy.h" #include "def.h" #include "fd-util.h" -#include "fileio-label.h" +#include "fileio.h" #include "format-util.h" #include "fs-util.h" #include "hashmap.h" +#include "main-func.h" #include "pager.h" #include "path-util.h" +#include "pretty-print.h" +#include "set.h" #include "selinux-util.h" #include "smack-util.h" #include "specifier.h" #include "string-util.h" #include "strv.h" -#include "terminal-util.h" +#include "tmpfile-util-label.h" #include "uid-range.h" #include "user-util.h" #include "utf8.h" @@ -62,19 +65,34 @@ static char *arg_root = NULL; static bool arg_cat_config = false; static const char *arg_replace = NULL; static bool arg_inline = false; -static bool arg_no_pager = false; +static PagerFlags arg_pager_flags = 0; static OrderedHashmap *users = NULL, *groups = NULL; static OrderedHashmap *todo_uids = NULL, *todo_gids = NULL; static OrderedHashmap *members = NULL; -static Hashmap *database_uid = NULL, *database_user = NULL; -static Hashmap *database_gid = NULL, *database_group = NULL; +static Hashmap *database_by_uid = NULL, *database_by_username = NULL; +static Hashmap *database_by_gid = NULL, *database_by_groupname = NULL; +static Set *database_users = NULL, *database_groups = NULL; static uid_t search_uid = UID_INVALID; static UidRange *uid_range = NULL; static unsigned n_uid_range = 0; +STATIC_DESTRUCTOR_REGISTER(groups, ordered_hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(users, ordered_hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(members, ordered_hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(todo_uids, ordered_hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(todo_gids, ordered_hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(database_by_uid, hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(database_by_username, hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(database_users, set_free_freep); +STATIC_DESTRUCTOR_REGISTER(database_by_gid, hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(database_by_groupname, hashmap_freep); +STATIC_DESTRUCTOR_REGISTER(database_groups, set_free_freep); +STATIC_DESTRUCTOR_REGISTER(uid_range, freep); +STATIC_DESTRUCTOR_REGISTER(arg_root, freep); + static int load_user_database(void) { _cleanup_fclose_ FILE *f = NULL; const char *passwd_path; @@ -86,11 +104,15 @@ static int load_user_database(void) { if (!f) return errno == ENOENT ? 0 : -errno; - r = hashmap_ensure_allocated(&database_user, &string_hash_ops); + r = hashmap_ensure_allocated(&database_by_username, &string_hash_ops); + if (r < 0) + return r; + + r = hashmap_ensure_allocated(&database_by_uid, NULL); if (r < 0) return r; - r = hashmap_ensure_allocated(&database_uid, NULL); + r = set_ensure_allocated(&database_users, NULL); if (r < 0) return r; @@ -102,21 +124,19 @@ static int load_user_database(void) { if (!n) return -ENOMEM; - k = hashmap_put(database_user, n, UID_TO_PTR(pw->pw_uid)); - if (k < 0 && k != -EEXIST) { + k = set_put(database_users, n); + if (k < 0) { free(n); return k; } - q = hashmap_put(database_uid, UID_TO_PTR(pw->pw_uid), n); - if (q < 0 && q != -EEXIST) { - if (k <= 0) - free(n); - return q; - } + k = hashmap_put(database_by_username, n, UID_TO_PTR(pw->pw_uid)); + if (k < 0 && k != -EEXIST) + return k; - if (k <= 0 && q <= 0) - free(n); + q = hashmap_put(database_by_uid, UID_TO_PTR(pw->pw_uid), n); + if (q < 0 && q != -EEXIST) + return q; } return r; } @@ -132,16 +152,19 @@ static int load_group_database(void) { if (!f) return errno == ENOENT ? 0 : -errno; - r = hashmap_ensure_allocated(&database_group, &string_hash_ops); + r = hashmap_ensure_allocated(&database_by_groupname, &string_hash_ops); + if (r < 0) + return r; + + r = hashmap_ensure_allocated(&database_by_gid, NULL); if (r < 0) return r; - r = hashmap_ensure_allocated(&database_gid, NULL); + r = set_ensure_allocated(&database_groups, NULL); if (r < 0) return r; - errno = 0; - while ((gr = fgetgrent(f))) { + while ((r = fgetgrent_sane(f, &gr)) > 0) { char *n; int k, q; @@ -149,28 +172,21 @@ static int load_group_database(void) { if (!n) return -ENOMEM; - k = hashmap_put(database_group, n, GID_TO_PTR(gr->gr_gid)); - if (k < 0 && k != -EEXIST) { + k = set_put(database_groups, n); + if (k < 0) { free(n); return k; } - q = hashmap_put(database_gid, GID_TO_PTR(gr->gr_gid), n); - if (q < 0 && q != -EEXIST) { - if (k <= 0) - free(n); - return q; - } - - if (k <= 0 && q <= 0) - free(n); + k = hashmap_put(database_by_groupname, n, GID_TO_PTR(gr->gr_gid)); + if (k < 0 && k != -EEXIST) + return k; - errno = 0; + q = hashmap_put(database_by_gid, GID_TO_PTR(gr->gr_gid), n); + if (q < 0 && q != -EEXIST) + return q; } - if (!IN_SET(errno, 0, ENOENT)) - return -errno; - - return 0; + return r; } static int make_backup(const char *target, const char *x) { @@ -822,11 +838,11 @@ static int uid_is_ok(uid_t uid, const char *name, bool check_with_gid) { } /* Let's check the files directly */ - if (hashmap_contains(database_uid, UID_TO_PTR(uid))) + if (hashmap_contains(database_by_uid, UID_TO_PTR(uid))) return 0; if (check_with_gid) { - n = hashmap_get(database_gid, GID_TO_PTR(uid)); + n = hashmap_get(database_by_gid, GID_TO_PTR(uid)); if (n && !streq(n, name)) return 0; } @@ -929,7 +945,7 @@ static int add_user(Item *i) { assert(i); /* Check the database directly */ - z = hashmap_get(database_user, i->name); + z = hashmap_get(database_by_username, i->name); if (z) { log_debug("User %s already exists.", i->name); i->uid = PTR_TO_UID(z); @@ -1046,10 +1062,10 @@ static int gid_is_ok(gid_t gid) { if (ordered_hashmap_get(todo_uids, UID_TO_PTR(gid))) return 0; - if (hashmap_contains(database_gid, GID_TO_PTR(gid))) + if (hashmap_contains(database_by_gid, GID_TO_PTR(gid))) return 0; - if (hashmap_contains(database_uid, UID_TO_PTR(gid))) + if (hashmap_contains(database_by_uid, UID_TO_PTR(gid))) return 0; if (!arg_root) { @@ -1078,7 +1094,7 @@ static int add_group(Item *i) { assert(i); /* Check the database directly */ - z = hashmap_get(database_group, i->name); + z = hashmap_get(database_by_groupname, i->name); if (z) { log_debug("Group %s already exists.", i->name); i->gid = PTR_TO_GID(z); @@ -1112,10 +1128,10 @@ static int add_group(Item *i) { * r > 0: means the gid does not exist -> fail * r == 0: means the gid exists -> nothing more to do. */ - if (r > 0) { - log_error("Failed to create %s: please create GID %d", i->name, i->gid); - return -EINVAL; - } + if (r > 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to create %s: please create GID %d", + i->name, i->gid); if (r == 0) return 0; } @@ -1227,10 +1243,9 @@ static int process_item(Item *i) { } } -static void item_free(Item *i) { - +static Item* item_free(Item *i) { if (!i) - return; + return NULL; free(i->name); free(i->uid_path); @@ -1238,10 +1253,11 @@ static void item_free(Item *i) { free(i->description); free(i->home); free(i->shell); - free(i); + return mfree(i); } DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free); +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_hash_ops, char, string_hash_func, string_compare_func, Item, item_free); static int add_implicit(void) { char *g, **l; @@ -1256,7 +1272,7 @@ static int add_implicit(void) { if (!ordered_hashmap_get(users, *m)) { _cleanup_(item_freep) Item *j = NULL; - r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&users, &item_hash_ops); if (r < 0) return log_oom(); @@ -1281,7 +1297,7 @@ static int add_implicit(void) { ordered_hashmap_get(groups, g))) { _cleanup_(item_freep) Item *j = NULL; - r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&groups, &item_hash_ops); if (r < 0) return log_oom(); @@ -1346,6 +1362,8 @@ static bool item_equal(Item *a, Item *b) { return true; } +DEFINE_PRIVATE_HASH_OPS_FULL(members_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free); + static int parse_line(const char *fname, unsigned line, const char *buffer) { static const Specifier specifier_table[] = { @@ -1536,7 +1554,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - r = ordered_hashmap_ensure_allocated(&members, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&members, &members_hash_ops); if (r < 0) return log_oom(); @@ -1578,7 +1596,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&users, &item_hash_ops); if (r < 0) return log_oom(); @@ -1629,7 +1647,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&groups, &item_hash_ops); if (r < 0) return log_oom(); @@ -1681,7 +1699,6 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { static int read_config_file(const char *fn, bool ignore_enoent) { _cleanup_fclose_ FILE *rf = NULL; FILE *f = NULL; - char line[LINE_MAX]; unsigned v = 0; int r = 0; @@ -1701,10 +1718,17 @@ static int read_config_file(const char *fn, bool ignore_enoent) { f = rf; } - FOREACH_LINE(line, f, break) { + for (;;) { + _cleanup_free_ char *line = NULL; char *l; int k; + k = read_line(f, LONG_LINE_MAX, &line); + if (k < 0) + return log_error_errno(k, "Failed to read '%s': %m", fn); + if (k == 0) + break; + v++; l = strstrip(line); @@ -1725,27 +1749,6 @@ static int read_config_file(const char *fn, bool ignore_enoent) { return r; } -static void free_database(Hashmap *by_name, Hashmap *by_id) { - char *name; - - for (;;) { - name = hashmap_first(by_id); - if (!name) - break; - - hashmap_remove(by_name, name); - - hashmap_steal_first_key(by_id); - free(name); - } - - while ((name = hashmap_steal_first_key(by_name))) - free(name); - - hashmap_free(by_name); - hashmap_free(by_id); -} - static int cat_config(void) { _cleanup_strv_free_ char **files = NULL; int r; @@ -1754,12 +1757,19 @@ static int cat_config(void) { if (r < 0) return r; - (void) pager_open(arg_no_pager, false); + (void) pager_open(arg_pager_flags); return cat_files(NULL, files, 0); } -static void help(void) { +static int help(void) { + _cleanup_free_ char *link = NULL; + int r; + + r = terminal_urlify_man("systemd-sysusers.service", "8", &link); + if (r < 0) + return log_oom(); + printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" "Creates system user accounts.\n\n" " -h --help Show this help\n" @@ -1769,7 +1779,12 @@ static void help(void) { " --replace=PATH Treat arguments as replacement for PATH\n" " --inline Treat arguments as configuration lines\n" " --no-pager Do not pipe output into a pager\n" - , program_invocation_short_name); + "\nSee the %s for details.\n" + , program_invocation_short_name + , link + ); + + return 0; } static int parse_argv(int argc, char *argv[]) { @@ -1804,8 +1819,7 @@ static int parse_argv(int argc, char *argv[]) { switch (c) { case 'h': - help(); - return 0; + return help(); case ARG_VERSION: return version(); @@ -1822,10 +1836,9 @@ static int parse_argv(int argc, char *argv[]) { case ARG_REPLACE: if (!path_is_absolute(optarg) || - !endswith(optarg, ".conf")) { - log_error("The argument to --replace= must an absolute path to a config file"); - return -EINVAL; - } + !endswith(optarg, ".conf")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "The argument to --replace= must an absolute path to a config file"); arg_replace = optarg; break; @@ -1835,7 +1848,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_NO_PAGER: - arg_no_pager = true; + arg_pager_flags |= PAGER_DISABLE; break; case '?': @@ -1845,15 +1858,13 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } - if (arg_replace && arg_cat_config) { - log_error("Option --replace= is not supported with --cat-config"); - return -EINVAL; - } + if (arg_replace && arg_cat_config) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Option --replace= is not supported with --cat-config"); - if (arg_replace && optind >= argc) { - log_error("When --replace= is given, some configuration items must be specified"); - return -EINVAL; - } + if (arg_replace && optind >= argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "When --replace= is given, some configuration items must be specified"); return 1; } @@ -1905,33 +1916,26 @@ static int read_config_files(char **args) { return 0; } -int main(int argc, char *argv[]) { +static int run(int argc, char *argv[]) { _cleanup_close_ int lock = -1; Iterator iterator; - int r; Item *i; - char *n; + int r; r = parse_argv(argc, argv); if (r <= 0) - goto finish; + return r; - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); + log_setup_service(); - if (arg_cat_config) { - r = cat_config(); - goto finish; - } + if (arg_cat_config) + return cat_config(); umask(0022); r = mac_selinux_init(); - if (r < 0) { - log_error_errno(r, "SELinux setup failed: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "SELinux setup failed: %m"); /* If command line arguments are specified along with --replace, read all * configuration files and insert the positional arguments at the specified @@ -1944,48 +1948,38 @@ int main(int argc, char *argv[]) { else r = parse_arguments(argv + optind); if (r < 0) - goto finish; + return r; /* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our detection * whether the names or UID/GID area already used otherwise doesn't get confused. After all, even though * nss-systemd synthesizes these users/groups, they should still appear in /etc/passwd and /etc/group, as the * synthesizing logic is merely supposed to be fallback for cases where we run with a completely unpopulated * /etc. */ - if (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0) { - r = log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m"); - goto finish; - } + if (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0) + return log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m"); if (!uid_range) { /* Default to default range of 1..SYSTEM_UID_MAX */ r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX); - if (r < 0) { - log_oom(); - goto finish; - } + if (r < 0) + return log_oom(); } r = add_implicit(); if (r < 0) - goto finish; + return r; lock = take_etc_passwd_lock(arg_root); - if (lock < 0) { - log_error_errno(lock, "Failed to take /etc/passwd lock: %m"); - goto finish; - } + if (lock < 0) + return log_error_errno(lock, "Failed to take /etc/passwd lock: %m"); r = load_user_database(); - if (r < 0) { - log_error_errno(r, "Failed to load user database: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to load user database: %m"); r = load_group_database(); - if (r < 0) { - log_error_errno(r, "Failed to read group database: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to read group database: %m"); ORDERED_HASHMAP_FOREACH(i, groups, iterator) (void) process_item(i); @@ -1995,29 +1989,9 @@ int main(int argc, char *argv[]) { r = write_files(); if (r < 0) - log_error_errno(r, "Failed to write files: %m"); + return log_error_errno(r, "Failed to write files: %m"); -finish: - pager_close(); - - ordered_hashmap_free_with_destructor(groups, item_free); - ordered_hashmap_free_with_destructor(users, item_free); - - while ((n = ordered_hashmap_first_key(members))) { - strv_free(ordered_hashmap_steal_first(members)); - free(n); - } - ordered_hashmap_free(members); - - ordered_hashmap_free(todo_uids); - ordered_hashmap_free(todo_gids); - - free_database(database_user, database_uid); - free_database(database_group, database_gid); - - free(uid_range); - - free(arg_root); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return 0; } + +DEFINE_MAIN_FUNCTION(run); |