The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_acl_posix1e.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1999-2006 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * This software was developed by Robert Watson for the TrustedBSD Project.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 /*
   31  * Developed by the TrustedBSD Project.
   32  *
   33  * ACL support routines specific to POSIX.1e access control lists.  These are
   34  * utility routines for code common across file systems implementing POSIX.1e
   35  * ACLs.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 #if 0
   40 __FBSDID("$FreeBSD: head/sys/kern/subr_acl_posix1e.c 341827 2018-12-11 19:32:16Z mjg $");
   41 #endif
   42 __KERNEL_RCSID(0, "$NetBSD: subr_acl_posix1e.c,v 1.1 2020/05/16 18:31:50 christos Exp $");
   43 
   44 #include <sys/param.h>
   45 #include <sys/kernel.h>
   46 #include <sys/module.h>
   47 #include <sys/systm.h>
   48 #include <sys/mount.h>
   49 #include <sys/vnode.h>
   50 #include <sys/kauth.h>
   51 #include <sys/errno.h>
   52 #include <sys/stat.h>
   53 #include <sys/acl.h>
   54 
   55 /*
   56  * For the purposes of filesystems maintaining the _OBJ entries in an inode
   57  * with a mode_t field, this routine converts a mode_t entry to an
   58  * acl_perm_t.
   59  */
   60 acl_perm_t
   61 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
   62 {
   63         acl_perm_t      perm = 0;
   64 
   65         switch(tag) {
   66         case ACL_USER_OBJ:
   67                 if (mode & S_IXUSR)
   68                         perm |= ACL_EXECUTE;
   69                 if (mode & S_IRUSR)
   70                         perm |= ACL_READ;
   71                 if (mode & S_IWUSR)
   72                         perm |= ACL_WRITE;
   73                 return (perm);
   74 
   75         case ACL_GROUP_OBJ:
   76                 if (mode & S_IXGRP)
   77                         perm |= ACL_EXECUTE;
   78                 if (mode & S_IRGRP)
   79                         perm |= ACL_READ;
   80                 if (mode & S_IWGRP)
   81                         perm |= ACL_WRITE;
   82                 return (perm);
   83 
   84         case ACL_OTHER:
   85                 if (mode & S_IXOTH)
   86                         perm |= ACL_EXECUTE;
   87                 if (mode & S_IROTH)
   88                         perm |= ACL_READ;
   89                 if (mode & S_IWOTH)
   90                         perm |= ACL_WRITE;
   91                 return (perm);
   92 
   93         default:
   94                 printf("%s: invalid tag (%u)\n", __func__, tag);
   95                 return (0);
   96         }
   97 }
   98 
   99 /*
  100  * Given inode information (uid, gid, mode), return an acl entry of the
  101  * appropriate type.
  102  */
  103 struct acl_entry
  104 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
  105 {
  106         struct acl_entry        acl_entry;
  107 
  108         acl_entry.ae_tag = tag;
  109         acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
  110         acl_entry.ae_entry_type = 0;
  111         acl_entry.ae_flags = 0;
  112         switch(tag) {
  113         case ACL_USER_OBJ:
  114                 acl_entry.ae_id = uid;
  115                 break;
  116 
  117         case ACL_GROUP_OBJ:
  118                 acl_entry.ae_id = gid;
  119                 break;
  120 
  121         case ACL_OTHER:
  122                 acl_entry.ae_id = ACL_UNDEFINED_ID;
  123                 break;
  124 
  125         default:
  126                 acl_entry.ae_id = ACL_UNDEFINED_ID;
  127                 printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
  128         }
  129 
  130         return (acl_entry);
  131 }
  132 
  133 /*
  134  * Utility function to generate a file mode given appropriate ACL entries.
  135  */
  136 mode_t
  137 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
  138     struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
  139 {
  140         mode_t  mode;
  141 
  142         mode = 0;
  143         if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
  144                 mode |= S_IXUSR;
  145         if (acl_user_obj_entry->ae_perm & ACL_READ)
  146                 mode |= S_IRUSR;
  147         if (acl_user_obj_entry->ae_perm & ACL_WRITE)
  148                 mode |= S_IWUSR;
  149         if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
  150                 mode |= S_IXGRP;
  151         if (acl_group_obj_entry->ae_perm & ACL_READ)
  152                 mode |= S_IRGRP;
  153         if (acl_group_obj_entry->ae_perm & ACL_WRITE)
  154                 mode |= S_IWGRP;
  155         if (acl_other_entry->ae_perm & ACL_EXECUTE)
  156                 mode |= S_IXOTH;
  157         if (acl_other_entry->ae_perm & ACL_READ)
  158                 mode |= S_IROTH;
  159         if (acl_other_entry->ae_perm & ACL_WRITE)
  160                 mode |= S_IWOTH;
  161 
  162         return (mode);
  163 }
  164 
  165 /*
  166  * Utility function to generate a file mode given a complete POSIX.1e access
  167  * ACL.  Note that if the ACL is improperly formed, this may result in a
  168  * panic.
  169  */
  170 mode_t
  171 acl_posix1e_acl_to_mode(struct acl *acl)
  172 {
  173         struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
  174         int i;
  175 
  176         /*
  177          * Find the ACL entries relevant to a POSIX permission mode.
  178          */
  179         acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
  180         for (i = 0; i < acl->acl_cnt; i++) {
  181                 switch (acl->acl_entry[i].ae_tag) {
  182                 case ACL_USER_OBJ:
  183                         acl_user_obj = &acl->acl_entry[i];
  184                         break;
  185 
  186                 case ACL_GROUP_OBJ:
  187                         acl_group_obj = &acl->acl_entry[i];
  188                         break;
  189 
  190                 case ACL_OTHER:
  191                         acl_other = &acl->acl_entry[i];
  192                         break;
  193 
  194                 case ACL_MASK:
  195                         acl_mask = &acl->acl_entry[i];
  196                         break;
  197 
  198                 case ACL_USER:
  199                 case ACL_GROUP:
  200                         break;
  201 
  202                 default:
  203                         panic("acl_posix1e_acl_to_mode: bad ae_tag");
  204                 }
  205         }
  206 
  207         if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
  208                 panic("acl_posix1e_acl_to_mode: missing base ae_tags");
  209 
  210         /*
  211          * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
  212          * the mode "group" bits with its permissions.  If there isn't, we
  213          * use the ACL_GROUP_OBJ permissions.
  214          */
  215         if (acl_mask != NULL)
  216                 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
  217                     acl_other));
  218         else
  219                 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
  220                     acl_other));
  221 }
  222 
  223 /*
  224  * Perform a syntactic check of the ACL, sufficient to allow an implementing
  225  * filesystem to determine if it should accept this and rely on the POSIX.1e
  226  * ACL properties.
  227  */
  228 int
  229 acl_posix1e_check(struct acl *acl)
  230 {
  231         int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
  232         int num_acl_mask, num_acl_other, i;
  233 
  234         /*
  235          * Verify that the number of entries does not exceed the maximum
  236          * defined for acl_t.
  237          *
  238          * Verify that the correct number of various sorts of ae_tags are
  239          * present:
  240          *   Exactly one ACL_USER_OBJ
  241          *   Exactly one ACL_GROUP_OBJ
  242          *   Exactly one ACL_OTHER
  243          *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
  244          *   ACL_MASK entry must also appear.
  245          *
  246          * Verify that all ae_perm entries are in ACL_PERM_BITS.
  247          *
  248          * Verify all ae_tag entries are understood by this implementation.
  249          *
  250          * Note: Does not check for uniqueness of qualifier (ae_id) field.
  251          */
  252         num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
  253             num_acl_mask = num_acl_other = 0;
  254         if (acl->acl_cnt > ACL_MAX_ENTRIES)
  255                 return (EINVAL);
  256         for (i = 0; i < acl->acl_cnt; i++) {
  257                 struct acl_entry *ae = &acl->acl_entry[i];
  258                 /*
  259                  * Check for a valid tag.
  260                  */
  261                 switch(ae->ae_tag) {
  262                 case ACL_USER_OBJ:
  263                         ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
  264                         if (ae->ae_id != ACL_UNDEFINED_ID)
  265                                 return (EINVAL);
  266                         num_acl_user_obj++;
  267                         break;
  268                 case ACL_GROUP_OBJ:
  269                         ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
  270                         if (ae->ae_id != ACL_UNDEFINED_ID)
  271                                 return (EINVAL);
  272                         num_acl_group_obj++;
  273                         break;
  274                 case ACL_USER:
  275                         if (ae->ae_id == ACL_UNDEFINED_ID)
  276                                 return (EINVAL);
  277                         num_acl_user++;
  278                         break;
  279                 case ACL_GROUP:
  280                         if (ae->ae_id == ACL_UNDEFINED_ID)
  281                                 return (EINVAL);
  282                         num_acl_group++;
  283                         break;
  284                 case ACL_OTHER:
  285                         ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
  286                         if (ae->ae_id != ACL_UNDEFINED_ID)
  287                                 return (EINVAL);
  288                         num_acl_other++;
  289                         break;
  290                 case ACL_MASK:
  291                         ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
  292                         if (ae->ae_id != ACL_UNDEFINED_ID)
  293                                 return (EINVAL);
  294                         num_acl_mask++;
  295                         break;
  296                 default:
  297                         return (EINVAL);
  298                 }
  299                 /*
  300                  * Check for valid perm entries.
  301                  */
  302                 if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
  303                     ACL_PERM_BITS)
  304                         return (EINVAL);
  305         }
  306         if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
  307             (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
  308                 return (EINVAL);
  309         if (((num_acl_group != 0) || (num_acl_user != 0)) &&
  310             (num_acl_mask != 1))
  311                 return (EINVAL);
  312         return (0);
  313 }
  314 
  315 /*
  316  * Given a requested mode for a new object, and a default ACL, combine the
  317  * two to produce a new mode.  Be careful not to clear any bits that aren't
  318  * intended to be affected by the POSIX.1e ACL.  Eventually, this might also
  319  * take the cmask as an argument, if we push that down into
  320  * per-filesystem-code.
  321  */
  322 mode_t
  323 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
  324 {
  325         mode_t mode;
  326 
  327         mode = cmode;
  328         /*
  329          * The current composition policy is that a permission bit must be
  330          * set in *both* the ACL and the requested creation mode for it to
  331          * appear in the resulting mode/ACL.  First clear any possibly
  332          * effected bits, then reconstruct.
  333          */
  334         mode &= ACL_PRESERVE_MASK;
  335         mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
  336 
  337         return (mode);
  338 }

Cache object: 0f0f8c4a55ff7cb94d881e7c851d91d0


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