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/kern_acl.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-2003 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  * Support for POSIX.1e access control lists.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD: releng/6.4/sys/kern/kern_acl.c 152361 2005-11-13 03:14:00Z csjp $");
   35 
   36 #include "opt_mac.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/sysproto.h>
   41 #include <sys/kernel.h>
   42 #include <sys/mac.h>
   43 #include <sys/malloc.h>
   44 #include <sys/mount.h>
   45 #include <sys/vnode.h>
   46 #include <sys/lock.h>
   47 #include <sys/mutex.h>
   48 #include <sys/namei.h>
   49 #include <sys/file.h>
   50 #include <sys/filedesc.h>
   51 #include <sys/proc.h>
   52 #include <sys/sysent.h>
   53 #include <sys/errno.h>
   54 #include <sys/stat.h>
   55 #include <sys/acl.h>
   56 
   57 #include <vm/uma.h>
   58 
   59 uma_zone_t      acl_zone;
   60 static int      vacl_set_acl(struct thread *td, struct vnode *vp,
   61                     acl_type_t type, struct acl *aclp);
   62 static int      vacl_get_acl(struct thread *td, struct vnode *vp,
   63                     acl_type_t type, struct acl *aclp);
   64 static int      vacl_aclcheck(struct thread *td, struct vnode *vp,
   65                     acl_type_t type, struct acl *aclp);
   66 
   67 /*
   68  * Implement a version of vaccess() that understands POSIX.1e ACL semantics.
   69  * Return 0 on success, else an errno value.  Should be merged into
   70  * vaccess() eventually.
   71  */
   72 int
   73 vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid,
   74     struct acl *acl, mode_t acc_mode, struct ucred *cred, int *privused)
   75 {
   76         struct acl_entry *acl_other, *acl_mask;
   77         mode_t dac_granted;
   78         mode_t cap_granted;
   79         mode_t acl_mask_granted;
   80         int group_matched, i;
   81 
   82         /*
   83          * Look for a normal, non-privileged way to access the file/directory
   84          * as requested.  If it exists, go with that.  Otherwise, attempt
   85          * to use privileges granted via cap_granted.  In some cases,
   86          * which privileges to use may be ambiguous due to "best match",
   87          * in which case fall back on first match for the time being.
   88          */
   89         if (privused != NULL)
   90                 *privused = 0;
   91 
   92         /*
   93          * Determine privileges now, but don't apply until we've found
   94          * a DAC entry that matches but has failed to allow access.
   95          */
   96 #ifndef CAPABILITIES
   97         if (suser_cred(cred, SUSER_ALLOWJAIL) == 0)
   98                 cap_granted = VALLPERM;
   99         else
  100                 cap_granted = 0;
  101 #else
  102         cap_granted = 0;
  103 
  104         if (type == VDIR) {
  105                 if ((acc_mode & VEXEC) && !cap_check(cred, NULL,
  106                      CAP_DAC_READ_SEARCH, SUSER_ALLOWJAIL))
  107                         cap_granted |= VEXEC;
  108         } else {
  109                 if ((acc_mode & VEXEC) && !cap_check(cred, NULL,
  110                     CAP_DAC_EXECUTE, SUSER_ALLOWJAIL))
  111                         cap_granted |= VEXEC;
  112         }
  113 
  114         if ((acc_mode & VREAD) && !cap_check(cred, NULL, CAP_DAC_READ_SEARCH,
  115             SUSER_ALLOWJAIL))
  116                 cap_granted |= VREAD;
  117 
  118         if (((acc_mode & VWRITE) || (acc_mode & VAPPEND)) &&
  119             !cap_check(cred, NULL, CAP_DAC_WRITE, SUSER_ALLOWJAIL))
  120                 cap_granted |= (VWRITE | VAPPEND);
  121 
  122         if ((acc_mode & VADMIN) && !cap_check(cred, NULL, CAP_FOWNER,
  123             SUSER_ALLOWJAIL))
  124                 cap_granted |= VADMIN;
  125 #endif /* CAPABILITIES */
  126 
  127         /*
  128          * The owner matches if the effective uid associated with the
  129          * credential matches that of the ACL_USER_OBJ entry.  While we're
  130          * doing the first scan, also cache the location of the ACL_MASK
  131          * and ACL_OTHER entries, preventing some future iterations.
  132          */
  133         acl_mask = acl_other = NULL;
  134         for (i = 0; i < acl->acl_cnt; i++) {
  135                 switch (acl->acl_entry[i].ae_tag) {
  136                 case ACL_USER_OBJ:
  137                         if (file_uid != cred->cr_uid)
  138                                 break;
  139                         dac_granted = 0;
  140                         dac_granted |= VADMIN;
  141                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  142                                 dac_granted |= VEXEC;
  143                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  144                                 dac_granted |= VREAD;
  145                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  146                                 dac_granted |= (VWRITE | VAPPEND);
  147                         if ((acc_mode & dac_granted) == acc_mode)
  148                                 return (0);
  149                         if ((acc_mode & (dac_granted | cap_granted)) ==
  150                             acc_mode) {
  151                                 if (privused != NULL)
  152                                         *privused = 1;
  153                                 return (0);
  154                         }
  155                         goto error;
  156 
  157                 case ACL_MASK:
  158                         acl_mask = &acl->acl_entry[i];
  159                         break;
  160 
  161                 case ACL_OTHER:
  162                         acl_other = &acl->acl_entry[i];
  163                         break;
  164 
  165                 default:
  166                         break;
  167                 }
  168         }
  169 
  170         /*
  171          * An ACL_OTHER entry should always exist in a valid access
  172          * ACL.  If it doesn't, then generate a serious failure.  For now,
  173          * this means a debugging message and EPERM, but in the future
  174          * should probably be a panic.
  175          */
  176         if (acl_other == NULL) {
  177                 /*
  178                  * XXX This should never happen
  179                  */
  180                 printf("vaccess_acl_posix1e: ACL_OTHER missing\n");
  181                 return (EPERM);
  182         }
  183 
  184         /*
  185          * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields
  186          * are masked by an ACL_MASK entry, if any.  As such, first identify
  187          * the ACL_MASK field, then iterate through identifying potential
  188          * user matches, then group matches.  If there is no ACL_MASK,
  189          * assume that the mask allows all requests to succeed.
  190          */
  191         if (acl_mask != NULL) {
  192                 acl_mask_granted = 0;
  193                 if (acl_mask->ae_perm & ACL_EXECUTE)
  194                         acl_mask_granted |= VEXEC;
  195                 if (acl_mask->ae_perm & ACL_READ)
  196                         acl_mask_granted |= VREAD;
  197                 if (acl_mask->ae_perm & ACL_WRITE)
  198                         acl_mask_granted |= (VWRITE | VAPPEND);
  199         } else
  200                 acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND;
  201 
  202         /*
  203          * Iterate through user ACL entries.  Do checks twice, first
  204          * without privilege, and then if a match is found but failed,
  205          * a second time with privilege.
  206          */
  207 
  208         /*
  209          * Check ACL_USER ACL entries.
  210          */
  211         for (i = 0; i < acl->acl_cnt; i++) {
  212                 switch (acl->acl_entry[i].ae_tag) {
  213                 case ACL_USER:
  214                         if (acl->acl_entry[i].ae_id != cred->cr_uid)
  215                                 break;
  216                         dac_granted = 0;
  217                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  218                                 dac_granted |= VEXEC;
  219                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  220                                 dac_granted |= VREAD;
  221                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  222                                 dac_granted |= (VWRITE | VAPPEND);
  223                         dac_granted &= acl_mask_granted;
  224                         if ((acc_mode & dac_granted) == acc_mode)
  225                                 return (0);
  226                         if ((acc_mode & (dac_granted | cap_granted)) !=
  227                             acc_mode)
  228                                 goto error;
  229 
  230                         if (privused != NULL)
  231                                 *privused = 1;
  232                         return (0);
  233                 }
  234         }
  235 
  236         /*
  237          * Group match is best-match, not first-match, so find a 
  238          * "best" match.  Iterate across, testing each potential group
  239          * match.  Make sure we keep track of whether we found a match
  240          * or not, so that we know if we should try again with any
  241          * available privilege, or if we should move on to ACL_OTHER.
  242          */
  243         group_matched = 0;
  244         for (i = 0; i < acl->acl_cnt; i++) {
  245                 switch (acl->acl_entry[i].ae_tag) {
  246                 case ACL_GROUP_OBJ:
  247                         if (!groupmember(file_gid, cred))
  248                                 break;
  249                         dac_granted = 0;
  250                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  251                                 dac_granted |= VEXEC;
  252                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  253                                 dac_granted |= VREAD;
  254                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  255                                 dac_granted |= (VWRITE | VAPPEND);
  256                         dac_granted  &= acl_mask_granted;
  257 
  258                         if ((acc_mode & dac_granted) == acc_mode)
  259                                 return (0);
  260 
  261                         group_matched = 1;
  262                         break;
  263 
  264                 case ACL_GROUP:
  265                         if (!groupmember(acl->acl_entry[i].ae_id, cred))
  266                                 break;
  267                         dac_granted = 0;
  268                         if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  269                                 dac_granted |= VEXEC;
  270                         if (acl->acl_entry[i].ae_perm & ACL_READ)
  271                                 dac_granted |= VREAD;
  272                         if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  273                                 dac_granted |= (VWRITE | VAPPEND);
  274                         dac_granted  &= acl_mask_granted;
  275 
  276                         if ((acc_mode & dac_granted) == acc_mode)
  277                                 return (0);
  278 
  279                         group_matched = 1;
  280                         break;
  281 
  282                 default:
  283                         break;
  284                 }
  285         }
  286 
  287         if (group_matched == 1) {
  288                 /*
  289                  * There was a match, but it did not grant rights via
  290                  * pure DAC.  Try again, this time with privilege.
  291                  */
  292                 for (i = 0; i < acl->acl_cnt; i++) {
  293                         switch (acl->acl_entry[i].ae_tag) {
  294                         case ACL_GROUP_OBJ:
  295                                 if (!groupmember(file_gid, cred))
  296                                         break;
  297                                 dac_granted = 0;
  298                                 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  299                                         dac_granted |= VEXEC;
  300                                 if (acl->acl_entry[i].ae_perm & ACL_READ)
  301                                         dac_granted |= VREAD;
  302                                 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  303                                         dac_granted |= (VWRITE | VAPPEND);
  304                                 dac_granted &= acl_mask_granted;
  305 
  306                                 if ((acc_mode & (dac_granted | cap_granted)) !=
  307                                     acc_mode)
  308                                         break;
  309 
  310                                 if (privused != NULL)
  311                                         *privused = 1;
  312                                 return (0);
  313 
  314                         case ACL_GROUP:
  315                                 if (!groupmember(acl->acl_entry[i].ae_id,
  316                                     cred))
  317                                         break;
  318                                 dac_granted = 0;
  319                                 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
  320                                 dac_granted |= VEXEC;
  321                                 if (acl->acl_entry[i].ae_perm & ACL_READ)
  322                                         dac_granted |= VREAD;
  323                                 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
  324                                         dac_granted |= (VWRITE | VAPPEND);
  325                                 dac_granted &= acl_mask_granted;
  326 
  327                                 if ((acc_mode & (dac_granted | cap_granted)) !=
  328                                     acc_mode)
  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 ((acc_mode & dac_granted) == acc_mode)
  358                 return (0);
  359         if ((acc_mode & (dac_granted | cap_granted)) == acc_mode) {
  360                 if (privused != NULL)
  361                         *privused = 1;
  362                 return (0);
  363         }
  364 
  365 error:
  366         return ((acc_mode & VADMIN) ? EPERM : EACCES);
  367 }
  368 
  369 /*
  370  * For the purposes of filesystems maintaining the _OBJ entries in an
  371  * inode with a mode_t field, this routine converts a mode_t entry
  372  * to an acl_perm_t.
  373  */
  374 acl_perm_t
  375 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
  376 {
  377         acl_perm_t      perm = 0;
  378 
  379         switch(tag) {
  380         case ACL_USER_OBJ:
  381                 if (mode & S_IXUSR)
  382                         perm |= ACL_EXECUTE;
  383                 if (mode & S_IRUSR)
  384                         perm |= ACL_READ;
  385                 if (mode & S_IWUSR)
  386                         perm |= ACL_WRITE;
  387                 return (perm);
  388 
  389         case ACL_GROUP_OBJ:
  390                 if (mode & S_IXGRP)
  391                         perm |= ACL_EXECUTE;
  392                 if (mode & S_IRGRP)
  393                         perm |= ACL_READ;
  394                 if (mode & S_IWGRP)
  395                         perm |= ACL_WRITE;
  396                 return (perm);
  397 
  398         case ACL_OTHER:
  399                 if (mode & S_IXOTH)
  400                         perm |= ACL_EXECUTE;
  401                 if (mode & S_IROTH)
  402                         perm |= ACL_READ;
  403                 if (mode & S_IWOTH)
  404                         perm |= ACL_WRITE;
  405                 return (perm);
  406 
  407         default:
  408                 printf("acl_posix1e_mode_to_perm: invalid tag (%d)\n", tag);
  409                 return (0);
  410         }
  411 }
  412 
  413 /*
  414  * Given inode information (uid, gid, mode), return an acl entry of the
  415  * appropriate type.
  416  */
  417 struct acl_entry
  418 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
  419 {
  420         struct acl_entry        acl_entry;
  421 
  422         acl_entry.ae_tag = tag;
  423         acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
  424         switch(tag) {
  425         case ACL_USER_OBJ:
  426                 acl_entry.ae_id = uid;
  427                 break;
  428 
  429         case ACL_GROUP_OBJ:
  430                 acl_entry.ae_id = gid;
  431                 break;
  432 
  433         case ACL_OTHER:
  434                 acl_entry.ae_id = ACL_UNDEFINED_ID;
  435                 break;
  436 
  437         default:
  438                 acl_entry.ae_id = ACL_UNDEFINED_ID;
  439                 printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
  440         }
  441 
  442         return (acl_entry);
  443 }
  444 
  445 /*
  446  * Utility function to generate a file mode given appropriate ACL entries.
  447  */
  448 mode_t
  449 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
  450     struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
  451 {
  452         mode_t  mode;
  453 
  454         mode = 0;
  455         if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
  456                 mode |= S_IXUSR;
  457         if (acl_user_obj_entry->ae_perm & ACL_READ)
  458                 mode |= S_IRUSR;
  459         if (acl_user_obj_entry->ae_perm & ACL_WRITE)
  460                 mode |= S_IWUSR;
  461         if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
  462                 mode |= S_IXGRP;
  463         if (acl_group_obj_entry->ae_perm & ACL_READ)
  464                 mode |= S_IRGRP;
  465         if (acl_group_obj_entry->ae_perm & ACL_WRITE)
  466                 mode |= S_IWGRP;
  467         if (acl_other_entry->ae_perm & ACL_EXECUTE)
  468                 mode |= S_IXOTH;
  469         if (acl_other_entry->ae_perm & ACL_READ)
  470                 mode |= S_IROTH;
  471         if (acl_other_entry->ae_perm & ACL_WRITE)
  472                 mode |= S_IWOTH;
  473 
  474         return (mode);
  475 }
  476 
  477 /*
  478  * Utility function to generate a file mode given a complete POSIX.1e
  479  * access ACL.  Note that if the ACL is improperly formed, this may
  480  * result in a panic.
  481  */
  482 mode_t
  483 acl_posix1e_acl_to_mode(struct acl *acl)
  484 {
  485         struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
  486         int i;
  487 
  488         /*
  489          * Find the ACL entries relevant to a POSIX permission mode.
  490          */
  491         acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
  492         for (i = 0; i < acl->acl_cnt; i++) {
  493                 switch (acl->acl_entry[i].ae_tag) {
  494                 case ACL_USER_OBJ:
  495                         acl_user_obj = &acl->acl_entry[i];
  496                         break;
  497 
  498                 case ACL_GROUP_OBJ:
  499                         acl_group_obj = &acl->acl_entry[i];
  500                         break;
  501 
  502                 case ACL_OTHER:
  503                         acl_other = &acl->acl_entry[i];
  504                         break;
  505 
  506                 case ACL_MASK:
  507                         acl_mask = &acl->acl_entry[i];
  508                         break;
  509 
  510                 case ACL_USER:
  511                 case ACL_GROUP:
  512                         break;
  513 
  514                 default:
  515                         panic("acl_posix1e_acl_to_mode: bad ae_tag");
  516                 }
  517         }
  518 
  519         if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
  520                 panic("acl_posix1e_acl_to_mode: missing base ae_tags");
  521 
  522         /*
  523          * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
  524          * the mode "group" bits with its permissions.  If there isn't, we
  525          * use the ACL_GROUP_OBJ permissions.
  526          */
  527         if (acl_mask != NULL)
  528                 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
  529                     acl_other));
  530         else
  531                 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
  532                     acl_other));
  533 }
  534 
  535 /*
  536  * Perform a syntactic check of the ACL, sufficient to allow an
  537  * implementing filesystem to determine if it should accept this and
  538  * rely on the POSIX.1e ACL properties.
  539  */
  540 int
  541 acl_posix1e_check(struct acl *acl)
  542 {
  543         int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
  544         int num_acl_mask, num_acl_other, i;
  545 
  546         /*
  547          * Verify that the number of entries does not exceed the maximum
  548          * defined for acl_t.
  549          * Verify that the correct number of various sorts of ae_tags are
  550          * present:
  551          *   Exactly one ACL_USER_OBJ
  552          *   Exactly one ACL_GROUP_OBJ
  553          *   Exactly one ACL_OTHER
  554          *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
  555          *   ACL_MASK entry must also appear.
  556          * Verify that all ae_perm entries are in ACL_PERM_BITS.
  557          * Verify all ae_tag entries are understood by this implementation.
  558          * Note: Does not check for uniqueness of qualifier (ae_id) field.
  559          */
  560         num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
  561             num_acl_mask = num_acl_other = 0;
  562         if (acl->acl_cnt > ACL_MAX_ENTRIES || acl->acl_cnt < 0)
  563                 return (EINVAL);
  564         for (i = 0; i < acl->acl_cnt; i++) {
  565                 /*
  566                  * Check for a valid tag.
  567                  */
  568                 switch(acl->acl_entry[i].ae_tag) {
  569                 case ACL_USER_OBJ:
  570                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  571                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  572                                 return (EINVAL);
  573                         num_acl_user_obj++;
  574                         break;
  575                 case ACL_GROUP_OBJ:
  576                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  577                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  578                                 return (EINVAL);
  579                         num_acl_group_obj++;
  580                         break;
  581                 case ACL_USER:
  582                         if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
  583                                 return (EINVAL);
  584                         num_acl_user++;
  585                         break;
  586                 case ACL_GROUP:
  587                         if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
  588                                 return (EINVAL);
  589                         num_acl_group++;
  590                         break;
  591                 case ACL_OTHER:
  592                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  593                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  594                                 return (EINVAL);
  595                         num_acl_other++;
  596                         break;
  597                 case ACL_MASK:
  598                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
  599                         if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
  600                                 return (EINVAL);
  601                         num_acl_mask++;
  602                         break;
  603                 default:
  604                         return (EINVAL);
  605                 }
  606                 /*
  607                  * Check for valid perm entries.
  608                  */
  609                 if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
  610                     ACL_PERM_BITS)
  611                         return (EINVAL);
  612         }
  613         if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
  614             (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
  615                 return (EINVAL);
  616         if (((num_acl_group != 0) || (num_acl_user != 0)) &&
  617             (num_acl_mask != 1))
  618                 return (EINVAL);
  619         return (0);
  620 }
  621 
  622 /*
  623  * Given a requested mode for a new object, and a default ACL, combine
  624  * the two to produce a new mode.  Be careful not to clear any bits that
  625  * aren't intended to be affected by the POSIX.1e ACL.  Eventually,
  626  * this might also take the cmask as an argument, if we push that down
  627  * into per-filesystem-code.
  628  */
  629 mode_t
  630 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
  631 {
  632         mode_t mode;
  633 
  634         mode = cmode;
  635         /*
  636          * The current composition policy is that a permission bit must
  637          * be set in *both* the ACL and the requested creation mode for
  638          * it to appear in the resulting mode/ACL.  First clear any
  639          * possibly effected bits, then reconstruct.
  640          */
  641         mode &= ACL_PRESERVE_MASK;
  642         mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
  643 
  644         return (mode);
  645 }
  646 
  647 /*
  648  * These calls wrap the real vnode operations, and are called by the 
  649  * syscall code once the syscall has converted the path or file
  650  * descriptor to a vnode (unlocked).  The aclp pointer is assumed
  651  * still to point to userland, so this should not be consumed within
  652  * the kernel except by syscall code.  Other code should directly
  653  * invoke VOP_{SET,GET}ACL.
  654  */
  655 
  656 /*
  657  * Given a vnode, set its ACL.
  658  */
  659 static int
  660 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
  661     struct acl *aclp)
  662 {
  663         struct acl inkernacl;
  664         struct mount *mp;
  665         int error;
  666 
  667         error = copyin(aclp, &inkernacl, sizeof(struct acl));
  668         if (error)
  669                 return(error);
  670         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
  671         if (error != 0)
  672                 return (error);
  673         VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
  674         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  675 #ifdef MAC
  676         error = mac_check_vnode_setacl(td->td_ucred, vp, type, &inkernacl);
  677         if (error != 0)
  678                 goto out;
  679 #endif
  680         error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td);
  681 #ifdef MAC
  682 out:
  683 #endif
  684         VOP_UNLOCK(vp, 0, td);
  685         vn_finished_write(mp);
  686         return(error);
  687 }
  688 
  689 /*
  690  * Given a vnode, get its ACL.
  691  */
  692 static int
  693 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
  694     struct acl *aclp)
  695 {
  696         struct acl inkernelacl;
  697         int error;
  698 
  699         VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
  700         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  701 #ifdef MAC
  702         error = mac_check_vnode_getacl(td->td_ucred, vp, type);
  703         if (error != 0)
  704                 goto out;
  705 #endif
  706         error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td);
  707 #ifdef MAC
  708 out:
  709 #endif
  710         VOP_UNLOCK(vp, 0, td);
  711         if (error == 0)
  712                 error = copyout(&inkernelacl, aclp, sizeof(struct acl));
  713         return (error);
  714 }
  715 
  716 /*
  717  * Given a vnode, delete its ACL.
  718  */
  719 static int
  720 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
  721 {
  722         struct mount *mp;
  723         int error;
  724 
  725         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
  726         if (error)
  727                 return (error);
  728         VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
  729         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  730 #ifdef MAC
  731         error = mac_check_vnode_deleteacl(td->td_ucred, vp, type);
  732         if (error)
  733                 goto out;
  734 #endif
  735         error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
  736 #ifdef MAC
  737 out:
  738 #endif
  739         VOP_UNLOCK(vp, 0, td);
  740         vn_finished_write(mp);
  741         return (error);
  742 }
  743 
  744 /*
  745  * Given a vnode, check whether an ACL is appropriate for it
  746  */
  747 static int
  748 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
  749     struct acl *aclp)
  750 {
  751         struct acl inkernelacl;
  752         int error;
  753 
  754         error = copyin(aclp, &inkernelacl, sizeof(struct acl));
  755         if (error)
  756                 return(error);
  757         error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td);
  758         return (error);
  759 }
  760 
  761 /*
  762  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.
  763  * Don't need to lock, as the vacl_ code will get/release any locks
  764  * required.
  765  */
  766 
  767 /*
  768  * Given a file path, get an ACL for it
  769  *
  770  * MPSAFE
  771  */
  772 int
  773 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
  774 {
  775         struct nameidata nd;
  776         int vfslocked, error;
  777 
  778         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  779         error = namei(&nd);
  780         vfslocked = NDHASGIANT(&nd);
  781         if (error == 0) {
  782                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  783                 NDFREE(&nd, 0);
  784         }
  785         VFS_UNLOCK_GIANT(vfslocked);
  786         return (error);
  787 }
  788 
  789 /*
  790  * Given a file path, get an ACL for it; don't follow links.
  791  *
  792  * MPSAFE
  793  */
  794 int
  795 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
  796 {
  797         struct nameidata nd;
  798         int vfslocked, error;
  799 
  800         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  801         error = namei(&nd);
  802         vfslocked = NDHASGIANT(&nd);
  803         if (error == 0) {
  804                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  805                 NDFREE(&nd, 0);
  806         }
  807         VFS_UNLOCK_GIANT(vfslocked);
  808         return (error);
  809 }
  810 
  811 /*
  812  * Given a file path, set an ACL for it
  813  *
  814  * MPSAFE
  815  */
  816 int
  817 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
  818 {
  819         struct nameidata nd;
  820         int vfslocked, error;
  821 
  822         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  823         error = namei(&nd);
  824         vfslocked = NDHASGIANT(&nd);
  825         if (error == 0) {
  826                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  827                 NDFREE(&nd, 0);
  828         }
  829         VFS_UNLOCK_GIANT(vfslocked);
  830         return (error);
  831 }
  832 
  833 /*
  834  * Given a file path, set an ACL for it; don't follow links.
  835  *
  836  * MPSAFE
  837  */
  838 int
  839 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
  840 {
  841         struct nameidata nd;
  842         int vfslocked, error;
  843 
  844         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  845         error = namei(&nd);
  846         vfslocked = NDHASGIANT(&nd);
  847         if (error == 0) {
  848                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  849                 NDFREE(&nd, 0);
  850         }
  851         VFS_UNLOCK_GIANT(vfslocked);
  852         return (error);
  853 }
  854 
  855 /*
  856  * Given a file descriptor, get an ACL for it
  857  *
  858  * MPSAFE
  859  */
  860 int
  861 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
  862 {
  863         struct file *fp;
  864         int vfslocked, error;
  865 
  866         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  867         if (error == 0) {
  868                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  869                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
  870                 fdrop(fp, td);
  871                 VFS_UNLOCK_GIANT(vfslocked);
  872         }
  873         return (error);
  874 }
  875 
  876 /*
  877  * Given a file descriptor, set an ACL for it
  878  *
  879  * MPSAFE
  880  */
  881 int
  882 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
  883 {
  884         struct file *fp;
  885         int vfslocked, error;
  886 
  887         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  888         if (error == 0) {
  889                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  890                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
  891                 fdrop(fp, td);
  892                 VFS_UNLOCK_GIANT(vfslocked);
  893         }
  894         return (error);
  895 }
  896 
  897 /*
  898  * Given a file path, delete an ACL from it.
  899  *
  900  * MPSAFE
  901  */
  902 int
  903 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
  904 {
  905         struct nameidata nd;
  906         int vfslocked, error;
  907 
  908         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  909         error = namei(&nd);
  910         vfslocked = NDHASGIANT(&nd);
  911         if (error == 0) {
  912                 error = vacl_delete(td, nd.ni_vp, uap->type);
  913                 NDFREE(&nd, 0);
  914         }
  915         VFS_UNLOCK_GIANT(vfslocked);
  916         return (error);
  917 }
  918 
  919 /*
  920  * Given a file path, delete an ACL from it; don't follow links.
  921  *
  922  * MPSAFE
  923  */
  924 int
  925 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
  926 {
  927         struct nameidata nd;
  928         int vfslocked, error;
  929 
  930         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  931         error = namei(&nd);
  932         vfslocked = NDHASGIANT(&nd);
  933         if (error == 0) {
  934                 error = vacl_delete(td, nd.ni_vp, uap->type);
  935                 NDFREE(&nd, 0);
  936         }
  937         VFS_UNLOCK_GIANT(vfslocked);
  938         return (error);
  939 }
  940 
  941 /*
  942  * Given a file path, delete an ACL from it.
  943  *
  944  * MPSAFE
  945  */
  946 int
  947 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
  948 {
  949         struct file *fp;
  950         int vfslocked, error;
  951 
  952         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  953         if (error == 0) {
  954                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  955                 error = vacl_delete(td, fp->f_vnode, uap->type);
  956                 fdrop(fp, td);
  957                 VFS_UNLOCK_GIANT(vfslocked);
  958         }
  959         return (error);
  960 }
  961 
  962 /*
  963  * Given a file path, check an ACL for it
  964  *
  965  * MPSAFE
  966  */
  967 int
  968 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
  969 {
  970         struct nameidata        nd;
  971         int vfslocked, error;
  972 
  973         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  974         error = namei(&nd);
  975         vfslocked = NDHASGIANT(&nd);
  976         if (error == 0) {
  977                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  978                 NDFREE(&nd, 0);
  979         }
  980         VFS_UNLOCK_GIANT(vfslocked);
  981         return (error);
  982 }
  983 
  984 /*
  985  * Given a file path, check an ACL for it; don't follow links.
  986  *
  987  * MPSAFE
  988  */
  989 int
  990 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
  991 {
  992         struct nameidata        nd;
  993         int vfslocked, error;
  994 
  995         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  996         error = namei(&nd);
  997         vfslocked = NDHASGIANT(&nd);
  998         if (error == 0) {
  999                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
 1000                 NDFREE(&nd, 0);
 1001         }
 1002         VFS_UNLOCK_GIANT(vfslocked);
 1003         return (error);
 1004 }
 1005 
 1006 /*
 1007  * Given a file descriptor, check an ACL for it
 1008  *
 1009  * MPSAFE
 1010  */
 1011 int
 1012 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
 1013 {
 1014         struct file *fp;
 1015         int vfslocked, error;
 1016 
 1017         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
 1018         if (error == 0) {
 1019                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
 1020                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
 1021                 fdrop(fp, td);
 1022                 VFS_UNLOCK_GIANT(vfslocked);
 1023         }
 1024         return (error);
 1025 }
 1026 
 1027 /* ARGUSED */
 1028 
 1029 static void
 1030 aclinit(void *dummy __unused)
 1031 {
 1032 
 1033         acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl),
 1034             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
 1035 }
 1036 SYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL)

Cache object: 3c59e8becbf6f2a50cbd0f85f5cda0b0


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