9393#endif
9494
9595#if defined(WOLFSSHD_UNIT_TEST ) && !defined(_WIN32 )
96+ /* Adapts the platform setgroups(2) to a fixed prototype so unit tests can
97+ * swap in a stub regardless of the size argument's native type (int on
98+ * macOS, size_t on Linux). */
99+ static int wsshd_setgroups_default (int size , const WGID_T * list )
100+ {
101+ return setgroups (size , list );
102+ }
96103int (* wsshd_setregid_cb )(WGID_T , WGID_T ) = setregid ;
97104int (* wsshd_setreuid_cb )(WUID_T , WUID_T ) = setreuid ;
105+ int (* wsshd_setgroups_cb )(int , const WGID_T * ) = wsshd_setgroups_default ;
98106#endif
99107
100108struct WOLFSSHD_AUTH {
@@ -1626,7 +1634,7 @@ static int RequestAuthentication(WS_UserAuthData* authData,
16261634 ret = WOLFSSH_USERAUTH_REJECTED ;
16271635 }
16281636 else {
1629- #ifdef WIN32
1637+ #ifdef _WIN32
16301638 /* Still need to get users token on Windows */
16311639 wolfSSH_Log (WS_LOG_INFO ,
16321640 "[SSHD] Relying on CA for public key check" );
@@ -1945,7 +1953,7 @@ int wolfSSHD_AuthRaisePermissions(WOLFSSHD_AUTH* auth)
19451953 int ret = 0 ;
19461954
19471955 wolfSSH_Log (WS_LOG_INFO , "[SSHD] Attempting to raise permissions level" );
1948- #ifndef WIN32
1956+ #ifndef _WIN32
19491957 if (auth ) {
19501958 if (setegid (auth -> sGid ) != 0 ) {
19511959 wolfSSH_Log (WS_LOG_ERROR , "[SSHD] Error raising gid" );
@@ -1970,7 +1978,7 @@ int wolfSSHD_AuthRaisePermissions(WOLFSSHD_AUTH* auth)
19701978int wolfSSHD_AuthReducePermissionsUser (WOLFSSHD_AUTH * auth , WUID_T uid ,
19711979 WGID_T gid )
19721980{
1973- #ifndef WIN32
1981+ #ifndef _WIN32
19741982#ifdef WOLFSSHD_UNIT_TEST
19751983 if (wsshd_setregid_cb (gid , gid ) != 0 ) {
19761984#else
@@ -2005,7 +2013,7 @@ int wolfSSHD_AuthReducePermissions(WOLFSSHD_AUTH* auth)
20052013 }
20062014
20072015 flag = wolfSSHD_ConfigGetPrivilegeSeparation (auth -> conf );
2008- #ifndef WIN32
2016+ #ifndef _WIN32
20092017 if (flag == WOLFSSHD_PRIV_SEPARAT || flag == WOLFSSHD_PRIV_SANDBOX ) {
20102018 wolfSSH_Log (WS_LOG_INFO , "[SSHD] Lowering permissions level" );
20112019
@@ -2023,13 +2031,25 @@ int wolfSSHD_AuthReducePermissions(WOLFSSHD_AUTH* auth)
20232031 return ret ;
20242032}
20252033
2026- #ifndef WIN32
2034+ #ifndef _WIN32
20272035#if defined(__OSX__ ) || defined( __APPLE__ )
20282036 #define WGETGROUPLIST (x ,y ,z ,w ) getgrouplist((x),(y),(int*)(z),(w))
20292037#else
20302038 #define WGETGROUPLIST (x ,y ,z ,w ) getgrouplist((x),(y),(z),(w))
20312039#endif
20322040
2041+ #if defined(WOLFSSHD_UNIT_TEST ) && !defined(_WIN32 )
2042+ /* Adapts getgrouplist(3) to a fixed prototype so unit tests can swap in a
2043+ * stub, hiding the macOS int/gid_t argument difference behind WGETGROUPLIST. */
2044+ static int wsshd_getgrouplist_default (const char * usr , WGID_T grp ,
2045+ WGID_T * groups , int * ngroups )
2046+ {
2047+ return WGETGROUPLIST (usr , grp , groups , ngroups );
2048+ }
2049+ int (* wsshd_getgrouplist_cb )(const char * , WGID_T , WGID_T * , int * )
2050+ = wsshd_getgrouplist_default ;
2051+ #endif
2052+
20332053/* Initial guess and upper bound for the number of groups a user can be in.
20342054 * getgrouplist cannot be reliably sized with a NULL probe (macOS returns
20352055 * success with size 0 and, when the buffer is too small, echoes the input size
@@ -2042,39 +2062,19 @@ int wolfSSHD_AuthReducePermissions(WOLFSSHD_AUTH* auth)
20422062#define WOLFSSHD_GROUP_LIST_MAX 65536
20432063#endif
20442064
2045- /* frees a group name array previously built by wolfSSHD_GetUserGroupNames */
2046- WOLFSSHD_STATIC void wolfSSHD_FreeUserGroupNames (void * heap , char * * names ,
2047- word32 count )
2048- {
2049- word32 i ;
2050-
2051- if (names != NULL ) {
2052- for (i = 0 ; i < count ; i ++ ) {
2053- WFREE (names [i ], heap , DYNTYPE_SSHD );
2054- }
2055- WFREE (names , heap , DYNTYPE_SSHD );
2056- }
2057- }
2058-
2059- /* Builds the list of group names the user belongs to, primary plus
2060- * supplementary, so Match Group can be evaluated against the full set. On
2061- * success sets *outNames to an owned array of owned names and *outCount to the
2062- * entry count; the caller frees them with wolfSSHD_FreeUserGroupNames. Returns
2063- * WS_SUCCESS on success, leaving *outNames NULL on failure. */
2064- WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames (void * heap , const char * usr ,
2065- WGID_T primaryGid , char * * * outNames , word32 * outCount )
2065+ /* Resolves the user's full gid list into an owned buffer via grow-and-retry
2066+ * sizing, since a NULL-size probe is unreliable (macOS reports size 0). Sets
2067+ * *outList (caller frees) and *outCount; returns WS_SUCCESS. */
2068+ static int wolfSSHD_GetUserGroupList (void * heap , const char * usr ,
2069+ WGID_T primaryGid , gid_t * * outList , int * outCount )
20662070{
20672071 int ret = WS_SUCCESS ;
20682072 int grpListSz = 0 ;
20692073 int allocSz ;
20702074 int res ;
2071- int i ;
20722075 gid_t * grpList = NULL ;
2073- char * * names = NULL ;
2074- struct group * g ;
2075- word32 count = 0 ;
20762076
2077- * outNames = NULL ;
2077+ * outList = NULL ;
20782078 * outCount = 0 ;
20792079
20802080#if defined(__QNX__ ) || defined(__QNXNTO__ )
@@ -2092,7 +2092,11 @@ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
20922092 }
20932093 if (ret == WS_SUCCESS ) {
20942094 grpListSz = allocSz ;
2095+ #ifdef WOLFSSHD_UNIT_TEST
2096+ res = wsshd_getgrouplist_cb (usr , primaryGid , grpList , & grpListSz );
2097+ #else
20952098 res = WGETGROUPLIST (usr , primaryGid , grpList , & grpListSz );
2099+ #endif
20962100 if (res != 0 ) {
20972101 ret = WS_FATAL_ERROR ;
20982102 }
@@ -2111,7 +2115,11 @@ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
21112115 }
21122116
21132117 grpListSz = allocSz ;
2118+ #ifdef WOLFSSHD_UNIT_TEST
2119+ res = wsshd_getgrouplist_cb (usr , primaryGid , grpList , & grpListSz );
2120+ #else
21142121 res = WGETGROUPLIST (usr , primaryGid , grpList , & grpListSz );
2122+ #endif
21152123 if (res < 0 ) {
21162124 /* buffer too small: discard, grow, and retry up to the cap */
21172125 WFREE (grpList , heap , DYNTYPE_SSHD );
@@ -2128,6 +2136,51 @@ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
21282136 }
21292137#endif
21302138
2139+ if (ret == WS_SUCCESS ) {
2140+ * outList = grpList ;
2141+ * outCount = grpListSz ;
2142+ }
2143+ else if (grpList != NULL ) {
2144+ WFREE (grpList , heap , DYNTYPE_SSHD );
2145+ }
2146+
2147+ return ret ;
2148+ }
2149+
2150+ /* frees a group name array previously built by wolfSSHD_GetUserGroupNames */
2151+ WOLFSSHD_STATIC void wolfSSHD_FreeUserGroupNames (void * heap , char * * names ,
2152+ word32 count )
2153+ {
2154+ word32 i ;
2155+
2156+ if (names != NULL ) {
2157+ for (i = 0 ; i < count ; i ++ ) {
2158+ WFREE (names [i ], heap , DYNTYPE_SSHD );
2159+ }
2160+ WFREE (names , heap , DYNTYPE_SSHD );
2161+ }
2162+ }
2163+
2164+ /* Builds the owned list of group names the user belongs to (primary plus
2165+ * supplementary) for Match Group evaluation; freed with
2166+ * wolfSSHD_FreeUserGroupNames. Returns WS_SUCCESS, *outNames NULL on failure. */
2167+ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames (void * heap , const char * usr ,
2168+ WGID_T primaryGid , char * * * outNames , word32 * outCount )
2169+ {
2170+ int ret ;
2171+ int grpListSz = 0 ;
2172+ int i ;
2173+ gid_t * grpList = NULL ;
2174+ char * * names = NULL ;
2175+ struct group * g ;
2176+ word32 count = 0 ;
2177+
2178+ * outNames = NULL ;
2179+ * outCount = 0 ;
2180+
2181+ ret = wolfSSHD_GetUserGroupList (heap , usr , primaryGid , & grpList ,
2182+ & grpListSz );
2183+
21312184 if (ret == WS_SUCCESS ) {
21322185 names = (char * * )WMALLOC (sizeof (char * ) * grpListSz , heap , DYNTYPE_SSHD );
21332186 if (names == NULL ) {
@@ -2167,52 +2220,32 @@ WOLFSSHD_STATIC int wolfSSHD_GetUserGroupNames(void* heap, const char* usr,
21672220
21682221 return ret ;
21692222}
2170- #endif /* WIN32 */
2223+ #endif /* _WIN32 */
21712224
21722225/* sets the extended groups the user is in, returns WS_SUCCESS on success */
21732226int wolfSSHD_AuthSetGroups (const WOLFSSHD_AUTH * auth , const char * usr ,
21742227 WGID_T gid )
21752228{
21762229 int ret = WS_SUCCESS ;
2177- #ifndef WIN32
2230+ #ifndef _WIN32
21782231 int grpListSz = 0 ;
21792232 gid_t * grpList = NULL ;
21802233
2181- #if defined(__QNX__ ) || defined(__QNXNTO__ )
2182- /* QNX does not support getting the exact group list size ahead of time,
2183- only the max group list size */
2184- grpListSz = sysconf ( _SC_NGROUPS_MAX );
2234+ /* resolve the full group list with portable grow-and-retry sizing, then
2235+ * apply it; a NULL-size probe is unreliable and would skip the drop. */
2236+ ret = wolfSSHD_GetUserGroupList (auth -> heap , usr , gid , & grpList , & grpListSz );
2237+ if (ret == WS_SUCCESS ) {
2238+ #ifdef WOLFSSHD_UNIT_TEST
2239+ if (wsshd_setgroups_cb (grpListSz , grpList ) == -1 ) {
21852240#else
2186- /* should return -1 if grpListSz is smaller than actual groups */
2187- if (WGETGROUPLIST (usr , gid , NULL , & grpListSz ) == -1 )
2241+ if (setgroups (grpListSz , grpList ) == -1 ) {
21882242#endif
2189- {
2190- grpList = (gid_t * )WMALLOC (sizeof (gid_t ) * grpListSz , auth -> heap ,
2191- DYNTYPE_SSHD );
2192- if (grpList == NULL ) {
2193- ret = WS_MEMORY_E ;
2194- }
2195- else {
2196- int res ;
2197-
2198- res = WGETGROUPLIST (usr , gid , grpList , & grpListSz );
2199- #if defined(__QNX__ ) || defined(__QNXNTO__ )
2200- if (res != 0 ) {
2201- ret = WS_FATAL_ERROR ;
2202- }
2203- #else
2204- if (res != grpListSz ) {
2205- ret = WS_FATAL_ERROR ;
2206- }
2207- #endif
2208-
2209- if (ret == WS_SUCCESS &&
2210- setgroups (grpListSz , grpList ) == -1 ) {
2211- ret = WS_FATAL_ERROR ;
2212- }
2213- WFREE (grpList , auth -> heap , DYNTYPE_SSHD );
2243+ ret = WS_FATAL_ERROR ;
22142244 }
22152245 }
2246+ if (grpList != NULL ) {
2247+ WFREE (grpList , auth -> heap , DYNTYPE_SSHD );
2248+ }
22162249#else
22172250 WOLFSSH_UNUSED (auth );
22182251 WOLFSSH_UNUSED (usr );
@@ -2247,7 +2280,7 @@ WOLFSSHD_CONFIG* wolfSSHD_AuthGetUserConf(const WOLFSSHD_AUTH* auth,
22472280
22482281 if (auth != NULL ) {
22492282 if (usr != NULL ) {
2250- #ifdef WIN32
2283+ #ifdef _WIN32
22512284 /* LogonUserEx(): group lookup is not implemented on Windows, so
22522285 * Match Group directives do not apply here */
22532286#else
@@ -2271,7 +2304,7 @@ WOLFSSHD_CONFIG* wolfSSHD_AuthGetUserConf(const WOLFSSHD_AUTH* auth,
22712304 ret = wolfSSHD_GetUserConf (auth -> conf , usr , (const char * * )grpNames ,
22722305 grpCount , host , localAdr , localPort , RDomain , adr );
22732306
2274- #ifndef WIN32
2307+ #ifndef _WIN32
22752308 wolfSSHD_FreeUserGroupNames (auth -> heap , grpNames , grpCount );
22762309#endif
22772310 }
0 commit comments