How do I pass credentials to a machine so I can use Microsoft.Win32.RegistryKey.OpenRemoteBaseKey() on it?

JCCyC picture JCCyC · Mar 29, 2010 · Viewed 11.4k times · Source

This .NET API works OK if I'm trying to open the Registry in a machine that's in the same domain as I am (and my logged-on user has admin rights on the target machine).

It gets tricky if it's an out-of-domain machine with a different, local administrative user (of whom I do have the password).

I tried to use WNetUseConnection() (which has served me well in the past in situations where what I wanted was to read a remote disk file) prior to calling OpenRemoteBaseKey(), but no dice -- I get an access denied exception.

Clearly, I must pass credentials some other way, but how?

Answer

Oskar Kjellin picture Oskar Kjellin · Mar 29, 2010

What I've used successfully to access files on a computer is the following code:

    #region imports 
        [DllImport("advapi32.dll", SetLastError = true)] 
        private static extern bool LogonUser(string 
        lpszUsername, string lpszDomain, string lpszPassword, 
        int dwLogonType, int dwLogonProvider, ref 
IntPtr phToken); 


        [DllImport("kernel32.dll", CharSet = CharSet.Auto, 
        SetLastError = true)] 
        private static extern bool CloseHandle(IntPtr handle 
        ); 

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, 
        SetLastError = true)] 
        public extern static bool DuplicateToken(IntPtr 
        existingTokenHandle, 
        int SECURITY_IMPERSONATION_LEVEL, ref IntPtr 
        duplicateTokenHandle); 
        #endregion 
        #region logon consts 
        // logon types 
        const int LOGON32_LOGON_INTERACTIVE = 2; 
        const int LOGON32_LOGON_NETWORK = 3; 
        const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 

        // logon providers 
        const int LOGON32_PROVIDER_DEFAULT = 0; 
        const int LOGON32_PROVIDER_WINNT50 = 3; 
        const int LOGON32_PROVIDER_WINNT40 = 2; 
        const int LOGON32_PROVIDER_WINNT35 = 1; 
        #endregion 

And then for signing in part, just use:

        IntPtr token = IntPtr.Zero; 

        bool isSuccess = LogonUser("username", "domain", "password", 
        LOGON32_LOGON_NEW_CREDENTIALS, 
        LOGON32_PROVIDER_DEFAULT, ref token); 
        using (WindowsImpersonationContext person = new WindowsIdentity(token).Impersonate()) 
        { 
        //do your thing 
         person.Undo(); 
        } 

As you might see, "Undo()" will make that you are no longer signed in as that user. So don't use it before you're done. But don't forget to use it!