Programmatic User Login (aka Win32 LogonUser)

By Michael Flanakin @ 6:04 AM :: 6734 Views :: .NET, Development :: Digg it!

Programmatic user login

Nothing new here. I just wanted to save this code snippet because it's popped up a few times in the past year and I have to go find it over and over. At least this will make it a little easier for me. This is by no means an authoritative reference -- it's simply what I have used. If you know of something I'm missing, please let me know.

First, you'll need to import the Win32 LogonUser() function:

using System.Runtime.InteropServices;

[DllImport("advapi32.dll", SetLastError=true)]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);

The only question you probably have is about the logon type and provider parameters. The only provider I know of is the default, 0, which uses "negotiate" (Kerberos, then NTLM) for Windows XP/Server 2003 and later machines. Windows 2000 defaults to NTLM. If you don't know the difference, let me know and I'll explain that in more detail. Here are a list of logon types:

  • Interactive (2) -- Intended for interactive use (duh) with something like terminal server or executing a remote shell. This type caches credentials for disconnected operations.
  • Network (3) -- Intended for high performance servers to authenticate plain-text passwords.
  • Batch (4) -- Intended for batch servers, which act on behalf of the user without his/her direct intervention. Typically used to process many plain-text auth attempts at a time.
  • Service (5) -- Intended for service accounts, which have the "service" privilege enabled -- don't ask me what that is because I don't know.
  • Unlock (7) -- Intended for GINA DLLs (whatever that is) that will interactively use the machine. This type includes some auditing.
  • Clear Text (8) -- Intended for double-hop impersonation scenarios where credentials will be sent to the target server to allow it to also impersonate the user. As I understand it, this is what IIS "Basic" authentication uses. To perform a double-hop, you'll actually have to do a few other things. I won't get into that here, but let me know if that'd be of interest.
  • New Credentials (9) -- Clones current credentials and uses new credentials for outbound connections. Supposedly, this doesn't work with the default provider -- it requires the WINNT50 provider, whatever that is.

The following is a list of the supported providers. I don't know anything about the non-default ones, but figured I'd list them for completeness..

  • Default (0) -- "Negotiate" (Kerberos, then NTLM) for Windows XP/Server 2003 and later; NTLM for Windows
  • NT 3.5 (1)
  • NT 4.0 (2)
  • NT 5.0 (3) -- Required for the "new credentials" logon type.

Next, well... just use it. As you can see, the last parameter in the LogonUser() function is an out parameter for a token which represents the user. This is key. All you need to do is initialize a WindowsIdentity instance with this token and you're well on your way.

using System.Security.Principal;

/// <summary>
/// Creates a new <see cref="WindowsIdentity"/> using the specified credentials.
/// </summary>
/// <remarks>
/// This method assumes an interactive logon for simplicity.
/// </remarks>

public static WindowsIdentity GetIdentity(string domain, string userName, string password)
    IntPtr token;
    bool success = LogonUser(userName, domain, password, 2, 0, out token);
    return (success) ? new WindowsIdentity(token) : null;

Pretty simple. Of course, we still aren't there, yet. Now that you have the identity, you most likely want to impersonate it. Luckily, this is a simple 2-liner... well, technically two 1-liners. I should also say that, if you want to do impersonation with an already-obtained WindowsIdentity (and you don't have a password), you'll start here.

ImpersonationContext context = GetIdentity("mydomain", "me", "mypassword").Impersonate();
// do work as impersonated user

That's it. Enjoy!