Moved credential-related code to nxt_credential.c.
This is required to avoid include cycles, as some nxt_clone_* functions depend on the credential structures, but nxt_process depends on clone structures.
This commit is contained in:
@@ -13,6 +13,7 @@ NXT_LIB_SRCS=" \
|
|||||||
src/nxt_mem_map.c \
|
src/nxt_mem_map.c \
|
||||||
src/nxt_socket.c \
|
src/nxt_socket.c \
|
||||||
src/nxt_socketpair.c \
|
src/nxt_socketpair.c \
|
||||||
|
src/nxt_credential.c \
|
||||||
src/nxt_process.c \
|
src/nxt_process.c \
|
||||||
src/nxt_process_title.c \
|
src/nxt_process_title.c \
|
||||||
src/nxt_signal.c \
|
src/nxt_signal.c \
|
||||||
|
|||||||
342
src/nxt_credential.c
Normal file
342
src/nxt_credential.c
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Igor Sysoev
|
||||||
|
* Copyright (C) NGINX, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nxt_main.h>
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t nxt_credential_groups_get(nxt_task_t *task, nxt_mp_t *mp,
|
||||||
|
nxt_credential_t *uc);
|
||||||
|
|
||||||
|
|
||||||
|
nxt_int_t
|
||||||
|
nxt_credential_get(nxt_task_t *task, nxt_mp_t *mp, nxt_credential_t *uc,
|
||||||
|
const char *group)
|
||||||
|
{
|
||||||
|
struct group *grp;
|
||||||
|
struct passwd *pwd;
|
||||||
|
|
||||||
|
nxt_errno = 0;
|
||||||
|
|
||||||
|
pwd = getpwnam(uc->user);
|
||||||
|
|
||||||
|
if (nxt_slow_path(pwd == NULL)) {
|
||||||
|
|
||||||
|
if (nxt_errno == 0) {
|
||||||
|
nxt_alert(task, "getpwnam(\"%s\") failed, user \"%s\" not found",
|
||||||
|
uc->user, uc->user);
|
||||||
|
} else {
|
||||||
|
nxt_alert(task, "getpwnam(\"%s\") failed %E", uc->user, nxt_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc->uid = pwd->pw_uid;
|
||||||
|
uc->base_gid = pwd->pw_gid;
|
||||||
|
|
||||||
|
if (group != NULL && group[0] != '\0') {
|
||||||
|
nxt_errno = 0;
|
||||||
|
|
||||||
|
grp = getgrnam(group);
|
||||||
|
|
||||||
|
if (nxt_slow_path(grp == NULL)) {
|
||||||
|
|
||||||
|
if (nxt_errno == 0) {
|
||||||
|
nxt_alert(task,
|
||||||
|
"getgrnam(\"%s\") failed, group \"%s\" not found",
|
||||||
|
group, group);
|
||||||
|
} else {
|
||||||
|
nxt_alert(task, "getgrnam(\"%s\") failed %E", group, nxt_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc->base_gid = grp->gr_gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_debug(task, "about to get \"%s\" groups (uid:%d, base gid:%d)",
|
||||||
|
uc->user, uc->uid, uc->base_gid);
|
||||||
|
|
||||||
|
if (nxt_credential_groups_get(task, mp, uc) != NXT_OK) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (NXT_DEBUG)
|
||||||
|
{
|
||||||
|
u_char *p, *end;
|
||||||
|
nxt_uint_t i;
|
||||||
|
u_char msg[NXT_MAX_ERROR_STR];
|
||||||
|
|
||||||
|
p = msg;
|
||||||
|
end = msg + NXT_MAX_ERROR_STR;
|
||||||
|
|
||||||
|
for (i = 0; i < uc->ngroups; i++) {
|
||||||
|
p = nxt_sprintf(p, end, "%d%c", uc->gids[i],
|
||||||
|
i+1 < uc->ngroups ? ',' : '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_debug(task, "user \"%s\" has gids:%*s", uc->user, p - msg, msg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if (NXT_HAVE_GETGROUPLIST && !NXT_MACOSX)
|
||||||
|
|
||||||
|
#define NXT_NGROUPS nxt_min(256, NGROUPS_MAX)
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_credential_groups_get(nxt_task_t *task, nxt_mp_t *mp,
|
||||||
|
nxt_credential_t *uc)
|
||||||
|
{
|
||||||
|
int ngroups;
|
||||||
|
gid_t groups[NXT_NGROUPS];
|
||||||
|
|
||||||
|
ngroups = NXT_NGROUPS;
|
||||||
|
|
||||||
|
if (getgrouplist(uc->user, uc->base_gid, groups, &ngroups) < 0) {
|
||||||
|
if (nxt_slow_path(ngroups <= NXT_NGROUPS)) {
|
||||||
|
nxt_alert(task, "getgrouplist(\"%s\", %d, ...) failed %E", uc->user,
|
||||||
|
uc->base_gid, nxt_errno);
|
||||||
|
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngroups > NXT_NGROUPS) {
|
||||||
|
if (ngroups > NGROUPS_MAX) {
|
||||||
|
ngroups = NGROUPS_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc->ngroups = ngroups;
|
||||||
|
|
||||||
|
uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(gid_t));
|
||||||
|
if (nxt_slow_path(uc->gids == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxt_slow_path(getgrouplist(uc->user, uc->base_gid, uc->gids,
|
||||||
|
&ngroups) < 0)) {
|
||||||
|
|
||||||
|
nxt_alert(task, "getgrouplist(\"%s\", %d) failed %E", uc->user,
|
||||||
|
uc->base_gid, nxt_errno);
|
||||||
|
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc->ngroups = ngroups;
|
||||||
|
|
||||||
|
uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(gid_t));
|
||||||
|
if (nxt_slow_path(uc->gids == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_memcpy(uc->gids, groups, ngroups * sizeof(gid_t));
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For operating systems that lack getgrouplist(3) or it's buggy (MacOS),
|
||||||
|
* nxt_credential_groups_get() stores an array of groups IDs which should be
|
||||||
|
* set by the setgroups() function for a given user. The initgroups()
|
||||||
|
* may block a just forked worker process for some time if LDAP or NDIS+
|
||||||
|
* is used, so nxt_credential_groups_get() allows to get worker user groups in
|
||||||
|
* main process. In a nutshell the initgroups() calls getgrouplist()
|
||||||
|
* followed by setgroups(). However older Solaris lacks the getgrouplist().
|
||||||
|
* Besides getgrouplist() does not allow to query the exact number of
|
||||||
|
* groups in some platforms, while NGROUPS_MAX can be quite large (e.g.
|
||||||
|
* 65536 on Linux).
|
||||||
|
* So nxt_credential_groups_get() emulates getgrouplist(): at first the
|
||||||
|
* function saves the super-user groups IDs, then calls initgroups() and saves
|
||||||
|
* the specified user groups IDs, and then restores the super-user groups IDs.
|
||||||
|
* This works at least on Linux, FreeBSD, and Solaris, but does not work
|
||||||
|
* on MacOSX, getgroups(2):
|
||||||
|
*
|
||||||
|
* To provide compatibility with applications that use getgroups() in
|
||||||
|
* environments where users may be in more than {NGROUPS_MAX} groups,
|
||||||
|
* a variant of getgroups(), obtained when compiling with either the
|
||||||
|
* macros _DARWIN_UNLIMITED_GETGROUPS or _DARWIN_C_SOURCE defined, can
|
||||||
|
* be used that is not limited to {NGROUPS_MAX} groups. However, this
|
||||||
|
* variant only returns the user's default group access list and not
|
||||||
|
* the group list modified by a call to setgroups(2).
|
||||||
|
*
|
||||||
|
* For such cases initgroups() is used in worker process as fallback.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_credential_groups_get(nxt_task_t *task, nxt_mp_t *mp, nxt_credential_t *uc)
|
||||||
|
{
|
||||||
|
int nsaved, ngroups;
|
||||||
|
nxt_int_t ret;
|
||||||
|
nxt_gid_t *saved;
|
||||||
|
|
||||||
|
nsaved = getgroups(0, NULL);
|
||||||
|
|
||||||
|
if (nxt_slow_path(nsaved == -1)) {
|
||||||
|
nxt_alert(task, "getgroups(0, NULL) failed %E", nxt_errno);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_debug(task, "getgroups(0, NULL): %d", nsaved);
|
||||||
|
|
||||||
|
if (nsaved > NGROUPS_MAX) {
|
||||||
|
/* MacOSX case. */
|
||||||
|
|
||||||
|
uc->gids = NULL;
|
||||||
|
uc->ngroups = 0;
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
saved = nxt_mp_alloc(mp, nsaved * sizeof(nxt_gid_t));
|
||||||
|
|
||||||
|
if (nxt_slow_path(saved == NULL)) {
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = NXT_ERROR;
|
||||||
|
|
||||||
|
nsaved = getgroups(nsaved, saved);
|
||||||
|
|
||||||
|
if (nxt_slow_path(nsaved == -1)) {
|
||||||
|
nxt_alert(task, "getgroups(%d) failed %E", nsaved, nxt_errno);
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_debug(task, "getgroups(): %d", nsaved);
|
||||||
|
|
||||||
|
if (initgroups(uc->user, uc->base_gid) != 0) {
|
||||||
|
if (nxt_errno == NXT_EPERM) {
|
||||||
|
nxt_log(task, NXT_LOG_NOTICE,
|
||||||
|
"initgroups(%s, %d) failed %E, ignored",
|
||||||
|
uc->user, uc->base_gid, nxt_errno);
|
||||||
|
|
||||||
|
ret = NXT_OK;
|
||||||
|
|
||||||
|
goto free;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
nxt_alert(task, "initgroups(%s, %d) failed %E",
|
||||||
|
uc->user, uc->base_gid, nxt_errno);
|
||||||
|
goto restore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngroups = getgroups(0, NULL);
|
||||||
|
|
||||||
|
if (nxt_slow_path(ngroups == -1)) {
|
||||||
|
nxt_alert(task, "getgroups(0, NULL) failed %E", nxt_errno);
|
||||||
|
goto restore;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_debug(task, "getgroups(0, NULL): %d", ngroups);
|
||||||
|
|
||||||
|
uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(nxt_gid_t));
|
||||||
|
|
||||||
|
if (nxt_slow_path(uc->gids == NULL)) {
|
||||||
|
goto restore;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngroups = getgroups(ngroups, uc->gids);
|
||||||
|
|
||||||
|
if (nxt_slow_path(ngroups == -1)) {
|
||||||
|
nxt_alert(task, "getgroups(%d) failed %E", ngroups, nxt_errno);
|
||||||
|
goto restore;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc->ngroups = ngroups;
|
||||||
|
|
||||||
|
ret = NXT_OK;
|
||||||
|
|
||||||
|
restore:
|
||||||
|
|
||||||
|
if (nxt_slow_path(setgroups(nsaved, saved) != 0)) {
|
||||||
|
nxt_alert(task, "setgroups(%d) failed %E", nsaved, nxt_errno);
|
||||||
|
ret = NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
free:
|
||||||
|
|
||||||
|
nxt_mp_free(mp, saved);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
nxt_int_t
|
||||||
|
nxt_credential_set(nxt_task_t *task, nxt_credential_t *uc)
|
||||||
|
{
|
||||||
|
nxt_debug(task, "user cred set: \"%s\" uid:%d base gid:%d",
|
||||||
|
uc->user, uc->uid, uc->base_gid);
|
||||||
|
|
||||||
|
if (setgid(uc->base_gid) != 0) {
|
||||||
|
|
||||||
|
#if (NXT_HAVE_CLONE)
|
||||||
|
if (nxt_errno == EINVAL) {
|
||||||
|
nxt_log(task, NXT_LOG_ERR, "The gid %d isn't valid in the "
|
||||||
|
"application namespace.", uc->base_gid);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nxt_alert(task, "setgid(%d) failed %E", uc->base_gid, nxt_errno);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uc->gids != NULL) {
|
||||||
|
if (setgroups(uc->ngroups, uc->gids) != 0) {
|
||||||
|
|
||||||
|
#if (NXT_HAVE_CLONE)
|
||||||
|
if (nxt_errno == EINVAL) {
|
||||||
|
nxt_log(task, NXT_LOG_ERR, "The user \"%s\" (uid: %d) has "
|
||||||
|
"supplementary group ids not valid in the application "
|
||||||
|
"namespace.", uc->user, uc->uid);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nxt_alert(task, "setgroups(%i) failed %E", uc->ngroups, nxt_errno);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* MacOSX fallback. */
|
||||||
|
if (initgroups(uc->user, uc->base_gid) != 0) {
|
||||||
|
nxt_alert(task, "initgroups(%s, %d) failed %E",
|
||||||
|
uc->user, uc->base_gid, nxt_errno);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setuid(uc->uid) != 0) {
|
||||||
|
|
||||||
|
#if (NXT_HAVE_CLONE)
|
||||||
|
if (nxt_errno == EINVAL) {
|
||||||
|
nxt_log(task, NXT_LOG_ERR, "The uid %d (user \"%s\") isn't "
|
||||||
|
"valid in the application namespace.", uc->uid, uc->user);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nxt_alert(task, "setuid(%d) failed %E", uc->uid, nxt_errno);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
28
src/nxt_credential.h
Normal file
28
src/nxt_credential.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Igor Sysoev
|
||||||
|
* Copyright (C) NGINX, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NXT_CREDENTIAL_H_INCLUDED_
|
||||||
|
#define _NXT_CREDENTIAL_H_INCLUDED_
|
||||||
|
|
||||||
|
|
||||||
|
typedef uid_t nxt_uid_t;
|
||||||
|
typedef gid_t nxt_gid_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *user;
|
||||||
|
nxt_uid_t uid;
|
||||||
|
nxt_gid_t base_gid;
|
||||||
|
nxt_uint_t ngroups;
|
||||||
|
nxt_gid_t *gids;
|
||||||
|
} nxt_credential_t;
|
||||||
|
|
||||||
|
|
||||||
|
NXT_EXPORT nxt_int_t nxt_credential_get(nxt_task_t *task, nxt_mp_t *mp,
|
||||||
|
nxt_credential_t *uc, const char *group);
|
||||||
|
NXT_EXPORT nxt_int_t nxt_credential_set(nxt_task_t *task,
|
||||||
|
nxt_credential_t *uc);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _NXT_CREDENTIAL_H_INCLUDED_ */
|
||||||
@@ -58,6 +58,7 @@ typedef uint16_t nxt_port_id_t;
|
|||||||
#include <nxt_thread.h>
|
#include <nxt_thread.h>
|
||||||
#include <nxt_process_type.h>
|
#include <nxt_process_type.h>
|
||||||
#include <nxt_capability.h>
|
#include <nxt_capability.h>
|
||||||
|
#include <nxt_credential.h>
|
||||||
#include <nxt_process.h>
|
#include <nxt_process.h>
|
||||||
#include <nxt_utf8.h>
|
#include <nxt_utf8.h>
|
||||||
#include <nxt_file_name.h>
|
#include <nxt_file_name.h>
|
||||||
|
|||||||
@@ -1677,8 +1677,7 @@ nxt_process_init_creds_set(nxt_task_t *task, nxt_process_init_t *init,
|
|||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
init->user_cred = nxt_mp_zalloc(init->mem_pool,
|
init->user_cred = nxt_mp_zalloc(init->mem_pool, sizeof(nxt_credential_t));
|
||||||
sizeof(nxt_user_cred_t));
|
|
||||||
|
|
||||||
if (nxt_slow_path(init->user_cred == NULL)) {
|
if (nxt_slow_path(init->user_cred == NULL)) {
|
||||||
return NXT_ERROR;
|
return NXT_ERROR;
|
||||||
@@ -1707,5 +1706,5 @@ nxt_process_init_creds_set(nxt_task_t *task, nxt_process_init_t *init,
|
|||||||
str = NULL;
|
str = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nxt_user_cred_get(task, init->mem_pool, init->user_cred, str);
|
return nxt_credential_get(task, init->mem_pool, init->user_cred, str);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
static void nxt_process_start(nxt_task_t *task, nxt_process_t *process);
|
static void nxt_process_start(nxt_task_t *task, nxt_process_t *process);
|
||||||
static nxt_int_t nxt_user_groups_get(nxt_task_t *task, nxt_mp_t *mp,
|
|
||||||
nxt_user_cred_t *uc);
|
|
||||||
static nxt_int_t nxt_process_worker_setup(nxt_task_t *task,
|
static nxt_int_t nxt_process_worker_setup(nxt_task_t *task,
|
||||||
nxt_process_t *process, int parentfd);
|
nxt_process_t *process, int parentfd);
|
||||||
|
|
||||||
@@ -279,7 +277,7 @@ nxt_process_start(nxt_task_t *task, nxt_process_t *process)
|
|||||||
nxt_random_init(&thread->random);
|
nxt_random_init(&thread->random);
|
||||||
|
|
||||||
if (rt->capabilities.setid && init->user_cred != NULL) {
|
if (rt->capabilities.setid && init->user_cred != NULL) {
|
||||||
ret = nxt_user_cred_set(task, init->user_cred);
|
ret = nxt_credential_set(task, init->user_cred);
|
||||||
if (ret != NXT_OK) {
|
if (ret != NXT_OK) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -526,337 +524,6 @@ nxt_nanosleep(nxt_nsec_t ns)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nxt_int_t
|
|
||||||
nxt_user_cred_get(nxt_task_t *task, nxt_mp_t *mp, nxt_user_cred_t *uc,
|
|
||||||
const char *group)
|
|
||||||
{
|
|
||||||
struct group *grp;
|
|
||||||
struct passwd *pwd;
|
|
||||||
|
|
||||||
nxt_errno = 0;
|
|
||||||
|
|
||||||
pwd = getpwnam(uc->user);
|
|
||||||
|
|
||||||
if (nxt_slow_path(pwd == NULL)) {
|
|
||||||
|
|
||||||
if (nxt_errno == 0) {
|
|
||||||
nxt_alert(task, "getpwnam(\"%s\") failed, user \"%s\" not found",
|
|
||||||
uc->user, uc->user);
|
|
||||||
} else {
|
|
||||||
nxt_alert(task, "getpwnam(\"%s\") failed %E", uc->user, nxt_errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
uc->uid = pwd->pw_uid;
|
|
||||||
uc->base_gid = pwd->pw_gid;
|
|
||||||
|
|
||||||
if (group != NULL && group[0] != '\0') {
|
|
||||||
nxt_errno = 0;
|
|
||||||
|
|
||||||
grp = getgrnam(group);
|
|
||||||
|
|
||||||
if (nxt_slow_path(grp == NULL)) {
|
|
||||||
|
|
||||||
if (nxt_errno == 0) {
|
|
||||||
nxt_alert(task,
|
|
||||||
"getgrnam(\"%s\") failed, group \"%s\" not found",
|
|
||||||
group, group);
|
|
||||||
} else {
|
|
||||||
nxt_alert(task, "getgrnam(\"%s\") failed %E", group, nxt_errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
uc->base_gid = grp->gr_gid;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_debug(task, "about to get \"%s\" groups (uid:%d, base gid:%d)",
|
|
||||||
uc->user, uc->uid, uc->base_gid);
|
|
||||||
|
|
||||||
if (nxt_user_groups_get(task, mp, uc) != NXT_OK) {
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (NXT_DEBUG)
|
|
||||||
{
|
|
||||||
u_char *p, *end;
|
|
||||||
nxt_uint_t i;
|
|
||||||
u_char msg[NXT_MAX_ERROR_STR];
|
|
||||||
|
|
||||||
p = msg;
|
|
||||||
end = msg + NXT_MAX_ERROR_STR;
|
|
||||||
|
|
||||||
for (i = 0; i < uc->ngroups; i++) {
|
|
||||||
p = nxt_sprintf(p, end, "%d%c", uc->gids[i],
|
|
||||||
i+1 < uc->ngroups ? ',' : '\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_debug(task, "user \"%s\" has gids:%*s", uc->user, p - msg, msg);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return NXT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if (NXT_HAVE_GETGROUPLIST && !NXT_MACOSX)
|
|
||||||
|
|
||||||
#define NXT_NGROUPS nxt_min(256, NGROUPS_MAX)
|
|
||||||
|
|
||||||
|
|
||||||
static nxt_int_t
|
|
||||||
nxt_user_groups_get(nxt_task_t *task, nxt_mp_t *mp, nxt_user_cred_t *uc)
|
|
||||||
{
|
|
||||||
int ngroups;
|
|
||||||
gid_t groups[NXT_NGROUPS];
|
|
||||||
|
|
||||||
ngroups = NXT_NGROUPS;
|
|
||||||
|
|
||||||
if (getgrouplist(uc->user, uc->base_gid, groups, &ngroups) < 0) {
|
|
||||||
if (nxt_slow_path(ngroups <= NXT_NGROUPS)) {
|
|
||||||
nxt_alert(task, "getgrouplist(\"%s\", %d, ...) failed %E", uc->user,
|
|
||||||
uc->base_gid, nxt_errno);
|
|
||||||
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ngroups > NXT_NGROUPS) {
|
|
||||||
if (ngroups > NGROUPS_MAX) {
|
|
||||||
ngroups = NGROUPS_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
uc->ngroups = ngroups;
|
|
||||||
|
|
||||||
uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(gid_t));
|
|
||||||
if (nxt_slow_path(uc->gids == NULL)) {
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nxt_slow_path(getgrouplist(uc->user, uc->base_gid, uc->gids,
|
|
||||||
&ngroups) < 0)) {
|
|
||||||
|
|
||||||
nxt_alert(task, "getgrouplist(\"%s\", %d) failed %E", uc->user,
|
|
||||||
uc->base_gid, nxt_errno);
|
|
||||||
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NXT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uc->ngroups = ngroups;
|
|
||||||
|
|
||||||
uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(gid_t));
|
|
||||||
if (nxt_slow_path(uc->gids == NULL)) {
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_memcpy(uc->gids, groups, ngroups * sizeof(gid_t));
|
|
||||||
|
|
||||||
return NXT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For operating systems that lack getgrouplist(3) or it's buggy (MacOS),
|
|
||||||
* nxt_user_groups_get() stores an array of groups IDs which should be
|
|
||||||
* set by the setgroups() function for a given user. The initgroups()
|
|
||||||
* may block a just forked worker process for some time if LDAP or NDIS+
|
|
||||||
* is used, so nxt_user_groups_get() allows to get worker user groups in
|
|
||||||
* main process. In a nutshell the initgroups() calls getgrouplist()
|
|
||||||
* followed by setgroups(). However older Solaris lacks the getgrouplist().
|
|
||||||
* Besides getgrouplist() does not allow to query the exact number of
|
|
||||||
* groups in some platforms, while NGROUPS_MAX can be quite large (e.g.
|
|
||||||
* 65536 on Linux).
|
|
||||||
* So nxt_user_groups_get() emulates getgrouplist(): at first the function
|
|
||||||
* saves the super-user groups IDs, then calls initgroups() and saves the
|
|
||||||
* specified user groups IDs, and then restores the super-user groups IDs.
|
|
||||||
* This works at least on Linux, FreeBSD, and Solaris, but does not work
|
|
||||||
* on MacOSX, getgroups(2):
|
|
||||||
*
|
|
||||||
* To provide compatibility with applications that use getgroups() in
|
|
||||||
* environments where users may be in more than {NGROUPS_MAX} groups,
|
|
||||||
* a variant of getgroups(), obtained when compiling with either the
|
|
||||||
* macros _DARWIN_UNLIMITED_GETGROUPS or _DARWIN_C_SOURCE defined, can
|
|
||||||
* be used that is not limited to {NGROUPS_MAX} groups. However, this
|
|
||||||
* variant only returns the user's default group access list and not
|
|
||||||
* the group list modified by a call to setgroups(2).
|
|
||||||
*
|
|
||||||
* For such cases initgroups() is used in worker process as fallback.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static nxt_int_t
|
|
||||||
nxt_user_groups_get(nxt_task_t *task, nxt_mp_t *mp, nxt_user_cred_t *uc)
|
|
||||||
{
|
|
||||||
int nsaved, ngroups;
|
|
||||||
nxt_int_t ret;
|
|
||||||
nxt_gid_t *saved;
|
|
||||||
|
|
||||||
nsaved = getgroups(0, NULL);
|
|
||||||
|
|
||||||
if (nxt_slow_path(nsaved == -1)) {
|
|
||||||
nxt_alert(task, "getgroups(0, NULL) failed %E", nxt_errno);
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_debug(task, "getgroups(0, NULL): %d", nsaved);
|
|
||||||
|
|
||||||
if (nsaved > NGROUPS_MAX) {
|
|
||||||
/* MacOSX case. */
|
|
||||||
|
|
||||||
uc->gids = NULL;
|
|
||||||
uc->ngroups = 0;
|
|
||||||
|
|
||||||
return NXT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
saved = nxt_mp_alloc(mp, nsaved * sizeof(nxt_gid_t));
|
|
||||||
|
|
||||||
if (nxt_slow_path(saved == NULL)) {
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = NXT_ERROR;
|
|
||||||
|
|
||||||
nsaved = getgroups(nsaved, saved);
|
|
||||||
|
|
||||||
if (nxt_slow_path(nsaved == -1)) {
|
|
||||||
nxt_alert(task, "getgroups(%d) failed %E", nsaved, nxt_errno);
|
|
||||||
goto free;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_debug(task, "getgroups(): %d", nsaved);
|
|
||||||
|
|
||||||
if (initgroups(uc->user, uc->base_gid) != 0) {
|
|
||||||
if (nxt_errno == NXT_EPERM) {
|
|
||||||
nxt_log(task, NXT_LOG_NOTICE,
|
|
||||||
"initgroups(%s, %d) failed %E, ignored",
|
|
||||||
uc->user, uc->base_gid, nxt_errno);
|
|
||||||
|
|
||||||
ret = NXT_OK;
|
|
||||||
|
|
||||||
goto free;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
nxt_alert(task, "initgroups(%s, %d) failed %E",
|
|
||||||
uc->user, uc->base_gid, nxt_errno);
|
|
||||||
goto restore;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngroups = getgroups(0, NULL);
|
|
||||||
|
|
||||||
if (nxt_slow_path(ngroups == -1)) {
|
|
||||||
nxt_alert(task, "getgroups(0, NULL) failed %E", nxt_errno);
|
|
||||||
goto restore;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_debug(task, "getgroups(0, NULL): %d", ngroups);
|
|
||||||
|
|
||||||
uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(nxt_gid_t));
|
|
||||||
|
|
||||||
if (nxt_slow_path(uc->gids == NULL)) {
|
|
||||||
goto restore;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngroups = getgroups(ngroups, uc->gids);
|
|
||||||
|
|
||||||
if (nxt_slow_path(ngroups == -1)) {
|
|
||||||
nxt_alert(task, "getgroups(%d) failed %E", ngroups, nxt_errno);
|
|
||||||
goto restore;
|
|
||||||
}
|
|
||||||
|
|
||||||
uc->ngroups = ngroups;
|
|
||||||
|
|
||||||
ret = NXT_OK;
|
|
||||||
|
|
||||||
restore:
|
|
||||||
|
|
||||||
if (nxt_slow_path(setgroups(nsaved, saved) != 0)) {
|
|
||||||
nxt_alert(task, "setgroups(%d) failed %E", nsaved, nxt_errno);
|
|
||||||
ret = NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
free:
|
|
||||||
|
|
||||||
nxt_mp_free(mp, saved);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
nxt_int_t
|
|
||||||
nxt_user_cred_set(nxt_task_t *task, nxt_user_cred_t *uc)
|
|
||||||
{
|
|
||||||
nxt_debug(task, "user cred set: \"%s\" uid:%d base gid:%d",
|
|
||||||
uc->user, uc->uid, uc->base_gid);
|
|
||||||
|
|
||||||
if (setgid(uc->base_gid) != 0) {
|
|
||||||
|
|
||||||
#if (NXT_HAVE_CLONE)
|
|
||||||
if (nxt_errno == EINVAL) {
|
|
||||||
nxt_log(task, NXT_LOG_ERR, "The gid %d isn't valid in the "
|
|
||||||
"application namespace.", uc->base_gid);
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nxt_alert(task, "setgid(%d) failed %E", uc->base_gid, nxt_errno);
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uc->gids != NULL) {
|
|
||||||
if (setgroups(uc->ngroups, uc->gids) != 0) {
|
|
||||||
|
|
||||||
#if (NXT_HAVE_CLONE)
|
|
||||||
if (nxt_errno == EINVAL) {
|
|
||||||
nxt_log(task, NXT_LOG_ERR, "The user \"%s\" (uid: %d) has "
|
|
||||||
"supplementary group ids not valid in the application "
|
|
||||||
"namespace.", uc->user, uc->uid);
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nxt_alert(task, "setgroups(%i) failed %E", uc->ngroups, nxt_errno);
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* MacOSX fallback. */
|
|
||||||
if (initgroups(uc->user, uc->base_gid) != 0) {
|
|
||||||
nxt_alert(task, "initgroups(%s, %d) failed %E",
|
|
||||||
uc->user, uc->base_gid, nxt_errno);
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setuid(uc->uid) != 0) {
|
|
||||||
|
|
||||||
#if (NXT_HAVE_CLONE)
|
|
||||||
if (nxt_errno == EINVAL) {
|
|
||||||
nxt_log(task, NXT_LOG_ERR, "The uid %d (user \"%s\") isn't "
|
|
||||||
"valid in the application namespace.", uc->uid, uc->user);
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nxt_alert(task, "setuid(%d) failed %E", uc->uid, nxt_errno);
|
|
||||||
return NXT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NXT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
|
nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,18 +11,8 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef pid_t nxt_pid_t;
|
typedef pid_t nxt_pid_t;
|
||||||
typedef uid_t nxt_uid_t;
|
|
||||||
typedef gid_t nxt_gid_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char *user;
|
|
||||||
nxt_uid_t uid;
|
|
||||||
nxt_gid_t base_gid;
|
|
||||||
nxt_uint_t ngroups;
|
|
||||||
nxt_gid_t *gids;
|
|
||||||
} nxt_user_cred_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nxt_int_t flags;
|
nxt_int_t flags;
|
||||||
nxt_conf_value_t *uidmap;
|
nxt_conf_value_t *uidmap;
|
||||||
@@ -38,7 +28,7 @@ struct nxt_process_init_s {
|
|||||||
nxt_mp_t *mem_pool;
|
nxt_mp_t *mem_pool;
|
||||||
nxt_process_start_t start;
|
nxt_process_start_t start;
|
||||||
const char *name;
|
const char *name;
|
||||||
nxt_user_cred_t *user_cred;
|
nxt_credential_t *user_cred;
|
||||||
|
|
||||||
const nxt_port_handlers_t *port_handlers;
|
const nxt_port_handlers_t *port_handlers;
|
||||||
const nxt_sig_event_t *signals;
|
const nxt_sig_event_t *signals;
|
||||||
@@ -153,9 +143,6 @@ NXT_EXPORT void nxt_process_title(nxt_task_t *task, const char *fmt, ...);
|
|||||||
#define nxt_abort() \
|
#define nxt_abort() \
|
||||||
(void) raise(SIGABRT)
|
(void) raise(SIGABRT)
|
||||||
|
|
||||||
NXT_EXPORT nxt_int_t nxt_user_cred_get(nxt_task_t *task, nxt_mp_t *mp,
|
|
||||||
nxt_user_cred_t *uc, const char *group);
|
|
||||||
NXT_EXPORT nxt_int_t nxt_user_cred_set(nxt_task_t *task, nxt_user_cred_t *uc);
|
|
||||||
|
|
||||||
NXT_EXPORT extern nxt_pid_t nxt_pid;
|
NXT_EXPORT extern nxt_pid_t nxt_pid;
|
||||||
NXT_EXPORT extern nxt_pid_t nxt_ppid;
|
NXT_EXPORT extern nxt_pid_t nxt_ppid;
|
||||||
|
|||||||
@@ -705,7 +705,7 @@ nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rt->capabilities.setid) {
|
if (rt->capabilities.setid) {
|
||||||
ret = nxt_user_cred_get(task, rt->mem_pool, &rt->user_cred,
|
ret = nxt_credential_get(task, rt->mem_pool, &rt->user_cred,
|
||||||
rt->group);
|
rt->group);
|
||||||
|
|
||||||
if (nxt_slow_path(ret != NXT_OK)) {
|
if (nxt_slow_path(ret != NXT_OK)) {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ struct nxt_runtime_s {
|
|||||||
const char *engine;
|
const char *engine;
|
||||||
uint32_t engine_connections;
|
uint32_t engine_connections;
|
||||||
uint32_t auxiliary_threads;
|
uint32_t auxiliary_threads;
|
||||||
nxt_user_cred_t user_cred;
|
nxt_credential_t user_cred;
|
||||||
nxt_capabilities_t capabilities;
|
nxt_capabilities_t capabilities;
|
||||||
const char *group;
|
const char *group;
|
||||||
const char *pid;
|
const char *pid;
|
||||||
|
|||||||
Reference in New Issue
Block a user