How to Recursively Apply ACL Permissions with setfacl in Linux: Proper Usage of -R Flag for Directories and Files


1 views

When working with Access Control Lists (ACL) in Linux, many administrators expect the -R flag in setfacl to behave like chmod -R, applying permissions uniformly to both directories and files. However, ACLs handle recursion differently due to their more granular permission system.

The command you tried:

setfacl -Rm d:u:foo:rwX test

Specifically sets default ACLs (notice the d: prefix), which only affect directories. This is why subtest/ received the ACL but subtest.txt didn't.

For complete recursive ACL application, you need two separate operations:

# Apply to existing files and directories
setfacl -Rm u:foo:rwX test/

# Set default ACLs for future items
setfacl -Rm d:u:foo:rwX test/

The capital X is crucial - it grants execute permission only if the target is a directory or already has execute permission. This prevents accidentally making scripts executable.

Always verify with:

getfacl -R test/ | less

For more control, you can use find:

# For directories
find test/ -type d -exec setfacl -m d:u:foo:rwX {} +

# For regular files
find test/ -type f -exec setfacl -m u:foo:rw {} +

Remember that:

  • Default ACLs only affect newly created items
  • Existing files need explicit permission setting
  • The order of operations matters when combining default and regular ACLs

Here's how I typically set up a web directory:

# Set default ACLs for future items
setfacl -Rm d:u:www-data:rwX,d:u:deploy:rwX /var/www/

# Apply to existing structure
setfacl -Rm u:www-data:rwX,u:deploy:rwX /var/www/

# Remove execute from files where not needed
find /var/www/ -type f -exec setfacl -m u:www-data:r-X,u:deploy:r-X {} +

When working with Linux filesystem permissions, many administrators encounter a specific challenge with setfacl's recursive flag (-R). The command appears to work partially - applying to directories but skipping files in the recursive operation. Here's the technical breakdown of what's happening:

$ tree test/
test/
├── subtest/
└── subtest.txt

The key lies in understanding the difference between regular ACL entries and default ACL entries (specified with d: prefix). Default ACLs only propagate to:

  • Newly created files/directories
  • Existing directories (when using -R)

This explains why your command:

setfacl -Rm d:u:foo:rwX test

affected subtest/ but not subtest.txt.

Method 1: Combined ACL Setting

For immediate effect on both existing files and directories:

setfacl -Rm u:foo:rwX test    # Applies to existing files and directories
setfacl -Rm d:u:foo:rwX test  # Sets default for future items

Method 2: Using find with setfacl

For more granular control:

find test/ -type d -exec setfacl -Rm d:u:foo:rwX {} +  # Directories
find test/ -type f -exec setfacl -Rm u:foo:rw {} +     # Files

Method 3: XCAPE Permission Flag

The capital X in permissions is special:

setfacl -Rm u:foo:rwX test    # Execute only if directory or already executable

Here's a complete setup for a web directory with mixed content:

# Set existing permissions
setfacl -Rm u:deploy:rwX /var/www/project
setfacl -Rm g:developers:r-X /var/www/project
setfacl -Rm d:u:deploy:rwX /var/www/project
setfacl -Rm d:g:developers:r-X /var/www/project

# Verify with:
getfacl /var/www/project
  • Order of operations matters - set defaults after setting current permissions
  • Remember that X differs from x in significant ways
  • Default ACLs don't automatically apply to symlinks (use -h flag carefully)
  • Consider filesystem limitations (some don't support all ACL features)