How to clone ZFS ACLs from one file to another

access-control-listsolariszfs

I'd like to clone all the ZFS ACLs from one file to another.

With POSIX ACLs this can be done by piping the output of getfacl to setfacl.

Is there an easy and quick way to do this with the NFSv4 style ACLs in ZFS? I know I can read off the output of ls -lV and then enter it as part of a chmod, but I can't seem to find a functional equivalent to the POSIX way of copying ACLs.

Best Answer

Instead of using ls -lV you can use ls -lv which can be fed in to a script to convert it to a sequence of chmod commands to duplicate the ACLs.

E.g. if the ACl looks like this:

$ ls -lv file1
     0:owner@::deny
     1:owner@:read_data/write_data/append_data/write_xattr/execute
         /write_attributes/write_acl/write_owner:allow
     2:group@:read_data/write_data/append_data:deny
     3:group@:execute:allow
     4:everyone@:read_data/write_data/append_data/write_xattr
        /write_attributes/write_acl/write_owner:deny
     5:everyone@:read_xattr/execute/read_attributes/read_acl/synchronize:allow

It should be turned in to the following sequence of chmod commands:

chmod A0=owner@::deny file2
chmod A1=owner@:read_data/write_data/append_data/write_xattr/execute/write_attributes/write_acl/write_owner:allow file2
chmod A2=group@:read_data/write_data/append_data:deny file2
chmod A3=group@:execute:allow file2
chmod A4=everyone@:read_data/write_data/append_data/write_xattr/write_attributes/write_acl/write_owner:deny file2
chmod A5=everyone@:read_xattr/execute/read_attributes/read_acl/synchronize:allow file2

I recently found myself in a situation where a script like the one described above would have been useful, so here's a little Bash script I made (can also be sourced to the shell and run as a function) to print the list of chmod commands necessary to copy the ZFS ACLs from one file to another:

#!/bin/bash

acl_as_chmods () {
# print list of chmod commands to copy the ACL entries from '$1' to '$2'
 [[ -a "$1" ]] 2>/dev/null || {
   echo "Valid reference file required." >&2
   return 1
 }
 ls -vd "$1" | {
   read # first line is not ACL information; bypass
   read ACL_entry
     echo -n "chmod A=${ACL_entry#*:}"
   # if no target file was specified as '$2', use 'TARGET' variable at runtime
   while read ACL_entry || { echo " ${2-\$TARGET}"; false; }
   do
     [[ "$ACL_entry" == [0-9]*:* ]] && \
       echo -en " ${2-\$TARGET}\nchmod A${ACL_entry%%:*}+${ACL_entry#*:}" || \
       echo -n "$ACL_entry"
   done
 }
}

## run as script or source function to shell?
__acl_as_chmods () {
 [[ "${FUNCNAME[1]}" == "source" ]] || acl_as_chmods "$@"
}

__acl_as_chmods "$@"

Here are a couple example usages and their output for file1 from above:

~$ ./acl_as_chmods.sh file1 file2
chmod A=owner@::deny file2
chmod A1+owner@:read_data/write_data/append_data/write_xattr/execute/write_attributes/write_acl/write_owner:allow file2
chmod A2+group@:read_data/write_data/append_data:deny file2
chmod A3+group@:execute:allow file2
chmod A4+everyone@:read_data/write_data/append_data/write_xattr/write_attributes/write_acl/write_owner:deny file2
chmod A5+everyone@:read_xattr/execute/read_attributes/read_acl/synchronize:allow file2

~$ source acl_as_chmods.sh
~$ acl_as_chmods file1
chmod A=owner@::deny $TARGET
chmod A1+owner@:read_data/write_data/append_data/write_xattr/execute/write_attributes/write_acl/write_owner:allow $TARGET
chmod A2+group@:read_data/write_data/append_data:deny $TARGET
chmod A3+group@:execute:allow $TARGET
chmod A4+everyone@:read_data/write_data/append_data/write_xattr/write_attributes/write_acl/write_owner:deny $TARGET
chmod A5+everyone@:read_xattr/execute/read_attributes/read_acl/synchronize:allow $TARGET

If we like, we can even evaluate these chmods directly, if both files are accessible on this host and we wish to copy the ACLs from file1 to file2 immediately:

~$ ls -Vd file*  #BEFORE
-rwx--x--x   1 user user       0 Jun 19 04:12 file1
            owner@:--------------:------:deny
            owner@:rwxp---A-W-Co-:------:allow
            group@:rw-p----------:------:deny
            group@:--x-----------:------:allow
         everyone@:rw-p---A-W-Co-:------:deny
         everyone@:--x---a-R-c--s:------:allow
---x------+  1 user user       0 Jun 19 04:12 file2
            owner@:--x-----------:------:allow

~$ eval "$(acl_as_chmods file1 file2)"

~$ ls -Vd file*  #AFTER 
-rwx--x--x   1 user user       0 Jun 19 04:12 file1
            owner@:--------------:------:deny
            owner@:rwxp---A-W-Co-:------:allow
            group@:rw-p----------:------:deny
            group@:--x-----------:------:allow
         everyone@:rw-p---A-W-Co-:------:deny
         everyone@:--x---a-R-c--s:------:allow
-rwx--x--x   1 user user       0 Jun 19 04:12 file2
            owner@:--------------:------:deny
            owner@:rwxp---A-W-Co-:------:allow
            group@:rw-p----------:------:deny
            group@:--x-----------:------:allow
         everyone@:rw-p---A-W-Co-:------:deny
         everyone@:--x---a-R-c--s:------:allow