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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: dbebf09203dba54b226cbe9b0e799265


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