diff options
Diffstat (limited to '')
-rw-r--r-- | src/sysusers/sysusers.c | 182 |
1 files changed, 63 insertions, 119 deletions
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 514f3c7..52f4a47 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -35,7 +35,7 @@ #include "strv.h" #include "sync-util.h" #include "tmpfile-util-label.h" -#include "uid-alloc-range.h" +#include "uid-classification.h" #include "uid-range.h" #include "user-util.h" #include "utf8.h" @@ -117,7 +117,7 @@ typedef struct Context { Set *names; uid_t search_uid; - UidRange *uid_range; + UIDRange *uid_range; UGIDAllocationRange login_defs; bool login_defs_need_warning; @@ -141,20 +141,6 @@ static void context_done(Context *c) { uid_range_free(c->uid_range); } -static int errno_is_not_exists(int code) { - /* See getpwnam(3) and getgrnam(3): those codes and others can be returned if the user or group are - * not found. */ - return IN_SET(code, 0, ENOENT, ESRCH, EBADF, EPERM); -} - -/* Note: the lifetime of the compound literal is the immediately surrounding block, - * see C11 ยง6.5.2.5, and - * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */ -#define FORMAT_UID(is_set, uid) \ - ((is_set) ? snprintf_ok((char[DECIMAL_STR_MAX(uid_t)]){}, DECIMAL_STR_MAX(uid_t), UID_FMT, uid) : "(unset)") -#define FORMAT_GID(is_set, gid) \ - ((is_set) ? snprintf_ok((char[DECIMAL_STR_MAX(gid_t)]){}, DECIMAL_STR_MAX(gid_t), GID_FMT, gid) : "(unset)") - static void maybe_emit_login_defs_warning(Context *c) { assert(c); @@ -347,6 +333,7 @@ static int putgrent_with_members( FILE *group) { char **a; + int r; assert(c); assert(gr); @@ -365,15 +352,15 @@ static int putgrent_with_members( if (strv_contains(l, *i)) continue; - if (strv_extend(&l, *i) < 0) - return -ENOMEM; + r = strv_extend(&l, *i); + if (r < 0) + return r; added = true; } if (added) { struct group t; - int r; strv_uniq(l); strv_sort(l); @@ -396,6 +383,7 @@ static int putsgent_with_members( FILE *gshadow) { char **a; + int r; assert(sg); assert(gshadow); @@ -413,15 +401,15 @@ static int putsgent_with_members( if (strv_contains(l, *i)) continue; - if (strv_extend(&l, *i) < 0) - return -ENOMEM; + r = strv_extend(&l, *i); + if (r < 0) + return r; added = true; } if (added) { struct sgrp t; - int r; strv_uniq(l); strv_sort(l); @@ -581,7 +569,7 @@ static int write_temporary_passwd( static usec_t epoch_or_now(void) { uint64_t epoch; - if (getenv_uint64_secure("SOURCE_DATE_EPOCH", &epoch) >= 0) { + if (secure_getenv_uint64("SOURCE_DATE_EPOCH", &epoch) >= 0) { if (epoch > UINT64_MAX/USEC_PER_SEC) /* Overflow check */ return USEC_INFINITY; return (usec_t) epoch * USEC_PER_SEC; @@ -1026,6 +1014,7 @@ static int uid_is_ok( const char *name, bool check_with_gid) { + int r; assert(c); /* Let's see if we already have assigned the UID a second time */ @@ -1056,24 +1045,21 @@ static int uid_is_ok( /* Let's also check via NSS, to avoid UID clashes over LDAP and such, just in case */ if (!arg_root) { - struct passwd *p; - struct group *g; + _cleanup_free_ struct group *g = NULL; - errno = 0; - p = getpwuid(uid); - if (p) + r = getpwuid_malloc(uid, /* ret= */ NULL); + if (r >= 0) return 0; - if (!IN_SET(errno, 0, ENOENT)) - return -errno; + if (r != -ESRCH) + return r; if (check_with_gid) { - errno = 0; - g = getgrgid((gid_t) uid); - if (g) { + r = getgrgid_malloc((gid_t) uid, &g); + if (r >= 0) { if (!streq(g->gr_name, name)) return 0; - } else if (!IN_SET(errno, 0, ENOENT)) - return -errno; + } else if (r != -ESRCH) + return r; } } @@ -1162,12 +1148,11 @@ static int add_user(Context *c, Item *i) { } if (!arg_root) { - struct passwd *p; + _cleanup_free_ struct passwd *p = NULL; /* Also check NSS */ - errno = 0; - p = getpwnam(i->name); - if (p) { + r = getpwnam_malloc(i->name, &p); + if (r >= 0) { log_debug("User %s already exists.", i->name); i->uid = p->pw_uid; i->uid_set = true; @@ -1178,8 +1163,8 @@ static int add_user(Context *c, Item *i) { return 0; } - if (!errno_is_not_exists(errno)) - return log_error_errno(errno, "Failed to check if user %s already exists: %m", i->name); + if (r != -ESRCH) + return log_error_errno(r, "Failed to check if user %s already exists: %m", i->name); } /* Try to use the suggested numeric UID */ @@ -1268,10 +1253,9 @@ static int gid_is_ok( const char *groupname, bool check_with_uid) { - struct group *g; - struct passwd *p; Item *user; char *username; + int r; assert(c); assert(groupname); @@ -1296,20 +1280,18 @@ static int gid_is_ok( } if (!arg_root) { - errno = 0; - g = getgrgid(gid); - if (g) + r = getgrgid_malloc(gid, /* ret= */ NULL); + if (r >= 0) return 0; - if (!IN_SET(errno, 0, ENOENT)) - return -errno; + if (r != -ESRCH) + return r; if (check_with_uid) { - errno = 0; - p = getpwuid((uid_t) gid); - if (p) + r = getpwuid_malloc(gid, /* ret= */ NULL); + if (r >= 0) return 0; - if (!IN_SET(errno, 0, ENOENT)) - return -errno; + if (r != -ESRCH) + return r; } } @@ -1322,6 +1304,7 @@ static int get_gid_by_name( gid_t *ret_gid) { void *z; + int r; assert(c); assert(ret_gid); @@ -1335,16 +1318,15 @@ static int get_gid_by_name( /* Also check NSS */ if (!arg_root) { - struct group *g; + _cleanup_free_ struct group *g = NULL; - errno = 0; - g = getgrnam(name); - if (g) { + r = getgrnam_malloc(name, &g); + if (r >= 0) { *ret_gid = g->gr_gid; return 0; } - if (!errno_is_not_exists(errno)) - return log_error_errno(errno, "Failed to check if group %s already exists: %m", name); + if (r != -ESRCH) + return log_error_errno(r, "Failed to check if group %s already exists: %m", name); } return -ENOENT; @@ -1630,7 +1612,8 @@ static int item_equivalent(Item *a, Item *b) { (a->uid_set && a->uid != b->uid)) { log_syntax(NULL, LOG_DEBUG, a->filename, a->line, 0, "Item not equivalent because UIDs differ (%s vs. %s)", - FORMAT_UID(a->uid_set, a->uid), FORMAT_UID(b->uid_set, b->uid)); + a->uid_set ? FORMAT_UID(a->uid) : "(unset)", + b->uid_set ? FORMAT_UID(b->uid) : "(unset)"); return false; } @@ -1638,7 +1621,8 @@ static int item_equivalent(Item *a, Item *b) { (a->gid_set && a->gid != b->gid)) { log_syntax(NULL, LOG_DEBUG, a->filename, a->line, 0, "Item not equivalent because GIDs differ (%s vs. %s)", - FORMAT_GID(a->gid_set, a->gid), FORMAT_GID(b->gid_set, b->gid)); + a->gid_set ? FORMAT_GID(a->gid) : "(unset)", + b->gid_set ? FORMAT_GID(b->gid) : "(unset)"); return false; } @@ -1658,7 +1642,7 @@ static int item_equivalent(Item *a, Item *b) { const char *a_shell = pick_shell(a), *b_shell = pick_shell(b); - if (!path_equal_ptr(a_shell, b_shell) && + if (!path_equal(a_shell, b_shell) && !(is_nologin_shell(a_shell) && is_nologin_shell(b_shell))) { _cleanup_free_ char *pa = NULL, *pb = NULL; @@ -1690,11 +1674,13 @@ static int item_equivalent(Item *a, Item *b) { } static int parse_line( - Context *c, const char *fname, unsigned line, - const char *buffer) { + const char *buffer, + bool *invalid_config, + void *context) { + Context *c = ASSERT_PTR(context); _cleanup_free_ char *action = NULL, *name = NULL, *resolved_name = NULL, *id = NULL, *resolved_id = NULL, @@ -1707,15 +1693,15 @@ static int parse_line( int r; const char *p; - assert(c); assert(fname); assert(line >= 1); assert(buffer); + assert(!invalid_config); /* We don't support invalid_config yet. */ /* Parse columns */ p = buffer; r = extract_many_words(&p, NULL, EXTRACT_UNQUOTE, - &action, &name, &id, &description, &home, &shell, NULL); + &action, &name, &id, &description, &home, &shell); if (r < 0) return log_syntax(NULL, LOG_ERR, fname, line, r, "Syntax error."); if (r < 2) @@ -1979,57 +1965,14 @@ static int parse_line( } static int read_config_file(Context *c, const char *fn, bool ignore_enoent) { - _cleanup_fclose_ FILE *rf = NULL; - _cleanup_free_ char *pp = NULL; - FILE *f = NULL; - unsigned v = 0; - int r = 0; - - assert(c); - assert(fn); - - if (streq(fn, "-")) - f = stdin; - else { - r = search_and_fopen(fn, "re", arg_root, (const char**) CONF_PATHS_STRV("sysusers.d"), &rf, &pp); - if (r < 0) { - if (ignore_enoent && r == -ENOENT) - return 0; - - return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn); - } - - f = rf; - fn = pp; - } - - for (;;) { - _cleanup_free_ char *line = NULL; - int k; - - k = read_stripped_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++; - - if (IN_SET(line[0], 0, '#')) - continue; - - k = parse_line(c, fn, v, line); - if (k < 0 && r == 0) - r = k; - } - - if (ferror(f)) { - log_error_errno(errno, "Failed to read from file %s: %m", fn); - if (r == 0) - r = -EIO; - } - - return r; + return conf_file_read( + arg_root, + (const char**) CONF_PATHS_STRV("sysusers.d"), + ASSERT_PTR(fn), + parse_line, + ASSERT_PTR(c), + ignore_enoent, + /* invalid_config= */ NULL); } static int cat_config(void) { @@ -2203,7 +2146,7 @@ static int parse_arguments(Context *c, char **args) { STRV_FOREACH(arg, args) { if (arg_inline) /* Use (argument):n, where n==1 for the first positional arg */ - r = parse_line(c, "(argument)", pos, *arg); + r = parse_line("(argument)", pos, *arg, /* invalid_config= */ NULL, c); else r = read_config_file(c, *arg, /* ignore_enoent= */ false); if (r < 0) @@ -2304,7 +2247,8 @@ static int run(int argc, char *argv[]) { DISSECT_IMAGE_VALIDATE_OS | DISSECT_IMAGE_RELAX_VAR_CHECK | DISSECT_IMAGE_FSCK | - DISSECT_IMAGE_GROWFS, + DISSECT_IMAGE_GROWFS | + DISSECT_IMAGE_ALLOW_USERSPACE_VERITY, &mounted_dir, /* ret_dir_fd= */ NULL, &loop_device); |