loadUserProfile and IIS7 - understanding temporary directory failures
I've noticed quite a few people running into temporary directory permission issues. The PHP blog post I made last month is one example of this issue, there are also several forum posts related to ASP & Access database failures, where the reported failure is:
Microsoft JET Database Engine error '80004005'
Unspecified error
Not a very helpful error, to be sure. It turns out all of these cases have a similar underlying cause: the effective user of the web application (including the anonymous user for unauthenticated requests) can not effectively write to the temporary directory. What changed in IIS7 and why did this always work before?
With IIS6, all worker processes, regardless of which the process identity was configured, used to C:\windows\temp as the temporary directory. More specifically, none of the worker processes loaded their 'user profile' by default, causing all of them to use c:\windows\temp as a temporary directory. Windows allows all users read/write/creator privledges on this directory, which allowed things to 'just work'. The negative side effect of this is that all AppPools are effectively sharing the same temporary directory by default, which could lead to cross-appPool information disclosure.
With IIS7, we've chosen a more secure default and now load user profile by default for all application pools. Unfortunately, the temporary directory underneath the user directory (for example - %windir%\serviceprofiles\networkservice\AppData\Local\Temp for the default NetworkService identity we use for DefaultAppPool) is not writable by anyone other than NetworkService by default.
There are two ways to workaround this. First, I recommend that ACL the NetworkService temporary directory to allow whichever users read/write/creator privs that you want to allow access so that you still have the benefits of loading a user profile and separating temp directories per appPool. This can easily be done on the command line like this:
icacls %windir%\serviceprofiles\networkservice\AppData\Local\Temp /grant Users:(CI)(S,WD,AD,X)
icacls %windir%\serviceprofiles\networkservice\AppData\Local\Temp /grant "CREATOR OWNER":(OI)(CI)(IO)(F)
This allows every user to create files and directories (WD = Write to Directory, AD = Add Directory, X = Execute, S = Synchronize). The user who creates them will be the “CREATOR OWNER” of the file/directory.
The “CREATOR OWNER” ACE allows this user to do whatever he wants with the file. Other users can’t access these files/directories because they are not “CREATOR OWNER” of them.
The other less favorable workaround is to disable the loadUserProfile setting on a per-appPool basis. loadUserProfile is a boolean property on an AppPool section, and can easily be set on the command line (for defaultAppPool) like this:
%windir%\system32\inetsrv\appcmd set config -section:applicationPools /[name='DefaultAppPool'].processModel.loadUserProfile:false
hope this helps -
bill