Last time around, we looked at an application compatibility side-effect of User Account Control on Windows Vista: the potential impact on Mapped Network Drives when running elevated. Another side-effect that may affect application compatibility is the changes we have made around per-user COM registration.
Back in Windows NT 4.0, HKEY_CLASSES_ROOT was simply an alias of HKEY_LOCAL_MACHINE\Software\Classes. However, beginning with Windows 2000, HKEY_CLASSES_ROOT is a merged view of the data in HKEY_LOCAL_MACHINE\Software\Classes and HKEY_CURRENT_USER\Software\Classes. Aaron Margosis discusses how to leverage this merged view (and the differences in permission) to resolve LUA bugs in his Technet article Problems of Privilege: Find and Fix LUA Bugs. You see, when we search for a COM registration, entries in the HKEY_CURRENT_USER hive take priority.
And it is exactly this property (fixing LUA bugs) that makes this load behavior dangerous if your process happens to be elevated. A standard user is able to write to these registry entries, which is why it can help applications to work. Because a standard user can write the configuration for a COM object, we don't want to open the door to an elevation of privilege attack. If we simply enforced the same rules for an elevated process, loading entries from the user hive first, then a process could easily write a new configuration for a commonly loaded COM object, point the configuration to arbitrary code, and have an elevated process pick up that arbitrary code, executing it with administrator privileges! Consequently, we block loading of COM registrations from the per-user registry hive if the process' integrity level is higher than medium. That means you won't pick up a per-user COM object if you are manifested as requireAdministrator, or if you have manually elevated the application (right click - Run as Administrator). It also means you won't pick up a per-user COM object if you are running as a member of the local Administrators group and you have disabled UAC for some reason.
So, if you are an application developer who is designing an application to run elevated, you should make sure that you drop your COM registrations in the per-machine hive (which creating a new key in HKCR will do by default) at install time, rather than relying on a per-user installation.
User Account Control on Windows Vista provides a convenience feature which allows you to elevate a process without leaving the current desktop. (For a discussion of why this is a convenience feature, rather than a security feature, see Mark Russinovich's blog entry here: http://blogs.technet.com/markrussinovich/archive/2007/02/12/638372.aspx).
Let's explore this at a fairly high level. To simplify things, let's assume you are running as an administrator with UAC enabled (although, to be more secure, it is better to run as a standard user). When you log in, you create a new token. We then detect that you have UAC enabled, we log in a second time, and end up with a new (highly restricted) token, which we use to launch the shell. There are two separate login events. When you are prompted to elevate, you go through consent.exe, which is able to leverage the Application Information service to essentially call CreateProcessAsUser with the fully-charged admin token. Remember - we are calling CreateProcessAsUser with a token generated with a separate login.
This convenience feature makes it easier to run into issues with mapped network drives. Prior to Windows 2000 SP2, device names remained globally visible until explicitly removed or the system restarted. For security reasons, we modified this behavior beginning with Windows 2000 SP2. From this point forward, all devices are associated with an authentication ID (LUID) - an ID generated for each logon session. (A process running in LocalSystem context can create a device name in the Global device namespace, although local namespace objects can hide global namespace objects.)
Because these mapped drives are associated with LUID, and because elevated applications are using a different LUID generated during a separate login event, the elevated application will no longer see any mapped drives for this user. (You will notice the same behavior previously using RunAs or CreateProcessAsUser, but UAC dramatically increases the number of users who will be using these concepts.)
The result? If you elevate a command prompt, you will no longer see any local namespace mapped drives created from your original login (whether created through a logon script, WNetAddConnection, or otherwise). We do put a mitigation in place for the scenario of launching from the shell. If you double click on an executable that is either detected as a setup or is manifested as requireAdministrator, we can detect that we just elevated and suddenly are getting an error message indicating that the path was not found, and copy that drive mapping over from the original LUID. However, that is the only scenario that we can automate.
So, if you need to leverage mapped drives from an elevated process, you should be certain to map these drives in the contect of the elevated login.
There is a lot of information that we have disseminated regarding UAC applying to applications, but not nearly as much regarding control panel applets. They are, indeed, quite similar. Just like a standard .exe, a .cpl file could have one of many possible execution levels. It may be perfectly fine to run as the user. For example, personalization options to change your desktop background don't require elevated rights because you aren't modifying machine state. However, modifying the configuration of the Windows Firewall does change machine-wide state and, consequently, does require elevated rights.
So, much like executable files, a control panel applet should contain a manifest specifying UAC run level.
But, what happens if you have a control panel applet that was installed by an application created before Windows Vista (and its manifest schema) existed? Well, since we can't determine which run level it requires, the principle of least privilege demands that we run it with restricted privileges. However, since this can break some control panel applets, we monitor this with the Program Compatibility Assistant. If we detect that you have launched a control panel applet that is not manifested, after you close the applet PCA will ask you if it worked correctly. If you say that it didn't, then we set a registry key to apply the RunAsAdmin shim to the applet on future invocations and then relaunch the applet.
This approach works perfectly well at the individual user level, but once you start seeing this from the perspective of an enterprise, you may be wondering why you would ever want every one of your users to have to make the same decision. And, indeed, you don't. You can apply the appropriate shim for a legacy control panel applet in a custom shim database that you deploy across your organization. Because it's a bit different than shimming a standard application, I figured I would walk through this procedure.
Using Compatibility Administrator, select your custom database, and press the toolbar button to create a new Fix. After filling out the name and vendor of the applet, you can either type the path to the executable (it will auto-complete), or else you can hit the browse button. If you hit the browse button, here you will notice the first difference from a standard executable. The file dialog is limited to .exe files, so you don't see the .cpl files while browsing around. However, you can go to the File name text box and type in *.cpl, and you will be able to see the applets in that directory.
So, find the applet that you want and click next. Take no compatibility modes, and click next again. From the Compatibility Fixes list (shims), select the RunAs* shim that works best for the applet (RunAsAdmin, RunAsHighest, or RunAsInvoker). However, now you'll find the other difference - if you try to click the Test Run button, you'll just get an error message. No point in trying that. Click next, and specify the properties you want to use for file matching, and click on Finish.
If you now save and install this custom shim database, you can go to the Control Panel, launch the applet, and it will be launched with the appropriate run level, and you will no longer be prompted by UAC to verify that it worked correctly. Now, you can specify the run level for legacy control panel applets across your organization without relying on each of your users to independently discover the best execution level and make that selection on their own.