Thursday, April 9, 2009

C#: Create WindowsIdentity From UserID and Password

Important: The code must be compiled with /unsafe flag

using System.Security;
using System.Security.Principal;
using System.Security.Permissions;
using System.Runtime.InteropServices;
...

WindowsIdentity LogonUserAndGetWindowsIdentify(string userId, string password, string domainId)
{
IntPtr tokenHandle = new IntPtr(0);
IntPtr dupeTokenHandle = new IntPtr(0);

tokenHandle = IntPtr.Zero;
dupeTokenHandle = IntPtr.Zero;

bool rcBool = LogonUser(userId, domainId, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);
if (!rcBool)
throw new Exception("Error while trying to log user on");

rcBool = DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle);
if (!rcBool)
throw new Exception("Error while trying to duplicate token");

WindowsIdentity newId = new WindowsIdentity(dupeTokenHandle);

CloseHandle(tokenHandle);
CloseHandle(dupeTokenHandle);

return newId;
}

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

[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int dwFlags, ref IntPtr lpSource, int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr* Arguments);

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

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

public unsafe static string GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;

int messageSize = 255;
String lpMsgBuf = "";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;

IntPtr ptrlpSource = IntPtr.Zero;
IntPtr prtArguments = IntPtr.Zero;

int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0, ref lpMsgBuf, messageSize, &prtArguments);
if (0 == retVal)
{
throw new Exception("Failed to format message for error code " + errorCode + ". ");
}

return lpMsgBuf;
}

2 comments:

  1. You are missing:

    const int LOGON32_PROVIDER_DEFAULT = 0;
    //This parameter causes LogonUser to create a primary token.
    const int LOGON32_LOGON_INTERACTIVE = 2;
    const int SecurityImpersonation = 2;

    ReplyDelete
  2. good stuff. but is your code working in 64bit machine??

    ReplyDelete

Please use your common sense before making a comment, and I truly appreciate your constructive criticisms.