I have a user DOMAIN\User.Name
that is according to whoami /GROUPS
in somewhat over 200 windows domain groups.
When I try do determine all groups for this user using the WinAPI function ::NetUserGetLocalGroups() I get only 27 groups for said user:
#include <windows.h>
#include <lm.h>
#include <string>
int main()
{
//query the domain server for the groups of the user
LPGROUP_USERS_INFO_0 pBuf = NULL;
DWORD dwLevel = 0;
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
NET_API_STATUS nStatus = MAX_NERR;
std::wstring serverName(L"\\\\MyDomainNameDns");
std::wstring userName(L"DOMAIN\\user.name");
nStatus = ::NetUserGetLocalGroups(serverName.c_str(),
userName.c_str(),
dwLevel,
LG_INCLUDE_INDIRECT,
reinterpret_cast<PBYTE*>(&pBuf),
dwPrefMaxLen,
&dwEntriesRead,
&dwTotalEntries);
}
dwTotalEntries
is 27 and nStatus
is 0, so it's not that I fetch only a part of all groups. Also I tried using ::NetUserGetGroups()
instead but had no success either.
NOTE: Using .NET functionality System.Security.Principal.WindowsIdentity.GetCurrent().Groups
indeed does give me all groups.
What could be the reason NetUserGetLocalGroups does not return get all groups as whoami
or .NET / WindowsIdentity
? What could be the difference between the groups returned/not returned?
After quite some more digging I found the following statement in a windows user group discussion:
Actually, NetUserGetLocalGroups / NetUserGetGroups do not handle nested or universal groups in windows 2000 native domains. Enumerating the SIDs from the token is the only reliable way.
So, in other words, use ::NetUserGetLocalGroups
/ NetUserGetGroups
if you want direct group membership. If you want to know the group ownership in order to find out whether a user has the right to do something, use the token / SID way (e.g. using ::OpenProcessToken
, ::GetTokenInformation
and ::LookupAccountSid
).
A user is in the (domain local) group Employee
. All employees have keycard access to the building, so the Employee
group is am member of the HasBuildingAccess
(domain local) group.
If you want to know, whether a user is (directly) in the Employee
group, use ::NetUserGetLocalGroups
. It contains the Employee
group, but not the HasBuildingAccess
group.
If you want to know however, whether a user has the right to access the building, enumerate the SIDs from the token. It will contain the HasBuildingAccess
group.