xref: /freebsd/sys/kern/vfs_acl.c (revision 91f37dcb)
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