none
Acceso denegado en equipo remoto RRS feed

  • Pregunta

  • Buenas tardes amigos.

    Estoy tratando con RegistryKey obtener unos datos de una computadora de mi LAN, cuando ejecuto la siguientes sentencias con un usuario que se que es administrador en el equipo remoto, me los devuelve sin problema, pero cuando lo hago con uno que no lo es me indica el mensaje "Acceso denegado al registro solicitado".

    La pregunta es, hay alguna manera de enviarle en dicha sentencias  el usuario\clave con el cual deseo conectarme?

    Aqui las sentencias que estoy utilizando :

    Imports System
    Imports Microsoft.Win32

    Dim rKey As Microsoft.Win32.RegistryKey
    rKey = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "\\PC26IBM039")

    Dim Keys As RegistryKey = rKey.OpenSubKey("System\CurrentControlSet\Control\ComputerName\ActiveComputerName")
    Dim VendorValue As Object = Keys.GetValue("ComputerName")

    Saludos.

    jueves, 22 de diciembre de 2011 21:01

Respuestas

  • "Edwin Delgado" escribió:

    > La parte (el programa) de autentificación del usuario administrador
    > lo realiza sin problema, pero al tratar de obtener el dato desde la
    > maquina remota parece que continua realizandolo con mi usuario común
    > (que no es administrador en la pc remota).

    ¡Claro! Porque tal y como está el código que te he indicado, lo único que se hace es validar las credenciales del usuario en el PC que está ejecutando el código, pero no lo está suplantando. Discúlpame por el olvido. ¡Mea culpa! :-(

    Modifica el método LogOn por éste otro:

    Imports System.Runtime.InteropServices
    Imports Microsoft.Win32
    Imports System.ComponentModel
    Imports System.Security.Principal

      <DllImport("Kernel32.dll", CharSet:=CharSet.Unicode)> _
        Private Shared Function CloseHandle( _
             ByVal hObject As IntPtr) As Int32
        End Function

        <DllImport("advapi32.dll", CharSet:=CharSet.Unicode)> _
        Private Shared Function LogonUser( _
             ByVal lpszUsername As String, _
             ByVal lpszDomain As String, _
             ByVal lpszPassword As String, _
             ByVal dwLogonType As Int32, _
             ByVal dwLogonProvider As Int32, _
             ByRef phToken As IntPtr) As Boolean
        End Function

        <DllImport("advapi32.dll")> _
        Private Shared Function RevertToSelf() As Int32
        End Function

        Private Sub LogOn(ByVal userName As String, _
                          ByVal userPassword As String, _
                          ByVal adminDomain As String)

            Dim impersonatedUser As WindowsImpersonationContext = Nothing
            Dim hToken As IntPtr = IntPtr.Zero

            If (adminDomain = String.Empty) Then _
                 adminDomain = "." ' Dominio local por defecto

            Try
                Const LOGON32_LOGON_INTERACTIVE As Int32 = 2
                Const LOGON32_PROVIDER_DEFAULT As Int32 = 0

                ' La función buscará al usuario en el dominio por defecto,
                ' según la configuración de la máquina. Si no le encuentra,
                ' comprobará los dominios de la intranet para buscar al
                ' usuario entre ellos.
                '
                ' La función recibe la información de LogOn (Id de Usuario,
                ' contraseña) y devuelve la ficha de seguridad.
                '
                Dim returnValue As Boolean = LogonUser(userName, _
                                                      adminDomain, _
                                                      userPassword, _
                                                      LOGON32_LOGON_INTERACTIVE, _
                                                      LOGON32_PROVIDER_DEFAULT, _
                                                      hToken)
                If (Not (returnValue)) Then
                    Dim ret As Int32 = Marshal.GetLastWin32Error()
                    Throw New Win32Exception(ret, "Las credenciales del usuario especificadas no son válidas.")
                End If

                ' Las credenciales del usuario son correctas. Su ficha estará
                ' en el campo 'm_hToken'.
                ' 
                ' Utilizamos el manipulador devuelto por la función LogonUer
                ' para suplantar el usuario actual.
                '
                impersonatedUser = WindowsIdentity.Impersonate(hToken)

                ' Llegado a éste punto, se comprende que las credenciales
                ' del usuario son correctas. Procedemos a leer el valor
                ' de la clave del registro de Windows.
                '
                Dim rKey As RegistryKey = _
                    RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "\\PC26IBM039")

                Dim Keys As RegistryKey = rKey.OpenSubKey( _
                    "System\CurrentControlSet\Control\ComputerName\ActiveComputerName")

                Dim VendorValue As Object = Keys.GetValue("ComputerName")

                Keys.Close()
                rKey.Close()

            Catch ex As Exception
                ' Login inválido; devolvemos la excepción.
                '
                Throw

            Finally
                If (impersonatedUser IsNot Nothing) Then
                    ' Terminamos la suplantación del usuario. El método
                    ' Undo se encarga de llamar a la función API
                    ' RevertToSelf
                    '
                    impersonatedUser.Undo()
                    impersonatedUser.Dispose()
                    impersonatedUser = Nothing
                End If

                If (Not (IntPtr.op_Equality(hToken, IntPtr.Zero))) Then
                    ' Cerramos el manipulador.
                    '
                    CloseHandle(hToken)
                End If

               
            End Try

        End Sub

    Cuando desees ejecutar el procedimiento «LogOn», lo llamarías de la siguiente manera:
     
        Try
           LogOn("Administrador", "contraseña_Administrador", "nombre_dominio")
     
        Catch ex As Exception
           MessageBox.Show(ex.Message)
     
        End Try

    Pero vuelvo a insistir que el servicio de Registro Remoto tiene que estar iniciado en el PC remoto, y por supuesto, las credenciales de la cuenta administrativa que le pases, tendrá que tener la misma contraseña, tanto en el PC que ejecuta el código como en el PC remoto.

    Espero que ahora puedas conectarte al registro remoto, y disculpa mi olvido por no indicarte en mi primera respuesta la utilización de un objeto 'WindowsImpersonationContext' para suplantar al usuario actual.

     


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.



    miércoles, 28 de diciembre de 2011 19:05
    Moderador

Todas las respuestas

  • "Edwin Delgado" preguntó:

    > Estoy tratando con RegistryKey obtener unos datos de una
    > computadora de mi LAN, cuando ejecuto la siguientes
    > sentencias con un usuario que se que es administrador en
    > el equipo remoto, me los devuelve sin problema, pero cuando
    > lo hago con uno que no lo es me indica el mensaje
    > "Acceso denegado al registro solicitado".
    >
    > La pregunta es, hay alguna manera de enviarle en dicha
    > sentencias el usuario\clave con el cual deseo conectarme?

    Sí, suplantando la identidad de un usuario que pertenezca al grupo de Administradores.

    Esta es una respuesta que hace ya tiempo respondí en el grupo de noticias en español de Visual Basic .net:

    https://groups.google.com/group/microsoft.public.es.dotnet.vb/browse_thread/thread/72a307fbc32a7c4e/e0b6ce7d4a6686db

    No obstante, la vuelvo a repetir para que quede constancia de ella en éste foro:

    Si deseas saber si el usuario es quién dice ser, puedes recurrir a la función API «LogonUser».

    A continuación expongo el código fuente traducido a Visual Basic .net, del ejemplo que aparece en el siguiente artículo de la Base del Conocimiento (en inglés), al que te remito para su lectura:

    How to impersonate a user from Active Server Pages

    Imports System.Runtime.InteropServices
    Imports Microsoft.Win32

       <DllImport("Kernel32.dll", CharSet:=CharSet.Unicode)> _
        Private Shared Function CloseHandle( _
            ByVal hObject As IntPtr) As Int32
        End Function

        <DllImport("advapi32.dll", CharSet:=CharSet.Unicode)> _
        Private Shared Function LogonUser( _
            ByVal lpszUsername As String, _
            ByVal lpszDomain As String, _
            ByVal lpszPassword As String, _
            ByVal dwLogonType As Int32, _
            ByVal dwLogonProvider As Int32, _
            ByRef phToken As IntPtr) As Int32
        End Function

        <DllImport("advapi32.dll")> _
        Private Shared Function RevertToSelf() As Int32
        End Function

        Private Sub LogOn(ByVal userName As String, _
                          ByVal userPassword As String, _
                          ByVal adminDomain As String)

            Dim hToken As IntPtr

            If (adminDomain = String.Empty) Then _
                adminDomain = "." ' Dominio local por defecto

            Try
                Const LOGON32_LOGON_INTERACTIVE As Int32 = 2
                Const LOGON32_PROVIDER_DEFAULT As Int32 = 0

                ' La función buscará al usuario en el dominio por defecto,
                ' según la configuración de la máquina. Si no le encuentra,
                ' comprobará los dominios de la intranet para buscar al
                ' usuario entre ellos.
                '
                ' La función recibe la información de LogOn (Id de Usuario,
                ' contraseña) y devuelve la ficha de seguridad.
                '
                Dim returnValue As Int32 = LogonUser(userName, _
                                                     adminDomain, _
                                                     userPassword, _
                                                     LOGON32_LOGON_INTERACTIVE, _
                                                     LOGON32_PROVIDER_DEFAULT, _
                                                     hToken)
                If (returnValue = 0) Then
                    ' Las credenciales del usuario especificadas
                    ' puede que no sean correctas. Abandonamos
                    ' el procedimiento.
                    '
                    Return
                End If

                ' Llegado a éste punto, se comprende que las credenciales
                ' del usuario son correctas. Procedemos a leer el valor
                ' de la clave del registro de Windows.
                '
                Dim rKey As RegistryKey = _
                    RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "PC26IBM039")

                Dim Keys As RegistryKey = rKey.OpenSubKey( _
                   "System\CurrentControlSet\Control\ComputerName\ActiveComputerName")

                Dim VendorValue As Object = Keys.GetValue("ComputerName")

            Catch ex As Exception
                ' Login inválido; devolvemos la excepción.
                '
                Throw

            Finally
                ' Cerramos el manipulador.
                '
                CloseHandle(hToken)

                ' Terminamos la suplantación.
                '
                Dim bln As Int32 = RevertToSelf()

                If (bln = 0) Then
                    ' El proceso no se ha podido revertir. En éste
                    ' caso, se aconseja finalizar la aplicación.
                    '
                    MessageBox.Show("Se aconseja finalizar la aplicación.")
                End If

            End Try

        End Sub

    Cuando desees ejecutar el procedimiento «LogOn», lo llamarías de la siguiente manera:

        Try
          LogOn("Administrador", "contraseña_Administrador", "nombre_dominio")

        Catch ex As Exception
          MessageBox.Show(ex.Message)

        End Try

    Si no existe un dominio, el tercer parámetro lo puedes sustituir por una cadena de longitud cero (String.Empty).

    Adapta el ejemplo a tus necesidades, pero recuerda siempre llamar a la función API 'RevertToSelf' para revertir la suplantación del usuario efectuada.

    Un saludo y ¡Feliz Año Nuevo!

     


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.



    lunes, 26 de diciembre de 2011 18:38
    Moderador
  • Muchas gracias SoftJaen por la respuesta, voy a tratar de hacerla y ver como me va.

     

    Saludos y Feliz Año.

     

    martes, 27 de diciembre de 2011 1:16
  • :-( pues no, igual me continua saliendo el mensaje "Acceso denegado al registro solicitado".

    La parte (el programa) de autentificación del usuario administrador lo realiza sin problema, pero al tratar de obtener el dato desde la maquina remota parece que continua realizandolo con mi usuario común (que no es administrador en la pc remota).

    Estoy viendo que en XP para obtener el dato "DefaultUserName" de la maquina remota no tengo problemas, es decir, no se necesita ser usuario administrador para leer ese dato del regedit :

       Dim rKey As Microsoft.Win32.RegistryKey
       rKey = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "\\PC26LN010")


       Dim RegKey As RegistryKey = rKey.OpenSubKey("Software\Microsoft\Windows NT\CurrentVersion\Winlogon")

       Dim VendorValue As Object = RegKey.GetValue("DefaultUserName")

    Pero para obtenerlo desde un Windows 7 tampoco se puede, pues vuelve a salir el mensaje de "Acceso denegado..."

       Dim rKey As Microsoft.Win32.RegistryKey
       rKey = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "\\PC26LN090")

       Dim RegKey As RegistryKey = rKey.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI")
       Dim VendorValue As Object = RegKey.GetValue("LastLoggedOnUser")

    Es decir, de todas maneras necesito poder logearme (desde mi programa) con un usuario administrador de Windows, pero q este sea reconocido también en la pc remota de la cual voy a obtener datos.

     

    martes, 27 de diciembre de 2011 17:17
  • "Edwin Delgado" escribió:

    > pues no, igual me continua saliendo el mensaje "Acceso denegado al registro solicitado".

    Pero ese equipo al que te deseas conectar, ¿tiene iniciado el servicio de Registro Remoto?

    Si no lo tiene iniciado me parece a mí que va a ser complicado que puedas leer algún valor del registro de ese PC remoto. ;-)

    Me ha dado por probar el código que te indiqué anteriormente para leer el registro de Windows del equipo de mi hijo, y no he tenido ningún tipo de problema. Los dos equipos tienen instalado Windows 7, y el de mi hijo, he tenido que iniciar el servicio comentado, porque por defecto hay que iniciarlo manualmente en lugar de que se inicie automáticamente al iniciar el sistema operativo.

    Aparte del código que te indiqué para suplantar al usuario, intenta ejecutar el código tal y como aparece en el ejemplo del siguiente tema de la ayuda de Visual Studio:

    RegistryKey.OpenRemoteBaseKey (Método) (RegistryHive, String)

     


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.

    miércoles, 28 de diciembre de 2011 12:04
    Moderador
  • "Edwin Delgado" escribió:

    > La parte (el programa) de autentificación del usuario administrador
    > lo realiza sin problema, pero al tratar de obtener el dato desde la
    > maquina remota parece que continua realizandolo con mi usuario común
    > (que no es administrador en la pc remota).

    ¡Claro! Porque tal y como está el código que te he indicado, lo único que se hace es validar las credenciales del usuario en el PC que está ejecutando el código, pero no lo está suplantando. Discúlpame por el olvido. ¡Mea culpa! :-(

    Modifica el método LogOn por éste otro:

    Imports System.Runtime.InteropServices
    Imports Microsoft.Win32
    Imports System.ComponentModel
    Imports System.Security.Principal

      <DllImport("Kernel32.dll", CharSet:=CharSet.Unicode)> _
        Private Shared Function CloseHandle( _
             ByVal hObject As IntPtr) As Int32
        End Function

        <DllImport("advapi32.dll", CharSet:=CharSet.Unicode)> _
        Private Shared Function LogonUser( _
             ByVal lpszUsername As String, _
             ByVal lpszDomain As String, _
             ByVal lpszPassword As String, _
             ByVal dwLogonType As Int32, _
             ByVal dwLogonProvider As Int32, _
             ByRef phToken As IntPtr) As Boolean
        End Function

        <DllImport("advapi32.dll")> _
        Private Shared Function RevertToSelf() As Int32
        End Function

        Private Sub LogOn(ByVal userName As String, _
                          ByVal userPassword As String, _
                          ByVal adminDomain As String)

            Dim impersonatedUser As WindowsImpersonationContext = Nothing
            Dim hToken As IntPtr = IntPtr.Zero

            If (adminDomain = String.Empty) Then _
                 adminDomain = "." ' Dominio local por defecto

            Try
                Const LOGON32_LOGON_INTERACTIVE As Int32 = 2
                Const LOGON32_PROVIDER_DEFAULT As Int32 = 0

                ' La función buscará al usuario en el dominio por defecto,
                ' según la configuración de la máquina. Si no le encuentra,
                ' comprobará los dominios de la intranet para buscar al
                ' usuario entre ellos.
                '
                ' La función recibe la información de LogOn (Id de Usuario,
                ' contraseña) y devuelve la ficha de seguridad.
                '
                Dim returnValue As Boolean = LogonUser(userName, _
                                                      adminDomain, _
                                                      userPassword, _
                                                      LOGON32_LOGON_INTERACTIVE, _
                                                      LOGON32_PROVIDER_DEFAULT, _
                                                      hToken)
                If (Not (returnValue)) Then
                    Dim ret As Int32 = Marshal.GetLastWin32Error()
                    Throw New Win32Exception(ret, "Las credenciales del usuario especificadas no son válidas.")
                End If

                ' Las credenciales del usuario son correctas. Su ficha estará
                ' en el campo 'm_hToken'.
                ' 
                ' Utilizamos el manipulador devuelto por la función LogonUer
                ' para suplantar el usuario actual.
                '
                impersonatedUser = WindowsIdentity.Impersonate(hToken)

                ' Llegado a éste punto, se comprende que las credenciales
                ' del usuario son correctas. Procedemos a leer el valor
                ' de la clave del registro de Windows.
                '
                Dim rKey As RegistryKey = _
                    RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "\\PC26IBM039")

                Dim Keys As RegistryKey = rKey.OpenSubKey( _
                    "System\CurrentControlSet\Control\ComputerName\ActiveComputerName")

                Dim VendorValue As Object = Keys.GetValue("ComputerName")

                Keys.Close()
                rKey.Close()

            Catch ex As Exception
                ' Login inválido; devolvemos la excepción.
                '
                Throw

            Finally
                If (impersonatedUser IsNot Nothing) Then
                    ' Terminamos la suplantación del usuario. El método
                    ' Undo se encarga de llamar a la función API
                    ' RevertToSelf
                    '
                    impersonatedUser.Undo()
                    impersonatedUser.Dispose()
                    impersonatedUser = Nothing
                End If

                If (Not (IntPtr.op_Equality(hToken, IntPtr.Zero))) Then
                    ' Cerramos el manipulador.
                    '
                    CloseHandle(hToken)
                End If

               
            End Try

        End Sub

    Cuando desees ejecutar el procedimiento «LogOn», lo llamarías de la siguiente manera:
     
        Try
           LogOn("Administrador", "contraseña_Administrador", "nombre_dominio")
     
        Catch ex As Exception
           MessageBox.Show(ex.Message)
     
        End Try

    Pero vuelvo a insistir que el servicio de Registro Remoto tiene que estar iniciado en el PC remoto, y por supuesto, las credenciales de la cuenta administrativa que le pases, tendrá que tener la misma contraseña, tanto en el PC que ejecuta el código como en el PC remoto.

    Espero que ahora puedas conectarte al registro remoto, y disculpa mi olvido por no indicarte en mi primera respuesta la utilización de un objeto 'WindowsImpersonationContext' para suplantar al usuario actual.

     


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.



    miércoles, 28 de diciembre de 2011 19:05
    Moderador
  • Bien!!!
    Mi estimado SoftJaén es usted un maestro, ahora si funciona; me parecia que por ahi estaba el problem, por que cuando ejecutaba la siguiente sentencia (luego de realizar los pasos de su primer post) me continuaba mostrando mi usuario actual, no el administrador.

    Dim Usuario As String = Environment.UserName

    Realizando los cambios de la segunda entrega ya funciona bien y puedo leer el regedit tanto de XP como de Win7; solo hay una parte que he dejado del primer post, es la siguiente:

    If (returnValue = 0) Then
                    Dim ret As Int32 = Marshal.GetLastWin32Error()
                    Throw New Win32Exception(ret, "Las credenciales del usuario especificadas no son válidas.")
    End If

    Muchisimas gracias, ahora si voy a adecuarlo a mi necesidad.

    Nuevamente feliz año.
    Supongo que usted es de Jaén de España? pues yo soy de una ciudad del interior de Perú también llamada asi :-)

    Saludos.

    • Marcado como respuesta Edwin Delgado miércoles, 28 de diciembre de 2011 20:35
    • Desmarcado como respuesta Edwin Delgado miércoles, 28 de diciembre de 2011 20:36
    miércoles, 28 de diciembre de 2011 19:59
  • > Supongo que usted es de Jaén de España? pues yo soy de una
    > ciudad del interior de Perú también llamada asi :-)

    ¡Así es! Podemos decir que somos paisanos pero de diferentes países. :-)

    Recuerda marcar como satisfactoria la respuesta si te ha sido útil, de ésta manera damos por cerrada ésta conversación.

     


    Enrique Martínez
      [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, activa la instrucción Option Strict.

    miércoles, 28 de diciembre de 2011 20:06
    Moderador