1

If I'm using NFSv4 ACLs on FreeBSD, and I change the ACLs on a directory in a way that affects the inherited ACLs of its child files+dirs (and potentially might cascade and affect the children/grandchildren of its child dirs), at what point is that recalculation done, and how is the process managed?

Concrete example: Suppose I have an existing dir hierarchy, and I want to add a new ACL that adds a denial, or removes an allow, for some group. I execute one of the following commands for the top level directory:

  • setfacl -a 0 g:mygroup:dD:fd:deny /path_to_dir
  • setfacl -x g:mygroup:dD:fd:allow /path_to_dir

But it's not clear how ACL propagation works, when it actually takes place, or even whether it happens (or needs to happen) from the docs. Also if files are copied with the wrong ACLs, I can't find a way to recalculate ACLs from the parent, or even whether such a thing exists.

My questions on this example:

  1. Is simply executing a setfacl command enough to trigger propagation of these rules, and (if needed) "cascade" them down the hierarchy, causing permissions/ACLs on all contained objects to be updated?
  2. Alternatively, is runtime recalculation during the setfacl command unnecessary, perhaps because FreeBSD calculates ACLs "on the fly" from the top directory down during any file access, rather than pre-emptively calculating and storing effective ACLs and updating them for all affected objects whenever ACLs change?
  3. If FreeBSD doesn't calculate downwards when the command is executed, and doesn't calculate them "on the fly", when does the new ACL become effective throughout the tree, and/or what must be done to make it effective further down the tree?
  4. If files/dirs exist with incorrect ACLs, is the only way to fix it, to make all ACLs on these files explicitly defined (and forego inheritance)?

Answers that wouldn't be useful:

If propagation is an issue and workarounds are needed, there are a couple of possible answers that might come to mind that don't really answer the question (for me). To help focus good answers, I'm noting them here as being non-answers:

  1. I'm aware that I could set explicit ACLs manually, using find /path_to_dir -exec setfacl to work around any propagation/recalculation issue. But this isn't helpful, because it means replacing inherited ACLs by explicit ACLs throughout. On many clients (Windows especially), explicit/inherited ACLs have different priorities, so this changes how ACLs are calculated, and ACLs that worked before might work differently afterwards. Too easy to break things. Also means that auditing permissions can't just check for files+dirs that aren't inheriting, because too much ACL setup will have moved to non-inherited and need case by case checking. Basically "yuck" :)
  2. I'm also aware that another possible answer might be to copy all affected files/dirs. to a new, parallel location in the same file system, because copying can be forced to create ACLs from scratch and those would be based on current ACLs of the top dir. This isn't applicable since it's usually unrealistic in reality to ask for an entire file system to be duplicated just to change an ACL. Also too easy to break things, disrupt things, messes round with rsync/backups/snapshots (if using zfs with snapshots).

I'd also like to keep to FreeBSD here, because different systems probably check and update acls very differently and the current system I need an answer on, is FreeBSD based.

2

There's definitely lack of documentation out there on this. From what I can tell, based on my own experience, is this:

setfacl does nothing more than add, modify or remove an access control entry (ACE) for a given access control list (ACL). No other ACEs on any other ACLs are affected, even if some of those ACEs were inherited from the ACE that changed. Those other "inherited" ACEs remain unchanged.

An ACE is inherited only at the time the file or directory inheriting it is created.

This means that if you are going to modify an ACE with either the f or d inhertiance bits set, you are responsible for manually "propogating" that change to anything that previously inherited from it IF THAT IS THE BEHAVIOR THAT YOU WANT. In some cases, it might not be, which is probably why FreeBSD doesn't do it automatically for you.

For example:

mkdir -p test_dir
getfacl test_dir
# file: test_dir
# owner: root
# group: wheel
#           owner@:rwxp--aARWcCos:-------:allow
#           group@:r-x---a-R-c--s:-------:allow
#        everyone@:r-x---a-R-c--s:-------:allow
setfacl -m g:staff:read_set:fd:allow test_dir # <- CREATE NEW ACE
getfacl test_dir
# file: test_dir
# owner: root
# group: wheel
#      group:staff:r-----a-R-c---:fd-----:allow <- NEW INHERITING ACE
#           owner@:rwxp--aARWcCos:-------:allow
#           group@:r-x---a-R-c--s:-------:allow
#        everyone@:r-x---a-R-c--s:-------:allow
mkdir -p test_dir/child_dir
getfacl test_dir/child_dir
# file: test_dir/child_dir
# owner: root
# group: wheel
#      group:staff:r-----a-R-c---:fd----I:allow <- NEW ACE INHERITED ON CREATE
#           owner@:rwxp--aARWcCos:-------:allow
#           group@:r-x---a-R-c--s:-------:allow
#        everyone@:r-x---a-R-c--s:-------:allow
touch test_dir/child_file
getfacl test_dir/child_file 
# file: test_dir/child_file
# owner: root
# group: wheel
#      group:staff:r-----a-R-c---:------I:allow <- NEW ACE INHERITED ON CREATE
#           owner@:rw-p--aARWcCos:-------:allow
#           group@:r-----a-R-c--s:-------:allow
#        everyone@:r-----a-R-c--s:-------:allow
setfacl -m g:staff:full_set:fd:allow test_dir # <- MODIFY ACE
getfacl test_dir
# file: test_dir
# owner: root
# group: wheel
#      group:staff:rwxpDdaARWcCos:fd-----:allow <- MODIFIED INHERITING ACE
#           owner@:rwxp--aARWcCos:-------:allow
#           group@:r-x---a-R-c--s:-------:allow
#        everyone@:r-x---a-R-c--s:-------:allow
getfacl test_dir/child_dir
# file: test_dir/child_dir
# owner: root
# group: wheel
#      group:staff:r-----a-R-c---:fd----I:allow <- DID NOT CHANGE
#           owner@:rwxp--aARWcCos:-------:allow
#           group@:r-x---a-R-c--s:-------:allow
#        everyone@:r-x---a-R-c--s:-------:allow
getfacl test_dir/child_file 
# file: test_dir/child_file
# owner: root
# group: wheel
#      group:staff:r-----a-R-c---:------I:allow <- DID NOT CHANGE
#           owner@:rw-p--aARWcCos:-------:allow
#           group@:r-----a-R-c--s:-------:allow
#        everyone@:r-----a-R-c--s:-------:allow

# MODIFY INHERITED ACEs TO MATCH MODIFIED INHERITING ACE
setfacl -m g:staff:full_set:fdI:allow test_dir/child_dir
setfacl -m g:staff:full_set:I:allow test_dir/child_file

So, to answer your questions:

  1. setfacl does not propogate any changes to existing inherited ACEs.
  2. FreeBSD do not recalculate anything on the fly.
  3. Premissions become effective only after you manually set them.
  4. No, you don't have to make them explicit. In your scenario, you probably want to update the existing inherited ACEs (the ones with the I flag set) with the same modifications you made to the inheriting ACE.

Two relevant FreeBSD issues that you might want to watch:

  • This is detailed and informative, but I'm looking for a way to get ACLs auto recalculated for a branch, even if manually triggered, because it's impractical to fix everything explicitly (reasons in OP). Windows has a "reset all acls" option that tells windows to walk+recalc the named directory tree/branch. What can I do to get that action in *nix? – Stilez Jun 2 '18 at 21:08
  • FreeBSD doesn't provide you with something like this. In the Windows world inheritance == propogation, in FreeBSD that is not the case. You'll have to write a script to do what you want to do. I am not aware of anything out there in the wild that will walk the tree and reset permissions in the way that you want after making a change. Sorry, I wish I could be of more help. – mike Jun 2 '18 at 21:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.