views:

598

answers:

3

I've noticed if you change the security settings for a particular directory, you can make that folder no longer "browsable" in windows. In particular, changing the "Read" permission for Administrators to "Deny" will make that folder inaccessible.

The question I now have, is how do I figure this out in code? I following gets me close, but it still ain't right:

/// <summary>
/// Takes in a directory and determines if the current user has read access to it (doesn't work for network drives)
/// THIS IS VERY HACKY
/// </summary>
/// <param name="dInfo">directoryInfo object to the directory to examine</param>
/// <returns>true if read access is available, false otherwise</returns>
public static bool IsDirectoryReadable(DirectoryInfo dInfo)
{
    try
    {
        System.Security.AccessControl.DirectorySecurity dirSec = dInfo.GetAccessControl();
        System.Security.Principal.WindowsIdentity self = System.Security.Principal.WindowsIdentity.GetCurrent();
        System.Security.Principal.WindowsPrincipal selfGroup = new System.Security.Principal.WindowsPrincipal(self);
        // Go through each access rule found for the directory
        foreach (System.Security.AccessControl.FileSystemAccessRule ar in dirSec.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier)))
        {
            if (selfGroup.IsInRole((System.Security.Principal.SecurityIdentifier)ar.IdentityReference))
            {
                // See if the Read right is included
                if ((ar.FileSystemRights & System.Security.AccessControl.FileSystemRights.Read) == System.Security.AccessControl.FileSystemRights.Read)
                {
                    if (ar.AccessControlType == System.Security.AccessControl.AccessControlType.Allow)
                    {
                        // If all of the above are true, we do have read access to this directory
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
        }
        // If we didn't find anything
        return false;
    }
    catch
    {
        // If anything goes wrong, assume false
        return false;
    }
}

I'm close with the above, but I'm still missing something huge. If I right click on a folder to set permissions, I see (in my example) 3 groups or user names: "Administrators, myUserName and SYSTEM". If I set the "Read" to Deny for either "Administrators" or "myUserName" I can no longer browse the directory. If I only set "System" to "Deny", I can still browse it.

There seems to be some sort of permission hierarchy implied, where either myUserName or Administrator supersedes the SYSTEM group/user.

The code above looks for the first Allow for "Read" it finds for my user identity and returns true. I could also write code that looks for the first "Deny" for Read and returns false.

I can set a folder to be Read - "Deny" for SYSTEM and Read - "Allow" for the other two accounts and still read the folder. If I change the code to look for Deny's and it encounters the SYSTEM user identity first, my function will return "false", which is... false. It might very well be Read - "Allow" for the other two accounts.

The problem that I still can't figure out is, how can I determine which user identity permission has priority over all of the others?

+1  A: 

It gets very tricky because ACL's allow inheritance, but they also have a model of most restrictive access. In other words, if you have a DENY anywhere in your user chain to a resource, no matter how many other groups may give you an ALLOW, you are denied. There is a good article on the subect on MSDN.

Nick
+1  A: 

The system group is related to the O/S process and not directly related to your user account. It's what the O/S would use to access the filesystem if there was no user context. Since your application is running as your "username" the permissions come from it and the groups it's in. Don't think you need to be checking System in this case unless I'm missing something.

Update: Keep in mind that Directory.Exists() will also check that you have permissions to read the directory.

Cory Charlton
I've got both "Read" and "List Contents" set to Deny for my current user for a directory. I can't double click into this directory. If I try (myDirectoryInfo.Exists), it shows up as "true". Hmmm... Doesn't seem to be working... Also doesn't work with (Directory.Exists())
Nick
Interesting, says *If you do not have at a minimum read-only permission to the directory, the Exists method will return false.* maybe it means read permissions into the parent folder since you can see the directory but not the contents of it.
Cory Charlton
A: 

The issue isn’t a permission hierarchy. The problem is that your code is returning true or false based on the first matching Role. You really need to evaluate all permissions.

I recently had to deal with this issue... I posted my code here.

Tom Brothers