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/vfs_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-2006 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  *
   31  * ACL system calls and other functions common across different ACL types.
   32  * Type-specific routines go into subr_acl_<type>.c.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/8.0/sys/kern/vfs_acl.c 198984 2009-11-06 11:29:10Z trasz $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/sysproto.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/kernel.h>
   43 #include <sys/malloc.h>
   44 #include <sys/mount.h>
   45 #include <sys/vnode.h>
   46 #include <sys/lock.h>
   47 #include <sys/mutex.h>
   48 #include <sys/namei.h>
   49 #include <sys/file.h>
   50 #include <sys/filedesc.h>
   51 #include <sys/proc.h>
   52 #include <sys/sysent.h>
   53 #include <sys/acl.h>
   54 
   55 #include <security/mac/mac_framework.h>
   56 
   57 CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
   58 
   59 MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
   60 
   61 static int      vacl_set_acl(struct thread *td, struct vnode *vp,
   62                     acl_type_t type, struct acl *aclp);
   63 static int      vacl_get_acl(struct thread *td, struct vnode *vp,
   64                     acl_type_t type, struct acl *aclp);
   65 static int      vacl_aclcheck(struct thread *td, struct vnode *vp,
   66                     acl_type_t type, struct acl *aclp);
   67 
   68 int
   69 acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
   70 {
   71         int i;
   72 
   73         if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
   74                 return (EINVAL);
   75         
   76         bzero(dest, sizeof(*dest));
   77 
   78         dest->acl_cnt = source->acl_cnt;
   79         dest->acl_maxcnt = ACL_MAX_ENTRIES;
   80 
   81         for (i = 0; i < dest->acl_cnt; i++) {
   82                 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
   83                 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
   84                 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
   85         }
   86 
   87         return (0);
   88 }
   89 
   90 int
   91 acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
   92 {
   93         int i;
   94 
   95         if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
   96                 return (EINVAL);
   97 
   98         bzero(dest, sizeof(*dest));
   99 
  100         dest->acl_cnt = source->acl_cnt;
  101 
  102         for (i = 0; i < dest->acl_cnt; i++) {
  103                 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
  104                 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
  105                 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
  106         }
  107 
  108         return (0);
  109 }
  110 
  111 /*
  112  * At one time, "struct ACL" was extended in order to add support for NFSv4
  113  * ACLs.  Instead of creating compatibility versions of all the ACL-related
  114  * syscalls, they were left intact.  It's possible to find out what the code
  115  * calling these syscalls (libc) expects basing on "type" argument - if it's
  116  * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
  117  * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
  118  * oldacl".  If it's something else, then it's the new "struct acl".  In the
  119  * latter case, the routines below just copyin/copyout the contents.  In the
  120  * former case, they copyin the "struct oldacl" and convert it to the new
  121  * format.
  122  */
  123 static int
  124 acl_copyin(void *user_acl, struct acl *kernel_acl, acl_type_t type)
  125 {
  126         int error;
  127         struct oldacl old;
  128 
  129         switch (type) {
  130         case ACL_TYPE_ACCESS_OLD:
  131         case ACL_TYPE_DEFAULT_OLD:
  132                 error = copyin(user_acl, &old, sizeof(old));
  133                 if (error != 0)
  134                         break;
  135                 acl_copy_oldacl_into_acl(&old, kernel_acl);
  136                 break;
  137 
  138         default:
  139                 error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
  140                 if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
  141                         return (EINVAL);
  142         }
  143 
  144         return (error);
  145 }
  146 
  147 static int
  148 acl_copyout(struct acl *kernel_acl, void *user_acl, acl_type_t type)
  149 {
  150         int error;
  151         struct oldacl old;
  152 
  153         switch (type) {
  154         case ACL_TYPE_ACCESS_OLD:
  155         case ACL_TYPE_DEFAULT_OLD:
  156                 error = acl_copy_acl_into_oldacl(kernel_acl, &old);
  157                 if (error != 0)
  158                         break;
  159 
  160                 error = copyout(&old, user_acl, sizeof(old));
  161                 break;
  162 
  163         default:
  164                 if (fuword32((char *)user_acl +
  165                     offsetof(struct acl, acl_maxcnt)) != ACL_MAX_ENTRIES)
  166                         return (EINVAL);
  167 
  168                 error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
  169         }
  170 
  171         return (error);
  172 }
  173 
  174 /*
  175  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
  176  * counterpart.  It's required for old (pre-NFS4 ACLs) libc to work
  177  * with new kernel.  Fixing 'type' for old binaries with new libc
  178  * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
  179  */
  180 static int
  181 acl_type_unold(int type)
  182 {
  183         switch (type) {
  184         case ACL_TYPE_ACCESS_OLD:
  185                 return (ACL_TYPE_ACCESS);
  186 
  187         case ACL_TYPE_DEFAULT_OLD:
  188                 return (ACL_TYPE_DEFAULT);
  189 
  190         default:
  191                 return (type);
  192         }
  193 }
  194 
  195 /*
  196  * These calls wrap the real vnode operations, and are called by the syscall
  197  * code once the syscall has converted the path or file descriptor to a vnode
  198  * (unlocked).  The aclp pointer is assumed still to point to userland, so
  199  * this should not be consumed within the kernel except by syscall code.
  200  * Other code should directly invoke VOP_{SET,GET}ACL.
  201  */
  202 
  203 /*
  204  * Given a vnode, set its ACL.
  205  */
  206 static int
  207 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
  208     struct acl *aclp)
  209 {
  210         struct acl *inkernelacl;
  211         struct mount *mp;
  212         int error;
  213 
  214         inkernelacl = acl_alloc(M_WAITOK);
  215         error = acl_copyin(aclp, inkernelacl, type);
  216         if (error)
  217                 goto out;
  218         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
  219         if (error != 0)
  220                 goto out;
  221         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  222 #ifdef MAC
  223         error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl);
  224         if (error != 0)
  225                 goto out_unlock;
  226 #endif
  227         error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
  228             td->td_ucred, td);
  229 #ifdef MAC
  230 out_unlock:
  231 #endif
  232         VOP_UNLOCK(vp, 0);
  233         vn_finished_write(mp);
  234 out:
  235         acl_free(inkernelacl);
  236         return(error);
  237 }
  238 
  239 /*
  240  * Given a vnode, get its ACL.
  241  */
  242 static int
  243 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
  244     struct acl *aclp)
  245 {
  246         struct acl *inkernelacl;
  247         int error;
  248 
  249         inkernelacl = acl_alloc(M_WAITOK);
  250         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  251 #ifdef MAC
  252         error = mac_vnode_check_getacl(td->td_ucred, vp, type);
  253         if (error != 0)
  254                 goto out;
  255 #endif
  256         error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
  257             td->td_ucred, td);
  258 
  259 #ifdef MAC
  260 out:
  261 #endif
  262         VOP_UNLOCK(vp, 0);
  263         if (error == 0)
  264                 error = acl_copyout(inkernelacl, aclp, type);
  265         acl_free(inkernelacl);
  266         return (error);
  267 }
  268 
  269 /*
  270  * Given a vnode, delete its ACL.
  271  */
  272 static int
  273 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
  274 {
  275         struct mount *mp;
  276         int error;
  277 
  278         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
  279         if (error)
  280                 return (error);
  281         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  282 #ifdef MAC
  283         error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
  284         if (error)
  285                 goto out;
  286 #endif
  287         error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
  288 #ifdef MAC
  289 out:
  290 #endif
  291         VOP_UNLOCK(vp, 0);
  292         vn_finished_write(mp);
  293         return (error);
  294 }
  295 
  296 /*
  297  * Given a vnode, check whether an ACL is appropriate for it
  298  */
  299 static int
  300 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
  301     struct acl *aclp)
  302 {
  303         struct acl *inkernelacl;
  304         int error;
  305 
  306         inkernelacl = acl_alloc(M_WAITOK);
  307         error = acl_copyin(aclp, inkernelacl, type);
  308         if (error)
  309                 goto out;
  310         error = VOP_ACLCHECK(vp, type, inkernelacl, td->td_ucred, td);
  311 out:
  312         acl_free(inkernelacl);
  313         return (error);
  314 }
  315 
  316 /*
  317  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
  318  * need to lock, as the vacl_ code will get/release any locks required.
  319  */
  320 
  321 /*
  322  * Given a file path, get an ACL for it
  323  */
  324 int
  325 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
  326 {
  327         struct nameidata nd;
  328         int vfslocked, error;
  329 
  330         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  331         error = namei(&nd);
  332         vfslocked = NDHASGIANT(&nd);
  333         if (error == 0) {
  334                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  335                 NDFREE(&nd, 0);
  336         }
  337         VFS_UNLOCK_GIANT(vfslocked);
  338         return (error);
  339 }
  340 
  341 /*
  342  * Given a file path, get an ACL for it; don't follow links.
  343  */
  344 int
  345 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
  346 {
  347         struct nameidata nd;
  348         int vfslocked, error;
  349 
  350         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  351         error = namei(&nd);
  352         vfslocked = NDHASGIANT(&nd);
  353         if (error == 0) {
  354                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  355                 NDFREE(&nd, 0);
  356         }
  357         VFS_UNLOCK_GIANT(vfslocked);
  358         return (error);
  359 }
  360 
  361 /*
  362  * Given a file path, set an ACL for it.
  363  */
  364 int
  365 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
  366 {
  367         struct nameidata nd;
  368         int vfslocked, error;
  369 
  370         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  371         error = namei(&nd);
  372         vfslocked = NDHASGIANT(&nd);
  373         if (error == 0) {
  374                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  375                 NDFREE(&nd, 0);
  376         }
  377         VFS_UNLOCK_GIANT(vfslocked);
  378         return (error);
  379 }
  380 
  381 /*
  382  * Given a file path, set an ACL for it; don't follow links.
  383  */
  384 int
  385 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
  386 {
  387         struct nameidata nd;
  388         int vfslocked, error;
  389 
  390         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  391         error = namei(&nd);
  392         vfslocked = NDHASGIANT(&nd);
  393         if (error == 0) {
  394                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  395                 NDFREE(&nd, 0);
  396         }
  397         VFS_UNLOCK_GIANT(vfslocked);
  398         return (error);
  399 }
  400 
  401 /*
  402  * Given a file descriptor, get an ACL for it.
  403  */
  404 int
  405 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
  406 {
  407         struct file *fp;
  408         int vfslocked, error;
  409 
  410         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  411         if (error == 0) {
  412                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  413                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
  414                 fdrop(fp, td);
  415                 VFS_UNLOCK_GIANT(vfslocked);
  416         }
  417         return (error);
  418 }
  419 
  420 /*
  421  * Given a file descriptor, set an ACL for it.
  422  */
  423 int
  424 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
  425 {
  426         struct file *fp;
  427         int vfslocked, error;
  428 
  429         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  430         if (error == 0) {
  431                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  432                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
  433                 fdrop(fp, td);
  434                 VFS_UNLOCK_GIANT(vfslocked);
  435         }
  436         return (error);
  437 }
  438 
  439 /*
  440  * Given a file path, delete an ACL from it.
  441  */
  442 int
  443 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
  444 {
  445         struct nameidata nd;
  446         int vfslocked, error;
  447 
  448         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  449         error = namei(&nd);
  450         vfslocked = NDHASGIANT(&nd);
  451         if (error == 0) {
  452                 error = vacl_delete(td, nd.ni_vp, uap->type);
  453                 NDFREE(&nd, 0);
  454         }
  455         VFS_UNLOCK_GIANT(vfslocked);
  456         return (error);
  457 }
  458 
  459 /*
  460  * Given a file path, delete an ACL from it; don't follow links.
  461  */
  462 int
  463 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
  464 {
  465         struct nameidata nd;
  466         int vfslocked, error;
  467 
  468         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  469         error = namei(&nd);
  470         vfslocked = NDHASGIANT(&nd);
  471         if (error == 0) {
  472                 error = vacl_delete(td, nd.ni_vp, uap->type);
  473                 NDFREE(&nd, 0);
  474         }
  475         VFS_UNLOCK_GIANT(vfslocked);
  476         return (error);
  477 }
  478 
  479 /*
  480  * Given a file path, delete an ACL from it.
  481  */
  482 int
  483 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
  484 {
  485         struct file *fp;
  486         int vfslocked, error;
  487 
  488         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  489         if (error == 0) {
  490                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  491                 error = vacl_delete(td, fp->f_vnode, uap->type);
  492                 fdrop(fp, td);
  493                 VFS_UNLOCK_GIANT(vfslocked);
  494         }
  495         return (error);
  496 }
  497 
  498 /*
  499  * Given a file path, check an ACL for it.
  500  */
  501 int
  502 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
  503 {
  504         struct nameidata        nd;
  505         int vfslocked, error;
  506 
  507         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  508         error = namei(&nd);
  509         vfslocked = NDHASGIANT(&nd);
  510         if (error == 0) {
  511                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  512                 NDFREE(&nd, 0);
  513         }
  514         VFS_UNLOCK_GIANT(vfslocked);
  515         return (error);
  516 }
  517 
  518 /*
  519  * Given a file path, check an ACL for it; don't follow links.
  520  */
  521 int
  522 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
  523 {
  524         struct nameidata        nd;
  525         int vfslocked, error;
  526 
  527         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  528         error = namei(&nd);
  529         vfslocked = NDHASGIANT(&nd);
  530         if (error == 0) {
  531                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  532                 NDFREE(&nd, 0);
  533         }
  534         VFS_UNLOCK_GIANT(vfslocked);
  535         return (error);
  536 }
  537 
  538 /*
  539  * Given a file descriptor, check an ACL for it.
  540  */
  541 int
  542 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
  543 {
  544         struct file *fp;
  545         int vfslocked, error;
  546 
  547         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  548         if (error == 0) {
  549                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  550                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
  551                 fdrop(fp, td);
  552                 VFS_UNLOCK_GIANT(vfslocked);
  553         }
  554         return (error);
  555 }
  556 
  557 struct acl *
  558 acl_alloc(int flags)
  559 {
  560         struct acl *aclp;
  561 
  562         aclp = malloc(sizeof(*aclp), M_ACL, flags);
  563         aclp->acl_maxcnt = ACL_MAX_ENTRIES;
  564 
  565         return (aclp);
  566 }
  567 
  568 void
  569 acl_free(struct acl *aclp)
  570 {
  571 
  572         free(aclp, M_ACL);
  573 }

Cache object: 17c352770440234c9deaddc480483333


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