This is the third in a series of notes about UAC in MSI. Per the earlier caveat, these are just my notes and not an official position from the Windows Installer team. The previous entries introduced the series, and introduced my view of the root problem. This entry will talk about the first hurdle for me in thinking about UAC support in MSI is understanding the the term per-user.
Are we talking Install Per-User or Security Per-User?
As I started to work through the language around User Account Control, I kept tripping on the UAC team's use of the term per-user. Given my collected experience with Windows Installer, I had a prexisting understanding of per-user in the installation context. After traversing the first set of UAC design documents, my first aha! moment came when I realized UAC is redefining the term per-user.
Previously, I asserted there has been a generational effect to how Users have been separated from Machine. The meaning of a Per-User install came from the first generation. Under that generation, the separation of User from Machine was some slight of hand with folder names. I imagine the justification at the time was that everyone ran as a full Administrator so any stronger conventions could just be circumvented. Eventually these folder conventions that were codified by the Windows Shell in the the IShellFolder interfaces, particularly SHGetSpecialFolderPath which was replaced with SHGetFolderPath.
As example of how these conventions were developing at the same time as the Windows Installer, observe initial versions of the Windows Installer redistributable included the shfolder.dll that provides the Shell Folders APIs.
If you'll look at the difference in SHGetSpecialFolderPath and SHGetFolderPath you'll notice that it the former API didn't have a user parameter while the latter did. Though I wasn't on the Windows Installer back then, I imagine the developer needing to support this construct was staring at the SHGetSpecialFolderPath implementation in the pre-Windows Installer code (called ACME) which was replaced with SHGetFolderPath. The quick change would be to flip the function name and then invent a mechanism to choose the token (more on this in a later entry). I could be completely wrong but this is how I make sense of it.
The reason why I focus on this specifically is in analyzing the behavior of ProgramFilesFolder property in definitions of per-user and per-machine from the Windows Installer SDK. This folder represents expected location for application installs and it DOESN'T SHIFT for a per-user install. This makes my spider-sense tingle particularly in the light of the Longhorn definition of per-user centers on the C:\Documents and Settings\username\Local Settings\Application Data.
As example of how Longhorn generation technology is using definition a new definition of per-user that centers on the C:\Documents and Settings\username\Local Settings\Application Data, consider ClickOnce. The early documentation incorrectly asserts that Windows Installer can not install to a per-user location. I deduce from inspection of the ClickOnce install location that per-user is simply a shifted definition.
I'd also note that the shifted definition is not entirely complete in that there is not a new CSIDL for a per-user application install location rather it must be hand constructed. This partial evolution is consistent with the first generation evolution where corporate conventions for per-user storage predated the incorporation into the shell.
After poking around at the different uses of per-user in the Longhorn team (wasn't called Vista quite yet) it started to dawn on me that the UAC team was the source of the new per-user definition. In the UAC quest to have Longhorn run using the Principle of Least Privilege, they had reset succeeded in resetting the definition of per-user. Under the new security consciousness, the locations that a Standard User had write access became the new definition.
The next question in my investigation was "what is the exhaustive list of locations that a Standard User will have write access to?". Turns out I could not find the definitive answer. The closest thing I got was that a Standard User CAN'T write
- Anything protected by Windows Resource Protection.
- Anything under c:\Windows
- Anything under c:\Program Files
- Anything under c:\Users\<Other Peoples Profiles>
- Anything in c:\Users\All Users
- Anything under c:\Program Data
- Anything under the non-mapped root drive (c:, d:, e:, etc)
- Setup programs that are running as administrator can loosen ACLs on anything not Windows Resource Protected
- Non-setup programs can have their writes to protected locations appear to succeed only to have Virtualization actually redirect to user writeable location.
FWIW... I had trouble keeping this in my head ;^). I continue to consult friends on UAC which you can do via their blog.
Filter for conflicts has helped me
For me, when UAC stuff got out of alignment, I found filtering for conflicts has helped quite a bit. When stuff stopped making sense, popping this filter on helped me pick out the nuances. Hope this helps you too.