aclutils.c revision fa9e4066f08beec538e775443c5be79dd423fcab
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER START
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The contents of this file are subject to the terms of the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Common Development and Distribution License, Version 1.0 only
fa9e4066f08beec538e775443c5be79dd423fcabahrens * (the "License"). You may not use this file except in compliance
fa9e4066f08beec538e775443c5be79dd423fcabahrens * with the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fa9e4066f08beec538e775443c5be79dd423fcabahrens * See the License for the specific language governing permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and limitations under the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * When distributing Covered Code, include this CDDL HEADER in each
fa9e4066f08beec538e775443c5be79dd423fcabahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If applicable, add the following below this CDDL HEADER, with the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fields enclosed by brackets "[]" replaced with your own identifying
fa9e4066f08beec538e775443c5be79dd423fcabahrens * information: Portions Copyright [yyyy] [name of copyright owner]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER END
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Use is subject to license terms.
fa9e4066f08beec538e775443c5be79dd423fcabahrens#pragma ident "%Z%%M% %I% %E% SMI"
fa9e4066f08beec538e775443c5be79dd423fcabahrenstypedef union {
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *file;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Free acl_t structure
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Determine whether a file has a trivial ACL
fa9e4066f08beec538e775443c5be79dd423fcabahrens * returns: 0 = trivial
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 1 = nontrivial
fa9e4066f08beec538e775443c5be79dd423fcabahrens * <0 some other system failure, such as ENOENT or EPERM
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrensaccess_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If the entity is not the owner and does not
fa9e4066f08beec538e775443c5be79dd423fcabahrens * have write permissions ACE_WRITE_ATTRIBUTES will
fa9e4066f08beec538e775443c5be79dd423fcabahrens * always go in the DENY ACE.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given an mode_t, convert it into an access_mask as used
fa9e4066f08beec538e775443c5be79dd423fcabahrens * by nfsace, assuming aclent_t -> nfsace semantics.
fa9e4066f08beec538e775443c5be79dd423fcabahrensmode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The following call takes care of correctly setting the following
fa9e4066f08beec538e775443c5be79dd423fcabahrens * mask bits in the access_mask:
fa9e4066f08beec538e775443c5be79dd423fcabahrens * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
fa9e4066f08beec538e775443c5be79dd423fcabahrens access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* write */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Given an nfsace (presumably an ALLOW entry), make a
fa9e4066f08beec538e775443c5be79dd423fcabahrens * corresponding DENY entry at the address given.
fa9e4066f08beec538e775443c5be79dd423fcabahrensace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
fa9e4066f08beec538e775443c5be79dd423fcabahrens deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
fa9e4066f08beec538e775443c5be79dd423fcabahrens ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
fa9e4066f08beec538e775443c5be79dd423fcabahrens deny->a_access_mask |= access_mask_set((allow->a_access_mask &
fa9e4066f08beec538e775443c5be79dd423fcabahrens ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Make an initial pass over an array of aclent_t's. Gather
fa9e4066f08beec538e775443c5be79dd423fcabahrens * information such as an ACL_MASK (if any), number of users,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * number of groups, and whether the array needs to be sorted.
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; i < n; i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Convert an array of aclent_t into an array of nfsace entries,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * following POSIX draft -> nfsv4 conversion semantics as outlined in
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the IETF draft.
fa9e4066f08beec538e775443c5be79dd423fcabahrensln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
fa9e4066f08beec538e775443c5be79dd423fcabahrens error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* allow + deny for each aclent */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * stick extra deny on the group_obj and on each
fa9e4066f08beec538e775443c5be79dd423fcabahrens * user|group for the mask (the group_obj was added
fa9e4066f08beec538e775443c5be79dd423fcabahrens * into the count for numgroup)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* ... and don't count the mask itself */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* sort the source if necessary */
fa9e4066f08beec538e775443c5be79dd423fcabahrens ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
fa9e4066f08beec538e775443c5be79dd423fcabahrens result = acep = calloc(1, resultsize * sizeof (ace_t));
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; i < n; i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * don't process CLASS_OBJ (mask); mask was grabbed in
fa9e4066f08beec538e775443c5be79dd423fcabahrens * ln_aent_preprocess()
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* If we need an ACL_MASK emulator, prepend it now */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Set the access mask for the prepended deny
fa9e4066f08beec538e775443c5be79dd423fcabahrens * ace. To do this, we invert the mask (found
fa9e4066f08beec538e775443c5be79dd423fcabahrens * in ln_aent_preprocess()) then convert it to an
fa9e4066f08beec538e775443c5be79dd423fcabahrens * DENY ace access_mask.
fa9e4066f08beec538e775443c5be79dd423fcabahrens acep->a_access_mask = mode_to_ace_access((mask ^ 07),
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* handle a_perm -> access_mask */
fa9e4066f08beec538e775443c5be79dd423fcabahrens acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* emulate a default aclent */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * handle a_perm and a_id
fa9e4066f08beec538e775443c5be79dd423fcabahrens * this must be done last, since it involves the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * corresponding deny aces, which are handled
fa9e4066f08beec538e775443c5be79dd423fcabahrens * differently for each different a_type.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Set the corresponding deny for the group ace.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The deny aces go after all of the groups, unlike
fa9e4066f08beec538e775443c5be79dd423fcabahrens * everything else, where they immediately follow
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the allow ace.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * We calculate "skip", the number of slots to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * skip ahead for the deny ace, here.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The pattern is:
fa9e4066f08beec538e775443c5be79dd423fcabahrens * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
fa9e4066f08beec538e775443c5be79dd423fcabahrens * thus, skip is
fa9e4066f08beec538e775443c5be79dd423fcabahrens * (2 * numgroup) - 1 - groupi
fa9e4066f08beec538e775443c5be79dd423fcabahrens * (2 * numgroup) to account for MD + A
fa9e4066f08beec538e775443c5be79dd423fcabahrens * - 1 to account for the fact that we're on the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * access (A), not the mask (MD)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * - groupi to account for the fact that we have
fa9e4066f08beec538e775443c5be79dd423fcabahrens * passed up groupi number of MD's.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If we just did the last group, skip acep past
fa9e4066f08beec538e775443c5be79dd423fcabahrens * all of the denies; else, just move ahead one.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (error != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrensconvert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
fa9e4066f08beec538e775443c5be79dd423fcabahrens ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens newacep = malloc(sizeof (ace_t) * (acecnt + dfacecnt));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) memcpy(newacep, acep, sizeof (ace_t) * acecnt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrenscacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp)
fa9e4066f08beec538e775443c5be79dd423fcabahrens const char *fname;
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * if acl's aren't supported then
fa9e4066f08beec538e775443c5be79dd423fcabahrens * send it through the old GETACL interface
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens malloc(acl_info->acl_cnt * acl_info->acl_entry_size);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * return -1 on failure, otherwise the number of acl
fa9e4066f08beec538e775443c5be79dd423fcabahrens * entries is returned
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Set an ACL, translates acl to ace_t when appropriate.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Translate aclent_t ACL's to ACE ACL's.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * replace old acl with newly translated acl
fa9e4066f08beec538e775443c5be79dd423fcabahrens newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Remove an ACL from a file and create a trivial ACL based
fa9e4066f08beec538e775443c5be79dd423fcabahrens * off of the mode argument. After acl has been set owner/group
fa9e4066f08beec538e775443c5be79dd423fcabahrens * are updated to match owner,group arguments
fa9e4066f08beec538e775443c5be79dd423fcabahrensacl_strip(const char *file, uid_t owner, gid_t group, mode_t mode)
fa9e4066f08beec538e775443c5be79dd423fcabahrens ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * force it through aclent flavor when file system doesn't
fa9e4066f08beec538e775443c5be79dd423fcabahrens * understand question
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Make aces match request mode
fa9e4066f08beec538e775443c5be79dd423fcabahrens adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6);
fa9e4066f08beec538e775443c5be79dd423fcabahrens adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Need to fixup who field for abstrations for
fa9e4066f08beec538e775443c5be79dd423fcabahrens * accurate comparison, since field is undefined.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (memcmp(aclent1, aclent2, sizeof (aclent_t)));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Find acl entries in acl that correspond to removeacl. Search
fa9e4066f08beec538e775443c5be79dd423fcabahrens * is started from slot. The flag argument indicates whether to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * remove all matches or just the first match.
fa9e4066f08beec538e775443c5be79dd423fcabahrensacl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag)
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST)
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (match == 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * List has changed, restart search from
fa9e4066f08beec538e775443c5be79dd423fcabahrens * beginning.
fa9e4066f08beec538e775443c5be79dd423fcabahrens acl_entry = ((char *)acl_entry + acl->acl_entry_size);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Replace entires entries in acl1 with the corresponding entries
fa9e4066f08beec538e775443c5be79dd423fcabahrens * in newentries. The where argument specifies where to begin
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the replacement. If the where argument is 1 greater than the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * number of acl entries in acl1 then they are appended. If the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * where argument is 2+ greater than the number of acl entries then
fa9e4066f08beec538e775443c5be79dd423fcabahrens * EACL_INVALID_SLOT is returned.
fa9e4066f08beec538e775443c5be79dd423fcabahrensacl_modifyentries(acl_t *acl1, acl_t *newentries, int where)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Did ACL grow?
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Add acl2 entries into acl1. The where argument specifies where
fa9e4066f08beec538e775443c5be79dd423fcabahrens * to add the entries.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * allow where to specify 1 past last slot for an append operation
fa9e4066f08beec538e775443c5be79dd423fcabahrens * but anything greater is an error.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * first push down entries where new ones will be inserted
fa9e4066f08beec538e775443c5be79dd423fcabahrens len = (acl1->acl_cnt - where) * acl1->acl_entry_size;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * now stick in new entries.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic char *
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* could not get passwd information: display uid instead */
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic char *
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* could not get group information: display gid instead */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* display ACL: assume it is sorted. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* no need to display uid */
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; i != len; i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (i == len) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * pretty print an ACL.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * For aclent_t ACL's the format is
fa9e4066f08beec538e775443c5be79dd423fcabahrens * similar to the old format used by getfacl,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * with the addition of adding a "slot" number
fa9e4066f08beec538e775443c5be79dd423fcabahrens * before each entry.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * for ace_t ACL's the cols variable will break up
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the long lines into multiple lines and will also
fa9e4066f08beec538e775443c5be79dd423fcabahrens * print a "slot" number.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * return text for an ACL error.
fa9e4066f08beec538e775443c5be79dd423fcabahrens "There is more than one user group owner entry"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "There is more than one user owner entry"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "There is more than one other entry"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "There is more than one mask entry"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Duplicate user or group entries"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Missing user/group owner, other, mask entry"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Memory error"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Unrecognized entry type"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Invalid inheritance flags"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Unrecognized entry flags"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Invalid ACL permissions"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Invalid ACL count"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Invalid ACL entry number specified"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "ACL entry doesn't exist"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "ACL type's are different"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (dgettext(TEXT_DOMAIN, "Invalid user or group"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (dgettext(TEXT_DOMAIN, "ACL string is invalid"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (dgettext(TEXT_DOMAIN, "Field expected to be blank"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (dgettext(TEXT_DOMAIN, "Invalid access type"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (dgettext(TEXT_DOMAIN, "Unrecognized entry"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "ACL specification missing required fields"));
fa9e4066f08beec538e775443c5be79dd423fcabahrens "Inheritance flags are only allowed on directories"));