14

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?

JCCyC
  • 16,140
  • 11
  • 48
  • 75

1 Answers1

39

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!

Oskar Kjellin
  • 21,280
  • 10
  • 54
  • 93
  • Could I keep the "token" variable around a long time, and then use the "using/Undo()" block at various points in tame using the same token?" – JCCyC Mar 29 '10 at 22:19
  • I Think so. It's the Impersonate that actually signs in. What I've used is a "GetImpersonation()" that returns a WindowsImpersonationContext like above – Oskar Kjellin Mar 29 '10 at 22:22
  • But won't person.Undo() render the person variable unusable for a future access? My plan was to call LogonUser(), keep the "token" pointer, and then use various using blocks exactly like yours, each with creation of a new WindowsImpersonationContext object. – JCCyC Mar 29 '10 at 22:46
  • Or maybe I may NOT call Undo() each time, just using(person) { something(); }, then using(person) { something_else(); }, and then when I'm sure I won't need the connection further, person.Undo()? – JCCyC Mar 29 '10 at 22:48
  • Then you will dispose your object each time and not being able to undo it (I think). Perhaps instead just leave a person hanging and don't have "using" but instead call dispose explicitly – Oskar Kjellin Mar 30 '10 at 07:32
  • You have DuplicateToken in your imports but it is never used in your example, what is that for? – Scott Chamberlain Jul 21 '10 at 16:11
  • @Scott It might be for me not cleaning up the code very well :) – Oskar Kjellin Jul 29 '10 at 14:24
  • I have tried with your code i am still not able to access the registry of a remote meachine using openremotebasekey –  Feb 10 '11 at 13:16
  • @hari I think that might be another problem – Oskar Kjellin Feb 14 '11 at 15:13
  • If you check the [.NET source code](https://referencesource.microsoft.com/mscorlib/R/ae6ee4d226c3f126.html), you'll see Dispose calls Undo. So Undo is already called automatically at the end of the using block. – Bloopy Mar 28 '22 at 08:54