Cannot copy file, even though FileIOPermission is granted in C#

.net, c#, file-permissions, security, windows-7

Solution

The CAS IOPermisson of read/write only grants you the ability to read or write. It takes no notice of filesystem level permissions (ACLs.) Examine the ACL on the folder a bit closer :)

-Oisin

Problem

I was trying out the `FileIOPermission` in Windows 7 in .NET 3.5. I have been a Windows XP user and was granted this permission as I was an administrator I wrote the following code, testing to see if I could write to C:\Program Files\Outlook...... ``` static void Main(string[] args) { Console.WriteLine("Am I an administrator? " + new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); // Try and open a file in C:\Program Files\Microsoft Office\Office14\BCSLaunch.dll string path = @"C:\Program Files\Microsoft Office\Office14\BCSLaunch.dll"; try { FileIOPermission ioPerm = new FileIOPermission(FileIOPermissionAccess.Read, path); ioPerm.Demand(); string backupPath = Path.ChangeExtension(path, ".bak"); FileIOPermission writeAccess = new FileIOPermission(FileIOPermissionAccess.AllAccess, backupPath); writeAccess.Demand(); Console.WriteLine("Read access is permitted: {0} => {1}",path,SecurityManager.IsGranted(ioPerm)); Console.WriteLine("Write backup file is permitted: {0} => {1}", backupPath, SecurityManager.IsGranted(writeAccess)); File.Copy(path, backupPath); Console.WriteLine("File copied! {0}",backupPath); Console.WriteLine("Deleting file....."); File.Delete(path); } catch (UnauthorizedAccessException uae) { Console.WriteLine(uae.ToString()); } Console.ReadLine(); } ``` So the program causes an `UnauthorizedAccessException` (which I expected), but what I don't understand is that the `Demand()` allows the permission, `SecurityManager` confirms that the permission is granted, but when performing the `File.Copy()` I do get the exception. Although I am happy to see .NET is stopping me, why didn't it notify me earlier when I called `Demand()`? I get the following output: ``` Am I an administrator? False Read access is permitted: C:\Program Files\Microsoft Office\Office14\BCSLaunch.dll => True Write backup file is permitted: C:\Program Files\Microsoft Office\Office14\BCSLaunch.bak => True System.UnauthorizedAccessException: Access to the path 'C:\Program Files\Microsoft Office\Office14\BCSLaunch.bak' is denied. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite) at System.IO.File.Copy(String sourceFileName, String destFileName) at TryAndGetUACPrompt.Program.Main(String[] args) in C:\Users\.............. ``` Please can someone help me understand why I am getting conflicting information? -- Update - 19:30 GMT I have looked through the ACLs of the source file using the following code: ``` Console.WriteLine("ACL Permissions for Source...."); FileSecurity fileSecurityForOriginalPath = new FileSecurity(path, AccessControlSections.Access); foreach (FileSystemAccessRule rule in fileSecurityForOriginalPath.GetAccessRules(true,true,typeof(NTAccount))) { Console.WriteLine("{0} => {1}", rule.FileSystemRights, rule.AccessControlType); } ``` The output is as follows: ``` ACL Permissions for Source.... FullControl => Allow FullControl => Allow ReadAndExecute, Synchronize => Allow ``` Therefore, I do have access to read it. However, I tried to use this code to view the permissions of the backup path and obviously, I get an exception as my backup (destination) file doesn't physically exist, so I can't check permissions on it. I will next try another suggestion to move this check into another method. Update - 19:45 GMT I have refactored the Read/Write demands into another method: ``` private static FileIOPermission CheckWriteAccess(string backupPath) { FileIOPermission writeAccess = new FileIOPermission(FileIOPermissionAccess.AllAccess, backupPath); writeAccess.Demand(); return writeAccess; } private static FileIOPermission CheckReadAccess(string path) { FileIOPermission ioPerm = new FileIOPermission(FileIOPermissionAccess.Read, path); ioPerm.Demand(); return ioPerm; } ``` These both return fine without exception. Therefore if the .NET Security augments the DACLs, I wonder why it thinks it will be successful, if in reality it isn't. -- Update 19:57 GMT Okay, I checked the permissions of the Directory, not the backupFile (destination file) and got this as output (using a foreach on the AuthorizationRuleCollection from .GetAccessRules()) ``` Checking write access in this directory.... FullControl => Allow 268435456 => Allow FullControl => Allow 268435456 => Allow FullControl => Allow 268435456 => Allow ReadAndExecute, Synchronize => Allow -1610612736 => Allow 268435456 => Allow ``` I used an `Enum.Format(typeof(FileSystemAccessRights),rule,"G")` to get the formatting, effectively doing the ToString(), but I just wasn't sure these numbers were correct. Code to output the above: ``` private static DirectorySecurity CheckWriteAccess(string backupPath) { DirectorySecurity writeAccess = new DirectorySecurity( Path.GetDirectoryName(backupPath),AccessControlSections.Access); Console.WriteLine("Checking write access in this directory...."); foreach (FileSystemAccessRule rule in writeAccess.GetAccessRules(true, true, typeof(NTAccount))) { Console.WriteLine("{0} => {1}", Enum.Format(typeof(FileSystemRights),rule.FileSystemRights,"G"), rule.AccessControlType); } return writeAccess; } ```

Original source