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

Cache object: 6f0298506a8f19e2702799a69c079148


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