Can ISAPI Extension override its user impersonation?

I usually want a high ratio of answer content to question content, but the following question is going to be pretty hard... because the question is lengthy with lots of good detail which make it easy for me to come up with the right answer without a lot of explanation. Well, here goes...

Question:

Web server environment:
Windows 2003 Server SP1 (Standard)
Default IIS installation
ActiveState Perl v5.8.7 (using the ISAPI extension rather than Perl.exe)
Third-party Perl web app

I will be running several cgi apps on our new web server and chose to use the new application pool feature in IIS 6.0 to isolate each one (for both performance and security reasons). To test out how all this was going to work, I setup my first application pool and designated one of our perl apps to this pool. In configuring the pool, I specified a custom user account that I had setup for this particular app (instead of using the built-in Network Service account). I added this new account to the IIS_WPG group and gave it adequate permissions to the perl app's directories (and the ActiveState perl runtimes). I assumed that all client requests received by the worker process of this pool would be carried out in the context of the worker process's identity. But after a few attempts at running the app via my browser (anonymous connection), it was failing due to permissions errors. I used a file monitor to see what the issue was, and I could see that the worker process was trying to create a file in my perl application's directory and was being denied. After closer inspection, I could see that it was because the anonymous user account was being used. 

I found your blog and of course my answer - impersonation by default. I then used the adsutil.vbs script and MS instructions to set CreateProcessAsUser to False in the metabase. I restarted IIS and confirmed the new parameter by opening the metabase file in a text editor. However, upon running my app again, it did the same thing - the worker process assigned to my app pool was still trying to create this file using the anonymous IUSR_MACHINE account. Any ideas? The only way to get things to work is to give the anonymous user write permissions to the necessary web app directories which seems to be counter-intuitive (and not secure, unless I'm missing the big picture). Is it possible that the ISAPI extension can override the impersonation setting? Couldn't find anything regarding this on ActiveState's site.

Answer:

Ok, in this case, you have pretty much located all of the possible answers (for the benefit of the new reader, the blog referenced by the question is here).

Yes, ISAPI extension can override IIS user impersonation, but that depends on the ISAPI.

CreateProcessAsUser only applies to CGI EXE since IIS has to launch a new process to run the CGI EXE. It basically changes how IIS calls the CreateProcessAsUser() Win32 API. Meanwhile, ISAPI DLLs are different because to execute them, they are dynamically loaded into the IIS process itself (that's why they are called Dynamic Link Library - DLL). Thus, there is no new process being created, so CreateProcessAsUser cannot apply.

Unfortunately, there is no IIS configuration to control whether IIS impersonates or uses process identity when executing ISAPI. IIS always uses process identity to run ISAPI Filter DLLs, and always uses impersonated identity to run ISAPI Extension DLLs. Before you ask - no, ISAPI Filter and ISAPI Extension are not interchangeable - they are very different beasts.

Now, I think the IIS configuration for running ISAPIs is pretty reasonable because:

  • ISAPI Filter does not "own" any request (so which user token to impersonate?) and it would be horrible performance to impersonate on every single filter event
  • ISAPI Extension "owns" a request and should run as the authenticated user identity. If it wants to control the identity it runs as, it should control it itself.

Answers...

Now, I think your real question is how to control the user identity which executes the perl script, and that comes down to two basic questions:

  1. How to control whether IIS executes user code using process identity or impersonated identity
  2. How to control the process identity and impersonated identity

As I have said earlier in the linked blog entry, IIS executes user code either through a CGI EXE, ISAPI Filter, or ISAPI Extension. ISAPI Filter always runs as process identity, ISAPI Extension always runs as impersonated identity, and CGI EXE has a switch to determine whether it runs as process or impersonated identity.

IIS defaults to impersonated identity, and user code can always access process identity by calling RevertToSelf(). I have no idea if ActiveState has such an implementation in their Perl ISAPI because it would allow Perl to run as either process or impersonated identity.

Process Identity is also easy to control on IIS6 - use the custom Application Pool Identity feature. Impersonated identity is also easy to control - for anonymous authentication, it is the configured anonymous user account; for any other authentication protocol, it is the authenticated NT user account.

I think in your case, since you are using the ISAPI Extension version of perl but need the perl scripts to run with a certain user a ccount, you need to control the impersonated identity. With anonymous authentication, you can do exactly that. You just need to configure the anonymous user identity in the virtual directory holding the perl scripts, and all anonymous requests to the perl scripts through that virtual directory will use your configured anonymous user identity. If you want even better control, consider using IIsWebFile to set the anonymous user identity on a per perl-script basis (see my other blog post on IIsWebFile on how this works).

However, realize that code in an ISAPI can ALWAYS get access to the process identity by calling RevertToSelf(), including from the Perl script itself. Thus, you should see that IIS uses Application Pool Identity more as an isolation mechanism than an execution mechanism.

//David