xref: /freebsd/sys/kern/vfs_acl.c (revision b249ce48ea5560afdcff57e72a9880b7d3132434)
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/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 
70aff4f2d3SBrooks Davis 
71aff4f2d3SBrooks Davis static int	kern___acl_aclcheck_path(struct thread *td, const char *path,
72aff4f2d3SBrooks Davis 		    acl_type_t type, struct acl *aclp, int follow);
73aff4f2d3SBrooks Davis static int	kern___acl_delete_path(struct thread *td, const char *path,
74aff4f2d3SBrooks Davis 		    acl_type_t type, int follow);
75aff4f2d3SBrooks Davis static int	kern___acl_get_path(struct thread *td, const char *path,
76aff4f2d3SBrooks Davis 		    acl_type_t type, struct acl *aclp, int follow);
77aff4f2d3SBrooks Davis static int	kern___acl_set_path(struct thread *td, const char *path,
78aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp, int follow);
79cbeb8402SRobert Watson static int	vacl_set_acl(struct thread *td, struct vnode *vp,
80aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp);
81cbeb8402SRobert Watson static int	vacl_get_acl(struct thread *td, struct vnode *vp,
82cbeb8402SRobert Watson 		    acl_type_t type, struct acl *aclp);
83b40ce416SJulian Elischer static int	vacl_aclcheck(struct thread *td, struct vnode *vp,
84aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp);
8591f37dcbSRobert Watson 
86ae1add4eSEdward Tomasz Napierala int
87ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
88ae1add4eSEdward Tomasz Napierala {
89ae1add4eSEdward Tomasz Napierala 	int i;
90ae1add4eSEdward Tomasz Napierala 
91ae1add4eSEdward Tomasz Napierala 	if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
92ae1add4eSEdward Tomasz Napierala 		return (EINVAL);
93ae1add4eSEdward Tomasz Napierala 
94ae1add4eSEdward Tomasz Napierala 	bzero(dest, sizeof(*dest));
95ae1add4eSEdward Tomasz Napierala 
96ae1add4eSEdward Tomasz Napierala 	dest->acl_cnt = source->acl_cnt;
97ae1add4eSEdward Tomasz Napierala 	dest->acl_maxcnt = ACL_MAX_ENTRIES;
98ae1add4eSEdward Tomasz Napierala 
99ae1add4eSEdward Tomasz Napierala 	for (i = 0; i < dest->acl_cnt; i++) {
100ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
101ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
102ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
103ae1add4eSEdward Tomasz Napierala 	}
104ae1add4eSEdward Tomasz Napierala 
105ae1add4eSEdward Tomasz Napierala 	return (0);
106ae1add4eSEdward Tomasz Napierala }
107ae1add4eSEdward Tomasz Napierala 
108ae1add4eSEdward Tomasz Napierala int
109ae1add4eSEdward Tomasz Napierala acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
110ae1add4eSEdward Tomasz Napierala {
111ae1add4eSEdward Tomasz Napierala 	int i;
112ae1add4eSEdward Tomasz Napierala 
113ce9d79aaSEdward Tomasz Napierala 	if (source->acl_cnt > OLDACL_MAX_ENTRIES)
114ae1add4eSEdward Tomasz Napierala 		return (EINVAL);
115ae1add4eSEdward Tomasz Napierala 
116ae1add4eSEdward Tomasz Napierala 	bzero(dest, sizeof(*dest));
117ae1add4eSEdward Tomasz Napierala 
118ae1add4eSEdward Tomasz Napierala 	dest->acl_cnt = source->acl_cnt;
119ae1add4eSEdward Tomasz Napierala 
120ae1add4eSEdward Tomasz Napierala 	for (i = 0; i < dest->acl_cnt; i++) {
121ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
122ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
123ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
124ae1add4eSEdward Tomasz Napierala 	}
125ae1add4eSEdward Tomasz Napierala 
126ae1add4eSEdward Tomasz Napierala 	return (0);
127ae1add4eSEdward Tomasz Napierala }
128ae1add4eSEdward Tomasz Napierala 
129ae1add4eSEdward Tomasz Napierala /*
130ae1add4eSEdward Tomasz Napierala  * At one time, "struct ACL" was extended in order to add support for NFSv4
131ae1add4eSEdward Tomasz Napierala  * ACLs.  Instead of creating compatibility versions of all the ACL-related
132ae1add4eSEdward Tomasz Napierala  * syscalls, they were left intact.  It's possible to find out what the code
133ae1add4eSEdward Tomasz Napierala  * calling these syscalls (libc) expects basing on "type" argument - if it's
134ae1add4eSEdward Tomasz Napierala  * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
135ae1add4eSEdward Tomasz Napierala  * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
136ae1add4eSEdward Tomasz Napierala  * oldacl".  If it's something else, then it's the new "struct acl".  In the
137ae1add4eSEdward Tomasz Napierala  * latter case, the routines below just copyin/copyout the contents.  In the
138ae1add4eSEdward Tomasz Napierala  * former case, they copyin the "struct oldacl" and convert it to the new
139ae1add4eSEdward Tomasz Napierala  * format.
140ae1add4eSEdward Tomasz Napierala  */
141ae1add4eSEdward Tomasz Napierala static int
142aff4f2d3SBrooks Davis acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type)
143ae1add4eSEdward Tomasz Napierala {
144ae1add4eSEdward Tomasz Napierala 	int error;
145ae1add4eSEdward Tomasz Napierala 	struct oldacl old;
146ae1add4eSEdward Tomasz Napierala 
147ae1add4eSEdward Tomasz Napierala 	switch (type) {
148ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
149ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
150ae1add4eSEdward Tomasz Napierala 		error = copyin(user_acl, &old, sizeof(old));
151ae1add4eSEdward Tomasz Napierala 		if (error != 0)
152ae1add4eSEdward Tomasz Napierala 			break;
153ae1add4eSEdward Tomasz Napierala 		acl_copy_oldacl_into_acl(&old, kernel_acl);
154ae1add4eSEdward Tomasz Napierala 		break;
155ae1add4eSEdward Tomasz Napierala 
156ae1add4eSEdward Tomasz Napierala 	default:
157ae1add4eSEdward Tomasz Napierala 		error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
158ae1add4eSEdward Tomasz Napierala 		if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
159ae1add4eSEdward Tomasz Napierala 			return (EINVAL);
160ae1add4eSEdward Tomasz Napierala 	}
161ae1add4eSEdward Tomasz Napierala 
162ae1add4eSEdward Tomasz Napierala 	return (error);
163ae1add4eSEdward Tomasz Napierala }
164ae1add4eSEdward Tomasz Napierala 
165ae1add4eSEdward Tomasz Napierala static int
166aff4f2d3SBrooks Davis acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type)
167ae1add4eSEdward Tomasz Napierala {
1680a2c94b8SKonstantin Belousov 	uint32_t am;
169ae1add4eSEdward Tomasz Napierala 	int error;
170ae1add4eSEdward Tomasz Napierala 	struct oldacl old;
171ae1add4eSEdward Tomasz Napierala 
172ae1add4eSEdward Tomasz Napierala 	switch (type) {
173ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
174ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
175ae1add4eSEdward Tomasz Napierala 		error = acl_copy_acl_into_oldacl(kernel_acl, &old);
176ae1add4eSEdward Tomasz Napierala 		if (error != 0)
177ae1add4eSEdward Tomasz Napierala 			break;
178ae1add4eSEdward Tomasz Napierala 
179ae1add4eSEdward Tomasz Napierala 		error = copyout(&old, user_acl, sizeof(old));
180ae1add4eSEdward Tomasz Napierala 		break;
181ae1add4eSEdward Tomasz Napierala 
182ae1add4eSEdward Tomasz Napierala 	default:
1830a2c94b8SKonstantin Belousov 		error = fueword32((char *)user_acl +
1840a2c94b8SKonstantin Belousov 		    offsetof(struct acl, acl_maxcnt), &am);
1850a2c94b8SKonstantin Belousov 		if (error == -1)
1860a2c94b8SKonstantin Belousov 			return (EFAULT);
1870a2c94b8SKonstantin Belousov 		if (am != ACL_MAX_ENTRIES)
188ae1add4eSEdward Tomasz Napierala 			return (EINVAL);
189ae1add4eSEdward Tomasz Napierala 
190ae1add4eSEdward Tomasz Napierala 		error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
191ae1add4eSEdward Tomasz Napierala 	}
192ae1add4eSEdward Tomasz Napierala 
193ae1add4eSEdward Tomasz Napierala 	return (error);
194ae1add4eSEdward Tomasz Napierala }
195ae1add4eSEdward Tomasz Napierala 
196ae1add4eSEdward Tomasz Napierala /*
197ae1add4eSEdward Tomasz Napierala  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
1986bb58cddSEdward Tomasz Napierala  * counterpart.  It's required for old (pre-NFSv4 ACLs) libc to work
199ae1add4eSEdward Tomasz Napierala  * with new kernel.  Fixing 'type' for old binaries with new libc
200ae1add4eSEdward Tomasz Napierala  * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
201ae1add4eSEdward Tomasz Napierala  */
202ae1add4eSEdward Tomasz Napierala static int
203ae1add4eSEdward Tomasz Napierala acl_type_unold(int type)
204ae1add4eSEdward Tomasz Napierala {
205ae1add4eSEdward Tomasz Napierala 	switch (type) {
206ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
207ae1add4eSEdward Tomasz Napierala 		return (ACL_TYPE_ACCESS);
208ae1add4eSEdward Tomasz Napierala 
209ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
210ae1add4eSEdward Tomasz Napierala 		return (ACL_TYPE_DEFAULT);
211ae1add4eSEdward Tomasz Napierala 
212ae1add4eSEdward Tomasz Napierala 	default:
213ae1add4eSEdward Tomasz Napierala 		return (type);
214ae1add4eSEdward Tomasz Napierala 	}
215ae1add4eSEdward Tomasz Napierala }
216ae1add4eSEdward Tomasz Napierala 
21791f37dcbSRobert Watson /*
218b0c521e2SRobert Watson  * These calls wrap the real vnode operations, and are called by the syscall
219b0c521e2SRobert Watson  * code once the syscall has converted the path or file descriptor to a vnode
220b0c521e2SRobert Watson  * (unlocked).  The aclp pointer is assumed still to point to userland, so
221b0c521e2SRobert Watson  * this should not be consumed within the kernel except by syscall code.
222b0c521e2SRobert Watson  * Other code should directly invoke VOP_{SET,GET}ACL.
22391f37dcbSRobert Watson  */
22491f37dcbSRobert Watson 
22591f37dcbSRobert Watson /*
22691f37dcbSRobert Watson  * Given a vnode, set its ACL.
22791f37dcbSRobert Watson  */
22891f37dcbSRobert Watson static int
229b40ce416SJulian Elischer vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
230aff4f2d3SBrooks Davis     const struct acl *aclp)
23191f37dcbSRobert Watson {
232b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
2334e1123c7SRobert Watson 	struct mount *mp;
23491f37dcbSRobert Watson 	int error;
23591f37dcbSRobert Watson 
236f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
237b998d381SEdward Tomasz Napierala 	inkernelacl = acl_alloc(M_WAITOK);
238ae1add4eSEdward Tomasz Napierala 	error = acl_copyin(aclp, inkernelacl, type);
239da9ce28eSEdward Tomasz Napierala 	if (error != 0)
240b998d381SEdward Tomasz Napierala 		goto out;
2414e1123c7SRobert Watson 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
2424e1123c7SRobert Watson 	if (error != 0)
243b998d381SEdward Tomasz Napierala 		goto out;
244cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
245f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
246c86ca022SRobert Watson #ifdef MAC
247b998d381SEdward Tomasz Napierala 	error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl);
248c86ca022SRobert Watson 	if (error != 0)
249b998d381SEdward Tomasz Napierala 		goto out_unlock;
250c86ca022SRobert Watson #endif
251ae1add4eSEdward Tomasz Napierala 	error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
252ae1add4eSEdward Tomasz Napierala 	    td->td_ucred, td);
253c86ca022SRobert Watson #ifdef MAC
254b998d381SEdward Tomasz Napierala out_unlock:
255c86ca022SRobert Watson #endif
256*b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
2574e1123c7SRobert Watson 	vn_finished_write(mp);
258b998d381SEdward Tomasz Napierala out:
259b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
26091f37dcbSRobert Watson 	return (error);
26191f37dcbSRobert Watson }
26291f37dcbSRobert Watson 
26391f37dcbSRobert Watson /*
26491f37dcbSRobert Watson  * Given a vnode, get its ACL.
26591f37dcbSRobert Watson  */
26691f37dcbSRobert Watson static int
267b40ce416SJulian Elischer vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
26891f37dcbSRobert Watson     struct acl *aclp)
26991f37dcbSRobert Watson {
270b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
27191f37dcbSRobert Watson 	int error;
27291f37dcbSRobert Watson 
273f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
27423c053d6SSergey Kandaurov 	inkernelacl = acl_alloc(M_WAITOK | M_ZERO);
275cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
276f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
277c86ca022SRobert Watson #ifdef MAC
27830d239bcSRobert Watson 	error = mac_vnode_check_getacl(td->td_ucred, vp, type);
279c86ca022SRobert Watson 	if (error != 0)
280c86ca022SRobert Watson 		goto out;
281c86ca022SRobert Watson #endif
282ae1add4eSEdward Tomasz Napierala 	error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
283ae1add4eSEdward Tomasz Napierala 	    td->td_ucred, td);
284ae1add4eSEdward Tomasz Napierala 
285c86ca022SRobert Watson #ifdef MAC
286c86ca022SRobert Watson out:
287c86ca022SRobert Watson #endif
288*b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
28991f37dcbSRobert Watson 	if (error == 0)
290ae1add4eSEdward Tomasz Napierala 		error = acl_copyout(inkernelacl, aclp, type);
291b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
29291f37dcbSRobert Watson 	return (error);
29391f37dcbSRobert Watson }
29491f37dcbSRobert Watson 
29591f37dcbSRobert Watson /*
29691f37dcbSRobert Watson  * Given a vnode, delete its ACL.
29791f37dcbSRobert Watson  */
29891f37dcbSRobert Watson static int
299b40ce416SJulian Elischer vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
30091f37dcbSRobert Watson {
3014e1123c7SRobert Watson 	struct mount *mp;
30291f37dcbSRobert Watson 	int error;
30391f37dcbSRobert Watson 
304f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
3054e1123c7SRobert Watson 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
306da9ce28eSEdward Tomasz Napierala 	if (error != 0)
3074e1123c7SRobert Watson 		return (error);
308cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
309f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
310c86ca022SRobert Watson #ifdef MAC
31130d239bcSRobert Watson 	error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
312da9ce28eSEdward Tomasz Napierala 	if (error != 0)
313c86ca022SRobert Watson 		goto out;
314c86ca022SRobert Watson #endif
315ae1add4eSEdward Tomasz Napierala 	error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
316c86ca022SRobert Watson #ifdef MAC
317c86ca022SRobert Watson out:
318c86ca022SRobert Watson #endif
319*b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
3204e1123c7SRobert Watson 	vn_finished_write(mp);
32191f37dcbSRobert Watson 	return (error);
32291f37dcbSRobert Watson }
32391f37dcbSRobert Watson 
32491f37dcbSRobert Watson /*
32591f37dcbSRobert Watson  * Given a vnode, check whether an ACL is appropriate for it
326f9070809SRobert Watson  *
327f9070809SRobert Watson  * XXXRW: No vnode lock held so can't audit vnode state...?
32891f37dcbSRobert Watson  */
32991f37dcbSRobert Watson static int
330b40ce416SJulian Elischer vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
331aff4f2d3SBrooks Davis     const struct acl *aclp)
33291f37dcbSRobert Watson {
333b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
33491f37dcbSRobert Watson 	int error;
33591f37dcbSRobert Watson 
336b998d381SEdward Tomasz Napierala 	inkernelacl = acl_alloc(M_WAITOK);
337ae1add4eSEdward Tomasz Napierala 	error = acl_copyin(aclp, inkernelacl, type);
338da9ce28eSEdward Tomasz Napierala 	if (error != 0)
339b998d381SEdward Tomasz Napierala 		goto out;
3406bb58cddSEdward Tomasz Napierala 	error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl,
3416bb58cddSEdward Tomasz Napierala 	    td->td_ucred, td);
342b998d381SEdward Tomasz Napierala out:
343b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
34491f37dcbSRobert Watson 	return (error);
34591f37dcbSRobert Watson }
34691f37dcbSRobert Watson 
34791f37dcbSRobert Watson /*
348b0c521e2SRobert Watson  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
349b0c521e2SRobert Watson  * need to lock, as the vacl_ code will get/release any locks required.
35091f37dcbSRobert Watson  */
35191f37dcbSRobert Watson 
35291f37dcbSRobert Watson /*
35391f37dcbSRobert Watson  * Given a file path, get an ACL for it
35491f37dcbSRobert Watson  */
35591f37dcbSRobert Watson int
3568451d0ddSKip Macy sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
35791f37dcbSRobert Watson {
35891f37dcbSRobert Watson 
359aff4f2d3SBrooks Davis 	return (kern___acl_get_path(td, uap->path, uap->type, uap->aclp,
360aff4f2d3SBrooks Davis 	    FOLLOW));
36191f37dcbSRobert Watson }
36291f37dcbSRobert Watson 
36391f37dcbSRobert Watson /*
3643c67c23bSRobert Watson  * Given a file path, get an ACL for it; don't follow links.
3653c67c23bSRobert Watson  */
3663c67c23bSRobert Watson int
3678451d0ddSKip Macy sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
3683c67c23bSRobert Watson {
369aff4f2d3SBrooks Davis 
370aff4f2d3SBrooks Davis 	return(kern___acl_get_path(td, uap->path, uap->type, uap->aclp,
371aff4f2d3SBrooks Davis 	    NOFOLLOW));
372aff4f2d3SBrooks Davis }
373aff4f2d3SBrooks Davis 
374aff4f2d3SBrooks Davis static int
375aff4f2d3SBrooks Davis kern___acl_get_path(struct thread *td, const char *path, acl_type_t type,
376aff4f2d3SBrooks Davis     struct acl *aclp, int follow)
377aff4f2d3SBrooks Davis {
3783c67c23bSRobert Watson 	struct nameidata nd;
3795050aa86SKonstantin Belousov 	int error;
3803c67c23bSRobert Watson 
381aff4f2d3SBrooks Davis 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td);
3823c67c23bSRobert Watson 	error = namei(&nd);
3833c67c23bSRobert Watson 	if (error == 0) {
384aff4f2d3SBrooks Davis 		error = vacl_get_acl(td, nd.ni_vp, type, aclp);
3853c67c23bSRobert Watson 		NDFREE(&nd, 0);
3863c67c23bSRobert Watson 	}
3873c67c23bSRobert Watson 	return (error);
3883c67c23bSRobert Watson }
3893c67c23bSRobert Watson 
3903c67c23bSRobert Watson /*
3910c14ff0eSRobert Watson  * Given a file path, set an ACL for it.
39291f37dcbSRobert Watson  */
39391f37dcbSRobert Watson int
3948451d0ddSKip Macy sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
39591f37dcbSRobert Watson {
39691f37dcbSRobert Watson 
397aff4f2d3SBrooks Davis 	return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp,
398aff4f2d3SBrooks Davis 	    FOLLOW));
39991f37dcbSRobert Watson }
40091f37dcbSRobert Watson 
40191f37dcbSRobert Watson /*
4023c67c23bSRobert Watson  * Given a file path, set an ACL for it; don't follow links.
4033c67c23bSRobert Watson  */
4043c67c23bSRobert Watson int
4058451d0ddSKip Macy sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
4063c67c23bSRobert Watson {
407aff4f2d3SBrooks Davis 
408aff4f2d3SBrooks Davis 	return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp,
409aff4f2d3SBrooks Davis 	    NOFOLLOW));
410aff4f2d3SBrooks Davis }
411aff4f2d3SBrooks Davis 
412aff4f2d3SBrooks Davis static int
413aff4f2d3SBrooks Davis kern___acl_set_path(struct thread *td, const char *path,
414aff4f2d3SBrooks Davis     acl_type_t type, const struct acl *aclp, int follow)
415aff4f2d3SBrooks Davis {
4163c67c23bSRobert Watson 	struct nameidata nd;
4175050aa86SKonstantin Belousov 	int error;
4183c67c23bSRobert Watson 
419aff4f2d3SBrooks Davis 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td);
4203c67c23bSRobert Watson 	error = namei(&nd);
4213c67c23bSRobert Watson 	if (error == 0) {
422aff4f2d3SBrooks Davis 		error = vacl_set_acl(td, nd.ni_vp, type, aclp);
4233c67c23bSRobert Watson 		NDFREE(&nd, 0);
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,
4407008be5bSPawel Jakub Dawidek 	    cap_rights_init(&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,
4607008be5bSPawel Jakub Dawidek 	    cap_rights_init(&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 
495aff4f2d3SBrooks Davis 	NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path, td);
4963c67c23bSRobert Watson 	error = namei(&nd);
4973c67c23bSRobert Watson 	if (error == 0) {
498aff4f2d3SBrooks Davis 		error = vacl_delete(td, nd.ni_vp, type);
4993c67c23bSRobert Watson 		NDFREE(&nd, 0);
5003c67c23bSRobert Watson 	}
5013c67c23bSRobert Watson 	return (error);
5023c67c23bSRobert Watson }
5033c67c23bSRobert Watson 
5043c67c23bSRobert Watson /*
50591f37dcbSRobert Watson  * Given a file path, delete an ACL from it.
50691f37dcbSRobert Watson  */
50791f37dcbSRobert Watson int
5088451d0ddSKip Macy sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
50991f37dcbSRobert Watson {
51091f37dcbSRobert Watson 	struct file *fp;
5117008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
5125050aa86SKonstantin Belousov 	int error;
51391f37dcbSRobert Watson 
514f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
5154da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
5167008be5bSPawel Jakub Dawidek 	    cap_rights_init(&rights, CAP_ACL_DELETE), &fp);
517f708f4d1SMatthew Dillon 	if (error == 0) {
5183b6d9652SPoul-Henning Kamp 		error = vacl_delete(td, fp->f_vnode, uap->type);
519426da3bcSAlfred Perlstein 		fdrop(fp, td);
520f708f4d1SMatthew Dillon 	}
52191f37dcbSRobert Watson 	return (error);
52291f37dcbSRobert Watson }
52391f37dcbSRobert Watson 
52491f37dcbSRobert Watson /*
5250c14ff0eSRobert Watson  * Given a file path, check an ACL for it.
52691f37dcbSRobert Watson  */
52791f37dcbSRobert Watson int
5288451d0ddSKip Macy sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
52991f37dcbSRobert Watson {
53091f37dcbSRobert Watson 
531aff4f2d3SBrooks Davis 	return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
532aff4f2d3SBrooks Davis 	    FOLLOW));
53391f37dcbSRobert Watson }
53491f37dcbSRobert Watson 
53591f37dcbSRobert Watson /*
5363c67c23bSRobert Watson  * Given a file path, check an ACL for it; don't follow links.
5373c67c23bSRobert Watson  */
5383c67c23bSRobert Watson int
5398451d0ddSKip Macy sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
5403c67c23bSRobert Watson {
541aff4f2d3SBrooks Davis 	return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
542aff4f2d3SBrooks Davis 	    NOFOLLOW));
543aff4f2d3SBrooks Davis }
544aff4f2d3SBrooks Davis 
545aff4f2d3SBrooks Davis static int
546aff4f2d3SBrooks Davis kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type,
547aff4f2d3SBrooks Davis     struct acl *aclp, int follow)
548aff4f2d3SBrooks Davis {
5497a172809SEdward Tomasz Napierala 	struct nameidata nd;
5505050aa86SKonstantin Belousov 	int error;
5513c67c23bSRobert Watson 
552aff4f2d3SBrooks Davis 	NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path, td);
5533c67c23bSRobert Watson 	error = namei(&nd);
5543c67c23bSRobert Watson 	if (error == 0) {
555aff4f2d3SBrooks Davis 		error = vacl_aclcheck(td, nd.ni_vp, type, aclp);
5563c67c23bSRobert Watson 		NDFREE(&nd, 0);
5573c67c23bSRobert Watson 	}
5583c67c23bSRobert Watson 	return (error);
5593c67c23bSRobert Watson }
5603c67c23bSRobert Watson 
5613c67c23bSRobert Watson /*
5620c14ff0eSRobert Watson  * Given a file descriptor, check an ACL for it.
56391f37dcbSRobert Watson  */
56491f37dcbSRobert Watson int
5658451d0ddSKip Macy sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
56691f37dcbSRobert Watson {
56791f37dcbSRobert Watson 	struct file *fp;
5687008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
5695050aa86SKonstantin Belousov 	int error;
57091f37dcbSRobert Watson 
571f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
5724da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
5737008be5bSPawel Jakub Dawidek 	    cap_rights_init(&rights, CAP_ACL_CHECK), &fp);
574f708f4d1SMatthew Dillon 	if (error == 0) {
5753b6d9652SPoul-Henning Kamp 		error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
576426da3bcSAlfred Perlstein 		fdrop(fp, td);
577f708f4d1SMatthew Dillon 	}
57891f37dcbSRobert Watson 	return (error);
57991f37dcbSRobert Watson }
580d1dfd921SChristian S.J. Peron 
581b998d381SEdward Tomasz Napierala struct acl *
582b998d381SEdward Tomasz Napierala acl_alloc(int flags)
583b998d381SEdward Tomasz Napierala {
584b998d381SEdward Tomasz Napierala 	struct acl *aclp;
585b998d381SEdward Tomasz Napierala 
586e0ee7589SEdward Tomasz Napierala 	aclp = malloc(sizeof(*aclp), M_ACL, flags);
5878ddc3590SEdward Tomasz Napierala 	if (aclp == NULL)
5888ddc3590SEdward Tomasz Napierala 		return (NULL);
5898ddc3590SEdward Tomasz Napierala 
590ae1add4eSEdward Tomasz Napierala 	aclp->acl_maxcnt = ACL_MAX_ENTRIES;
591b998d381SEdward Tomasz Napierala 
592b998d381SEdward Tomasz Napierala 	return (aclp);
593b998d381SEdward Tomasz Napierala }
594b998d381SEdward Tomasz Napierala 
595b998d381SEdward Tomasz Napierala void
596b998d381SEdward Tomasz Napierala acl_free(struct acl *aclp)
597b998d381SEdward Tomasz Napierala {
598b998d381SEdward Tomasz Napierala 
599e0ee7589SEdward Tomasz Napierala 	free(aclp, M_ACL);
600b998d381SEdward Tomasz Napierala }
601