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: releng/12.0/sys/kern/subr_acl_posix1e.c 326271 2017-11-27 15:20:12Z pfg $");
   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, int *privused)
   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         if (privused != NULL)
   81                 *privused = 0;
   82 
   83         /*
   84          * Determine privileges now, but don't apply until we've found a DAC
   85          * entry that matches but has failed to allow access.
   86          *
   87          * XXXRW: Ideally, we'd determine the privileges required before
   88          * asking for them.
   89          */
   90         priv_granted = 0;
   91 
   92         if (type == VDIR) {
   93                 if ((accmode & VEXEC) && !priv_check_cred(cred,
   94                      PRIV_VFS_LOOKUP, 0))
   95                         priv_granted |= VEXEC;
   96         } else {
   97                 /*
   98                  * Ensure that at least one execute bit is on. Otherwise,
   99                  * a privileged user will always succeed, and we don't want
  100                  * this to happen unless the file really is executable.
  101                  */
  102                 if ((accmode & VEXEC) && (acl_posix1e_acl_to_mode(acl) &
  103                     (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 &&
  104                     !priv_check_cred(cred, PRIV_VFS_EXEC, 0))
  105                         priv_granted |= VEXEC;
  106         }
  107 
  108         if ((accmode & VREAD) && !priv_check_cred(cred, PRIV_VFS_READ, 0))
  109                 priv_granted |= VREAD;
  110 
  111         if (((accmode & VWRITE) || (accmode & VAPPEND)) &&
  112             !priv_check_cred(cred, PRIV_VFS_WRITE, 0))
  113                 priv_granted |= (VWRITE | VAPPEND);
  114 
  115         if ((accmode & VADMIN) && !priv_check_cred(cred, PRIV_VFS_ADMIN, 0))
  116                 priv_granted |= VADMIN;
  117 
  118         /*
  119          * The owner matches if the effective uid associated with the
  120          * credential matches that of the ACL_USER_OBJ entry.  While we're
  121          * doing the first scan, also cache the location of the ACL_MASK and
  122          * ACL_OTHER entries, preventing some future iterations.
  123          */
  124         acl_mask = acl_other = NULL;
  125         for (i = 0; i < acl->acl_cnt; i++) {
  126                 switch (acl->acl_entry[i].ae_tag) {
  127                 case ACL_USER_OBJ:
  128                         if (file_uid != cred->cr_uid)
  129                                 break;
  130                         dac_granted = 0;
  131                         dac_granted |= VADMIN;
  132                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  133                                 dac_granted |= VEXEC;
  134                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  135                                 dac_granted |= VREAD;
  136                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  137                                 dac_granted |= (VWRITE | VAPPEND);
  138                         if ((accmode & dac_granted) == accmode)
  139                                 return (0);
  140 
  141                         /*
  142                          * XXXRW: Do privilege lookup here.
  143                          */
  144                         if ((accmode & (dac_granted | priv_granted)) ==
  145                             accmode) {
  146                                 if (privused != NULL)
  147                                         *privused = 1;
  148                                 return (0);
  149                         }
  150                         goto error;
  151 
  152                 case ACL_MASK:
  153                         acl_mask = &acl->acl_entry[i];
  154                         break;
  155 
  156                 case ACL_OTHER:
  157                         acl_other = &acl->acl_entry[i];
  158                         break;
  159 
  160                 default:
  161                         break;
  162                 }
  163         }
  164 
  165         /*
  166          * An ACL_OTHER entry should always exist in a valid access ACL.  If
  167          * it doesn't, then generate a serious failure.  For now, this means
  168          * a debugging message and EPERM, but in the future should probably
  169          * be a panic.
  170          */
  171         if (acl_other == NULL) {
  172                 /*
  173                  * XXX This should never happen
  174                  */
  175                 printf("vaccess_acl_posix1e: ACL_OTHER missing\n");
  176                 return (EPERM);
  177         }
  178 
  179         /*
  180          * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are
  181          * masked by an ACL_MASK entry, if any.  As such, first identify the
  182          * ACL_MASK field, then iterate through identifying potential user
  183          * matches, then group matches.  If there is no ACL_MASK, assume that
  184          * the mask allows all requests to succeed.
  185          */
  186         if (acl_mask != NULL) {
  187                 acl_mask_granted = 0;
  188                 if (acl_mask->ae_perm & ACL_EXECUTE)
  189                         acl_mask_granted |= VEXEC;
  190                 if (acl_mask->ae_perm & ACL_READ)
  191                         acl_mask_granted |= VREAD;
  192                 if (acl_mask->ae_perm & ACL_WRITE)
  193                         acl_mask_granted |= (VWRITE | VAPPEND);
  194         } else
  195                 acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND;
  196 
  197         /*
  198          * Check ACL_USER ACL entries.  There will either be one or no
  199          * matches; if there is one, we accept or rejected based on the
  200          * match; otherwise, we continue on to groups.
  201          */
  202         for (i = 0; i < acl->acl_cnt; i++) {
  203                 switch (acl->acl_entry[i].ae_tag) {
  204                 case ACL_USER:
  205                         if (acl->acl_entry[i].ae_id != cred->cr_uid)
  206                                 break;
  207                         dac_granted = 0;
  208                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  209                                 dac_granted |= VEXEC;
  210                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  211                                 dac_granted |= VREAD;
  212                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  213                                 dac_granted |= (VWRITE | VAPPEND);
  214                         dac_granted &= acl_mask_granted;
  215                         if ((accmode & dac_granted) == accmode)
  216                                 return (0);
  217                         /*
  218                          * XXXRW: Do privilege lookup here.
  219                          */
  220                         if ((accmode & (dac_granted | priv_granted)) !=
  221                             accmode)
  222                                 goto error;
  223 
  224                         if (privused != NULL)
  225                                 *privused = 1;
  226                         return (0);
  227                 }
  228         }
  229 
  230         /*
  231          * Group match is best-match, not first-match, so find a "best"
  232          * match.  Iterate across, testing each potential group match.  Make
  233          * sure we keep track of whether we found a match or not, so that we
  234          * know if we should try again with any available privilege, or if we
  235          * should move on to ACL_OTHER.
  236          */
  237         group_matched = 0;
  238         for (i = 0; i < acl->acl_cnt; i++) {
  239                 switch (acl->acl_entry[i].ae_tag) {
  240                 case ACL_GROUP_OBJ:
  241                         if (!groupmember(file_gid, cred))
  242                                 break;
  243                         dac_granted = 0;
  244                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  245                                 dac_granted |= VEXEC;
  246                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  247                                 dac_granted |= VREAD;
  248                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  249                                 dac_granted |= (VWRITE | VAPPEND);
  250                         dac_granted  &= acl_mask_granted;
  251 
  252                         if ((accmode & dac_granted) == accmode)
  253                                 return (0);
  254 
  255                         group_matched = 1;
  256                         break;
  257 
  258                 case ACL_GROUP:
  259                         if (!groupmember(acl->acl_entry[i].ae_id, cred))
  260                                 break;
  261                         dac_granted = 0;
  262                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  263                                 dac_granted |= VEXEC;
  264                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  265                                 dac_granted |= VREAD;
  266                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  267                                 dac_granted |= (VWRITE | VAPPEND);
  268                         dac_granted  &= acl_mask_granted;
  269 
  270                         if ((accmode & dac_granted) == accmode)
  271                                 return (0);
  272 
  273                         group_matched = 1;
  274                         break;
  275 
  276                 default:
  277                         break;
  278                 }
  279         }
  280 
  281         if (group_matched == 1) {
  282                 /*
  283                  * There was a match, but it did not grant rights via pure
  284                  * DAC.  Try again, this time with privilege.
  285                  */
  286                 for (i = 0; i < acl->acl_cnt; i++) {
  287                         switch (acl->acl_entry[i].ae_tag) {
  288                         case ACL_GROUP_OBJ:
  289                                 if (!groupmember(file_gid, cred))
  290                                         break;
  291                                 dac_granted = 0;
  292                                 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  293                                         dac_granted |= VEXEC;
  294                                 if (acl->acl_entry[i].ae_perm & ACL_READ)
  295                                         dac_granted |= VREAD;
  296                                 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  297                                         dac_granted |= (VWRITE | VAPPEND);
  298                                 dac_granted &= acl_mask_granted;
  299 
  300                                 /*
  301                                  * XXXRW: Do privilege lookup here.
  302                                  */
  303                                 if ((accmode & (dac_granted | priv_granted))
  304                                     != accmode)
  305                                         break;
  306 
  307                                 if (privused != NULL)
  308                                         *privused = 1;
  309                                 return (0);
  310 
  311                         case ACL_GROUP:
  312                                 if (!groupmember(acl->acl_entry[i].ae_id,
  313                                     cred))
  314                                         break;
  315                                 dac_granted = 0;
  316                                 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  317                                 dac_granted |= VEXEC;
  318                                 if (acl->acl_entry[i].ae_perm & ACL_READ)
  319                                         dac_granted |= VREAD;
  320                                 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  321                                         dac_granted |= (VWRITE | VAPPEND);
  322                                 dac_granted &= acl_mask_granted;
  323 
  324                                 /*
  325                                  * XXXRW: Do privilege lookup here.
  326                                  */
  327                                 if ((accmode & (dac_granted | priv_granted))
  328                                     != accmode)
  329                                         break;
  330 
  331                                 if (privused != NULL)
  332                                         *privused = 1;
  333                                 return (0);
  334 
  335                         default:
  336                                 break;
  337                         }
  338                 }
  339                 /*
  340                  * Even with privilege, group membership was not sufficient.
  341                  * Return failure.
  342                  */
  343                 goto error;
  344         }
  345                 
  346         /*
  347          * Fall back on ACL_OTHER.  ACL_MASK is not applied to ACL_OTHER.
  348          */
  349         dac_granted = 0;
  350         if (acl_other->ae_perm & ACL_EXECUTE)
  351                 dac_granted |= VEXEC;
  352         if (acl_other->ae_perm & ACL_READ)
  353                 dac_granted |= VREAD;
  354         if (acl_other->ae_perm & ACL_WRITE)
  355                 dac_granted |= (VWRITE | VAPPEND);
  356 
  357         if ((accmode & dac_granted) == accmode)
  358                 return (0);
  359         /*
  360          * XXXRW: Do privilege lookup here.
  361          */
  362         if ((accmode & (dac_granted | priv_granted)) == accmode) {
  363                 if (privused != NULL)
  364                         *privused = 1;
  365                 return (0);
  366         }
  367 
  368 error:
  369         return ((accmode & VADMIN) ? EPERM : EACCES);
  370 }
  371 
  372 /*
  373  * For the purposes of filesystems maintaining the _OBJ entries in an inode
  374  * with a mode_t field, this routine converts a mode_t entry to an
  375  * acl_perm_t.
  376  */
  377 acl_perm_t
  378 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
  379 {
  380         acl_perm_t      perm = 0;
  381 
  382         switch(tag) {
  383         case ACL_USER_OBJ:
  384                 if (mode & S_IXUSR)
  385                         perm |= ACL_EXECUTE;
  386                 if (mode & S_IRUSR)
  387                         perm |= ACL_READ;
  388                 if (mode & S_IWUSR)
  389                         perm |= ACL_WRITE;
  390                 return (perm);
  391 
  392         case ACL_GROUP_OBJ:
  393                 if (mode & S_IXGRP)
  394                         perm |= ACL_EXECUTE;
  395                 if (mode & S_IRGRP)
  396                         perm |= ACL_READ;
  397                 if (mode & S_IWGRP)
  398                         perm |= ACL_WRITE;
  399                 return (perm);
  400 
  401         case ACL_OTHER:
  402                 if (mode & S_IXOTH)
  403                         perm |= ACL_EXECUTE;
  404                 if (mode & S_IROTH)
  405                         perm |= ACL_READ;
  406                 if (mode & S_IWOTH)
  407                         perm |= ACL_WRITE;
  408                 return (perm);
  409 
  410         default:
  411                 printf("acl_posix1e_mode_to_perm: invalid tag (%d)\n", tag);
  412                 return (0);
  413         }
  414 }
  415 
  416 /*
  417  * Given inode information (uid, gid, mode), return an acl entry of the
  418  * appropriate type.
  419  */
  420 struct acl_entry
  421 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
  422 {
  423         struct acl_entry        acl_entry;
  424 
  425         acl_entry.ae_tag = tag;
  426         acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
  427         acl_entry.ae_entry_type = 0;
  428         acl_entry.ae_flags = 0;
  429         switch(tag) {
  430         case ACL_USER_OBJ:
  431                 acl_entry.ae_id = uid;
  432                 break;
  433 
  434         case ACL_GROUP_OBJ:
  435                 acl_entry.ae_id = gid;
  436                 break;
  437 
  438         case ACL_OTHER:
  439                 acl_entry.ae_id = ACL_UNDEFINED_ID;
  440                 break;
  441 
  442         default:
  443                 acl_entry.ae_id = ACL_UNDEFINED_ID;
  444                 printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
  445         }
  446 
  447         return (acl_entry);
  448 }
  449 
  450 /*
  451  * Utility function to generate a file mode given appropriate ACL entries.
  452  */
  453 mode_t
  454 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
  455     struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
  456 {
  457         mode_t  mode;
  458 
  459         mode = 0;
  460         if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
  461                 mode |= S_IXUSR;
  462         if (acl_user_obj_entry->ae_perm & ACL_READ)
  463                 mode |= S_IRUSR;
  464         if (acl_user_obj_entry->ae_perm & ACL_WRITE)
  465                 mode |= S_IWUSR;
  466         if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
  467                 mode |= S_IXGRP;
  468         if (acl_group_obj_entry->ae_perm & ACL_READ)
  469                 mode |= S_IRGRP;
  470         if (acl_group_obj_entry->ae_perm & ACL_WRITE)
  471                 mode |= S_IWGRP;
  472         if (acl_other_entry->ae_perm & ACL_EXECUTE)
  473                 mode |= S_IXOTH;
  474         if (acl_other_entry->ae_perm & ACL_READ)
  475                 mode |= S_IROTH;
  476         if (acl_other_entry->ae_perm & ACL_WRITE)
  477                 mode |= S_IWOTH;
  478 
  479         return (mode);
  480 }
  481 
  482 /*
  483  * Utility function to generate a file mode given a complete POSIX.1e access
  484  * ACL.  Note that if the ACL is improperly formed, this may result in a
  485  * panic.
  486  */
  487 mode_t
  488 acl_posix1e_acl_to_mode(struct acl *acl)
  489 {
  490         struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
  491         int i;
  492 
  493         /*
  494          * Find the ACL entries relevant to a POSIX permission mode.
  495          */
  496         acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
  497         for (i = 0; i < acl->acl_cnt; i++) {
  498                 switch (acl->acl_entry[i].ae_tag) {
  499                 case ACL_USER_OBJ:
  500                         acl_user_obj = &acl->acl_entry[i];
  501                         break;
  502 
  503                 case ACL_GROUP_OBJ:
  504                         acl_group_obj = &acl->acl_entry[i];
  505                         break;
  506 
  507                 case ACL_OTHER:
  508                         acl_other = &acl->acl_entry[i];
  509                         break;
  510 
  511                 case ACL_MASK:
  512                         acl_mask = &acl->acl_entry[i];
  513                         break;
  514 
  515                 case ACL_USER:
  516                 case ACL_GROUP:
  517                         break;
  518 
  519                 default:
  520                         panic("acl_posix1e_acl_to_mode: bad ae_tag");
  521                 }
  522         }
  523 
  524         if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
  525                 panic("acl_posix1e_acl_to_mode: missing base ae_tags");
  526 
  527         /*
  528          * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
  529          * the mode "group" bits with its permissions.  If there isn't, we
  530          * use the ACL_GROUP_OBJ permissions.
  531          */
  532         if (acl_mask != NULL)
  533                 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
  534                     acl_other));
  535         else
  536                 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
  537                     acl_other));
  538 }
  539 
  540 /*
  541  * Perform a syntactic check of the ACL, sufficient to allow an implementing
  542  * filesystem to determine if it should accept this and rely on the POSIX.1e
  543  * ACL properties.
  544  */
  545 int
  546 acl_posix1e_check(struct acl *acl)
  547 {
  548         int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
  549         int num_acl_mask, num_acl_other, i;
  550 
  551         /*
  552          * Verify that the number of entries does not exceed the maximum
  553          * defined for acl_t.
  554          *
  555          * Verify that the correct number of various sorts of ae_tags are
  556          * present:
  557          *   Exactly one ACL_USER_OBJ
  558          *   Exactly one ACL_GROUP_OBJ
  559          *   Exactly one ACL_OTHER
  560          *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
  561          *   ACL_MASK entry must also appear.
  562          *
  563          * Verify that all ae_perm entries are in ACL_PERM_BITS.
  564          *
  565          * Verify all ae_tag entries are understood by this implementation.
  566          *
  567          * Note: Does not check for uniqueness of qualifier (ae_id) field.
  568          */
  569         num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
  570             num_acl_mask = num_acl_other = 0;
  571         if (acl->acl_cnt > ACL_MAX_ENTRIES)
  572                 return (EINVAL);
  573         for (i = 0; i < acl->acl_cnt; i++) {
  574                 /*
  575                  * Check for a valid tag.
  576                  */
  577                 switch(acl->acl_entry[i].ae_tag) {
  578                 case ACL_USER_OBJ:
  579                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  580                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  581                                 return (EINVAL);
  582                         num_acl_user_obj++;
  583                         break;
  584                 case ACL_GROUP_OBJ:
  585                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  586                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  587                                 return (EINVAL);
  588                         num_acl_group_obj++;
  589                         break;
  590                 case ACL_USER:
  591                         if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
  592                                 return (EINVAL);
  593                         num_acl_user++;
  594                         break;
  595                 case ACL_GROUP:
  596                         if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
  597                                 return (EINVAL);
  598                         num_acl_group++;
  599                         break;
  600                 case ACL_OTHER:
  601                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  602                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  603                                 return (EINVAL);
  604                         num_acl_other++;
  605                         break;
  606                 case ACL_MASK:
  607                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  608                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  609                                 return (EINVAL);
  610                         num_acl_mask++;
  611                         break;
  612                 default:
  613                         return (EINVAL);
  614                 }
  615                 /*
  616                  * Check for valid perm entries.
  617                  */
  618                 if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
  619                     ACL_PERM_BITS)
  620                         return (EINVAL);
  621         }
  622         if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
  623             (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
  624                 return (EINVAL);
  625         if (((num_acl_group != 0) || (num_acl_user != 0)) &&
  626             (num_acl_mask != 1))
  627                 return (EINVAL);
  628         return (0);
  629 }
  630 
  631 /*
  632  * Given a requested mode for a new object, and a default ACL, combine the
  633  * two to produce a new mode.  Be careful not to clear any bits that aren't
  634  * intended to be affected by the POSIX.1e ACL.  Eventually, this might also
  635  * take the cmask as an argument, if we push that down into
  636  * per-filesystem-code.
  637  */
  638 mode_t
  639 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
  640 {
  641         mode_t mode;
  642 
  643         mode = cmode;
  644         /*
  645          * The current composition policy is that a permission bit must be
  646          * set in *both* the ACL and the requested creation mode for it to
  647          * appear in the resulting mode/ACL.  First clear any possibly
  648          * effected bits, then reconstruct.
  649          */
  650         mode &= ACL_PRESERVE_MASK;
  651         mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
  652 
  653         return (mode);
  654 }
  655 
  656 
  657 static int
  658 acl_posix1e_modload(module_t mod, int what, void *arg)
  659 {
  660         int ret;
  661 
  662         ret = 0;
  663 
  664         switch (what) {
  665         case MOD_LOAD:
  666         case MOD_SHUTDOWN:
  667                 break;
  668 
  669         case MOD_QUIESCE:
  670                 /* XXX TODO */
  671                 ret = 0;
  672                 break;
  673 
  674         case MOD_UNLOAD:
  675                 /* XXX TODO */
  676                 ret = 0;
  677                 break;
  678         default:
  679                 ret = EINVAL;
  680                 break;
  681         }
  682 
  683         return (ret);
  684 }
  685 
  686 static moduledata_t acl_posix1e_mod = {
  687         "acl_posix1e",
  688         acl_posix1e_modload,
  689         NULL
  690 };
  691 
  692 DECLARE_MODULE(acl_posix1e, acl_posix1e_mod, SI_SUB_VFS, SI_ORDER_FIRST);
  693 MODULE_VERSION(acl_posix1e, 1);

Cache object: 833acfe67fc3ac2e8a8cbde223a2846c


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