开发者

Impersonation in .NET in Windows 7 (Requested registry access is not allowed)

So I am using a user to run the following code that is a member of the "User" group on a Windows 7, x64 machine. I am trying to use impersonation (by logging in as a user that is part of the Administrator group) to allow the current user to read from the registry. For some reason the login happens successfully but even though WindowsIdentity.GetCurrent() is returning the user that is part of the Administrator group I am still getting an error message saying "Requested registry access is not allowed". What am I doing wrong?

This is the main code:

            Dim ra As RunAs = Nothing
            If UserDomain.Length > 0 AndAlso UserName.Length > 0 AndAlso UserPassword.Length > 0 Then开发者_运维技巧
                ra = New RunAs
                ra.ImpersonateStart(UserDomain, UserName, UserPassword)
            End If
            If Not My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 0) Is Nothing AndAlso _
            My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 0) = 0 Then
                    My.Computer.Registry.SetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 1)
            End If

And suppose my RunAs class is the following:

Public Class RunAs
 Public Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean

    Public Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal ExistingTokenHandle As IntPtr, _
      ByVal SECURITY_IMPERSONATION_LEVEL As Integer, _
      ByRef DuplicateTokenHandle As IntPtr) As Boolean

    ' Test harness.
    ' If you incorporate this code into a DLL, be sure to demand FullTrust.
    <PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
    Public Sub ImpersonateStart(ByVal Domain As String, ByVal userName As String, ByVal Password As String)
            tokenHandle = IntPtr.Zero
            ' Call LogonUser to obtain a handle to an access token.
            Dim returnValue As Boolean = LogonUser(userName, Domain, Password, 2, 0, tokenHandle)

            'check if logon successful
            If returnValue = False Then
                Dim ret As Integer = Marshal.GetLastWin32Error()
                Console.WriteLine("LogonUser failed with error code : {0}", ret)
                Throw New System.ComponentModel.Win32Exception(ret)
                Exit Sub
            End If

            'Logon succeeded

            ' Use the token handle returned by LogonUser.
            Dim newId As New WindowsIdentity(tokenHandle)
            impersonatedUser = newId.Impersonate()
    End Sub
End Class


I agree with @Hans. With UAC, you need to restart the application with UAC privileges, which will cause the UAC prompt to display. A simple way to accomplish this is as follows:

  1. In normal path of the application, when admin privileges are needed, restart the application with UAC request and a command-line flag, like /admin.
  2. On second run of the application, detect the flag /admin, and do the administrative part of the application.
  3. When the second run finishes (#2), if it was successful, then continue application logic from the first pass. If not successful, display error/perform appropriate exception handling logic.

In our application, I have a helper method called RunElevated that attempts to restart the application with requested administrator privileges, which will cause the UAC prompt to display (I have also included my IsAdmin() helper function):

Private Function RunElevated(commandLine As String, Optional ByVal timeout As Integer = 0) As Boolean
    Dim startInfo As New ProcessStartInfo
    startInfo.UseShellExecute = True
    startInfo.WorkingDirectory = Environment.CurrentDirectory
    Dim uri As New Uri(Assembly.GetEntryAssembly.GetName.CodeBase)
    startInfo.FileName = uri.LocalPath
    startInfo.Verb = "runas"
    startInfo.Arguments = commandLine

    Dim success As Boolean
    Try
        Dim p As Process = Process.Start(startInfo)
        ' wait thirty seconds for completion
        If timeout > 0 Then
            If Not p.WaitForExit(30000) Then
                ' did not complete in thirty seconds, so kill
                p.Kill()
                success = False
            Else
                success = True
            End If
        Else
            p.WaitForExit()
            success = True
        End If
    Catch ex As Win32Exception
        success = False
    Catch ex As Exception
        MsgBox("Error occurred while trying to start application as administrator: " & ex.Message)
        success = False
    End Try
    Return success
End Function

Public Function IsAdmin() As Boolean
    Dim id As WindowsIdentity = WindowsIdentity.GetCurrent
    Dim p As New WindowsPrincipal(id)
    Return p.IsInRole(WindowsBuiltInRole.Administrator)
End Function

To use, I pass a flag and run elevated. In my case, I have a function that sets registry keys, and uses the flag /setregistry to indicate that the instance is started for UAC purposes to just set the registry keys. That code looks something like this:

    Dim success As Boolean
    If Not IsAdmin() Then
        ' try to create the registry keys as administrator
        success = RunElevated("/setregistry", 30000)
        success = success And ValidateKeysSet() ' check if it was successful
        Return success
    End If

    ' If we are Admin (Not IsAdmin() = False), then go ahead and set the keys here

Then in the startup logic (Form_Load, since this is a forms application), I check if that flag is present:

    If Command.ToLower.Contains("/setregistry") Then
        ' if application instance is for sole purpose of setting registry keys as admin
        If IsAdmin() Then
            SetRegistryKeys() ' set the keys, since we are admin
        Else
            MsgBox("ERROR: Application must be run as administrator to set registry keys.")
        End If
    Else
        ' Perform normal startup process
    End If
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜