A few years back, I received some questions pertaining to what privileges were required to modify the source list for a given product. The questions have come up again and rather than debating on where this information belongs (MSDN vs. TechNet vs. whitepaper), I figured I’d skip all of that and lay it out in a blog entry. (The debate will rage on in the mean time, but at least I’ll get the info out and in public).
The first question happened to deal with the AlwaysInstallElevated policy. This is not a policy anyone on the Windows Installer team recommends using (due to its security implications), but we certainly understand that there are those out there that do.
Q: Does the AlwaysInstallElevated policy guarantee that the installation is elevated?
This is actually a tricky question. As long as the AlwaysInstallElevated policy is set (in both HKLM and HKCU), the install transactions are elevated. However, this doesn’t guarantee that the subsequent install transactions are elevated when the policy is unset. Only managed applications have “sticky” elevation where all subsequent install transactions are elevated. There are two types of managed installations – per-machine and per-user. In fact, there are three types of installations that Windows Installer considers: per-user, per-user managed, per-machine. You can easily come to the conclusion that all per-machine installations are managed. However, the same can’t be said of per-user. The only way a per-user install becomes managed is if it was initially advertised via the MsiAdvertiseScript API in the manner documented here.
So, if you perform a per-machine installation with the AlwaysInstallElevated policy, you end up with a managed install. You can unset the policy and still have operations for that install run elevated. On the other hand, if you perform a per-user installation with the AlwaysInstallElevated policy, then that install’s operations are only elevated while the policy remains set. You can’t create a per-user managed installation with the AlwaysInstallElevated policy.
Q: How do I know if my installation is managed (and in what context)?
There are two API you can use to query for this information. The first is the unfortunately misnamed MsiIsProductElevated API which really should have been called MsiIsProductManaged since that’s what it tells you. The pfElevated parameter is set to TRUE if the product is managed.
To determine the context, use the MsiGetProductInfo API and query the INSTALLPROPERTY_ASSIGNMENTTYPE property. If the value of the property is 1, then the context is per-machine. If the value of the context is 0, then the context is per-user. Per-user and per-machine is determined by the ALLUSERS property setting.
Combining the two will tell you if you have a per-machine, per-user managed, or per-user unmanaged install.
Q: What does all of this mean in relation to source list modification?
There’s a set of source list API that allows for modifications such as the addition of new sources, removal of sources, and clearing of the source list (e.g. MsiSourceListClearAll). If the caller doesn’t have the privilege to complete the operation, the API returns ERROR_ACCESS_DENIED. Each of these actually have a small blurb in the remarks section that describes when this can occur, but here’s a closer look…
When MSI is evaluating this, it’s including several pieces of information:
· The caller (admin user or not)
· Product Elevation Context (managed or unmanaged)
· Product Install Context (per-user or per-machine)
· Which user
These bits of information combined with some of the source list control policies determine whether the operation will complete successfully.
Now, let’s consider the default scenario where the AlwaysInstallElevated policy is completely out of the picture. The following table answers the question, Is Source List Modification Allowed? The “x-axis” represents the product install context. The “y-axis” represents the caller’s context.
Per-User Managed (Self)
Per-User Unmanaged (Self)
Per-User Managed (Other User)
Per-User Unmanaged (Other User)
Admin* / System
* Note that on Windows Vista, the admin would have to be the full (unfiltered) administrative token
You can summarize the table as follows: Only administrators (and local system) are allowed to access and modify source list information across users. However, this is restricted to only per-user managed applications for other users. The administrator cannot alter the source list for an unmanaged installation for a different user. The standard user can only update his/her own unmanaged per-user install.
So, let’s throw some source list policies into the mix – let’s say that the DisableBrowse source list policy is enabled and set to 1. The table above now becomes this:
So the new summary is: Administrators (and local system) access and modification privileges are unaltered by policy setting. DisableBrowse always disables source list update for all standard users.
Now, let’s restore DisableBrowse to its default and instead set the AllowLockdownBrowse policy to 1. The table now becomes:
So now with AllowLockdownBrowse, we given the standard user the ability to modify the source list for all per-machine and per-user applications (managed or unmanaged) installed for that user.
The final change we’ll make is to throw out DisableBrowse and AllowLockdownBrowse and instead just set the AlwaysInstallElevated policy. The table now becomes:
Note that per-user unmanaged installs for the standard user now become a No with the AlwaysInstallElevated policy set. This is because the AlwaysInstallElevated policy changes these products to acting as elevated.
Therefore, whenever you have the AlwaysInstallElevated policy set, you have to have the AllowLockdownBrowse policy also set in order to allow source list modification. This is summarized in this final table (below) representing AlwaysInstallElevated + AllowLockdownBrowse:
This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm.