Merge pull request #31011 from poettering/getpwnam-tweaks

clean up getpwnam() calls and related interfaces
This commit is contained in:
Lennart Poettering 2024-01-22 20:58:33 +01:00 committed by GitHub
commit 4b1a02d866
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 312 additions and 256 deletions

View file

@ -322,7 +322,7 @@ int get_user_creds(
if (ret_shell)
*ret_shell = (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
(isempty(p->pw_shell) ||
!path_is_valid(p->pw_dir) ||
!path_is_valid(p->pw_shell) ||
!path_is_absolute(p->pw_shell) ||
is_nologin_shell(p->pw_shell))) ? NULL : p->pw_shell;
@ -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;
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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)

View file

@ -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)

View file

@ -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;
}

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -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;