xref: /freebsd/sys/kern/vfs_acl.c (revision 8a36da99deb0e19363ec04e4d3facd869c1028f5)
191f37dcbSRobert Watson /*-
2*8a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*8a36da99SPedro F. Giffuni  *
4f9070809SRobert Watson  * Copyright (c) 1999-2006, 2016-2017 Robert N. M. Watson
591f37dcbSRobert Watson  * All rights reserved.
691f37dcbSRobert Watson  *
76d878543SRobert Watson  * This software was developed by Robert Watson for the TrustedBSD Project.
86d878543SRobert Watson  *
9f9070809SRobert Watson  * Portions of this software were developed by BAE Systems, the University of
10f9070809SRobert Watson  * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
11f9070809SRobert Watson  * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
12f9070809SRobert Watson  * Computing (TC) research program.
13f9070809SRobert Watson  *
1491f37dcbSRobert Watson  * Redistribution and use in source and binary forms, with or without
1591f37dcbSRobert Watson  * modification, are permitted provided that the following conditions
1691f37dcbSRobert Watson  * are met:
1791f37dcbSRobert Watson  * 1. Redistributions of source code must retain the above copyright
1891f37dcbSRobert Watson  *    notice, this list of conditions and the following disclaimer.
1991f37dcbSRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
2091f37dcbSRobert Watson  *    notice, this list of conditions and the following disclaimer in the
2191f37dcbSRobert Watson  *    documentation and/or other materials provided with the distribution.
2291f37dcbSRobert Watson  *
2391f37dcbSRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2491f37dcbSRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2591f37dcbSRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2691f37dcbSRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2791f37dcbSRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2891f37dcbSRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2991f37dcbSRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3091f37dcbSRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3191f37dcbSRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3291f37dcbSRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3391f37dcbSRobert Watson  * SUCH DAMAGE.
3491f37dcbSRobert Watson  */
3591f37dcbSRobert Watson /*
365293465fSRobert Watson  * Developed by the TrustedBSD Project.
37e4256d1eSRobert Watson  *
38e4256d1eSRobert Watson  * ACL system calls and other functions common across different ACL types.
39e4256d1eSRobert Watson  * Type-specific routines go into subr_acl_<type>.c.
4091f37dcbSRobert Watson  */
4191f37dcbSRobert Watson 
42677b542eSDavid E. O'Brien #include <sys/cdefs.h>
43677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
44677b542eSDavid E. O'Brien 
4591f37dcbSRobert Watson #include <sys/param.h>
4691f37dcbSRobert Watson #include <sys/systm.h>
4791f37dcbSRobert Watson #include <sys/sysproto.h>
484a144410SRobert Watson #include <sys/capsicum.h>
4957b4252eSKonstantin Belousov #include <sys/fcntl.h>
5091f37dcbSRobert Watson #include <sys/kernel.h>
5191f37dcbSRobert Watson #include <sys/malloc.h>
5242e7197fSChristian S.J. Peron #include <sys/mount.h>
5391f37dcbSRobert Watson #include <sys/vnode.h>
5491f37dcbSRobert Watson #include <sys/lock.h>
55f708f4d1SMatthew Dillon #include <sys/mutex.h>
5691f37dcbSRobert Watson #include <sys/namei.h>
5791f37dcbSRobert Watson #include <sys/file.h>
5813438f68SAlfred Perlstein #include <sys/filedesc.h>
5991f37dcbSRobert Watson #include <sys/proc.h>
6091f37dcbSRobert Watson #include <sys/sysent.h>
6191f37dcbSRobert Watson #include <sys/acl.h>
6291f37dcbSRobert Watson 
63f9070809SRobert Watson #include <security/audit/audit.h>
64aed55708SRobert Watson #include <security/mac/mac_framework.h>
65aed55708SRobert Watson 
66ae1add4eSEdward Tomasz Napierala CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
67ae1add4eSEdward Tomasz Napierala 
68ae1add4eSEdward Tomasz Napierala MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
6991f37dcbSRobert Watson 
70cbeb8402SRobert Watson static int	vacl_set_acl(struct thread *td, struct vnode *vp,
71cbeb8402SRobert Watson 		    acl_type_t type, struct acl *aclp);
72cbeb8402SRobert Watson static int	vacl_get_acl(struct thread *td, struct vnode *vp,
73cbeb8402SRobert Watson 		    acl_type_t type, struct acl *aclp);
74b40ce416SJulian Elischer static int	vacl_aclcheck(struct thread *td, struct vnode *vp,
75b114e127SRobert Watson 		    acl_type_t type, struct acl *aclp);
7691f37dcbSRobert Watson 
77ae1add4eSEdward Tomasz Napierala int
78ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
79ae1add4eSEdward Tomasz Napierala {
80ae1add4eSEdward Tomasz Napierala 	int i;
81ae1add4eSEdward Tomasz Napierala 
82ae1add4eSEdward Tomasz Napierala 	if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
83ae1add4eSEdward Tomasz Napierala 		return (EINVAL);
84ae1add4eSEdward Tomasz Napierala 
85ae1add4eSEdward Tomasz Napierala 	bzero(dest, sizeof(*dest));
86ae1add4eSEdward Tomasz Napierala 
87ae1add4eSEdward Tomasz Napierala 	dest->acl_cnt = source->acl_cnt;
88ae1add4eSEdward Tomasz Napierala 	dest->acl_maxcnt = ACL_MAX_ENTRIES;
89ae1add4eSEdward Tomasz Napierala 
90ae1add4eSEdward Tomasz Napierala 	for (i = 0; i < dest->acl_cnt; i++) {
91ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
92ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
93ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
94ae1add4eSEdward Tomasz Napierala 	}
95ae1add4eSEdward Tomasz Napierala 
96ae1add4eSEdward Tomasz Napierala 	return (0);
97ae1add4eSEdward Tomasz Napierala }
98ae1add4eSEdward Tomasz Napierala 
99ae1add4eSEdward Tomasz Napierala int
100ae1add4eSEdward Tomasz Napierala acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
101ae1add4eSEdward Tomasz Napierala {
102ae1add4eSEdward Tomasz Napierala 	int i;
103ae1add4eSEdward Tomasz Napierala 
104ce9d79aaSEdward Tomasz Napierala 	if (source->acl_cnt > OLDACL_MAX_ENTRIES)
105ae1add4eSEdward Tomasz Napierala 		return (EINVAL);
106ae1add4eSEdward Tomasz Napierala 
107ae1add4eSEdward Tomasz Napierala 	bzero(dest, sizeof(*dest));
108ae1add4eSEdward Tomasz Napierala 
109ae1add4eSEdward Tomasz Napierala 	dest->acl_cnt = source->acl_cnt;
110ae1add4eSEdward Tomasz Napierala 
111ae1add4eSEdward Tomasz Napierala 	for (i = 0; i < dest->acl_cnt; i++) {
112ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
113ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
114ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
115ae1add4eSEdward Tomasz Napierala 	}
116ae1add4eSEdward Tomasz Napierala 
117ae1add4eSEdward Tomasz Napierala 	return (0);
118ae1add4eSEdward Tomasz Napierala }
119ae1add4eSEdward Tomasz Napierala 
120ae1add4eSEdward Tomasz Napierala /*
121ae1add4eSEdward Tomasz Napierala  * At one time, "struct ACL" was extended in order to add support for NFSv4
122ae1add4eSEdward Tomasz Napierala  * ACLs.  Instead of creating compatibility versions of all the ACL-related
123ae1add4eSEdward Tomasz Napierala  * syscalls, they were left intact.  It's possible to find out what the code
124ae1add4eSEdward Tomasz Napierala  * calling these syscalls (libc) expects basing on "type" argument - if it's
125ae1add4eSEdward Tomasz Napierala  * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
126ae1add4eSEdward Tomasz Napierala  * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
127ae1add4eSEdward Tomasz Napierala  * oldacl".  If it's something else, then it's the new "struct acl".  In the
128ae1add4eSEdward Tomasz Napierala  * latter case, the routines below just copyin/copyout the contents.  In the
129ae1add4eSEdward Tomasz Napierala  * former case, they copyin the "struct oldacl" and convert it to the new
130ae1add4eSEdward Tomasz Napierala  * format.
131ae1add4eSEdward Tomasz Napierala  */
132ae1add4eSEdward Tomasz Napierala static int
133ae1add4eSEdward Tomasz Napierala acl_copyin(void *user_acl, struct acl *kernel_acl, acl_type_t type)
134ae1add4eSEdward Tomasz Napierala {
135ae1add4eSEdward Tomasz Napierala 	int error;
136ae1add4eSEdward Tomasz Napierala 	struct oldacl old;
137ae1add4eSEdward Tomasz Napierala 
138ae1add4eSEdward Tomasz Napierala 	switch (type) {
139ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
140ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
141ae1add4eSEdward Tomasz Napierala 		error = copyin(user_acl, &old, sizeof(old));
142ae1add4eSEdward Tomasz Napierala 		if (error != 0)
143ae1add4eSEdward Tomasz Napierala 			break;
144ae1add4eSEdward Tomasz Napierala 		acl_copy_oldacl_into_acl(&old, kernel_acl);
145ae1add4eSEdward Tomasz Napierala 		break;
146ae1add4eSEdward Tomasz Napierala 
147ae1add4eSEdward Tomasz Napierala 	default:
148ae1add4eSEdward Tomasz Napierala 		error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
149ae1add4eSEdward Tomasz Napierala 		if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
150ae1add4eSEdward Tomasz Napierala 			return (EINVAL);
151ae1add4eSEdward Tomasz Napierala 	}
152ae1add4eSEdward Tomasz Napierala 
153ae1add4eSEdward Tomasz Napierala 	return (error);
154ae1add4eSEdward Tomasz Napierala }
155ae1add4eSEdward Tomasz Napierala 
156ae1add4eSEdward Tomasz Napierala static int
157ae1add4eSEdward Tomasz Napierala acl_copyout(struct acl *kernel_acl, void *user_acl, acl_type_t type)
158ae1add4eSEdward Tomasz Napierala {
1590a2c94b8SKonstantin Belousov 	uint32_t am;
160ae1add4eSEdward Tomasz Napierala 	int error;
161ae1add4eSEdward Tomasz Napierala 	struct oldacl old;
162ae1add4eSEdward Tomasz Napierala 
163ae1add4eSEdward Tomasz Napierala 	switch (type) {
164ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
165ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
166ae1add4eSEdward Tomasz Napierala 		error = acl_copy_acl_into_oldacl(kernel_acl, &old);
167ae1add4eSEdward Tomasz Napierala 		if (error != 0)
168ae1add4eSEdward Tomasz Napierala 			break;
169ae1add4eSEdward Tomasz Napierala 
170ae1add4eSEdward Tomasz Napierala 		error = copyout(&old, user_acl, sizeof(old));
171ae1add4eSEdward Tomasz Napierala 		break;
172ae1add4eSEdward Tomasz Napierala 
173ae1add4eSEdward Tomasz Napierala 	default:
1740a2c94b8SKonstantin Belousov 		error = fueword32((char *)user_acl +
1750a2c94b8SKonstantin Belousov 		    offsetof(struct acl, acl_maxcnt), &am);
1760a2c94b8SKonstantin Belousov 		if (error == -1)
1770a2c94b8SKonstantin Belousov 			return (EFAULT);
1780a2c94b8SKonstantin Belousov 		if (am != ACL_MAX_ENTRIES)
179ae1add4eSEdward Tomasz Napierala 			return (EINVAL);
180ae1add4eSEdward Tomasz Napierala 
181ae1add4eSEdward Tomasz Napierala 		error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
182ae1add4eSEdward Tomasz Napierala 	}
183ae1add4eSEdward Tomasz Napierala 
184ae1add4eSEdward Tomasz Napierala 	return (error);
185ae1add4eSEdward Tomasz Napierala }
186ae1add4eSEdward Tomasz Napierala 
187ae1add4eSEdward Tomasz Napierala /*
188ae1add4eSEdward Tomasz Napierala  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
1896bb58cddSEdward Tomasz Napierala  * counterpart.  It's required for old (pre-NFSv4 ACLs) libc to work
190ae1add4eSEdward Tomasz Napierala  * with new kernel.  Fixing 'type' for old binaries with new libc
191ae1add4eSEdward Tomasz Napierala  * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
192ae1add4eSEdward Tomasz Napierala  */
193ae1add4eSEdward Tomasz Napierala static int
194ae1add4eSEdward Tomasz Napierala acl_type_unold(int type)
195ae1add4eSEdward Tomasz Napierala {
196ae1add4eSEdward Tomasz Napierala 	switch (type) {
197ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
198ae1add4eSEdward Tomasz Napierala 		return (ACL_TYPE_ACCESS);
199ae1add4eSEdward Tomasz Napierala 
200ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
201ae1add4eSEdward Tomasz Napierala 		return (ACL_TYPE_DEFAULT);
202ae1add4eSEdward Tomasz Napierala 
203ae1add4eSEdward Tomasz Napierala 	default:
204ae1add4eSEdward Tomasz Napierala 		return (type);
205ae1add4eSEdward Tomasz Napierala 	}
206ae1add4eSEdward Tomasz Napierala }
207ae1add4eSEdward Tomasz Napierala 
20891f37dcbSRobert Watson /*
209b0c521e2SRobert Watson  * These calls wrap the real vnode operations, and are called by the syscall
210b0c521e2SRobert Watson  * code once the syscall has converted the path or file descriptor to a vnode
211b0c521e2SRobert Watson  * (unlocked).  The aclp pointer is assumed still to point to userland, so
212b0c521e2SRobert Watson  * this should not be consumed within the kernel except by syscall code.
213b0c521e2SRobert Watson  * Other code should directly invoke VOP_{SET,GET}ACL.
21491f37dcbSRobert Watson  */
21591f37dcbSRobert Watson 
21691f37dcbSRobert Watson /*
21791f37dcbSRobert Watson  * Given a vnode, set its ACL.
21891f37dcbSRobert Watson  */
21991f37dcbSRobert Watson static int
220b40ce416SJulian Elischer vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
22191f37dcbSRobert Watson     struct acl *aclp)
22291f37dcbSRobert Watson {
223b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
2244e1123c7SRobert Watson 	struct mount *mp;
22591f37dcbSRobert Watson 	int error;
22691f37dcbSRobert Watson 
227f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
228b998d381SEdward Tomasz Napierala 	inkernelacl = acl_alloc(M_WAITOK);
229ae1add4eSEdward Tomasz Napierala 	error = acl_copyin(aclp, inkernelacl, type);
230da9ce28eSEdward Tomasz Napierala 	if (error != 0)
231b998d381SEdward Tomasz Napierala 		goto out;
2324e1123c7SRobert Watson 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
2334e1123c7SRobert Watson 	if (error != 0)
234b998d381SEdward Tomasz Napierala 		goto out;
235cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
236f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
237c86ca022SRobert Watson #ifdef MAC
238b998d381SEdward Tomasz Napierala 	error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl);
239c86ca022SRobert Watson 	if (error != 0)
240b998d381SEdward Tomasz Napierala 		goto out_unlock;
241c86ca022SRobert Watson #endif
242ae1add4eSEdward Tomasz Napierala 	error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
243ae1add4eSEdward Tomasz Napierala 	    td->td_ucred, td);
244c86ca022SRobert Watson #ifdef MAC
245b998d381SEdward Tomasz Napierala out_unlock:
246c86ca022SRobert Watson #endif
24722db15c0SAttilio Rao 	VOP_UNLOCK(vp, 0);
2484e1123c7SRobert Watson 	vn_finished_write(mp);
249b998d381SEdward Tomasz Napierala out:
250b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
25191f37dcbSRobert Watson 	return (error);
25291f37dcbSRobert Watson }
25391f37dcbSRobert Watson 
25491f37dcbSRobert Watson /*
25591f37dcbSRobert Watson  * Given a vnode, get its ACL.
25691f37dcbSRobert Watson  */
25791f37dcbSRobert Watson static int
258b40ce416SJulian Elischer vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
25991f37dcbSRobert Watson     struct acl *aclp)
26091f37dcbSRobert Watson {
261b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
26291f37dcbSRobert Watson 	int error;
26391f37dcbSRobert Watson 
264f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
26523c053d6SSergey Kandaurov 	inkernelacl = acl_alloc(M_WAITOK | M_ZERO);
266cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
267f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
268c86ca022SRobert Watson #ifdef MAC
26930d239bcSRobert Watson 	error = mac_vnode_check_getacl(td->td_ucred, vp, type);
270c86ca022SRobert Watson 	if (error != 0)
271c86ca022SRobert Watson 		goto out;
272c86ca022SRobert Watson #endif
273ae1add4eSEdward Tomasz Napierala 	error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
274ae1add4eSEdward Tomasz Napierala 	    td->td_ucred, td);
275ae1add4eSEdward Tomasz Napierala 
276c86ca022SRobert Watson #ifdef MAC
277c86ca022SRobert Watson out:
278c86ca022SRobert Watson #endif
27922db15c0SAttilio Rao 	VOP_UNLOCK(vp, 0);
28091f37dcbSRobert Watson 	if (error == 0)
281ae1add4eSEdward Tomasz Napierala 		error = acl_copyout(inkernelacl, aclp, type);
282b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
28391f37dcbSRobert Watson 	return (error);
28491f37dcbSRobert Watson }
28591f37dcbSRobert Watson 
28691f37dcbSRobert Watson /*
28791f37dcbSRobert Watson  * Given a vnode, delete its ACL.
28891f37dcbSRobert Watson  */
28991f37dcbSRobert Watson static int
290b40ce416SJulian Elischer vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
29191f37dcbSRobert Watson {
2924e1123c7SRobert Watson 	struct mount *mp;
29391f37dcbSRobert Watson 	int error;
29491f37dcbSRobert Watson 
295f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
2964e1123c7SRobert Watson 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
297da9ce28eSEdward Tomasz Napierala 	if (error != 0)
2984e1123c7SRobert Watson 		return (error);
299cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
300f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
301c86ca022SRobert Watson #ifdef MAC
30230d239bcSRobert Watson 	error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
303da9ce28eSEdward Tomasz Napierala 	if (error != 0)
304c86ca022SRobert Watson 		goto out;
305c86ca022SRobert Watson #endif
306ae1add4eSEdward Tomasz Napierala 	error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
307c86ca022SRobert Watson #ifdef MAC
308c86ca022SRobert Watson out:
309c86ca022SRobert Watson #endif
31022db15c0SAttilio Rao 	VOP_UNLOCK(vp, 0);
3114e1123c7SRobert Watson 	vn_finished_write(mp);
31291f37dcbSRobert Watson 	return (error);
31391f37dcbSRobert Watson }
31491f37dcbSRobert Watson 
31591f37dcbSRobert Watson /*
31691f37dcbSRobert Watson  * Given a vnode, check whether an ACL is appropriate for it
317f9070809SRobert Watson  *
318f9070809SRobert Watson  * XXXRW: No vnode lock held so can't audit vnode state...?
31991f37dcbSRobert Watson  */
32091f37dcbSRobert Watson static int
321b40ce416SJulian Elischer vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
32291f37dcbSRobert Watson     struct acl *aclp)
32391f37dcbSRobert Watson {
324b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
32591f37dcbSRobert Watson 	int error;
32691f37dcbSRobert Watson 
327b998d381SEdward Tomasz Napierala 	inkernelacl = acl_alloc(M_WAITOK);
328ae1add4eSEdward Tomasz Napierala 	error = acl_copyin(aclp, inkernelacl, type);
329da9ce28eSEdward Tomasz Napierala 	if (error != 0)
330b998d381SEdward Tomasz Napierala 		goto out;
3316bb58cddSEdward Tomasz Napierala 	error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl,
3326bb58cddSEdward Tomasz Napierala 	    td->td_ucred, td);
333b998d381SEdward Tomasz Napierala out:
334b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
33591f37dcbSRobert Watson 	return (error);
33691f37dcbSRobert Watson }
33791f37dcbSRobert Watson 
33891f37dcbSRobert Watson /*
339b0c521e2SRobert Watson  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
340b0c521e2SRobert Watson  * need to lock, as the vacl_ code will get/release any locks required.
34191f37dcbSRobert Watson  */
34291f37dcbSRobert Watson 
34391f37dcbSRobert Watson /*
34491f37dcbSRobert Watson  * Given a file path, get an ACL for it
34591f37dcbSRobert Watson  */
34691f37dcbSRobert Watson int
3478451d0ddSKip Macy sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
34891f37dcbSRobert Watson {
34991f37dcbSRobert Watson 	struct nameidata nd;
3505050aa86SKonstantin Belousov 	int error;
35191f37dcbSRobert Watson 
352f9070809SRobert Watson 	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
353f9070809SRobert Watson 	    td);
35491f37dcbSRobert Watson 	error = namei(&nd);
355f708f4d1SMatthew Dillon 	if (error == 0) {
356f97182acSAlfred Perlstein 		error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
35791f37dcbSRobert Watson 		NDFREE(&nd, 0);
358f708f4d1SMatthew Dillon 	}
35991f37dcbSRobert Watson 	return (error);
36091f37dcbSRobert Watson }
36191f37dcbSRobert Watson 
36291f37dcbSRobert Watson /*
3633c67c23bSRobert Watson  * Given a file path, get an ACL for it; don't follow links.
3643c67c23bSRobert Watson  */
3653c67c23bSRobert Watson int
3668451d0ddSKip Macy sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
3673c67c23bSRobert Watson {
3683c67c23bSRobert Watson 	struct nameidata nd;
3695050aa86SKonstantin Belousov 	int error;
3703c67c23bSRobert Watson 
371f9070809SRobert Watson 	NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
372f9070809SRobert Watson 	    td);
3733c67c23bSRobert Watson 	error = namei(&nd);
3743c67c23bSRobert Watson 	if (error == 0) {
3753c67c23bSRobert Watson 		error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
3763c67c23bSRobert Watson 		NDFREE(&nd, 0);
3773c67c23bSRobert Watson 	}
3783c67c23bSRobert Watson 	return (error);
3793c67c23bSRobert Watson }
3803c67c23bSRobert Watson 
3813c67c23bSRobert Watson /*
3820c14ff0eSRobert Watson  * Given a file path, set an ACL for it.
38391f37dcbSRobert Watson  */
38491f37dcbSRobert Watson int
3858451d0ddSKip Macy sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
38691f37dcbSRobert Watson {
38791f37dcbSRobert Watson 	struct nameidata nd;
3885050aa86SKonstantin Belousov 	int error;
38991f37dcbSRobert Watson 
390f9070809SRobert Watson 	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
391f9070809SRobert Watson 	    td);
39291f37dcbSRobert Watson 	error = namei(&nd);
393f708f4d1SMatthew Dillon 	if (error == 0) {
394f97182acSAlfred Perlstein 		error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
39591f37dcbSRobert Watson 		NDFREE(&nd, 0);
396f708f4d1SMatthew Dillon 	}
39791f37dcbSRobert Watson 	return (error);
39891f37dcbSRobert Watson }
39991f37dcbSRobert Watson 
40091f37dcbSRobert Watson /*
4013c67c23bSRobert Watson  * Given a file path, set an ACL for it; don't follow links.
4023c67c23bSRobert Watson  */
4033c67c23bSRobert Watson int
4048451d0ddSKip Macy sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
4053c67c23bSRobert Watson {
4063c67c23bSRobert Watson 	struct nameidata nd;
4075050aa86SKonstantin Belousov 	int error;
4083c67c23bSRobert Watson 
409f9070809SRobert Watson 	NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
410f9070809SRobert Watson 	    td);
4113c67c23bSRobert Watson 	error = namei(&nd);
4123c67c23bSRobert Watson 	if (error == 0) {
4133c67c23bSRobert Watson 		error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
4143c67c23bSRobert Watson 		NDFREE(&nd, 0);
4153c67c23bSRobert Watson 	}
4163c67c23bSRobert Watson 	return (error);
4173c67c23bSRobert Watson }
4183c67c23bSRobert Watson 
4193c67c23bSRobert Watson /*
420b5368498SRobert Watson  * Given a file descriptor, get an ACL for it.
42191f37dcbSRobert Watson  */
42291f37dcbSRobert Watson int
4238451d0ddSKip Macy sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
42491f37dcbSRobert Watson {
42591f37dcbSRobert Watson 	struct file *fp;
4267008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
4275050aa86SKonstantin Belousov 	int error;
42891f37dcbSRobert Watson 
429f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
4304da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
4317008be5bSPawel Jakub Dawidek 	    cap_rights_init(&rights, CAP_ACL_GET), &fp);
432f708f4d1SMatthew Dillon 	if (error == 0) {
4333b6d9652SPoul-Henning Kamp 		error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
434426da3bcSAlfred Perlstein 		fdrop(fp, td);
435f708f4d1SMatthew Dillon 	}
43691f37dcbSRobert Watson 	return (error);
43791f37dcbSRobert Watson }
43891f37dcbSRobert Watson 
43991f37dcbSRobert Watson /*
440b5368498SRobert Watson  * Given a file descriptor, set an ACL for it.
44191f37dcbSRobert Watson  */
44291f37dcbSRobert Watson int
4438451d0ddSKip Macy sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
44491f37dcbSRobert Watson {
44591f37dcbSRobert Watson 	struct file *fp;
4467008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
4475050aa86SKonstantin Belousov 	int error;
44891f37dcbSRobert Watson 
449f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
4504da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
4517008be5bSPawel Jakub Dawidek 	    cap_rights_init(&rights, CAP_ACL_SET), &fp);
452f708f4d1SMatthew Dillon 	if (error == 0) {
4533b6d9652SPoul-Henning Kamp 		error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
454426da3bcSAlfred Perlstein 		fdrop(fp, td);
455f708f4d1SMatthew Dillon 	}
45691f37dcbSRobert Watson 	return (error);
45791f37dcbSRobert Watson }
45891f37dcbSRobert Watson 
45991f37dcbSRobert Watson /*
46091f37dcbSRobert Watson  * Given a file path, delete an ACL from it.
46191f37dcbSRobert Watson  */
46291f37dcbSRobert Watson int
4638451d0ddSKip Macy sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
46491f37dcbSRobert Watson {
46591f37dcbSRobert Watson 	struct nameidata nd;
4665050aa86SKonstantin Belousov 	int error;
46791f37dcbSRobert Watson 
4685050aa86SKonstantin Belousov 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
46991f37dcbSRobert Watson 	error = namei(&nd);
470f708f4d1SMatthew Dillon 	if (error == 0) {
471d1e405c5SAlfred Perlstein 		error = vacl_delete(td, nd.ni_vp, uap->type);
47291f37dcbSRobert Watson 		NDFREE(&nd, 0);
473f708f4d1SMatthew Dillon 	}
47491f37dcbSRobert Watson 	return (error);
47591f37dcbSRobert Watson }
47691f37dcbSRobert Watson 
47791f37dcbSRobert Watson /*
4783c67c23bSRobert Watson  * Given a file path, delete an ACL from it; don't follow links.
4793c67c23bSRobert Watson  */
4803c67c23bSRobert Watson int
4818451d0ddSKip Macy sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
4823c67c23bSRobert Watson {
4833c67c23bSRobert Watson 	struct nameidata nd;
4845050aa86SKonstantin Belousov 	int error;
4853c67c23bSRobert Watson 
4865050aa86SKonstantin Belousov 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
4873c67c23bSRobert Watson 	error = namei(&nd);
4883c67c23bSRobert Watson 	if (error == 0) {
4893c67c23bSRobert Watson 		error = vacl_delete(td, nd.ni_vp, uap->type);
4903c67c23bSRobert Watson 		NDFREE(&nd, 0);
4913c67c23bSRobert Watson 	}
4923c67c23bSRobert Watson 	return (error);
4933c67c23bSRobert Watson }
4943c67c23bSRobert Watson 
4953c67c23bSRobert Watson /*
49691f37dcbSRobert Watson  * Given a file path, delete an ACL from it.
49791f37dcbSRobert Watson  */
49891f37dcbSRobert Watson int
4998451d0ddSKip Macy sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
50091f37dcbSRobert Watson {
50191f37dcbSRobert Watson 	struct file *fp;
5027008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
5035050aa86SKonstantin Belousov 	int error;
50491f37dcbSRobert Watson 
505f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
5064da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
5077008be5bSPawel Jakub Dawidek 	    cap_rights_init(&rights, CAP_ACL_DELETE), &fp);
508f708f4d1SMatthew Dillon 	if (error == 0) {
5093b6d9652SPoul-Henning Kamp 		error = vacl_delete(td, fp->f_vnode, uap->type);
510426da3bcSAlfred Perlstein 		fdrop(fp, td);
511f708f4d1SMatthew Dillon 	}
51291f37dcbSRobert Watson 	return (error);
51391f37dcbSRobert Watson }
51491f37dcbSRobert Watson 
51591f37dcbSRobert Watson /*
5160c14ff0eSRobert Watson  * Given a file path, check an ACL for it.
51791f37dcbSRobert Watson  */
51891f37dcbSRobert Watson int
5198451d0ddSKip Macy sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
52091f37dcbSRobert Watson {
52191f37dcbSRobert Watson 	struct nameidata nd;
5225050aa86SKonstantin Belousov 	int error;
52391f37dcbSRobert Watson 
5245050aa86SKonstantin Belousov 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
52591f37dcbSRobert Watson 	error = namei(&nd);
526f708f4d1SMatthew Dillon 	if (error == 0) {
527f97182acSAlfred Perlstein 		error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
52891f37dcbSRobert Watson 		NDFREE(&nd, 0);
529f708f4d1SMatthew Dillon 	}
53091f37dcbSRobert Watson 	return (error);
53191f37dcbSRobert Watson }
53291f37dcbSRobert Watson 
53391f37dcbSRobert Watson /*
5343c67c23bSRobert Watson  * Given a file path, check an ACL for it; don't follow links.
5353c67c23bSRobert Watson  */
5363c67c23bSRobert Watson int
5378451d0ddSKip Macy sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
5383c67c23bSRobert Watson {
5397a172809SEdward Tomasz Napierala 	struct nameidata nd;
5405050aa86SKonstantin Belousov 	int error;
5413c67c23bSRobert Watson 
5425050aa86SKonstantin Belousov 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
5433c67c23bSRobert Watson 	error = namei(&nd);
5443c67c23bSRobert Watson 	if (error == 0) {
5453c67c23bSRobert Watson 		error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
5463c67c23bSRobert Watson 		NDFREE(&nd, 0);
5473c67c23bSRobert Watson 	}
5483c67c23bSRobert Watson 	return (error);
5493c67c23bSRobert Watson }
5503c67c23bSRobert Watson 
5513c67c23bSRobert Watson /*
5520c14ff0eSRobert Watson  * Given a file descriptor, check an ACL for it.
55391f37dcbSRobert Watson  */
55491f37dcbSRobert Watson int
5558451d0ddSKip Macy sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
55691f37dcbSRobert Watson {
55791f37dcbSRobert Watson 	struct file *fp;
5587008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
5595050aa86SKonstantin Belousov 	int error;
56091f37dcbSRobert Watson 
561f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
5624da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
5637008be5bSPawel Jakub Dawidek 	    cap_rights_init(&rights, CAP_ACL_CHECK), &fp);
564f708f4d1SMatthew Dillon 	if (error == 0) {
5653b6d9652SPoul-Henning Kamp 		error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
566426da3bcSAlfred Perlstein 		fdrop(fp, td);
567f708f4d1SMatthew Dillon 	}
56891f37dcbSRobert Watson 	return (error);
56991f37dcbSRobert Watson }
570d1dfd921SChristian S.J. Peron 
571b998d381SEdward Tomasz Napierala struct acl *
572b998d381SEdward Tomasz Napierala acl_alloc(int flags)
573b998d381SEdward Tomasz Napierala {
574b998d381SEdward Tomasz Napierala 	struct acl *aclp;
575b998d381SEdward Tomasz Napierala 
576e0ee7589SEdward Tomasz Napierala 	aclp = malloc(sizeof(*aclp), M_ACL, flags);
5778ddc3590SEdward Tomasz Napierala 	if (aclp == NULL)
5788ddc3590SEdward Tomasz Napierala 		return (NULL);
5798ddc3590SEdward Tomasz Napierala 
580ae1add4eSEdward Tomasz Napierala 	aclp->acl_maxcnt = ACL_MAX_ENTRIES;
581b998d381SEdward Tomasz Napierala 
582b998d381SEdward Tomasz Napierala 	return (aclp);
583b998d381SEdward Tomasz Napierala }
584b998d381SEdward Tomasz Napierala 
585b998d381SEdward Tomasz Napierala void
586b998d381SEdward Tomasz Napierala acl_free(struct acl *aclp)
587b998d381SEdward Tomasz Napierala {
588b998d381SEdward Tomasz Napierala 
589e0ee7589SEdward Tomasz Napierala 	free(aclp, M_ACL);
590b998d381SEdward Tomasz Napierala }
591