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

Cache object: 08c9dd194a628c8f5a4e23b8fc94862b


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