xref: /freebsd/sys/kern/vfs_acl.c (revision 85dac03e30e6aebdf0808cd750cc5ab96efcb67c)
191f37dcbSRobert Watson /*-
28a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
38a36da99SPedro 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/acl.h>
6191f37dcbSRobert Watson 
62f9070809SRobert Watson #include <security/audit/audit.h>
63aed55708SRobert Watson #include <security/mac/mac_framework.h>
64aed55708SRobert Watson 
65ae1add4eSEdward Tomasz Napierala CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
66ae1add4eSEdward Tomasz Napierala 
67ae1add4eSEdward Tomasz Napierala MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
6891f37dcbSRobert Watson 
69aff4f2d3SBrooks Davis static int	kern___acl_aclcheck_path(struct thread *td, const char *path,
70aff4f2d3SBrooks Davis 		    acl_type_t type, struct acl *aclp, int follow);
71aff4f2d3SBrooks Davis static int	kern___acl_delete_path(struct thread *td, const char *path,
72aff4f2d3SBrooks Davis 		    acl_type_t type, int follow);
73aff4f2d3SBrooks Davis static int	kern___acl_get_path(struct thread *td, const char *path,
74aff4f2d3SBrooks Davis 		    acl_type_t type, struct acl *aclp, int follow);
75aff4f2d3SBrooks Davis static int	kern___acl_set_path(struct thread *td, const char *path,
76aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp, int follow);
77cbeb8402SRobert Watson static int	vacl_set_acl(struct thread *td, struct vnode *vp,
78aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp);
79cbeb8402SRobert Watson static int	vacl_get_acl(struct thread *td, struct vnode *vp,
80cbeb8402SRobert Watson 		    acl_type_t type, struct acl *aclp);
81b40ce416SJulian Elischer static int	vacl_aclcheck(struct thread *td, struct vnode *vp,
82aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp);
8391f37dcbSRobert Watson 
84ae1add4eSEdward Tomasz Napierala int
85ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
86ae1add4eSEdward Tomasz Napierala {
87ae1add4eSEdward Tomasz Napierala 	int i;
88ae1add4eSEdward Tomasz Napierala 
89ae1add4eSEdward Tomasz Napierala 	if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
90ae1add4eSEdward Tomasz Napierala 		return (EINVAL);
91ae1add4eSEdward Tomasz Napierala 
92ae1add4eSEdward Tomasz Napierala 	bzero(dest, sizeof(*dest));
93ae1add4eSEdward Tomasz Napierala 
94ae1add4eSEdward Tomasz Napierala 	dest->acl_cnt = source->acl_cnt;
95ae1add4eSEdward Tomasz Napierala 	dest->acl_maxcnt = ACL_MAX_ENTRIES;
96ae1add4eSEdward Tomasz Napierala 
97ae1add4eSEdward Tomasz Napierala 	for (i = 0; i < dest->acl_cnt; i++) {
98ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
99ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
100ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
101ae1add4eSEdward Tomasz Napierala 	}
102ae1add4eSEdward Tomasz Napierala 
103ae1add4eSEdward Tomasz Napierala 	return (0);
104ae1add4eSEdward Tomasz Napierala }
105ae1add4eSEdward Tomasz Napierala 
106ae1add4eSEdward Tomasz Napierala int
107ae1add4eSEdward Tomasz Napierala acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
108ae1add4eSEdward Tomasz Napierala {
109ae1add4eSEdward Tomasz Napierala 	int i;
110ae1add4eSEdward Tomasz Napierala 
111ce9d79aaSEdward Tomasz Napierala 	if (source->acl_cnt > OLDACL_MAX_ENTRIES)
112ae1add4eSEdward Tomasz Napierala 		return (EINVAL);
113ae1add4eSEdward Tomasz Napierala 
114ae1add4eSEdward Tomasz Napierala 	bzero(dest, sizeof(*dest));
115ae1add4eSEdward Tomasz Napierala 
116ae1add4eSEdward Tomasz Napierala 	dest->acl_cnt = source->acl_cnt;
117ae1add4eSEdward Tomasz Napierala 
118ae1add4eSEdward Tomasz Napierala 	for (i = 0; i < dest->acl_cnt; i++) {
119ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
120ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
121ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
122ae1add4eSEdward Tomasz Napierala 	}
123ae1add4eSEdward Tomasz Napierala 
124ae1add4eSEdward Tomasz Napierala 	return (0);
125ae1add4eSEdward Tomasz Napierala }
126ae1add4eSEdward Tomasz Napierala 
127ae1add4eSEdward Tomasz Napierala /*
128ae1add4eSEdward Tomasz Napierala  * At one time, "struct ACL" was extended in order to add support for NFSv4
129ae1add4eSEdward Tomasz Napierala  * ACLs.  Instead of creating compatibility versions of all the ACL-related
130ae1add4eSEdward Tomasz Napierala  * syscalls, they were left intact.  It's possible to find out what the code
131ae1add4eSEdward Tomasz Napierala  * calling these syscalls (libc) expects basing on "type" argument - if it's
132ae1add4eSEdward Tomasz Napierala  * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
133ae1add4eSEdward Tomasz Napierala  * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
134ae1add4eSEdward Tomasz Napierala  * oldacl".  If it's something else, then it's the new "struct acl".  In the
135ae1add4eSEdward Tomasz Napierala  * latter case, the routines below just copyin/copyout the contents.  In the
136ae1add4eSEdward Tomasz Napierala  * former case, they copyin the "struct oldacl" and convert it to the new
137ae1add4eSEdward Tomasz Napierala  * format.
138ae1add4eSEdward Tomasz Napierala  */
139ae1add4eSEdward Tomasz Napierala static int
140aff4f2d3SBrooks Davis acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type)
141ae1add4eSEdward Tomasz Napierala {
142ae1add4eSEdward Tomasz Napierala 	int error;
143ae1add4eSEdward Tomasz Napierala 	struct oldacl old;
144ae1add4eSEdward Tomasz Napierala 
145ae1add4eSEdward Tomasz Napierala 	switch (type) {
146ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
147ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
148ae1add4eSEdward Tomasz Napierala 		error = copyin(user_acl, &old, sizeof(old));
149ae1add4eSEdward Tomasz Napierala 		if (error != 0)
150ae1add4eSEdward Tomasz Napierala 			break;
151ae1add4eSEdward Tomasz Napierala 		acl_copy_oldacl_into_acl(&old, kernel_acl);
152ae1add4eSEdward Tomasz Napierala 		break;
153ae1add4eSEdward Tomasz Napierala 
154ae1add4eSEdward Tomasz Napierala 	default:
155ae1add4eSEdward Tomasz Napierala 		error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
156ae1add4eSEdward Tomasz Napierala 		if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
157ae1add4eSEdward Tomasz Napierala 			return (EINVAL);
158ae1add4eSEdward Tomasz Napierala 	}
159ae1add4eSEdward Tomasz Napierala 
160ae1add4eSEdward Tomasz Napierala 	return (error);
161ae1add4eSEdward Tomasz Napierala }
162ae1add4eSEdward Tomasz Napierala 
163ae1add4eSEdward Tomasz Napierala static int
164aff4f2d3SBrooks Davis acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type)
165ae1add4eSEdward Tomasz Napierala {
1660a2c94b8SKonstantin Belousov 	uint32_t am;
167ae1add4eSEdward Tomasz Napierala 	int error;
168ae1add4eSEdward Tomasz Napierala 	struct oldacl old;
169ae1add4eSEdward Tomasz Napierala 
170ae1add4eSEdward Tomasz Napierala 	switch (type) {
171ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
172ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
173ae1add4eSEdward Tomasz Napierala 		error = acl_copy_acl_into_oldacl(kernel_acl, &old);
174ae1add4eSEdward Tomasz Napierala 		if (error != 0)
175ae1add4eSEdward Tomasz Napierala 			break;
176ae1add4eSEdward Tomasz Napierala 
177ae1add4eSEdward Tomasz Napierala 		error = copyout(&old, user_acl, sizeof(old));
178ae1add4eSEdward Tomasz Napierala 		break;
179ae1add4eSEdward Tomasz Napierala 
180ae1add4eSEdward Tomasz Napierala 	default:
1810a2c94b8SKonstantin Belousov 		error = fueword32((char *)user_acl +
1820a2c94b8SKonstantin Belousov 		    offsetof(struct acl, acl_maxcnt), &am);
1830a2c94b8SKonstantin Belousov 		if (error == -1)
1840a2c94b8SKonstantin Belousov 			return (EFAULT);
1850a2c94b8SKonstantin Belousov 		if (am != ACL_MAX_ENTRIES)
186ae1add4eSEdward Tomasz Napierala 			return (EINVAL);
187ae1add4eSEdward Tomasz Napierala 
188ae1add4eSEdward Tomasz Napierala 		error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
189ae1add4eSEdward Tomasz Napierala 	}
190ae1add4eSEdward Tomasz Napierala 
191ae1add4eSEdward Tomasz Napierala 	return (error);
192ae1add4eSEdward Tomasz Napierala }
193ae1add4eSEdward Tomasz Napierala 
194ae1add4eSEdward Tomasz Napierala /*
195ae1add4eSEdward Tomasz Napierala  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
1966bb58cddSEdward Tomasz Napierala  * counterpart.  It's required for old (pre-NFSv4 ACLs) libc to work
197ae1add4eSEdward Tomasz Napierala  * with new kernel.  Fixing 'type' for old binaries with new libc
198ae1add4eSEdward Tomasz Napierala  * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
199ae1add4eSEdward Tomasz Napierala  */
200ae1add4eSEdward Tomasz Napierala static int
201ae1add4eSEdward Tomasz Napierala acl_type_unold(int type)
202ae1add4eSEdward Tomasz Napierala {
203ae1add4eSEdward Tomasz Napierala 	switch (type) {
204ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
205ae1add4eSEdward Tomasz Napierala 		return (ACL_TYPE_ACCESS);
206ae1add4eSEdward Tomasz Napierala 
207ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
208ae1add4eSEdward Tomasz Napierala 		return (ACL_TYPE_DEFAULT);
209ae1add4eSEdward Tomasz Napierala 
210ae1add4eSEdward Tomasz Napierala 	default:
211ae1add4eSEdward Tomasz Napierala 		return (type);
212ae1add4eSEdward Tomasz Napierala 	}
213ae1add4eSEdward Tomasz Napierala }
214ae1add4eSEdward Tomasz Napierala 
21591f37dcbSRobert Watson /*
216b0c521e2SRobert Watson  * These calls wrap the real vnode operations, and are called by the syscall
217b0c521e2SRobert Watson  * code once the syscall has converted the path or file descriptor to a vnode
218b0c521e2SRobert Watson  * (unlocked).  The aclp pointer is assumed still to point to userland, so
219b0c521e2SRobert Watson  * this should not be consumed within the kernel except by syscall code.
220b0c521e2SRobert Watson  * Other code should directly invoke VOP_{SET,GET}ACL.
22191f37dcbSRobert Watson  */
22291f37dcbSRobert Watson 
22391f37dcbSRobert Watson /*
22491f37dcbSRobert Watson  * Given a vnode, set its ACL.
22591f37dcbSRobert Watson  */
22691f37dcbSRobert Watson static int
227b40ce416SJulian Elischer vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
228aff4f2d3SBrooks Davis     const struct acl *aclp)
22991f37dcbSRobert Watson {
230b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
2314e1123c7SRobert Watson 	struct mount *mp;
23291f37dcbSRobert Watson 	int error;
23391f37dcbSRobert Watson 
234f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
235b998d381SEdward Tomasz Napierala 	inkernelacl = acl_alloc(M_WAITOK);
236ae1add4eSEdward Tomasz Napierala 	error = acl_copyin(aclp, inkernelacl, type);
237da9ce28eSEdward Tomasz Napierala 	if (error != 0)
238b998d381SEdward Tomasz Napierala 		goto out;
239a75d1dddSMateusz Guzik 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
2404e1123c7SRobert Watson 	if (error != 0)
241b998d381SEdward Tomasz Napierala 		goto out;
242cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
243f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
244c86ca022SRobert Watson #ifdef MAC
245b998d381SEdward Tomasz Napierala 	error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl);
246c86ca022SRobert Watson 	if (error != 0)
247b998d381SEdward Tomasz Napierala 		goto out_unlock;
248c86ca022SRobert Watson #endif
249ae1add4eSEdward Tomasz Napierala 	error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
250ae1add4eSEdward Tomasz Napierala 	    td->td_ucred, td);
251c86ca022SRobert Watson #ifdef MAC
252b998d381SEdward Tomasz Napierala out_unlock:
253c86ca022SRobert Watson #endif
254b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
2554e1123c7SRobert Watson 	vn_finished_write(mp);
256b998d381SEdward Tomasz Napierala out:
257b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
25891f37dcbSRobert Watson 	return (error);
25991f37dcbSRobert Watson }
26091f37dcbSRobert Watson 
26191f37dcbSRobert Watson /*
26291f37dcbSRobert Watson  * Given a vnode, get its ACL.
26391f37dcbSRobert Watson  */
26491f37dcbSRobert Watson static int
265b40ce416SJulian Elischer vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
26691f37dcbSRobert Watson     struct acl *aclp)
26791f37dcbSRobert Watson {
268b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
26991f37dcbSRobert Watson 	int error;
27091f37dcbSRobert Watson 
271f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
27223c053d6SSergey Kandaurov 	inkernelacl = acl_alloc(M_WAITOK | M_ZERO);
273cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
274f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
275c86ca022SRobert Watson #ifdef MAC
27630d239bcSRobert Watson 	error = mac_vnode_check_getacl(td->td_ucred, vp, type);
277c86ca022SRobert Watson 	if (error != 0)
278c86ca022SRobert Watson 		goto out;
279c86ca022SRobert Watson #endif
280ae1add4eSEdward Tomasz Napierala 	error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
281ae1add4eSEdward Tomasz Napierala 	    td->td_ucred, td);
282ae1add4eSEdward Tomasz Napierala 
283c86ca022SRobert Watson #ifdef MAC
284c86ca022SRobert Watson out:
285c86ca022SRobert Watson #endif
286b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
28791f37dcbSRobert Watson 	if (error == 0)
288ae1add4eSEdward Tomasz Napierala 		error = acl_copyout(inkernelacl, aclp, type);
289b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
29091f37dcbSRobert Watson 	return (error);
29191f37dcbSRobert Watson }
29291f37dcbSRobert Watson 
29391f37dcbSRobert Watson /*
29491f37dcbSRobert Watson  * Given a vnode, delete its ACL.
29591f37dcbSRobert Watson  */
29691f37dcbSRobert Watson static int
297b40ce416SJulian Elischer vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
29891f37dcbSRobert Watson {
2994e1123c7SRobert Watson 	struct mount *mp;
30091f37dcbSRobert Watson 	int error;
30191f37dcbSRobert Watson 
302f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
303a75d1dddSMateusz Guzik 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
304da9ce28eSEdward Tomasz Napierala 	if (error != 0)
3054e1123c7SRobert Watson 		return (error);
306cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
307f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
308c86ca022SRobert Watson #ifdef MAC
30930d239bcSRobert Watson 	error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
310da9ce28eSEdward Tomasz Napierala 	if (error != 0)
311c86ca022SRobert Watson 		goto out;
312c86ca022SRobert Watson #endif
313ae1add4eSEdward Tomasz Napierala 	error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
314c86ca022SRobert Watson #ifdef MAC
315c86ca022SRobert Watson out:
316c86ca022SRobert Watson #endif
317b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
3184e1123c7SRobert Watson 	vn_finished_write(mp);
31991f37dcbSRobert Watson 	return (error);
32091f37dcbSRobert Watson }
32191f37dcbSRobert Watson 
32291f37dcbSRobert Watson /*
32391f37dcbSRobert Watson  * Given a vnode, check whether an ACL is appropriate for it
324f9070809SRobert Watson  *
325f9070809SRobert Watson  * XXXRW: No vnode lock held so can't audit vnode state...?
32691f37dcbSRobert Watson  */
32791f37dcbSRobert Watson static int
328b40ce416SJulian Elischer vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
329aff4f2d3SBrooks Davis     const struct acl *aclp)
33091f37dcbSRobert Watson {
331b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
33291f37dcbSRobert Watson 	int error;
33391f37dcbSRobert Watson 
334b998d381SEdward Tomasz Napierala 	inkernelacl = acl_alloc(M_WAITOK);
335ae1add4eSEdward Tomasz Napierala 	error = acl_copyin(aclp, inkernelacl, type);
336da9ce28eSEdward Tomasz Napierala 	if (error != 0)
337b998d381SEdward Tomasz Napierala 		goto out;
3386bb58cddSEdward Tomasz Napierala 	error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl,
3396bb58cddSEdward Tomasz Napierala 	    td->td_ucred, td);
340b998d381SEdward Tomasz Napierala out:
341b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
34291f37dcbSRobert Watson 	return (error);
34391f37dcbSRobert Watson }
34491f37dcbSRobert Watson 
34591f37dcbSRobert Watson /*
346b0c521e2SRobert Watson  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
347b0c521e2SRobert Watson  * need to lock, as the vacl_ code will get/release any locks required.
34891f37dcbSRobert Watson  */
34991f37dcbSRobert Watson 
35091f37dcbSRobert Watson /*
35191f37dcbSRobert Watson  * Given a file path, get an ACL for it
35291f37dcbSRobert Watson  */
35391f37dcbSRobert Watson int
3548451d0ddSKip Macy sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
35591f37dcbSRobert Watson {
35691f37dcbSRobert Watson 
357aff4f2d3SBrooks Davis 	return (kern___acl_get_path(td, uap->path, uap->type, uap->aclp,
358aff4f2d3SBrooks Davis 	    FOLLOW));
35991f37dcbSRobert Watson }
36091f37dcbSRobert Watson 
36191f37dcbSRobert Watson /*
3623c67c23bSRobert Watson  * Given a file path, get an ACL for it; don't follow links.
3633c67c23bSRobert Watson  */
3643c67c23bSRobert Watson int
3658451d0ddSKip Macy sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
3663c67c23bSRobert Watson {
367aff4f2d3SBrooks Davis 
368aff4f2d3SBrooks Davis 	return(kern___acl_get_path(td, uap->path, uap->type, uap->aclp,
369aff4f2d3SBrooks Davis 	    NOFOLLOW));
370aff4f2d3SBrooks Davis }
371aff4f2d3SBrooks Davis 
372aff4f2d3SBrooks Davis static int
373aff4f2d3SBrooks Davis kern___acl_get_path(struct thread *td, const char *path, acl_type_t type,
374aff4f2d3SBrooks Davis     struct acl *aclp, int follow)
375aff4f2d3SBrooks Davis {
3763c67c23bSRobert Watson 	struct nameidata nd;
3775050aa86SKonstantin Belousov 	int error;
3783c67c23bSRobert Watson 
3797e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path);
3803c67c23bSRobert Watson 	error = namei(&nd);
3813c67c23bSRobert Watson 	if (error == 0) {
382aff4f2d3SBrooks Davis 		error = vacl_get_acl(td, nd.ni_vp, type, aclp);
383*85dac03eSMateusz Guzik 		vrele(nd.ni_vp);
384*85dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
3853c67c23bSRobert Watson 	}
3863c67c23bSRobert Watson 	return (error);
3873c67c23bSRobert Watson }
3883c67c23bSRobert Watson 
3893c67c23bSRobert Watson /*
3900c14ff0eSRobert Watson  * Given a file path, set an ACL for it.
39191f37dcbSRobert Watson  */
39291f37dcbSRobert Watson int
3938451d0ddSKip Macy sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
39491f37dcbSRobert Watson {
39591f37dcbSRobert Watson 
396aff4f2d3SBrooks Davis 	return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp,
397aff4f2d3SBrooks Davis 	    FOLLOW));
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 {
406aff4f2d3SBrooks Davis 
407aff4f2d3SBrooks Davis 	return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp,
408aff4f2d3SBrooks Davis 	    NOFOLLOW));
409aff4f2d3SBrooks Davis }
410aff4f2d3SBrooks Davis 
411aff4f2d3SBrooks Davis static int
412aff4f2d3SBrooks Davis kern___acl_set_path(struct thread *td, const char *path,
413aff4f2d3SBrooks Davis     acl_type_t type, const struct acl *aclp, int follow)
414aff4f2d3SBrooks Davis {
4153c67c23bSRobert Watson 	struct nameidata nd;
4165050aa86SKonstantin Belousov 	int error;
4173c67c23bSRobert Watson 
4187e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path);
4193c67c23bSRobert Watson 	error = namei(&nd);
4203c67c23bSRobert Watson 	if (error == 0) {
421aff4f2d3SBrooks Davis 		error = vacl_set_acl(td, nd.ni_vp, type, aclp);
422*85dac03eSMateusz Guzik 		vrele(nd.ni_vp);
423*85dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
4243c67c23bSRobert Watson 	}
4253c67c23bSRobert Watson 	return (error);
4263c67c23bSRobert Watson }
4273c67c23bSRobert Watson 
4283c67c23bSRobert Watson /*
429b5368498SRobert Watson  * Given a file descriptor, get an ACL for it.
43091f37dcbSRobert Watson  */
43191f37dcbSRobert Watson int
4328451d0ddSKip Macy sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
43391f37dcbSRobert Watson {
43491f37dcbSRobert Watson 	struct file *fp;
4357008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
4365050aa86SKonstantin Belousov 	int error;
43791f37dcbSRobert Watson 
438f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
4394da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
440e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_ACL_GET), &fp);
441f708f4d1SMatthew Dillon 	if (error == 0) {
4423b6d9652SPoul-Henning Kamp 		error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
443426da3bcSAlfred Perlstein 		fdrop(fp, td);
444f708f4d1SMatthew Dillon 	}
44591f37dcbSRobert Watson 	return (error);
44691f37dcbSRobert Watson }
44791f37dcbSRobert Watson 
44891f37dcbSRobert Watson /*
449b5368498SRobert Watson  * Given a file descriptor, set an ACL for it.
45091f37dcbSRobert Watson  */
45191f37dcbSRobert Watson int
4528451d0ddSKip Macy sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
45391f37dcbSRobert Watson {
45491f37dcbSRobert Watson 	struct file *fp;
4557008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
4565050aa86SKonstantin Belousov 	int error;
45791f37dcbSRobert Watson 
458f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
4594da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
460e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_ACL_SET), &fp);
461f708f4d1SMatthew Dillon 	if (error == 0) {
4623b6d9652SPoul-Henning Kamp 		error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
463426da3bcSAlfred Perlstein 		fdrop(fp, td);
464f708f4d1SMatthew Dillon 	}
46591f37dcbSRobert Watson 	return (error);
46691f37dcbSRobert Watson }
46791f37dcbSRobert Watson 
46891f37dcbSRobert Watson /*
46991f37dcbSRobert Watson  * Given a file path, delete an ACL from it.
47091f37dcbSRobert Watson  */
47191f37dcbSRobert Watson int
4728451d0ddSKip Macy sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
47391f37dcbSRobert Watson {
47491f37dcbSRobert Watson 
475aff4f2d3SBrooks Davis 	return (kern___acl_delete_path(td, uap->path, uap->type, FOLLOW));
47691f37dcbSRobert Watson }
47791f37dcbSRobert Watson 
47891f37dcbSRobert Watson /*
4793c67c23bSRobert Watson  * Given a file path, delete an ACL from it; don't follow links.
4803c67c23bSRobert Watson  */
4813c67c23bSRobert Watson int
4828451d0ddSKip Macy sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
4833c67c23bSRobert Watson {
484aff4f2d3SBrooks Davis 
485aff4f2d3SBrooks Davis 	return (kern___acl_delete_path(td, uap->path, uap->type, NOFOLLOW));
486aff4f2d3SBrooks Davis }
487aff4f2d3SBrooks Davis 
488aff4f2d3SBrooks Davis static int
489aff4f2d3SBrooks Davis kern___acl_delete_path(struct thread *td, const char *path,
490aff4f2d3SBrooks Davis     acl_type_t type, int follow)
491aff4f2d3SBrooks Davis {
4923c67c23bSRobert Watson 	struct nameidata nd;
4935050aa86SKonstantin Belousov 	int error;
4943c67c23bSRobert Watson 
4957e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path);
4963c67c23bSRobert Watson 	error = namei(&nd);
4973c67c23bSRobert Watson 	if (error == 0) {
498aff4f2d3SBrooks Davis 		error = vacl_delete(td, nd.ni_vp, type);
499*85dac03eSMateusz Guzik 		vrele(nd.ni_vp);
500*85dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
5013c67c23bSRobert Watson 	}
5023c67c23bSRobert Watson 	return (error);
5033c67c23bSRobert Watson }
5043c67c23bSRobert Watson 
5053c67c23bSRobert Watson /*
50691f37dcbSRobert Watson  * Given a file path, delete an ACL from it.
50791f37dcbSRobert Watson  */
50891f37dcbSRobert Watson int
5098451d0ddSKip Macy sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
51091f37dcbSRobert Watson {
51191f37dcbSRobert Watson 	struct file *fp;
5127008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
5135050aa86SKonstantin Belousov 	int error;
51491f37dcbSRobert Watson 
515f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
5164da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
517e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_ACL_DELETE), &fp);
518f708f4d1SMatthew Dillon 	if (error == 0) {
5193b6d9652SPoul-Henning Kamp 		error = vacl_delete(td, fp->f_vnode, uap->type);
520426da3bcSAlfred Perlstein 		fdrop(fp, td);
521f708f4d1SMatthew Dillon 	}
52291f37dcbSRobert Watson 	return (error);
52391f37dcbSRobert Watson }
52491f37dcbSRobert Watson 
52591f37dcbSRobert Watson /*
5260c14ff0eSRobert Watson  * Given a file path, check an ACL for it.
52791f37dcbSRobert Watson  */
52891f37dcbSRobert Watson int
5298451d0ddSKip Macy sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
53091f37dcbSRobert Watson {
53191f37dcbSRobert Watson 
532aff4f2d3SBrooks Davis 	return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
533aff4f2d3SBrooks Davis 	    FOLLOW));
53491f37dcbSRobert Watson }
53591f37dcbSRobert Watson 
53691f37dcbSRobert Watson /*
5373c67c23bSRobert Watson  * Given a file path, check an ACL for it; don't follow links.
5383c67c23bSRobert Watson  */
5393c67c23bSRobert Watson int
5408451d0ddSKip Macy sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
5413c67c23bSRobert Watson {
542aff4f2d3SBrooks Davis 	return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
543aff4f2d3SBrooks Davis 	    NOFOLLOW));
544aff4f2d3SBrooks Davis }
545aff4f2d3SBrooks Davis 
546aff4f2d3SBrooks Davis static int
547aff4f2d3SBrooks Davis kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type,
548aff4f2d3SBrooks Davis     struct acl *aclp, int follow)
549aff4f2d3SBrooks Davis {
5507a172809SEdward Tomasz Napierala 	struct nameidata nd;
5515050aa86SKonstantin Belousov 	int error;
5523c67c23bSRobert Watson 
5537e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path);
5543c67c23bSRobert Watson 	error = namei(&nd);
5553c67c23bSRobert Watson 	if (error == 0) {
556aff4f2d3SBrooks Davis 		error = vacl_aclcheck(td, nd.ni_vp, type, aclp);
557*85dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
5583c67c23bSRobert Watson 	}
5593c67c23bSRobert Watson 	return (error);
5603c67c23bSRobert Watson }
5613c67c23bSRobert Watson 
5623c67c23bSRobert Watson /*
5630c14ff0eSRobert Watson  * Given a file descriptor, check an ACL for it.
56491f37dcbSRobert Watson  */
56591f37dcbSRobert Watson int
5668451d0ddSKip Macy sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
56791f37dcbSRobert Watson {
56891f37dcbSRobert Watson 	struct file *fp;
5697008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
5705050aa86SKonstantin Belousov 	int error;
57191f37dcbSRobert Watson 
572f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
5734da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
574e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_ACL_CHECK), &fp);
575f708f4d1SMatthew Dillon 	if (error == 0) {
5763b6d9652SPoul-Henning Kamp 		error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
577426da3bcSAlfred Perlstein 		fdrop(fp, td);
578f708f4d1SMatthew Dillon 	}
57991f37dcbSRobert Watson 	return (error);
58091f37dcbSRobert Watson }
581d1dfd921SChristian S.J. Peron 
582b998d381SEdward Tomasz Napierala struct acl *
583b998d381SEdward Tomasz Napierala acl_alloc(int flags)
584b998d381SEdward Tomasz Napierala {
585b998d381SEdward Tomasz Napierala 	struct acl *aclp;
586b998d381SEdward Tomasz Napierala 
587e0ee7589SEdward Tomasz Napierala 	aclp = malloc(sizeof(*aclp), M_ACL, flags);
5888ddc3590SEdward Tomasz Napierala 	if (aclp == NULL)
5898ddc3590SEdward Tomasz Napierala 		return (NULL);
5908ddc3590SEdward Tomasz Napierala 
591ae1add4eSEdward Tomasz Napierala 	aclp->acl_maxcnt = ACL_MAX_ENTRIES;
592b998d381SEdward Tomasz Napierala 
593b998d381SEdward Tomasz Napierala 	return (aclp);
594b998d381SEdward Tomasz Napierala }
595b998d381SEdward Tomasz Napierala 
596b998d381SEdward Tomasz Napierala void
597b998d381SEdward Tomasz Napierala acl_free(struct acl *aclp)
598b998d381SEdward Tomasz Napierala {
599b998d381SEdward Tomasz Napierala 
600e0ee7589SEdward Tomasz Napierala 	free(aclp, M_ACL);
601b998d381SEdward Tomasz Napierala }
602