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.4/sys/kern/vfs_acl.c 246758 2013-02-13 10:18:26Z pluknet $");
   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-NFSv4 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 | M_ZERO);
  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, acl_type_unold(type), inkernelacl,
  311             td->td_ucred, td);
  312 out:
  313         acl_free(inkernelacl);
  314         return (error);
  315 }
  316 
  317 /*
  318  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
  319  * need to lock, as the vacl_ code will get/release any locks required.
  320  */
  321 
  322 /*
  323  * Given a file path, get an ACL for it
  324  */
  325 int
  326 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
  327 {
  328         struct nameidata nd;
  329         int vfslocked, error;
  330 
  331         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  332         error = namei(&nd);
  333         vfslocked = NDHASGIANT(&nd);
  334         if (error == 0) {
  335                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  336                 NDFREE(&nd, 0);
  337         }
  338         VFS_UNLOCK_GIANT(vfslocked);
  339         return (error);
  340 }
  341 
  342 /*
  343  * Given a file path, get an ACL for it; don't follow links.
  344  */
  345 int
  346 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
  347 {
  348         struct nameidata nd;
  349         int vfslocked, error;
  350 
  351         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  352         error = namei(&nd);
  353         vfslocked = NDHASGIANT(&nd);
  354         if (error == 0) {
  355                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  356                 NDFREE(&nd, 0);
  357         }
  358         VFS_UNLOCK_GIANT(vfslocked);
  359         return (error);
  360 }
  361 
  362 /*
  363  * Given a file path, set an ACL for it.
  364  */
  365 int
  366 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
  367 {
  368         struct nameidata nd;
  369         int vfslocked, error;
  370 
  371         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  372         error = namei(&nd);
  373         vfslocked = NDHASGIANT(&nd);
  374         if (error == 0) {
  375                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  376                 NDFREE(&nd, 0);
  377         }
  378         VFS_UNLOCK_GIANT(vfslocked);
  379         return (error);
  380 }
  381 
  382 /*
  383  * Given a file path, set an ACL for it; don't follow links.
  384  */
  385 int
  386 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
  387 {
  388         struct nameidata nd;
  389         int vfslocked, error;
  390 
  391         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  392         error = namei(&nd);
  393         vfslocked = NDHASGIANT(&nd);
  394         if (error == 0) {
  395                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  396                 NDFREE(&nd, 0);
  397         }
  398         VFS_UNLOCK_GIANT(vfslocked);
  399         return (error);
  400 }
  401 
  402 /*
  403  * Given a file descriptor, get an ACL for it.
  404  */
  405 int
  406 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
  407 {
  408         struct file *fp;
  409         int vfslocked, error;
  410 
  411         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  412         if (error == 0) {
  413                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  414                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
  415                 fdrop(fp, td);
  416                 VFS_UNLOCK_GIANT(vfslocked);
  417         }
  418         return (error);
  419 }
  420 
  421 /*
  422  * Given a file descriptor, set an ACL for it.
  423  */
  424 int
  425 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
  426 {
  427         struct file *fp;
  428         int vfslocked, error;
  429 
  430         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  431         if (error == 0) {
  432                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  433                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
  434                 fdrop(fp, td);
  435                 VFS_UNLOCK_GIANT(vfslocked);
  436         }
  437         return (error);
  438 }
  439 
  440 /*
  441  * Given a file path, delete an ACL from it.
  442  */
  443 int
  444 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
  445 {
  446         struct nameidata nd;
  447         int vfslocked, error;
  448 
  449         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  450         error = namei(&nd);
  451         vfslocked = NDHASGIANT(&nd);
  452         if (error == 0) {
  453                 error = vacl_delete(td, nd.ni_vp, uap->type);
  454                 NDFREE(&nd, 0);
  455         }
  456         VFS_UNLOCK_GIANT(vfslocked);
  457         return (error);
  458 }
  459 
  460 /*
  461  * Given a file path, delete an ACL from it; don't follow links.
  462  */
  463 int
  464 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
  465 {
  466         struct nameidata nd;
  467         int vfslocked, error;
  468 
  469         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  470         error = namei(&nd);
  471         vfslocked = NDHASGIANT(&nd);
  472         if (error == 0) {
  473                 error = vacl_delete(td, nd.ni_vp, uap->type);
  474                 NDFREE(&nd, 0);
  475         }
  476         VFS_UNLOCK_GIANT(vfslocked);
  477         return (error);
  478 }
  479 
  480 /*
  481  * Given a file path, delete an ACL from it.
  482  */
  483 int
  484 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
  485 {
  486         struct file *fp;
  487         int vfslocked, error;
  488 
  489         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  490         if (error == 0) {
  491                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  492                 error = vacl_delete(td, fp->f_vnode, uap->type);
  493                 fdrop(fp, td);
  494                 VFS_UNLOCK_GIANT(vfslocked);
  495         }
  496         return (error);
  497 }
  498 
  499 /*
  500  * Given a file path, check an ACL for it.
  501  */
  502 int
  503 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
  504 {
  505         struct nameidata        nd;
  506         int vfslocked, error;
  507 
  508         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
  509         error = namei(&nd);
  510         vfslocked = NDHASGIANT(&nd);
  511         if (error == 0) {
  512                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  513                 NDFREE(&nd, 0);
  514         }
  515         VFS_UNLOCK_GIANT(vfslocked);
  516         return (error);
  517 }
  518 
  519 /*
  520  * Given a file path, check an ACL for it; don't follow links.
  521  */
  522 int
  523 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
  524 {
  525         struct nameidata        nd;
  526         int vfslocked, error;
  527 
  528         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
  529         error = namei(&nd);
  530         vfslocked = NDHASGIANT(&nd);
  531         if (error == 0) {
  532                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  533                 NDFREE(&nd, 0);
  534         }
  535         VFS_UNLOCK_GIANT(vfslocked);
  536         return (error);
  537 }
  538 
  539 /*
  540  * Given a file descriptor, check an ACL for it.
  541  */
  542 int
  543 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
  544 {
  545         struct file *fp;
  546         int vfslocked, error;
  547 
  548         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
  549         if (error == 0) {
  550                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
  551                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
  552                 fdrop(fp, td);
  553                 VFS_UNLOCK_GIANT(vfslocked);
  554         }
  555         return (error);
  556 }
  557 
  558 struct acl *
  559 acl_alloc(int flags)
  560 {
  561         struct acl *aclp;
  562 
  563         aclp = malloc(sizeof(*aclp), M_ACL, flags);
  564         aclp->acl_maxcnt = ACL_MAX_ENTRIES;
  565 
  566         return (aclp);
  567 }
  568 
  569 void
  570 acl_free(struct acl *aclp)
  571 {
  572 
  573         free(aclp, M_ACL);
  574 }

Cache object: 7f7264c09330bafe5197959ed96396e9


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