The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_acl_nfs4.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2008-2010 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * ACL support routines specific to NFSv4 access control lists.  These are
   30  * utility routines for code common across file systems implementing NFSv4
   31  * ACLs.
   32  */
   33 
   34 #ifdef _KERNEL
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD$");
   37 
   38 #include <sys/param.h>
   39 #include <sys/kernel.h>
   40 #include <sys/module.h>
   41 #include <sys/systm.h>
   42 #include <sys/mount.h>
   43 #include <sys/priv.h>
   44 #include <sys/vnode.h>
   45 #include <sys/errno.h>
   46 #include <sys/stat.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/acl.h>
   49 #else
   50 #include <errno.h>
   51 #include <assert.h>
   52 #include <sys/acl.h>
   53 #include <sys/stat.h>
   54 #define KASSERT(a, b) assert(a)
   55 #define CTASSERT(a)
   56 
   57 #endif /* !_KERNEL */
   58 
   59 #ifdef _KERNEL
   60 
   61 static void     acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode);
   62 
   63 static int      acl_nfs4_old_semantics = 0;
   64 
   65 SYSCTL_INT(_vfs, OID_AUTO, acl_nfs4_old_semantics, CTLFLAG_RW,
   66     &acl_nfs4_old_semantics, 0, "Use pre-PSARC/2010/029 NFSv4 ACL semantics");
   67 
   68 static struct {
   69         accmode_t accmode;
   70         int mask;
   71 } accmode2mask[] = {{VREAD, ACL_READ_DATA},
   72                     {VWRITE, ACL_WRITE_DATA},
   73                     {VAPPEND, ACL_APPEND_DATA},
   74                     {VEXEC, ACL_EXECUTE},
   75                     {VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
   76                     {VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
   77                     {VDELETE_CHILD, ACL_DELETE_CHILD},
   78                     {VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES},
   79                     {VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
   80                     {VDELETE, ACL_DELETE},
   81                     {VREAD_ACL, ACL_READ_ACL},
   82                     {VWRITE_ACL, ACL_WRITE_ACL},
   83                     {VWRITE_OWNER, ACL_WRITE_OWNER},
   84                     {VSYNCHRONIZE, ACL_SYNCHRONIZE},
   85                     {0, 0}};
   86 
   87 static int
   88 _access_mask_from_accmode(accmode_t accmode)
   89 {
   90         int access_mask = 0, i;
   91 
   92         for (i = 0; accmode2mask[i].accmode != 0; i++) {
   93                 if (accmode & accmode2mask[i].accmode)
   94                         access_mask |= accmode2mask[i].mask;
   95         }
   96 
   97         /*
   98          * VAPPEND is just a modifier for VWRITE; if the caller asked
   99          * for 'VAPPEND | VWRITE', we want to check for ACL_APPEND_DATA only.
  100          */
  101         if (access_mask & ACL_APPEND_DATA)
  102                 access_mask &= ~ACL_WRITE_DATA;
  103 
  104         return (access_mask);
  105 }
  106 
  107 /*
  108  * Return 0, iff access is allowed, 1 otherwise.
  109  */
  110 static int
  111 _acl_denies(const struct acl *aclp, int access_mask, struct ucred *cred,
  112     int file_uid, int file_gid, int *denied_explicitly)
  113 {
  114         int i;
  115         const struct acl_entry *entry;
  116 
  117         if (denied_explicitly != NULL)
  118                 *denied_explicitly = 0;
  119 
  120         KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES,
  121             ("aclp->acl_cnt <= ACL_MAX_ENTRIES"));
  122 
  123         for (i = 0; i < aclp->acl_cnt; i++) {
  124                 entry = &(aclp->acl_entry[i]);
  125 
  126                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
  127                     entry->ae_entry_type != ACL_ENTRY_TYPE_DENY)
  128                         continue;
  129                 if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY)
  130                         continue;
  131                 switch (entry->ae_tag) {
  132                 case ACL_USER_OBJ:
  133                         if (file_uid != cred->cr_uid)
  134                                 continue;
  135                         break;
  136                 case ACL_USER:
  137                         if (entry->ae_id != cred->cr_uid)
  138                                 continue;
  139                         break;
  140                 case ACL_GROUP_OBJ:
  141                         if (!groupmember(file_gid, cred))
  142                                 continue;
  143                         break;
  144                 case ACL_GROUP:
  145                         if (!groupmember(entry->ae_id, cred))
  146                                 continue;
  147                         break;
  148                 default:
  149                         KASSERT(entry->ae_tag == ACL_EVERYONE,
  150                             ("entry->ae_tag == ACL_EVERYONE"));
  151                 }
  152 
  153                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_DENY) {
  154                         if (entry->ae_perm & access_mask) {
  155                                 if (denied_explicitly != NULL)
  156                                         *denied_explicitly = 1;
  157                                 return (1);
  158                         }
  159                 }
  160 
  161                 access_mask &= ~(entry->ae_perm);
  162                 if (access_mask == 0)
  163                         return (0);
  164         }
  165 
  166         if (access_mask == 0)
  167                 return (0);
  168 
  169         return (1);
  170 }
  171 
  172 int
  173 vaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid,
  174     struct acl *aclp, accmode_t accmode, struct ucred *cred)
  175 {
  176         accmode_t priv_granted = 0;
  177         int denied, explicitly_denied, access_mask, is_directory,
  178             must_be_owner = 0;
  179         mode_t file_mode = 0;
  180 
  181         KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND |
  182             VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS |
  183             VDELETE_CHILD | VREAD_ATTRIBUTES | VWRITE_ATTRIBUTES | VDELETE |
  184             VREAD_ACL | VWRITE_ACL | VWRITE_OWNER | VSYNCHRONIZE)) == 0,
  185             ("invalid bit in accmode"));
  186         KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE),
  187                 ("VAPPEND without VWRITE"));
  188 
  189         if (accmode & VADMIN)
  190                 must_be_owner = 1;
  191 
  192         /*
  193          * Ignore VSYNCHRONIZE permission.
  194          */
  195         accmode &= ~VSYNCHRONIZE;
  196 
  197         access_mask = _access_mask_from_accmode(accmode);
  198 
  199         if (type == VDIR)
  200                 is_directory = 1;
  201         else
  202                 is_directory = 0;
  203 
  204         /*
  205          * File owner is always allowed to read and write the ACL
  206          * and basic attributes.  This is to prevent a situation
  207          * where user would change ACL in a way that prevents him
  208          * from undoing the change.
  209          */
  210         if (file_uid == cred->cr_uid)
  211                 access_mask &= ~(ACL_READ_ACL | ACL_WRITE_ACL |
  212                     ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES);
  213 
  214         /*
  215          * Ignore append permission for regular files; use write
  216          * permission instead.
  217          */
  218         if (!is_directory && (access_mask & ACL_APPEND_DATA)) {
  219                 access_mask &= ~ACL_APPEND_DATA;
  220                 access_mask |= ACL_WRITE_DATA;
  221         }
  222 
  223         denied = _acl_denies(aclp, access_mask, cred, file_uid, file_gid,
  224             &explicitly_denied);
  225 
  226         if (must_be_owner) {
  227                 if (file_uid != cred->cr_uid)
  228                         denied = EPERM;
  229         }
  230 
  231         /*
  232          * For VEXEC, ensure that at least one execute bit is set for
  233          * non-directories. We have to check the mode here to stay
  234          * consistent with execve(2). See the test in
  235          * exec_check_permissions().
  236          */
  237         acl_nfs4_sync_mode_from_acl(&file_mode, aclp);
  238         if (!denied && !is_directory && (accmode & VEXEC) &&
  239             (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
  240                 denied = EACCES;
  241 
  242         if (!denied)
  243                 return (0);
  244 
  245         /*
  246          * Access failed.  Iff it was not denied explicitly and
  247          * VEXPLICIT_DENY flag was specified, allow access.
  248          */
  249         if ((accmode & VEXPLICIT_DENY) && explicitly_denied == 0)
  250                 return (0);
  251 
  252         accmode &= ~VEXPLICIT_DENY;
  253 
  254         /*
  255          * No match.  Try to use privileges, if there are any.
  256          */
  257         if (is_directory) {
  258                 if ((accmode & VEXEC) && !priv_check_cred(cred, PRIV_VFS_LOOKUP))
  259                         priv_granted |= VEXEC;
  260         } else {
  261                 /*
  262                  * Ensure that at least one execute bit is on. Otherwise,
  263                  * a privileged user will always succeed, and we don't want
  264                  * this to happen unless the file really is executable.
  265                  */
  266                 if ((accmode & VEXEC) && (file_mode &
  267                     (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 &&
  268                     !priv_check_cred(cred, PRIV_VFS_EXEC))
  269                         priv_granted |= VEXEC;
  270         }
  271 
  272         if ((accmode & VREAD) && !priv_check_cred(cred, PRIV_VFS_READ))
  273                 priv_granted |= VREAD;
  274 
  275         if ((accmode & (VWRITE | VAPPEND | VDELETE_CHILD)) &&
  276             !priv_check_cred(cred, PRIV_VFS_WRITE))
  277                 priv_granted |= (VWRITE | VAPPEND | VDELETE_CHILD);
  278 
  279         if ((accmode & VADMIN_PERMS) &&
  280             !priv_check_cred(cred, PRIV_VFS_ADMIN))
  281                 priv_granted |= VADMIN_PERMS;
  282 
  283         if ((accmode & VSTAT_PERMS) &&
  284             !priv_check_cred(cred, PRIV_VFS_STAT))
  285                 priv_granted |= VSTAT_PERMS;
  286 
  287         if ((accmode & priv_granted) == accmode) {
  288                 return (0);
  289         }
  290 
  291         if (accmode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE))
  292                 denied = EPERM;
  293         else
  294                 denied = EACCES;
  295 
  296         return (denied);
  297 }
  298 #endif /* _KERNEL */
  299 
  300 static int
  301 _acl_entry_matches(struct acl_entry *entry, acl_tag_t tag, acl_perm_t perm,
  302     acl_entry_type_t entry_type)
  303 {
  304         if (entry->ae_tag != tag)
  305                 return (0);
  306 
  307         if (entry->ae_id != ACL_UNDEFINED_ID)
  308                 return (0);
  309 
  310         if (entry->ae_perm != perm)
  311                 return (0);
  312 
  313         if (entry->ae_entry_type != entry_type)
  314                 return (0);
  315 
  316         if (entry->ae_flags != 0)
  317                 return (0);
  318 
  319         return (1);
  320 }
  321 
  322 static struct acl_entry *
  323 _acl_append(struct acl *aclp, acl_tag_t tag, acl_perm_t perm,
  324     acl_entry_type_t entry_type)
  325 {
  326         struct acl_entry *entry;
  327 
  328         KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES,
  329             ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES"));
  330 
  331         entry = &(aclp->acl_entry[aclp->acl_cnt]);
  332         aclp->acl_cnt++;
  333 
  334         entry->ae_tag = tag;
  335         entry->ae_id = ACL_UNDEFINED_ID;
  336         entry->ae_perm = perm;
  337         entry->ae_entry_type = entry_type;
  338         entry->ae_flags = 0;
  339 
  340         return (entry);
  341 }
  342 
  343 static struct acl_entry *
  344 _acl_duplicate_entry(struct acl *aclp, unsigned entry_index)
  345 {
  346         unsigned i;
  347 
  348         KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES,
  349             ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES"));
  350 
  351         for (i = aclp->acl_cnt; i > entry_index; i--)
  352                 aclp->acl_entry[i] = aclp->acl_entry[i - 1];
  353 
  354         aclp->acl_cnt++;
  355 
  356         return (&(aclp->acl_entry[entry_index + 1]));
  357 }
  358 
  359 static void
  360 acl_nfs4_sync_acl_from_mode_draft(struct acl *aclp, mode_t mode,
  361     int file_owner_id)
  362 {
  363         int meets, must_append;
  364         unsigned i;
  365         struct acl_entry *entry, *copy, *previous,
  366             *a1, *a2, *a3, *a4, *a5, *a6;
  367         mode_t amode;
  368         const int READ = 04;
  369         const int WRITE = 02;
  370         const int EXEC = 01;
  371 
  372         KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES,
  373             ("aclp->acl_cnt <= ACL_MAX_ENTRIES"));
  374 
  375         /*
  376          * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt
  377          *
  378          * 3.16.6.3. Applying a Mode to an Existing ACL
  379          */
  380 
  381         /*
  382          * 1. For each ACE:
  383          */
  384         for (i = 0; i < aclp->acl_cnt; i++) {
  385                 entry = &(aclp->acl_entry[i]);
  386 
  387                 /*
  388                  * 1.1. If the type is neither ALLOW or DENY - skip.
  389                  */
  390                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
  391                     entry->ae_entry_type != ACL_ENTRY_TYPE_DENY)
  392                         continue;
  393 
  394                 /*
  395                  * 1.2. If ACL_ENTRY_INHERIT_ONLY is set - skip.
  396                  */
  397                 if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY)
  398                         continue;
  399 
  400                 /*
  401                  * 1.3. If ACL_ENTRY_FILE_INHERIT or ACL_ENTRY_DIRECTORY_INHERIT
  402                  *      are set:
  403                  */
  404                 if (entry->ae_flags &
  405                     (ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT)) {
  406                         /*
  407                          * 1.3.1. A copy of the current ACE is made, and placed
  408                          *        in the ACL immediately following the current
  409                          *        ACE.
  410                          */
  411                         copy = _acl_duplicate_entry(aclp, i);
  412 
  413                         /*
  414                          * 1.3.2. In the first ACE, the flag
  415                          *        ACL_ENTRY_INHERIT_ONLY is set.
  416                          */
  417                         entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
  418 
  419                         /*
  420                          * 1.3.3. In the second ACE, the following flags
  421                          *        are cleared:
  422                          *        ACL_ENTRY_FILE_INHERIT,
  423                          *        ACL_ENTRY_DIRECTORY_INHERIT,
  424                          *        ACL_ENTRY_NO_PROPAGATE_INHERIT.
  425                          */
  426                         copy->ae_flags &= ~(ACL_ENTRY_FILE_INHERIT |
  427                             ACL_ENTRY_DIRECTORY_INHERIT |
  428                             ACL_ENTRY_NO_PROPAGATE_INHERIT);
  429 
  430                         /*
  431                          * The algorithm continues on with the second ACE.
  432                          */
  433                         i++;
  434                         entry = copy;
  435                 }
  436 
  437                 /*
  438                  * 1.4. If it's owner@, group@ or everyone@ entry, clear
  439                  *      ACL_READ_DATA, ACL_WRITE_DATA, ACL_APPEND_DATA
  440                  *      and ACL_EXECUTE.  Continue to the next entry.
  441                  */
  442                 if (entry->ae_tag == ACL_USER_OBJ ||
  443                     entry->ae_tag == ACL_GROUP_OBJ ||
  444                     entry->ae_tag == ACL_EVERYONE) {
  445                         entry->ae_perm &= ~(ACL_READ_DATA | ACL_WRITE_DATA |
  446                             ACL_APPEND_DATA | ACL_EXECUTE);
  447                         continue;
  448                 }
  449 
  450                 /*
  451                  * 1.5. Otherwise, if the "who" field did not match one
  452                  *      of OWNER@, GROUP@, EVERYONE@:
  453                  *
  454                  * 1.5.1. If the type is ALLOW, check the preceding ACE.
  455                  *        If it does not meet all of the following criteria:
  456                  */
  457                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW)
  458                         continue;
  459 
  460                 meets = 0;
  461                 if (i > 0) {
  462                         meets = 1;
  463                         previous = &(aclp->acl_entry[i - 1]);
  464 
  465                         /*
  466                          * 1.5.1.1. The type field is DENY,
  467                          */
  468                         if (previous->ae_entry_type != ACL_ENTRY_TYPE_DENY)
  469                                 meets = 0;
  470 
  471                         /*
  472                          * 1.5.1.2. The "who" field is the same as the current
  473                          *          ACE,
  474                          *
  475                          * 1.5.1.3. The flag bit ACE4_IDENTIFIER_GROUP
  476                          *          is the same as it is in the current ACE,
  477                          *          and no other flag bits are set,
  478                          */
  479                         if (previous->ae_id != entry->ae_id ||
  480                             previous->ae_tag != entry->ae_tag)
  481                                 meets = 0;
  482 
  483                         if (previous->ae_flags)
  484                                 meets = 0;
  485 
  486                         /*
  487                          * 1.5.1.4. The mask bits are a subset of the mask bits
  488                          *          of the current ACE, and are also subset of
  489                          *          the following: ACL_READ_DATA,
  490                          *          ACL_WRITE_DATA, ACL_APPEND_DATA, ACL_EXECUTE
  491                          */
  492                         if (previous->ae_perm & ~(entry->ae_perm))
  493                                 meets = 0;
  494 
  495                         if (previous->ae_perm & ~(ACL_READ_DATA |
  496                             ACL_WRITE_DATA | ACL_APPEND_DATA | ACL_EXECUTE))
  497                                 meets = 0;
  498                 }
  499 
  500                 if (!meets) {
  501                         /*
  502                          * Then the ACE of type DENY, with a who equal
  503                          * to the current ACE, flag bits equal to
  504                          * (<current ACE flags> & <ACE_IDENTIFIER_GROUP>)
  505                          * and no mask bits, is prepended.
  506                          */
  507                         previous = entry;
  508                         entry = _acl_duplicate_entry(aclp, i);
  509 
  510                         /* Adjust counter, as we've just added an entry. */
  511                         i++;
  512 
  513                         previous->ae_tag = entry->ae_tag;
  514                         previous->ae_id = entry->ae_id;
  515                         previous->ae_flags = entry->ae_flags;
  516                         previous->ae_perm = 0;
  517                         previous->ae_entry_type = ACL_ENTRY_TYPE_DENY;
  518                 }
  519 
  520                 /*
  521                  * 1.5.2. The following modifications are made to the prepended
  522                  *        ACE.  The intent is to mask the following ACE
  523                  *        to disallow ACL_READ_DATA, ACL_WRITE_DATA,
  524                  *        ACL_APPEND_DATA, or ACL_EXECUTE, based upon the group
  525                  *        permissions of the new mode.  As a special case,
  526                  *        if the ACE matches the current owner of the file,
  527                  *        the owner bits are used, rather than the group bits.
  528                  *        This is reflected in the algorithm below.
  529                  */
  530                 amode = mode >> 3;
  531 
  532                 /*
  533                  * If ACE4_IDENTIFIER_GROUP is not set, and the "who" field
  534                  * in ACE matches the owner of the file, we shift amode three
  535                  * more bits, in order to have the owner permission bits
  536                  * placed in the three low order bits of amode.
  537                  */
  538                 if (entry->ae_tag == ACL_USER && entry->ae_id == file_owner_id)
  539                         amode = amode >> 3;
  540 
  541                 if (entry->ae_perm & ACL_READ_DATA) {
  542                         if (amode & READ)
  543                                 previous->ae_perm &= ~ACL_READ_DATA;
  544                         else
  545                                 previous->ae_perm |= ACL_READ_DATA;
  546                 }
  547 
  548                 if (entry->ae_perm & ACL_WRITE_DATA) {
  549                         if (amode & WRITE)
  550                                 previous->ae_perm &= ~ACL_WRITE_DATA;
  551                         else
  552                                 previous->ae_perm |= ACL_WRITE_DATA;
  553                 }
  554 
  555                 if (entry->ae_perm & ACL_APPEND_DATA) {
  556                         if (amode & WRITE)
  557                                 previous->ae_perm &= ~ACL_APPEND_DATA;
  558                         else
  559                                 previous->ae_perm |= ACL_APPEND_DATA;
  560                 }
  561 
  562                 if (entry->ae_perm & ACL_EXECUTE) {
  563                         if (amode & EXEC)
  564                                 previous->ae_perm &= ~ACL_EXECUTE;
  565                         else
  566                                 previous->ae_perm |= ACL_EXECUTE;
  567                 }
  568 
  569                 /*
  570                  * 1.5.3. If ACE4_IDENTIFIER_GROUP is set in the flags
  571                  *        of the ALLOW ace:
  572                  *
  573                  * XXX: This point is not there in the Falkner's draft.
  574                  */
  575                 if (entry->ae_tag == ACL_GROUP &&
  576                     entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) {
  577                         mode_t extramode, ownermode;
  578                         extramode = (mode >> 3) & 07;
  579                         ownermode = mode >> 6;
  580                         extramode &= ~ownermode;
  581 
  582                         if (extramode) {
  583                                 if (extramode & READ) {
  584                                         entry->ae_perm &= ~ACL_READ_DATA;
  585                                         previous->ae_perm &= ~ACL_READ_DATA;
  586                                 }
  587 
  588                                 if (extramode & WRITE) {
  589                                         entry->ae_perm &=
  590                                             ~(ACL_WRITE_DATA | ACL_APPEND_DATA);
  591                                         previous->ae_perm &=
  592                                             ~(ACL_WRITE_DATA | ACL_APPEND_DATA);
  593                                 }
  594 
  595                                 if (extramode & EXEC) {
  596                                         entry->ae_perm &= ~ACL_EXECUTE;
  597                                         previous->ae_perm &= ~ACL_EXECUTE;
  598                                 }
  599                         }
  600                 }
  601         }
  602 
  603         /*
  604          * 2. If there at least six ACEs, the final six ACEs are examined.
  605          *    If they are not equal to what we want, append six ACEs.
  606          */
  607         must_append = 0;
  608         if (aclp->acl_cnt < 6) {
  609                 must_append = 1;
  610         } else {
  611                 a6 = &(aclp->acl_entry[aclp->acl_cnt - 1]);
  612                 a5 = &(aclp->acl_entry[aclp->acl_cnt - 2]);
  613                 a4 = &(aclp->acl_entry[aclp->acl_cnt - 3]);
  614                 a3 = &(aclp->acl_entry[aclp->acl_cnt - 4]);
  615                 a2 = &(aclp->acl_entry[aclp->acl_cnt - 5]);
  616                 a1 = &(aclp->acl_entry[aclp->acl_cnt - 6]);
  617 
  618                 if (!_acl_entry_matches(a1, ACL_USER_OBJ, 0,
  619                     ACL_ENTRY_TYPE_DENY))
  620                         must_append = 1;
  621                 if (!_acl_entry_matches(a2, ACL_USER_OBJ, ACL_WRITE_ACL |
  622                     ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
  623                     ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW))
  624                         must_append = 1;
  625                 if (!_acl_entry_matches(a3, ACL_GROUP_OBJ, 0,
  626                     ACL_ENTRY_TYPE_DENY))
  627                         must_append = 1;
  628                 if (!_acl_entry_matches(a4, ACL_GROUP_OBJ, 0,
  629                     ACL_ENTRY_TYPE_ALLOW))
  630                         must_append = 1;
  631                 if (!_acl_entry_matches(a5, ACL_EVERYONE, ACL_WRITE_ACL |
  632                     ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
  633                     ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY))
  634                         must_append = 1;
  635                 if (!_acl_entry_matches(a6, ACL_EVERYONE, ACL_READ_ACL |
  636                     ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS |
  637                     ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW))
  638                         must_append = 1;
  639         }
  640 
  641         if (must_append) {
  642                 KASSERT(aclp->acl_cnt + 6 <= ACL_MAX_ENTRIES,
  643                     ("aclp->acl_cnt <= ACL_MAX_ENTRIES"));
  644 
  645                 a1 = _acl_append(aclp, ACL_USER_OBJ, 0, ACL_ENTRY_TYPE_DENY);
  646                 a2 = _acl_append(aclp, ACL_USER_OBJ, ACL_WRITE_ACL |
  647                     ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
  648                     ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW);
  649                 a3 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_DENY);
  650                 a4 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_ALLOW);
  651                 a5 = _acl_append(aclp, ACL_EVERYONE, ACL_WRITE_ACL |
  652                     ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
  653                     ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY);
  654                 a6 = _acl_append(aclp, ACL_EVERYONE, ACL_READ_ACL |
  655                     ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS |
  656                     ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW);
  657 
  658                 KASSERT(a1 != NULL && a2 != NULL && a3 != NULL && a4 != NULL &&
  659                     a5 != NULL && a6 != NULL, ("couldn't append to ACL."));
  660         }
  661 
  662         /*
  663          * 3. The final six ACEs are adjusted according to the incoming mode.
  664          */
  665         if (mode & S_IRUSR)
  666                 a2->ae_perm |= ACL_READ_DATA;
  667         else
  668                 a1->ae_perm |= ACL_READ_DATA;
  669         if (mode & S_IWUSR)
  670                 a2->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
  671         else
  672                 a1->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
  673         if (mode & S_IXUSR)
  674                 a2->ae_perm |= ACL_EXECUTE;
  675         else
  676                 a1->ae_perm |= ACL_EXECUTE;
  677 
  678         if (mode & S_IRGRP)
  679                 a4->ae_perm |= ACL_READ_DATA;
  680         else
  681                 a3->ae_perm |= ACL_READ_DATA;
  682         if (mode & S_IWGRP)
  683                 a4->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
  684         else
  685                 a3->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
  686         if (mode & S_IXGRP)
  687                 a4->ae_perm |= ACL_EXECUTE;
  688         else
  689                 a3->ae_perm |= ACL_EXECUTE;
  690 
  691         if (mode & S_IROTH)
  692                 a6->ae_perm |= ACL_READ_DATA;
  693         else
  694                 a5->ae_perm |= ACL_READ_DATA;
  695         if (mode & S_IWOTH)
  696                 a6->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
  697         else
  698                 a5->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
  699         if (mode & S_IXOTH)
  700                 a6->ae_perm |= ACL_EXECUTE;
  701         else
  702                 a5->ae_perm |= ACL_EXECUTE;
  703 }
  704 
  705 #ifdef _KERNEL
  706 void
  707 acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode,
  708     int file_owner_id)
  709 {
  710 
  711         if (acl_nfs4_old_semantics)
  712                 acl_nfs4_sync_acl_from_mode_draft(aclp, mode, file_owner_id);
  713         else
  714                 acl_nfs4_trivial_from_mode(aclp, mode);
  715 }
  716 #endif /* _KERNEL */
  717 
  718 void
  719 acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp)
  720 {
  721         int i;
  722         mode_t old_mode = *_mode, mode = 0, seen = 0;
  723         const struct acl_entry *entry;
  724 
  725         KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES,
  726             ("aclp->acl_cnt <= ACL_MAX_ENTRIES"));
  727 
  728         /*
  729          * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt
  730          *
  731          * 3.16.6.1. Recomputing mode upon SETATTR of ACL
  732          */
  733 
  734         for (i = 0; i < aclp->acl_cnt; i++) {
  735                 entry = &(aclp->acl_entry[i]);
  736 
  737                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
  738                     entry->ae_entry_type != ACL_ENTRY_TYPE_DENY)
  739                         continue;
  740 
  741                 if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY)
  742                         continue;
  743 
  744                 if (entry->ae_tag == ACL_USER_OBJ) {
  745                         if ((entry->ae_perm & ACL_READ_DATA) &&
  746                             ((seen & S_IRUSR) == 0)) {
  747                                 seen |= S_IRUSR;
  748                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  749                                         mode |= S_IRUSR;
  750                         }
  751                         if ((entry->ae_perm & ACL_WRITE_DATA) &&
  752                              ((seen & S_IWUSR) == 0)) {
  753                                 seen |= S_IWUSR;
  754                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  755                                         mode |= S_IWUSR;
  756                         }
  757                         if ((entry->ae_perm & ACL_EXECUTE) &&
  758                             ((seen & S_IXUSR) == 0)) {
  759                                 seen |= S_IXUSR;
  760                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  761                                         mode |= S_IXUSR;
  762                         }
  763                 } else if (entry->ae_tag == ACL_GROUP_OBJ) {
  764                         if ((entry->ae_perm & ACL_READ_DATA) &&
  765                             ((seen & S_IRGRP) == 0)) {
  766                                 seen |= S_IRGRP;
  767                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  768                                         mode |= S_IRGRP;
  769                         }
  770                         if ((entry->ae_perm & ACL_WRITE_DATA) &&
  771                             ((seen & S_IWGRP) == 0)) {
  772                                 seen |= S_IWGRP;
  773                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  774                                         mode |= S_IWGRP;
  775                         }
  776                         if ((entry->ae_perm & ACL_EXECUTE) &&
  777                             ((seen & S_IXGRP) == 0)) {
  778                                 seen |= S_IXGRP;
  779                                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  780                                         mode |= S_IXGRP;
  781                         }
  782                 } else if (entry->ae_tag == ACL_EVERYONE) {
  783                         if (entry->ae_perm & ACL_READ_DATA) {
  784                                 if ((seen & S_IRUSR) == 0) {
  785                                         seen |= S_IRUSR;
  786                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  787                                                 mode |= S_IRUSR;
  788                                 }
  789                                 if ((seen & S_IRGRP) == 0) {
  790                                         seen |= S_IRGRP;
  791                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  792                                                 mode |= S_IRGRP;
  793                                 }
  794                                 if ((seen & S_IROTH) == 0) {
  795                                         seen |= S_IROTH;
  796                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  797                                                 mode |= S_IROTH;
  798                                 }
  799                         }
  800                         if (entry->ae_perm & ACL_WRITE_DATA) {
  801                                 if ((seen & S_IWUSR) == 0) {
  802                                         seen |= S_IWUSR;
  803                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  804                                                 mode |= S_IWUSR;
  805                                 }
  806                                 if ((seen & S_IWGRP) == 0) {
  807                                         seen |= S_IWGRP;
  808                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  809                                                 mode |= S_IWGRP;
  810                                 }
  811                                 if ((seen & S_IWOTH) == 0) {
  812                                         seen |= S_IWOTH;
  813                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  814                                                 mode |= S_IWOTH;
  815                                 }
  816                         }
  817                         if (entry->ae_perm & ACL_EXECUTE) {
  818                                 if ((seen & S_IXUSR) == 0) {
  819                                         seen |= S_IXUSR;
  820                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  821                                                 mode |= S_IXUSR;
  822                                 }
  823                                 if ((seen & S_IXGRP) == 0) {
  824                                         seen |= S_IXGRP;
  825                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  826                                                 mode |= S_IXGRP;
  827                                 }
  828                                 if ((seen & S_IXOTH) == 0) {
  829                                         seen |= S_IXOTH;
  830                                         if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  831                                                 mode |= S_IXOTH;
  832                                 }
  833                         }
  834                 }
  835         }
  836 
  837         *_mode = mode | (old_mode & ACL_PRESERVE_MASK);
  838 }
  839 
  840 #ifdef _KERNEL
  841 /*
  842  * Calculate inherited ACL in a manner compatible with NFSv4 Minor Version 1,
  843  * draft-ietf-nfsv4-minorversion1-03.txt.
  844  */
  845 static void             
  846 acl_nfs4_compute_inherited_acl_draft(const struct acl *parent_aclp,
  847     struct acl *child_aclp, mode_t mode, int file_owner_id,
  848     int is_directory)
  849 {
  850         int i, flags;
  851         const struct acl_entry *parent_entry;
  852         struct acl_entry *entry, *copy;
  853 
  854         KASSERT(child_aclp->acl_cnt == 0, ("child_aclp->acl_cnt == 0"));
  855         KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES,
  856             ("parent_aclp->acl_cnt <= ACL_MAX_ENTRIES"));
  857 
  858         /*
  859          * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt
  860          *
  861          * 3.16.6.2. Applying the mode given to CREATE or OPEN
  862          *           to an inherited ACL
  863          */
  864 
  865         /*
  866          * 1. Form an ACL that is the concatenation of all inheritable ACEs.
  867          */
  868         for (i = 0; i < parent_aclp->acl_cnt; i++) {
  869                 parent_entry = &(parent_aclp->acl_entry[i]);
  870                 flags = parent_entry->ae_flags;
  871 
  872                 /*
  873                  * Entry is not inheritable at all.
  874                  */
  875                 if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT |
  876                     ACL_ENTRY_FILE_INHERIT)) == 0)
  877                         continue;
  878 
  879                 /*
  880                  * We're creating a file, but entry is not inheritable
  881                  * by files.
  882                  */
  883                 if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0)
  884                         continue;
  885 
  886                 /*
  887                  * Entry is inheritable only by files, but has NO_PROPAGATE
  888                  * flag set, and we're creating a directory, so it wouldn't
  889                  * propagate to any file in that directory anyway.
  890                  */
  891                 if (is_directory &&
  892                     (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 &&
  893                     (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT))
  894                         continue;
  895 
  896                 KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES,
  897                     ("child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES"));
  898                 child_aclp->acl_entry[child_aclp->acl_cnt] = *parent_entry;
  899                 child_aclp->acl_cnt++;
  900         }
  901 
  902         /*
  903          * 2. For each entry in the new ACL, adjust its flags, possibly
  904          *    creating two entries in place of one.
  905          */
  906         for (i = 0; i < child_aclp->acl_cnt; i++) {
  907                 entry = &(child_aclp->acl_entry[i]);
  908 
  909                 /*
  910                  * This is not in the specification, but SunOS
  911                  * apparently does that.
  912                  */
  913                 if (((entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT) ||
  914                     !is_directory) &&
  915                     entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  916                         entry->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER);
  917 
  918                 /*
  919                  * 2.A. If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if the object
  920                  *      being created is not a directory, then clear the
  921                  *      following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT,
  922                  *      ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT,
  923                  *      ACL_ENTRY_INHERIT_ONLY.
  924                  */
  925                 if (entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT ||
  926                     !is_directory) {
  927                         entry->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT |
  928                         ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT |
  929                         ACL_ENTRY_INHERIT_ONLY);
  930 
  931                         /*
  932                          * Continue on to the next ACE.
  933                          */
  934                         continue;
  935                 }
  936 
  937                 /*
  938                  * 2.B. If the object is a directory and ACL_ENTRY_FILE_INHERIT
  939                  *      is set, but ACL_ENTRY_NO_PROPAGATE_INHERIT is not set, ensure
  940                  *      that ACL_ENTRY_INHERIT_ONLY is set.  Continue to the
  941                  *      next ACE.  Otherwise...
  942                  */
  943                 /*
  944                  * XXX: Read it again and make sure what does the "otherwise"
  945                  *      apply to.
  946                  */
  947                 if (is_directory &&
  948                     (entry->ae_flags & ACL_ENTRY_FILE_INHERIT) &&
  949                     ((entry->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) {
  950                         entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
  951                         continue;
  952                 }
  953 
  954                 /*
  955                  * 2.C. If the type of the ACE is neither ALLOW nor deny,
  956                  *      then continue.
  957                  */
  958                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
  959                     entry->ae_entry_type != ACL_ENTRY_TYPE_DENY)
  960                         continue;
  961 
  962                 /*
  963                  * 2.D. Copy the original ACE into a second, adjacent ACE.
  964                  */
  965                 copy = _acl_duplicate_entry(child_aclp, i);
  966 
  967                 /*
  968                  * 2.E. On the first ACE, ensure that ACL_ENTRY_INHERIT_ONLY
  969                  *      is set.
  970                  */
  971                 entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
  972 
  973                 /*
  974                  * 2.F. On the second ACE, clear the following flags:
  975                  *      ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_FILE_INHERIT,
  976                  *      ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_INHERIT_ONLY.
  977                  */
  978                 copy->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT |
  979                     ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT |
  980                     ACL_ENTRY_INHERIT_ONLY);
  981 
  982                 /*
  983                  * 2.G. On the second ACE, if the type is ALLOW,
  984                  *      an implementation MAY clear the following
  985                  *      mask bits: ACL_WRITE_ACL, ACL_WRITE_OWNER.
  986                  */
  987                 if (copy->ae_entry_type == ACL_ENTRY_TYPE_ALLOW)
  988                         copy->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER);
  989 
  990                 /*
  991                  * Increment the counter to skip the copied entry.
  992                  */
  993                 i++;
  994         }
  995 
  996         /*
  997          * 3. To ensure that the mode is honored, apply the algorithm describe
  998          *    in Section 2.16.6.3, using the mode that is to be used for file
  999          *    creation.
 1000          */
 1001         acl_nfs4_sync_acl_from_mode(child_aclp, mode, file_owner_id);
 1002 }
 1003 #endif /* _KERNEL */
 1004 
 1005 /*
 1006  * Populate the ACL with entries inherited from parent_aclp.
 1007  */
 1008 static void             
 1009 acl_nfs4_inherit_entries(const struct acl *parent_aclp,
 1010     struct acl *child_aclp, mode_t mode, int file_owner_id,
 1011     int is_directory)
 1012 {
 1013         int i, flags, tag;
 1014         const struct acl_entry *parent_entry;
 1015         struct acl_entry *entry;
 1016 
 1017         KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES,
 1018             ("parent_aclp->acl_cnt <= ACL_MAX_ENTRIES"));
 1019 
 1020         for (i = 0; i < parent_aclp->acl_cnt; i++) {
 1021                 parent_entry = &(parent_aclp->acl_entry[i]);
 1022                 flags = parent_entry->ae_flags;
 1023                 tag = parent_entry->ae_tag;
 1024 
 1025                 /*
 1026                  * Don't inherit owner@, group@, or everyone@ entries.
 1027                  */
 1028                 if (tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ ||
 1029                     tag == ACL_EVERYONE)
 1030                         continue;
 1031 
 1032                 /*
 1033                  * Entry is not inheritable at all.
 1034                  */
 1035                 if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT |
 1036                     ACL_ENTRY_FILE_INHERIT)) == 0)
 1037                         continue;
 1038 
 1039                 /*
 1040                  * We're creating a file, but entry is not inheritable
 1041                  * by files.
 1042                  */
 1043                 if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0)
 1044                         continue;
 1045 
 1046                 /*
 1047                  * Entry is inheritable only by files, but has NO_PROPAGATE
 1048                  * flag set, and we're creating a directory, so it wouldn't
 1049                  * propagate to any file in that directory anyway.
 1050                  */
 1051                 if (is_directory &&
 1052                     (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 &&
 1053                     (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT))
 1054                         continue;
 1055 
 1056                 /*
 1057                  * Entry qualifies for being inherited.
 1058                  */
 1059                 KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES,
 1060                     ("child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES"));
 1061                 entry = &(child_aclp->acl_entry[child_aclp->acl_cnt]);
 1062                 *entry = *parent_entry;
 1063                 child_aclp->acl_cnt++;
 1064 
 1065                 entry->ae_flags &= ~ACL_ENTRY_INHERIT_ONLY;
 1066                 entry->ae_flags |= ACL_ENTRY_INHERITED;
 1067 
 1068                 /*
 1069                  * If the type of the ACE is neither ALLOW nor DENY,
 1070                  * then leave it as it is and proceed to the next one.
 1071                  */
 1072                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
 1073                     entry->ae_entry_type != ACL_ENTRY_TYPE_DENY)
 1074                         continue;
 1075 
 1076                 /*
 1077                  * If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if
 1078                  * the object being created is not a directory, then clear
 1079                  * the following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT,
 1080                  * ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT,
 1081                  * ACL_ENTRY_INHERIT_ONLY.
 1082                  */
 1083                 if (entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT ||
 1084                     !is_directory) {
 1085                         entry->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT |
 1086                         ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT |
 1087                         ACL_ENTRY_INHERIT_ONLY);
 1088                 }
 1089 
 1090                 /*
 1091                  * If the object is a directory and ACL_ENTRY_FILE_INHERIT
 1092                  * is set, but ACL_ENTRY_DIRECTORY_INHERIT is not set, ensure
 1093                  * that ACL_ENTRY_INHERIT_ONLY is set.
 1094                  */
 1095                 if (is_directory &&
 1096                     (entry->ae_flags & ACL_ENTRY_FILE_INHERIT) &&
 1097                     ((entry->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) {
 1098                         entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
 1099                 }
 1100 
 1101                 if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW &&
 1102                     (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) == 0) {
 1103                         /*
 1104                          * Some permissions must never be inherited.
 1105                          */
 1106                         entry->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER |
 1107                             ACL_WRITE_NAMED_ATTRS | ACL_WRITE_ATTRIBUTES);
 1108 
 1109                         /*
 1110                          * Others must be masked according to the file mode.
 1111                          */
 1112                         if ((mode & S_IRGRP) == 0)
 1113                                 entry->ae_perm &= ~ACL_READ_DATA;
 1114                         if ((mode & S_IWGRP) == 0)
 1115                                 entry->ae_perm &=
 1116                                     ~(ACL_WRITE_DATA | ACL_APPEND_DATA);
 1117                         if ((mode & S_IXGRP) == 0)
 1118                                 entry->ae_perm &= ~ACL_EXECUTE;
 1119                 }
 1120         }
 1121 }
 1122 
 1123 /*
 1124  * Calculate inherited ACL in a manner compatible with PSARC/2010/029.
 1125  * It's also being used to calculate a trivial ACL, by inheriting from
 1126  * a NULL ACL.
 1127  */
 1128 static void             
 1129 acl_nfs4_compute_inherited_acl_psarc(const struct acl *parent_aclp,
 1130     struct acl *aclp, mode_t mode, int file_owner_id, int is_directory)
 1131 {
 1132         acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0;
 1133         acl_perm_t user_allow, group_allow, everyone_allow;
 1134 
 1135         KASSERT(aclp->acl_cnt == 0, ("aclp->acl_cnt == 0"));
 1136 
 1137         user_allow = group_allow = everyone_allow = ACL_READ_ACL |
 1138             ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE;
 1139         user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
 1140             ACL_WRITE_NAMED_ATTRS;
 1141 
 1142         if (mode & S_IRUSR)
 1143                 user_allow |= ACL_READ_DATA;
 1144         if (mode & S_IWUSR)
 1145                 user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
 1146         if (mode & S_IXUSR)
 1147                 user_allow |= ACL_EXECUTE;
 1148 
 1149         if (mode & S_IRGRP)
 1150                 group_allow |= ACL_READ_DATA;
 1151         if (mode & S_IWGRP)
 1152                 group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
 1153         if (mode & S_IXGRP)
 1154                 group_allow |= ACL_EXECUTE;
 1155 
 1156         if (mode & S_IROTH)
 1157                 everyone_allow |= ACL_READ_DATA;
 1158         if (mode & S_IWOTH)
 1159                 everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
 1160         if (mode & S_IXOTH)
 1161                 everyone_allow |= ACL_EXECUTE;
 1162 
 1163         user_deny = ((group_allow | everyone_allow) & ~user_allow);
 1164         group_deny = everyone_allow & ~group_allow;
 1165         user_allow_first = group_deny & ~user_deny;
 1166 
 1167         if (user_allow_first != 0)
 1168                 _acl_append(aclp, ACL_USER_OBJ, user_allow_first,
 1169                     ACL_ENTRY_TYPE_ALLOW);
 1170         if (user_deny != 0)
 1171                 _acl_append(aclp, ACL_USER_OBJ, user_deny,
 1172                     ACL_ENTRY_TYPE_DENY);
 1173         if (group_deny != 0)
 1174                 _acl_append(aclp, ACL_GROUP_OBJ, group_deny,
 1175                     ACL_ENTRY_TYPE_DENY);
 1176 
 1177         if (parent_aclp != NULL)
 1178                 acl_nfs4_inherit_entries(parent_aclp, aclp, mode,
 1179                     file_owner_id, is_directory);
 1180 
 1181         _acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW);
 1182         _acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW);
 1183         _acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW);
 1184 }
 1185 
 1186 #ifdef _KERNEL
 1187 void            
 1188 acl_nfs4_compute_inherited_acl(const struct acl *parent_aclp,
 1189     struct acl *child_aclp, mode_t mode, int file_owner_id,
 1190     int is_directory)
 1191 {
 1192 
 1193         if (acl_nfs4_old_semantics)
 1194                 acl_nfs4_compute_inherited_acl_draft(parent_aclp, child_aclp,
 1195                     mode, file_owner_id, is_directory);
 1196         else
 1197                 acl_nfs4_compute_inherited_acl_psarc(parent_aclp, child_aclp,
 1198                     mode, file_owner_id, is_directory);
 1199 }
 1200 #endif /* _KERNEL */
 1201 
 1202 /*
 1203  * Calculate trivial ACL in a manner compatible with PSARC/2010/029.
 1204  * Note that this results in an ACL different from (but semantically
 1205  * equal to) the "canonical six" trivial ACL computed using algorithm
 1206  * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2.
 1207  */
 1208 static void
 1209 acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode)
 1210 {
 1211 
 1212         aclp->acl_cnt = 0;
 1213         acl_nfs4_compute_inherited_acl_psarc(NULL, aclp, mode, -1, -1);
 1214 }
 1215 
 1216 #ifndef _KERNEL
 1217 /*
 1218  * This routine is used by libc to implement acl_strip_np(3)
 1219  * and acl_is_trivial_np(3).
 1220  */
 1221 void
 1222 acl_nfs4_trivial_from_mode_libc(struct acl *aclp, int mode, int canonical_six)
 1223 {
 1224 
 1225         aclp->acl_cnt = 0;
 1226         if (canonical_six)
 1227                 acl_nfs4_sync_acl_from_mode_draft(aclp, mode, -1);
 1228         else
 1229                 acl_nfs4_trivial_from_mode(aclp, mode);
 1230 }
 1231 #endif /* !_KERNEL */
 1232 
 1233 #ifdef _KERNEL
 1234 static int
 1235 _acls_are_equal(const struct acl *a, const struct acl *b)
 1236 {
 1237         int i;
 1238         const struct acl_entry *entrya, *entryb;
 1239 
 1240         if (a->acl_cnt != b->acl_cnt)
 1241                 return (0);
 1242 
 1243         for (i = 0; i < b->acl_cnt; i++) {
 1244                 entrya = &(a->acl_entry[i]);
 1245                 entryb = &(b->acl_entry[i]);
 1246 
 1247                 if (entrya->ae_tag != entryb->ae_tag ||
 1248                     entrya->ae_id != entryb->ae_id ||
 1249                     entrya->ae_perm != entryb->ae_perm ||
 1250                     entrya->ae_entry_type != entryb->ae_entry_type ||
 1251                     entrya->ae_flags != entryb->ae_flags)
 1252                         return (0);
 1253         }
 1254 
 1255         return (1);
 1256 }
 1257 
 1258 /*
 1259  * This routine is used to determine whether to remove extended attribute
 1260  * that stores ACL contents.
 1261  */
 1262 int
 1263 acl_nfs4_is_trivial(const struct acl *aclp, int file_owner_id)
 1264 {
 1265         int trivial;
 1266         mode_t tmpmode = 0;
 1267         struct acl *tmpaclp;
 1268 
 1269         if (aclp->acl_cnt > 6)
 1270                 return (0);
 1271 
 1272         /*
 1273          * Compute the mode from the ACL, then compute new ACL from that mode.
 1274          * If the ACLs are identical, then the ACL is trivial.
 1275          *
 1276          * XXX: I guess there is a faster way to do this.  However, even
 1277          *      this slow implementation significantly speeds things up
 1278          *      for files that don't have non-trivial ACLs - it's critical
 1279          *      for performance to not use EA when they are not needed.
 1280          *
 1281          * First try the PSARC/2010/029 semantics.
 1282          */
 1283         tmpaclp = acl_alloc(M_WAITOK | M_ZERO);
 1284         acl_nfs4_sync_mode_from_acl(&tmpmode, aclp);
 1285         acl_nfs4_trivial_from_mode(tmpaclp, tmpmode);
 1286         trivial = _acls_are_equal(aclp, tmpaclp);
 1287         if (trivial) {
 1288                 acl_free(tmpaclp);
 1289                 return (trivial);
 1290         }
 1291 
 1292         /*
 1293          * Check if it's a draft-ietf-nfsv4-minorversion1-03.txt trivial ACL.
 1294          */
 1295         tmpaclp->acl_cnt = 0;
 1296         acl_nfs4_sync_acl_from_mode_draft(tmpaclp, tmpmode, file_owner_id);
 1297         trivial = _acls_are_equal(aclp, tmpaclp);
 1298         acl_free(tmpaclp);
 1299 
 1300         return (trivial);
 1301 }
 1302 #endif /* _KERNEL */
 1303 
 1304 int
 1305 acl_nfs4_check(const struct acl *aclp, int is_directory)
 1306 {
 1307         int i;
 1308         const struct acl_entry *entry;
 1309 
 1310         /*
 1311          * The spec doesn't seem to say anything about ACL validity.
 1312          * It seems there is not much to do here.  There is even no need
 1313          * to count "owner@" or "everyone@" (ACL_USER_OBJ and ACL_EVERYONE)
 1314          * entries, as there can be several of them and that's perfectly
 1315          * valid.  There can be none of them too.  Really.
 1316          */
 1317 
 1318         if (aclp->acl_cnt > ACL_MAX_ENTRIES || aclp->acl_cnt <= 0)
 1319                 return (EINVAL);
 1320 
 1321         for (i = 0; i < aclp->acl_cnt; i++) {
 1322                 entry = &(aclp->acl_entry[i]);
 1323 
 1324                 switch (entry->ae_tag) {
 1325                 case ACL_USER_OBJ:
 1326                 case ACL_GROUP_OBJ:
 1327                 case ACL_EVERYONE:
 1328                         if (entry->ae_id != ACL_UNDEFINED_ID)
 1329                                 return (EINVAL);
 1330                         break;
 1331 
 1332                 case ACL_USER:
 1333                 case ACL_GROUP:
 1334                         if (entry->ae_id == ACL_UNDEFINED_ID)
 1335                                 return (EINVAL);
 1336                         break;
 1337 
 1338                 default:
 1339                         return (EINVAL);
 1340                 }
 1341 
 1342                 if ((entry->ae_perm | ACL_NFS4_PERM_BITS) != ACL_NFS4_PERM_BITS)
 1343                         return (EINVAL);
 1344 
 1345                 /*
 1346                  * Disallow ACL_ENTRY_TYPE_AUDIT and ACL_ENTRY_TYPE_ALARM for now.
 1347                  */
 1348                 if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
 1349                     entry->ae_entry_type != ACL_ENTRY_TYPE_DENY)
 1350                         return (EINVAL);
 1351 
 1352                 if ((entry->ae_flags | ACL_FLAGS_BITS) != ACL_FLAGS_BITS)
 1353                         return (EINVAL);
 1354 
 1355                 /* Disallow unimplemented flags. */
 1356                 if (entry->ae_flags & (ACL_ENTRY_SUCCESSFUL_ACCESS |
 1357                     ACL_ENTRY_FAILED_ACCESS))
 1358                         return (EINVAL);
 1359 
 1360                 /* Disallow flags not allowed for ordinary files. */
 1361                 if (!is_directory) {
 1362                         if (entry->ae_flags & (ACL_ENTRY_FILE_INHERIT |
 1363                             ACL_ENTRY_DIRECTORY_INHERIT |
 1364                             ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_INHERIT_ONLY))
 1365                                 return (EINVAL);
 1366                 }
 1367         }
 1368 
 1369         return (0);
 1370 }
 1371 
 1372 #ifdef  _KERNEL
 1373 static int
 1374 acl_nfs4_modload(module_t module, int what, void *arg)
 1375 {
 1376         int ret;
 1377 
 1378         ret = 0;
 1379 
 1380         switch (what) {
 1381         case MOD_LOAD:
 1382         case MOD_SHUTDOWN:
 1383                 break;
 1384 
 1385         case MOD_QUIESCE:
 1386                 /* XXX TODO */
 1387                 ret = 0;
 1388                 break;
 1389 
 1390         case MOD_UNLOAD:
 1391                 /* XXX TODO */
 1392                 ret = 0;
 1393                 break;
 1394         default:
 1395                 ret = EINVAL;
 1396                 break;
 1397         }
 1398 
 1399         return (ret);
 1400 }
 1401 
 1402 static moduledata_t acl_nfs4_mod = {
 1403         "acl_nfs4",
 1404         acl_nfs4_modload,
 1405         NULL
 1406 };
 1407 
 1408 /*
 1409  * XXX TODO: which subsystem, order?
 1410  */
 1411 DECLARE_MODULE(acl_nfs4, acl_nfs4_mod, SI_SUB_VFS, SI_ORDER_FIRST);
 1412 MODULE_VERSION(acl_nfs4, 1);
 1413 #endif  /* _KERNEL */

Cache object: a82b6135267d77559001203d1de135ea


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.