Tuesday, December 1, 2009

Making .Net Applications UAC compliant (Vista,Server 2008, etc)

UAC(User access control) is a feature which users started feeling the pain of :) in Vista and this legacy will continue in most of the microsoft products which will be released in subsequent future. Take for eg windows 2008, windows 7 etc. they all will feature those popups which prompt you when an application is started. Sometimes i think..."Why does it ask me for some action i have taken in all good sense"... well i havent got a good answer yet and just as i started working on making software UAC compatible.... I got a good chance to explore it. So here I am trying to share the experience and the knowledge in as small an article as much i can shorten.


Before embarking on making a software for the UAC feature rich vista or Os's to come, we have to know about what a Standard User is. A standard user is any system user who doesnt need to know about anything except use the box and leave it. Actually 90% of users of a system are supposed to be Standard users and a few must be eligible to be Admin powered users. So whats the difference between a standard user and an admin user. A standard user has limited rights... since he is not supposed to do a variety of things like,,,, accessing the registry, changing it... create files where you are not authorized, trying to delete files made by other users, trying to rename a file created by some other user, peeping around dark corners in your PC etc. More over the security features revolving around UAC also restrict applications to doing any write/create/delete/update IO operation in Program Files.

Rule 1. If your application writes to any file/folder within "Program Files"... its gonna fail. So change this to a location which is common for any kind of a user (especially our so dear Standard User).

Rule 2. If your application needs to store user specific data then use %userprofile% location. Programatic access can be found by using the Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) method in C#. This would give you the current user's application data path.

Rule 3. Rule 1 and Rule 2 are as a result of the virtualization that takes place in Vista and server 2008. The writes to any directory in C:\program files is directed to a user specific store. Tring to save a txt file to c:\Program Files will prompt the user to save it to My documents folder for eg:
C:\Users\rmathew\Documents.

To re-route the reads and writes which occur at the program files directory to a common path we should consider the Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) folder. This will Get the folder named "ProgramData" in Vista and 2k8. A common path on vista would look like C:\ProgramData. Developers wanting to share common data across all users on a sytem for a specific application, will have to store their data at this specific location. All reads and writes which occured at C:\Program Files folder structure will have to be redirected to the CommonApplicationData folder. Read writes would include log files, config files, xml files generated on the fly etc. Developers will have to give FULL RIGHTS to "EveryOne" user on this folder and all files must inherit security attributes from the above folder.

Rule 4. Add a Manifest file to your Application. The manifest file is used by the OS to read the specifics of the application requesting to start execution. The effective authorization and rights of the applications are specified in the manfiest file. Embed the same as resource. If the name of the executable is Abc.exe, the manifest will be Abc.exe.manifest. These manifest files are generated in visual Studio 2008 by default but in previous versions of visual studio this manifes file needs to be added as a post build event.
In Visual Studio 2005 a Post Build Event can be fired  to add the assembly manifest file

"C:\Program Files\Microsoft Visual Studio 8\VC\bin\mt.exe" -manifest "$(ProjectDir)$(TargetName).exe.manifest" -outputresource:"$(TargetDir)$(TargetName).exe;#1"


Rule 5. Give the ACL(Access control list) to specific folders where write operations have to be performed.

if (!Directory.Exists(initialCachePath))
{

    //Creating Directory
    DirectoryInfo dirinf= Directory.CreateDirectory(<some directory you need to create>);

   //Get the access control list on the created directory
    DirectorySecurity dSecurity = dirinf.GetAccessControl();

    //Adding accessing rights for "Everyone" on that folder with full control
    dSecurity.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl,  InheritanceFlags.ContainerInherit
InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));

//apply permissions to directory(s)
dirinf.SetAccessControl(dSecurity);

}


Rule 6. Test Test and retest.

No comments: