0
votes

I have a web application that impersonates using the Win32 API. I recently returned from a trip to find the part of the application that impersonates failing.

The reason for the impersonation is that there is a network share that is used for a specific purpose. When my web application accesses that network share, it must impersonate a special account. For the sake of discussion, the uid is "Bob", the password is "1234", and the domain is "home".

Two weeks ago, I wrote my program to use the Win32 API to impersonate Bob and all was well. Now, the Win32 API indicates logon failure. I'm having trouble figuring out what could have changed. To be specific, the server indicates that it fails to impersonate Bob. The error occurs before the server actually tries to access a network share.

The bizarre thing is that if I connect to my web server with MSTSC, I can click on "Map Network Drive" in the Windows Explorer and access the files using Bob@home and password 1234. (I enter the uid and password by clicking on "Connect using a different user name" in the "Map Network Drive" dialog)

It seems that something different must be happening when I try to access my network share with impersonation versus using the Windows Explorer.

What is that difference?

Update: I feel like the answer to this problem is that there is some sort of logon permission that is being denied that is somehow not involved when I access my files through Windows Explorer.

1
Are you asking what the difference is between accessing the share through impersonation vs. accessing it through windows explorer from your account on your machine? Can you post some code? - James Johnson
I am asking what is the difference between accessing the share through impoersonation vs. accessing it through Windows Explorer with the same account used for impersonation - Vivian River
Have you verified the permissions on the share? I'm assuming that you specified permissions for the folder, but a lot of people forget to apply the permissions to the share. - James Johnson
Yes, the permissions have been verified. I can access the folder from anywhere on the network; I just can't access it through impersonation. - Vivian River
Are you specifying the domain in your calling code? - Josh

1 Answers

2
votes

Make sure that you're using the UNC path to access the folder:

string path = @"\\server\folder";

I don't know what your impersonation class looks like, but here's a class that I use for similar tasks:

/// <summary> 
/// Leverages the Windows API (advapi32.dll) to programmatically impersonate a user. 
/// </summary> 
public class ImpersonationContext : IDisposable 
{ 
    #region constants 

    private const int LOGON32_LOGON_INTERACTIVE = 2; 
    private const int LOGON32_PROVIDER_DEFAULT = 0; 

    #endregion 

    #region global variables 

    private WindowsImpersonationContext impersonationContext; 
    private bool impersonating; 

    #endregion 

    #region unmanaged code 

    [DllImport("advapi32.dll")] 
    private static extern int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern bool RevertToSelf(); 

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

    #endregion 

    #region constructors 

    public ImpersonationContext() 
    { 
        impersonating = false; 
    } 

    /// <summary> 
    /// Overloaded constructor and begins impersonating. 
    /// </summary> 
    public ImpersonationContext(string userName, string password, string domain) 
    { 
        this.BeginImpersonationContext(userName, password, domain); 
    } 

    #endregion 

    #region impersonation methods 

    /// <summary> 
    /// Begins the impersonation context for the specified user. 
    /// </summary> 
    /// <remarks>Don't call this method if you used the overloaded constructor.</remarks> 
    public void BeginImpersonationContext(string userName, string password, string domain) 
    { 
        //initialize token and duplicate variables 
        IntPtr token = IntPtr.Zero; 
        IntPtr tokenDuplicate = IntPtr.Zero; 

        if (RevertToSelf()) 
        { 
            if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) 
            { 
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
                { 
                    using (WindowsIdentity tempWindowsIdentity = new WindowsIdentity(tokenDuplicate)) 
                    { 
                        //begin the impersonation context and mark impersonating true 
                        impersonationContext = tempWindowsIdentity.Impersonate(); 
                        impersonating = true; 
                    } 
                } 
            } 
        } 

        //close the handle to the account token 
        if (token != IntPtr.Zero) 
            CloseHandle(token); 

        //close the handle to the duplicated account token 
        if (tokenDuplicate != IntPtr.Zero) 
            CloseHandle(tokenDuplicate); 
    } 

    /// <summary> 
    /// Ends the current impersonation context. 
    /// </summary> 
    public void EndImpersonationContext() 
    { 
        //if the context exists undo it and dispose of the object 
        if (impersonationContext != null) 
        { 
            //end the impersonation context and dispose of the object 
            impersonationContext.Undo(); 
            impersonationContext.Dispose(); 
        } 

        //mark the impersonation flag false 
        impersonating = false; 
    } 

    #endregion 

    #region properties 

    /// <summary> 
    /// Gets a value indicating whether the impersonation is currently active. 
    /// </summary> 
    public bool Impersonating 
    { 
        get 
        { 
            return impersonating; 
        } 
    } 

    #endregion 

    #region IDisposable implementation 

    ~ImpersonationContext() 
    { 
        Dispose(false); 
    } 

    public void Dispose() 
    { 
        Dispose(true);                
    } 

    protected virtual void Dispose(bool disposing) 
    { 
        if (disposing) 
        { 
            if (impersonationContext != null) 
            { 
                impersonationContext.Undo(); 
                impersonationContext.Dispose(); 
            } 
        } 
    } 

    #endregion     
} 

Using ImpersonationContext:

using (ImpersonationContext context = new ImpersonationContext("user", "password", "domain")) 
{ 
    if (context.Impersonating) 
    { 
        Process.Start(@"/Support/SendFax/SendFax.exe"); 
    } 
}