Pregunta

Solución (algo):

Resulta que esta suplantación con la seguridad de .NET solo permite el acceso a nivel de aplicación. Dado que el objeto COM está en el nivel del sistema, el usuario suplantado todavía no puede instanciarlo. Descubrí esto haciendo clic derecho en el ejecutable y seleccionando "Ejecutar como ...", el programa funcionó bien. Descubrí que inicia el programa con acceso al sistema (asumiendo que el usuario con el que lo está ejecutando tiene esas credenciales). Ahora estoy en el proceso de crear un programa externo que lanzará esta aplicación usando este método.

Gracias por los consejos: D


Tengo una instalación de Windows XP en una máquina virtual. Es parte de mi dominio, pero el usuario que ha iniciado sesión es solo un usuario local. Obviamente, si intento acceder a un recurso compartido de red, solicitará un usuario / contraseña:

 texto alternativo

El programa que estoy probando en la máquina virtual utiliza un objeto COM para interactuar con los datos de otro programa. Si no me hago pasar por la suplantación, obtengo errores porque no tengo las credenciales adecuadas.

Hice una investigación sobre el tema y encontré una serie de sitios web que tenían una cantidad decente de información de VB.NET. El problema que tengo con el código que escribí es que puedo acceder a los recursos de la red, pero no puedo crear una instancia del objeto COM.

Si lleno y envío la solicitud de credenciales (arriba) antes de intentar crear una instancia, funciona bien. Eso me lleva a creer que debe haber algo que esté haciendo la solicitud de credenciales de WinXP y que yo no. A continuación se muestra el código que estoy utilizando para la suplantación:

Public Sub BeginImpersonation()
    Const LOGON32_PROVIDER_DEFAULT As Integer = 0
    Const LOGON32_LOGON_INTERACTIVE As Integer = 2
    Const SecurityImpersonation As Integer = 2

    Dim win32ErrorNumber As Integer

    _tokenHandle = IntPtr.Zero
    _dupeTokenHandle = IntPtr.Zero

    If Not LogonUser(_username, _domainname, _password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, _tokenHandle) Then
        win32ErrorNumber = System.Runtime.InteropServices.Marshal.GetLastWin32Error()
        Throw New ImpersonationException(win32ErrorNumber, GetErrorMessage(win32ErrorNumber), _username, _domainname)
    End If

    If Not DuplicateToken(_tokenHandle, SecurityImpersonation, _dupeTokenHandle) Then
        win32ErrorNumber = System.Runtime.InteropServices.Marshal.GetLastWin32Error()

        CloseHandle(_tokenHandle)
        Throw New ImpersonationException(win32ErrorNumber, "Unable to duplicate token!", _username, _domainname)
    End If

    Dim newId As New System.Security.Principal.WindowsIdentity(_dupeTokenHandle)
    _impersonatedUser = newId.Impersonate()
    _impersonating = True
End Sub

También he intentado enviar diferentes indicadores al método del imitador, pero nada parece estar funcionando. Aquí están las diferentes banderas que encontré:

Enum LOGON32_LOGON
    INTERACTIVE = 2
    NETWORK = 3
    BATCH = 4
    SERVICE = 5
    UNLOCK = 7
    NETWORK_CLEARTEXT = 8
    NEW_CREDENTIALS = 9
End Enum
Enum LOGON32_PROVIDER
    [DEFAULT] = 0
    WINNT35 = 1
    WINNT40 = 2
    WINNT50 = 3
End Enum
Enum SECURITY_LEVEL
    Anonymous = 0
    Identification = 1
    Impersonation = 2
    Delegation = 3
End Enum
¿Fue útil?

Solución

Me he topado con esto antes y he usado dos soluciones diferentes. Lo más fácil fue usar una aplicación de terceros: TqcRunas: http://www.quimeras.com/Products/products.asp que le permite empaquetar las credenciales necesarias en un archivo cifrado. Sin embargo, es un dolor si la contraseña se ve obligada a caducar.

La otra solución que he usado es llamar a un nuevo proceso con credenciales alternativas:

        Dim myProcessStartInfo As ProcessStartInfo = New ProcessStartInfo

    With myProcessStartInfo

        .FileName = "file path and name"

        .Domain = "domainname"
        .UserName = "username"

        'password needs to be a SerureString
        Using NewPassword As New Security.SecureString
            With NewPassword
                For Each c As Char In "password".ToCharArray
                    .AppendChar(c)
                Next c
                .MakeReadOnly()
            End With
            .Password = NewPassword.Copy
        End Using

        'UseShellExecute must be false for impersonated process
        .UseShellExecute = False

    End With

    Using Process As New System.Diagnostics.Process
        With Process
            .StartInfo = myProcessStartInfo
            .Start()
        End With
    End Using

Otros consejos

Con tus definiciones, yo uso

LogonUser(_username, _domainname, _password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, _tokenHandle)

en mi código que se autentica a través de la red. Me estoy haciendo pasar por un usuario local en el cuadro remoto, como tú. Sin embargo, hace tanto tiempo que no recuerdo la razón para usar estos valores.

Hago algo similar para asignar unidades de red para copiar archivos entre máquinas. No escribí el código, pero es casi lo mismo que el tuyo, excepto por dos cosas:

  • Después de que el método Impersonate vuelva, cierro ambos tokens utilizando la rutina CloseHandle, antes de salir de mi método de imitador.

  • En la parte superior del imitador, lo primero que sucede es una llamada a RevertToSelf, probablemente para cancelar cualquier suplantación anterior.

No sé si harían una diferencia, pero vale la pena intentarlo. Aquí están las declaraciones relevantes:

Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long
Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top