views:

71

answers:

6

When I use:

File.Copy(strRemoteFolder, strLocalFolder)

I get an UnauthorizedAccessException with the following message: "Access to the path ... is denied."

In .NET, how do I copy a file from a remote computer that requires authentication to my local machine? I understand that I'm going to need to supply a username and password in some fashion, but I don't know how to supply that information via an API in .NET.

A: 

adjust the sharing privileges on the target system to allow access.

Randy
I specifically need a solution in .NET. The target machine is on a different domain and we're unable to supply credentials across differing domains.
Ben McCormack
that does not invalidate the answer. otherwise you could just write a program and get any protected data from any other machine. not likely to happen.
Randy
A: 

You will not be able to copy files from a protected server without authenticating yourself.

Rajorshi
A: 

You can use LogonUser() contained within the advapi32.dll. I haven't used it personally, but it seems straight forward enough.

[DllImport("ADVAPI32.DLL")] 
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, 
int dwLogonType, int dwLogonProvider, out int phToken);

http://www.codeproject.com/KB/cs/cpimpersonation1.aspx
http://www.pinvoke.net/default.aspx/advapi32.logonuser

senloe
+1  A: 

You can use the unmanaged LogonUser function to get an account token for a session on the remote machine, and then call WindowsIdentity.Impersonate to use that session. The MSDN page on WindowsIdentity.Impersonate describes how to make the p/invoke call to LogonUser.

You probably won't be able to use File.Copy since you won't have access to the local machine, but you can call File.OpenRead to open the remote file and then revert your token. Something like this:

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

public static Stream OpenFileWithAccount(string filename, string username, string domain, string password)
{
    IntPtr token;
    if (!LogonUser(username, domain, password, 2, 0, out token))
    {
        throw new Win32Exception();
    }
    try
    {
        using (WindowsIdentity.Impersonate(token))
        {
            return File.OpenRead(filename);
        }
    }
    finally
    {
        CloseHandle(token);
    }
}
Quartermeister
Perhaps you got the arguments to the method call in the wrong order? ->(username, domain, password ....) as in the declaration
MaLio
@MaLio: You're right, I did. Thanks for the catch!
Quartermeister
A: 

The suggestions to use LogonUser to login on the remote computer is definitively wrong. You should use WNetAddConnection2 or NetUseAdd with parameter level 2 (USE_INFO_2) native API to make remote login.

Oleg
A: 

Since you have control over both machines, you can create a local user on both machines with matching passwords, then run the program as that user.

Or you can just create the user on the remote machine and map a drive to that computer using the username/password of that user. You would specify the user as RemoteServer\NewUser. So you the parameters to net use as referenced here would be use s: \\remoteserver\share /USER:RemoteServer\NewUser password. Then call net again but pass use s: /delete to clean up...

(The assumption here is that you've properly configured the user to have access to the specific share/folder in question.)

Tim Coker