views:

816

answers:

2

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;
}
+4  A: 

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

x0n
it might also be that ou cannot READ the DLL because it's open by a process exclusively.
x0n
@x0n: I think that would lead to an `IOException` rather than `UnauthorizedAccessException`. (+1 for the answer, though)
Fredrik Mörk
So what you are saying is that .NET doesn't have any user restrictions from within the CLR that would restrict access, hence I'm allowed. BUT .. then I have to interrogate the file system directly and then see if thats blocking it?
Dominic Zukiewicz
@dominic - yes. The CLR CAS system implements what's known as a "sandbox." To use an analogy, it decides whether it will or won't let you try to open a door (IOPermission) depending on the security rules (Evidence). However, when you try to open the door, you find it is locked (ACL.)
x0n
A: 

the Demand Method walks the calls stack and checks the permissions of the caller of the method calling Demand. In this case, you probably don't have any callers and demand by default returns true.

Try moving the code into a different method and call it from Main and see what happens.

This thread might help: http://social.msdn.microsoft.com/Forums/en-US/clr/thread/2604643a-812d-4501-a820-4db36285b72d

Moron