Index: head/bin/setfacl/setfacl.1 =================================================================== --- head/bin/setfacl/setfacl.1 (revision 287444) +++ head/bin/setfacl/setfacl.1 (revision 287445) @@ -1,490 +1,492 @@ .\"- .\" Copyright (c) 2001 Chris D. Faulhaber .\" Copyright (c) 2011 Edward Tomasz Napierała .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd April 1, 2013 +.Dd September 4, 2015 .Dt SETFACL 1 .Os .Sh NAME .Nm setfacl .Nd set ACL information .Sh SYNOPSIS .Nm .Op Fl bdhkn .Op Fl a Ar position entries .Op Fl m Ar entries .Op Fl M Ar file .Op Fl x Ar entries | position .Op Fl X Ar file .Op Ar .Sh DESCRIPTION The .Nm utility sets discretionary access control information on the specified file(s). If no files are specified, or the list consists of the only .Sq Fl , the file names are taken from the standard input. .Pp The following options are available: .Bl -tag -width indent .It Fl a Ar position entries Modify the ACL on the specified files by inserting new ACL entries specified in .Ar entries , starting at position .Ar position , counting from zero. This option is only applicable to NFSv4 ACLs. .It Fl b Remove all ACL entries except for the three required entries (POSIX.1e ACLs) or six "canonical" entries (NFSv4 ACLs). If the POSIX.1e ACL contains a .Dq Li mask entry, the permissions of the .Dq Li group entry in the resulting ACL will be set to the permission associated with both the .Dq Li group and .Dq Li mask entries of the current ACL. .It Fl d The operations apply to the default ACL entries instead of access ACL entries. Currently only directories may have default ACL's. This option is not applicable to NFSv4 ACLs. .It Fl h If the target of the operation is a symbolic link, perform the operation on the symbolic link itself, rather than following the link. .It Fl k Delete any default ACL entries on the specified files. It is not considered an error if the specified files do not have any default ACL entries. An error will be reported if any of the specified files cannot have a default entry (i.e.\& non-directories). This option is not applicable to NFSv4 ACLs. .It Fl m Ar entries Modify the ACL on the specified file. New entries will be added, and existing entries will be modified according to the .Ar entries argument. For NFSv4 ACLs, it is recommended to use the .Fl a and .Fl x options instead. .It Fl M Ar file Modify the ACL entries on the specified files by adding new ACL entries and modifying existing ACL entries with the ACL entries specified in the file .Ar file . If .Ar file is .Fl , the input is taken from stdin. .It Fl n Do not recalculate the permissions associated with the ACL mask entry. This option is not applicable to NFSv4 ACLs. .It Fl x Ar entries | position If .Ar entries is specified, remove the ACL entries specified there from the access or default ACL of the specified files. Otherwise, remove entry at index .Ar position , counting from zero. .It Fl X Ar file Remove the ACL entries specified in the file .Ar file from the access or default ACL of the specified files. .El .Pp The above options are evaluated in the order specified on the command-line. .Sh POSIX.1e ACL ENTRIES A POSIX.1E ACL entry contains three colon-separated fields: an ACL tag, an ACL qualifier, and discretionary access permissions: .Bl -tag -width indent .It Ar "ACL tag" The ACL tag specifies the ACL entry type and consists of one of the following: .Dq Li user or .Ql u specifying the access granted to the owner of the file or a specified user; .Dq Li group or .Ql g specifying the access granted to the file owning group or a specified group; .Dq Li other or .Ql o specifying the access granted to any process that does not match any user or group ACL entry; .Dq Li mask or .Ql m specifying the maximum access granted to any ACL entry except the .Dq Li user ACL entry for the file owner and the .Dq Li other ACL entry. .It Ar "ACL qualifier" The ACL qualifier field describes the user or group associated with the ACL entry. It may consist of one of the following: uid or user name, gid or group name, or empty. For .Dq Li user ACL entries, an empty field specifies access granted to the file owner. For .Dq Li group ACL entries, an empty field specifies access granted to the file owning group. .Dq Li mask and .Dq Li other ACL entries do not use this field. .It Ar "access permissions" The access permissions field contains up to one of each of the following: .Ql r , .Ql w , and .Ql x to set read, write, and execute permissions, respectively. Each of these may be excluded or replaced with a .Ql - character to indicate no access. .El .Pp A .Dq Li mask ACL entry is required on a file with any ACL entries other than the default .Dq Li user , .Dq Li group , and .Dq Li other ACL entries. If the .Fl n option is not specified and no .Dq Li mask ACL entry was specified, the .Nm utility will apply a .Dq Li mask ACL entry consisting of the union of the permissions associated with all .Dq Li group ACL entries in the resulting ACL. .Pp Traditional POSIX interfaces acting on file system object modes have modified semantics in the presence of POSIX.1e extended ACLs. When a mask entry is present on the access ACL of an object, the mask entry is substituted for the group bits; this occurs in programs such as .Xr stat 1 or .Xr ls 1 . When the mode is modified on an object that has a mask entry, the changes applied to the group bits will actually be applied to the mask entry. These semantics provide for greater application compatibility: applications modifying the mode instead of the ACL will see conservative behavior, limiting the effective rights granted by all of the additional user and group entries; this occurs in programs such as .Xr chmod 1 . .Pp ACL entries applied from a file using the .Fl M or .Fl X options shall be of the following form: one ACL entry per line, as previously specified; whitespace is ignored; any text after a .Ql # is ignored (comments). .Pp When POSIX.1e ACL entries are evaluated, the access check algorithm checks the ACL entries in the following order: file owner, .Dq Li user ACL entries, file owning group, .Dq Li group ACL entries, and .Dq Li other ACL entry. .Pp Multiple ACL entries specified on the command line are separated by commas. .Pp It is possible for files and directories to inherit ACL entries from their parent directory. This is accomplished through the use of the default ACL. It should be noted that before you can specify a default ACL, the mandatory ACL entries for user, group, other and mask must be set. For more details see the examples below. Default ACLs can be created by using .Fl d . .Sh NFSv4 ACL ENTRIES An NFSv4 ACL entry contains four or five colon-separated fields: an ACL tag, an ACL qualifier (only for .Dq Li user and .Dq Li group tags), discretionary access permissions, ACL inheritance flags, and ACL type: .Bl -tag -width indent .It Ar "ACL tag" The ACL tag specifies the ACL entry type and consists of one of the following: .Dq Li user or .Ql u specifying the access granted to the specified user; .Dq Li group or .Ql g specifying the access granted to the specified group; .Dq Li owner@ specifying the access granted to the owner of the file; .Dq Li group@ specifying the access granted to the file owning group; .Dq Li everyone@ specifying everyone. Note that .Dq Li everyone@ is not the same as traditional Unix .Dq Li other - it means, literally, everyone, including file owner and owning group. .It Ar "ACL qualifier" The ACL qualifier field describes the user or group associated with the ACL entry. It may consist of one of the following: uid or user name, or gid or group name. In entries whose tag type is one of .Dq Li owner@ , .Dq Li group@ , or .Dq Li everyone@ , this field is omitted altogether, including the trailing comma. .It Ar "access permissions" Access permissions may be specified in either short or long form. Short and long forms may not be mixed. Permissions in long form are separated by the .Ql / character; in short form, they are concatenated together. Valid permissions are: .Bl -tag -width ".Dv modify_set" .It Short Long .It r read_data .It w write_data .It x execute .It p append_data .It D delete_child .It d delete .It a read_attributes .It A write_attributes .It R read_xattr .It W write_xattr .It c read_acl .It C write_acl .It o write_owner .It s synchronize .El .Pp In addition, the following permission sets may be used: .Bl -tag -width ".Dv modify_set" .It Set Permissions .It full_set all permissions, as shown above .It modify_set all permissions except write_acl and write_owner .It read_set read_data, read_attributes, read_xattr and read_acl .It write_set write_data, append_data, write_attributes and write_xattr .El .It Ar "ACL inheritance flags" Inheritance flags may be specified in either short or long form. Short and long forms may not be mixed. Access flags in long form are separated by the .Ql / character; in short form, they are concatenated together. Valid inheritance flags are: .Bl -tag -width ".Dv short" .It Short Long .It f file_inherit .It d dir_inherit .It i inherit_only .It n no_propagate +.It I +inherited .El .Pp -Inheritance flags may be only set on directories. +Other than the "inherited" flag, inheritance flags may be only set on directories. .It Ar "ACL type" The ACL type field is either .Dq Li allow or .Dq Li deny . .El .Pp ACL entries applied from a file using the .Fl M or .Fl X options shall be of the following form: one ACL entry per line, as previously specified; whitespace is ignored; any text after a .Ql # is ignored (comments). .Pp NFSv4 ACL entries are evaluated in their visible order. .Pp Multiple ACL entries specified on the command line are separated by commas. .Pp Note that the file owner is always granted the read_acl, write_acl, read_attributes, and write_attributes permissions, even if the ACL would deny it. .Sh EXIT STATUS .Ex -std .Sh EXAMPLES .Dl setfacl -d -m u::rwx,g::rx,o::rx,mask::rwx dir .Dl setfacl -d -m g:admins:rwx dir .Pp The first command sets the mandatory elements of the POSIX.1e default ACL. The second command specifies that users in group admins can have read, write, and execute permissions for directory named "dir". It should be noted that any files or directories created underneath "dir" will inherit these default ACLs upon creation. .Pp .Dl setfacl -m u::rwx,g:mail:rw file .Pp Sets read, write, and execute permissions for the .Pa file owner's POSIX.1e ACL entry and read and write permissions for group mail on .Pa file . .Pp .Dl setfacl -m owner@:rwxp::allow,g:mail:rwp::allow file .Pp Semantically equal to the example above, but for NFSv4 ACL. .Pp .Dl setfacl -M file1 file2 .Pp Sets/updates the ACL entries contained in .Pa file1 on .Pa file2 . .Pp .Dl setfacl -x g:mail:rw file .Pp Remove the group mail POSIX.1e ACL entry containing read/write permissions from .Pa file . .Pp .Dl setfacl -x0 file .Pp Remove the first entry from the NFSv4 ACL from .Pa file . .Pp .Dl setfacl -bn file .Pp Remove all .Dq Li access ACL entries except for the three required from .Pa file . .Pp .Dl getfacl file1 | setfacl -b -n -M - file2 .Pp Copy ACL entries from .Pa file1 to .Pa file2 . .Sh SEE ALSO .Xr getfacl 1 , .Xr acl 3 , .Xr getextattr 8 , .Xr setextattr 8 , .Xr acl 9 , .Xr extattr 9 .Sh STANDARDS The .Nm utility is expected to be .Tn IEEE Std 1003.2c compliant. .Sh HISTORY Extended Attribute and Access Control List support was developed as part of the .Tn TrustedBSD Project and introduced in .Fx 5.0 . NFSv4 ACL support was introduced in .Fx 8.1 . .Sh AUTHORS .An -nosplit The .Nm utility was written by .An Chris D. Faulhaber Aq Mt jedgar@fxp.org . NFSv4 ACL support was implemented by .An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org . Index: head/lib/libc/posix1e/acl_add_flag_np.3 =================================================================== --- head/lib/libc/posix1e/acl_add_flag_np.3 (revision 287444) +++ head/lib/libc/posix1e/acl_add_flag_np.3 (revision 287445) @@ -1,97 +1,98 @@ .\"- .\" Copyright (c) 2008, 2009 Edward Tomasz Napierala .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd October 30, 2014 +.Dd September 4, 2015 .Dt ACL_ADD_FLAG_NP 3 .Os .Sh NAME .Nm acl_add_flag_np .Nd add flags to a flagset .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/types.h .In sys/acl.h .Ft int .Fn acl_add_flag_np "acl_flagset_t flagset_d" "acl_flag_t flag" .Sh DESCRIPTION The .Fn acl_add_flag_np function is a non-portable call that adds the NFSv4 ACL flags contained in .Fa flags to the flagset .Fa flagset_d . .Pp Note: it is not considered an error to attempt to add flags that already exist in the flagset. .Pp Valid values are: .Bl -column -offset 3n "ACL_ENTRY_NO_PROPAGATE_INHERIT" .It ACL_ENTRY_FILE_INHERIT Ta "Will be inherited by files." .It ACL_ENTRY_DIRECTORY_INHERIT Ta "Will be inherited by directories." .It ACL_ENTRY_NO_PROPAGATE_INHERIT Ta "Will not propagate." .It ACL_ENTRY_INHERIT_ONLY Ta "Inherit-only." +.It ACL_ENTRY_INHERITED Ta "Inherited from parent" .El .Sh RETURN VALUES .Rv -std acl_add_flag_np .Sh ERRORS The .Fn acl_add_flag_np function fails if: .Bl -tag -width Er .It Bq Er EINVAL Argument .Fa flagset_d is not a valid descriptor for a flagset within an ACL entry. Argument .Fa flag does not contain a valid .Vt acl_flag_t value. .El .Sh SEE ALSO .Xr acl 3 , .Xr acl_clear_flags_np 3 , .Xr acl_delete_flag_np 3 , .Xr acl_get_flagset_np 3 , .Xr acl_set_flagset_np 3 , .Xr posix1e 3 .Sh STANDARDS POSIX.1e is described in IEEE POSIX.1e draft 17. .Sh HISTORY POSIX.1e support was introduced in .Fx 4.0 . The .Fn acl_add_flag_np function was added in .Fx 8.0 . .Sh AUTHORS The .Fn acl_add_flag_np function was written by .An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org . Index: head/lib/libc/posix1e/acl_support_nfs4.c =================================================================== --- head/lib/libc/posix1e/acl_support_nfs4.c (revision 287444) +++ head/lib/libc/posix1e/acl_support_nfs4.c (revision 287445) @@ -1,260 +1,261 @@ /*- * Copyright (c) 2008, 2009 Edward Tomasz Napierała * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "acl_support.h" struct flagnames_struct { uint32_t flag; const char *name; char letter; }; struct flagnames_struct a_flags[] = {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'}, { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'}, { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'}, { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'}, { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'}, { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'}, + { ACL_ENTRY_INHERITED, "inherited", 'I' }, /* * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it * in the "flags" field. There is no ACE_OWNER, ACE_GROUP or * ACE_EVERYONE either, for obvious reasons. */ { 0, 0, 0}}; struct flagnames_struct a_access_masks[] = {{ ACL_READ_DATA, "read_data", 'r'}, { ACL_WRITE_DATA, "write_data", 'w'}, { ACL_EXECUTE, "execute", 'x'}, { ACL_APPEND_DATA, "append_data", 'p'}, { ACL_DELETE_CHILD, "delete_child", 'D'}, { ACL_DELETE, "delete", 'd'}, { ACL_READ_ATTRIBUTES, "read_attributes", 'a'}, { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'}, { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'}, { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'}, { ACL_READ_ACL, "read_acl", 'c'}, { ACL_WRITE_ACL, "write_acl", 'C'}, { ACL_WRITE_OWNER, "write_owner", 'o'}, { ACL_SYNCHRONIZE, "synchronize", 's'}, { ACL_FULL_SET, "full_set", '\0'}, { ACL_MODIFY_SET, "modify_set", '\0'}, { ACL_READ_SET, "read_set", '\0'}, { ACL_WRITE_SET, "write_set", '\0'}, { 0, 0, 0}}; static const char * format_flag(uint32_t *var, const struct flagnames_struct *flags) { for (; flags->name != 0; flags++) { if ((flags->flag & *var) == 0) continue; *var &= ~flags->flag; return (flags->name); } return (NULL); } static int format_flags_verbose(char *str, size_t size, uint32_t var, const struct flagnames_struct *flags) { size_t off = 0; const char *tmp; while ((tmp = format_flag(&var, flags)) != NULL) { off += snprintf(str + off, size - off, "%s/", tmp); assert (off < size); } /* If there were any flags added... */ if (off > 0) { off--; /* ... then remove the last slash. */ assert(str[off] == '/'); } str[off] = '\0'; return (0); } static int format_flags_compact(char *str, size_t size, uint32_t var, const struct flagnames_struct *flags) { size_t i; for (i = 0; flags[i].letter != '\0'; i++) { assert(i < size); if ((flags[i].flag & var) == 0) str[i] = '-'; else str[i] = flags[i].letter; } str[i] = '\0'; return (0); } static int parse_flags_verbose(const char *strp, uint32_t *var, const struct flagnames_struct *flags, const char *flags_name, int *try_compact) { int i, found, ever_found = 0; char *str, *flag; str = strdup(strp); *try_compact = 0; *var = 0; while (str != NULL) { flag = strsep(&str, "/:"); found = 0; for (i = 0; flags[i].name != NULL; i++) { if (strcmp(flags[i].name, flag) == 0) { *var |= flags[i].flag; found = 1; ever_found = 1; } } if (!found) { if (ever_found) warnx("malformed ACL: \"%s\" field contains " "invalid flag \"%s\"", flags_name, flag); else *try_compact = 1; free(str); return (-1); } } free(str); return (0); } static int parse_flags_compact(const char *str, uint32_t *var, const struct flagnames_struct *flags, const char *flags_name) { int i, j, found; *var = 0; for (i = 0;; i++) { if (str[i] == '\0') return (0); /* Ignore minus signs. */ if (str[i] == '-') continue; found = 0; for (j = 0; flags[j].name != NULL; j++) { if (flags[j].letter == str[i]) { *var |= flags[j].flag; found = 1; break; } } if (!found) { warnx("malformed ACL: \"%s\" field contains " "invalid flag \"%c\"", flags_name, str[i]); return (-1); } } } int _nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose) { if (verbose) return (format_flags_verbose(str, size, var, a_flags)); return (format_flags_compact(str, size, var, a_flags)); } int _nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose) { if (verbose) return (format_flags_verbose(str, size, var, a_access_masks)); return (format_flags_compact(str, size, var, a_access_masks)); } int _nfs4_parse_flags(const char *str, acl_flag_t *flags) { int error, try_compact; int tmpflags; error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact); if (error && try_compact) error = parse_flags_compact(str, &tmpflags, a_flags, "flags"); *flags = tmpflags; return (error); } int _nfs4_parse_access_mask(const char *str, acl_perm_t *perms) { int error, try_compact; int tmpperms; error = parse_flags_verbose(str, &tmpperms, a_access_masks, "access permissions", &try_compact); if (error && try_compact) error = parse_flags_compact(str, &tmpperms, a_access_masks, "access permissions"); *perms = tmpperms; return (error); } Index: head/share/man/man9/acl.9 =================================================================== --- head/share/man/man9/acl.9 (revision 287444) +++ head/share/man/man9/acl.9 (revision 287445) @@ -1,219 +1,225 @@ .\"- .\" Copyright (c) 1999-2001 Robert N. M. Watson .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd September 18, 2009 +.Dd September 4, 2015 .Dt ACL 9 .Os .Sh NAME .Nm acl .Nd virtual file system access control lists .Sh SYNOPSIS .In sys/param.h .In sys/vnode.h .In sys/acl.h .Pp In the kernel configuration file: .Cd "options UFS_ACL" .Sh DESCRIPTION Access control lists, or ACLs, allow fine-grained specification of rights for vnodes representing files and directories. However, as there are a plethora of file systems with differing ACL semantics, the vnode interface is aware only of the syntax of ACLs, relying on the underlying file system to implement the details. Depending on the underlying file system, each file or directory may have zero or more ACLs associated with it, named using the .Fa type field of the appropriate vnode ACL calls: .Xr VOP_ACLCHECK 9 , .Xr VOP_GETACL 9 , and .Xr VOP_SETACL 9 . .Pp Currently, each ACL is represented in-kernel by a fixed-size .Vt acl structure, defined as follows: .Bd -literal -offset indent struct acl { unsigned int acl_maxcnt; unsigned int acl_cnt; int acl_spare[4]; struct acl_entry acl_entry[ACL_MAX_ENTRIES]; }; .Ed .Pp An ACL is constructed from a fixed size array of ACL entries, each of which consists of a set of permissions, principal namespace, and principal identifier. In this implementation, the .Vt acl_maxcnt field is always set to .Dv ACL_MAX_ENTRIES . .Pp Each individual ACL entry is of the type .Vt acl_entry_t , which is a structure with the following members: .Bl -tag -width 2n .It Vt acl_tag_t Va ae_tag The following is a list of definitions of ACL types to be set in .Va ae_tag : .Pp .Bl -tag -width ".Dv ACL_UNDEFINED_FIELD" -offset indent -compact .It Dv ACL_UNDEFINED_FIELD Undefined ACL type. .It Dv ACL_USER_OBJ Discretionary access rights for processes whose effective user ID matches the user ID of the file's owner. .It Dv ACL_USER Discretionary access rights for processes whose effective user ID matches the ACL entry qualifier. .It Dv ACL_GROUP_OBJ Discretionary access rights for processes whose effective group ID or any supplemental groups match the group ID of the file's owner. .It Dv ACL_GROUP Discretionary access rights for processes whose effective group ID or any supplemental groups match the ACL entry qualifier. .It Dv ACL_MASK The maximum discretionary access rights that can be granted to a process in the file group class. This is only valid for POSIX.1e ACLs. .It Dv ACL_OTHER Discretionary access rights for processes not covered by any other ACL entry. This is only valid for POSIX.1e ACLs. .It Dv ACL_OTHER_OBJ Same as .Dv ACL_OTHER . .It Dv ACL_EVERYONE Discretionary access rights for all users. This is only valid for NFSv4 ACLs. .El .Pp Each POSIX.1e ACL must contain exactly one .Dv ACL_USER_OBJ , one .Dv ACL_GROUP_OBJ , and one .Dv ACL_OTHER . If any of .Dv ACL_USER , .Dv ACL_GROUP , or .Dv ACL_OTHER are present, then exactly one .Dv ACL_MASK entry should be present. .It Vt uid_t Va ae_id The ID of user for whom this ACL describes access permissions. For entries other than .Dv ACL_USER and .Dv ACL_GROUP , this field should be set to .Dv ACL_UNDEFINED_ID . .It Vt acl_perm_t Va ae_perm This field defines what kind of access the process matching this ACL has for accessing the associated file. For POSIX.1e ACLs, the following are valid: .Bl -tag -width ".Dv ACL_WRITE_NAMED_ATTRS" .It Dv ACL_EXECUTE The process may execute the associated file. .It Dv ACL_WRITE The process may write to the associated file. .It Dv ACL_READ The process may read from the associated file. .It Dv ACL_PERM_NONE The process has no read, write or execute permissions to the associated file. .El .Pp For NFSv4 ACLs, the following are valid: .Bl -tag -width ".Dv ACL_WRITE_NAMED_ATTRS" .It Dv ACL_READ_DATA The process may read from the associated file. .It Dv ACL_LIST_DIRECTORY Same as .Dv ACL_READ_DATA . .It Dv ACL_WRITE_DATA The process may write to the associated file. .It Dv ACL_ADD_FILE Same as .Dv ACL_ACL_WRITE_DATA . .It Dv ACL_APPEND_DATA .It Dv ACL_ADD_SUBDIRECTORY Same as .Dv ACL_APPEND_DATA . .It Dv ACL_READ_NAMED_ATTRS Ignored. .It Dv ACL_WRITE_NAMED_ATTRS Ignored. .It Dv ACL_EXECUTE The process may execute the associated file. .It Dv ACL_DELETE_CHILD .It Dv ACL_READ_ATTRIBUTES .It Dv ACL_WRITE_ATTRIBUTES .It Dv ACL_DELETE .It Dv ACL_READ_ACL .It Dv ACL_WRITE_ACL .It Dv ACL_WRITE_OWNER .It Dv ACL_SYNCHRONIZE Ignored. .El .It Vt acl_entry_type_t Va ae_entry_type This field defines the type of NFSv4 ACL entry. It is not used with POSIX.1e ACLs. The following values are valid: .Bl -tag -width ".Dv ACL_WRITE_NAMED_ATTRS" .It Dv ACL_ENTRY_TYPE_ALLOW .It Dv ACL_ENTRY_TYPE_DENY .El .It Vt acl_flag_t Va ae_flags This field defines the inheritance flags of NFSv4 ACL entry. It is not used with POSIX.1e ACLs. The following values are valid: .Bl -tag -width ".Dv ACL_ENTRY_DIRECTORY_INHERIT" .It Dv ACL_ENTRY_FILE_INHERIT .It Dv ACL_ENTRY_DIRECTORY_INHERIT .It Dv ACL_ENTRY_NO_PROPAGATE_INHERIT .It Dv ACL_ENTRY_INHERIT_ONLY +.It Dv ACL_ENTRY_INHERITED .El +The +.Dv ACL_ENTRY_INHERITED +flag is set on an ACE that has been inherited from its parent. +It may also be set programmatically, and is valid on both files +and directories. .El .Sh SEE ALSO .Xr acl 3 , .Xr vaccess 9 , .Xr vaccess_acl_nfs4 9 , .Xr vaccess_acl_posix1e 9 , .Xr VFS 9 , .Xr VOP_ACLCHECK 9 , .Xr VOP_GETACL 9 , .Xr VOP_SETACL 9 .Sh AUTHORS This manual page was written by .An Robert Watson . Index: head/sys/cddl/compat/opensolaris/kern/opensolaris_acl.c =================================================================== --- head/sys/cddl/compat/opensolaris/kern/opensolaris_acl.c (revision 287444) +++ head/sys/cddl/compat/opensolaris/kern/opensolaris_acl.c (revision 287445) @@ -1,219 +1,221 @@ /*- * Copyright (c) 2008, 2009 Edward Tomasz Napierała * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include struct zfs2bsd { uint32_t zb_zfs; int zb_bsd; }; struct zfs2bsd perms[] = {{ACE_READ_DATA, ACL_READ_DATA}, {ACE_WRITE_DATA, ACL_WRITE_DATA}, {ACE_EXECUTE, ACL_EXECUTE}, {ACE_APPEND_DATA, ACL_APPEND_DATA}, {ACE_DELETE_CHILD, ACL_DELETE_CHILD}, {ACE_DELETE, ACL_DELETE}, {ACE_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, {ACE_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, {ACE_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, {ACE_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, {ACE_READ_ACL, ACL_READ_ACL}, {ACE_WRITE_ACL, ACL_WRITE_ACL}, {ACE_WRITE_OWNER, ACL_WRITE_OWNER}, {ACE_SYNCHRONIZE, ACL_SYNCHRONIZE}, {0, 0}}; struct zfs2bsd flags[] = {{ACE_FILE_INHERIT_ACE, ACL_ENTRY_FILE_INHERIT}, {ACE_DIRECTORY_INHERIT_ACE, ACL_ENTRY_DIRECTORY_INHERIT}, {ACE_NO_PROPAGATE_INHERIT_ACE, ACL_ENTRY_NO_PROPAGATE_INHERIT}, {ACE_INHERIT_ONLY_ACE, ACL_ENTRY_INHERIT_ONLY}, + {ACE_INHERITED_ACE, + ACL_ENTRY_INHERITED}, {ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ACL_ENTRY_SUCCESSFUL_ACCESS}, {ACE_FAILED_ACCESS_ACE_FLAG, ACL_ENTRY_FAILED_ACCESS}, {0, 0}}; static int _bsd_from_zfs(uint32_t zfs, const struct zfs2bsd *table) { const struct zfs2bsd *tmp; int bsd = 0; for (tmp = table; tmp->zb_zfs != 0; tmp++) { if (zfs & tmp->zb_zfs) bsd |= tmp->zb_bsd; } return (bsd); } static uint32_t _zfs_from_bsd(int bsd, const struct zfs2bsd *table) { const struct zfs2bsd *tmp; uint32_t zfs = 0; for (tmp = table; tmp->zb_bsd != 0; tmp++) { if (bsd & tmp->zb_bsd) zfs |= tmp->zb_zfs; } return (zfs); } int acl_from_aces(struct acl *aclp, const ace_t *aces, int nentries) { int i; struct acl_entry *entry; const ace_t *ace; if (nentries < 1) { printf("acl_from_aces: empty ZFS ACL; returning EINVAL.\n"); return (EINVAL); } if (nentries > ACL_MAX_ENTRIES) { /* * I believe it may happen only when moving a pool * from SunOS to FreeBSD. */ printf("acl_from_aces: ZFS ACL too big to fit " "into 'struct acl'; returning EINVAL.\n"); return (EINVAL); } bzero(aclp, sizeof(*aclp)); aclp->acl_maxcnt = ACL_MAX_ENTRIES; aclp->acl_cnt = nentries; for (i = 0; i < nentries; i++) { entry = &(aclp->acl_entry[i]); ace = &(aces[i]); if (ace->a_flags & ACE_OWNER) entry->ae_tag = ACL_USER_OBJ; else if (ace->a_flags & ACE_GROUP) entry->ae_tag = ACL_GROUP_OBJ; else if (ace->a_flags & ACE_EVERYONE) entry->ae_tag = ACL_EVERYONE; else if (ace->a_flags & ACE_IDENTIFIER_GROUP) entry->ae_tag = ACL_GROUP; else entry->ae_tag = ACL_USER; if (entry->ae_tag == ACL_USER || entry->ae_tag == ACL_GROUP) entry->ae_id = ace->a_who; else entry->ae_id = ACL_UNDEFINED_ID; entry->ae_perm = _bsd_from_zfs(ace->a_access_mask, perms); entry->ae_flags = _bsd_from_zfs(ace->a_flags, flags); switch (ace->a_type) { case ACE_ACCESS_ALLOWED_ACE_TYPE: entry->ae_entry_type = ACL_ENTRY_TYPE_ALLOW; break; case ACE_ACCESS_DENIED_ACE_TYPE: entry->ae_entry_type = ACL_ENTRY_TYPE_DENY; break; case ACE_SYSTEM_AUDIT_ACE_TYPE: entry->ae_entry_type = ACL_ENTRY_TYPE_AUDIT; break; case ACE_SYSTEM_ALARM_ACE_TYPE: entry->ae_entry_type = ACL_ENTRY_TYPE_ALARM; break; default: panic("acl_from_aces: a_type is 0x%x", ace->a_type); } } return (0); } void aces_from_acl(ace_t *aces, int *nentries, const struct acl *aclp) { int i; const struct acl_entry *entry; ace_t *ace; bzero(aces, sizeof(*aces) * aclp->acl_cnt); *nentries = aclp->acl_cnt; for (i = 0; i < aclp->acl_cnt; i++) { entry = &(aclp->acl_entry[i]); ace = &(aces[i]); ace->a_who = entry->ae_id; if (entry->ae_tag == ACL_USER_OBJ) ace->a_flags = ACE_OWNER; else if (entry->ae_tag == ACL_GROUP_OBJ) ace->a_flags = (ACE_GROUP | ACE_IDENTIFIER_GROUP); else if (entry->ae_tag == ACL_GROUP) ace->a_flags = ACE_IDENTIFIER_GROUP; else if (entry->ae_tag == ACL_EVERYONE) ace->a_flags = ACE_EVERYONE; else /* ACL_USER */ ace->a_flags = 0; ace->a_access_mask = _zfs_from_bsd(entry->ae_perm, perms); ace->a_flags |= _zfs_from_bsd(entry->ae_flags, flags); switch (entry->ae_entry_type) { case ACL_ENTRY_TYPE_ALLOW: ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; break; case ACL_ENTRY_TYPE_DENY: ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE; break; case ACL_ENTRY_TYPE_ALARM: ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE; break; case ACL_ENTRY_TYPE_AUDIT: ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE; break; default: panic("aces_from_acl: ae_entry_type is 0x%x", entry->ae_entry_type); } } } Index: head/sys/cddl/contrib/opensolaris/uts/common/sys/acl.h =================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/sys/acl.h (revision 287444) +++ head/sys/cddl/contrib/opensolaris/uts/common/sys/acl.h (revision 287445) @@ -1,311 +1,312 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2014 Garrett D'Amore * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_ACL_H #define _SYS_ACL_H #include #include #if defined(_KERNEL) /* * When compiling OpenSolaris kernel code, this file is getting * included instead of FreeBSD one. Pull the original sys/acl.h as well. */ #undef _SYS_ACL_H #include_next #define _SYS_ACL_H #endif /* _KERNEL */ #ifdef __cplusplus extern "C" { #endif #define MAX_ACL_ENTRIES (1024) /* max entries of each type */ typedef struct { int a_type; /* the type of ACL entry */ uid_t a_id; /* the entry in -uid or gid */ o_mode_t a_perm; /* the permission field */ } aclent_t; typedef struct ace { uid_t a_who; /* uid or gid */ uint32_t a_access_mask; /* read,write,... */ uint16_t a_flags; /* see below */ uint16_t a_type; /* allow or deny */ } ace_t; #ifndef _KERNEL typedef struct acl_info acl_t; #endif /* * The following are Defined types for an aclent_t. */ #define USER_OBJ (0x01) /* object owner */ #define USER (0x02) /* additional users */ #define GROUP_OBJ (0x04) /* owning group of the object */ #define GROUP (0x08) /* additional groups */ #define CLASS_OBJ (0x10) /* file group class and mask entry */ #define OTHER_OBJ (0x20) /* other entry for the object */ #define ACL_DEFAULT (0x1000) /* default flag */ /* default object owner */ #define DEF_USER_OBJ (ACL_DEFAULT | USER_OBJ) /* default additional users */ #define DEF_USER (ACL_DEFAULT | USER) /* default owning group */ #define DEF_GROUP_OBJ (ACL_DEFAULT | GROUP_OBJ) /* default additional groups */ #define DEF_GROUP (ACL_DEFAULT | GROUP) /* default mask entry */ #define DEF_CLASS_OBJ (ACL_DEFAULT | CLASS_OBJ) /* default other entry */ #define DEF_OTHER_OBJ (ACL_DEFAULT | OTHER_OBJ) /* * The following are defined for ace_t. */ #define ACE_READ_DATA 0x00000001 #define ACE_LIST_DIRECTORY 0x00000001 #define ACE_WRITE_DATA 0x00000002 #define ACE_ADD_FILE 0x00000002 #define ACE_APPEND_DATA 0x00000004 #define ACE_ADD_SUBDIRECTORY 0x00000004 #define ACE_READ_NAMED_ATTRS 0x00000008 #define ACE_WRITE_NAMED_ATTRS 0x00000010 #define ACE_EXECUTE 0x00000020 #define ACE_DELETE_CHILD 0x00000040 #define ACE_READ_ATTRIBUTES 0x00000080 #define ACE_WRITE_ATTRIBUTES 0x00000100 #define ACE_DELETE 0x00010000 #define ACE_READ_ACL 0x00020000 #define ACE_WRITE_ACL 0x00040000 #define ACE_WRITE_OWNER 0x00080000 #define ACE_SYNCHRONIZE 0x00100000 #define ACE_FILE_INHERIT_ACE 0x0001 #define ACE_DIRECTORY_INHERIT_ACE 0x0002 #define ACE_NO_PROPAGATE_INHERIT_ACE 0x0004 #define ACE_INHERIT_ONLY_ACE 0x0008 #define ACE_SUCCESSFUL_ACCESS_ACE_FLAG 0x0010 #define ACE_FAILED_ACCESS_ACE_FLAG 0x0020 #define ACE_IDENTIFIER_GROUP 0x0040 #define ACE_INHERITED_ACE 0x0080 #define ACE_OWNER 0x1000 #define ACE_GROUP 0x2000 #define ACE_EVERYONE 0x4000 #define ACE_ACCESS_ALLOWED_ACE_TYPE 0x0000 #define ACE_ACCESS_DENIED_ACE_TYPE 0x0001 #define ACE_SYSTEM_AUDIT_ACE_TYPE 0x0002 #define ACE_SYSTEM_ALARM_ACE_TYPE 0x0003 #define ACL_AUTO_INHERIT 0x0001 #define ACL_PROTECTED 0x0002 #define ACL_DEFAULTED 0x0004 #define ACL_FLAGS_ALL (ACL_AUTO_INHERIT|ACL_PROTECTED| \ ACL_DEFAULTED) #ifdef _KERNEL /* * These are only applicable in a CIFS context. */ #define ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x04 #define ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05 #define ACE_ACCESS_DENIED_OBJECT_ACE_TYPE 0x06 #define ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07 #define ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08 #define ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x09 #define ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE 0x0A #define ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE 0x0B #define ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE 0x0C #define ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE 0x0D #define ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE 0x0E #define ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE 0x0F #define ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 0x10 #define ACE_ALL_TYPES 0x001F typedef struct ace_object { uid_t a_who; /* uid or gid */ uint32_t a_access_mask; /* read,write,... */ uint16_t a_flags; /* see below */ uint16_t a_type; /* allow or deny */ uint8_t a_obj_type[16]; /* obj type */ uint8_t a_inherit_obj_type[16]; /* inherit obj */ } ace_object_t; #endif #define ACE_ALL_PERMS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS| \ ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES| \ ACE_WRITE_ATTRIBUTES|ACE_DELETE|ACE_READ_ACL|ACE_WRITE_ACL| \ ACE_WRITE_OWNER|ACE_SYNCHRONIZE) #define ACE_ALL_WRITE_PERMS (ACE_WRITE_DATA|ACE_APPEND_DATA| \ ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS|ACE_WRITE_ACL| \ ACE_WRITE_OWNER|ACE_DELETE|ACE_DELETE_CHILD) #define ACE_READ_PERMS (ACE_READ_DATA|ACE_READ_ACL|ACE_READ_ATTRIBUTES| \ ACE_READ_NAMED_ATTRS) #define ACE_WRITE_PERMS (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES| \ ACE_WRITE_NAMED_ATTRS) #define ACE_MODIFY_PERMS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS| \ ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES| \ ACE_WRITE_ATTRIBUTES|ACE_DELETE|ACE_READ_ACL|ACE_SYNCHRONIZE) /* * The following flags are supported by both NFSv4 ACLs and ace_t. */ #define ACE_NFSV4_SUP_FLAGS (ACE_FILE_INHERIT_ACE | \ ACE_DIRECTORY_INHERIT_ACE | \ ACE_NO_PROPAGATE_INHERIT_ACE | \ ACE_INHERIT_ONLY_ACE | \ + ACE_INHERITED_ACE | \ ACE_IDENTIFIER_GROUP) #define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE| \ ACE_IDENTIFIER_GROUP) -#define ACE_INHERIT_FLAGS (ACE_FILE_INHERIT_ACE| \ +#define ACE_INHERIT_FLAGS (ACE_FILE_INHERIT_ACE| ACL_INHERITED_ACE| \ ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE) /* cmd args to acl(2) for aclent_t */ #define GETACL 1 #define SETACL 2 #define GETACLCNT 3 /* cmd's to manipulate ace acls. */ #define ACE_GETACL 4 #define ACE_SETACL 5 #define ACE_GETACLCNT 6 /* minimal acl entries from GETACLCNT */ #define MIN_ACL_ENTRIES 4 #if !defined(_KERNEL) /* acl check errors */ #define GRP_ERROR 1 #define USER_ERROR 2 #define OTHER_ERROR 3 #define CLASS_ERROR 4 #define DUPLICATE_ERROR 5 #define MISS_ERROR 6 #define MEM_ERROR 7 #define ENTRY_ERROR 8 /* * similar to ufs_acl.h: changed to char type for user commands (tar, cpio) * Attribute types */ #define UFSD_FREE ('0') /* Free entry */ #define UFSD_ACL ('1') /* Access Control Lists */ #define UFSD_DFACL ('2') /* reserved for future use */ #define ACE_ACL ('3') /* ace_t style acls */ /* * flag to [f]acl_get() * controls whether a trivial acl should be returned. */ #define ACL_NO_TRIVIAL 0x2 /* * Flags to control acl_totext() */ #define ACL_APPEND_ID 0x1 /* append uid/gid to user/group entries */ #define ACL_COMPACT_FMT 0x2 /* build ACL in ls -V format */ #define ACL_NORESOLVE 0x4 /* don't do name service lookups */ #define ACL_SID_FMT 0x8 /* use usersid/groupsid when appropriate */ /* * Legacy aclcheck errors for aclent_t ACLs */ #define EACL_GRP_ERROR GRP_ERROR #define EACL_USER_ERROR USER_ERROR #define EACL_OTHER_ERROR OTHER_ERROR #define EACL_CLASS_ERROR CLASS_ERROR #define EACL_DUPLICATE_ERROR DUPLICATE_ERROR #define EACL_MISS_ERROR MISS_ERROR #define EACL_MEM_ERROR MEM_ERROR #define EACL_ENTRY_ERROR ENTRY_ERROR #define EACL_INHERIT_ERROR 9 /* invalid inherit flags */ #define EACL_FLAGS_ERROR 10 /* unknown flag value */ #define EACL_PERM_MASK_ERROR 11 /* unknown permission */ #define EACL_COUNT_ERROR 12 /* invalid acl count */ #define EACL_INVALID_SLOT 13 /* invalid acl slot */ #define EACL_NO_ACL_ENTRY 14 /* Entry doesn't exist */ #define EACL_DIFF_TYPE 15 /* acls aren't same type */ #define EACL_INVALID_USER_GROUP 16 /* need user/group name */ #define EACL_INVALID_STR 17 /* invalid acl string */ #define EACL_FIELD_NOT_BLANK 18 /* can't have blank field */ #define EACL_INVALID_ACCESS_TYPE 19 /* invalid access type */ #define EACL_UNKNOWN_DATA 20 /* Unrecognized data in ACL */ #define EACL_MISSING_FIELDS 21 /* missing fields in acl */ #define EACL_INHERIT_NOTDIR 22 /* Need dir for inheritance */ extern int aclcheck(aclent_t *, int, int *); extern int acltomode(aclent_t *, int, mode_t *); extern int aclfrommode(aclent_t *, int, mode_t *); extern int aclsort(int, int, aclent_t *); extern char *acltotext(aclent_t *, int); extern aclent_t *aclfromtext(char *, int *); extern void acl_free(acl_t *); extern int acl_get(const char *, int, acl_t **); extern int facl_get(int, int, acl_t **); extern int acl_set(const char *, acl_t *acl); extern int facl_set(int, acl_t *acl); extern int acl_strip(const char *, uid_t, gid_t, mode_t); extern int acl_trivial(const char *); extern char *acl_totext(acl_t *, int); extern int acl_fromtext(const char *, acl_t **); extern int acl_check(acl_t *, int); #else /* !defined(_KERNEL) */ extern void ksort(caddr_t, int, int, int (*)(void *, void *)); extern int cmp2acls(void *, void *); #endif /* !defined(_KERNEL) */ extern int acl(const char *path, int cmd, int cnt, void *buf); extern int facl(int fd, int cmd, int cnt, void *buf); #ifdef __cplusplus } #endif #endif /* _SYS_ACL_H */ Index: head/sys/kern/subr_acl_nfs4.c =================================================================== --- head/sys/kern/subr_acl_nfs4.c (revision 287444) +++ head/sys/kern/subr_acl_nfs4.c (revision 287445) @@ -1,1417 +1,1418 @@ /*- * Copyright (c) 2008-2010 Edward Tomasz Napierała * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * ACL support routines specific to NFSv4 access control lists. These are * utility routines for code common across file systems implementing NFSv4 * ACLs. */ #ifdef _KERNEL #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #else #include #include #include #include #define KASSERT(a, b) assert(a) #define CTASSERT(a) #endif /* !_KERNEL */ #ifdef _KERNEL static void acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode); static int acl_nfs4_old_semantics = 0; SYSCTL_INT(_vfs, OID_AUTO, acl_nfs4_old_semantics, CTLFLAG_RW, &acl_nfs4_old_semantics, 0, "Use pre-PSARC/2010/029 NFSv4 ACL semantics"); static struct { accmode_t accmode; int mask; } accmode2mask[] = {{VREAD, ACL_READ_DATA}, {VWRITE, ACL_WRITE_DATA}, {VAPPEND, ACL_APPEND_DATA}, {VEXEC, ACL_EXECUTE}, {VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, {VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, {VDELETE_CHILD, ACL_DELETE_CHILD}, {VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES}, {VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, {VDELETE, ACL_DELETE}, {VREAD_ACL, ACL_READ_ACL}, {VWRITE_ACL, ACL_WRITE_ACL}, {VWRITE_OWNER, ACL_WRITE_OWNER}, {VSYNCHRONIZE, ACL_SYNCHRONIZE}, {0, 0}}; static int _access_mask_from_accmode(accmode_t accmode) { int access_mask = 0, i; for (i = 0; accmode2mask[i].accmode != 0; i++) { if (accmode & accmode2mask[i].accmode) access_mask |= accmode2mask[i].mask; } /* * VAPPEND is just a modifier for VWRITE; if the caller asked * for 'VAPPEND | VWRITE', we want to check for ACL_APPEND_DATA only. */ if (access_mask & ACL_APPEND_DATA) access_mask &= ~ACL_WRITE_DATA; return (access_mask); } /* * Return 0, iff access is allowed, 1 otherwise. */ static int _acl_denies(const struct acl *aclp, int access_mask, struct ucred *cred, int file_uid, int file_gid, int *denied_explicitly) { int i; const struct acl_entry *entry; if (denied_explicitly != NULL) *denied_explicitly = 0; KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES, ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); for (i = 0; i < aclp->acl_cnt; i++) { entry = &(aclp->acl_entry[i]); if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) continue; if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) continue; switch (entry->ae_tag) { case ACL_USER_OBJ: if (file_uid != cred->cr_uid) continue; break; case ACL_USER: if (entry->ae_id != cred->cr_uid) continue; break; case ACL_GROUP_OBJ: if (!groupmember(file_gid, cred)) continue; break; case ACL_GROUP: if (!groupmember(entry->ae_id, cred)) continue; break; default: KASSERT(entry->ae_tag == ACL_EVERYONE, ("entry->ae_tag == ACL_EVERYONE")); } if (entry->ae_entry_type == ACL_ENTRY_TYPE_DENY) { if (entry->ae_perm & access_mask) { if (denied_explicitly != NULL) *denied_explicitly = 1; return (1); } } access_mask &= ~(entry->ae_perm); if (access_mask == 0) return (0); } if (access_mask == 0) return (0); return (1); } int vaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid, struct acl *aclp, accmode_t accmode, struct ucred *cred, int *privused) { accmode_t priv_granted = 0; int denied, explicitly_denied, access_mask, is_directory, must_be_owner = 0; mode_t file_mode = 0; KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND | VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS | VDELETE_CHILD | VREAD_ATTRIBUTES | VWRITE_ATTRIBUTES | VDELETE | VREAD_ACL | VWRITE_ACL | VWRITE_OWNER | VSYNCHRONIZE)) == 0, ("invalid bit in accmode")); KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE), ("VAPPEND without VWRITE")); if (privused != NULL) *privused = 0; if (accmode & VADMIN) must_be_owner = 1; /* * Ignore VSYNCHRONIZE permission. */ accmode &= ~VSYNCHRONIZE; access_mask = _access_mask_from_accmode(accmode); if (type == VDIR) is_directory = 1; else is_directory = 0; /* * File owner is always allowed to read and write the ACL * and basic attributes. This is to prevent a situation * where user would change ACL in a way that prevents him * from undoing the change. */ if (file_uid == cred->cr_uid) access_mask &= ~(ACL_READ_ACL | ACL_WRITE_ACL | ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES); /* * Ignore append permission for regular files; use write * permission instead. */ if (!is_directory && (access_mask & ACL_APPEND_DATA)) { access_mask &= ~ACL_APPEND_DATA; access_mask |= ACL_WRITE_DATA; } denied = _acl_denies(aclp, access_mask, cred, file_uid, file_gid, &explicitly_denied); if (must_be_owner) { if (file_uid != cred->cr_uid) denied = EPERM; } /* * For VEXEC, ensure that at least one execute bit is set for * non-directories. We have to check the mode here to stay * consistent with execve(2). See the test in * exec_check_permissions(). */ acl_nfs4_sync_mode_from_acl(&file_mode, aclp); if (!denied && !is_directory && (accmode & VEXEC) && (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) denied = EACCES; if (!denied) return (0); /* * Access failed. Iff it was not denied explicitly and * VEXPLICIT_DENY flag was specified, allow access. */ if ((accmode & VEXPLICIT_DENY) && explicitly_denied == 0) return (0); accmode &= ~VEXPLICIT_DENY; /* * No match. Try to use privileges, if there are any. */ if (is_directory) { if ((accmode & VEXEC) && !priv_check_cred(cred, PRIV_VFS_LOOKUP, 0)) priv_granted |= VEXEC; } else { /* * Ensure that at least one execute bit is on. Otherwise, * a privileged user will always succeed, and we don't want * this to happen unless the file really is executable. */ if ((accmode & VEXEC) && (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 && !priv_check_cred(cred, PRIV_VFS_EXEC, 0)) priv_granted |= VEXEC; } if ((accmode & VREAD) && !priv_check_cred(cred, PRIV_VFS_READ, 0)) priv_granted |= VREAD; if ((accmode & (VWRITE | VAPPEND | VDELETE_CHILD)) && !priv_check_cred(cred, PRIV_VFS_WRITE, 0)) priv_granted |= (VWRITE | VAPPEND | VDELETE_CHILD); if ((accmode & VADMIN_PERMS) && !priv_check_cred(cred, PRIV_VFS_ADMIN, 0)) priv_granted |= VADMIN_PERMS; if ((accmode & VSTAT_PERMS) && !priv_check_cred(cred, PRIV_VFS_STAT, 0)) priv_granted |= VSTAT_PERMS; if ((accmode & priv_granted) == accmode) { if (privused != NULL) *privused = 1; return (0); } if (accmode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE)) denied = EPERM; else denied = EACCES; return (denied); } #endif /* _KERNEL */ static int _acl_entry_matches(struct acl_entry *entry, acl_tag_t tag, acl_perm_t perm, acl_entry_type_t entry_type) { if (entry->ae_tag != tag) return (0); if (entry->ae_id != ACL_UNDEFINED_ID) return (0); if (entry->ae_perm != perm) return (0); if (entry->ae_entry_type != entry_type) return (0); if (entry->ae_flags != 0) return (0); return (1); } static struct acl_entry * _acl_append(struct acl *aclp, acl_tag_t tag, acl_perm_t perm, acl_entry_type_t entry_type) { struct acl_entry *entry; KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); entry = &(aclp->acl_entry[aclp->acl_cnt]); aclp->acl_cnt++; entry->ae_tag = tag; entry->ae_id = ACL_UNDEFINED_ID; entry->ae_perm = perm; entry->ae_entry_type = entry_type; entry->ae_flags = 0; return (entry); } static struct acl_entry * _acl_duplicate_entry(struct acl *aclp, int entry_index) { int i; KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); for (i = aclp->acl_cnt; i > entry_index; i--) aclp->acl_entry[i] = aclp->acl_entry[i - 1]; aclp->acl_cnt++; return (&(aclp->acl_entry[entry_index + 1])); } static void acl_nfs4_sync_acl_from_mode_draft(struct acl *aclp, mode_t mode, int file_owner_id) { int i, meets, must_append; struct acl_entry *entry, *copy, *previous, *a1, *a2, *a3, *a4, *a5, *a6; mode_t amode; const int READ = 04; const int WRITE = 02; const int EXEC = 01; KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES, ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); /* * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt * * 3.16.6.3. Applying a Mode to an Existing ACL */ /* * 1. For each ACE: */ for (i = 0; i < aclp->acl_cnt; i++) { entry = &(aclp->acl_entry[i]); /* * 1.1. If the type is neither ALLOW or DENY - skip. */ if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) continue; /* * 1.2. If ACL_ENTRY_INHERIT_ONLY is set - skip. */ if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) continue; /* * 1.3. If ACL_ENTRY_FILE_INHERIT or ACL_ENTRY_DIRECTORY_INHERIT * are set: */ if (entry->ae_flags & (ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT)) { /* * 1.3.1. A copy of the current ACE is made, and placed * in the ACL immediately following the current * ACE. */ copy = _acl_duplicate_entry(aclp, i); /* * 1.3.2. In the first ACE, the flag * ACL_ENTRY_INHERIT_ONLY is set. */ entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; /* * 1.3.3. In the second ACE, the following flags * are cleared: * ACL_ENTRY_FILE_INHERIT, * ACL_ENTRY_DIRECTORY_INHERIT, * ACL_ENTRY_NO_PROPAGATE_INHERIT. */ copy->ae_flags &= ~(ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_NO_PROPAGATE_INHERIT); /* * The algorithm continues on with the second ACE. */ i++; entry = copy; } /* * 1.4. If it's owner@, group@ or everyone@ entry, clear * ACL_READ_DATA, ACL_WRITE_DATA, ACL_APPEND_DATA * and ACL_EXECUTE. Continue to the next entry. */ if (entry->ae_tag == ACL_USER_OBJ || entry->ae_tag == ACL_GROUP_OBJ || entry->ae_tag == ACL_EVERYONE) { entry->ae_perm &= ~(ACL_READ_DATA | ACL_WRITE_DATA | ACL_APPEND_DATA | ACL_EXECUTE); continue; } /* * 1.5. Otherwise, if the "who" field did not match one * of OWNER@, GROUP@, EVERYONE@: * * 1.5.1. If the type is ALLOW, check the preceding ACE. * If it does not meet all of the following criteria: */ if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW) continue; meets = 0; if (i > 0) { meets = 1; previous = &(aclp->acl_entry[i - 1]); /* * 1.5.1.1. The type field is DENY, */ if (previous->ae_entry_type != ACL_ENTRY_TYPE_DENY) meets = 0; /* * 1.5.1.2. The "who" field is the same as the current * ACE, * * 1.5.1.3. The flag bit ACE4_IDENTIFIER_GROUP * is the same as it is in the current ACE, * and no other flag bits are set, */ if (previous->ae_id != entry->ae_id || previous->ae_tag != entry->ae_tag) meets = 0; if (previous->ae_flags) meets = 0; /* * 1.5.1.4. The mask bits are a subset of the mask bits * of the current ACE, and are also subset of * the following: ACL_READ_DATA, * ACL_WRITE_DATA, ACL_APPEND_DATA, ACL_EXECUTE */ if (previous->ae_perm & ~(entry->ae_perm)) meets = 0; if (previous->ae_perm & ~(ACL_READ_DATA | ACL_WRITE_DATA | ACL_APPEND_DATA | ACL_EXECUTE)) meets = 0; } if (!meets) { /* * Then the ACE of type DENY, with a who equal * to the current ACE, flag bits equal to * ( & ) * and no mask bits, is prepended. */ previous = entry; entry = _acl_duplicate_entry(aclp, i); /* Adjust counter, as we've just added an entry. */ i++; previous->ae_tag = entry->ae_tag; previous->ae_id = entry->ae_id; previous->ae_flags = entry->ae_flags; previous->ae_perm = 0; previous->ae_entry_type = ACL_ENTRY_TYPE_DENY; } /* * 1.5.2. The following modifications are made to the prepended * ACE. The intent is to mask the following ACE * to disallow ACL_READ_DATA, ACL_WRITE_DATA, * ACL_APPEND_DATA, or ACL_EXECUTE, based upon the group * permissions of the new mode. As a special case, * if the ACE matches the current owner of the file, * the owner bits are used, rather than the group bits. * This is reflected in the algorithm below. */ amode = mode >> 3; /* * If ACE4_IDENTIFIER_GROUP is not set, and the "who" field * in ACE matches the owner of the file, we shift amode three * more bits, in order to have the owner permission bits * placed in the three low order bits of amode. */ if (entry->ae_tag == ACL_USER && entry->ae_id == file_owner_id) amode = amode >> 3; if (entry->ae_perm & ACL_READ_DATA) { if (amode & READ) previous->ae_perm &= ~ACL_READ_DATA; else previous->ae_perm |= ACL_READ_DATA; } if (entry->ae_perm & ACL_WRITE_DATA) { if (amode & WRITE) previous->ae_perm &= ~ACL_WRITE_DATA; else previous->ae_perm |= ACL_WRITE_DATA; } if (entry->ae_perm & ACL_APPEND_DATA) { if (amode & WRITE) previous->ae_perm &= ~ACL_APPEND_DATA; else previous->ae_perm |= ACL_APPEND_DATA; } if (entry->ae_perm & ACL_EXECUTE) { if (amode & EXEC) previous->ae_perm &= ~ACL_EXECUTE; else previous->ae_perm |= ACL_EXECUTE; } /* * 1.5.3. If ACE4_IDENTIFIER_GROUP is set in the flags * of the ALLOW ace: * * XXX: This point is not there in the Falkner's draft. */ if (entry->ae_tag == ACL_GROUP && entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) { mode_t extramode, ownermode; extramode = (mode >> 3) & 07; ownermode = mode >> 6; extramode &= ~ownermode; if (extramode) { if (extramode & READ) { entry->ae_perm &= ~ACL_READ_DATA; previous->ae_perm &= ~ACL_READ_DATA; } if (extramode & WRITE) { entry->ae_perm &= ~(ACL_WRITE_DATA | ACL_APPEND_DATA); previous->ae_perm &= ~(ACL_WRITE_DATA | ACL_APPEND_DATA); } if (extramode & EXEC) { entry->ae_perm &= ~ACL_EXECUTE; previous->ae_perm &= ~ACL_EXECUTE; } } } } /* * 2. If there at least six ACEs, the final six ACEs are examined. * If they are not equal to what we want, append six ACEs. */ must_append = 0; if (aclp->acl_cnt < 6) { must_append = 1; } else { a6 = &(aclp->acl_entry[aclp->acl_cnt - 1]); a5 = &(aclp->acl_entry[aclp->acl_cnt - 2]); a4 = &(aclp->acl_entry[aclp->acl_cnt - 3]); a3 = &(aclp->acl_entry[aclp->acl_cnt - 4]); a2 = &(aclp->acl_entry[aclp->acl_cnt - 5]); a1 = &(aclp->acl_entry[aclp->acl_cnt - 6]); if (!_acl_entry_matches(a1, ACL_USER_OBJ, 0, ACL_ENTRY_TYPE_DENY)) must_append = 1; if (!_acl_entry_matches(a2, ACL_USER_OBJ, ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW)) must_append = 1; if (!_acl_entry_matches(a3, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_DENY)) must_append = 1; if (!_acl_entry_matches(a4, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_ALLOW)) must_append = 1; if (!_acl_entry_matches(a5, ACL_EVERYONE, ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY)) must_append = 1; if (!_acl_entry_matches(a6, ACL_EVERYONE, ACL_READ_ACL | ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW)) must_append = 1; } if (must_append) { KASSERT(aclp->acl_cnt + 6 <= ACL_MAX_ENTRIES, ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); a1 = _acl_append(aclp, ACL_USER_OBJ, 0, ACL_ENTRY_TYPE_DENY); a2 = _acl_append(aclp, ACL_USER_OBJ, ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW); a3 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_DENY); a4 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_ALLOW); a5 = _acl_append(aclp, ACL_EVERYONE, ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY); a6 = _acl_append(aclp, ACL_EVERYONE, ACL_READ_ACL | ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW); KASSERT(a1 != NULL && a2 != NULL && a3 != NULL && a4 != NULL && a5 != NULL && a6 != NULL, ("couldn't append to ACL.")); } /* * 3. The final six ACEs are adjusted according to the incoming mode. */ if (mode & S_IRUSR) a2->ae_perm |= ACL_READ_DATA; else a1->ae_perm |= ACL_READ_DATA; if (mode & S_IWUSR) a2->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); else a1->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); if (mode & S_IXUSR) a2->ae_perm |= ACL_EXECUTE; else a1->ae_perm |= ACL_EXECUTE; if (mode & S_IRGRP) a4->ae_perm |= ACL_READ_DATA; else a3->ae_perm |= ACL_READ_DATA; if (mode & S_IWGRP) a4->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); else a3->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); if (mode & S_IXGRP) a4->ae_perm |= ACL_EXECUTE; else a3->ae_perm |= ACL_EXECUTE; if (mode & S_IROTH) a6->ae_perm |= ACL_READ_DATA; else a5->ae_perm |= ACL_READ_DATA; if (mode & S_IWOTH) a6->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); else a5->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); if (mode & S_IXOTH) a6->ae_perm |= ACL_EXECUTE; else a5->ae_perm |= ACL_EXECUTE; } #ifdef _KERNEL void acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id) { if (acl_nfs4_old_semantics) acl_nfs4_sync_acl_from_mode_draft(aclp, mode, file_owner_id); else acl_nfs4_trivial_from_mode(aclp, mode); } #endif /* _KERNEL */ void acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp) { int i; mode_t old_mode = *_mode, mode = 0, seen = 0; const struct acl_entry *entry; KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES, ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); /* * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt * * 3.16.6.1. Recomputing mode upon SETATTR of ACL */ for (i = 0; i < aclp->acl_cnt; i++) { entry = &(aclp->acl_entry[i]); if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) continue; if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) continue; if (entry->ae_tag == ACL_USER_OBJ) { if ((entry->ae_perm & ACL_READ_DATA) && ((seen & S_IRUSR) == 0)) { seen |= S_IRUSR; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IRUSR; } if ((entry->ae_perm & ACL_WRITE_DATA) && ((seen & S_IWUSR) == 0)) { seen |= S_IWUSR; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IWUSR; } if ((entry->ae_perm & ACL_EXECUTE) && ((seen & S_IXUSR) == 0)) { seen |= S_IXUSR; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IXUSR; } } else if (entry->ae_tag == ACL_GROUP_OBJ) { if ((entry->ae_perm & ACL_READ_DATA) && ((seen & S_IRGRP) == 0)) { seen |= S_IRGRP; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IRGRP; } if ((entry->ae_perm & ACL_WRITE_DATA) && ((seen & S_IWGRP) == 0)) { seen |= S_IWGRP; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IWGRP; } if ((entry->ae_perm & ACL_EXECUTE) && ((seen & S_IXGRP) == 0)) { seen |= S_IXGRP; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IXGRP; } } else if (entry->ae_tag == ACL_EVERYONE) { if (entry->ae_perm & ACL_READ_DATA) { if ((seen & S_IRUSR) == 0) { seen |= S_IRUSR; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IRUSR; } if ((seen & S_IRGRP) == 0) { seen |= S_IRGRP; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IRGRP; } if ((seen & S_IROTH) == 0) { seen |= S_IROTH; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IROTH; } } if (entry->ae_perm & ACL_WRITE_DATA) { if ((seen & S_IWUSR) == 0) { seen |= S_IWUSR; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IWUSR; } if ((seen & S_IWGRP) == 0) { seen |= S_IWGRP; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IWGRP; } if ((seen & S_IWOTH) == 0) { seen |= S_IWOTH; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IWOTH; } } if (entry->ae_perm & ACL_EXECUTE) { if ((seen & S_IXUSR) == 0) { seen |= S_IXUSR; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IXUSR; } if ((seen & S_IXGRP) == 0) { seen |= S_IXGRP; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IXGRP; } if ((seen & S_IXOTH) == 0) { seen |= S_IXOTH; if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) mode |= S_IXOTH; } } } } *_mode = mode | (old_mode & ACL_PRESERVE_MASK); } #ifdef _KERNEL /* * Calculate inherited ACL in a manner compatible with NFSv4 Minor Version 1, * draft-ietf-nfsv4-minorversion1-03.txt. */ static void acl_nfs4_compute_inherited_acl_draft(const struct acl *parent_aclp, struct acl *child_aclp, mode_t mode, int file_owner_id, int is_directory) { int i, flags; const struct acl_entry *parent_entry; struct acl_entry *entry, *copy; KASSERT(child_aclp->acl_cnt == 0, ("child_aclp->acl_cnt == 0")); KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES, ("parent_aclp->acl_cnt <= ACL_MAX_ENTRIES")); /* * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt * * 3.16.6.2. Applying the mode given to CREATE or OPEN * to an inherited ACL */ /* * 1. Form an ACL that is the concatenation of all inheritable ACEs. */ for (i = 0; i < parent_aclp->acl_cnt; i++) { parent_entry = &(parent_aclp->acl_entry[i]); flags = parent_entry->ae_flags; /* * Entry is not inheritable at all. */ if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_FILE_INHERIT)) == 0) continue; /* * We're creating a file, but entry is not inheritable * by files. */ if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0) continue; /* * Entry is inheritable only by files, but has NO_PROPAGATE * flag set, and we're creating a directory, so it wouldn't * propagate to any file in that directory anyway. */ if (is_directory && (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 && (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)) continue; KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, ("child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); child_aclp->acl_entry[child_aclp->acl_cnt] = *parent_entry; child_aclp->acl_cnt++; } /* * 2. For each entry in the new ACL, adjust its flags, possibly * creating two entries in place of one. */ for (i = 0; i < child_aclp->acl_cnt; i++) { entry = &(child_aclp->acl_entry[i]); /* * This is not in the specification, but SunOS * apparently does that. */ if (((entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT) || !is_directory) && entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) entry->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER); /* * 2.A. If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if the object * being created is not a directory, then clear the * following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT, * ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT, * ACL_ENTRY_INHERIT_ONLY. */ if (entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT || !is_directory) { entry->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_INHERIT_ONLY); /* * Continue on to the next ACE. */ continue; } /* * 2.B. If the object is a directory and ACL_ENTRY_FILE_INHERIT * is set, but ACL_ENTRY_NO_PROPAGATE_INHERIT is not set, ensure * that ACL_ENTRY_INHERIT_ONLY is set. Continue to the * next ACE. Otherwise... */ /* * XXX: Read it again and make sure what does the "otherwise" * apply to. */ if (is_directory && (entry->ae_flags & ACL_ENTRY_FILE_INHERIT) && ((entry->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) { entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; continue; } /* * 2.C. If the type of the ACE is neither ALLOW nor deny, * then continue. */ if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) continue; /* * 2.D. Copy the original ACE into a second, adjacent ACE. */ copy = _acl_duplicate_entry(child_aclp, i); /* * 2.E. On the first ACE, ensure that ACL_ENTRY_INHERIT_ONLY * is set. */ entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; /* * 2.F. On the second ACE, clear the following flags: * ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_FILE_INHERIT, * ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_INHERIT_ONLY. */ copy->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_INHERIT_ONLY); /* * 2.G. On the second ACE, if the type is ALLOW, * an implementation MAY clear the following * mask bits: ACL_WRITE_ACL, ACL_WRITE_OWNER. */ if (copy->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) copy->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER); /* * Increment the counter to skip the copied entry. */ i++; } /* * 3. To ensure that the mode is honored, apply the algorithm describe * in Section 2.16.6.3, using the mode that is to be used for file * creation. */ acl_nfs4_sync_acl_from_mode(child_aclp, mode, file_owner_id); } #endif /* _KERNEL */ /* * Populate the ACL with entries inherited from parent_aclp. */ static void acl_nfs4_inherit_entries(const struct acl *parent_aclp, struct acl *child_aclp, mode_t mode, int file_owner_id, int is_directory) { int i, flags, tag; const struct acl_entry *parent_entry; struct acl_entry *entry; KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES, ("parent_aclp->acl_cnt <= ACL_MAX_ENTRIES")); for (i = 0; i < parent_aclp->acl_cnt; i++) { parent_entry = &(parent_aclp->acl_entry[i]); flags = parent_entry->ae_flags; tag = parent_entry->ae_tag; /* * Don't inherit owner@, group@, or everyone@ entries. */ if (tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_EVERYONE) continue; /* * Entry is not inheritable at all. */ if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_FILE_INHERIT)) == 0) continue; /* * We're creating a file, but entry is not inheritable * by files. */ if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0) continue; /* * Entry is inheritable only by files, but has NO_PROPAGATE * flag set, and we're creating a directory, so it wouldn't * propagate to any file in that directory anyway. */ if (is_directory && (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 && (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)) continue; /* * Entry qualifies for being inherited. */ KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, ("child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); entry = &(child_aclp->acl_entry[child_aclp->acl_cnt]); *entry = *parent_entry; child_aclp->acl_cnt++; entry->ae_flags &= ~ACL_ENTRY_INHERIT_ONLY; + entry->ae_flags |= ACL_ENTRY_INHERITED; /* * If the type of the ACE is neither ALLOW nor DENY, * then leave it as it is and proceed to the next one. */ if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) continue; /* * If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if * the object being created is not a directory, then clear * the following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT, * ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT, * ACL_ENTRY_INHERIT_ONLY. */ if (entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT || !is_directory) { entry->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_INHERIT_ONLY); } /* * If the object is a directory and ACL_ENTRY_FILE_INHERIT * is set, but ACL_ENTRY_DIRECTORY_INHERIT is not set, ensure * that ACL_ENTRY_INHERIT_ONLY is set. */ if (is_directory && (entry->ae_flags & ACL_ENTRY_FILE_INHERIT) && ((entry->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) { entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; } if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW && (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) == 0) { /* * Some permissions must never be inherited. */ entry->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_NAMED_ATTRS | ACL_WRITE_ATTRIBUTES); /* * Others must be masked according to the file mode. */ if ((mode & S_IRGRP) == 0) entry->ae_perm &= ~ACL_READ_DATA; if ((mode & S_IWGRP) == 0) entry->ae_perm &= ~(ACL_WRITE_DATA | ACL_APPEND_DATA); if ((mode & S_IXGRP) == 0) entry->ae_perm &= ~ACL_EXECUTE; } } } /* * Calculate inherited ACL in a manner compatible with PSARC/2010/029. * It's also being used to calculate a trivial ACL, by inheriting from * a NULL ACL. */ static void acl_nfs4_compute_inherited_acl_psarc(const struct acl *parent_aclp, struct acl *aclp, mode_t mode, int file_owner_id, int is_directory) { acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0; acl_perm_t user_allow, group_allow, everyone_allow; KASSERT(aclp->acl_cnt == 0, ("aclp->acl_cnt == 0")); user_allow = group_allow = everyone_allow = ACL_READ_ACL | ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE; user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | ACL_WRITE_NAMED_ATTRS; if (mode & S_IRUSR) user_allow |= ACL_READ_DATA; if (mode & S_IWUSR) user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); if (mode & S_IXUSR) user_allow |= ACL_EXECUTE; if (mode & S_IRGRP) group_allow |= ACL_READ_DATA; if (mode & S_IWGRP) group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); if (mode & S_IXGRP) group_allow |= ACL_EXECUTE; if (mode & S_IROTH) everyone_allow |= ACL_READ_DATA; if (mode & S_IWOTH) everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); if (mode & S_IXOTH) everyone_allow |= ACL_EXECUTE; user_deny = ((group_allow | everyone_allow) & ~user_allow); group_deny = everyone_allow & ~group_allow; user_allow_first = group_deny & ~user_deny; if (user_allow_first != 0) _acl_append(aclp, ACL_USER_OBJ, user_allow_first, ACL_ENTRY_TYPE_ALLOW); if (user_deny != 0) _acl_append(aclp, ACL_USER_OBJ, user_deny, ACL_ENTRY_TYPE_DENY); if (group_deny != 0) _acl_append(aclp, ACL_GROUP_OBJ, group_deny, ACL_ENTRY_TYPE_DENY); if (parent_aclp != NULL) acl_nfs4_inherit_entries(parent_aclp, aclp, mode, file_owner_id, is_directory); _acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW); _acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW); _acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW); } #ifdef _KERNEL void acl_nfs4_compute_inherited_acl(const struct acl *parent_aclp, struct acl *child_aclp, mode_t mode, int file_owner_id, int is_directory) { if (acl_nfs4_old_semantics) acl_nfs4_compute_inherited_acl_draft(parent_aclp, child_aclp, mode, file_owner_id, is_directory); else acl_nfs4_compute_inherited_acl_psarc(parent_aclp, child_aclp, mode, file_owner_id, is_directory); } #endif /* _KERNEL */ /* * Calculate trivial ACL in a manner compatible with PSARC/2010/029. * Note that this results in an ACL different from (but semantically * equal to) the "canonical six" trivial ACL computed using algorithm * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2. */ static void acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode) { aclp->acl_cnt = 0; acl_nfs4_compute_inherited_acl_psarc(NULL, aclp, mode, -1, -1); } #ifndef _KERNEL /* * This routine is used by libc to implement acl_strip_np(3) * and acl_is_trivial_np(3). */ void acl_nfs4_trivial_from_mode_libc(struct acl *aclp, int mode, int canonical_six) { aclp->acl_cnt = 0; if (canonical_six) acl_nfs4_sync_acl_from_mode_draft(aclp, mode, -1); else acl_nfs4_trivial_from_mode(aclp, mode); } #endif /* !_KERNEL */ #ifdef _KERNEL static int _acls_are_equal(const struct acl *a, const struct acl *b) { int i; const struct acl_entry *entrya, *entryb; if (a->acl_cnt != b->acl_cnt) return (0); for (i = 0; i < b->acl_cnt; i++) { entrya = &(a->acl_entry[i]); entryb = &(b->acl_entry[i]); if (entrya->ae_tag != entryb->ae_tag || entrya->ae_id != entryb->ae_id || entrya->ae_perm != entryb->ae_perm || entrya->ae_entry_type != entryb->ae_entry_type || entrya->ae_flags != entryb->ae_flags) return (0); } return (1); } /* * This routine is used to determine whether to remove extended attribute * that stores ACL contents. */ int acl_nfs4_is_trivial(const struct acl *aclp, int file_owner_id) { int trivial; mode_t tmpmode = 0; struct acl *tmpaclp; if (aclp->acl_cnt > 6) return (0); /* * Compute the mode from the ACL, then compute new ACL from that mode. * If the ACLs are identical, then the ACL is trivial. * * XXX: I guess there is a faster way to do this. However, even * this slow implementation significantly speeds things up * for files that don't have non-trivial ACLs - it's critical * for performance to not use EA when they are not needed. * * First try the PSARC/2010/029 semantics. */ tmpaclp = acl_alloc(M_WAITOK | M_ZERO); acl_nfs4_sync_mode_from_acl(&tmpmode, aclp); acl_nfs4_trivial_from_mode(tmpaclp, tmpmode); trivial = _acls_are_equal(aclp, tmpaclp); if (trivial) { acl_free(tmpaclp); return (trivial); } /* * Check if it's a draft-ietf-nfsv4-minorversion1-03.txt trivial ACL. */ tmpaclp->acl_cnt = 0; acl_nfs4_sync_acl_from_mode_draft(tmpaclp, tmpmode, file_owner_id); trivial = _acls_are_equal(aclp, tmpaclp); acl_free(tmpaclp); return (trivial); } #endif /* _KERNEL */ int acl_nfs4_check(const struct acl *aclp, int is_directory) { int i; const struct acl_entry *entry; /* * The spec doesn't seem to say anything about ACL validity. * It seems there is not much to do here. There is even no need * to count "owner@" or "everyone@" (ACL_USER_OBJ and ACL_EVERYONE) * entries, as there can be several of them and that's perfectly * valid. There can be none of them too. Really. */ if (aclp->acl_cnt > ACL_MAX_ENTRIES || aclp->acl_cnt <= 0) return (EINVAL); for (i = 0; i < aclp->acl_cnt; i++) { entry = &(aclp->acl_entry[i]); switch (entry->ae_tag) { case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_EVERYONE: if (entry->ae_id != ACL_UNDEFINED_ID) return (EINVAL); break; case ACL_USER: case ACL_GROUP: if (entry->ae_id == ACL_UNDEFINED_ID) return (EINVAL); break; default: return (EINVAL); } if ((entry->ae_perm | ACL_NFS4_PERM_BITS) != ACL_NFS4_PERM_BITS) return (EINVAL); /* * Disallow ACL_ENTRY_TYPE_AUDIT and ACL_ENTRY_TYPE_ALARM for now. */ if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) return (EINVAL); if ((entry->ae_flags | ACL_FLAGS_BITS) != ACL_FLAGS_BITS) return (EINVAL); /* Disallow unimplemented flags. */ if (entry->ae_flags & (ACL_ENTRY_SUCCESSFUL_ACCESS | ACL_ENTRY_FAILED_ACCESS)) return (EINVAL); /* Disallow flags not allowed for ordinary files. */ if (!is_directory) { if (entry->ae_flags & (ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_INHERIT_ONLY)) return (EINVAL); } } return (0); } #ifdef _KERNEL static int acl_nfs4_modload(module_t module, int what, void *arg) { int ret; ret = 0; switch (what) { case MOD_LOAD: case MOD_SHUTDOWN: break; case MOD_QUIESCE: /* XXX TODO */ ret = 0; break; case MOD_UNLOAD: /* XXX TODO */ ret = 0; break; default: ret = EINVAL; break; } return (ret); } static moduledata_t acl_nfs4_mod = { "acl_nfs4", acl_nfs4_modload, NULL }; /* * XXX TODO: which subsystem, order? */ DECLARE_MODULE(acl_nfs4, acl_nfs4_mod, SI_SUB_VFS, SI_ORDER_FIRST); MODULE_VERSION(acl_nfs4, 1); #endif /* _KERNEL */ Index: head/sys/sys/acl.h =================================================================== --- head/sys/sys/acl.h (revision 287444) +++ head/sys/sys/acl.h (revision 287445) @@ -1,416 +1,417 @@ /*- * Copyright (c) 1999-2001 Robert N. M. Watson * Copyright (c) 2008 Edward Tomasz Napierała * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Developed by the TrustedBSD Project. * Support for POSIX.1e and NFSv4 access control lists. */ #ifndef _SYS_ACL_H_ #define _SYS_ACL_H_ #include #include #include /* * POSIX.1e and NFSv4 ACL types and related constants. */ typedef uint32_t acl_tag_t; typedef uint32_t acl_perm_t; typedef uint16_t acl_entry_type_t; typedef uint16_t acl_flag_t; typedef int acl_type_t; typedef int *acl_permset_t; typedef uint16_t *acl_flagset_t; /* * With 254 entries, "struct acl_t_struct" is exactly one 4kB page big. * Note that with NFSv4 ACLs, the maximum number of ACL entries one * may set on file or directory is about half of ACL_MAX_ENTRIES. * * If you increase this, you might also need to increase * _ACL_T_ALIGNMENT_BITS in lib/libc/posix1e/acl_support.h. * * The maximum number of POSIX.1e ACLs is controlled * by OLDACL_MAX_ENTRIES. Changing that one will break binary * compatibility with pre-8.0 userland and change on-disk ACL layout. */ #define ACL_MAX_ENTRIES 254 #if defined(_KERNEL) || defined(_ACL_PRIVATE) #define POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM #define POSIX1E_ACL_ACCESS_EXTATTR_NAME "posix1e.acl_access" #define POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM #define POSIX1E_ACL_DEFAULT_EXTATTR_NAME "posix1e.acl_default" #define NFS4_ACL_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM #define NFS4_ACL_EXTATTR_NAME "nfs4.acl" #define OLDACL_MAX_ENTRIES 32 /* * "struct oldacl" is used in compatibility ACL syscalls and for on-disk * storage of POSIX.1e ACLs. */ typedef int oldacl_tag_t; typedef mode_t oldacl_perm_t; struct oldacl_entry { oldacl_tag_t ae_tag; uid_t ae_id; oldacl_perm_t ae_perm; }; typedef struct oldacl_entry *oldacl_entry_t; struct oldacl { int acl_cnt; struct oldacl_entry acl_entry[OLDACL_MAX_ENTRIES]; }; /* * Current "struct acl". */ struct acl_entry { acl_tag_t ae_tag; uid_t ae_id; acl_perm_t ae_perm; /* NFSv4 entry type, "allow" or "deny". Unused in POSIX.1e ACLs. */ acl_entry_type_t ae_entry_type; /* NFSv4 ACL inheritance. Unused in POSIX.1e ACLs. */ acl_flag_t ae_flags; }; typedef struct acl_entry *acl_entry_t; /* * Internal ACL structure, used in libc, kernel APIs and for on-disk * storage of NFSv4 ACLs. POSIX.1e ACLs use "struct oldacl" for on-disk * storage. */ struct acl { unsigned int acl_maxcnt; unsigned int acl_cnt; /* Will be required e.g. to implement NFSv4.1 ACL inheritance. */ int acl_spare[4]; struct acl_entry acl_entry[ACL_MAX_ENTRIES]; }; /* * ACL structure internal to libc. */ struct acl_t_struct { struct acl ats_acl; int ats_cur_entry; /* * ats_brand is for libc internal bookkeeping only. * Applications should use acl_get_brand_np(3). * Kernel code should use the "type" argument passed * to VOP_SETACL, VOP_GETACL or VOP_ACLCHECK calls; * ACL_TYPE_ACCESS or ACL_TYPE_DEFAULT mean POSIX.1e * ACL, ACL_TYPE_NFS4 means NFSv4 ACL. */ int ats_brand; }; typedef struct acl_t_struct *acl_t; #else /* _KERNEL || _ACL_PRIVATE */ typedef void *acl_entry_t; typedef void *acl_t; #endif /* !_KERNEL && !_ACL_PRIVATE */ /* * Possible valid values for ats_brand field. */ #define ACL_BRAND_UNKNOWN 0 #define ACL_BRAND_POSIX 1 #define ACL_BRAND_NFS4 2 /* * Possible valid values for ae_tag field. For explanation, see acl(9). */ #define ACL_UNDEFINED_TAG 0x00000000 #define ACL_USER_OBJ 0x00000001 #define ACL_USER 0x00000002 #define ACL_GROUP_OBJ 0x00000004 #define ACL_GROUP 0x00000008 #define ACL_MASK 0x00000010 #define ACL_OTHER 0x00000020 #define ACL_OTHER_OBJ ACL_OTHER #define ACL_EVERYONE 0x00000040 /* * Possible valid values for ae_entry_type field, valid only for NFSv4 ACLs. */ #define ACL_ENTRY_TYPE_ALLOW 0x0100 #define ACL_ENTRY_TYPE_DENY 0x0200 #define ACL_ENTRY_TYPE_AUDIT 0x0400 #define ACL_ENTRY_TYPE_ALARM 0x0800 /* * Possible valid values for acl_type_t arguments. First two * are provided only for backwards binary compatibility. */ #define ACL_TYPE_ACCESS_OLD 0x00000000 #define ACL_TYPE_DEFAULT_OLD 0x00000001 #define ACL_TYPE_ACCESS 0x00000002 #define ACL_TYPE_DEFAULT 0x00000003 #define ACL_TYPE_NFS4 0x00000004 /* * Possible bits in ae_perm field for POSIX.1e ACLs. Note * that ACL_EXECUTE may be used in both NFSv4 and POSIX.1e ACLs. */ #define ACL_EXECUTE 0x0001 #define ACL_WRITE 0x0002 #define ACL_READ 0x0004 #define ACL_PERM_NONE 0x0000 #define ACL_PERM_BITS (ACL_EXECUTE | ACL_WRITE | ACL_READ) #define ACL_POSIX1E_BITS (ACL_EXECUTE | ACL_WRITE | ACL_READ) /* * Possible bits in ae_perm field for NFSv4 ACLs. */ #define ACL_READ_DATA 0x00000008 #define ACL_LIST_DIRECTORY 0x00000008 #define ACL_WRITE_DATA 0x00000010 #define ACL_ADD_FILE 0x00000010 #define ACL_APPEND_DATA 0x00000020 #define ACL_ADD_SUBDIRECTORY 0x00000020 #define ACL_READ_NAMED_ATTRS 0x00000040 #define ACL_WRITE_NAMED_ATTRS 0x00000080 /* ACL_EXECUTE is defined above. */ #define ACL_DELETE_CHILD 0x00000100 #define ACL_READ_ATTRIBUTES 0x00000200 #define ACL_WRITE_ATTRIBUTES 0x00000400 #define ACL_DELETE 0x00000800 #define ACL_READ_ACL 0x00001000 #define ACL_WRITE_ACL 0x00002000 #define ACL_WRITE_OWNER 0x00004000 #define ACL_SYNCHRONIZE 0x00008000 #define ACL_FULL_SET (ACL_READ_DATA | ACL_WRITE_DATA | \ ACL_APPEND_DATA | ACL_READ_NAMED_ATTRS | ACL_WRITE_NAMED_ATTRS | \ ACL_EXECUTE | ACL_DELETE_CHILD | ACL_READ_ATTRIBUTES | \ ACL_WRITE_ATTRIBUTES | ACL_DELETE | ACL_READ_ACL | ACL_WRITE_ACL | \ ACL_WRITE_OWNER | ACL_SYNCHRONIZE) #define ACL_MODIFY_SET (ACL_FULL_SET & \ ~(ACL_WRITE_ACL | ACL_WRITE_OWNER)) #define ACL_READ_SET (ACL_READ_DATA | ACL_READ_NAMED_ATTRS | \ ACL_READ_ATTRIBUTES | ACL_READ_ACL) #define ACL_WRITE_SET (ACL_WRITE_DATA | ACL_APPEND_DATA | \ ACL_WRITE_NAMED_ATTRS | ACL_WRITE_ATTRIBUTES) #define ACL_NFS4_PERM_BITS ACL_FULL_SET /* * Possible entry_id values for acl_get_entry(3). */ #define ACL_FIRST_ENTRY 0 #define ACL_NEXT_ENTRY 1 /* * Possible values in ae_flags field; valid only for NFSv4 ACLs. */ #define ACL_ENTRY_FILE_INHERIT 0x0001 #define ACL_ENTRY_DIRECTORY_INHERIT 0x0002 #define ACL_ENTRY_NO_PROPAGATE_INHERIT 0x0004 #define ACL_ENTRY_INHERIT_ONLY 0x0008 #define ACL_ENTRY_SUCCESSFUL_ACCESS 0x0010 #define ACL_ENTRY_FAILED_ACCESS 0x0020 +#define ACL_ENTRY_INHERITED 0x0080 #define ACL_FLAGS_BITS (ACL_ENTRY_FILE_INHERIT | \ ACL_ENTRY_DIRECTORY_INHERIT | ACL_ENTRY_NO_PROPAGATE_INHERIT | \ ACL_ENTRY_INHERIT_ONLY | ACL_ENTRY_SUCCESSFUL_ACCESS | \ - ACL_ENTRY_FAILED_ACCESS) + ACL_ENTRY_FAILED_ACCESS | ACL_ENTRY_INHERITED) /* * Undefined value in ae_id field. ae_id should be set to this value * iff ae_tag is ACL_USER_OBJ, ACL_GROUP_OBJ, ACL_OTHER or ACL_EVERYONE. */ #define ACL_UNDEFINED_ID ((uid_t)-1) /* * Possible values for _flags parameter in acl_to_text_np(3). */ #define ACL_TEXT_VERBOSE 0x01 #define ACL_TEXT_NUMERIC_IDS 0x02 #define ACL_TEXT_APPEND_ID 0x04 /* * POSIX.1e ACLs are capable of expressing the read, write, and execute bits * of the POSIX mode field. We provide two masks: one that defines the bits * the ACL will replace in the mode, and the other that defines the bits that * must be preseved when an ACL is updating a mode. */ #define ACL_OVERRIDE_MASK (S_IRWXU | S_IRWXG | S_IRWXO) #define ACL_PRESERVE_MASK (~ACL_OVERRIDE_MASK) #ifdef _KERNEL /* * Filesystem-independent code to move back and forth between POSIX mode and * POSIX.1e ACL representations. */ acl_perm_t acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode); struct acl_entry acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode); mode_t acl_posix1e_perms_to_mode( struct acl_entry *acl_user_obj_entry, struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry); mode_t acl_posix1e_acl_to_mode(struct acl *acl); mode_t acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl); struct acl *acl_alloc(int flags); void acl_free(struct acl *aclp); void acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id); void acl_nfs4_sync_mode_from_acl(mode_t *mode, const struct acl *aclp); int acl_nfs4_is_trivial(const struct acl *aclp, int file_owner_id); void acl_nfs4_compute_inherited_acl( const struct acl *parent_aclp, struct acl *child_aclp, mode_t mode, int file_owner_id, int is_directory); int acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest); int acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest); /* * To allocate 'struct acl', use acl_alloc()/acl_free() instead of this. */ MALLOC_DECLARE(M_ACL); /* * Filesystem-independent syntax check for a POSIX.1e ACL. */ int acl_posix1e_check(struct acl *acl); int acl_nfs4_check(const struct acl *aclp, int is_directory); #else /* !_KERNEL */ #if defined(_ACL_PRIVATE) /* * Syscall interface -- use the library calls instead as the syscalls have * strict ACL entry ordering requirements. */ __BEGIN_DECLS int __acl_aclcheck_fd(int _filedes, acl_type_t _type, struct acl *_aclp); int __acl_aclcheck_file(const char *_path, acl_type_t _type, struct acl *_aclp); int __acl_aclcheck_link(const char *_path, acl_type_t _type, struct acl *_aclp); int __acl_delete_fd(int _filedes, acl_type_t _type); int __acl_delete_file(const char *_path_p, acl_type_t _type); int __acl_delete_link(const char *_path_p, acl_type_t _type); int __acl_get_fd(int _filedes, acl_type_t _type, struct acl *_aclp); int __acl_get_file(const char *_path, acl_type_t _type, struct acl *_aclp); int __acl_get_link(const char *_path, acl_type_t _type, struct acl *_aclp); int __acl_set_fd(int _filedes, acl_type_t _type, struct acl *_aclp); int __acl_set_file(const char *_path, acl_type_t _type, struct acl *_aclp); int __acl_set_link(const char *_path, acl_type_t _type, struct acl *_aclp); __END_DECLS #endif /* _ACL_PRIVATE */ /* * Supported POSIX.1e ACL manipulation and assignment/retrieval API _np calls * are local extensions that reflect an environment capable of opening file * descriptors of directories, and allowing additional ACL type for different * filesystems (i.e., AFS). */ __BEGIN_DECLS int acl_add_flag_np(acl_flagset_t _flagset_d, acl_flag_t _flag); int acl_add_perm(acl_permset_t _permset_d, acl_perm_t _perm); int acl_calc_mask(acl_t *_acl_p); int acl_clear_flags_np(acl_flagset_t _flagset_d); int acl_clear_perms(acl_permset_t _permset_d); int acl_copy_entry(acl_entry_t _dest_d, acl_entry_t _src_d); ssize_t acl_copy_ext(void *_buf_p, acl_t _acl, ssize_t _size); acl_t acl_copy_int(const void *_buf_p); int acl_create_entry(acl_t *_acl_p, acl_entry_t *_entry_p); int acl_create_entry_np(acl_t *_acl_p, acl_entry_t *_entry_p, int _index); int acl_delete_entry(acl_t _acl, acl_entry_t _entry_d); int acl_delete_entry_np(acl_t _acl, int _index); int acl_delete_fd_np(int _filedes, acl_type_t _type); int acl_delete_file_np(const char *_path_p, acl_type_t _type); int acl_delete_link_np(const char *_path_p, acl_type_t _type); int acl_delete_def_file(const char *_path_p); int acl_delete_def_link_np(const char *_path_p); int acl_delete_flag_np(acl_flagset_t _flagset_d, acl_flag_t _flag); int acl_delete_perm(acl_permset_t _permset_d, acl_perm_t _perm); acl_t acl_dup(acl_t _acl); int acl_free(void *_obj_p); acl_t acl_from_text(const char *_buf_p); int acl_get_brand_np(acl_t _acl, int *_brand_p); int acl_get_entry(acl_t _acl, int _entry_id, acl_entry_t *_entry_p); acl_t acl_get_fd(int _fd); acl_t acl_get_fd_np(int fd, acl_type_t _type); acl_t acl_get_file(const char *_path_p, acl_type_t _type); int acl_get_entry_type_np(acl_entry_t _entry_d, acl_entry_type_t *_entry_type_p); acl_t acl_get_link_np(const char *_path_p, acl_type_t _type); void *acl_get_qualifier(acl_entry_t _entry_d); int acl_get_flag_np(acl_flagset_t _flagset_d, acl_flag_t _flag); int acl_get_perm_np(acl_permset_t _permset_d, acl_perm_t _perm); int acl_get_flagset_np(acl_entry_t _entry_d, acl_flagset_t *_flagset_p); int acl_get_permset(acl_entry_t _entry_d, acl_permset_t *_permset_p); int acl_get_tag_type(acl_entry_t _entry_d, acl_tag_t *_tag_type_p); acl_t acl_init(int _count); int acl_set_fd(int _fd, acl_t _acl); int acl_set_fd_np(int _fd, acl_t _acl, acl_type_t _type); int acl_set_file(const char *_path_p, acl_type_t _type, acl_t _acl); int acl_set_entry_type_np(acl_entry_t _entry_d, acl_entry_type_t _entry_type); int acl_set_link_np(const char *_path_p, acl_type_t _type, acl_t _acl); int acl_set_flagset_np(acl_entry_t _entry_d, acl_flagset_t _flagset_d); int acl_set_permset(acl_entry_t _entry_d, acl_permset_t _permset_d); int acl_set_qualifier(acl_entry_t _entry_d, const void *_tag_qualifier_p); int acl_set_tag_type(acl_entry_t _entry_d, acl_tag_t _tag_type); ssize_t acl_size(acl_t _acl); char *acl_to_text(acl_t _acl, ssize_t *_len_p); char *acl_to_text_np(acl_t _acl, ssize_t *_len_p, int _flags); int acl_valid(acl_t _acl); int acl_valid_fd_np(int _fd, acl_type_t _type, acl_t _acl); int acl_valid_file_np(const char *_path_p, acl_type_t _type, acl_t _acl); int acl_valid_link_np(const char *_path_p, acl_type_t _type, acl_t _acl); int acl_is_trivial_np(const acl_t _acl, int *_trivialp); acl_t acl_strip_np(const acl_t _acl, int recalculate_mask); __END_DECLS #endif /* !_KERNEL */ #endif /* !_SYS_ACL_H_ */ Index: head/tools/regression/acltools/tools-crossfs.test =================================================================== --- head/tools/regression/acltools/tools-crossfs.test (revision 287444) +++ head/tools/regression/acltools/tools-crossfs.test (revision 287445) @@ -1,323 +1,323 @@ # Copyright (c) 2008, 2009 Edward Tomasz Napierała # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # # This is a tools-level test intended to verify that cp(1) and mv(1) # do the right thing with respect to ACLs. Run it as root using # ACL-enabled kernel: # # /usr/src/tools/regression/acltools/run /usr/src/tools/regression/acltools/tools-nfs4.test # # You need to have three subdirectories, named nfs4, posix and none, # with filesystems with NFSv4 ACLs, POSIX.1e ACLs and no ACLs enabled, # respectively, mounted on them, in your current directory. # # WARNING: Creates files in unsafe way. $ whoami > root $ umask 022 $ touch nfs4/xxx $ getfacl -nq nfs4/xxx -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ touch posix/xxx $ getfacl -nq posix/xxx > user::rw- > group::r-- > other::r-- # mv with POSIX.1e ACLs. $ rm -f posix/xxx $ rm -f posix/yyy $ touch posix/xxx $ chmod 456 posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -r--r-xrw- $ setfacl -m u:42:x,g:43:w posix/xxx $ mv posix/xxx posix/yyy $ getfacl -nq posix/yyy > user::r-- > user:42:--x > group::r-x > group:43:-w- > mask::rwx > other::rw- $ ls -l posix/yyy | cut -d' ' -f1 > -r--rwxrw-+ # mv from POSIX.1e to none. $ rm -f posix/xxx $ rm -f none/xxx $ touch posix/xxx $ chmod 345 posix/xxx $ setfacl -m u:42:x,g:43:w posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > --wxrwxr-x+ $ mv posix/xxx none/xxx > mv: failed to set acl entries for none/xxx: Operation not supported $ ls -l none/xxx | cut -d' ' -f1 > --wxrwxr-x # mv from POSIX.1e to NFSv4. $ rm -f posix/xxx $ rm -f nfs4/xxx $ touch posix/xxx $ chmod 456 posix/xxx $ setfacl -m u:42:x,g:43:w posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -r--rwxrw-+ $ mv posix/yyy nfs4/xxx > mv: failed to set acl entries for nfs4/xxx: Invalid argument $ getfacl -nq nfs4/xxx -> owner@:-wxp----------:------:deny -> owner@:r-----aARWcCos:------:allow -> group@:rwxp--a-R-c--s:------:allow -> everyone@:rw-p--a-R-c--s:------:allow +> owner@:-wxp----------:-------:deny +> owner@:r-----aARWcCos:-------:allow +> group@:rwxp--a-R-c--s:-------:allow +> everyone@:rw-p--a-R-c--s:-------:allow $ ls -l nfs4/xxx | cut -d' ' -f1 > -r--rwxrw- # mv with NFSv4 ACLs. $ rm -f nfs4/xxx $ rm -f nfs4/yyy $ touch nfs4/xxx $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ mv nfs4/xxx nfs4/yyy $ getfacl -nq nfs4/yyy -> user:42:--x-----------:------:allow -> group:43:-w------------:------:allow -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> user:42:--x-----------:-------:allow +> group:43:-w------------:-------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ ls -l nfs4/yyy | cut -d' ' -f1 > -rw-r--r--+ # mv from NFSv4 to POSIX.1e without any ACLs. $ rm -f nfs4/xxx $ rm -f posix/xxx $ touch nfs4/xxx $ chmod 456 nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > -r--r-xrw- $ mv nfs4/xxx posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -r--r-xrw- # mv from NFSv4 to none. $ rm -f nfs4/xxx $ rm -f none/xxx $ touch nfs4/xxx $ chmod 345 nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > --wxr--r-x $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > --wxr--r-x+ $ mv nfs4/xxx none/xxx > mv: failed to set acl entries for none/xxx: Operation not supported $ ls -l none/xxx | cut -d' ' -f1 > --wxr--r-x # mv from NFSv4 to POSIX.1e. $ rm -f nfs4/xxx $ rm -f posix/xxx $ touch nfs4/xxx $ chmod 345 nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > --wxr--r-x $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > --wxr--r-x+ $ mv nfs4/xxx posix/xxx > mv: failed to set acl entries for posix/xxx: Invalid argument $ ls -l posix/xxx | cut -d' ' -f1 > --wxr--r-x # cp with POSIX.1e ACLs. $ rm -f posix/xxx $ rm -f posix/yyy $ touch posix/xxx $ setfacl -m u:42:x,g:43:w posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -rw-rwxr--+ $ cp posix/xxx posix/yyy $ ls -l posix/yyy | cut -d' ' -f1 > -rw-r-xr-- # cp -p with POSIX.1e ACLs. $ rm -f posix/xxx $ rm -f posix/yyy $ touch posix/xxx $ setfacl -m u:42:x,g:43:w posix/xxx $ getfacl -nq posix/xxx > user::rw- > user:42:--x > group::r-- > group:43:-w- > mask::rwx > other::r-- $ ls -l posix/xxx | cut -d' ' -f1 > -rw-rwxr--+ $ cp -p posix/xxx posix/yyy $ getfacl -nq posix/yyy > user::rw- > user:42:--x > group::r-- > group:43:-w- > mask::rwx > other::r-- $ ls -l posix/yyy | cut -d' ' -f1 > -rw-rwxr--+ # cp from POSIX.1e to none. $ rm -f posix/xxx $ rm -f none/xxx $ touch posix/xxx $ setfacl -m u:42:x,g:43:w posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -rw-rwxr--+ $ cp posix/xxx none/xxx $ ls -l none/xxx | cut -d' ' -f1 > -rw-r-xr-- # cp -p from POSIX.1e to none. $ rm -f posix/xxx $ rm -f none/xxx $ touch posix/xxx $ setfacl -m u:42:x,g:43:w posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -rw-rwxr--+ $ cp -p posix/xxx none/xxx > cp: failed to set acl entries for none/xxx: Operation not supported $ ls -l none/xxx | cut -d' ' -f1 > -rw-rwxr-- # cp from POSIX.1e to NFSv4. $ rm -f posix/xxx $ rm -f nfs4/xxx $ touch posix/xxx $ setfacl -m u:42:x,g:43:w posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -rw-rwxr--+ $ cp posix/xxx nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > -rw-r-xr-- # cp -p from POSIX.1e to NFSv4. $ rm -f posix/xxx $ rm -f nfs4/xxx $ touch posix/xxx $ setfacl -m u:42:x,g:43:w posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -rw-rwxr--+ $ cp -p posix/xxx nfs4/xxx > cp: failed to set acl entries for nfs4/xxx: Invalid argument $ ls -l nfs4/xxx | cut -d' ' -f1 > -rw-rwxr-- # cp with NFSv4 ACLs. $ rm -f nfs4/xxx $ rm -f nfs4/yyy $ touch nfs4/xxx $ chmod 543 nfs4/xxx $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > -r-xr---wx+ $ cp nfs4/xxx nfs4/yyy $ ls -l nfs4/yyy | cut -d' ' -f1 > -r-xr----x # cp -p with NFSv4 ACLs. $ rm -f nfs4/xxx $ rm -f nfs4/yyy $ touch nfs4/xxx $ chmod 543 nfs4/xxx $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ cp -p nfs4/xxx nfs4/yyy $ getfacl -nq nfs4/yyy -> user:42:--x-----------:------:allow -> group:43:-w------------:------:allow -> owner@:--x-----------:------:allow -> owner@:-w-p----------:------:deny -> group@:-wxp----------:------:deny -> owner@:r-x---aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:-wxp--a-R-c--s:------:allow +> user:42:--x-----------:-------:allow +> group:43:-w------------:-------:allow +> owner@:--x-----------:-------:allow +> owner@:-w-p----------:-------:deny +> group@:-wxp----------:-------:deny +> owner@:r-x---aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:-wxp--a-R-c--s:-------:allow $ ls -l nfs4/yyy | cut -d' ' -f1 > -r-xr---wx+ # cp from NFSv4 to none. $ rm -f nfs4/xxx $ rm -f none/xxx $ touch nfs4/xxx $ chmod 543 nfs4/xxx $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > -r-xr---wx+ $ cp nfs4/xxx none/xxx $ ls -l none/xxx | cut -d' ' -f1 > -r-xr----x # cp -p from NFSv4 to none. $ rm -f nfs4/xxx $ rm -f none/xxx $ touch nfs4/xxx $ chmod 543 nfs4/xxx $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > -r-xr---wx+ $ cp -p nfs4/xxx none/xxx > cp: failed to set acl entries for none/xxx: Operation not supported $ ls -l none/xxx | cut -d' ' -f1 > -r-xr---wx # cp from NFSv4 to POSIX.1e. $ rm -f nfs4/xxx $ rm -f posix/xxx $ touch nfs4/xxx $ chmod 543 nfs4/xxx $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > -r-xr---wx+ $ cp nfs4/xxx posix/xxx $ ls -l posix/xxx | cut -d' ' -f1 > -r-xr----x # cp -p from NFSv4 to POSIX.1e. $ rm -f nfs4/xxx $ rm -f posix/xxx $ touch nfs4/xxx $ chmod 543 nfs4/xxx $ setfacl -a0 u:42:x:allow,g:43:w:allow nfs4/xxx $ ls -l nfs4/xxx | cut -d' ' -f1 > -r-xr---wx+ $ cp -p nfs4/xxx posix/xxx > cp: failed to set acl entries for posix/xxx: Invalid argument $ ls -l posix/xxx | cut -d' ' -f1 > -r-xr---wx Index: head/tools/regression/acltools/tools-nfs4-psarc.test =================================================================== --- head/tools/regression/acltools/tools-nfs4-psarc.test (revision 287444) +++ head/tools/regression/acltools/tools-nfs4-psarc.test (revision 287445) @@ -1,562 +1,562 @@ # Copyright (c) 2008, 2009 Edward Tomasz Napierała # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # # This is a tools-level test for NFSv4 ACL functionality with PSARC/2010/029 # semantics. Run it as root using ACL-enabled kernel: # # /usr/src/tools/regression/acltools/run /usr/src/tools/regression/acltools/tools-nfs4-psarc.test # # WARNING: Creates files in unsafe way. $ whoami > root $ umask 022 # Smoke test for getfacl(1). $ touch xxx $ getfacl xxx > # file: xxx > # owner: root > # group: wheel -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ getfacl -q xxx -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow # Check verbose mode formatting. $ getfacl -v xxx > # file: xxx > # owner: root > # group: wheel > owner@:read_data/write_data/append_data/read_attributes/write_attributes/read_xattr/write_xattr/read_acl/write_acl/write_owner/synchronize::allow > group@:read_data/read_attributes/read_xattr/read_acl/synchronize::allow > everyone@:read_data/read_attributes/read_xattr/read_acl/synchronize::allow # Test setfacl -a. $ setfacl -a2 u:0:write_acl:allow,g:1:read_acl:deny xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Test user and group name resolving. $ rm xxx $ touch xxx $ setfacl -a2 u:root:write_acl:allow,g:daemon:read_acl:deny xxx $ getfacl xxx > # file: xxx > # owner: root > # group: wheel -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> user:root:-----------C--:------:allow -> group:daemon:----------c---:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> user:root:-----------C--:-------:allow +> group:daemon:----------c---:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Check whether ls correctly marks files with "+". $ ls -l xxx | cut -d' ' -f1 > -rw-r--r--+ # Test removing entries by number. $ setfacl -x 1 xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:rw-p--aARWcCos:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Test setfacl -m. $ setfacl -a0 everyone@:rwx:deny xxx $ setfacl -a0 everyone@:rwx:deny xxx $ setfacl -a0 everyone@:rwx:deny xxx $ setfacl -m everyone@::deny xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> owner@:rw-p--aARWcCos:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:r-----a-R-c--s:------:allow +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> owner@:rw-p--aARWcCos:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Test getfacl -i. $ getfacl -i xxx > # file: xxx > # owner: root > # group: wheel -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> owner@:rw-p--aARWcCos:------:allow -> user:root:-----------C--:------:allow:0 -> group:daemon:----------c---:------:deny:1 -> everyone@:r-----a-R-c--s:------:allow +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> owner@:rw-p--aARWcCos:-------:allow +> user:root:-----------C--:-------:allow:0 +> group:daemon:----------c---:-------:deny:1 +> everyone@:r-----a-R-c--s:-------:allow # Make sure cp without any flags does not copy copy the ACL. $ cp xxx yyy $ ls -l yyy | cut -d' ' -f1 > -rw-r--r-- # Make sure it does with the "-p" flag. $ rm yyy $ cp -p xxx yyy $ getfacl -n yyy > # file: yyy > # owner: root > # group: wheel -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> owner@:rw-p--aARWcCos:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:r-----a-R-c--s:------:allow +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> owner@:rw-p--aARWcCos:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ rm yyy # Test removing entries by... by example? $ setfacl -x everyone@::deny xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:rw-p--aARWcCos:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Test setfacl -b. $ setfacl -b xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > -rw-r--r-- # Check setfacl(1) and getfacl(1) with multiple files. $ touch xxx yyy zzz $ ls -l xxx yyy zzz | cut -d' ' -f1 > -rw-r--r-- > -rw-r--r-- > -rw-r--r-- $ setfacl -m u:42:x:allow,g:43:w:allow nnn xxx yyy zzz > setfacl: nnn: stat() failed: No such file or directory $ ls -l nnn xxx yyy zzz | cut -d' ' -f1 > ls: nnn: No such file or directory > -rw-r--r--+ > -rw-r--r--+ > -rw-r--r--+ $ getfacl -nq nnn xxx yyy zzz > getfacl: nnn: stat() failed: No such file or directory -> user:42:--x-----------:------:allow -> group:43:-w------------:------:allow -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> user:42:--x-----------:-------:allow +> group:43:-w------------:-------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow > -> user:42:--x-----------:------:allow -> group:43:-w------------:------:allow -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> user:42:--x-----------:-------:allow +> group:43:-w------------:-------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow > -> user:42:--x-----------:------:allow -> group:43:-w------------:------:allow -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> user:42:--x-----------:-------:allow +> group:43:-w------------:-------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ setfacl -b nnn xxx yyy zzz > setfacl: nnn: stat() failed: No such file or directory $ ls -l nnn xxx yyy zzz | cut -d' ' -f1 > ls: nnn: No such file or directory > -rw-r--r-- > -rw-r--r-- > -rw-r--r-- $ rm xxx yyy zzz # Test applying mode to an ACL. $ touch xxx $ setfacl -a0 user:42:r:allow,user:43:w:deny,user:43:w:allow,user:44:x:allow -x everyone@::allow xxx $ chmod 600 xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:rw-p--aARWcCos:------:allow -> group@:------a-R-c--s:------:allow -> everyone@:------a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:------a-R-c--s:-------:allow +> everyone@:------a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > -rw------- $ rm xxx $ touch xxx $ chown 42 xxx $ setfacl -a0 user:42:r:allow,user:43:w:deny,user:43:w:allow,user:44:x:allow xxx $ chmod 600 xxx $ getfacl -n xxx > # file: xxx > # owner: 42 > # group: wheel -> owner@:rw-p--aARWcCos:------:allow -> group@:------a-R-c--s:------:allow -> everyone@:------a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:------a-R-c--s:-------:allow +> everyone@:------a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > -rw------- $ rm xxx $ touch xxx $ chown 43 xxx $ setfacl -a0 user:42:r:allow,user:43:w:deny,user:43:w:allow,user:44:x:allow xxx $ chmod 124 xxx $ getfacl -n xxx > # file: xxx > # owner: 43 > # group: wheel -> owner@:rw-p----------:------:deny -> group@:r-------------:------:deny -> owner@:--x---aARWcCos:------:allow -> group@:-w-p--a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p----------:-------:deny +> group@:r-------------:-------:deny +> owner@:--x---aARWcCos:-------:allow +> group@:-w-p--a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > ---x-w-r-- $ rm xxx $ touch xxx $ chown 43 xxx $ setfacl -a0 user:42:r:allow,user:43:w:deny,user:43:w:allow,user:44:x:allow xxx $ chmod 412 xxx $ getfacl -n xxx > # file: xxx > # owner: 43 > # group: wheel -> owner@:-wxp----------:------:deny -> group@:-w-p----------:------:deny -> owner@:r-----aARWcCos:------:allow -> group@:--x---a-R-c--s:------:allow -> everyone@:-w-p--a-R-c--s:------:allow +> owner@:-wxp----------:-------:deny +> group@:-w-p----------:-------:deny +> owner@:r-----aARWcCos:-------:allow +> group@:--x---a-R-c--s:-------:allow +> everyone@:-w-p--a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > -r----x-w- $ mkdir ddd $ setfacl -a0 group:44:rwapd:allow ddd $ setfacl -a0 group:43:write_data/delete_child:d:deny,group@:ad:allow ddd $ setfacl -a0 user:42:rx:fi:allow,group:42:write_data/delete_child:d:allow ddd $ setfacl -m everyone@:-w-p--a-R-c--s:fi:allow ddd $ getfacl -n ddd > # file: ddd > # owner: root > # group: wheel -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:-d----:allow -> group:43:-w--D---------:-d----:deny -> group@:-----da-------:------:allow -> group:44:rw-p-da-------:------:allow -> owner@:rwxp--aARWcCos:------:allow -> group@:r-x---a-R-c--s:------:allow -> everyone@:-w-p--a-R-c--s:f-i---:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-d-----:allow +> group:43:-w--D---------:-d-----:deny +> group@:-----da-------:-------:allow +> group:44:rw-p-da-------:-------:allow +> owner@:rwxp--aARWcCos:-------:allow +> group@:r-x---a-R-c--s:-------:allow +> everyone@:-w-p--a-R-c--s:f-i----:allow $ chmod 777 ddd $ getfacl -n ddd > # file: ddd > # owner: root > # group: wheel -> owner@:rwxp--aARWcCos:------:allow -> group@:rwxp--a-R-c--s:------:allow -> everyone@:rwxp--a-R-c--s:------:allow +> owner@:rwxp--aARWcCos:-------:allow +> group@:rwxp--a-R-c--s:-------:allow +> everyone@:rwxp--a-R-c--s:-------:allow # Test applying ACL to mode. $ rmdir ddd $ mkdir ddd $ setfacl -a0 u:42:rwx:fi:allow ddd $ ls -ld ddd | cut -d' ' -f1 > drwxr-xr-x+ $ rmdir ddd $ mkdir ddd $ chmod 0 ddd $ setfacl -a0 owner@:r:allow,group@:w:deny,group@:wx:allow ddd $ ls -ld ddd | cut -d' ' -f1 > dr----x---+ $ rmdir ddd $ mkdir ddd $ chmod 0 ddd $ setfacl -a0 owner@:r:allow,group@:w:fi:deny,group@:wx:allow ddd $ ls -ld ddd | cut -d' ' -f1 > dr---wx---+ $ rmdir ddd $ mkdir ddd $ chmod 0 ddd $ setfacl -a0 owner@:r:allow,group:43:w:deny,group:43:wx:allow ddd $ ls -ld ddd | cut -d' ' -f1 > dr--------+ $ rmdir ddd $ mkdir ddd $ chmod 0 ddd $ setfacl -a0 owner@:r:allow,user:43:w:deny,user:43:wx:allow ddd $ ls -ld ddd | cut -d' ' -f1 > dr--------+ # Test inheritance. $ rmdir ddd $ mkdir ddd $ setfacl -a0 group:43:write_data/write_acl:fin:deny,u:43:rwxp:allow ddd $ setfacl -a0 user:42:rx:fi:allow,group:42:write_data/delete_child:dn:deny ddd $ setfacl -a0 user:42:write_acl/write_owner:fi:allow ddd $ setfacl -a0 group:41:read_data/read_attributes:dni:allow ddd $ setfacl -a0 user:41:write_data/write_attributes:fn:allow ddd $ getfacl -qn ddd -> user:41:-w-----A------:f--n--:allow -> group:41:r-----a-------:-din--:allow -> user:42:-----------Co-:f-i---:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:-d-n--:deny -> group:43:-w---------C--:f-in--:deny -> user:43:rwxp----------:------:allow -> owner@:rwxp--aARWcCos:------:allow -> group@:r-x---a-R-c--s:------:allow -> everyone@:r-x---a-R-c--s:------:allow +> user:41:-w-----A------:f--n---:allow +> group:41:r-----a-------:-din---:allow +> user:42:-----------Co-:f-i----:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-d-n---:deny +> group:43:-w---------C--:f-in---:deny +> user:43:rwxp----------:-------:allow +> owner@:rwxp--aARWcCos:-------:allow +> group@:r-x---a-R-c--s:-------:allow +> everyone@:r-x---a-R-c--s:-------:allow $ cd ddd $ touch xxx $ getfacl -qn xxx -> user:41:--------------:------:allow -> user:42:--------------:------:allow -> user:42:r-------------:------:allow -> group:43:-w---------C--:------:deny -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> user:41:--------------:------I:allow +> user:42:--------------:------I:allow +> user:42:r-------------:------I:allow +> group:43:-w---------C--:------I:deny +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ rm xxx $ umask 077 $ touch xxx $ getfacl -qn xxx -> user:41:--------------:------:allow -> user:42:--------------:------:allow -> user:42:--------------:------:allow -> group:43:-w---------C--:------:deny -> owner@:rw-p--aARWcCos:------:allow -> group@:------a-R-c--s:------:allow -> everyone@:------a-R-c--s:------:allow +> user:41:--------------:------I:allow +> user:42:--------------:------I:allow +> user:42:--------------:------I:allow +> group:43:-w---------C--:------I:deny +> owner@:rw-p--aARWcCos:-------:allow +> group@:------a-R-c--s:-------:allow +> everyone@:------a-R-c--s:-------:allow $ rm xxx $ umask 770 $ touch xxx $ getfacl -qn xxx -> owner@:rw-p----------:------:deny -> group@:rw-p----------:------:deny -> user:41:--------------:------:allow -> user:42:--------------:------:allow -> user:42:--------------:------:allow -> group:43:-w---------C--:------:deny -> owner@:------aARWcCos:------:allow -> group@:------a-R-c--s:------:allow -> everyone@:rw-p--a-R-c--s:------:allow +> owner@:rw-p----------:-------:deny +> group@:rw-p----------:-------:deny +> user:41:--------------:------I:allow +> user:42:--------------:------I:allow +> user:42:--------------:------I:allow +> group:43:-w---------C--:------I:deny +> owner@:------aARWcCos:-------:allow +> group@:------a-R-c--s:-------:allow +> everyone@:rw-p--a-R-c--s:-------:allow $ rm xxx $ umask 707 $ touch xxx $ getfacl -qn xxx -> owner@:rw-p----------:------:deny -> user:41:-w------------:------:allow -> user:42:--------------:------:allow -> user:42:r-------------:------:allow -> group:43:-w---------C--:------:deny -> owner@:------aARWcCos:------:allow -> group@:rw-p--a-R-c--s:------:allow -> everyone@:------a-R-c--s:------:allow +> owner@:rw-p----------:-------:deny +> user:41:-w------------:------I:allow +> user:42:--------------:------I:allow +> user:42:r-------------:------I:allow +> group:43:-w---------C--:------I:deny +> owner@:------aARWcCos:-------:allow +> group@:rw-p--a-R-c--s:-------:allow +> everyone@:------a-R-c--s:-------:allow $ umask 077 $ mkdir yyy $ getfacl -qn yyy -> group:41:------a-------:------:allow -> user:42:-----------Co-:f-i---:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:------:deny -> owner@:rwxp--aARWcCos:------:allow -> group@:------a-R-c--s:------:allow -> everyone@:------a-R-c--s:------:allow +> group:41:------a-------:------I:allow +> user:42:-----------Co-:f-i---I:allow +> user:42:r-x-----------:f-i---I:allow +> group:42:-w--D---------:------I:deny +> owner@:rwxp--aARWcCos:-------:allow +> group@:------a-R-c--s:-------:allow +> everyone@:------a-R-c--s:-------:allow $ rmdir yyy $ umask 770 $ mkdir yyy $ getfacl -qn yyy -> owner@:rwxp----------:------:deny -> group@:rwxp----------:------:deny -> group:41:------a-------:------:allow -> user:42:-----------Co-:f-i---:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:------:deny -> owner@:------aARWcCos:------:allow -> group@:------a-R-c--s:------:allow -> everyone@:rwxp--a-R-c--s:------:allow +> owner@:rwxp----------:-------:deny +> group@:rwxp----------:-------:deny +> group:41:------a-------:------I:allow +> user:42:-----------Co-:f-i---I:allow +> user:42:r-x-----------:f-i---I:allow +> group:42:-w--D---------:------I:deny +> owner@:------aARWcCos:-------:allow +> group@:------a-R-c--s:-------:allow +> everyone@:rwxp--a-R-c--s:-------:allow $ rmdir yyy $ umask 707 $ mkdir yyy $ getfacl -qn yyy -> owner@:rwxp----------:------:deny -> group:41:r-----a-------:------:allow -> user:42:-----------Co-:f-i---:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:------:deny -> owner@:------aARWcCos:------:allow -> group@:rwxp--a-R-c--s:------:allow -> everyone@:------a-R-c--s:------:allow +> owner@:rwxp----------:-------:deny +> group:41:r-----a-------:------I:allow +> user:42:-----------Co-:f-i---I:allow +> user:42:r-x-----------:f-i---I:allow +> group:42:-w--D---------:------I:deny +> owner@:------aARWcCos:-------:allow +> group@:rwxp--a-R-c--s:-------:allow +> everyone@:------a-R-c--s:-------:allow # There is some complication regarding how write_acl and write_owner flags # get inherited. Make sure we got it right. $ setfacl -b . $ setfacl -a0 u:42:Co:f:allow . $ setfacl -a0 u:43:Co:d:allow . $ setfacl -a0 u:44:Co:fd:allow . $ setfacl -a0 u:45:Co:fi:allow . $ setfacl -a0 u:46:Co:di:allow . $ setfacl -a0 u:47:Co:fdi:allow . $ setfacl -a0 u:48:Co:fn:allow . $ setfacl -a0 u:49:Co:dn:allow . $ setfacl -a0 u:50:Co:fdn:allow . $ setfacl -a0 u:51:Co:fni:allow . $ setfacl -a0 u:52:Co:dni:allow . $ setfacl -a0 u:53:Co:fdni:allow . $ umask 022 $ rm xxx $ touch xxx $ getfacl -nq xxx -> user:53:--------------:------:allow -> user:51:--------------:------:allow -> user:50:--------------:------:allow -> user:48:--------------:------:allow -> user:47:--------------:------:allow -> user:45:--------------:------:allow -> user:44:--------------:------:allow -> user:42:--------------:------:allow -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> user:53:--------------:------I:allow +> user:51:--------------:------I:allow +> user:50:--------------:------I:allow +> user:48:--------------:------I:allow +> user:47:--------------:------I:allow +> user:45:--------------:------I:allow +> user:44:--------------:------I:allow +> user:42:--------------:------I:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ rmdir yyy $ mkdir yyy $ getfacl -nq yyy -> user:53:--------------:------:allow -> user:52:--------------:------:allow -> user:50:--------------:------:allow -> user:49:--------------:------:allow -> user:47:--------------:fd----:allow -> user:46:--------------:-d----:allow -> user:45:-----------Co-:f-i---:allow -> user:44:--------------:fd----:allow -> user:43:--------------:-d----:allow -> user:42:-----------Co-:f-i---:allow -> owner@:rwxp--aARWcCos:------:allow -> group@:r-x---a-R-c--s:------:allow -> everyone@:r-x---a-R-c--s:------:allow +> user:53:--------------:------I:allow +> user:52:--------------:------I:allow +> user:50:--------------:------I:allow +> user:49:--------------:------I:allow +> user:47:--------------:fd----I:allow +> user:46:--------------:-d----I:allow +> user:45:-----------Co-:f-i---I:allow +> user:44:--------------:fd----I:allow +> user:43:--------------:-d----I:allow +> user:42:-----------Co-:f-i---I:allow +> owner@:rwxp--aARWcCos:-------:allow +> group@:r-x---a-R-c--s:-------:allow +> everyone@:r-x---a-R-c--s:-------:allow $ setfacl -b . $ setfacl -a0 u:42:Co:f:deny . $ setfacl -a0 u:43:Co:d:deny . $ setfacl -a0 u:44:Co:fd:deny . $ setfacl -a0 u:45:Co:fi:deny . $ setfacl -a0 u:46:Co:di:deny . $ setfacl -a0 u:47:Co:fdi:deny . $ setfacl -a0 u:48:Co:fn:deny . $ setfacl -a0 u:49:Co:dn:deny . $ setfacl -a0 u:50:Co:fdn:deny . $ setfacl -a0 u:51:Co:fni:deny . $ setfacl -a0 u:52:Co:dni:deny . $ setfacl -a0 u:53:Co:fdni:deny . $ umask 022 $ rm xxx $ touch xxx $ getfacl -nq xxx -> user:53:-----------Co-:------:deny -> user:51:-----------Co-:------:deny -> user:50:-----------Co-:------:deny -> user:48:-----------Co-:------:deny -> user:47:-----------Co-:------:deny -> user:45:-----------Co-:------:deny -> user:44:-----------Co-:------:deny -> user:42:-----------Co-:------:deny -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> user:53:-----------Co-:------I:deny +> user:51:-----------Co-:------I:deny +> user:50:-----------Co-:------I:deny +> user:48:-----------Co-:------I:deny +> user:47:-----------Co-:------I:deny +> user:45:-----------Co-:------I:deny +> user:44:-----------Co-:------I:deny +> user:42:-----------Co-:------I:deny +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow $ rmdir yyy $ mkdir yyy $ getfacl -nq yyy -> user:53:-----------Co-:------:deny -> user:52:-----------Co-:------:deny -> user:50:-----------Co-:------:deny -> user:49:-----------Co-:------:deny -> user:47:-----------Co-:fd----:deny -> user:46:-----------Co-:-d----:deny -> user:45:-----------Co-:f-i---:deny -> user:44:-----------Co-:fd----:deny -> user:43:-----------Co-:-d----:deny -> user:42:-----------Co-:f-i---:deny -> owner@:rwxp--aARWcCos:------:allow -> group@:r-x---a-R-c--s:------:allow -> everyone@:r-x---a-R-c--s:------:allow +> user:53:-----------Co-:------I:deny +> user:52:-----------Co-:------I:deny +> user:50:-----------Co-:------I:deny +> user:49:-----------Co-:------I:deny +> user:47:-----------Co-:fd----I:deny +> user:46:-----------Co-:-d----I:deny +> user:45:-----------Co-:f-i---I:deny +> user:44:-----------Co-:fd----I:deny +> user:43:-----------Co-:-d----I:deny +> user:42:-----------Co-:f-i---I:deny +> owner@:rwxp--aARWcCos:-------:allow +> group@:r-x---a-R-c--s:-------:allow +> everyone@:r-x---a-R-c--s:-------:allow $ rmdir yyy $ rm xxx $ cd .. $ rmdir ddd $ rm xxx Index: head/tools/regression/acltools/tools-nfs4-trivial.test =================================================================== --- head/tools/regression/acltools/tools-nfs4-trivial.test (revision 287444) +++ head/tools/regression/acltools/tools-nfs4-trivial.test (revision 287445) @@ -1,82 +1,82 @@ # Copyright (c) 2011 Edward Tomasz Napierała # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # # This is a tools-level test for acl_is_trivial_np(3). Run it as root on ZFS. # Note that this does not work on UFS with NFSv4 ACLs enabled - UFS recognizes # both kind of trivial ACLs and replaces it by the default one. # # WARNING: Creates files in unsafe way. $ whoami > root $ umask 022 # Check whether ls(1) correctly recognizes PSARC/2010/029-style trivial ACLs. $ touch xxx $ ls -l xxx | cut -d' ' -f1 > -rw-r--r-- $ getfacl -q xxx -> owner@:rw-p--aARWcCos:------:allow -> group@:r-----a-R-c--s:------:allow -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p--aARWcCos:-------:allow +> group@:r-----a-R-c--s:-------:allow +> everyone@:r-----a-R-c--s:-------:allow # Check whether ls(1) correctly recognizes draft-style trivial ACLs. $ rm xxx $ touch xxx $ setfacl -a0 owner@:x:deny,owner@:rwpAWCo:allow,group@:wxp:deny,group@:r:allow,everyone@:wxpAWCo:deny,everyone@:raRcs:allow xxx $ setfacl -x5 xxx $ setfacl -x5 xxx $ setfacl -x5 xxx $ ls -l xxx | cut -d' ' -f1 > -rw-r--r-- $ getfacl -q xxx -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Make sure ls(1) actually can recognize something as non-trivial. $ setfacl -x0 xxx $ ls -l xxx | cut -d' ' -f1 > -rw-r--r--+ $ getfacl -q xxx -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ rm xxx Index: head/tools/regression/acltools/tools-nfs4.test =================================================================== --- head/tools/regression/acltools/tools-nfs4.test (revision 287444) +++ head/tools/regression/acltools/tools-nfs4.test (revision 287445) @@ -1,828 +1,828 @@ # Copyright (c) 2008, 2009 Edward Tomasz Napierała # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # # This is a tools-level test for NFSv4 ACL functionality. Run it as root # using ACL-enabled kernel: # # /usr/src/tools/regression/acltools/run /usr/src/tools/regression/acltools/tools-nfs4.test # # WARNING: Creates files in unsafe way. $ whoami > root $ umask 022 # Smoke test for getfacl(1). $ touch xxx $ getfacl xxx > # file: xxx > # owner: root > # group: wheel -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ getfacl -q xxx -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Check verbose mode formatting. $ getfacl -v xxx > # file: xxx > # owner: root > # group: wheel > owner@:execute::deny > owner@:read_data/write_data/append_data/write_attributes/write_xattr/write_acl/write_owner::allow > group@:write_data/execute/append_data::deny > group@:read_data::allow > everyone@:write_data/execute/append_data/write_attributes/write_xattr/write_acl/write_owner::deny > everyone@:read_data/read_attributes/read_xattr/read_acl/synchronize::allow # Test setfacl -a. $ setfacl -a2 u:0:write_acl:allow,g:1:read_acl:deny xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Test user and group name resolving. $ rm xxx $ touch xxx $ setfacl -a2 u:root:write_acl:allow,g:daemon:read_acl:deny xxx $ getfacl xxx > # file: xxx > # owner: root > # group: wheel -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> user:root:-----------C--:------:allow -> group:daemon:----------c---:------:deny -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> user:root:-----------C--:-------:allow +> group:daemon:----------c---:-------:deny +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Check whether ls correctly marks files with "+". $ ls -l xxx | cut -d' ' -f1 > -rw-r--r--+ # Test removing entries by number. $ setfacl -x 4 xxx $ setfacl -x 4 xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Test setfacl -m. $ setfacl -a0 everyone@:rwx:deny xxx $ setfacl -a0 everyone@:rwx:deny xxx $ setfacl -a0 everyone@:rwx:deny xxx $ setfacl -m everyone@::deny xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:--------------:------:deny -> everyone@:r-----a-R-c--s:------:allow +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:--------------:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Test getfacl -i. $ getfacl -i xxx > # file: xxx > # owner: root > # group: wheel -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> user:root:-----------C--:------:allow:0 -> group:daemon:----------c---:------:deny:1 -> everyone@:--------------:------:deny -> everyone@:r-----a-R-c--s:------:allow +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> user:root:-----------C--:-------:allow:0 +> group:daemon:----------c---:-------:deny:1 +> everyone@:--------------:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Make sure cp without any flags does not copy copy the ACL. $ cp xxx yyy $ ls -l yyy | cut -d' ' -f1 > -rw-r--r-- # Make sure it does with the "-p" flag. $ rm yyy $ cp -p xxx yyy $ getfacl -n yyy > # file: yyy > # owner: root > # group: wheel -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> everyone@:--------------:------:deny -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:--------------:------:deny -> everyone@:r-----a-R-c--s:------:allow +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> everyone@:--------------:-------:deny +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:--------------:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ rm yyy # Test removing entries by... by example? $ setfacl -x everyone@::deny xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> user:0:-----------C--:------:allow -> group:1:----------c---:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> user:0:-----------C--:-------:allow +> group:1:----------c---:-------:deny +> everyone@:r-----a-R-c--s:-------:allow # Test setfacl -b. $ setfacl -b xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > -rw-r--r-- # Check setfacl(1) and getfacl(1) with multiple files. $ touch xxx yyy zzz $ ls -l xxx yyy zzz | cut -d' ' -f1 > -rw-r--r-- > -rw-r--r-- > -rw-r--r-- $ setfacl -m u:42:x:allow,g:43:w:allow nnn xxx yyy zzz > setfacl: nnn: stat() failed: No such file or directory $ ls -l nnn xxx yyy zzz | cut -d' ' -f1 > ls: nnn: No such file or directory > -rw-r--r--+ > -rw-r--r--+ > -rw-r--r--+ $ getfacl -nq nnn xxx yyy zzz > getfacl: nnn: stat() failed: No such file or directory -> user:42:--x-----------:------:allow -> group:43:-w------------:------:allow -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> user:42:--x-----------:-------:allow +> group:43:-w------------:-------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow > -> user:42:--x-----------:------:allow -> group:43:-w------------:------:allow -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> user:42:--x-----------:-------:allow +> group:43:-w------------:-------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow > -> user:42:--x-----------:------:allow -> group:43:-w------------:------:allow -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> user:42:--x-----------:-------:allow +> group:43:-w------------:-------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ setfacl -b nnn xxx yyy zzz > setfacl: nnn: stat() failed: No such file or directory $ ls -l nnn xxx yyy zzz | cut -d' ' -f1 > ls: nnn: No such file or directory > -rw-r--r-- > -rw-r--r-- > -rw-r--r-- $ rm xxx yyy zzz # Test applying mode to an ACL. $ touch xxx $ setfacl -a0 user:42:r:allow,user:43:w:deny,user:43:w:allow,user:44:x:allow -x everyone@::allow xxx $ chmod 600 xxx $ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel -> user:42:r-------------:------:deny -> user:42:r-------------:------:allow -> user:43:-w------------:------:deny -> user:43:-w------------:------:allow -> user:44:--x-----------:------:deny -> user:44:--x-----------:------:allow -> owner@:--------------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:--------------:------:deny -> group@:--------------:------:allow -> everyone@:-------A-W-Co-:------:deny -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:rwxp----------:------:deny -> group@:--------------:------:allow -> everyone@:rwxp---A-W-Co-:------:deny -> everyone@:------a-R-c--s:------:allow +> user:42:r-------------:-------:deny +> user:42:r-------------:-------:allow +> user:43:-w------------:-------:deny +> user:43:-w------------:-------:allow +> user:44:--x-----------:-------:deny +> user:44:--x-----------:-------:allow +> owner@:--------------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:--------------:-------:deny +> group@:--------------:-------:allow +> everyone@:-------A-W-Co-:-------:deny +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:rwxp----------:-------:deny +> group@:--------------:-------:allow +> everyone@:rwxp---A-W-Co-:-------:deny +> everyone@:------a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > -rw-------+ $ rm xxx $ touch xxx $ chown 42 xxx $ setfacl -a0 user:42:r:allow,user:43:w:deny,user:43:w:allow,user:44:x:allow xxx $ chmod 600 xxx $ getfacl -n xxx > # file: xxx > # owner: 42 > # group: wheel -> user:42:--------------:------:deny -> user:42:r-------------:------:allow -> user:43:-w------------:------:deny -> user:43:-w------------:------:allow -> user:44:--x-----------:------:deny -> user:44:--x-----------:------:allow -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:rwxp----------:------:deny -> group@:--------------:------:allow -> everyone@:rwxp---A-W-Co-:------:deny -> everyone@:------a-R-c--s:------:allow +> user:42:--------------:-------:deny +> user:42:r-------------:-------:allow +> user:43:-w------------:-------:deny +> user:43:-w------------:-------:allow +> user:44:--x-----------:-------:deny +> user:44:--x-----------:-------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:rwxp----------:-------:deny +> group@:--------------:-------:allow +> everyone@:rwxp---A-W-Co-:-------:deny +> everyone@:------a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > -rw-------+ $ rm xxx $ touch xxx $ chown 43 xxx $ setfacl -a0 user:42:r:allow,user:43:w:deny,user:43:w:allow,user:44:x:allow xxx $ chmod 124 xxx $ getfacl -n xxx > # file: xxx > # owner: 43 > # group: wheel -> user:42:r-------------:------:deny -> user:42:r-------------:------:allow -> user:43:-w------------:------:deny -> user:43:-w------------:------:allow -> user:44:--x-----------:------:deny -> user:44:--x-----------:------:allow -> owner@:rw-p----------:------:deny -> owner@:--x----A-W-Co-:------:allow -> group@:r-x-----------:------:deny -> group@:-w-p----------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> user:42:r-------------:-------:deny +> user:42:r-------------:-------:allow +> user:43:-w------------:-------:deny +> user:43:-w------------:-------:allow +> user:44:--x-----------:-------:deny +> user:44:--x-----------:-------:allow +> owner@:rw-p----------:-------:deny +> owner@:--x----A-W-Co-:-------:allow +> group@:r-x-----------:-------:deny +> group@:-w-p----------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > ---x-w-r--+ $ rm xxx $ touch xxx $ chown 43 xxx $ setfacl -a0 user:42:r:allow,user:43:w:deny,user:43:w:allow,user:44:x:allow xxx $ chmod 412 xxx $ getfacl -n xxx > # file: xxx > # owner: 43 > # group: wheel -> user:42:r-------------:------:deny -> user:42:r-------------:------:allow -> user:43:-w------------:------:deny -> user:43:-w------------:------:allow -> user:44:--------------:------:deny -> user:44:--x-----------:------:allow -> owner@:-wxp----------:------:deny -> owner@:r------A-W-Co-:------:allow -> group@:rw-p----------:------:deny -> group@:--x-----------:------:allow -> everyone@:r-x----A-W-Co-:------:deny -> everyone@:-w-p--a-R-c--s:------:allow +> user:42:r-------------:-------:deny +> user:42:r-------------:-------:allow +> user:43:-w------------:-------:deny +> user:43:-w------------:-------:allow +> user:44:--------------:-------:deny +> user:44:--x-----------:-------:allow +> owner@:-wxp----------:-------:deny +> owner@:r------A-W-Co-:-------:allow +> group@:rw-p----------:-------:deny +> group@:--x-----------:-------:allow +> everyone@:r-x----A-W-Co-:-------:deny +> everyone@:-w-p--a-R-c--s:-------:allow $ ls -l xxx | cut -d' ' -f1 > -r----x-w-+ $ mkdir ddd $ setfacl -a0 group:44:rwapd:allow ddd $ setfacl -a0 group:43:write_data/delete_child:d:deny,group@:ad:allow ddd $ setfacl -a0 user:42:rx:fi:allow,group:42:write_data/delete_child:d:allow ddd $ setfacl -m everyone@:-w-p--a-R-c--s:fi:allow ddd $ getfacl -n ddd > # file: ddd > # owner: root > # group: wheel -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:-d----:allow -> group:43:-w--D---------:-d----:deny -> group@:-----da-------:------:allow -> group:44:rw-p-da-------:------:allow -> owner@:--------------:------:deny -> owner@:rwxp---A-W-Co-:------:allow -> group@:-w-p----------:------:deny -> group@:r-x-----------:------:allow -> everyone@:-w-p---A-W-Co-:------:deny -> everyone@:-w-p--a-R-c--s:f-i---:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-d-----:allow +> group:43:-w--D---------:-d-----:deny +> group@:-----da-------:-------:allow +> group:44:rw-p-da-------:-------:allow +> owner@:--------------:-------:deny +> owner@:rwxp---A-W-Co-:-------:allow +> group@:-w-p----------:-------:deny +> group@:r-x-----------:-------:allow +> everyone@:-w-p---A-W-Co-:-------:deny +> everyone@:-w-p--a-R-c--s:f-i----:allow $ chmod 777 ddd $ getfacl -n ddd > # file: ddd > # owner: root > # group: wheel -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:-di---:allow -> group:42:--------------:------:deny -> group:42:-w--D---------:------:allow -> group:43:-w--D---------:-di---:deny -> group:43:-w--D---------:------:deny -> group@:-----da-------:------:allow -> group:44:--------------:------:deny -> group:44:rw-p-da-------:------:allow -> owner@:--------------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:--------------:------:deny -> group@:--------------:------:allow -> everyone@:-------A-W-Co-:------:deny -> everyone@:-w-p--a-R-c--s:f-i---:allow -> owner@:--------------:------:deny -> owner@:rwxp---A-W-Co-:------:allow -> group@:--------------:------:deny -> group@:rwxp----------:------:allow -> everyone@:-------A-W-Co-:------:deny -> everyone@:rwxp--a-R-c--s:------:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-di----:allow +> group:42:--------------:-------:deny +> group:42:-w--D---------:-------:allow +> group:43:-w--D---------:-di----:deny +> group:43:-w--D---------:-------:deny +> group@:-----da-------:-------:allow +> group:44:--------------:-------:deny +> group:44:rw-p-da-------:-------:allow +> owner@:--------------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:--------------:-------:deny +> group@:--------------:-------:allow +> everyone@:-------A-W-Co-:-------:deny +> everyone@:-w-p--a-R-c--s:f-i----:allow +> owner@:--------------:-------:deny +> owner@:rwxp---A-W-Co-:-------:allow +> group@:--------------:-------:deny +> group@:rwxp----------:-------:allow +> everyone@:-------A-W-Co-:-------:deny +> everyone@:rwxp--a-R-c--s:-------:allow $ rmdir ddd $ mkdir ddd $ setfacl -a0 group:44:rwapd:allow ddd $ setfacl -a0 group:43:write_data/delete_child:d:deny,group@:ad:allow ddd $ setfacl -a0 user:42:rx:fi:allow,group:42:write_data/delete_child:d:allow ddd $ setfacl -m everyone@:-w-p--a-R-c--s:fi:allow ddd $ chmod 124 ddd $ getfacl -n ddd > # file: ddd > # owner: root > # group: wheel -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:-di---:allow -> group:42:--------------:------:deny -> group:42:----D---------:------:allow -> group:43:-w--D---------:-di---:deny -> group:43:-w--D---------:------:deny -> group@:-----da-------:------:allow -> group:44:r-------------:------:deny -> group:44:r----da-------:------:allow -> owner@:--------------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:--------------:------:deny -> group@:--------------:------:allow -> everyone@:-------A-W-Co-:------:deny -> everyone@:-w-p--a-R-c--s:f-i---:allow -> owner@:rw-p----------:------:deny -> owner@:--x----A-W-Co-:------:allow -> group@:r-x-----------:------:deny -> group@:-w-p----------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-di----:allow +> group:42:--------------:-------:deny +> group:42:----D---------:-------:allow +> group:43:-w--D---------:-di----:deny +> group:43:-w--D---------:-------:deny +> group@:-----da-------:-------:allow +> group:44:r-------------:-------:deny +> group:44:r----da-------:-------:allow +> owner@:--------------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:--------------:-------:deny +> group@:--------------:-------:allow +> everyone@:-------A-W-Co-:-------:deny +> everyone@:-w-p--a-R-c--s:f-i----:allow +> owner@:rw-p----------:-------:deny +> owner@:--x----A-W-Co-:-------:allow +> group@:r-x-----------:-------:deny +> group@:-w-p----------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ rmdir ddd $ mkdir ddd $ setfacl -a0 group:44:rwapd:allow ddd $ setfacl -a0 group:43:write_data/delete_child:d:deny,group@:ad:allow ddd $ setfacl -a0 user:42:rx:allow,user:42:rx:fi:allow,group:42:write_data/delete_child:d:allow ddd $ setfacl -m everyone@:-w-p--a-R-c--s:fi:allow ddd $ chmod 412 ddd $ getfacl -n ddd > # file: ddd > # owner: root > # group: wheel -> user:42:r-------------:------:deny -> user:42:r-x-----------:------:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:-di---:allow -> group:42:-w------------:------:deny -> group:42:-w--D---------:------:allow -> group:43:-w--D---------:-di---:deny -> group:43:-w--D---------:------:deny -> group@:-----da-------:------:allow -> group:44:rw-p----------:------:deny -> group:44:rw-p-da-------:------:allow -> owner@:--------------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:--------------:------:deny -> group@:--------------:------:allow -> everyone@:-------A-W-Co-:------:deny -> everyone@:-w-p--a-R-c--s:f-i---:allow -> owner@:-wxp----------:------:deny -> owner@:r------A-W-Co-:------:allow -> group@:rw-p----------:------:deny -> group@:--x-----------:------:allow -> everyone@:r-x----A-W-Co-:------:deny -> everyone@:-w-p--a-R-c--s:------:allow +> user:42:r-------------:-------:deny +> user:42:r-x-----------:-------:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-di----:allow +> group:42:-w------------:-------:deny +> group:42:-w--D---------:-------:allow +> group:43:-w--D---------:-di----:deny +> group:43:-w--D---------:-------:deny +> group@:-----da-------:-------:allow +> group:44:rw-p----------:-------:deny +> group:44:rw-p-da-------:-------:allow +> owner@:--------------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:--------------:-------:deny +> group@:--------------:-------:allow +> everyone@:-------A-W-Co-:-------:deny +> everyone@:-w-p--a-R-c--s:f-i----:allow +> owner@:-wxp----------:-------:deny +> owner@:r------A-W-Co-:-------:allow +> group@:rw-p----------:-------:deny +> group@:--x-----------:-------:allow +> everyone@:r-x----A-W-Co-:-------:deny +> everyone@:-w-p--a-R-c--s:-------:allow $ rmdir ddd $ mkdir ddd $ setfacl -a0 group:44:rwapd:allow ddd $ setfacl -a0 group:43:write_data/delete_child:d:deny,group@:ad:allow ddd $ setfacl -a0 user:42:rx:allow,user:42:rx:fi:allow,group:42:write_data/delete_child:d:allow ddd $ setfacl -m everyone@:-w-p--a-R-c--s:fi:allow ddd $ chown 42 ddd $ chmod 412 ddd $ getfacl -n ddd > # file: ddd > # owner: 42 > # group: wheel -> user:42:--x-----------:------:deny -> user:42:r-x-----------:------:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:-di---:allow -> group:42:-w------------:------:deny -> group:42:-w--D---------:------:allow -> group:43:-w--D---------:-di---:deny -> group:43:-w--D---------:------:deny -> group@:-----da-------:------:allow -> group:44:rw-p----------:------:deny -> group:44:rw-p-da-------:------:allow -> owner@:--------------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:--------------:------:deny -> group@:--------------:------:allow -> everyone@:-------A-W-Co-:------:deny -> everyone@:-w-p--a-R-c--s:f-i---:allow -> owner@:-wxp----------:------:deny -> owner@:r------A-W-Co-:------:allow -> group@:rw-p----------:------:deny -> group@:--x-----------:------:allow -> everyone@:r-x----A-W-Co-:------:deny -> everyone@:-w-p--a-R-c--s:------:allow +> user:42:--x-----------:-------:deny +> user:42:r-x-----------:-------:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-di----:allow +> group:42:-w------------:-------:deny +> group:42:-w--D---------:-------:allow +> group:43:-w--D---------:-di----:deny +> group:43:-w--D---------:-------:deny +> group@:-----da-------:-------:allow +> group:44:rw-p----------:-------:deny +> group:44:rw-p-da-------:-------:allow +> owner@:--------------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:--------------:-------:deny +> group@:--------------:-------:allow +> everyone@:-------A-W-Co-:-------:deny +> everyone@:-w-p--a-R-c--s:f-i----:allow +> owner@:-wxp----------:-------:deny +> owner@:r------A-W-Co-:-------:allow +> group@:rw-p----------:-------:deny +> group@:--x-----------:-------:allow +> everyone@:r-x----A-W-Co-:-------:deny +> everyone@:-w-p--a-R-c--s:-------:allow # Test applying ACL to mode. $ rmdir ddd $ mkdir ddd $ setfacl -a0 u:42:rwx:fi:allow ddd $ ls -ld ddd | cut -d' ' -f1 > drwxr-xr-x+ $ rmdir ddd $ mkdir ddd $ chmod 0 ddd $ setfacl -a0 owner@:r:allow,group@:w:deny,group@:wx:allow ddd $ ls -ld ddd | cut -d' ' -f1 > dr----x---+ $ rmdir ddd $ mkdir ddd $ chmod 0 ddd $ setfacl -a0 owner@:r:allow,group@:w:fi:deny,group@:wx:allow ddd $ ls -ld ddd | cut -d' ' -f1 > dr---wx---+ $ rmdir ddd $ mkdir ddd $ chmod 0 ddd $ setfacl -a0 owner@:r:allow,group:43:w:deny,group:43:wx:allow ddd $ ls -ld ddd | cut -d' ' -f1 > dr--------+ $ rmdir ddd $ mkdir ddd $ chmod 0 ddd $ setfacl -a0 owner@:r:allow,user:43:w:deny,user:43:wx:allow ddd $ ls -ld ddd | cut -d' ' -f1 > dr--------+ # Test inheritance. $ rmdir ddd $ mkdir ddd $ setfacl -a0 group:43:write_data/write_acl:fin:deny,u:43:rwxp:allow ddd $ setfacl -a0 user:42:rx:fi:allow,group:42:write_data/delete_child:dn:deny ddd $ setfacl -a0 user:42:write_acl/write_owner:fi:allow ddd $ setfacl -a0 group:41:read_data/read_attributes:dni:allow ddd $ setfacl -a0 user:41:write_data/write_attributes:fn:allow ddd $ getfacl -qn ddd -> user:41:-w-----A------:f--n--:allow -> group:41:r-----a-------:-din--:allow -> user:42:-----------Co-:f-i---:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:-d-n--:deny -> group:43:-w---------C--:f-in--:deny -> user:43:rwxp----------:------:allow -> owner@:--------------:------:deny -> owner@:rwxp---A-W-Co-:------:allow -> group@:-w-p----------:------:deny -> group@:r-x-----------:------:allow -> everyone@:-w-p---A-W-Co-:------:deny -> everyone@:r-x---a-R-c--s:------:allow +> user:41:-w-----A------:f--n---:allow +> group:41:r-----a-------:-din---:allow +> user:42:-----------Co-:f-i----:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-d-n---:deny +> group:43:-w---------C--:f-in---:deny +> user:43:rwxp----------:-------:allow +> owner@:--------------:-------:deny +> owner@:rwxp---A-W-Co-:-------:allow +> group@:-w-p----------:-------:deny +> group@:r-x-----------:-------:allow +> everyone@:-w-p---A-W-Co-:-------:deny +> everyone@:r-x---a-R-c--s:-------:allow $ cd ddd $ touch xxx $ getfacl -qn xxx -> user:41:-w------------:------:deny -> user:41:-w-----A------:------:allow -> user:42:--------------:------:deny -> user:42:--------------:------:allow -> user:42:--x-----------:------:deny -> user:42:r-x-----------:------:allow -> group:43:-w---------C--:------:deny -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> user:41:-w------------:-------:deny +> user:41:-w-----A------:-------:allow +> user:42:--------------:-------:deny +> user:42:--------------:-------:allow +> user:42:--x-----------:-------:deny +> user:42:r-x-----------:-------:allow +> group:43:-w---------C--:-------:deny +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ rm xxx $ umask 077 $ touch xxx $ getfacl -qn xxx -> user:41:-w------------:------:deny -> user:41:-w-----A------:------:allow -> user:42:--------------:------:deny -> user:42:--------------:------:allow -> user:42:r-x-----------:------:deny -> user:42:r-x-----------:------:allow -> group:43:-w---------C--:------:deny -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:rwxp----------:------:deny -> group@:--------------:------:allow -> everyone@:rwxp---A-W-Co-:------:deny -> everyone@:------a-R-c--s:------:allow +> user:41:-w------------:-------:deny +> user:41:-w-----A------:-------:allow +> user:42:--------------:-------:deny +> user:42:--------------:-------:allow +> user:42:r-x-----------:-------:deny +> user:42:r-x-----------:-------:allow +> group:43:-w---------C--:-------:deny +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:rwxp----------:-------:deny +> group@:--------------:-------:allow +> everyone@:rwxp---A-W-Co-:-------:deny +> everyone@:------a-R-c--s:-------:allow $ rm xxx $ umask 770 $ touch xxx $ getfacl -qn xxx -> user:41:-w------------:------:deny -> user:41:-w-----A------:------:allow -> user:42:--------------:------:deny -> user:42:--------------:------:allow -> user:42:r-x-----------:------:deny -> user:42:r-x-----------:------:allow -> group:43:-w---------C--:------:deny -> owner@:rwxp----------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:rwxp----------:------:deny -> group@:--------------:------:allow -> everyone@:--x----A-W-Co-:------:deny -> everyone@:rw-p--a-R-c--s:------:allow +> user:41:-w------------:-------:deny +> user:41:-w-----A------:-------:allow +> user:42:--------------:-------:deny +> user:42:--------------:-------:allow +> user:42:r-x-----------:-------:deny +> user:42:r-x-----------:-------:allow +> group:43:-w---------C--:-------:deny +> owner@:rwxp----------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:rwxp----------:-------:deny +> group@:--------------:-------:allow +> everyone@:--x----A-W-Co-:-------:deny +> everyone@:rw-p--a-R-c--s:-------:allow $ rm xxx $ umask 707 $ touch xxx $ getfacl -qn xxx -> user:41:--------------:------:deny -> user:41:-w-----A------:------:allow -> user:42:--------------:------:deny -> user:42:--------------:------:allow -> user:42:--x-----------:------:deny -> user:42:r-x-----------:------:allow -> group:43:-w---------C--:------:deny -> owner@:rwxp----------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:--x-----------:------:deny -> group@:rw-p----------:------:allow -> everyone@:rwxp---A-W-Co-:------:deny -> everyone@:------a-R-c--s:------:allow +> user:41:--------------:-------:deny +> user:41:-w-----A------:-------:allow +> user:42:--------------:-------:deny +> user:42:--------------:-------:allow +> user:42:--x-----------:-------:deny +> user:42:r-x-----------:-------:allow +> group:43:-w---------C--:-------:deny +> owner@:rwxp----------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:--x-----------:-------:deny +> group@:rw-p----------:-------:allow +> everyone@:rwxp---A-W-Co-:-------:deny +> everyone@:------a-R-c--s:-------:allow $ umask 077 $ mkdir yyy $ getfacl -qn yyy -> group:41:r-------------:------:deny -> group:41:r-----a-------:------:allow -> user:42:-----------Co-:f-i---:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:------:deny -> owner@:--------------:------:deny -> owner@:rwxp---A-W-Co-:------:allow -> group@:rwxp----------:------:deny -> group@:--------------:------:allow -> everyone@:rwxp---A-W-Co-:------:deny -> everyone@:------a-R-c--s:------:allow +> group:41:r-------------:-------:deny +> group:41:r-----a-------:-------:allow +> user:42:-----------Co-:f-i----:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-------:deny +> owner@:--------------:-------:deny +> owner@:rwxp---A-W-Co-:-------:allow +> group@:rwxp----------:-------:deny +> group@:--------------:-------:allow +> everyone@:rwxp---A-W-Co-:-------:deny +> everyone@:------a-R-c--s:-------:allow $ rmdir yyy $ umask 770 $ mkdir yyy $ getfacl -qn yyy -> group:41:r-------------:------:deny -> group:41:r-----a-------:------:allow -> user:42:-----------Co-:f-i---:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:------:deny -> owner@:rwxp----------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:rwxp----------:------:deny -> group@:--------------:------:allow -> everyone@:-------A-W-Co-:------:deny -> everyone@:rwxp--a-R-c--s:------:allow +> group:41:r-------------:-------:deny +> group:41:r-----a-------:-------:allow +> user:42:-----------Co-:f-i----:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-------:deny +> owner@:rwxp----------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:rwxp----------:-------:deny +> group@:--------------:-------:allow +> everyone@:-------A-W-Co-:-------:deny +> everyone@:rwxp--a-R-c--s:-------:allow $ rmdir yyy $ umask 707 $ mkdir yyy $ getfacl -qn yyy -> group:41:--------------:------:deny -> group:41:------a-------:------:allow -> user:42:-----------Co-:f-i---:allow -> user:42:r-x-----------:f-i---:allow -> group:42:-w--D---------:------:deny -> owner@:rwxp----------:------:deny -> owner@:-------A-W-Co-:------:allow -> group@:--------------:------:deny -> group@:rwxp----------:------:allow -> everyone@:rwxp---A-W-Co-:------:deny -> everyone@:------a-R-c--s:------:allow +> group:41:--------------:-------:deny +> group:41:------a-------:-------:allow +> user:42:-----------Co-:f-i----:allow +> user:42:r-x-----------:f-i----:allow +> group:42:-w--D---------:-------:deny +> owner@:rwxp----------:-------:deny +> owner@:-------A-W-Co-:-------:allow +> group@:--------------:-------:deny +> group@:rwxp----------:-------:allow +> everyone@:rwxp---A-W-Co-:-------:deny +> everyone@:------a-R-c--s:-------:allow # There is some complication regarding how write_acl and write_owner flags # get inherited. Make sure we got it right. $ setfacl -b . $ setfacl -a0 u:42:Co:f:allow . $ setfacl -a0 u:43:Co:d:allow . $ setfacl -a0 u:44:Co:fd:allow . $ setfacl -a0 u:45:Co:fi:allow . $ setfacl -a0 u:46:Co:di:allow . $ setfacl -a0 u:47:Co:fdi:allow . $ setfacl -a0 u:48:Co:fn:allow . $ setfacl -a0 u:49:Co:dn:allow . $ setfacl -a0 u:50:Co:fdn:allow . $ setfacl -a0 u:51:Co:fni:allow . $ setfacl -a0 u:52:Co:dni:allow . $ setfacl -a0 u:53:Co:fdni:allow . $ umask 022 $ rm xxx $ touch xxx $ getfacl -nq xxx -> user:53:--------------:------:deny -> user:53:--------------:------:allow -> user:51:--------------:------:deny -> user:51:--------------:------:allow -> user:50:--------------:------:deny -> user:50:--------------:------:allow -> user:48:--------------:------:deny -> user:48:--------------:------:allow -> user:47:--------------:------:deny -> user:47:--------------:------:allow -> user:45:--------------:------:deny -> user:45:--------------:------:allow -> user:44:--------------:------:deny -> user:44:--------------:------:allow -> user:42:--------------:------:deny -> user:42:--------------:------:allow -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> user:53:--------------:-------:deny +> user:53:--------------:-------:allow +> user:51:--------------:-------:deny +> user:51:--------------:-------:allow +> user:50:--------------:-------:deny +> user:50:--------------:-------:allow +> user:48:--------------:-------:deny +> user:48:--------------:-------:allow +> user:47:--------------:-------:deny +> user:47:--------------:-------:allow +> user:45:--------------:-------:deny +> user:45:--------------:-------:allow +> user:44:--------------:-------:deny +> user:44:--------------:-------:allow +> user:42:--------------:-------:deny +> user:42:--------------:-------:allow +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ rmdir yyy $ mkdir yyy $ getfacl -nq yyy -> user:53:--------------:------:deny -> user:53:--------------:------:allow -> user:52:--------------:------:deny -> user:52:--------------:------:allow -> user:50:--------------:------:deny -> user:50:--------------:------:allow -> user:49:--------------:------:deny -> user:49:--------------:------:allow -> user:47:-----------Co-:fdi---:allow -> user:47:--------------:------:deny -> user:47:--------------:------:allow -> user:46:-----------Co-:-di---:allow -> user:46:--------------:------:deny -> user:46:--------------:------:allow -> user:45:-----------Co-:f-i---:allow -> user:44:-----------Co-:fdi---:allow -> user:44:--------------:------:deny -> user:44:--------------:------:allow -> user:43:-----------Co-:-di---:allow -> user:43:--------------:------:deny -> user:43:--------------:------:allow -> user:42:-----------Co-:f-i---:allow -> owner@:--------------:------:deny -> owner@:rwxp---A-W-Co-:------:allow -> group@:-w-p----------:------:deny -> group@:r-x-----------:------:allow -> everyone@:-w-p---A-W-Co-:------:deny -> everyone@:r-x---a-R-c--s:------:allow +> user:53:--------------:-------:deny +> user:53:--------------:-------:allow +> user:52:--------------:-------:deny +> user:52:--------------:-------:allow +> user:50:--------------:-------:deny +> user:50:--------------:-------:allow +> user:49:--------------:-------:deny +> user:49:--------------:-------:allow +> user:47:-----------Co-:fdi----:allow +> user:47:--------------:-------:deny +> user:47:--------------:-------:allow +> user:46:-----------Co-:-di----:allow +> user:46:--------------:-------:deny +> user:46:--------------:-------:allow +> user:45:-----------Co-:f-i----:allow +> user:44:-----------Co-:fdi----:allow +> user:44:--------------:-------:deny +> user:44:--------------:-------:allow +> user:43:-----------Co-:-di----:allow +> user:43:--------------:-------:deny +> user:43:--------------:-------:allow +> user:42:-----------Co-:f-i----:allow +> owner@:--------------:-------:deny +> owner@:rwxp---A-W-Co-:-------:allow +> group@:-w-p----------:-------:deny +> group@:r-x-----------:-------:allow +> everyone@:-w-p---A-W-Co-:-------:deny +> everyone@:r-x---a-R-c--s:-------:allow $ setfacl -b . $ setfacl -a0 u:42:Co:f:deny . $ setfacl -a0 u:43:Co:d:deny . $ setfacl -a0 u:44:Co:fd:deny . $ setfacl -a0 u:45:Co:fi:deny . $ setfacl -a0 u:46:Co:di:deny . $ setfacl -a0 u:47:Co:fdi:deny . $ setfacl -a0 u:48:Co:fn:deny . $ setfacl -a0 u:49:Co:dn:deny . $ setfacl -a0 u:50:Co:fdn:deny . $ setfacl -a0 u:51:Co:fni:deny . $ setfacl -a0 u:52:Co:dni:deny . $ setfacl -a0 u:53:Co:fdni:deny . $ umask 022 $ rm xxx $ touch xxx $ getfacl -nq xxx -> user:53:-----------Co-:------:deny -> user:51:-----------Co-:------:deny -> user:50:-----------Co-:------:deny -> user:48:-----------Co-:------:deny -> user:47:-----------Co-:------:deny -> user:45:-----------Co-:------:deny -> user:44:-----------Co-:------:deny -> user:42:-----------Co-:------:deny -> owner@:--x-----------:------:deny -> owner@:rw-p---A-W-Co-:------:allow -> group@:-wxp----------:------:deny -> group@:r-------------:------:allow -> everyone@:-wxp---A-W-Co-:------:deny -> everyone@:r-----a-R-c--s:------:allow +> user:53:-----------Co-:-------:deny +> user:51:-----------Co-:-------:deny +> user:50:-----------Co-:-------:deny +> user:48:-----------Co-:-------:deny +> user:47:-----------Co-:-------:deny +> user:45:-----------Co-:-------:deny +> user:44:-----------Co-:-------:deny +> user:42:-----------Co-:-------:deny +> owner@:--x-----------:-------:deny +> owner@:rw-p---A-W-Co-:-------:allow +> group@:-wxp----------:-------:deny +> group@:r-------------:-------:allow +> everyone@:-wxp---A-W-Co-:-------:deny +> everyone@:r-----a-R-c--s:-------:allow $ rmdir yyy $ mkdir yyy $ getfacl -nq yyy -> user:53:-----------Co-:------:deny -> user:52:-----------Co-:------:deny -> user:50:-----------Co-:------:deny -> user:49:-----------Co-:------:deny -> user:47:-----------Co-:fdi---:deny -> user:47:-----------Co-:------:deny -> user:46:-----------Co-:-di---:deny -> user:46:-----------Co-:------:deny -> user:45:-----------Co-:f-i---:deny -> user:44:-----------Co-:fdi---:deny -> user:44:-----------Co-:------:deny -> user:43:-----------Co-:-di---:deny -> user:43:-----------Co-:------:deny -> user:42:-----------Co-:f-i---:deny -> owner@:--------------:------:deny -> owner@:rwxp---A-W-Co-:------:allow -> group@:-w-p----------:------:deny -> group@:r-x-----------:------:allow -> everyone@:-w-p---A-W-Co-:------:deny -> everyone@:r-x---a-R-c--s:------:allow +> user:53:-----------Co-:-------:deny +> user:52:-----------Co-:-------:deny +> user:50:-----------Co-:-------:deny +> user:49:-----------Co-:-------:deny +> user:47:-----------Co-:fdi----:deny +> user:47:-----------Co-:-------:deny +> user:46:-----------Co-:-di----:deny +> user:46:-----------Co-:-------:deny +> user:45:-----------Co-:f-i----:deny +> user:44:-----------Co-:fdi----:deny +> user:44:-----------Co-:-------:deny +> user:43:-----------Co-:-di----:deny +> user:43:-----------Co-:-------:deny +> user:42:-----------Co-:f-i----:deny +> owner@:--------------:-------:deny +> owner@:rwxp---A-W-Co-:-------:allow +> group@:-w-p----------:-------:deny +> group@:r-x-----------:-------:allow +> everyone@:-w-p---A-W-Co-:-------:deny +> everyone@:r-x---a-R-c--s:-------:allow $ rmdir yyy $ rm xxx $ cd .. $ rmdir ddd $ rm xxx