Recently got a chance to exercise some of the technical muscles us generalists love to preen.
The basic problem: A windows service that writes files to a local directory needs to be able to write files to a directory on a Unix system. Quickly (as in we have a day or two at most to get this to work).
- The windows service runs as LocalSystem which cannot access resources over the network. It has to (as far as I know) run as LocalSystem because it needs interactive desktop access.
- FTP and Samba are not available due to local policy.
But we can’t even SEE uNIX directories
Since the remote host is running some flavor of Unix I expected we’d have to use NFS. Our Windows builds don’t include NFS support.
Fortunately Microsoft gives away a Windows add-on, Windows Services for Unix (SFU), that allows Windows to access NFS exports. After a little setup that is. In a non-NIS environment authentication is handled locally. So the client system (the one mounting the NFS exported directory) needs its own copy of the user name, user id, password and group id of the account it will use to authenticate access to the Unix system.
In the Unix world that would have been the end of the story. You’d pass the info on the command-line when you access the remote directory. Fortunately there’s a wonderful GUI in SFU (PCNFSD) that lets you map Windows accounts to locally defined Unix user IDs. Once mapped NFS mounts can be accessed in the Windows familiar UNC format (\\server\export) or NFS format (server://export).
Now that our Windows machine can “see” the remote directory we’ve got to modify our service so that it can write to it. From my web programming days I remembered that a process can impersonate another user. In a web context this is usually done when the app server process (worker process) needs to do something on behalf of the currently connected user; something the account under which the worker process executes does not have the privs to do.
Since this is a .Net service, platform invoke is necessary to access the LogonUser() and related Win32 APIs. Oddly enough System.Security.Principal has a class that wraps the impersonation API call but does not wrap the functionality necessary to acquire the security token required by impersonation.
But we don’t speak Unix here
We don’t have any systems running unix but fortunately, as described in this previous post, I’ve still got a Virtual PC vhd of RedHat Fedora 11. This will do for testing purposes. It’s painfully slow, since I can’t seem to get Fedora to boot in Virtual PC 2007sp? with hardware virtualization support enabled (heck, I was suprised that my laptop even supports hardware virtualization). I’m sure a VMware appliance would run faster but I didn’t have that on-hand and time was short.
After booting into Fedora I’m pleasantly surprised by all of the things they’ve copied from Windows. I expected to have to play around with /etc/fstab then bounce nfsd manually but all of this configuration can be done via UI these days. After creating a test user, exporting a directory in the test user’s home directory and noting the test user’s user ID and group ID we’re off to plug these into our PCNFSD account mapper and start testing.
But We Can’t Read Maps
Managed/.Net processes can apparently only see drives mapped by the user under which the process is running (maybe this limitation isn’t specific to managed processes?) So using a persistent mapped drive, which SFU doesn’t support anyway, isn’t an option. Fortunately UNC syntax works (albeit slowly the very first access).
Tying it all together
An ls –al provides that feeling of satisfaction as the recently created file shows up in the listing. In pretty colors no less. Woohoo!