mirror of https://github.com/wolfSSL/wolfssh.git
wolfsshd: make the supplementary-group drop reliable and tested
parent
a72b9448ad
commit
9702235f91
|
|
@ -93,12 +93,20 @@
|
|||
#endif
|
||||
|
||||
#if defined(WOLFSSHD_UNIT_TEST) && !defined(_WIN32)
|
||||
/* Adapts the platform setgroups(2) to a fixed prototype so unit tests can
|
||||
* swap in a stub regardless of the size argument's native type (int on
|
||||
* macOS, size_t on Linux). */
|
||||
static int wsshd_setgroups_default(int size, const WGID_T* list)
|
||||
{
|
||||
return setgroups(size, list);
|
||||
}
|
||||
int (*wsshd_setregid_cb)(WGID_T, WGID_T) = setregid;
|
||||
int (*wsshd_setreuid_cb)(WUID_T, WUID_T) = setreuid;
|
||||
int (*wsshd_setegid_cb)(WGID_T) = setegid;
|
||||
int (*wsshd_seteuid_cb)(WUID_T) = seteuid;
|
||||
struct passwd* (*wsshd_getpwnam_cb)(const char*) = getpwnam;
|
||||
#define getpwnam wsshd_getpwnam_cb
|
||||
int (*wsshd_setgroups_cb)(int, const WGID_T*) = wsshd_setgroups_default;
|
||||
#endif
|
||||
|
||||
struct WOLFSSHD_AUTH {
|
||||
|
|
@ -1812,7 +1820,7 @@ static int RequestAuthentication(WS_UserAuthData* authData,
|
|||
ret = WOLFSSH_USERAUTH_REJECTED;
|
||||
}
|
||||
else {
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
/* Still need to get users token on Windows */
|
||||
wolfSSH_Log(WS_LOG_INFO,
|
||||
"[SSHD] Relying on CA for public key check");
|
||||
|
|
@ -2173,7 +2181,7 @@ int wolfSSHD_AuthRaisePermissions(WOLFSSHD_AUTH* auth)
|
|||
int wolfSSHD_AuthReducePermissionsUser(WOLFSSHD_AUTH* auth, WUID_T uid,
|
||||
WGID_T gid)
|
||||
{
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
#ifdef WOLFSSHD_UNIT_TEST
|
||||
if (wsshd_setregid_cb(gid, gid) != 0) {
|
||||
#else
|
||||
|
|
@ -2208,7 +2216,7 @@ int wolfSSHD_AuthReducePermissions(WOLFSSHD_AUTH* auth)
|
|||
}
|
||||
|
||||
flag = wolfSSHD_ConfigGetPrivilegeSeparation(auth->conf);
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
if (flag == WOLFSSHD_PRIV_SEPARAT || flag == WOLFSSHD_PRIV_SANDBOX) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Lowering permissions level");
|
||||
|
||||
|
|
@ -2226,13 +2234,25 @@ int wolfSSHD_AuthReducePermissions(WOLFSSHD_AUTH* auth)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
#if defined(__OSX__) || defined( __APPLE__)
|
||||
#define WGETGROUPLIST(x,y,z,w) getgrouplist((x),(y),(int*)(z),(w))
|
||||
#else
|
||||
#define WGETGROUPLIST(x,y,z,w) getgrouplist((x),(y),(z),(w))
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSHD_UNIT_TEST) && !defined(_WIN32)
|
||||
/* Adapts getgrouplist(3) to a fixed prototype so unit tests can swap in a
|
||||
* stub, hiding the macOS int/gid_t argument difference behind WGETGROUPLIST. */
|
||||
static int wsshd_getgrouplist_default(const char* usr, WGID_T grp,
|
||||
WGID_T* groups, int* ngroups)
|
||||
{
|
||||
return WGETGROUPLIST(usr, grp, groups, ngroups);
|
||||
}
|
||||
int (*wsshd_getgrouplist_cb)(const char*, WGID_T, WGID_T*, int*)
|
||||
= wsshd_getgrouplist_default;
|
||||
#endif
|
||||
|
||||
/* Initial guess and upper bound for the number of groups a user can be in.
|
||||
* getgrouplist cannot be reliably sized with a NULL probe (macOS returns
|
||||
* success with size 0 and, when the buffer is too small, echoes the input size
|
||||
|
|
@ -2245,39 +2265,19 @@ int wolfSSHD_AuthReducePermissions(WOLFSSHD_AUTH* auth)
|
|||
#define WOLFSSHD_GROUP_LIST_MAX 65536
|
||||
#endif
|
||||
|
||||
/* frees a group name array previously built by wolfSSHD_GetUserGroupNames */
|
||||
WOLFSSHD_STATIC void wolfSSHD_FreeUserGroupNames(void* heap, char** names,
|
||||
word32 count)
|
||||
{
|
||||
word32 i;
|
||||
|
||||
if (names != NULL) {
|
||||
for (i = 0; i < count; i++) {
|
||||
WFREE(names[i], heap, DYNTYPE_SSHD);
|
||||
}
|
||||
WFREE(names, heap, DYNTYPE_SSHD);
|
||||
}
|
||||
}
|
||||
|
||||
/* Builds the list of group names the user belongs to, primary plus
|
||||
* supplementary, so Match Group can be evaluated against the full set. On
|
||||
* success sets *outNames to an owned array of owned names and *outCount to the
|
||||
* entry count; the caller frees them with wolfSSHD_FreeUserGroupNames. Returns
|
||||
* WS_SUCCESS on success, leaving *outNames NULL on failure. */
|
||||
WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
|
||||
WGID_T primaryGid, char*** outNames, word32* outCount)
|
||||
/* Resolves the user's full gid list into an owned buffer via grow-and-retry
|
||||
* sizing, since a NULL-size probe is unreliable (macOS reports size 0). Sets
|
||||
* *outList (caller frees) and *outCount; returns WS_SUCCESS. */
|
||||
static int wolfSSHD_GetUserGroupList(void* heap, const char* usr,
|
||||
WGID_T primaryGid, gid_t** outList, int* outCount)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
int grpListSz = 0;
|
||||
int allocSz;
|
||||
int res;
|
||||
int i;
|
||||
gid_t* grpList = NULL;
|
||||
char** names = NULL;
|
||||
struct group* g;
|
||||
word32 count = 0;
|
||||
|
||||
*outNames = NULL;
|
||||
*outList = NULL;
|
||||
*outCount = 0;
|
||||
|
||||
#if defined(__QNX__) || defined(__QNXNTO__)
|
||||
|
|
@ -2295,7 +2295,11 @@ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
|
|||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
grpListSz = allocSz;
|
||||
#ifdef WOLFSSHD_UNIT_TEST
|
||||
res = wsshd_getgrouplist_cb(usr, primaryGid, grpList, &grpListSz);
|
||||
#else
|
||||
res = WGETGROUPLIST(usr, primaryGid, grpList, &grpListSz);
|
||||
#endif
|
||||
if (res != 0) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
|
@ -2314,7 +2318,11 @@ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
|
|||
}
|
||||
|
||||
grpListSz = allocSz;
|
||||
#ifdef WOLFSSHD_UNIT_TEST
|
||||
res = wsshd_getgrouplist_cb(usr, primaryGid, grpList, &grpListSz);
|
||||
#else
|
||||
res = WGETGROUPLIST(usr, primaryGid, grpList, &grpListSz);
|
||||
#endif
|
||||
if (res < 0) {
|
||||
/* buffer too small: discard, grow, and retry up to the cap */
|
||||
WFREE(grpList, heap, DYNTYPE_SSHD);
|
||||
|
|
@ -2331,6 +2339,51 @@ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
*outList = grpList;
|
||||
*outCount = grpListSz;
|
||||
}
|
||||
else if (grpList != NULL) {
|
||||
WFREE(grpList, heap, DYNTYPE_SSHD);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* frees a group name array previously built by wolfSSHD_GetUserGroupNames */
|
||||
WOLFSSHD_STATIC void wolfSSHD_FreeUserGroupNames(void* heap, char** names,
|
||||
word32 count)
|
||||
{
|
||||
word32 i;
|
||||
|
||||
if (names != NULL) {
|
||||
for (i = 0; i < count; i++) {
|
||||
WFREE(names[i], heap, DYNTYPE_SSHD);
|
||||
}
|
||||
WFREE(names, heap, DYNTYPE_SSHD);
|
||||
}
|
||||
}
|
||||
|
||||
/* Builds the owned list of group names the user belongs to (primary plus
|
||||
* supplementary) for Match Group evaluation; freed with
|
||||
* wolfSSHD_FreeUserGroupNames. Returns WS_SUCCESS, *outNames NULL on failure. */
|
||||
WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
|
||||
WGID_T primaryGid, char*** outNames, word32* outCount)
|
||||
{
|
||||
int ret;
|
||||
int grpListSz = 0;
|
||||
int i;
|
||||
gid_t* grpList = NULL;
|
||||
char** names = NULL;
|
||||
struct group* g;
|
||||
word32 count = 0;
|
||||
|
||||
*outNames = NULL;
|
||||
*outCount = 0;
|
||||
|
||||
ret = wolfSSHD_GetUserGroupList(heap, usr, primaryGid, &grpList,
|
||||
&grpListSz);
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
names = (char**)WMALLOC(sizeof(char*) * grpListSz, heap, DYNTYPE_SSHD);
|
||||
if (names == NULL) {
|
||||
|
|
@ -2370,52 +2423,32 @@ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* sets the extended groups the user is in, returns WS_SUCCESS on success */
|
||||
int wolfSSHD_AuthSetGroups(const WOLFSSHD_AUTH* auth, const char* usr,
|
||||
WGID_T gid)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
int grpListSz = 0;
|
||||
gid_t* grpList = NULL;
|
||||
|
||||
#if defined(__QNX__) || defined(__QNXNTO__)
|
||||
/* QNX does not support getting the exact group list size ahead of time,
|
||||
only the max group list size */
|
||||
grpListSz = sysconf( _SC_NGROUPS_MAX );
|
||||
/* resolve the full group list with portable grow-and-retry sizing, then
|
||||
* apply it; a NULL-size probe is unreliable and would skip the drop. */
|
||||
ret = wolfSSHD_GetUserGroupList(auth->heap, usr, gid, &grpList, &grpListSz);
|
||||
if (ret == WS_SUCCESS) {
|
||||
#ifdef WOLFSSHD_UNIT_TEST
|
||||
if (wsshd_setgroups_cb(grpListSz, grpList) == -1) {
|
||||
#else
|
||||
/* should return -1 if grpListSz is smaller than actual groups */
|
||||
if (WGETGROUPLIST(usr, gid, NULL, &grpListSz) == -1)
|
||||
if (setgroups(grpListSz, grpList) == -1) {
|
||||
#endif
|
||||
{
|
||||
grpList = (gid_t*)WMALLOC(sizeof(gid_t) * grpListSz, auth->heap,
|
||||
DYNTYPE_SSHD);
|
||||
if (grpList == NULL) {
|
||||
ret = WS_MEMORY_E;
|
||||
}
|
||||
else {
|
||||
int res;
|
||||
|
||||
res = WGETGROUPLIST(usr, gid, grpList, &grpListSz);
|
||||
#if defined(__QNX__) || defined(__QNXNTO__)
|
||||
if (res != 0) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
#else
|
||||
if (res != grpListSz) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret == WS_SUCCESS &&
|
||||
setgroups(grpListSz, grpList) == -1) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
WFREE(grpList, auth->heap, DYNTYPE_SSHD);
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
if (grpList != NULL) {
|
||||
WFREE(grpList, auth->heap, DYNTYPE_SSHD);
|
||||
}
|
||||
#else
|
||||
WOLFSSH_UNUSED(auth);
|
||||
WOLFSSH_UNUSED(usr);
|
||||
|
|
@ -2450,7 +2483,7 @@ WOLFSSHD_CONFIG* wolfSSHD_AuthGetUserConf(const WOLFSSHD_AUTH* auth,
|
|||
|
||||
if (auth != NULL) {
|
||||
if (usr != NULL) {
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
/* LogonUserEx(): group lookup is not implemented on Windows, so
|
||||
* Match Group directives do not apply here */
|
||||
#else
|
||||
|
|
@ -2474,7 +2507,7 @@ WOLFSSHD_CONFIG* wolfSSHD_AuthGetUserConf(const WOLFSSHD_AUTH* auth,
|
|||
ret = wolfSSHD_GetUserConf(auth->conf, usr, (const char**)grpNames,
|
||||
grpCount, host, localAdr, localPort, RDomain, adr);
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
wolfSSHD_FreeUserGroupNames(auth->heap, grpNames, grpCount);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ extern int (*wsshd_setreuid_cb)(WUID_T, WUID_T);
|
|||
extern int (*wsshd_setegid_cb)(WGID_T);
|
||||
extern int (*wsshd_seteuid_cb)(WUID_T);
|
||||
extern struct passwd* (*wsshd_getpwnam_cb)(const char*);
|
||||
extern int (*wsshd_setgroups_cb)(int, const WGID_T*);
|
||||
extern int (*wsshd_getgrouplist_cb)(const char*, WGID_T, WGID_T*, int*);
|
||||
int wolfSSHD_GetUserGroupNames(void* heap, const char* usr, WGID_T primaryGid,
|
||||
char*** outNames, word32* outCount);
|
||||
void wolfSSHD_FreeUserGroupNames(void* heap, char** names, word32 count);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSH_DEFAULT_LOG_WIDTH
|
||||
|
|
@ -1462,6 +1463,88 @@ static void InstallPrivDropStubs(int regidRet, int reuidRet,
|
|||
s_setreuid_arg0 = s_setreuid_arg1 = 0;
|
||||
}
|
||||
|
||||
#define GROUP_STUB_MAX 16
|
||||
static WGID_T s_grouplist_groups[GROUP_STUB_MAX];
|
||||
static int s_grouplist_count;
|
||||
static int s_grouplist_always_fail;
|
||||
static int s_grouplist_calls;
|
||||
static WGID_T s_setgroups_seen[GROUP_STUB_MAX];
|
||||
static int s_setgroups_size;
|
||||
static int s_setgroups_list_nonnull;
|
||||
static int s_setgroups_ret;
|
||||
static int s_setgroups_called;
|
||||
|
||||
static int stub_getgrouplist(const char* usr, WGID_T grp, WGID_T* groups,
|
||||
int* ngroups)
|
||||
{
|
||||
int i;
|
||||
|
||||
WOLFSSH_UNUSED(usr);
|
||||
WOLFSSH_UNUSED(grp);
|
||||
s_grouplist_calls++;
|
||||
/* simulate a lookup that never fits, exercising the resolve failure path */
|
||||
if (s_grouplist_always_fail) {
|
||||
*ngroups = s_grouplist_count;
|
||||
return -1;
|
||||
}
|
||||
/* too-small buffer: echo the needed size and return -1 so the caller grows
|
||||
* and retries, matching the getgrouplist(3) contract. */
|
||||
if (groups == NULL || *ngroups < s_grouplist_count) {
|
||||
*ngroups = s_grouplist_count;
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < s_grouplist_count; i++) {
|
||||
groups[i] = s_grouplist_groups[i];
|
||||
}
|
||||
*ngroups = s_grouplist_count;
|
||||
#if defined(__QNX__) || defined(__QNXNTO__)
|
||||
/* QNX getgrouplist returns 0 on success rather than the count */
|
||||
return 0;
|
||||
#else
|
||||
return s_grouplist_count;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int stub_setgroups(int size, const WGID_T* list)
|
||||
{
|
||||
int i;
|
||||
|
||||
s_setgroups_called = 1;
|
||||
s_setgroups_size = size;
|
||||
/* record what we can while the buffer is live; the caller frees it on
|
||||
* return, so the pointer itself must not be inspected afterwards. */
|
||||
s_setgroups_list_nonnull = (list != NULL);
|
||||
for (i = 0; list != NULL && i < size && i < GROUP_STUB_MAX; i++) {
|
||||
s_setgroups_seen[i] = list[i];
|
||||
}
|
||||
return s_setgroups_ret;
|
||||
}
|
||||
|
||||
static void InstallGroupStubs(int setgroupsRet,
|
||||
int (**savedGrouplist)(const char*, WGID_T, WGID_T*, int*),
|
||||
int (**savedSetgroups)(int, const WGID_T*))
|
||||
{
|
||||
int i;
|
||||
|
||||
*savedGrouplist = wsshd_getgrouplist_cb;
|
||||
*savedSetgroups = wsshd_setgroups_cb;
|
||||
wsshd_getgrouplist_cb = stub_getgrouplist;
|
||||
wsshd_setgroups_cb = stub_setgroups;
|
||||
s_grouplist_count = 3;
|
||||
s_grouplist_groups[0] = 1001;
|
||||
s_grouplist_groups[1] = 1002;
|
||||
s_grouplist_groups[2] = 1003;
|
||||
s_grouplist_always_fail = 0;
|
||||
s_grouplist_calls = 0;
|
||||
s_setgroups_ret = setgroupsRet;
|
||||
s_setgroups_called = 0;
|
||||
s_setgroups_size = 0;
|
||||
s_setgroups_list_nonnull = 0;
|
||||
for (i = 0; i < GROUP_STUB_MAX; i++) {
|
||||
s_setgroups_seen[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Exercises the group-name enumeration helper against the account running the
|
||||
* test. Covers the allocation and ownership contract end to end (the names
|
||||
* array, each duplicated name, and the gid scratch buffer) so a sanitizer run
|
||||
|
|
@ -1847,6 +1930,134 @@ static int test_AuthRaisePermissions_uidFail(void)
|
|||
wolfSSHD_ConfigFree(conf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Drives the supplementary-group drop with getgrouplist and setgroups mocked
|
||||
* so it is deterministic across platforms; asserts setgroups is invoked with
|
||||
* the resolved group count. */
|
||||
static int test_AuthSetGroups_ok(void)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
WOLFSSHD_CONFIG* conf = NULL;
|
||||
WOLFSSHD_AUTH* auth = NULL;
|
||||
int (*savedGrouplist)(const char*, WGID_T, WGID_T*, int*);
|
||||
int (*savedSetgroups)(int, const WGID_T*);
|
||||
|
||||
conf = wolfSSHD_ConfigNew(NULL);
|
||||
if (conf == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
if (ret == WS_SUCCESS) {
|
||||
auth = wolfSSHD_AuthCreateUser(NULL, conf);
|
||||
if (auth == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
InstallGroupStubs(0, &savedGrouplist, &savedSetgroups);
|
||||
|
||||
if (ret == WS_SUCCESS
|
||||
&& wolfSSHD_AuthSetGroups(auth, "testuser", 1000) != WS_SUCCESS)
|
||||
ret = WS_FATAL_ERROR;
|
||||
|
||||
/* the drop must actually call setgroups with the resolved list */
|
||||
if (ret == WS_SUCCESS && !s_setgroups_called)
|
||||
ret = WS_FATAL_ERROR;
|
||||
if (ret == WS_SUCCESS && s_setgroups_size != s_grouplist_count)
|
||||
ret = WS_FATAL_ERROR;
|
||||
if (ret == WS_SUCCESS && !s_setgroups_list_nonnull)
|
||||
ret = WS_FATAL_ERROR;
|
||||
/* the exact resolved gids must reach setgroups, not just the count */
|
||||
if (ret == WS_SUCCESS
|
||||
&& (s_setgroups_seen[0] != 1001 || s_setgroups_seen[1] != 1002
|
||||
|| s_setgroups_seen[2] != 1003))
|
||||
ret = WS_FATAL_ERROR;
|
||||
#if !defined(__QNX__) && !defined(__QNXNTO__)
|
||||
/* the small init size (-DWOLFSSHD_GROUP_LIST_INIT=1) forces at least one
|
||||
* grow-and-retry before the lookup fits, covering that branch */
|
||||
if (ret == WS_SUCCESS && s_grouplist_calls < 2)
|
||||
ret = WS_FATAL_ERROR;
|
||||
#endif
|
||||
|
||||
wsshd_getgrouplist_cb = savedGrouplist;
|
||||
wsshd_setgroups_cb = savedSetgroups;
|
||||
if (auth != NULL)
|
||||
(void)wolfSSHD_AuthFreeUser(auth);
|
||||
if (conf != NULL)
|
||||
wolfSSHD_ConfigFree(conf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* A setgroups(2) failure must abort the privilege setup with WS_FATAL_ERROR
|
||||
* rather than being silently ignored. */
|
||||
static int test_AuthSetGroups_setgroups_fail(void)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
WOLFSSHD_CONFIG* conf = NULL;
|
||||
WOLFSSHD_AUTH* auth = NULL;
|
||||
int (*savedGrouplist)(const char*, WGID_T, WGID_T*, int*);
|
||||
int (*savedSetgroups)(int, const WGID_T*);
|
||||
|
||||
conf = wolfSSHD_ConfigNew(NULL);
|
||||
if (conf == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
if (ret == WS_SUCCESS) {
|
||||
auth = wolfSSHD_AuthCreateUser(NULL, conf);
|
||||
if (auth == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
InstallGroupStubs(-1, &savedGrouplist, &savedSetgroups);
|
||||
|
||||
if (ret == WS_SUCCESS
|
||||
&& wolfSSHD_AuthSetGroups(auth, "testuser", 1000) != WS_FATAL_ERROR)
|
||||
ret = WS_FATAL_ERROR;
|
||||
if (ret == WS_SUCCESS && !s_setgroups_called)
|
||||
ret = WS_FATAL_ERROR;
|
||||
|
||||
wsshd_getgrouplist_cb = savedGrouplist;
|
||||
wsshd_setgroups_cb = savedSetgroups;
|
||||
if (auth != NULL)
|
||||
(void)wolfSSHD_AuthFreeUser(auth);
|
||||
if (conf != NULL)
|
||||
wolfSSHD_ConfigFree(conf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* A getgrouplist lookup that never succeeds must fail closed with
|
||||
* WS_FATAL_ERROR and never reach the setgroups drop. */
|
||||
static int test_AuthSetGroups_getgrouplist_fail(void)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
WOLFSSHD_CONFIG* conf = NULL;
|
||||
WOLFSSHD_AUTH* auth = NULL;
|
||||
int (*savedGrouplist)(const char*, WGID_T, WGID_T*, int*);
|
||||
int (*savedSetgroups)(int, const WGID_T*);
|
||||
|
||||
conf = wolfSSHD_ConfigNew(NULL);
|
||||
if (conf == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
if (ret == WS_SUCCESS) {
|
||||
auth = wolfSSHD_AuthCreateUser(NULL, conf);
|
||||
if (auth == NULL)
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
InstallGroupStubs(0, &savedGrouplist, &savedSetgroups);
|
||||
s_grouplist_always_fail = 1;
|
||||
|
||||
if (ret == WS_SUCCESS
|
||||
&& wolfSSHD_AuthSetGroups(auth, "testuser", 1000) != WS_FATAL_ERROR)
|
||||
ret = WS_FATAL_ERROR;
|
||||
/* group resolution failed, so the drop must not have run */
|
||||
if (ret == WS_SUCCESS && s_setgroups_called)
|
||||
ret = WS_FATAL_ERROR;
|
||||
|
||||
wsshd_getgrouplist_cb = savedGrouplist;
|
||||
wsshd_setgroups_cb = savedSetgroups;
|
||||
if (auth != NULL)
|
||||
(void)wolfSSHD_AuthFreeUser(auth);
|
||||
if (conf != NULL)
|
||||
wolfSSHD_ConfigFree(conf);
|
||||
return ret;
|
||||
}
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
/* Locks in the NULL-safe comparison used by RequestAuthentication to fail
|
||||
|
|
@ -2798,6 +3009,9 @@ const TEST_CASE testCases[] = {
|
|||
TEST_DECL(test_AuthRaisePermissions_nullArg),
|
||||
TEST_DECL(test_AuthRaisePermissions_gidFailSkipsUid),
|
||||
TEST_DECL(test_AuthRaisePermissions_uidFail),
|
||||
TEST_DECL(test_AuthSetGroups_ok),
|
||||
TEST_DECL(test_AuthSetGroups_setgroups_fail),
|
||||
TEST_DECL(test_AuthSetGroups_getgrouplist_fail),
|
||||
#endif
|
||||
#if defined(WOLFSSH_HAVE_LIBCRYPT) || defined(WOLFSSH_HAVE_LIBLOGIN)
|
||||
TEST_DECL(test_CheckPasswordHashUnix),
|
||||
|
|
|
|||
Loading…
Reference in New Issue