mirror of
https://github.com/systemd/systemd
synced 2024-07-21 02:05:05 +00:00
Merge pull request #31011 from poettering/getpwnam-tweaks
clean up getpwnam() calls and related interfaces
This commit is contained in:
commit
4b1a02d866
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue