diff --git a/src/basic/user-util.c b/src/basic/user-util.c index ae6f13a8cf..cee9154141 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -431,31 +431,11 @@ char* uid_to_name(uid_t uid) { return strdup(NOBODY_USER_NAME); if (uid_is_valid(uid)) { - long bufsize; + _cleanup_free_ struct passwd *pw = NULL; - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize <= 0) - bufsize = 4096; - - for (;;) { - struct passwd pwbuf, *pw = NULL; - _cleanup_free_ char *buf = NULL; - - buf = malloc(bufsize); - if (!buf) - return NULL; - - r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw); - if (r == 0 && pw) - return strdup(pw->pw_name); - if (r != ERANGE) - break; - - if (bufsize > LONG_MAX/2) /* overflow check */ - return NULL; - - bufsize *= 2; - } + r = getpwuid_malloc(uid, &pw); + if (r >= 0) + return strdup(pw->pw_name); } if (asprintf(&ret, UID_FMT, uid) < 0) @@ -474,31 +454,11 @@ char* gid_to_name(gid_t gid) { return strdup(NOBODY_GROUP_NAME); if (gid_is_valid(gid)) { - long bufsize; + _cleanup_free_ struct group *gr = NULL; - bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); - if (bufsize <= 0) - bufsize = 4096; - - for (;;) { - struct group grbuf, *gr = NULL; - _cleanup_free_ char *buf = NULL; - - buf = malloc(bufsize); - if (!buf) - return NULL; - - r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr); - if (r == 0 && gr) - return strdup(gr->gr_name); - if (r != ERANGE) - break; - - if (bufsize > LONG_MAX/2) /* overflow check */ - return NULL; - - bufsize *= 2; - } + r = getgrgid_malloc(gid, &gr); + if (r >= 0) + return strdup(gr->gr_name); } if (asprintf(&ret, GID_FMT, gid) < 0) @@ -609,9 +569,10 @@ int getgroups_alloc(gid_t** gids) { } int get_home_dir(char **ret) { - struct passwd *p; + _cleanup_free_ struct passwd *p = NULL; const char *e; uid_t u; + int r; assert(ret); @@ -626,19 +587,17 @@ int get_home_dir(char **ret) { e = "/root"; goto found; } - if (u == UID_NOBODY && synthesize_nobody()) { e = "/"; goto found; } /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno_or_else(ESRCH); - e = p->pw_dir; + r = getpwuid_malloc(u, &p); + if (r < 0) + return r; + e = p->pw_dir; if (!path_is_valid(e) || !path_is_absolute(e)) return -EINVAL; @@ -647,9 +606,10 @@ int get_home_dir(char **ret) { } int get_shell(char **ret) { - struct passwd *p; + _cleanup_free_ struct passwd *p = NULL; const char *e; uid_t u; + int r; assert(ret); @@ -670,12 +630,11 @@ int get_shell(char **ret) { } /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno_or_else(ESRCH); - e = p->pw_shell; + r = getpwuid_malloc(u, &p); + if (r < 0) + return r; + e = p->pw_shell; if (!path_is_valid(e) || !path_is_absolute(e)) return -EINVAL; @@ -1089,3 +1048,180 @@ const char* get_home_root(void) { return "/home"; } + +static size_t getpw_buffer_size(void) { + long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + return bufsize <= 0 ? 4096U : (size_t) bufsize; +} + +static bool errno_is_user_doesnt_exist(int error) { + /* See getpwnam(3) and getgrnam(3): those codes and others can be returned if the user or group are + * not found. */ + return IN_SET(abs(error), ENOENT, ESRCH, EBADF, EPERM); +} + +int getpwnam_malloc(const char *name, struct passwd **ret) { + size_t bufsize = getpw_buffer_size(); + int r; + + /* A wrapper around getpwnam_r() that allocates the necessary buffer on the heap. The caller must + * free() the returned sructured! */ + + if (isempty(name)) + return -EINVAL; + + for (;;) { + _cleanup_free_ void *buf = NULL; + + buf = malloc(ALIGN(sizeof(struct passwd)) + bufsize); + if (!buf) + return -ENOMEM; + + struct passwd *pw = NULL; + r = getpwnam_r(name, buf, (char*) buf + ALIGN(sizeof(struct passwd)), (size_t) bufsize, &pw); + if (r == 0) { + if (pw) { + if (ret) + *ret = TAKE_PTR(buf); + return 0; + } + + return -ESRCH; + } + + assert(r > 0); + + /* getpwnam() may fail with ENOENT if /etc/passwd is missing. For us that is equivalent to + * the name not being defined. */ + if (errno_is_user_doesnt_exist(r)) + return -ESRCH; + if (r != ERANGE) + return -r; + + if (bufsize > SIZE_MAX/2 - ALIGN(sizeof(struct passwd))) + return -ENOMEM; + bufsize *= 2; + } +} + +int getpwuid_malloc(uid_t uid, struct passwd **ret) { + size_t bufsize = getpw_buffer_size(); + int r; + + if (!uid_is_valid(uid)) + return -EINVAL; + + for (;;) { + _cleanup_free_ void *buf = NULL; + + buf = malloc(ALIGN(sizeof(struct passwd)) + bufsize); + if (!buf) + return -ENOMEM; + + struct passwd *pw = NULL; + r = getpwuid_r(uid, buf, (char*) buf + ALIGN(sizeof(struct passwd)), (size_t) bufsize, &pw); + if (r == 0) { + if (pw) { + if (ret) + *ret = TAKE_PTR(buf); + return 0; + } + + return -ESRCH; + } + + assert(r > 0); + + if (errno_is_user_doesnt_exist(r)) + return -ESRCH; + if (r != ERANGE) + return -r; + + if (bufsize > SIZE_MAX/2 - ALIGN(sizeof(struct passwd))) + return -ENOMEM; + bufsize *= 2; + } +} + +static size_t getgr_buffer_size(void) { + long bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); + return bufsize <= 0 ? 4096U : (size_t) bufsize; +} + +int getgrnam_malloc(const char *name, struct group **ret) { + size_t bufsize = getgr_buffer_size(); + int r; + + if (isempty(name)) + return -EINVAL; + + for (;;) { + _cleanup_free_ void *buf = NULL; + + buf = malloc(ALIGN(sizeof(struct group)) + bufsize); + if (!buf) + return -ENOMEM; + + struct group *gr = NULL; + r = getgrnam_r(name, buf, (char*) buf + ALIGN(sizeof(struct group)), (size_t) bufsize, &gr); + if (r == 0) { + if (gr) { + if (ret) + *ret = TAKE_PTR(buf); + return 0; + } + + return -ESRCH; + } + + assert(r > 0); + + if (errno_is_user_doesnt_exist(r)) + return -ESRCH; + if (r != ERANGE) + return -r; + + if (bufsize > SIZE_MAX/2 - ALIGN(sizeof(struct group))) + return -ENOMEM; + bufsize *= 2; + } +} + +int getgrgid_malloc(gid_t gid, struct group **ret) { + size_t bufsize = getgr_buffer_size(); + int r; + + if (!gid_is_valid(gid)) + return -EINVAL; + + for (;;) { + _cleanup_free_ void *buf = NULL; + + buf = malloc(ALIGN(sizeof(struct group)) + bufsize); + if (!buf) + return -ENOMEM; + + struct group *gr = NULL; + r = getgrgid_r(gid, buf, (char*) buf + ALIGN(sizeof(struct group)), (size_t) bufsize, &gr); + if (r == 0) { + if (gr) { + if (ret) + *ret = TAKE_PTR(buf); + return 0; + } + + return -ESRCH; + } + + assert(r > 0); + + if (errno_is_user_doesnt_exist(r)) + return -ESRCH; + if (r != ERANGE) + return -r; + + if (bufsize > SIZE_MAX/2 - ALIGN(sizeof(struct group))) + return -ENOMEM; + bufsize *= 2; + } +} diff --git a/src/basic/user-util.h b/src/basic/user-util.h index b363c2b28e..9d07ef31d2 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -158,3 +158,9 @@ static inline bool hashed_password_is_locked_or_invalid(const char *password) { * Also see https://github.com/systemd/systemd/pull/24680#pullrequestreview-1439464325. */ #define PASSWORD_UNPROVISIONED "!unprovisioned" + +int getpwuid_malloc(uid_t uid, struct passwd **ret); +int getpwnam_malloc(const char *name, struct passwd **ret); + +int getgrnam_malloc(const char *name, struct group **ret); +int getgrgid_malloc(gid_t gid, struct group **ret); diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c index 484b0e29ab..8462a31e5b 100644 --- a/src/core/dynamic-user.c +++ b/src/core/dynamic-user.c @@ -293,8 +293,8 @@ static int pick_uid(char **suggested_paths, const char *name, uid_t *ret_uid) { } /* Some superficial check whether this UID/GID might already be taken by some static user */ - if (getpwuid(candidate) || - getgrgid((gid_t) candidate) || + if (getpwuid_malloc(candidate, /* ret= */ NULL) >= 0 || + getgrgid_malloc((gid_t) candidate, /* ret= */ NULL) >= 0 || search_ipc(candidate, (gid_t) candidate) != 0) { (void) unlink(lock_path); continue; @@ -417,30 +417,26 @@ static int dynamic_user_realize( /* First, let's parse this as numeric UID */ r = parse_uid(d->name, &num); if (r < 0) { - struct passwd *p; - struct group *g; + _cleanup_free_ struct passwd *p = NULL; + _cleanup_free_ struct group *g = NULL; if (is_user) { /* OK, this is not a numeric UID. Let's see if there's a user by this name */ - p = getpwnam(d->name); - if (p) { + if (getpwnam_malloc(d->name, &p) >= 0) { num = p->pw_uid; gid = p->pw_gid; } else { /* if the user does not exist but the group with the same name exists, refuse operation */ - g = getgrnam(d->name); - if (g) + if (getgrnam_malloc(d->name, /* ret= */ NULL) >= 0) return -EILSEQ; } } else { /* Let's see if there's a group by this name */ - g = getgrnam(d->name); - if (g) + if (getgrnam_malloc(d->name, &g) >= 0) num = (uid_t) g->gr_gid; else { /* if the group does not exist but the user with the same name exists, refuse operation */ - p = getpwnam(d->name); - if (p) + if (getpwnam_malloc(d->name, /* ret= */ NULL) >= 0) return -EILSEQ; } } @@ -482,13 +478,12 @@ static int dynamic_user_realize( uid_lock_fd = new_uid_lock_fd; } } else if (is_user && !uid_is_dynamic(num)) { - struct passwd *p; + _cleanup_free_ struct passwd *p = NULL; /* Statically allocated user may have different uid and gid. So, let's obtain the gid. */ - errno = 0; - p = getpwuid(num); - if (!p) - return errno_or_else(ESRCH); + r = getpwuid_malloc(num, &p); + if (r < 0) + return r; gid = p->pw_gid; } diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 18a7cb83b9..652a6d5c89 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -1079,12 +1079,11 @@ static int process_root_account(int rfd) { return log_error_errno(k, "Failed to check if directory file descriptor is root: %m"); if (arg_copy_root_shell && k == 0) { - struct passwd *p; + _cleanup_free_ struct passwd *p = NULL; - errno = 0; - p = getpwnam("root"); - if (!p) - return log_error_errno(errno_or_else(EIO), "Failed to find passwd entry for root: %m"); + r = getpwnam_malloc("root", &p); + if (r < 0) + return log_error_errno(r, "Failed to find passwd entry for root: %m"); r = free_and_strdup(&arg_root_shell, p->pw_shell); if (r < 0) diff --git a/src/home/homed-manager-bus.c b/src/home/homed-manager-bus.c index 5395ae62c1..d45e0f1238 100644 --- a/src/home/homed-manager-bus.c +++ b/src/home/homed-manager-bus.c @@ -342,8 +342,6 @@ static int method_deactivate_home(sd_bus_message *message, void *userdata, sd_bu static int validate_and_allocate_home(Manager *m, UserRecord *hr, Home **ret, sd_bus_error *error) { _cleanup_(user_record_unrefp) UserRecord *signed_hr = NULL; - struct passwd *pw; - struct group *gr; bool signed_locally; Home *other; int r; @@ -360,13 +358,17 @@ static int validate_and_allocate_home(Manager *m, UserRecord *hr, Home **ret, sd if (other) return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s exists already, refusing.", hr->user_name); - pw = getpwnam(hr->user_name); - if (pw) + r = getpwnam_malloc(hr->user_name, /* ret= */ NULL); + if (r >= 0) return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s exists in the NSS user database, refusing.", hr->user_name); + if (r != -ESRCH) + return r; - gr = getgrnam(hr->user_name); - if (gr) + r = getgrnam_malloc(hr->user_name, /* ret= */ NULL); + if (r >= 0) return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s conflicts with an NSS group by the same name, refusing.", hr->user_name); + if (r != -ESRCH) + return r; r = manager_verify_user_record(m, hr); switch (r) { @@ -397,17 +399,24 @@ static int validate_and_allocate_home(Manager *m, UserRecord *hr, Home **ret, sd } if (uid_is_valid(hr->uid)) { + _cleanup_free_ struct passwd *pw = NULL; + _cleanup_free_ struct group *gr = NULL; + other = hashmap_get(m->homes_by_uid, UID_TO_PTR(hr->uid)); if (other) return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use by home %s, refusing.", hr->uid, other->user_name); - pw = getpwuid(hr->uid); - if (pw) + r = getpwuid_malloc(hr->uid, &pw); + if (r >= 0) return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use by NSS user %s, refusing.", hr->uid, pw->pw_name); + if (r != -ESRCH) + return r; - gr = getgrgid(hr->uid); - if (gr) + r = getgrgid_malloc(hr->uid, &gr); + if (r >= 0) return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use as GID by NSS group %s, refusing.", hr->uid, gr->gr_name); + if (r != -ESRCH) + return r; } else { r = manager_augment_record_with_uid(m, hr); if (r < 0) diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index b1d0c51120..810ecb23fc 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -588,8 +588,8 @@ static int manager_acquire_uid( assert(ret); for (;;) { - struct passwd *pw; - struct group *gr; + _cleanup_free_ struct passwd *pw = NULL; + _cleanup_free_ struct group *gr = NULL; uid_t candidate; Home *other; @@ -632,19 +632,27 @@ static int manager_acquire_uid( continue; } - pw = getpwuid(candidate); - if (pw) { + r = getpwuid_malloc(candidate, &pw); + if (r >= 0) { log_debug("Candidate UID " UID_FMT " already registered by another user in NSS (%s), let's try another.", candidate, pw->pw_name); continue; } + if (r != -ESRCH) { + log_debug_errno(r, "Failed to check if an NSS user is already registered for candidate UID " UID_FMT ", assuming there might be: %m", candidate); + continue; + } - gr = getgrgid((gid_t) candidate); - if (gr) { + r = getgrgid_malloc((gid_t) candidate, &gr); + if (r >= 0) { log_debug("Candidate UID " UID_FMT " already registered by another group in NSS (%s), let's try another.", candidate, gr->gr_name); continue; } + if (r != -ESRCH) { + log_debug_errno(r, "Failed to check if an NSS group is already registered for candidate UID " UID_FMT ", assuming there might be: %m", candidate); + continue; + } r = search_ipc(candidate, (gid_t) candidate); if (r < 0) @@ -715,7 +723,7 @@ static int manager_add_home_by_image( } } else { /* Check NSS, in case there's another user or group by this name */ - if (getpwnam(user_name) || getgrnam(user_name)) { + if (getpwnam_malloc(user_name, /* ret= */ NULL) >= 0 || getgrnam_malloc(user_name, /* ret= */ NULL) >= 0) { log_debug("Found an existing user or group by name '%s', ignoring image '%s'.", user_name, image_path); return 0; } diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 8f70253ef6..3bb8527703 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1419,10 +1419,10 @@ static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + _cleanup_free_ struct passwd *pw = NULL; _cleanup_free_ char *cc = NULL; Manager *m = ASSERT_PTR(userdata); int r, b, interactive; - struct passwd *pw; const char *path; uint32_t uid, auth_uid; @@ -1450,10 +1450,9 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; - errno = 0; - pw = getpwuid(uid); - if (!pw) - return errno_or_else(ENOENT); + r = getpwuid_malloc(uid, &pw); + if (r < 0) + return r; r = bus_verify_polkit_async_full( message, diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index c48b51323b..89ef0e4daa 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4211,13 +4211,13 @@ static int uid_shift_pick(uid_t *shift, LockFile *ret_lock_file) { return r; /* Make some superficial checks whether the range is currently known in the user database */ - if (getpwuid(candidate)) + if (getpwuid_malloc(candidate, /* ret= */ NULL) >= 0) goto next; - if (getpwuid(candidate + UINT32_C(0xFFFE))) + if (getpwuid_malloc(candidate + UINT32_C(0xFFFE), /* ret= */ NULL) >= 0) goto next; - if (getgrgid(candidate)) + if (getgrgid_malloc(candidate, /* ret= */ NULL) >= 0) goto next; - if (getgrgid(candidate + UINT32_C(0xFFFE))) + if (getgrgid_malloc(candidate + UINT32_C(0xFFFE), /* ret= */ NULL) >= 0) goto next; *ret_lock_file = lf; diff --git a/src/shared/user-record-nss.c b/src/shared/user-record-nss.c index 414a49331b..ffb5721466 100644 --- a/src/shared/user-record-nss.c +++ b/src/shared/user-record-nss.c @@ -208,39 +208,17 @@ int nss_user_record_by_name( bool with_shadow, UserRecord **ret) { - _cleanup_free_ char *buf = NULL, *sbuf = NULL; - struct passwd pwd, *result; + _cleanup_free_ char *sbuf = NULL; + _cleanup_free_ struct passwd *result = NULL; bool incomplete = false; - size_t buflen = 4096; struct spwd spwd, *sresult = NULL; int r; assert(name); - for (;;) { - buf = malloc(buflen); - if (!buf) - return -ENOMEM; - - r = getpwnam_r(name, &pwd, buf, buflen, &result); - if (r == 0) { - if (!result) - return -ESRCH; - - break; - } - - if (r < 0) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), "getpwnam_r() returned a negative value"); - if (r != ERANGE) - return -r; - - if (buflen > SIZE_MAX / 2) - return -ERANGE; - - buflen *= 2; - buf = mfree(buf); - } + r = getpwnam_malloc(name, &result); + if (r < 0) + return r; if (with_shadow) { r = nss_spwd_for_passwd(result, &spwd, &sbuf); @@ -266,36 +244,15 @@ int nss_user_record_by_uid( bool with_shadow, UserRecord **ret) { - _cleanup_free_ char *buf = NULL, *sbuf = NULL; - struct passwd pwd, *result; + _cleanup_free_ char *sbuf = NULL; + _cleanup_free_ struct passwd *result = NULL; bool incomplete = false; - size_t buflen = 4096; struct spwd spwd, *sresult = NULL; int r; - for (;;) { - buf = malloc(buflen); - if (!buf) - return -ENOMEM; - - r = getpwuid_r(uid, &pwd, buf, buflen, &result); - if (r == 0) { - if (!result) - return -ESRCH; - - break; - } - if (r < 0) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), "getpwuid_r() returned a negative value"); - if (r != ERANGE) - return -r; - - if (buflen > SIZE_MAX / 2) - return -ERANGE; - - buflen *= 2; - buf = mfree(buf); - } + r = getpwuid_malloc(uid, &result); + if (r < 0) + return r; if (with_shadow) { r = nss_spwd_for_passwd(result, &spwd, &sbuf); @@ -422,38 +379,17 @@ int nss_group_record_by_name( bool with_shadow, GroupRecord **ret) { - _cleanup_free_ char *buf = NULL, *sbuf = NULL; - struct group grp, *result; + _cleanup_free_ char *sbuf = NULL; + _cleanup_free_ struct group *result = NULL; bool incomplete = false; - size_t buflen = 4096; struct sgrp sgrp, *sresult = NULL; int r; assert(name); - for (;;) { - buf = malloc(buflen); - if (!buf) - return -ENOMEM; - - r = getgrnam_r(name, &grp, buf, buflen, &result); - if (r == 0) { - if (!result) - return -ESRCH; - - break; - } - - if (r < 0) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), "getgrnam_r() returned a negative value"); - if (r != ERANGE) - return -r; - if (buflen > SIZE_MAX / 2) - return -ERANGE; - - buflen *= 2; - buf = mfree(buf); - } + r = getgrnam_malloc(name, &result); + if (r < 0) + return r; if (with_shadow) { r = nss_sgrp_for_group(result, &sgrp, &sbuf); @@ -479,35 +415,15 @@ int nss_group_record_by_gid( bool with_shadow, GroupRecord **ret) { - _cleanup_free_ char *buf = NULL, *sbuf = NULL; - struct group grp, *result; + _cleanup_free_ char *sbuf = NULL; + _cleanup_free_ struct group *result = NULL; bool incomplete = false; - size_t buflen = 4096; struct sgrp sgrp, *sresult = NULL; int r; - for (;;) { - buf = malloc(buflen); - if (!buf) - return -ENOMEM; - - r = getgrgid_r(gid, &grp, buf, buflen, &result); - if (r == 0) { - if (!result) - return -ESRCH; - break; - } - - if (r < 0) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), "getgrgid_r() returned a negative value"); - if (r != ERANGE) - return -r; - if (buflen > SIZE_MAX / 2) - return -ERANGE; - - buflen *= 2; - buf = mfree(buf); - } + r = getgrgid_malloc(gid, &result); + if (r < 0) + return r; if (with_shadow) { r = nss_sgrp_for_group(result, &sgrp, &sbuf); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 4d5d61c691..96fb6f8ad5 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -141,12 +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 */ @@ -1028,6 +1022,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 */ @@ -1058,24 +1053,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; } } @@ -1164,12 +1156,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; @@ -1180,8 +1171,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 */ @@ -1270,10 +1261,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); @@ -1298,20 +1288,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; } } @@ -1324,6 +1312,7 @@ static int get_gid_by_name( gid_t *ret_gid) { void *z; + int r; assert(c); assert(ret_gid); @@ -1337,16 +1326,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;