Reputation: 9483
My Problem
I'm using PInvoked Windows API functions to verify if a user is part of the local administrators group. I'm utilizing GetCurrentProcess
, OpenProcessToken
, GetTokenInformation
and LookupAccountSid
to verify if the user is a local admin.
GetTokenInformation
returns a TOKEN_GROUPS
struct with an array of SID_AND_ATTRIBUTES
structs. I iterate over the collection and compare the user names returned by LookupAccountSid
.
My problem is that, locally (or more generally on our in-house domain), this works as expected. The builtin\Administrators is located within the group membership of the current process token and my method returns true. On another domain of another developer the function returns false.
The LookupAccountSid
functions properly for the first 2 iterations of the TOKEN_GROUPS
struct, returning None and Everyone, and then craps out complaining that "A Parameter is incorrect."
What would cause only two groups to work correctly?
The TOKEN_GROUPS
struct indicates that there are 14 groups. I'm assuming it's the SID that is invalid.
Everything that I have PInvoked I have taken from an example on the PInvoke website. The only difference is that with the LookupAccountSid
I have changed the Sid
parameter from a byte[]
to a IntPtr
because SID_AND_ATTRIBUTES
is also defined with an IntPtr
. Is this ok since LookupAccountSid
is defined with a PSID?
LookupAccountSid PInvoke
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool LookupAccountSid(
string lpSystemName,
IntPtr Sid,
StringBuilder lpName,
ref uint cchName,
StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out SID_NAME_USE peUse);
Where the code falls over
for (int i = 0; i < usize; i++)
{
accountCount = 0;
domainCount = 0;
//Get Sizes
LookupAccountSid(null, tokenGroups.Groups[i].SID, null, ref accountCount, null,
ref domainCount, out snu);
accountName2.EnsureCapacity((int) accountCount);
domainName.EnsureCapacity((int) domainCount);
if (!LookupAccountSid(null, tokenGroups.Groups[i].SID, accountName2, ref accountCount, domainName,
ref domainCount, out snu))
{
//Finds its way here after 2 iterations
//But only in a different developers domain
var error = Marshal.GetLastWin32Error();
_log.InfoFormat("Failed to look up SID's account name. {0}", new Win32Exception(error).Message);
continue;
}
If more code is needed let me know. Any help would be greatly appreciated.
Upvotes: 2
Views: 2560
Reputation: 101569
I'm not sure if NetUserGetLocalGroups knows about deny SIDs (If you need to verify if the current process (not the user account!) is in the admin group, you have to handle deny SIDs)
If you only need to support 2000 and later, PInvoke CheckTokenMembership (That MSDN page has a IsUserAdmin example function)
On NT4 you need to get a TokenGroups array from GetTokenInformation, but you don't call LookupAccountSid, you just call EqualSid on every item and compare it to a admin group SID you create with AllocateAndInitializeSid(...,SECURITY_BUILTIN_DOMAIN_RID,...)
Upvotes: 2
Reputation: 490048
It sounds like you're trying to duplicate the functionality of NetUserGetLocalGroups
. You can also use NetUserGetInfo
with an information level of 1, and check the value of usri1_priv
in the USER_INFO_1
for USER_PRIV_ADMIN
.
Upvotes: 2