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/ufs/ufs/ufs_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-2001, 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 /*
   30  * Support for POSIX.1e access control lists: UFS-specific support functions.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD: releng/5.2/sys/ufs/ufs/ufs_acl.c 118411 2003-08-04 03:29:13Z rwatson $");
   35 
   36 #include "opt_ufs.h"
   37 #include "opt_quota.h"
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/stat.h>
   42 #include <sys/mount.h>
   43 #include <sys/vnode.h>
   44 #include <sys/types.h>
   45 #include <sys/acl.h>
   46 #include <sys/event.h>
   47 #include <sys/extattr.h>
   48 
   49 #include <ufs/ufs/quota.h>
   50 #include <ufs/ufs/inode.h>
   51 #include <ufs/ufs/acl.h>
   52 #include <ufs/ufs/extattr.h>
   53 #include <ufs/ufs/dir.h>
   54 #include <ufs/ufs/ufsmount.h>
   55 #include <ufs/ufs/ufs_extern.h>
   56 
   57 #ifdef UFS_ACL
   58 
   59 /*
   60  * Synchronize an ACL and an inode by copying over appropriate inode fields
   61  * to the passed ACL.  Assumes an ACL that would satisfy acl_posix1e_check(),
   62  * and may panic if not.
   63  */
   64 void
   65 ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl)
   66 {
   67         struct acl_entry        *acl_mask, *acl_group_obj;
   68         int     i;
   69 
   70         /*
   71          * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK
   72          * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is
   73          * present.
   74          */
   75         acl_mask = NULL;
   76         acl_group_obj = NULL;
   77         for (i = 0; i < acl->acl_cnt; i++) {
   78                 switch (acl->acl_entry[i].ae_tag) {
   79                 case ACL_USER_OBJ:
   80                         acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
   81                             ACL_USER_OBJ, ip->i_mode);
   82                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
   83                         break;
   84         
   85                 case ACL_GROUP_OBJ:
   86                         acl_group_obj = &acl->acl_entry[i];
   87                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
   88                         break;
   89 
   90                 case ACL_OTHER:
   91                         acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
   92                             ACL_OTHER, ip->i_mode);
   93                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
   94                         break;
   95 
   96                 case ACL_MASK:
   97                         acl_mask = &acl->acl_entry[i];
   98                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
   99                         break;
  100 
  101                 case ACL_USER:
  102                 case ACL_GROUP:
  103                         break;
  104         
  105                 default:
  106                         panic("ufs_sync_acl_from_inode(): bad ae_tag");
  107                 }
  108         }
  109 
  110         if (acl_group_obj == NULL)
  111                 panic("ufs_sync_acl_from_inode(): no ACL_GROUP_OBJ");
  112 
  113         if (acl_mask == NULL) {
  114                 /*
  115                  * There is no ACL_MASK, so update ACL_GROUP_OBJ.
  116                  */
  117                 acl_group_obj->ae_perm = acl_posix1e_mode_to_perm(
  118                     ACL_GROUP_OBJ, ip->i_mode);
  119         } else {
  120                 /*
  121                  * Update the ACL_MASK entry instead of ACL_GROUP_OBJ.
  122                  */
  123                 acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ,
  124                     ip->i_mode);
  125         }
  126 }
  127 
  128 /*
  129  * Calculate what the inode mode should look like based on an authoritative
  130  * ACL for the inode.  Replace only the fields in the inode that the ACL
  131  * can represent.
  132  */
  133 void
  134 ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip)
  135 {
  136 
  137         ip->i_mode &= ACL_PRESERVE_MASK;
  138         ip->i_mode |= acl_posix1e_acl_to_mode(acl);
  139         DIP(ip, i_mode) = ip->i_mode;
  140 }
  141 
  142 /*
  143  * Retrieve the ACL on a file.
  144  *
  145  * As part of the ACL is stored in the inode, and the rest in an EA,
  146  * assemble both into a final ACL product.  Right now this is not done
  147  * very efficiently.
  148  */
  149 int
  150 ufs_getacl(ap)
  151         struct vop_getacl_args /* {
  152                 struct vnode *vp;
  153                 struct acl_type_t type;
  154                 struct acl *aclp;
  155                 struct ucred *cred;
  156                 struct thread *td;
  157         } */ *ap;
  158 {
  159         struct inode *ip = VTOI(ap->a_vp);
  160         int error, len;
  161 
  162         /*
  163          * XXX: If ufs_getacl() should work on file systems not supporting
  164          * ACLs, remove this check.
  165          */
  166         if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
  167                 return (EOPNOTSUPP);
  168 
  169         /*
  170          * Attempt to retrieve the ACL based on the ACL type.
  171          */
  172         bzero(ap->a_aclp, sizeof(*ap->a_aclp));
  173         len = sizeof(*ap->a_aclp);
  174         switch(ap->a_type) {
  175         case ACL_TYPE_ACCESS:
  176                 /*
  177                  * ACL_TYPE_ACCESS ACLs may or may not be stored in the
  178                  * EA, as they are in fact a combination of the inode
  179                  * ownership/permissions and the EA contents.  If the
  180                  * EA is present, merge the two in a temporary ACL
  181                  * storage, otherwise just return the inode contents.
  182                  */
  183                 error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
  184                     POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
  185                     POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) ap->a_aclp,
  186                     ap->a_td);
  187                 switch (error) {
  188                 /* XXX: If ufs_getacl() should work on filesystems without
  189                  * the EA configured, add case EOPNOTSUPP here. */
  190                 case ENOATTR:
  191                         /*
  192                          * Legitimately no ACL set on object, purely
  193                          * emulate it through the inode.  These fields will
  194                          * be updated when the ACL is synchronized with
  195                          * the inode later.
  196                          */
  197                         ap->a_aclp->acl_cnt = 3;
  198                         ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ;
  199                         ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
  200                         ap->a_aclp->acl_entry[0].ae_perm = ACL_PERM_NONE;
  201                         ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
  202                         ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
  203                         ap->a_aclp->acl_entry[1].ae_perm = ACL_PERM_NONE;
  204                         ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER;
  205                         ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
  206                         ap->a_aclp->acl_entry[2].ae_perm = ACL_PERM_NONE;
  207                         ufs_sync_acl_from_inode(ip, ap->a_aclp);
  208                         error = 0;
  209                         break;
  210 
  211                 case 0:
  212                         if (len != sizeof(*ap->a_aclp)) {
  213                                 /*
  214                                  * A short (or long) read, meaning that for
  215                                  * some reason the ACL is corrupted.  Return
  216                                  * EPERM since the object DAC protections
  217                                  * are unsafe.
  218                                  */
  219                                 printf("ufs_getacl(): Loaded invalid ACL ("
  220                                     "%d bytes)\n", len);
  221                                 return (EPERM);
  222                         }
  223                         ufs_sync_acl_from_inode(ip, ap->a_aclp);
  224                         break;
  225 
  226                 default:
  227                         break;
  228                 }
  229                 break;
  230 
  231         case ACL_TYPE_DEFAULT:
  232                 if (ap->a_vp->v_type != VDIR) {
  233                         error = EINVAL;
  234                         break;
  235                 }
  236                 error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
  237                     POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
  238                     POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len,
  239                     (char *) ap->a_aclp, ap->a_td);
  240                 /*
  241                  * Unlike ACL_TYPE_ACCESS, there is no relationship between
  242                  * the inode contents and the ACL, and it is therefore
  243                  * possible for the request for the ACL to fail since the
  244                  * ACL is undefined.  In this situation, return success
  245                  * and an empty ACL, as required by POSIX.1e.
  246                  */
  247                 switch (error) {
  248                 /* XXX: If ufs_getacl() should work on filesystems without
  249                  * the EA configured, add case EOPNOTSUPP here. */
  250                 case ENOATTR:
  251                         bzero(ap->a_aclp, sizeof(*ap->a_aclp));
  252                         ap->a_aclp->acl_cnt = 0;
  253                         error = 0;
  254                         break;
  255 
  256                 case 0:
  257                         if (len != sizeof(*ap->a_aclp)) {
  258                                 /*
  259                                  * A short (or long) read, meaning that for
  260                                  * some reason the ACL is corrupted.  Return
  261                                  * EPERM since the object default DAC
  262                                  * protections are unsafe.
  263                                  */
  264                                 printf("ufs_getacl(): Loaded invalid ACL ("
  265                                     "%d bytes)\n", len);
  266                                 return (EPERM);
  267                         }
  268                         break;
  269 
  270                 default:
  271                         break;
  272                 }
  273                 break;
  274 
  275         default:
  276                 error = EINVAL;
  277         }
  278 
  279         return (error);
  280 }
  281 
  282 /*
  283  * Set the ACL on a file.
  284  *
  285  * As part of the ACL is stored in the inode, and the rest in an EA,
  286  * this is necessarily non-atomic, and has complex authorization.
  287  * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(),
  288  * a fair number of different access checks may be required to go ahead
  289  * with the operation at all.
  290  */
  291 int
  292 ufs_setacl(ap)
  293         struct vop_setacl_args /* {
  294                 struct vnode *vp;
  295                 acl_type_t type;
  296                 struct acl *aclp;
  297                 struct ucred *cred;
  298                 struct proc *p;
  299         } */ *ap;
  300 {
  301         struct inode *ip = VTOI(ap->a_vp);
  302         int error;
  303 
  304         if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
  305                 return (EOPNOTSUPP);
  306 
  307         /*
  308          * If this is a set operation rather than a delete operation,
  309          * invoke VOP_ACLCHECK() on the passed ACL to determine if it is
  310          * valid for the target.  This will include a check on ap->a_type.
  311          */
  312         if (ap->a_aclp != NULL) {
  313                 /*
  314                  * Set operation.
  315                  */
  316                 error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp,
  317                     ap->a_cred, ap->a_td);
  318                 if (error != 0)
  319                         return (error);
  320         } else {
  321                 /*
  322                  * Delete operation.
  323                  * POSIX.1e allows only deletion of the default ACL on a
  324                  * directory (ACL_TYPE_DEFAULT).
  325                  */
  326                 if (ap->a_type != ACL_TYPE_DEFAULT)
  327                         return (EINVAL);
  328                 if (ap->a_vp->v_type != VDIR)
  329                         return (ENOTDIR);
  330         }
  331 
  332         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
  333                 return (EROFS);
  334 
  335         /*
  336          * Authorize the ACL operation.
  337          */
  338         if (ip->i_flags & (IMMUTABLE | APPEND))
  339                 return (EPERM);
  340 
  341         /*
  342          * Must hold VADMIN (be file owner) or have appropriate privilege.
  343          */
  344         if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td)))
  345                 return (error);
  346 
  347         switch(ap->a_type) {
  348         case ACL_TYPE_ACCESS:
  349                 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
  350                     POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
  351                     POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*ap->a_aclp),
  352                     (char *) ap->a_aclp, ap->a_td);
  353                 break;
  354 
  355         case ACL_TYPE_DEFAULT:
  356                 if (ap->a_aclp == NULL) {
  357                         error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED,
  358                             POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
  359                             POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td);
  360                         /*
  361                          * Attempting to delete a non-present default ACL
  362                          * will return success for portability purposes.
  363                          * (TRIX)
  364                          *
  365                          * XXX: Note that since we can't distinguish
  366                          * "that EA is not supported" from "that EA is not
  367                          * defined", the success case here overlaps the
  368                          * the ENOATTR->EOPNOTSUPP case below.
  369                          */
  370                         if (error == ENOATTR)
  371                                 error = 0;
  372                 } else
  373                         error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
  374                             POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
  375                             POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
  376                             sizeof(*ap->a_aclp), (char *) ap->a_aclp, ap->a_td);
  377                 break;
  378 
  379         default:
  380                 error = EINVAL;
  381         }
  382         /*
  383          * Map lack of attribute definition in UFS_EXTATTR into lack of
  384          * support for ACLs on the filesystem.
  385          */
  386         if (error == ENOATTR)
  387                 return (EOPNOTSUPP);
  388         if (error != 0)
  389                 return (error);
  390 
  391         if (ap->a_type == ACL_TYPE_ACCESS) {
  392                 /*
  393                  * Now that the EA is successfully updated, update the
  394                  * inode and mark it as changed.
  395                  */
  396                 ufs_sync_inode_from_acl(ap->a_aclp, ip);
  397                 ip->i_flag |= IN_CHANGE;
  398         }
  399 
  400         VN_KNOTE(ap->a_vp, NOTE_ATTRIB);
  401         return (0);
  402 }
  403 
  404 /*
  405  * Check the validity of an ACL for a file.
  406  */
  407 int
  408 ufs_aclcheck(ap)
  409         struct vop_aclcheck_args /* {
  410                 struct vnode *vp;
  411                 acl_type_t type;
  412                 struct acl *aclp;
  413                 struct ucred *cred;
  414                 struct thread *td;
  415         } */ *ap;
  416 {
  417 
  418         if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
  419                 return (EOPNOTSUPP);
  420 
  421         /*
  422          * Verify we understand this type of ACL, and that it applies
  423          * to this kind of object.
  424          * Rely on the acl_posix1e_check() routine to verify the contents.
  425          */
  426         switch(ap->a_type) {
  427         case ACL_TYPE_ACCESS:
  428                 break;
  429 
  430         case ACL_TYPE_DEFAULT:
  431                 if (ap->a_vp->v_type != VDIR)
  432                         return (EINVAL);
  433                 break;
  434 
  435         default:
  436                 return (EINVAL);
  437         }
  438         return (acl_posix1e_check(ap->a_aclp));
  439 }
  440 
  441 #endif /* !UFS_ACL */

Cache object: f6ff2f256c2d614a573f14a096d0c14d


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