VB.NET Tips / Tricks / Examples and Help

VB.NET How to tell if a user can elevate to admin rights in Vista and Windows 7

Generally finding out if a user has the permissions to do something involves trying to do that thing, and handling the access denied (error 5) exception that results.

What if you wanted to know if a user is an admin though prior to doing some admin task via code? Normally this would be as easy as checking if the user is a member of the built in administrators group in Windows, however with Vista and Windows 7, the OS uses a split token so your user account runs with standard user permissions, but can elevate as needed to full admin rights.

When a standard user does the same thing, and invokes some process that requires administrative rights, they will be prompted with a user id/password dialog, and must enter the credentials of an account that is an admin member on the system.

My reason for having to look at this was due to a program where a process running as a standard user downloads some update files to the user's temp folder, and then launches an application as administrator to process those files. If the standard user gets a credentials dialog, and enters in alternate admin credentials, then the user profile changes, and the temp directory is now the admins temp directory, not the standard user's. This created lots of problems, and while there were a few options for a resolution, most were going to be messy, and I opted to go for the following approach:

When the user goes to download update files from the software, determine if they are an admin, and if not, determine if they CAN be an admin. If they can, then I know they will get the regular click through elevation prompt, and the profile will remain the same. However if they are not an admin, and they can not elevate to an admin, I can void the download, and inform the user the main download process should be invoked by an administrator. This will cause the temp files to be in the correct place, as well as some other environment variables that the program uses, and the update will succeed.

So that was my reason for needing it, but I know that several other reasons could exist for wanting to know if a Vista/7 user is an admin, but not running currently as one.

Ok so you probably came here for code and not to listen to my coding issues, so lets get down to it.

Here is the entire class file. It consists of just a few API calls, as well as 3 public functions for you to consume.

IsRunningAsAdmin(): Does the standard check to simply determine if the user is in the administrators group. Will return false for admins running the process with reduced rights in Vista/7.
CanElevateToAdmin(): Uses the Windows API calls to determine if the user can elevate, or is elevated currently.
RunningStandardButCanElevate(): Just a combination of the two above methods, as a shortcut to determine if the user can elevate to admin, but currently is not.

As you can probably tell by the method names, they are all boolean methods.

One thing to note, is that the CanElevateToAdmin method will check the OS version, and only do the API calls when the major version is greater than 5. (5 being Windows XP, 6+ being Vista and up) Otherwise it simply does the standard admin check. 

Sometimes the code formatting may look a little odd, it is just to avoid weird wrapping in the blog post. Wink

 

Imports System.Runtime.InteropServices

 

Class AdminCheck

 

#Region "CONSTANTS"

    Const TOKEN_QUERY As UInt32 = &H8

    Const INT_SIZE As Integer = 4

#End Region

 

#Region "ENUMERATIONS"

 

    Private Enum TOKEN_ELEVATION_TYPE

        TokenElevationTypeDefault = 1

        TokenElevationTypeFull

        TokenElevationTypeLimited

    End Enum

 

    Private Enum TOKEN_INFO_CLASS

        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

        ' MaxTokenInfoClass should always be the last enum

    End Enum

 

#End Region

 

#Region "WIN API FUNCTIONS"

 

    <DllImport("kernel32.dll")> _

    Private Shared Function GetCurrentProcess() As IntPtr

    End Function

 

    <DllImport("advapi32.dll", SetLastError:=True)> _

    Private Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, _

                                            ByVal DesiredAccess As UInt32, _

                                            ByRef TokenHandle As IntPtr) As Boolean

    End Function

 

    <DllImport("advapi32.dll", SetLastError:=True)> _

    Private Shared Function GetTokenInformation( _

                            ByVal TokenHandle As IntPtr, _

                            ByVal TokenInformationClass As TOKEN_INFO_CLASS, _

                            ByVal TokenInformation As IntPtr, _

                            ByVal TokenInformationLength As Integer, _

                            ByRef ReturnLength As UInteger) As Boolean

    End Function

 

#End Region

 

#Region "PUBLIC METHODS"

 

    ''' <summary>

    ''' RETURNS TRUE WHEN THE CURRENT USER IS A MEMBER OF THE

    ''' ADMINISTRATORS GROUP AND IS ALSO RUNNING THE PROCESS

    ''' ELEVATED AS AN ADMINISTRATOR, OTHERWISE RETURNS FALSE.

    ''' </summary>

    ''' <returns>Boolean</returns>

    Public Shared Function IsRunningAsAdmin() As Boolean

 

        Return My.User.IsInRole(ApplicationServices.BuiltInRole.Administrator)

 

    End Function

 

    ''' <summary>

    ''' RETURNS TRUE WHEN THE CURRENT USER CAN ELEVATE TO ADMINISTRATOR RIGHTS

    ''' OR ALREADY HAD ELEVATED TO ADMINISTRATOR RIGHTS,

    ''' OTHERWISE RETURNS FALSE

    ''' </summary>

    ''' <returns>Boolean</returns>

    Public Shared Function CanElevateToAdmin() As Boolean

 

        'DETERMINE IF THE CURRENT USER IS ALREADY RUNNING WITH ADMIN RIGHTS

        Dim IsAdmin = IsRunningAsAdmin()

 

        'EXIT OUT NOW IF THE USER IS AN ADMIN, RETURNING TRUE

        'THERE IS NO ELEVATION NEEDED IF THE USER IS ALREADY

        'RUNNING WITH ADMIN RIGHTS

        If IsAdmin Then Return True

 

        'IF VISTA OR HIGHER, CHECK FOR SPLIT TOKEN

        If Environment.OSVersion.Version.Major > 5 Then

            Try

                Dim myToken As IntPtr

                Dim elevationType As TOKEN_ELEVATION_TYPE

                Dim dwSize As UInteger

                Dim pElevationType As IntPtr = Marshal.AllocHGlobal(INT_SIZE)

 

                'GET A TOKEN REFERENCE FOR THE USER RUNNING THIS PROCESS

                OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, myToken)

 

                'GET THE ELEVATION INFORMATION FOR THIS TOKEN

                GetTokenInformation(myToken, _

                                    TOKEN_INFO_CLASS.TokenElevationType, _

                                    pElevationType, _

                                    INT_SIZE, _

                                    dwSize)

 

                'CAST THE RESULT TO ENUM TYPE

                elevationType = DirectCast( _

                                Marshal.ReadInt32(pElevationType),  _

                                TOKEN_ELEVATION_TYPE)

 

                'FREE ALLOCATED UNMANAGED MEMORY

                Marshal.FreeHGlobal(pElevationType)

 

                'DETERMINE THE RESULT OF THE ELEVATION CHECK

                '==============================================

                'TokenElevationTypeFull - User has a split token,

                'and the process is running elevated

 

                'TokenElevationTypeLimited - User has a split token,

                'but the process is not running elevated

 

                'TokenElevationTypeDefault - User is not using a split token

                '==============================================

                Return (elevationType = _

                        TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited) OrElse _

                       (elevationType = _

                        TOKEN_ELEVATION_TYPE.TokenElevationTypeFull)

 

            Catch ex As Exception

                'LOG/HANDLE ERROR

                'RETURN FALSE IN EVENT OF ERROR

                Return False

            End Try

        Else

            'PRIOR TO VISTA, ONLY CHECK

            'NEEDED IS IF THE USER IS IN THE ADMIN GROUP

            Return IsAdmin

        End If

 

    End Function

 

    ''' <summary>

    ''' RETURNS TRUE WHEN USER IS RUNNING AS A STANDARD USER CURRENTLY

    ''' BUT CAN ELEVATE TO ADMIN RIGHTS WITH THEIR OWN CREDENTIALS

    ''' OTHERWISE RETURNS FALSE

    ''' </summary>

    ''' <returns>Boolean</returns>

    Public Shared Function RunningStandardButCanElevate() As Boolean

        Return CanElevateToAdmin() And (Not IsRunningAsAdmin())

    End Function

 

#End Region

 

End Class

Hopefully this will come in handy for anyone else that may be looking to determine this information. I did a good amount of searching around the web, and wasn't able to find a good example of this, especially in Visual Basic.

Thanks to Rob Teixeira for pointing me to GetTokenInformation API function, which enabled me to ultimately solve this issue.


Posted Jul 29 2009, 08:20 PM by Matthew Kleinwaks
Filed under: , , , ,

Comments

chad boss wrote re: VB.NET How to tell if a user can elevate to admin rights in Vista and Windows 7
on Mon, Sep 14 2009 11:21 AM

hey, great post. just what i need...i think. any way you could post a little code using the above class, just for reference? also, have you tested this in Vista/7 64-bit? just wondering if it works in the 64-bit world.

Matthew Kleinwaks wrote re: VB.NET How to tell if a user can elevate to admin rights in Vista and Windows 7
on Mon, Sep 14 2009 11:58 AM

Chad,

The 3 exposed functions from this class are shared, and all return boolean types, so the usage is simply to call these functions without any instance of the class.

For example, if you had 2 checkboxes on the form, one called chkCanElevate and a chkIsAdmin you could use code like this:

chkCanElevate.Checked = AdminCheck.CanElevateToAdmin

chkIsAdmin.Checked = AdminCheck.IsRunningAsAdmin

As far as supported operating systems, yes this works on both x86 and x64 Windows.



© 2014 - ZerosAndTheOne.com - Hosting by Orcsweb (http://www.orcsweb.com/)
Powered by Community Server (Non-Commercial Edition), by Telligent Systems