Question regarding filter driver attach to \Device\Mup

Just wondering if anyone might know if something we’re trying to do is going to even be possible with a fs filter driver. Sorry this post is so long but I couldn’t seem to explain the problem adequately otherwise.

Some background… I currently have a filter driver that runs on a server (2003 or 2008), that primarily is concerned with giving an altered file/dir view to remote users that map a drive to a share on the server.

For example: On the server I have 2 local drives C: and E:. I share the contents of C:\Shared out to clients as a share named “Shared”.

Now I also have a folder on drive E (E:\Background). This folder is not shared but what I want to do is make it so when the client maps to “Shared” it sees not only the contents of C:\Shared but also sees contents of E:\Background merged into the view.

So suppose contents of C:\Shared include file1.txt, and E:\Background contains file file2.txt. So we make it local users of the server see the expected view of C:\Shared, however users that access C:\Shared remotely through the mapped drive (i.e. \Server\Shared) will actually see both file1.txt and file2.txt as if they both existed in the same folder on C:.

So what I’ve described so far is what we currently have working. We attach our filter to C: and E:, pass down the folders paths we are interested in (C:\Shared and E:\Background), and the filter creates the merged view and also redirects I/O as appropriate to E: so everything appears to the remote user as a single storage location.

But what we are wanting to do now is to allow the “background” storage location (E:\Background in this case), to now be able to be to a non-local drive such as a remote NAS device or other server that uses CIFS to share out storage.

We do already support remote access but only with iSCSI, since in this block-level case the remote drive appears to be local (i.e. F:). But we want to be able to do this at the file protocol level using a UNC path to access the remote “background” location (i.e. \RemoteServer\SharedVol).

We’ve tried attaching to \Device\Mup (2008) or \Device\LanmanRedirector (2003) and can actually get it to work but only when we map the drive locally on the server where the share is defined (i.e. the server with C: locally connected).

In the working case if I look at a CIFS/SMB Lan trace as well as filter driver debug output, I can see that when the user maps a drive to C:\Shared, we see a IRP_MJ_CREATE to open C:\Shared and at this point we also do our own CREATE to \RemoteServer\SharedVol. We save the returned handle so we can later merge in the contents of the remote share with C:\Shared when we get the IRP_MJ_DIRECTORY_CONTROL request.

In the working case we also see at this point a CIFS connection is made to RemoteServer using the SAME client credentials that was used originally when the mapping was made to the “Shared” share that points to C:\Shared.

But now if we try to do this in the normal case where the client mapping the drive is server hosting C:\Shared share is on a remote client it doesn’t work.

The reason it doesn’t work is because when the filter sees the IRP_CREATE to C:\Primary and attempts to mirror that CREATE over to \RemoteServer\SharedVol, we receive an ACCESS_DENIED error and can’t progress further.

In the LAN trace of the failing case I see that when the CIFS connection is made to \RemoteServer we aren’t using the client username/credentials but are making a NULL user connection instead (i.e. Username in SessionSetup CIFS request is EMPTY/NULL). Since NULL users normally (and rightfully so) have no rights to anything, we see the ACCESS_DENIED error.

Doing some google and MSDN Lib research, I thought perhaps this had to do with authentication “Impersonation” vs. “Delegation”. I can see documentation that says that in order to do multi-tiered authentication in this way that the middle tier server (in our case the server hosting C:\Shared) must support “Delegated Authentication”, which means being and AD Domain member, running Kerberos5, and configured to allow Delegation.

So I set up an AD Domain (currently set at Windows Server 2003 functional level), joined the client and the \RemoteServer to the Domain and tried again…but same problem.

For whatever reason when the middle server hosting C:\Primary running our filter driver attempts to map to \RemoteServer\SharedVol on behalf of the client that originally mapped to \MidServer\Shared (i.e. C:\Shared), the original Client Username/Creds are NOT used but NULL/Empty Username is used instead which fails with AccessDenied.

So I guess my main question is — is it even possible with our current filter driver model to do this? Does Delegated Authentication only work in certain cases and the Mup/Redirector and/or CIFS doesn’t support this?

I guess that we are really trying to indirectly create a share to a remote share, something that Windows won’t allow you to normally do using NET USE (i.e. NET USE only takes local drives (C:, D:, etc) for SHARE destination, NOT remote mapped drives or UNC paths (Z:, Y:, \RemoteServer\SharedVol, etc.).

If you’ve made it to this point in your reading I commend you. Sorry for the very long post. Hope my questions make sense. Any help is greatly appreciated.

What you are trying to do is possible.
I guess you have done most of research needed for this.

Let me explain Constrained Delegation (s4u - security for users) a bit more:
A specific user is allowed to impersonate any user (without needing a password) to authenticate with a specific service on a remote server.
This specific service on the remote server happens to be CIFS/SMB in your case.
You need to choose a user and configure it for Delegation (This is not the user which will be connected to your server). You need to God user running on your server.

Your threads need to be running in the context of this special user and you need to impersonate the user connecting to your server in these threads and then make the remote calls.

I think a layered FS Filter should be a desired approach for this case, so that you can un-impersonate the thread.

So theoretically, what you want to do is possible.
However, there will be significant implementation challenges.

We did use this infrastructure for our in-band migration product.
However, we were a packet filter and not a FS Filter.

Divya,

Another option might be to convince the user-application to create the
network session for you.

As a test you could try issuing a STATUS_REDIRECT response to a network
share and see if a proper authenticated client session is opened at that
point.

Of course, if this works, you will need something suitable to trigger
this action.

Perhaps when the user tried to open c:\shared you could issue
STATUS_REPARSE to the server share, and then when they query that remote
directory you can merge it with the local directory?

I mention this as I suppose that is what is working for me when I direct
to other network shares - but I haven’t tested in all circumstances yet
so I cannot be sure if that is why it works, and some of my servers are
setup as trusted for delegation.

Sam

* divya.jain wrote, On 10/11/09 05:47:

What you are trying to do is possible.
I guess you have done most of research needed for this.

Let me explain Constrained Delegation (s4u - security for users) a bit more:
A specific user is allowed to impersonate any user (without needing a password) to authenticate with a specific service on a remote server.
This specific service on the remote server happens to be CIFS/SMB in your case.
You need to choose a user and configure it for Delegation (This is not the user which will be connected to your server). You need to God user running on your server.

Your threads need to be running in the context of this special user and you need to impersonate the user connecting to your server in these threads and then make the remote calls.

I think a layered FS Filter should be a desired approach for this case, so that you can un-impersonate the thread.

So theoretically, what you want to do is possible.
However, there will be significant implementation challenges.

We did use this infrastructure for our in-band migration product.
However, we were a packet filter and not a FS Filter.


NTFSD is sponsored by OSR

For our schedule of debugging and file system seminars
(including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

>The reason it doesn’t work is because when the filter sees the IRP_CREATE to

C:\Primary and attempts to mirror that CREATE over to \RemoteServer\SharedVol,
we receive an ACCESS_DENIED error and can’t progress further.

The IRP_CREATE to “C:\Primary” is executed in the context of specific user. The create to \RemoteServer\SharedVol should be executed in the same thread context so primary or impersonation token can be used for authentication. I suppose that given user has access to the share \RemoteServer\SharedVol. I think that only IRP_MJ_CREATES need to be impersonated. If you need to execute IRP_MJ_CREATE in context of system worker thread you need to impersonate this thread before you call IRP_MJ_CREATE on share. Take look on CreateParameters in IO stack location, here you can gain either a primary or an impersonation token.

IIRC there can be the flag named like CONNECT_TREE in IRP specified for IRP_MJ_CREATE. In this case the IRP buffer can contain Extended named attributes (username, password, domain). Take look on smbmrx sample in WDK 6001 how to arrange EAs. You have to use the native API to specify EA (NtCreateFile()) or roll your own IRP. So this can be way for you to specify credentials explicitly, which is not very secure.

Bronislav Gabrhelik

Thanks to all of you for the feedback and suggestions. Looks like there may be a few different options for me to try.

Sam - you mentioned issuing a STATUS_REDIRECT…did you actually mean STATUS_REPARSE?

We are currently using STATUS_REPARSE in some cases to redirect to the alternate path, other times when we don’t redirect but rather just want to get a handle to the “mirror” path on the alternate volume we are calling ZwCreateFile and then saving the returned handle for use in later I/Os where we need to do any I/O tinkering.l

I think a little later after I get a chance to review exactly what we’re doing during IRP_CREATE, I’ll explain what we currently do, and perhaps that will help narrow down what option might be most appropriate to attempt first to try and get the remote case working.

Thanks again for you kind help.

* tklee_home wrote, On 10/11/09 16:45:

Thanks to all of you for the feedback and suggestions. Looks like there may be a few different options for me to try.

Sam - you mentioned issuing a STATUS_REDIRECT…did you actually mean STATUS_REPARSE?

Yes, sorry

Sam

No problem Sam - I figured that must be what you meant, I nearly made the same typo when I asked the question to clarify.

So we currently do use STATUS_REPARSE in some cases on a file open (but NOT directory) to redirect IRP_CREATE requests away from C:\Shared over to \RemoteServer\SharedVol.

However in this case that is failing it is the directory case (i.e. CreateOptions FILE_DIRECTORY_FILE bit is set), where we do things a little differently (using ZwCreateFile) as outlined in the pseudo-code below:

Note: My driver is a FS mini-filter driver so we rely on filter mgr to do some of the heavy lifting for us. So this means we have PreCreate and PostCreate functions to handle IRP_CREATE pre/post processing.

Assumptions:

  • Prior to PreCreate being called we have earlier attached to C:\ (i.e. \Device\HardiskVolume1) and \RemoteServer\SharedVol (i.e. \Device\Mup\RemoteServer\SharedVol).

  • We can assume that any directories/subdirs that exist on RemoteServer\SharedVol also exist on C:\Shared

  • We also have a table telling us that we only care about files/dir located at C:\Shared and below. Our intent is two-fold:

  1. Merge in contents of \RemoteServer\SharedVol with those of C:\Shared so that as far as end user is aware C:\Shared contains all files/folders from either location. Most of the work here happens in our PostDirControl handler.
  2. If request comes to open/create file in C:\Shared that actually exits on \RemoteServer\SharedVol then we need to redirect the request over to RemoteServer.

PreCreate code flow:

If IRP is NOT from a remote user (i.e. CurrentProcess/Thread Token type is IMPERSONATION)
then we don’t do anything - return FLT_PREOP_SUCCESS_NO_CALLBACK

Also return FLT_PREOP_SUCCESS_NO_CALLBACK if IRP is for a file/dir that isn’t in C:\Shared or below in the directory tree.

Check for cases of FILE (but NOT DIRECTORY) opens where the file exists on RemoteServer and not on C drive, in some cases we need to handle these at PreCreate time, we handle them by returning STATUS_REPARSE in IoStatus and return FLT_PREOP_COMPLETE

Otherwise for File/Dir IRP_CREATEs we care about but didn’t handle already, save some context for later and return FLT_PREOP_SUCCESS_WITH_CALLBACK.

…then later in PostCreate:

IF original IRP_CREATE to C:\Shared… returned SUCCESS
save away some state/context info we care about in STREAMHANDLE_CONTEXT
IF this was a CREATE for a DIRECTORY
Call ZwCreateFile for directory on \RemoteServer\SharedVol… that is the mirror to C:\Shared…
Save returned handle for later use primarily in PostDirControl handling.
NOTE: This is where we are failing - ZwCreateFile returns ACCESS_DENIED which corresponds to LAN trace showing connection to \RemoteServer being made with UserName = BLANK/NULL so then the SMB_TreeConnect to \RemoteServer\SharedVol returns ACCESS_DENIED since NULL user has no rights.

Else handle cases of ERROR returned in IoStatus for original IRP_CREATE to C:\Shared.
In some cases here we do the redirect with STATUS_REPARSE at this point.

Return FLT_POSTOP_FINISHED_PROCESSING

Not sure if this changes anyone’s opinion of what I should try next to fix the remote authentication problem, but thought I’d go over this just to clarify what we currently do.

Thanks for all the help.

@Sam,

I am surprised the method you described worked for you.

Per my understanding (limited :wink: ),
srv.sys will impersonate the user connected from the remote client.
The token for this thread allows for only local access.
It does not allow access to remote resources.
When redirecting such requests to remote share, at some time, the rdr will check for this token.
If the token is for limited resources, then rdr should establish a null session.

Seems like, this is working a bit differently for you.
The rdr is picking up an existing session before making this critical check.
This doesn’t sound right to me. The rdr should basically validate the privileges of the thread token before using an already established session.

This would be same as saying, if i do a net use to a remote machine from my server from a particular user, when this user connects to srv.sys, I should be able to redirect access to this session.

* tklee_home wrote, On 10/11/09 23:13:

No problem Sam - I figured that must be what you meant, I nearly made the same typo when I asked the question to clarify.

So we currently do use STATUS_REPARSE in some cases on a file open (but NOT directory) to redirect IRP_CREATE requests away from C:\Shared over to \RemoteServer\SharedVol.

However in this case that is failing it is the directory case (i.e. CreateOptions FILE_DIRECTORY_FILE bit is set), where we do things a little differently (using ZwCreateFile) as outlined in the pseudo-code below:

Note: My driver is a FS mini-filter driver so we rely on filter mgr to do some of the heavy lifting for us. So this means we have PreCreate and PostCreate functions to handle IRP_CREATE pre/post processing.

Assumptions:

  • Prior to PreCreate being called we have earlier attached to C:\ (i.e. \Device\HardiskVolume1) and \RemoteServer\SharedVol (i.e. \Device\Mup\RemoteServer\SharedVol).

At this point I am disqualified to think of how a server is attaching to
another server in the context of a client remote user. I’ve done this
for samba in a similar situation, but I don’t know how windows would do it.

IF original IRP_CREATE to C:\Shared… returned SUCCESS
save away some state/context info we care about in STREAMHANDLE_CONTEXT
IF this was a CREATE for a DIRECTORY
Call ZwCreateFile for directory on \RemoteServer\SharedVol… that is the mirror to C:\Shared…
Save returned handle for later use primarily in PostDirControl handling.
NOTE: This is where we are failing - ZwCreateFile returns ACCESS_DENIED which corresponds to LAN trace showing connection to \RemoteServer being made with UserName = BLANK/NULL so then the SMB_TreeConnect to \RemoteServer\SharedVol returns ACCESS_DENIED since NULL user has no rights.

And this is irrespective of the remote share being accessed via UNC or
mapped driver letters?

It seems significant that you see a conenction being made with
BLANK/NULL when you said above that you already had a session.

Perhaps the post-create is run in another thread without the right
tokens to issue ZwCreateFile, and I wonder if you meant FltCreateFile,
or prior minifilters (maybe even yours) may mangle the filename, yet you
are working in a context of potentially already-mangled names.

Else handle cases of ERROR returned in IoStatus for original IRP_CREATE to C:\Shared.
In some cases here we do the redirect with STATUS_REPARSE at this point.

Return FLT_POSTOP_FINISHED_PROCESSING

Not sure if this changes anyone’s opinion of what I should try next to fix the remote authentication problem, but thought I’d go over this just to clarify what we currently do.

Did you also make your middle server “trusted for delegation”? (Right
click on the computer account).

Sam

* divya.jain wrote, On 11/11/09 05:40:

@Sam,

I am surprised the method you described worked for you.

I read the original message too hastily, I had understood that the
filter ran against a windows server, not ran on a windows server.

Certainly it becomes hard to explain what is meant by accessing a remote
mapped drive when mappings are session specific.

Sam

Thanks for the additional feedback. Sorry for the delayed response.

And this is irrespective of the remote share being accessed via UNC or mapped driver letters? It
seems significant that you see a conenction being made with BLANK/NULL when you said above that > you already had a session. Perhaps the post-create is run in another thread without the right tokens > to issue ZwCreateFile, and I wonder if you meant FltCreateFile, or prior minifilters (maybe even
yours) may mangle the filename, yet you are working in a context of potentially already-mangled
names.

Sam - It doesn’t seem to matter whether the remote share is accessed via UNC or mapped drive letter. I can however get it to work in the case when the remote share is not actually remote, but is just a share that is running on the localhost/middle-server, i.e. same machine where the filter is running (mapping to \localhost\SharedVol).

So from what Divya has suggested, I’m thinking in this case I am “Impersonating” and since it stays on themiddle server and doesn’t have to truly go remote that I am allowed to do it.

I have tried making the middle server “trusted for delegation” but that didn’t seem to help.

Perhaps the post-create is run in another thread without the right tokens to issue ZwCreateFile, >and I wonder if you meant FltCreateFile, or prior minifilters (maybe even yours) may mangle the >filename, yet you are working in a context of potentially already-mangled names.

I had thought that post-create was guaranteed to run in the same thread as pre-create. Perhaps I’ll try doing things at pre-create time and see if it makes a difference. Also I am using ZwCreateFile rather than FltCreateFile. Originally I was using the Flt call but for some reason I switched to Zw, I can’t remember exactly why at the moment.

So if I can’t get this to work within our current model, perhaps the layered filter model suggested by Divya with “super user” thread doing impersonation is the next thing to look at?

Also as far as paid options (consulting, etc.) for getting help with this problem, my company hasn’t done this in the past but may be willing to go that route in the future. Any suggestions on who might best be able to solve the type problems I’ve been describing?

Many thanks.