Mark A. Donohoe
Mark A. Donohoe

Reputation: 30408

How does Windows resolve conflicting FileSystem permissions/rights?

In the security system of Windows, a user can belong to many groups, and a group can contain other groups. What are the 'rules' for how conflicting permissions get resolved in Windows?

For instance, say a user is in Group A and also in Group B. Group A has 'Deny Read' on a file while 'Group B' has 'Allow Read'. Can the user read the file?

What if the user itself has been denied the rights to read something, but it's in a group where that permission was explicitly allowed?

While I know how to get the permissions for a particular FileSystem resource via the AccessRules and the rights they expose, since the rules target a specific IdentityReference which could be a user or a group, I have seen conflicts and am trying to determine the logic to figure out 'who wins'.

...or is there a known way to say 'Get me all rights for this user, also taking into consideration any memberships' and let the system worry about it? (I'm surprised I haven't found exactly that already. What I'm doing seems like an awful lot of work.)

var Identity = WindowsIdentity.GetCurrent();
var fileInfo = new FileInfo(@"C:\Code\Path\To\Some\File.txt");

// Get all identity references for this user (user's and it's groups)
var identityReferences = new HashSet<IdentityReference>();
identityReferences.Add(Identity.User);
foreach(var group in Identity.Groups)
    identityReferences.Add(group);

// Get all rules for this user on this specific FileInfo
var fileSystemAccessRules = fileInfo.GetAccessControl()
    .GetAccessRules(true, true, typeof(SecurityIdentifier))
    .OfType<FileSystemAccessRule>()
    .Where(rule => identityReferences.Contains(rule.IdentityReference));

FileSystemRights allowedUserRightsMask = 0;
FileSystemRights deniedUserRightsMask  = 0;

// Get mask of all granted, and all denied rules
foreach(var fileSystemAccessRule in fileSystemAccessRules)
{
    var ruleRights = fileSystemAccessRule.FileSystemRights;

    var relevantUserRightsMask = (fileSystemAccessRule.AccessControlType == AccessControlType.Allow)
        ? allowedUserRightsMask
        : deniedUserRightsMask;

    relevantUserRightsMask |= ruleRights;
}

// Do something with the final user rights mask here.

Upvotes: 4

Views: 1308

Answers (2)

Harry Johnston
Harry Johnston

Reputation: 36318

The precedence is determined by the order of the ACEs, as described in the oddly named How AccessCheck Works in MSDN:

The system examines each ACE in sequence until one of the following events occurs:

An access-denied ACE explicitly denies any of the requested access rights to one of the trustees listed in the thread's access token.

One or more access-allowed ACEs for trustees listed in the thread's access token explicitly grant all the requested access rights.

All ACEs have been checked and there is still at least one requested access right that has not been explicitly allowed, in which case, access is implicitly denied.

There is also a standard order in which the ACEs in a DACL should appear, as described in Order of ACEs in a DACL. If the permissions have been set by the built-in Windows tools, the ACEs will be in this order, which is how you get the rules Esteban described in his answer (see referenced article). Note, however, that a DACL does not have to follow this standard. Applications can set a DACL that does not - though it is usually unwise to do so, because it confuses the Windows GUI.

(Note that some APIs may automatically reorder the ACEs in an ACL to the standard order; if you need to retain the actual order of ACEs in an ACL, make sure you are using an API that does not do this.)

To complicate matters, there are also additional rules, such as the fact that the owner of an object has READ_CONTROL and WRITE_DAC granted implicitly, and that there are additional trustees such as INTERACTIVE in a typical access token, not related to group membership.

Typically, the correct behaviour is not to attempt to determine what access rights you have, but rather to simply attempt whatever action you want to take and handle the error if it fails. (In particular, keep in mind that access to a file could fail for a reason other than access rights, such as because the file is in use by another process.)

However, in the rare cases where you really do need to determine the applicable access rights, you can do so using the AuthzAccessCheck() function. Sample code is available in the documentation on the (deprecated and inaccurate) GetEffectiveRightsFromAcl() function.

(I am not familiar enough with .NET to be sure whether it contains a built-in equivalent; I would guess that it does not. However, you can P/Invoke if necessary.)

Upvotes: 1

Esteban Araya
Esteban Araya

Reputation: 29664

As outlined in Understanding Windows NTFS Permissions permission precedence is as follows:

  1. Explicit Deny
  2. Explicit Allow
  3. Inherited Deny
  4. Inherited Allow

So, to answer your question: it depends. Explicit deny always takes precedence; inherited deny, however, "loses" to explicit allow.

See the article for more details on the implications of this.

Upvotes: 2

Related Questions