C#: How to check if the current user is an Administrator (even if UAC is on)

How to check if the current user is an Administrator (even if UAC is on)

There may be a scenario where you want to determine from code if the current user is an Administrator.

One example of this which I have had to deal with is checking for software updates.

Say your application contacts a service to see if there is a newer version of the application available; if so, you can download and run the installer.

Imagine that the installer requires admin privileges; you don’t want to run the installer if the current user does not have administrative privileges.

So how can we check if the user is an admin or not?

In VB6, C++ etc

There is a Windows API function you can use very easily to see if the current user is an admin: IsUserAnAdmin.

Visual Basic 6 Declaration

Private Declare Function IsUserAnAdmin Lib “Shell32″ Alias “#680″ () As Integer

While you can still use this, it is actually deprecated, and the documentation recommends you call the CheckTokenMembership function instead (which IsUserAnAdmin is a wrapper for).

.NET

C#.NET

using System;

using System.Security.Principal;

var identity = WindowsIdentity.GetCurrent();

if (identity == null) throw new InvalidOperationException("Couldn’t get the current user identity");

var principal = new WindowsPrincipal(identity);

return principal.IsInRole(WindowsBuiltInRole.Administrator);

User Account Control (UAC)

A problem arises when you use any of the above code on a machine that has UAC enabled, and the process is not elevated.

While the user may be an administrator, when the process is not elevated yet, the user has a split token – which doesn’t have the administrator privileges.

A way around this is to use the GetTokenInformation API call to inspect the token to see if it’s a split token. In most cases this will mean that UAC is on and the current user is an administrator.

This is not 100% reliable (see References) but it’s probably the best we can do for now.

C#.NET

This code is slightly easier in .NET, as there’s already a fair amount of code we don’t have to write to get the current process’s token.

First, we’ll need some code to support the GetTokenInformation API call:

[DllImport("advapi32.dll", SetLastError = true)]

static extern bool GetTokenInformation(IntPtr tokenHandle, TokenInformationClass tokenInformationClass, IntPtr tokenInformation, int tokenInformationLength, out int returnLength);

/// <summary>

/// Passed to <see cref="GetTokenInformation"/> to specify what

/// information about the token to return.

/// </summary>

enum TokenInformationClass

{

TokenUser = 1,

TokenGroups,

TokenPrivileges,

TokenOwner,

TokenPrimaryGroup,

TokenDefaultDacl,

TokenSource,

TokenType,

TokenImpersonationLevel,

TokenStatistics,

TokenRestrictedSids,

TokenSessionId,

TokenGroupsAndPrivileges,

TokenSessionReference,

TokenSandBoxInert,

TokenAuditPolicy,

TokenOrigin,

TokenElevationType,

TokenLinkedToken,

TokenElevation,

TokenHasRestrictions,

TokenAccessInformation,

TokenVirtualizationAllowed,

TokenVirtualizationEnabled,

TokenIntegrityLevel,

TokenUiAccess,

TokenMandatoryPolicy,

TokenLogonSid,

MaxTokenInfoClass

}

/// <summary>

/// The elevation type for a user token.

/// </summary>

enum TokenElevationType

{

TokenElevationTypeDefault = 1,

TokenElevationTypeFull,

TokenElevationTypeLimited

}

Then, the actual code to detect if the user is an Administrator (returning true if they are, otherwise false).

var identity = WindowsIdentity.GetCurrent();

if (identity == null) throw new InvalidOperationException("Couldn’t get the current user identity");

var principal = new WindowsPrincipal(identity);

// Check if this user has the Administrator role. If they do, return immediately.

// If UAC is on, and the process is not elevated, then this will actually return false.

if (principal.IsInRole(WindowsBuiltInRole.Administrator)) return true;

// If we’re not running in Vista onwards, we don’t have to worry about checking for UAC.

if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6)

{

// Operating system does not support UAC; skipping elevation check.

return false;

}

int tokenInfLength = Marshal.SizeOf(typeof(int));

IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInfLength);

try

{

var token = identity.Token;

var result = GetTokenInformation(token, TokenInformationClass.TokenElevationType, tokenInformation, tokenInfLength, out tokenInfLength);

if (!result)

{

var exception = Marshal.GetExceptionForHR( Marshal.GetHRForLastWin32Error() );

throw new InvalidOperationException("Couldn’t get token information", exception);

}

var elevationType = (TokenElevationType)Marshal.ReadInt32(tokenInformation);

switch (elevationType)

{

case TokenElevationType.TokenElevationTypeDefault:

// TokenElevationTypeDefault – User is not using a split token, so they cannot elevate.

return false;

case TokenElevationType.TokenElevationTypeFull:

// TokenElevationTypeFull – User has a split token, and the process is running elevated. Assuming they’re an administrator.

return true;

case TokenElevationType.TokenElevationTypeLimited:

// TokenElevationTypeLimited – User has a split token, but the process is not running elevated. Assuming they’re an administrator.

return true;

default:

// Unknown token elevation type.

return false;

}

}

finally

{

if (tokenInformation != IntPtr.Zero) Marshal.FreeHGlobal(tokenInformation);

}

References

http://www.davidmoore.info/2011/06/20/how-to-check-if-the-current-user-is-an-administrator-even-if-uac-is-on/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s