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_posix1e.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) 1999-2006 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * This software was developed by Robert Watson for the TrustedBSD Project.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 /*
   31  * Developed by the TrustedBSD Project.
   32  *
   33  * ACL support routines specific to POSIX.1e access control lists.  These are
   34  * utility routines for code common across file systems implementing POSIX.1e
   35  * ACLs.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD$");
   40 
   41 #include <sys/param.h>
   42 #include <sys/kernel.h>
   43 #include <sys/module.h>
   44 #include <sys/systm.h>
   45 #include <sys/mount.h>
   46 #include <sys/priv.h>
   47 #include <sys/vnode.h>
   48 #include <sys/errno.h>
   49 #include <sys/stat.h>
   50 #include <sys/acl.h>
   51 
   52 /*
   53  * Implement a version of vaccess() that understands POSIX.1e ACL semantics;
   54  * the access ACL has already been prepared for evaluation by the file system
   55  * and is passed via 'uid', 'gid', and 'acl'.  Return 0 on success, else an
   56  * errno value.
   57  */
   58 int
   59 vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid,
   60     struct acl *acl, accmode_t accmode, struct ucred *cred)
   61 {
   62         struct acl_entry *acl_other, *acl_mask;
   63         accmode_t dac_granted;
   64         accmode_t priv_granted;
   65         accmode_t acl_mask_granted;
   66         int group_matched, i;
   67 
   68         KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0,
   69             ("invalid bit in accmode"));
   70         KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE),
   71                 ("VAPPEND without VWRITE"));
   72 
   73         /*
   74          * Look for a normal, non-privileged way to access the file/directory
   75          * as requested.  If it exists, go with that.  Otherwise, attempt to
   76          * use privileges granted via priv_granted.  In some cases, which
   77          * privileges to use may be ambiguous due to "best match", in which
   78          * case fall back on first match for the time being.
   79          */
   80 
   81         /*
   82          * Determine privileges now, but don't apply until we've found a DAC
   83          * entry that matches but has failed to allow access.
   84          *
   85          * XXXRW: Ideally, we'd determine the privileges required before
   86          * asking for them.
   87          */
   88         priv_granted = 0;
   89 
   90         if (type == VDIR) {
   91                 if ((accmode & VEXEC) && !priv_check_cred(cred, PRIV_VFS_LOOKUP))
   92                         priv_granted |= VEXEC;
   93         } else {
   94                 /*
   95                  * Ensure that at least one execute bit is on. Otherwise,
   96                  * a privileged user will always succeed, and we don't want
   97                  * this to happen unless the file really is executable.
   98                  */
   99                 if ((accmode & VEXEC) && (acl_posix1e_acl_to_mode(acl) &
  100                     (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 &&
  101                     !priv_check_cred(cred, PRIV_VFS_EXEC))
  102                         priv_granted |= VEXEC;
  103         }
  104 
  105         if ((accmode & VREAD) && !priv_check_cred(cred, PRIV_VFS_READ))
  106                 priv_granted |= VREAD;
  107 
  108         if (((accmode & VWRITE) || (accmode & VAPPEND)) &&
  109             !priv_check_cred(cred, PRIV_VFS_WRITE))
  110                 priv_granted |= (VWRITE | VAPPEND);
  111 
  112         if ((accmode & VADMIN) && !priv_check_cred(cred, PRIV_VFS_ADMIN))
  113                 priv_granted |= VADMIN;
  114 
  115         /*
  116          * The owner matches if the effective uid associated with the
  117          * credential matches that of the ACL_USER_OBJ entry.  While we're
  118          * doing the first scan, also cache the location of the ACL_MASK and
  119          * ACL_OTHER entries, preventing some future iterations.
  120          */
  121         acl_mask = acl_other = NULL;
  122         for (i = 0; i < acl->acl_cnt; i++) {
  123                 switch (acl->acl_entry[i].ae_tag) {
  124                 case ACL_USER_OBJ:
  125                         if (file_uid != cred->cr_uid)
  126                                 break;
  127                         dac_granted = 0;
  128                         dac_granted |= VADMIN;
  129                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  130                                 dac_granted |= VEXEC;
  131                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  132                                 dac_granted |= VREAD;
  133                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  134                                 dac_granted |= (VWRITE | VAPPEND);
  135                         if ((accmode & dac_granted) == accmode)
  136                                 return (0);
  137 
  138                         /*
  139                          * XXXRW: Do privilege lookup here.
  140                          */
  141                         if ((accmode & (dac_granted | priv_granted)) ==
  142                             accmode) {
  143                                 return (0);
  144                         }
  145                         goto error;
  146 
  147                 case ACL_MASK:
  148                         acl_mask = &acl->acl_entry[i];
  149                         break;
  150 
  151                 case ACL_OTHER:
  152                         acl_other = &acl->acl_entry[i];
  153                         break;
  154 
  155                 default:
  156                         break;
  157                 }
  158         }
  159 
  160         /*
  161          * An ACL_OTHER entry should always exist in a valid access ACL.  If
  162          * it doesn't, then generate a serious failure.  For now, this means
  163          * a debugging message and EPERM, but in the future should probably
  164          * be a panic.
  165          */
  166         if (acl_other == NULL) {
  167                 /*
  168                  * XXX This should never happen
  169                  */
  170                 printf("vaccess_acl_posix1e: ACL_OTHER missing\n");
  171                 return (EPERM);
  172         }
  173 
  174         /*
  175          * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are
  176          * masked by an ACL_MASK entry, if any.  As such, first identify the
  177          * ACL_MASK field, then iterate through identifying potential user
  178          * matches, then group matches.  If there is no ACL_MASK, assume that
  179          * the mask allows all requests to succeed.
  180          */
  181         if (acl_mask != NULL) {
  182                 acl_mask_granted = 0;
  183                 if (acl_mask->ae_perm & ACL_EXECUTE)
  184                         acl_mask_granted |= VEXEC;
  185                 if (acl_mask->ae_perm & ACL_READ)
  186                         acl_mask_granted |= VREAD;
  187                 if (acl_mask->ae_perm & ACL_WRITE)
  188                         acl_mask_granted |= (VWRITE | VAPPEND);
  189         } else
  190                 acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND;
  191 
  192         /*
  193          * Check ACL_USER ACL entries.  There will either be one or no
  194          * matches; if there is one, we accept or rejected based on the
  195          * match; otherwise, we continue on to groups.
  196          */
  197         for (i = 0; i < acl->acl_cnt; i++) {
  198                 switch (acl->acl_entry[i].ae_tag) {
  199                 case ACL_USER:
  200                         if (acl->acl_entry[i].ae_id != cred->cr_uid)
  201                                 break;
  202                         dac_granted = 0;
  203                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  204                                 dac_granted |= VEXEC;
  205                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  206                                 dac_granted |= VREAD;
  207                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  208                                 dac_granted |= (VWRITE | VAPPEND);
  209                         dac_granted &= acl_mask_granted;
  210                         if ((accmode & dac_granted) == accmode)
  211                                 return (0);
  212                         /*
  213                          * XXXRW: Do privilege lookup here.
  214                          */
  215                         if ((accmode & (dac_granted | priv_granted)) !=
  216                             accmode)
  217                                 goto error;
  218 
  219                         return (0);
  220                 }
  221         }
  222 
  223         /*
  224          * Group match is best-match, not first-match, so find a "best"
  225          * match.  Iterate across, testing each potential group match.  Make
  226          * sure we keep track of whether we found a match or not, so that we
  227          * know if we should try again with any available privilege, or if we
  228          * should move on to ACL_OTHER.
  229          */
  230         group_matched = 0;
  231         for (i = 0; i < acl->acl_cnt; i++) {
  232                 switch (acl->acl_entry[i].ae_tag) {
  233                 case ACL_GROUP_OBJ:
  234                         if (!groupmember(file_gid, cred))
  235                                 break;
  236                         dac_granted = 0;
  237                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  238                                 dac_granted |= VEXEC;
  239                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  240                                 dac_granted |= VREAD;
  241                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  242                                 dac_granted |= (VWRITE | VAPPEND);
  243                         dac_granted  &= acl_mask_granted;
  244 
  245                         if ((accmode & dac_granted) == accmode)
  246                                 return (0);
  247 
  248                         group_matched = 1;
  249                         break;
  250 
  251                 case ACL_GROUP:
  252                         if (!groupmember(acl->acl_entry[i].ae_id, cred))
  253                                 break;
  254                         dac_granted = 0;
  255                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  256                                 dac_granted |= VEXEC;
  257                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  258                                 dac_granted |= VREAD;
  259                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  260                                 dac_granted |= (VWRITE | VAPPEND);
  261                         dac_granted  &= acl_mask_granted;
  262 
  263                         if ((accmode & dac_granted) == accmode)
  264                                 return (0);
  265 
  266                         group_matched = 1;
  267                         break;
  268 
  269                 default:
  270                         break;
  271                 }
  272         }
  273 
  274         if (group_matched == 1) {
  275                 /*
  276                  * There was a match, but it did not grant rights via pure
  277                  * DAC.  Try again, this time with privilege.
  278                  */
  279                 for (i = 0; i < acl->acl_cnt; i++) {
  280                         switch (acl->acl_entry[i].ae_tag) {
  281                         case ACL_GROUP_OBJ:
  282                                 if (!groupmember(file_gid, cred))
  283                                         break;
  284                                 dac_granted = 0;
  285                                 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  286                                         dac_granted |= VEXEC;
  287                                 if (acl->acl_entry[i].ae_perm & ACL_READ)
  288                                         dac_granted |= VREAD;
  289                                 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  290                                         dac_granted |= (VWRITE | VAPPEND);
  291                                 dac_granted &= acl_mask_granted;
  292 
  293                                 /*
  294                                  * XXXRW: Do privilege lookup here.
  295                                  */
  296                                 if ((accmode & (dac_granted | priv_granted))
  297                                     != accmode)
  298                                         break;
  299 
  300                                 return (0);
  301 
  302                         case ACL_GROUP:
  303                                 if (!groupmember(acl->acl_entry[i].ae_id,
  304                                     cred))
  305                                         break;
  306                                 dac_granted = 0;
  307                                 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  308                                 dac_granted |= VEXEC;
  309                                 if (acl->acl_entry[i].ae_perm & ACL_READ)
  310                                         dac_granted |= VREAD;
  311                                 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  312                                         dac_granted |= (VWRITE | VAPPEND);
  313                                 dac_granted &= acl_mask_granted;
  314 
  315                                 /*
  316                                  * XXXRW: Do privilege lookup here.
  317                                  */
  318                                 if ((accmode & (dac_granted | priv_granted))
  319                                     != accmode)
  320                                         break;
  321 
  322                                 return (0);
  323 
  324                         default:
  325                                 break;
  326                         }
  327                 }
  328                 /*
  329                  * Even with privilege, group membership was not sufficient.
  330                  * Return failure.
  331                  */
  332                 goto error;
  333         }
  334                 
  335         /*
  336          * Fall back on ACL_OTHER.  ACL_MASK is not applied to ACL_OTHER.
  337          */
  338         dac_granted = 0;
  339         if (acl_other->ae_perm & ACL_EXECUTE)
  340                 dac_granted |= VEXEC;
  341         if (acl_other->ae_perm & ACL_READ)
  342                 dac_granted |= VREAD;
  343         if (acl_other->ae_perm & ACL_WRITE)
  344                 dac_granted |= (VWRITE | VAPPEND);
  345 
  346         if ((accmode & dac_granted) == accmode)
  347                 return (0);
  348         /*
  349          * XXXRW: Do privilege lookup here.
  350          */
  351         if ((accmode & (dac_granted | priv_granted)) == accmode) {
  352                 return (0);
  353         }
  354 
  355 error:
  356         return ((accmode & VADMIN) ? EPERM : EACCES);
  357 }
  358 
  359 /*
  360  * For the purposes of filesystems maintaining the _OBJ entries in an inode
  361  * with a mode_t field, this routine converts a mode_t entry to an
  362  * acl_perm_t.
  363  */
  364 acl_perm_t
  365 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
  366 {
  367         acl_perm_t      perm = 0;
  368 
  369         switch(tag) {
  370         case ACL_USER_OBJ:
  371                 if (mode & S_IXUSR)
  372                         perm |= ACL_EXECUTE;
  373                 if (mode & S_IRUSR)
  374                         perm |= ACL_READ;
  375                 if (mode & S_IWUSR)
  376                         perm |= ACL_WRITE;
  377                 return (perm);
  378 
  379         case ACL_GROUP_OBJ:
  380                 if (mode & S_IXGRP)
  381                         perm |= ACL_EXECUTE;
  382                 if (mode & S_IRGRP)
  383                         perm |= ACL_READ;
  384                 if (mode & S_IWGRP)
  385                         perm |= ACL_WRITE;
  386                 return (perm);
  387 
  388         case ACL_OTHER:
  389                 if (mode & S_IXOTH)
  390                         perm |= ACL_EXECUTE;
  391                 if (mode & S_IROTH)
  392                         perm |= ACL_READ;
  393                 if (mode & S_IWOTH)
  394                         perm |= ACL_WRITE;
  395                 return (perm);
  396 
  397         default:
  398                 printf("acl_posix1e_mode_to_perm: invalid tag (%d)\n", tag);
  399                 return (0);
  400         }
  401 }
  402 
  403 /*
  404  * Given inode information (uid, gid, mode), return an acl entry of the
  405  * appropriate type.
  406  */
  407 struct acl_entry
  408 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
  409 {
  410         struct acl_entry        acl_entry;
  411 
  412         acl_entry.ae_tag = tag;
  413         acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
  414         acl_entry.ae_entry_type = 0;
  415         acl_entry.ae_flags = 0;
  416         switch(tag) {
  417         case ACL_USER_OBJ:
  418                 acl_entry.ae_id = uid;
  419                 break;
  420 
  421         case ACL_GROUP_OBJ:
  422                 acl_entry.ae_id = gid;
  423                 break;
  424 
  425         case ACL_OTHER:
  426                 acl_entry.ae_id = ACL_UNDEFINED_ID;
  427                 break;
  428 
  429         default:
  430                 acl_entry.ae_id = ACL_UNDEFINED_ID;
  431                 printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
  432         }
  433 
  434         return (acl_entry);
  435 }
  436 
  437 /*
  438  * Utility function to generate a file mode given appropriate ACL entries.
  439  */
  440 mode_t
  441 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
  442     struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
  443 {
  444         mode_t  mode;
  445 
  446         mode = 0;
  447         if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
  448                 mode |= S_IXUSR;
  449         if (acl_user_obj_entry->ae_perm & ACL_READ)
  450                 mode |= S_IRUSR;
  451         if (acl_user_obj_entry->ae_perm & ACL_WRITE)
  452                 mode |= S_IWUSR;
  453         if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
  454                 mode |= S_IXGRP;
  455         if (acl_group_obj_entry->ae_perm & ACL_READ)
  456                 mode |= S_IRGRP;
  457         if (acl_group_obj_entry->ae_perm & ACL_WRITE)
  458                 mode |= S_IWGRP;
  459         if (acl_other_entry->ae_perm & ACL_EXECUTE)
  460                 mode |= S_IXOTH;
  461         if (acl_other_entry->ae_perm & ACL_READ)
  462                 mode |= S_IROTH;
  463         if (acl_other_entry->ae_perm & ACL_WRITE)
  464                 mode |= S_IWOTH;
  465 
  466         return (mode);
  467 }
  468 
  469 /*
  470  * Utility function to generate a file mode given a complete POSIX.1e access
  471  * ACL.  Note that if the ACL is improperly formed, this may result in a
  472  * panic.
  473  */
  474 mode_t
  475 acl_posix1e_acl_to_mode(struct acl *acl)
  476 {
  477         struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
  478         int i;
  479 
  480         /*
  481          * Find the ACL entries relevant to a POSIX permission mode.
  482          */
  483         acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
  484         for (i = 0; i < acl->acl_cnt; i++) {
  485                 switch (acl->acl_entry[i].ae_tag) {
  486                 case ACL_USER_OBJ:
  487                         acl_user_obj = &acl->acl_entry[i];
  488                         break;
  489 
  490                 case ACL_GROUP_OBJ:
  491                         acl_group_obj = &acl->acl_entry[i];
  492                         break;
  493 
  494                 case ACL_OTHER:
  495                         acl_other = &acl->acl_entry[i];
  496                         break;
  497 
  498                 case ACL_MASK:
  499                         acl_mask = &acl->acl_entry[i];
  500                         break;
  501 
  502                 case ACL_USER:
  503                 case ACL_GROUP:
  504                         break;
  505 
  506                 default:
  507                         panic("acl_posix1e_acl_to_mode: bad ae_tag");
  508                 }
  509         }
  510 
  511         if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
  512                 panic("acl_posix1e_acl_to_mode: missing base ae_tags");
  513 
  514         /*
  515          * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
  516          * the mode "group" bits with its permissions.  If there isn't, we
  517          * use the ACL_GROUP_OBJ permissions.
  518          */
  519         if (acl_mask != NULL)
  520                 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
  521                     acl_other));
  522         else
  523                 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
  524                     acl_other));
  525 }
  526 
  527 /*
  528  * Perform a syntactic check of the ACL, sufficient to allow an implementing
  529  * filesystem to determine if it should accept this and rely on the POSIX.1e
  530  * ACL properties.
  531  */
  532 int
  533 acl_posix1e_check(struct acl *acl)
  534 {
  535         int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
  536         int num_acl_mask, num_acl_other, i;
  537 
  538         /*
  539          * Verify that the number of entries does not exceed the maximum
  540          * defined for acl_t.
  541          *
  542          * Verify that the correct number of various sorts of ae_tags are
  543          * present:
  544          *   Exactly one ACL_USER_OBJ
  545          *   Exactly one ACL_GROUP_OBJ
  546          *   Exactly one ACL_OTHER
  547          *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
  548          *   ACL_MASK entry must also appear.
  549          *
  550          * Verify that all ae_perm entries are in ACL_PERM_BITS.
  551          *
  552          * Verify all ae_tag entries are understood by this implementation.
  553          *
  554          * Note: Does not check for uniqueness of qualifier (ae_id) field.
  555          */
  556         num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
  557             num_acl_mask = num_acl_other = 0;
  558         if (acl->acl_cnt > ACL_MAX_ENTRIES)
  559                 return (EINVAL);
  560         for (i = 0; i < acl->acl_cnt; i++) {
  561                 /*
  562                  * Check for a valid tag.
  563                  */
  564                 switch(acl->acl_entry[i].ae_tag) {
  565                 case ACL_USER_OBJ:
  566                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  567                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  568                                 return (EINVAL);
  569                         num_acl_user_obj++;
  570                         break;
  571                 case ACL_GROUP_OBJ:
  572                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  573                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  574                                 return (EINVAL);
  575                         num_acl_group_obj++;
  576                         break;
  577                 case ACL_USER:
  578                         if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
  579                                 return (EINVAL);
  580                         num_acl_user++;
  581                         break;
  582                 case ACL_GROUP:
  583                         if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
  584                                 return (EINVAL);
  585                         num_acl_group++;
  586                         break;
  587                 case ACL_OTHER:
  588                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  589                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  590                                 return (EINVAL);
  591                         num_acl_other++;
  592                         break;
  593                 case ACL_MASK:
  594                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  595                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  596                                 return (EINVAL);
  597                         num_acl_mask++;
  598                         break;
  599                 default:
  600                         return (EINVAL);
  601                 }
  602                 /*
  603                  * Check for valid perm entries.
  604                  */
  605                 if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
  606                     ACL_PERM_BITS)
  607                         return (EINVAL);
  608         }
  609         if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
  610             (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
  611                 return (EINVAL);
  612         if (((num_acl_group != 0) || (num_acl_user != 0)) &&
  613             (num_acl_mask != 1))
  614                 return (EINVAL);
  615         return (0);
  616 }
  617 
  618 /*
  619  * Given a requested mode for a new object, and a default ACL, combine the
  620  * two to produce a new mode.  Be careful not to clear any bits that aren't
  621  * intended to be affected by the POSIX.1e ACL.  Eventually, this might also
  622  * take the cmask as an argument, if we push that down into
  623  * per-filesystem-code.
  624  */
  625 mode_t
  626 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
  627 {
  628         mode_t mode;
  629 
  630         mode = cmode;
  631         /*
  632          * The current composition policy is that a permission bit must be
  633          * set in *both* the ACL and the requested creation mode for it to
  634          * appear in the resulting mode/ACL.  First clear any possibly
  635          * effected bits, then reconstruct.
  636          */
  637         mode &= ACL_PRESERVE_MASK;
  638         mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
  639 
  640         return (mode);
  641 }
  642 
  643 static int
  644 acl_posix1e_modload(module_t mod, int what, void *arg)
  645 {
  646         int ret;
  647 
  648         ret = 0;
  649 
  650         switch (what) {
  651         case MOD_LOAD:
  652         case MOD_SHUTDOWN:
  653                 break;
  654 
  655         case MOD_QUIESCE:
  656                 /* XXX TODO */
  657                 ret = 0;
  658                 break;
  659 
  660         case MOD_UNLOAD:
  661                 /* XXX TODO */
  662                 ret = 0;
  663                 break;
  664         default:
  665                 ret = EINVAL;
  666                 break;
  667         }
  668 
  669         return (ret);
  670 }
  671 
  672 static moduledata_t acl_posix1e_mod = {
  673         "acl_posix1e",
  674         acl_posix1e_modload,
  675         NULL
  676 };
  677 
  678 DECLARE_MODULE(acl_posix1e, acl_posix1e_mod, SI_SUB_VFS, SI_ORDER_FIRST);
  679 MODULE_VERSION(acl_posix1e, 1);

Cache object: 5e23180ac9a8d9c9225b9eac2f2d7928


[ 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.