191f37dcbSRobert Watson /*- 291f37dcbSRobert Watson * Copyright (c) 1999 Robert N. M. Watson 391f37dcbSRobert Watson * All rights reserved. 491f37dcbSRobert Watson * 591f37dcbSRobert Watson * Redistribution and use in source and binary forms, with or without 691f37dcbSRobert Watson * modification, are permitted provided that the following conditions 791f37dcbSRobert Watson * are met: 891f37dcbSRobert Watson * 1. Redistributions of source code must retain the above copyright 991f37dcbSRobert Watson * notice, this list of conditions and the following disclaimer. 1091f37dcbSRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 1191f37dcbSRobert Watson * notice, this list of conditions and the following disclaimer in the 1291f37dcbSRobert Watson * documentation and/or other materials provided with the distribution. 1391f37dcbSRobert Watson * 1491f37dcbSRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1591f37dcbSRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1691f37dcbSRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1791f37dcbSRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1891f37dcbSRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1991f37dcbSRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2091f37dcbSRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2191f37dcbSRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2291f37dcbSRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2391f37dcbSRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2491f37dcbSRobert Watson * SUCH DAMAGE. 2591f37dcbSRobert Watson * 2691f37dcbSRobert Watson * $FreeBSD$ 2791f37dcbSRobert Watson */ 2891f37dcbSRobert Watson 2991f37dcbSRobert Watson /* 3091f37dcbSRobert Watson * Generic routines to support file system ACLs, at a syntactic level 3191f37dcbSRobert Watson * Semantics are the responsibility of the underlying file system 3291f37dcbSRobert Watson */ 3391f37dcbSRobert Watson 3491f37dcbSRobert Watson #include <sys/param.h> 3591f37dcbSRobert Watson #include <sys/systm.h> 3691f37dcbSRobert Watson #include <sys/sysproto.h> 3791f37dcbSRobert Watson #include <sys/kernel.h> 3891f37dcbSRobert Watson #include <sys/malloc.h> 3991f37dcbSRobert Watson #include <sys/vnode.h> 4091f37dcbSRobert Watson #include <sys/lock.h> 4191f37dcbSRobert Watson #include <sys/namei.h> 4291f37dcbSRobert Watson #include <sys/file.h> 4391f37dcbSRobert Watson #include <sys/proc.h> 4491f37dcbSRobert Watson #include <sys/sysent.h> 4591f37dcbSRobert Watson #include <sys/errno.h> 4691f37dcbSRobert Watson #include <sys/stat.h> 4791f37dcbSRobert Watson #include <sys/acl.h> 4891f37dcbSRobert Watson #include <vm/vm_zone.h> 4991f37dcbSRobert Watson 5091f37dcbSRobert Watson static MALLOC_DEFINE(M_ACL, "acl", "access control list"); 5191f37dcbSRobert Watson 5291f37dcbSRobert Watson static int vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, 5391f37dcbSRobert Watson struct acl *aclp); 5491f37dcbSRobert Watson static int vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, 5591f37dcbSRobert Watson struct acl *aclp); 5691f37dcbSRobert Watson static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, 5791f37dcbSRobert Watson struct acl *aclp); 5891f37dcbSRobert Watson 5991f37dcbSRobert Watson /* 6091f37dcbSRobert Watson * These calls wrap the real vnode operations, and are called by the 6191f37dcbSRobert Watson * syscall code once the syscall has converted the path or file 6291f37dcbSRobert Watson * descriptor to a vnode (unlocked). The aclp pointer is assumed 6391f37dcbSRobert Watson * still to point to userland, so this should not be consumed within 6491f37dcbSRobert Watson * the kernel except by syscall code. Other code should directly 6591f37dcbSRobert Watson * invoke VOP_{SET,GET}ACL. 6691f37dcbSRobert Watson */ 6791f37dcbSRobert Watson 6891f37dcbSRobert Watson /* 6991f37dcbSRobert Watson * Given a vnode, set its ACL. 7091f37dcbSRobert Watson */ 7191f37dcbSRobert Watson static int 7291f37dcbSRobert Watson vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, 7391f37dcbSRobert Watson struct acl *aclp) 7491f37dcbSRobert Watson { 7591f37dcbSRobert Watson struct acl inkernacl; 7691f37dcbSRobert Watson int error; 7791f37dcbSRobert Watson 7891f37dcbSRobert Watson error = copyin(aclp, &inkernacl, sizeof(struct acl)); 7991f37dcbSRobert Watson if (error) 8091f37dcbSRobert Watson return(error); 8191f37dcbSRobert Watson VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 8291f37dcbSRobert Watson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 8391f37dcbSRobert Watson error = VOP_SETACL(vp, type, &inkernacl, p->p_ucred, p); 8491f37dcbSRobert Watson VOP_UNLOCK(vp, 0, p); 8591f37dcbSRobert Watson return(error); 8691f37dcbSRobert Watson } 8791f37dcbSRobert Watson 8891f37dcbSRobert Watson /* 8991f37dcbSRobert Watson * Given a vnode, get its ACL. 9091f37dcbSRobert Watson */ 9191f37dcbSRobert Watson static int 9291f37dcbSRobert Watson vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, 9391f37dcbSRobert Watson struct acl *aclp) 9491f37dcbSRobert Watson { 9591f37dcbSRobert Watson struct acl inkernelacl; 9691f37dcbSRobert Watson int error; 9791f37dcbSRobert Watson 9891f37dcbSRobert Watson error = VOP_GETACL(vp, type, &inkernelacl, p->p_ucred, p); 9991f37dcbSRobert Watson if (error == 0) 10091f37dcbSRobert Watson error = copyout(&inkernelacl, aclp, sizeof(struct acl)); 10191f37dcbSRobert Watson return (error); 10291f37dcbSRobert Watson } 10391f37dcbSRobert Watson 10491f37dcbSRobert Watson /* 10591f37dcbSRobert Watson * Given a vnode, delete its ACL. 10691f37dcbSRobert Watson */ 10791f37dcbSRobert Watson static int 10891f37dcbSRobert Watson vacl_delete(struct proc *p, struct vnode *vp, acl_type_t type) 10991f37dcbSRobert Watson { 11091f37dcbSRobert Watson int error; 11191f37dcbSRobert Watson 11291f37dcbSRobert Watson VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 11391f37dcbSRobert Watson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 11491f37dcbSRobert Watson error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, p->p_ucred, p); 11591f37dcbSRobert Watson VOP_UNLOCK(vp, 0, p); 11691f37dcbSRobert Watson return (error); 11791f37dcbSRobert Watson } 11891f37dcbSRobert Watson 11991f37dcbSRobert Watson /* 12091f37dcbSRobert Watson * Given a vnode, check whether an ACL is appropriate for it 12191f37dcbSRobert Watson */ 12291f37dcbSRobert Watson static int 12391f37dcbSRobert Watson vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, 12491f37dcbSRobert Watson struct acl *aclp) 12591f37dcbSRobert Watson { 12691f37dcbSRobert Watson struct acl inkernelacl; 12791f37dcbSRobert Watson int error; 12891f37dcbSRobert Watson 12991f37dcbSRobert Watson error = copyin(aclp, &inkernelacl, sizeof(struct acl)); 13091f37dcbSRobert Watson if (error) 13191f37dcbSRobert Watson return(error); 13291f37dcbSRobert Watson error = VOP_ACLCHECK(vp, type, &inkernelacl, p->p_ucred, p); 13391f37dcbSRobert Watson return (error); 13491f37dcbSRobert Watson } 13591f37dcbSRobert Watson 13691f37dcbSRobert Watson /* 13791f37dcbSRobert Watson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. 13891f37dcbSRobert Watson * Don't need to lock, as the vacl_ code will get/release any locks 13991f37dcbSRobert Watson * required. 14091f37dcbSRobert Watson */ 14191f37dcbSRobert Watson 14291f37dcbSRobert Watson /* 14391f37dcbSRobert Watson * Given a file path, get an ACL for it 14491f37dcbSRobert Watson */ 14591f37dcbSRobert Watson int 14691f37dcbSRobert Watson acl_syscall_get_file(struct proc *p, struct acl_syscall_get_file_args *uap) 14791f37dcbSRobert Watson { 14891f37dcbSRobert Watson struct nameidata nd; 14991f37dcbSRobert Watson int error; 15091f37dcbSRobert Watson 15191f37dcbSRobert Watson /* what flags are required here -- possible not LOCKLEAF? */ 15291f37dcbSRobert Watson NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 15391f37dcbSRobert Watson error = namei(&nd); 15491f37dcbSRobert Watson if (error) 15591f37dcbSRobert Watson return(error); 15691f37dcbSRobert Watson error = vacl_get_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); 15791f37dcbSRobert Watson NDFREE(&nd, 0); 15891f37dcbSRobert Watson return (error); 15991f37dcbSRobert Watson } 16091f37dcbSRobert Watson 16191f37dcbSRobert Watson /* 16291f37dcbSRobert Watson * Given a file path, set an ACL for it 16391f37dcbSRobert Watson */ 16491f37dcbSRobert Watson int 16591f37dcbSRobert Watson acl_syscall_set_file(struct proc *p, struct acl_syscall_set_file_args *uap) 16691f37dcbSRobert Watson { 16791f37dcbSRobert Watson struct nameidata nd; 16891f37dcbSRobert Watson int error; 16991f37dcbSRobert Watson 17091f37dcbSRobert Watson NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 17191f37dcbSRobert Watson error = namei(&nd); 17291f37dcbSRobert Watson if (error) 17391f37dcbSRobert Watson return(error); 17491f37dcbSRobert Watson error = vacl_set_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); 17591f37dcbSRobert Watson NDFREE(&nd, 0); 17691f37dcbSRobert Watson return (error); 17791f37dcbSRobert Watson } 17891f37dcbSRobert Watson 17991f37dcbSRobert Watson /* 18091f37dcbSRobert Watson * Given a file descriptor, get an ACL for it 18191f37dcbSRobert Watson */ 18291f37dcbSRobert Watson int 18391f37dcbSRobert Watson acl_syscall_get_fd(struct proc *p, struct acl_syscall_get_fd_args *uap) 18491f37dcbSRobert Watson { 18591f37dcbSRobert Watson struct file *fp; 18691f37dcbSRobert Watson int error; 18791f37dcbSRobert Watson 18891f37dcbSRobert Watson error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); 18991f37dcbSRobert Watson if (error) 19091f37dcbSRobert Watson return(error); 19191f37dcbSRobert Watson return vacl_get_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), 19291f37dcbSRobert Watson SCARG(uap, aclp)); 19391f37dcbSRobert Watson } 19491f37dcbSRobert Watson 19591f37dcbSRobert Watson /* 19691f37dcbSRobert Watson * Given a file descriptor, set an ACL for it 19791f37dcbSRobert Watson */ 19891f37dcbSRobert Watson int 19991f37dcbSRobert Watson acl_syscall_set_fd(struct proc *p, struct acl_syscall_set_fd_args *uap) 20091f37dcbSRobert Watson { 20191f37dcbSRobert Watson struct file *fp; 20291f37dcbSRobert Watson int error; 20391f37dcbSRobert Watson 20491f37dcbSRobert Watson error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); 20591f37dcbSRobert Watson if (error) 20691f37dcbSRobert Watson return(error); 20791f37dcbSRobert Watson return vacl_set_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), 20891f37dcbSRobert Watson SCARG(uap, aclp)); 20991f37dcbSRobert Watson } 21091f37dcbSRobert Watson 21191f37dcbSRobert Watson /* 21291f37dcbSRobert Watson * Given a file path, delete an ACL from it. 21391f37dcbSRobert Watson */ 21491f37dcbSRobert Watson int 21591f37dcbSRobert Watson acl_syscall_delete_file(struct proc *p, 21691f37dcbSRobert Watson struct acl_syscall_delete_file_args *uap) 21791f37dcbSRobert Watson { 21891f37dcbSRobert Watson struct nameidata nd; 21991f37dcbSRobert Watson int error; 22091f37dcbSRobert Watson 22191f37dcbSRobert Watson NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 22291f37dcbSRobert Watson error = namei(&nd); 22391f37dcbSRobert Watson if (error) 22491f37dcbSRobert Watson return(error); 22591f37dcbSRobert Watson error = vacl_delete(p, nd.ni_vp, SCARG(uap, type)); 22691f37dcbSRobert Watson NDFREE(&nd, 0); 22791f37dcbSRobert Watson return (error); 22891f37dcbSRobert Watson } 22991f37dcbSRobert Watson 23091f37dcbSRobert Watson /* 23191f37dcbSRobert Watson * Given a file path, delete an ACL from it. 23291f37dcbSRobert Watson */ 23391f37dcbSRobert Watson int 23491f37dcbSRobert Watson acl_syscall_delete_fd(struct proc *p, 23591f37dcbSRobert Watson struct acl_syscall_delete_fd_args *uap) 23691f37dcbSRobert Watson { 23791f37dcbSRobert Watson struct file *fp; 23891f37dcbSRobert Watson int error; 23991f37dcbSRobert Watson 24091f37dcbSRobert Watson error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); 24191f37dcbSRobert Watson if (error) 24291f37dcbSRobert Watson return(error); 24391f37dcbSRobert Watson error = vacl_delete(p, (struct vnode *)fp->f_data, SCARG(uap, type)); 24491f37dcbSRobert Watson return (error); 24591f37dcbSRobert Watson } 24691f37dcbSRobert Watson 24791f37dcbSRobert Watson /* 24891f37dcbSRobert Watson * Given a file path, check an ACL for it 24991f37dcbSRobert Watson */ 25091f37dcbSRobert Watson int 25191f37dcbSRobert Watson acl_syscall_aclcheck_file(struct proc *p, 25291f37dcbSRobert Watson struct acl_syscall_aclcheck_file_args *uap) 25391f37dcbSRobert Watson { 25491f37dcbSRobert Watson struct nameidata nd; 25591f37dcbSRobert Watson int error; 25691f37dcbSRobert Watson 25791f37dcbSRobert Watson NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 25891f37dcbSRobert Watson error = namei(&nd); 25991f37dcbSRobert Watson if (error) 26091f37dcbSRobert Watson return(error); 26191f37dcbSRobert Watson error = vacl_aclcheck(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); 26291f37dcbSRobert Watson NDFREE(&nd, 0); 26391f37dcbSRobert Watson return (error); 26491f37dcbSRobert Watson } 26591f37dcbSRobert Watson 26691f37dcbSRobert Watson /* 26791f37dcbSRobert Watson * Given a file descriptor, check an ACL for it 26891f37dcbSRobert Watson */ 26991f37dcbSRobert Watson int 27091f37dcbSRobert Watson acl_syscall_aclcheck_fd(struct proc *p, 27191f37dcbSRobert Watson struct acl_syscall_aclcheck_fd_args *uap) 27291f37dcbSRobert Watson { 27391f37dcbSRobert Watson struct file *fp; 27491f37dcbSRobert Watson int error; 27591f37dcbSRobert Watson 27691f37dcbSRobert Watson error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); 27791f37dcbSRobert Watson if (error) 27891f37dcbSRobert Watson return(error); 27991f37dcbSRobert Watson return vacl_aclcheck(p, (struct vnode *)fp->f_data, SCARG(uap, type), 28091f37dcbSRobert Watson SCARG(uap, aclp)); 28191f37dcbSRobert Watson } 282