Check If the Current User Is Administrator

Check if the current user is administrator

using System.Security.Principal;

public static bool IsAdministrator()
{
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
{
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}

Checking if the current user is in the administrator group with WinAPI

if user member of BUILTIN\Administrators (S-1-5-32-544) group (alias) this sid present in it token groups. and usually only in this case (of course possible create token for not admin user with S-1-5-32-544 and for admin user without it). so simply and effective check - list token groups and look - are S-1-5-32-544 present here, with any attributes. IsUserAdmin not simply check for this sid, but

Even if a SID is present in the token, the system may not use the
SID in an access check. The SID may be disabled or have the SE_GROUP_USE_FOR_DENY_ONLY attribute. The system uses only enabled SIDs to grant access when performing an access check.

when admin user (member of S-1-5-32-544 Alias) interactive login to system and UAC active - system filter it token, and set SE_GROUP_USE_FOR_DENY_ONLY attribute for S-1-5-32-544 (except built-in Administrator - S-1-5-32-500)

so code can be next:

inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}

ULONG IsUserInAdminGroup(BOOLEAN* pb)
{
*pb = FALSE;

HANDLE hToken;
ULONG dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));

if (dwError == NOERROR)
{
// /RTCs must be disabled !
static volatile UCHAR guz = 0;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb = 0x100;

union {
PVOID buf;
PTOKEN_GROUPS ptg;
};

do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}

dwError = BOOL_TO_ERROR(GetTokenInformation(hToken, ::TokenGroups, buf, cb, &rcb));

} while (dwError == ERROR_INSUFFICIENT_BUFFER);

CloseHandle(hToken);

if (dwError == NOERROR)
{
if (ULONG GroupCount = ptg->GroupCount)
{
static const SID_IDENTIFIER_AUTHORITY NT_AUTHORITY = SECURITY_NT_AUTHORITY;
PSID_AND_ATTRIBUTES Groups = ptg->Groups;
do
{
PSID Sid = Groups++->Sid;
if (*GetSidSubAuthorityCount(Sid) == 2 &&
*GetSidSubAuthority(Sid, 0) == SECURITY_BUILTIN_DOMAIN_RID &&
*GetSidSubAuthority(Sid, 1) == DOMAIN_ALIAS_RID_ADMINS &&
!memcmp(&NT_AUTHORITY, GetSidIdentifierAuthority(Sid), sizeof(SID_IDENTIFIER_AUTHORITY)))
{
*pb = TRUE;
break;
}
} while (--GroupCount);
}

return NOERROR;
}
}

return dwError;
}

also possible do direct check of user sid from token - are it member of DOMAIN_ALIAS_RID_ADMINS alias. here question - how exactly is the task, why this necessary at all. example of code (used ntsam.h and linked with samlib.lib - part of standard windows SDK)

HRESULT IsUserInAdminGroup(PSID UserSid, BOOLEAN* pb)
{
SAM_HANDLE ServerHandle, DomainHandle;

NTSTATUS status = SamConnect(0, &ServerHandle, SAM_SERVER_LOOKUP_DOMAIN, 0);

if (0 <= status)
{
ULONG len = GetSidLengthRequired(1);

PSID BuiltIn = (PSID)alloca(len);
static const SID_IDENTIFIER_AUTHORITY NT_AUTHORITY = SECURITY_NT_AUTHORITY;

InitializeSid(BuiltIn, const_cast<SID_IDENTIFIER_AUTHORITY*>(&NT_AUTHORITY), 1);
*GetSidSubAuthority(BuiltIn, 0) = SECURITY_BUILTIN_DOMAIN_RID;

status = SamOpenDomain(ServerHandle, DOMAIN_READ, BuiltIn, &DomainHandle);

SamCloseHandle(ServerHandle);

if (0 <= status)
{
ULONG MembershipCount, *Aliases;

status = SamGetAliasMembership(DomainHandle, 1, &UserSid, &MembershipCount, &Aliases);

SamCloseHandle(DomainHandle);

if (0 <= status)
{
PVOID buf = Aliases;
if (MembershipCount)
{
do
{
if (*Aliases++ == DOMAIN_ALIAS_RID_ADMINS)
{
*pb = TRUE;
break;
}
} while (--MembershipCount);
}
SamFreeMemory(buf);
}
}
}

return HRESULT_FROM_NT(status);
}

HRESULT IsUserInAdminGroup(BOOLEAN* pb)
{
*pb = FALSE;

HANDLE hToken;
ULONG dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));

if (dwError == NOERROR)
{
// /RTCs must be disabled !
static volatile UCHAR guz = 0;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb = 0x80;

union {
PVOID buf;
PTOKEN_USER ptu;
};

do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}

dwError = BOOL_TO_ERROR(GetTokenInformation(hToken, ::TokenUser, buf, cb, &rcb));

} while (dwError == ERROR_INSUFFICIENT_BUFFER);

CloseHandle(hToken);

if (dwError == NOERROR)
{
return IsUserInAdminGroup(ptu->User.Sid, pb);
}
}

return HRESULT_FROM_WIN32(dwError);
}

Check if logged on user is an administrator when non-elevated

If you want to determine if the current user is a member of the local Administrators group (even if not elevated), here are some options.

$null -ne (whoami /groups /fo csv |
ConvertFrom-Csv |
Where-Object { $_.SID -eq "S-1-5-32-544" })

You can also use isadmin.exe (https://westmesatech.com/?page_id=23) and check for an exit code of 2 (member of administrators, but not enabled, hence not elevated).

How to check if currently logged in user is admin or not

Sitecore.Security.Accounts.User class has built in property IsAdministrator:

    Sitecore.Context.User.IsAdministrator

Faster method to test if (not current) user is an administrator

Well, I found it out, however it's still weird...

Updated code: (I changed matching group name to matching group SID).

public static dynamic[] Users => WMI.Query("SELECT * FROM Win32_UserAccount WHERE Disabled = 0").Select<dynamic, dynamic>(d => {
using (var machineContext = new PrincipalContext(ContextType.Machine))
using (Principal principal = Principal.FindByIdentity(machineContext, d.SID))
d.IsAdmin = principal.GetGroups().Any(i => i.Sid.IsWellKnown(System.Security.Principal.WellKnownSidType.BuiltinAdministratorsSid));
return d;
}).ToArray();

It turns out GetGroups() is way faster than IsMemberOf().

Update: It's actually roughly 135 times faster. GetGroups() with Any() took 17ms instead of 2300ms IsMemberOf() took.

As a bonus I'll share with my WMI.Query ;)

/// <summary>
/// Safe, managed WMI queries support.
/// </summary>
static class WMI {

/// <summary>
/// Queries WMI and returns results as an array of dynamic objects.
/// </summary>
/// <param name="q"></param>
/// <returns></returns>
public static dynamic[] Query(string q) {
using (var s = new ManagementObjectSearcher(q))
return
s
.Get()
.OfType<ManagementObject>()
.Select(i => {
var x = new ExpandoObject();
using (i) foreach (var p in i.Properties) (x as IDictionary<string, object>).Add(p.Name, p.Value);
return x;
})
.ToArray();
}
}


Related Topics



Leave a reply



Submit