News about UAC in Vista is all over the web. As a developer of shrink-wrap desktop software I thought I’d continue my string of “comments” (ok, bitching) about Vista now that I’m in a better place.
The most obvious places where UAC “helps you be more secure” are:
· Writing to the registry requires elevation
· Assumes any setup program needs to be run with Admin privileges
· Writing to the \windows folder requires elevation
· Writing to the \program files\ folder (and all folders below it) requires elevation
Another interesting tidbit is that Vista ships with .NET 2.0 installed. That’s good news. However MSI files built in VS 2003 will demand that .NET 1.1.4322 is installed despite the fact that .NET 2 should run those apps just fine. Oddly enough, navigating to \windows\Microsoft.Net\Framework\ on a Vista install will show the following directories:
However the v1 directories do not have the full install, just some GAC tools presumably for sort of tool compatibility, so tests detecting a specific 1.x version will fail.
One interesting thing I tried but ultimately did not go with was marking my application so Vista knows it needs to run with Admin permissions by embedding a manifest in the .exe. I found instructions for what the manifest should look like and a made a post-build event that would embed the resource in the assembly. This worked well and Vista displayed my .exe with a nice “shield” overlay letting the users know they’d be prompted to elevate. Sticking this .exe inside an MSI seems to clobber the manifest however, using dumpbin.exe confirms this. Rather than dig for the answer to this I made some code changes as indicated below.
For this software developer, here are the changes I had to make to get a product running on Vista as painless for the user as possible:
1) Created a .NET v2 version of our product. Granted, I’d rather use 2.0 across the board but some of our customers won’t upgrade and we sometimes distribute via http so a bootstrap including the 2.0 install is a little bigger than where I’d like to be. I did this by sharing the individual files across two VSS projects and just creating separate project/solution files for 2.0 in a different location. Thanks to Matt Terski for the tip. This feels evil for some reason but it works.
2) Re-wrote the installers. The .NET 1.1 installers accomplish some of the installation tasks with Custom Actions written in .NET. Some of these actions do things like registering a device with a WIA event using the WIA automation layer and therefore require admin permissions. While I would think the MSI would spawn my .net EXE with the same security tokens (already elevated and using the admin token) as the parent process this did not seem to be the case as the custom actions reliably crashed the install every time. I set up the MSI to write the same registry keys that the WIA code would have done and worked around the other custom actions so that everything is part of the MSI. Since the installer writes to the registry, it must still install with elevated permissions.
3) Non-Admin Logging Mode. Previously the application did innocuous things like Write a log file in the same directory as the .exe using log4net. I had to do some digging to find how to change a DOM configurated FileAppender location at runtime (http://insario.com/blog/jfk/archive/2004/11/30/164.aspx) and change this from \Program Files\MyProgram\ to a user-specific location if the code runs on Vista. (OS version = NT 6.0blahblah)
4) Non-Admin App settings. Written in .NET 1.1 initially the app used some dynamic windows forms properties: GUI features bound to an App.config setting. Since App.config lives in \Program Files\MyProgram updating these properties also wasn’t going to be non-admin friendly. Somewhat loathingly, I added a “Settings” file to the .NET 2 project. And set the code to use settings vs. writing to app.config with some conditional compilation. Hooray for #if NET2. The Settings feature wasn’t trumpeted like MASTER PAGES AND GENERICS when .NET 2 was rolling out but it’s worth looking into if you are not familiar with it. Settings can be marked with a UserScopedSettingAttribute() or regular old Application Scope. User scope settings are stored in a User specific location (although I’m damned if I could find the file itself but it works) and therefore no elevation needed. Nice of .NET 2 to handle that for me. This is probably a better design choice anyway but again it’s mainly a 1.1 app.
Now my code installs as Admin and then happily does all its Camera/WIA/Exif/Internet hooha without requiring elevation. Digging through the UAC documentation to see where I was going wrong was frustrating at first, and if anyone knows how I can keep an MSI created in VS2005 from clobbering my manifest (at install time or packaging time, I’m not sure which) that will probably come in handy at some point.