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

Cache object: 83131c90d30718dbaacdec0d716225bc


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