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/10.1/sys/kern/vfs_acl.c 255219 2013-09-05 00:09:56Z pjd $");
   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 error;
  331 
  332         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
  333         error = namei(&nd);
  334         if (error == 0) {
  335                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  336                 NDFREE(&nd, 0);
  337         }
  338         return (error);
  339 }
  340 
  341 /*
  342  * Given a file path, get an ACL for it; don't follow links.
  343  */
  344 int
  345 sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
  346 {
  347         struct nameidata nd;
  348         int error;
  349 
  350         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
  351         error = namei(&nd);
  352         if (error == 0) {
  353                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
  354                 NDFREE(&nd, 0);
  355         }
  356         return (error);
  357 }
  358 
  359 /*
  360  * Given a file path, set an ACL for it.
  361  */
  362 int
  363 sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
  364 {
  365         struct nameidata nd;
  366         int error;
  367 
  368         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
  369         error = namei(&nd);
  370         if (error == 0) {
  371                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  372                 NDFREE(&nd, 0);
  373         }
  374         return (error);
  375 }
  376 
  377 /*
  378  * Given a file path, set an ACL for it; don't follow links.
  379  */
  380 int
  381 sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
  382 {
  383         struct nameidata nd;
  384         int error;
  385 
  386         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
  387         error = namei(&nd);
  388         if (error == 0) {
  389                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
  390                 NDFREE(&nd, 0);
  391         }
  392         return (error);
  393 }
  394 
  395 /*
  396  * Given a file descriptor, get an ACL for it.
  397  */
  398 int
  399 sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
  400 {
  401         struct file *fp;
  402         cap_rights_t rights;
  403         int error;
  404 
  405         error = getvnode(td->td_proc->p_fd, uap->filedes,
  406             cap_rights_init(&rights, CAP_ACL_GET), &fp);
  407         if (error == 0) {
  408                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
  409                 fdrop(fp, td);
  410         }
  411         return (error);
  412 }
  413 
  414 /*
  415  * Given a file descriptor, set an ACL for it.
  416  */
  417 int
  418 sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
  419 {
  420         struct file *fp;
  421         cap_rights_t rights;
  422         int error;
  423 
  424         error = getvnode(td->td_proc->p_fd, uap->filedes,
  425             cap_rights_init(&rights, CAP_ACL_SET), &fp);
  426         if (error == 0) {
  427                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
  428                 fdrop(fp, td);
  429         }
  430         return (error);
  431 }
  432 
  433 /*
  434  * Given a file path, delete an ACL from it.
  435  */
  436 int
  437 sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
  438 {
  439         struct nameidata nd;
  440         int error;
  441 
  442         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
  443         error = namei(&nd);
  444         if (error == 0) {
  445                 error = vacl_delete(td, nd.ni_vp, uap->type);
  446                 NDFREE(&nd, 0);
  447         }
  448         return (error);
  449 }
  450 
  451 /*
  452  * Given a file path, delete an ACL from it; don't follow links.
  453  */
  454 int
  455 sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
  456 {
  457         struct nameidata nd;
  458         int error;
  459 
  460         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
  461         error = namei(&nd);
  462         if (error == 0) {
  463                 error = vacl_delete(td, nd.ni_vp, uap->type);
  464                 NDFREE(&nd, 0);
  465         }
  466         return (error);
  467 }
  468 
  469 /*
  470  * Given a file path, delete an ACL from it.
  471  */
  472 int
  473 sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
  474 {
  475         struct file *fp;
  476         cap_rights_t rights;
  477         int error;
  478 
  479         error = getvnode(td->td_proc->p_fd, uap->filedes,
  480             cap_rights_init(&rights, CAP_ACL_DELETE), &fp);
  481         if (error == 0) {
  482                 error = vacl_delete(td, fp->f_vnode, uap->type);
  483                 fdrop(fp, td);
  484         }
  485         return (error);
  486 }
  487 
  488 /*
  489  * Given a file path, check an ACL for it.
  490  */
  491 int
  492 sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
  493 {
  494         struct nameidata nd;
  495         int error;
  496 
  497         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
  498         error = namei(&nd);
  499         if (error == 0) {
  500                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  501                 NDFREE(&nd, 0);
  502         }
  503         return (error);
  504 }
  505 
  506 /*
  507  * Given a file path, check an ACL for it; don't follow links.
  508  */
  509 int
  510 sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
  511 {
  512         struct nameidata nd;
  513         int error;
  514 
  515         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
  516         error = namei(&nd);
  517         if (error == 0) {
  518                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
  519                 NDFREE(&nd, 0);
  520         }
  521         return (error);
  522 }
  523 
  524 /*
  525  * Given a file descriptor, check an ACL for it.
  526  */
  527 int
  528 sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
  529 {
  530         struct file *fp;
  531         cap_rights_t rights;
  532         int error;
  533 
  534         error = getvnode(td->td_proc->p_fd, uap->filedes,
  535             cap_rights_init(&rights, CAP_ACL_CHECK), &fp);
  536         if (error == 0) {
  537                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
  538                 fdrop(fp, td);
  539         }
  540         return (error);
  541 }
  542 
  543 struct acl *
  544 acl_alloc(int flags)
  545 {
  546         struct acl *aclp;
  547 
  548         aclp = malloc(sizeof(*aclp), M_ACL, flags);
  549         if (aclp == NULL)
  550                 return (NULL);
  551 
  552         aclp->acl_maxcnt = ACL_MAX_ENTRIES;
  553 
  554         return (aclp);
  555 }
  556 
  557 void
  558 acl_free(struct acl *aclp)
  559 {
  560 
  561         free(aclp, M_ACL);
  562 }

Cache object: 01c442337b8a9476abe6c88e24898bb0


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