We've run into an interesting situation that needs solving, and my searches have turned up nill. I therefore appeal to the SO community for help.
The issue is this: we have a need to programmatically access a shared file that is not in our domain, and is not within a trusted external domain via remote file sharing / UNC. Naturally, we need to supply credentials to the remote machine.
Typically, one solves this problem in one of two ways:
- Map the file share as a drive and supply the credentials at that time. This is typically done using the
NET USE
command or the Win32 functions that duplicateNET USE
. - Access the file with a UNC path as if the remote computer were on the domain and ensure that the account under which the program runs is duplicated (including password) on the remote machine as a local user. Basically leverage the fact that Windows will automatically supply the current user's credentials when the user attempts to access a shared file.
- Don't use remote file sharing. Use FTP (or some other means) to transfer the file, work on it locally, then transfer it back.
For various and sundry reasons, our security / network architects have rejected the first two approaches. The second approach is obviously a security hole; if the remote computer is compromised, the local computer is now at risk. The first approach is unsatisfactory because the newly mounted drive is a shared resource available to other programs on the local computer during file access by the program. Even though it's quite possible to make this temporary, it's still a hole in their opinion.
They're open to the third option, but the remote network admins insist on SFTP rather than FTPS, and FtpWebRequest only supports FTPS. SFTP is the more firewall-friendly option and there are a couple libraries I could use for that approach, but I'd prefer to reduce my dependencies if I can.
I've searched MSDN for either a managed or a win32 means of using remote file sharing, but I have failed to come up with anything useful.
And so I ask: Is there another way? Did I miss a super-secret win32 function that does what I want? Or must I pursue some variant of option 3?
Rather than WNetUseConnection, I would recommend NetUseAdd. WNetUseConnection is a legacy function that's been superceded by WNetUseConnection2 and WNetUseConnection3, but all of those functions create a network device that's visible in Windows Explorer. NetUseAdd is the equivalent of calling net use in a DOS prompt to authenticate on a remote computer.
If you call NetUseAdd then subsequent attempts to access the directory should succeed.
I've seen option 3 implemented with JScape tools in a pretty straightforward fashion. You might give it a try. It's not free, but it does its job.
While I don't know myself, I would certainly hope that #2 is incorrect...I'd like to think that Windows isn't going to AUTOMATICALLY give out my login information (least of all my password!) to any machine, let alone one that isn't part of my trust.
Regardless, have you explored the impersonation architecture? Your code is going to look similar to this:
In this case, the
token
variable is an IntPtr. In order to get a value for this variable, you'll have to call the unmanaged LogonUser Windows API function. A quick trip to pinvoke.net gives us the following signature:Username, domain, and password should seem fairly obvious. Have a look at the various values that can be passed to dwLogonType and dwLogonProvider to determine the one that best suits your needs.
This code hasn't been tested, as I don't have a second domain here where I can verify, but this should hopefully put you on the right track.
For people looking for a quick solution, you can use the
NetworkShareAccesser
I wrote recently (based on this answer (thanks so much!)):Usage:
WARNING: Please make absolutely sure, that
Dispose
of theNetworkShareAccesser
is called (even if you app crashes!), otherwise an open connection will remain on Windows. You can see all open connections by opening thecmd
prompt and enternet use
.The Code:
Most SFTP servers support SCP as well which can be a lot easier to find libraries for. You could even just call an existing client from your code like pscp included with PuTTY.
If the type of file you're working with is something simple like a text or XML file, you could even go so far as to write your own client/server implementation to manipulate the file using something like .NET Remoting or web services.
Here a minimal POC class w/ all the cruft removed
You can directly use
\\server\share\folder
w/WNetUseConnection
, no need to strip it to\\server
part only beforehand.