Search code examples
c#.netimpersonation

WindowsIdentity Impersonate method fails when impersonating an admin account


I'm trying to impersonate a user account in a .NET console application and when it reaches the point where I call the Impersonate() method, the application seems to exit instantly. The method call is in a try-catch block, but it never even reaches the 'catch' block so I can't see what the error was!

Here's the relevant code:

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

And then at the start of my application:

bool returnValue = LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref m_tokenHandle);
if (!returnValue)
{
    int ret = Marshal.GetLastWin32Error();
    throw new System.ComponentModel.Win32Exception(ret);
}
// Impersonate
WindowsIdentity _identity = new WindowsIdentity(m_tokenHandle);
EmailHelper.SendErrorMessage("Windows Identity Created!", string.Format("Created at: {0}", DateTime.Now.ToLongTimeString()));
try
{
    m_impersonatedUser = _identity.Impersonate();
    EmailHelper.SendErrorMessage("Impersonation Complete...", string.Format("Impersonation at: {0}", DateTime.Now.ToLongTimeString()));
}
catch
{
    int ret = Marshal.GetLastWin32Error();
    EmailHelper.SendErrorMessage("Error impersonating user!", string.Format("Error: {0}", ret));
}
finally
{
    EmailHelper.SendErrorMessage("Finally block executed?!", "What is going on?");
}

I'm getting the initial "Windows identity created" email but not any of the others! Does anyone know how I can find out what my underlying error is and why my impersonation isn't working?

Thanks!

EDIT:

I tried the code from this MSDN article: http://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx with the only modification being trying to create a file when impersonating.

The modification was changing this code:

using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
    // Check the identity.
    Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);
}

To:

using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
    // Check the identity.
    Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);
    System.IO.File.CreateText(@"Test.txt");
}

The output I am getting when running the exe as a "standard" user says that LogonUser succeeded, WindowsIdentity.GetCurrent().Name returns the impersonated user name but creating the file fails with error code 1346, which, according to MSDN, is:

ERROR_BAD_IMPERSONATION_LEVEL 1346 (0x542) Either a required impersonation level was not provided, or the provided impersonation level is invalid.

What does that mean? Google hasn't been able to shed any light on it yet...

EDIT 2:

I can impersonate another standard user account using this code, but when I try to impersonate my admin account it fails. Is it possible to change the code somehow to allow a standard user running this exe to impersonate an admin account?


Solution

  • Sadly this still doesn't seem to work and I have a hunch that trying to impersonate an admin account using WindowsIdentity may not be supported, or my approach is flawed. Either way, rather anticlimactically, I've decided to go for a different approach entirely and put the code I want to run as an admin into a separate executable, and then started that exe as a new process with the admin credentials.

    System.Diagnostics.Process.Start(myExecutablePath, args, adminUsername, adminPassword, domainName);
    

    This works fine, so perhaps anyone encountering this issue might be able to use this workaround as well.