Search code examples
asp.netnetworkingimpersonationmapped-drive

Accessing mapped drives when impersonating in ASP.NET


Short version: Is it possible or not to use impersonation in ASP.NET to access mapped drives?

Long Version:

I'm currently using impersonation in ASP.NET to gain access to network files. This is working perfectly for any network file using a UNC path, but it is failing to access any files on mapped drives defined for the user account I'm impersonating.

For example, let's say a file lives on the network at \\machine\folder\file.txt, and let's also say that drive S: is mapped to \\machine\folder. We need to be able to access both the full UNC path, \\machine\folder\file.txt, as well as the shorter, mapped drive path, S:\file.txt.

Obviously the standard ASP.NET process cannot access either.

Using a console application that runs under the local account with the mapped S: drive, calling File.Exists(@"\\machine\folder\file.txt") returns true, and File.Exists(@"S:\file.txt") also returns true.

However, when impersonating in an ASP.NET context with the same local account, only File.Exists(@"\\machine\folder\file.txt") returns true. File.Exists(@"S:\file.txt") returns false.

I'm testing with IIS 7 running on my local Windows 7 Professional box, though this will need to run in both IIS 6 and IIS 7.

Impersonation is handled with a couple of classes in C# which I'll include here:

public static class Impersonation
{
    private static WindowsImpersonationContext context;

    public static void ImpersonateUser(string username, string password)
    {
        ImpersonateUser(".", username, password);
    }

    public static void ImpersonateUser(string domain, string username, string password)
    {
        StopImpersonating();

        IntPtr userToken;
        var returnValue = ImpersonationImports.LogonUser(username, domain, password,
                                                  ImpersonationImports.LOGON32_LOGON_INTERACTIVE,
                                                  ImpersonationImports.LOGON32_PROVIDER_DEFAULT,
                                                  out userToken);
        context = WindowsIdentity.Impersonate(userToken);
    }

    public static void StopImpersonating()
    {
        if (context != null)
        {
            context.Undo();
            context = null;
        }
    }
}

public static class ImpersonationImports
{
    public const int LOGON32_LOGON_INTERACTIVE = 2;
    public const int LOGON32_LOGON_NETWORK = 3;
    public const int LOGON32_LOGON_BATCH = 4;
    public const int LOGON32_LOGON_SERVICE = 5;
    public const int LOGON32_LOGON_UNLOCK = 7;
    public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
    public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
    public const int LOGON32_PROVIDER_DEFAULT = 0;

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

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern int RevertToSelf();

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern int CloseHandle(IntPtr hObject);
}

Then, during Page_Load, we basically do something like this:

Impersonation.ImpersonateUser("DOMAIN", "username", "password");

if (!File.Exists(@"S:\file.txt"))
     throw new WeCannotContinueException();

I realize using mapped drives isn't a best practice, but for legacy reasons it's desirable for our business. Is it possible or not to use impersonation in ASP.NET to access mapped drives?


Solution

  • No, but you can use a symbolic link instead. Mklink /d will create a directory link.