xref: /freebsd/sys/kern/vfs_acl.c (revision fdafd315)
191f37dcbSRobert Watson /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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 
4291f37dcbSRobert Watson #include <sys/param.h>
4391f37dcbSRobert Watson #include <sys/systm.h>
4491f37dcbSRobert Watson #include <sys/sysproto.h>
454a144410SRobert Watson #include <sys/capsicum.h>
4657b4252eSKonstantin Belousov #include <sys/fcntl.h>
4791f37dcbSRobert Watson #include <sys/kernel.h>
4891f37dcbSRobert Watson #include <sys/malloc.h>
4942e7197fSChristian S.J. Peron #include <sys/mount.h>
5091f37dcbSRobert Watson #include <sys/vnode.h>
5191f37dcbSRobert Watson #include <sys/lock.h>
52f708f4d1SMatthew Dillon #include <sys/mutex.h>
5391f37dcbSRobert Watson #include <sys/namei.h>
5491f37dcbSRobert Watson #include <sys/file.h>
5513438f68SAlfred Perlstein #include <sys/filedesc.h>
5691f37dcbSRobert Watson #include <sys/proc.h>
5791f37dcbSRobert Watson #include <sys/acl.h>
5891f37dcbSRobert Watson 
59f9070809SRobert Watson #include <security/audit/audit.h>
60aed55708SRobert Watson #include <security/mac/mac_framework.h>
61aed55708SRobert Watson 
62ae1add4eSEdward Tomasz Napierala CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
63ae1add4eSEdward Tomasz Napierala 
64ae1add4eSEdward Tomasz Napierala MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
6591f37dcbSRobert Watson 
66aff4f2d3SBrooks Davis static int	kern___acl_aclcheck_path(struct thread *td, const char *path,
67aff4f2d3SBrooks Davis 		    acl_type_t type, struct acl *aclp, int follow);
68aff4f2d3SBrooks Davis static int	kern___acl_delete_path(struct thread *td, const char *path,
69aff4f2d3SBrooks Davis 		    acl_type_t type, int follow);
70aff4f2d3SBrooks Davis static int	kern___acl_get_path(struct thread *td, const char *path,
71aff4f2d3SBrooks Davis 		    acl_type_t type, struct acl *aclp, int follow);
72aff4f2d3SBrooks Davis static int	kern___acl_set_path(struct thread *td, const char *path,
73aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp, int follow);
74cbeb8402SRobert Watson static int	vacl_set_acl(struct thread *td, struct vnode *vp,
75aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp);
76cbeb8402SRobert Watson static int	vacl_get_acl(struct thread *td, struct vnode *vp,
77cbeb8402SRobert Watson 		    acl_type_t type, struct acl *aclp);
78b40ce416SJulian Elischer static int	vacl_aclcheck(struct thread *td, struct vnode *vp,
79aff4f2d3SBrooks Davis 		    acl_type_t type, const struct acl *aclp);
8091f37dcbSRobert Watson 
81ae1add4eSEdward Tomasz Napierala int
acl_copy_oldacl_into_acl(const struct oldacl * source,struct acl * dest)82ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
83ae1add4eSEdward Tomasz Napierala {
84ae1add4eSEdward Tomasz Napierala 	int i;
85ae1add4eSEdward Tomasz Napierala 
86ae1add4eSEdward Tomasz Napierala 	if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
87ae1add4eSEdward Tomasz Napierala 		return (EINVAL);
88ae1add4eSEdward Tomasz Napierala 
89ae1add4eSEdward Tomasz Napierala 	bzero(dest, sizeof(*dest));
90ae1add4eSEdward Tomasz Napierala 
91ae1add4eSEdward Tomasz Napierala 	dest->acl_cnt = source->acl_cnt;
92ae1add4eSEdward Tomasz Napierala 	dest->acl_maxcnt = ACL_MAX_ENTRIES;
93ae1add4eSEdward Tomasz Napierala 
94ae1add4eSEdward Tomasz Napierala 	for (i = 0; i < dest->acl_cnt; i++) {
95ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
96ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
97ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
98ae1add4eSEdward Tomasz Napierala 	}
99ae1add4eSEdward Tomasz Napierala 
100ae1add4eSEdward Tomasz Napierala 	return (0);
101ae1add4eSEdward Tomasz Napierala }
102ae1add4eSEdward Tomasz Napierala 
103ae1add4eSEdward Tomasz Napierala int
acl_copy_acl_into_oldacl(const struct acl * source,struct oldacl * dest)104ae1add4eSEdward Tomasz Napierala acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
105ae1add4eSEdward Tomasz Napierala {
106ae1add4eSEdward Tomasz Napierala 	int i;
107ae1add4eSEdward Tomasz Napierala 
108ce9d79aaSEdward Tomasz Napierala 	if (source->acl_cnt > OLDACL_MAX_ENTRIES)
109ae1add4eSEdward Tomasz Napierala 		return (EINVAL);
110ae1add4eSEdward Tomasz Napierala 
111ae1add4eSEdward Tomasz Napierala 	bzero(dest, sizeof(*dest));
112ae1add4eSEdward Tomasz Napierala 
113ae1add4eSEdward Tomasz Napierala 	dest->acl_cnt = source->acl_cnt;
114ae1add4eSEdward Tomasz Napierala 
115ae1add4eSEdward Tomasz Napierala 	for (i = 0; i < dest->acl_cnt; i++) {
116ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
117ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
118ae1add4eSEdward Tomasz Napierala 		dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
119ae1add4eSEdward Tomasz Napierala 	}
120ae1add4eSEdward Tomasz Napierala 
121ae1add4eSEdward Tomasz Napierala 	return (0);
122ae1add4eSEdward Tomasz Napierala }
123ae1add4eSEdward Tomasz Napierala 
124ae1add4eSEdward Tomasz Napierala /*
125ae1add4eSEdward Tomasz Napierala  * At one time, "struct ACL" was extended in order to add support for NFSv4
126ae1add4eSEdward Tomasz Napierala  * ACLs.  Instead of creating compatibility versions of all the ACL-related
127ae1add4eSEdward Tomasz Napierala  * syscalls, they were left intact.  It's possible to find out what the code
128ae1add4eSEdward Tomasz Napierala  * calling these syscalls (libc) expects basing on "type" argument - if it's
129ae1add4eSEdward Tomasz Napierala  * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
130ae1add4eSEdward Tomasz Napierala  * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
131ae1add4eSEdward Tomasz Napierala  * oldacl".  If it's something else, then it's the new "struct acl".  In the
132ae1add4eSEdward Tomasz Napierala  * latter case, the routines below just copyin/copyout the contents.  In the
133ae1add4eSEdward Tomasz Napierala  * former case, they copyin the "struct oldacl" and convert it to the new
134ae1add4eSEdward Tomasz Napierala  * format.
135ae1add4eSEdward Tomasz Napierala  */
136ae1add4eSEdward Tomasz Napierala static int
acl_copyin(const void * user_acl,struct acl * kernel_acl,acl_type_t type)137aff4f2d3SBrooks Davis acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type)
138ae1add4eSEdward Tomasz Napierala {
139ae1add4eSEdward Tomasz Napierala 	int error;
140ae1add4eSEdward Tomasz Napierala 	struct oldacl old;
141ae1add4eSEdward Tomasz Napierala 
142ae1add4eSEdward Tomasz Napierala 	switch (type) {
143ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
144ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
145ae1add4eSEdward Tomasz Napierala 		error = copyin(user_acl, &old, sizeof(old));
146ae1add4eSEdward Tomasz Napierala 		if (error != 0)
147ae1add4eSEdward Tomasz Napierala 			break;
148ae1add4eSEdward Tomasz Napierala 		acl_copy_oldacl_into_acl(&old, kernel_acl);
149ae1add4eSEdward Tomasz Napierala 		break;
150ae1add4eSEdward Tomasz Napierala 
151ae1add4eSEdward Tomasz Napierala 	default:
152ae1add4eSEdward Tomasz Napierala 		error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
153ae1add4eSEdward Tomasz Napierala 		if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
154ae1add4eSEdward Tomasz Napierala 			return (EINVAL);
155ae1add4eSEdward Tomasz Napierala 	}
156ae1add4eSEdward Tomasz Napierala 
157ae1add4eSEdward Tomasz Napierala 	return (error);
158ae1add4eSEdward Tomasz Napierala }
159ae1add4eSEdward Tomasz Napierala 
160ae1add4eSEdward Tomasz Napierala static int
acl_copyout(const struct acl * kernel_acl,void * user_acl,acl_type_t type)161aff4f2d3SBrooks Davis acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type)
162ae1add4eSEdward Tomasz Napierala {
1630a2c94b8SKonstantin Belousov 	uint32_t am;
164ae1add4eSEdward Tomasz Napierala 	int error;
165ae1add4eSEdward Tomasz Napierala 	struct oldacl old;
166ae1add4eSEdward Tomasz Napierala 
167ae1add4eSEdward Tomasz Napierala 	switch (type) {
168ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
169ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
170ae1add4eSEdward Tomasz Napierala 		error = acl_copy_acl_into_oldacl(kernel_acl, &old);
171ae1add4eSEdward Tomasz Napierala 		if (error != 0)
172ae1add4eSEdward Tomasz Napierala 			break;
173ae1add4eSEdward Tomasz Napierala 
174ae1add4eSEdward Tomasz Napierala 		error = copyout(&old, user_acl, sizeof(old));
175ae1add4eSEdward Tomasz Napierala 		break;
176ae1add4eSEdward Tomasz Napierala 
177ae1add4eSEdward Tomasz Napierala 	default:
1780a2c94b8SKonstantin Belousov 		error = fueword32((char *)user_acl +
1790a2c94b8SKonstantin Belousov 		    offsetof(struct acl, acl_maxcnt), &am);
1800a2c94b8SKonstantin Belousov 		if (error == -1)
1810a2c94b8SKonstantin Belousov 			return (EFAULT);
1820a2c94b8SKonstantin Belousov 		if (am != ACL_MAX_ENTRIES)
183ae1add4eSEdward Tomasz Napierala 			return (EINVAL);
184ae1add4eSEdward Tomasz Napierala 
185ae1add4eSEdward Tomasz Napierala 		error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
186ae1add4eSEdward Tomasz Napierala 	}
187ae1add4eSEdward Tomasz Napierala 
188ae1add4eSEdward Tomasz Napierala 	return (error);
189ae1add4eSEdward Tomasz Napierala }
190ae1add4eSEdward Tomasz Napierala 
191ae1add4eSEdward Tomasz Napierala /*
192ae1add4eSEdward Tomasz Napierala  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
1936bb58cddSEdward Tomasz Napierala  * counterpart.  It's required for old (pre-NFSv4 ACLs) libc to work
194ae1add4eSEdward Tomasz Napierala  * with new kernel.  Fixing 'type' for old binaries with new libc
195ae1add4eSEdward Tomasz Napierala  * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
196ae1add4eSEdward Tomasz Napierala  */
197ae1add4eSEdward Tomasz Napierala static int
acl_type_unold(int type)198ae1add4eSEdward Tomasz Napierala acl_type_unold(int type)
199ae1add4eSEdward Tomasz Napierala {
200ae1add4eSEdward Tomasz Napierala 	switch (type) {
201ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_ACCESS_OLD:
202ae1add4eSEdward Tomasz Napierala 		return (ACL_TYPE_ACCESS);
203ae1add4eSEdward Tomasz Napierala 
204ae1add4eSEdward Tomasz Napierala 	case ACL_TYPE_DEFAULT_OLD:
205ae1add4eSEdward Tomasz Napierala 		return (ACL_TYPE_DEFAULT);
206ae1add4eSEdward Tomasz Napierala 
207ae1add4eSEdward Tomasz Napierala 	default:
208ae1add4eSEdward Tomasz Napierala 		return (type);
209ae1add4eSEdward Tomasz Napierala 	}
210ae1add4eSEdward Tomasz Napierala }
211ae1add4eSEdward Tomasz Napierala 
21291f37dcbSRobert Watson /*
213b0c521e2SRobert Watson  * These calls wrap the real vnode operations, and are called by the syscall
214b0c521e2SRobert Watson  * code once the syscall has converted the path or file descriptor to a vnode
215b0c521e2SRobert Watson  * (unlocked).  The aclp pointer is assumed still to point to userland, so
216b0c521e2SRobert Watson  * this should not be consumed within the kernel except by syscall code.
217b0c521e2SRobert Watson  * Other code should directly invoke VOP_{SET,GET}ACL.
21891f37dcbSRobert Watson  */
21991f37dcbSRobert Watson 
22091f37dcbSRobert Watson /*
22191f37dcbSRobert Watson  * Given a vnode, set its ACL.
22291f37dcbSRobert Watson  */
22391f37dcbSRobert Watson static int
vacl_set_acl(struct thread * td,struct vnode * vp,acl_type_t type,const struct acl * aclp)224b40ce416SJulian Elischer vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
225aff4f2d3SBrooks Davis     const struct acl *aclp)
22691f37dcbSRobert Watson {
227b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
2284e1123c7SRobert Watson 	struct mount *mp;
22991f37dcbSRobert Watson 	int error;
23091f37dcbSRobert Watson 
231f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
232b998d381SEdward Tomasz Napierala 	inkernelacl = acl_alloc(M_WAITOK);
233ae1add4eSEdward Tomasz Napierala 	error = acl_copyin(aclp, inkernelacl, type);
234da9ce28eSEdward Tomasz Napierala 	if (error != 0)
235b998d381SEdward Tomasz Napierala 		goto out;
236a75d1dddSMateusz Guzik 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
2374e1123c7SRobert Watson 	if (error != 0)
238b998d381SEdward Tomasz Napierala 		goto out;
239cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
240f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
241c86ca022SRobert Watson #ifdef MAC
242b998d381SEdward Tomasz Napierala 	error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl);
243c86ca022SRobert Watson 	if (error != 0)
244b998d381SEdward Tomasz Napierala 		goto out_unlock;
245c86ca022SRobert Watson #endif
246ae1add4eSEdward Tomasz Napierala 	error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
247ae1add4eSEdward Tomasz Napierala 	    td->td_ucred, td);
248c86ca022SRobert Watson #ifdef MAC
249b998d381SEdward Tomasz Napierala out_unlock:
250c86ca022SRobert Watson #endif
251b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
2524e1123c7SRobert Watson 	vn_finished_write(mp);
253b998d381SEdward Tomasz Napierala out:
254b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
25591f37dcbSRobert Watson 	return (error);
25691f37dcbSRobert Watson }
25791f37dcbSRobert Watson 
25891f37dcbSRobert Watson /*
25991f37dcbSRobert Watson  * Given a vnode, get its ACL.
26091f37dcbSRobert Watson  */
26191f37dcbSRobert Watson static int
vacl_get_acl(struct thread * td,struct vnode * vp,acl_type_t type,struct acl * aclp)262b40ce416SJulian Elischer vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
26391f37dcbSRobert Watson     struct acl *aclp)
26491f37dcbSRobert Watson {
265b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
26691f37dcbSRobert Watson 	int error;
26791f37dcbSRobert Watson 
268f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
26923c053d6SSergey Kandaurov 	inkernelacl = acl_alloc(M_WAITOK | M_ZERO);
270cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
271f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
272c86ca022SRobert Watson #ifdef MAC
27330d239bcSRobert Watson 	error = mac_vnode_check_getacl(td->td_ucred, vp, type);
274c86ca022SRobert Watson 	if (error != 0)
275c86ca022SRobert Watson 		goto out;
276c86ca022SRobert Watson #endif
277ae1add4eSEdward Tomasz Napierala 	error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
278ae1add4eSEdward Tomasz Napierala 	    td->td_ucred, td);
279ae1add4eSEdward Tomasz Napierala 
280c86ca022SRobert Watson #ifdef MAC
281c86ca022SRobert Watson out:
282c86ca022SRobert Watson #endif
283b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
28491f37dcbSRobert Watson 	if (error == 0)
285ae1add4eSEdward Tomasz Napierala 		error = acl_copyout(inkernelacl, aclp, type);
286b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
28791f37dcbSRobert Watson 	return (error);
28891f37dcbSRobert Watson }
28991f37dcbSRobert Watson 
29091f37dcbSRobert Watson /*
29191f37dcbSRobert Watson  * Given a vnode, delete its ACL.
29291f37dcbSRobert Watson  */
29391f37dcbSRobert Watson static int
vacl_delete(struct thread * td,struct vnode * vp,acl_type_t type)294b40ce416SJulian Elischer vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
29591f37dcbSRobert Watson {
2964e1123c7SRobert Watson 	struct mount *mp;
29791f37dcbSRobert Watson 	int error;
29891f37dcbSRobert Watson 
299f9070809SRobert Watson 	AUDIT_ARG_VALUE(type);
300a75d1dddSMateusz Guzik 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
301da9ce28eSEdward Tomasz Napierala 	if (error != 0)
3024e1123c7SRobert Watson 		return (error);
303cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
304f9070809SRobert Watson 	AUDIT_ARG_VNODE1(vp);
305c86ca022SRobert Watson #ifdef MAC
30630d239bcSRobert Watson 	error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
307da9ce28eSEdward Tomasz Napierala 	if (error != 0)
308c86ca022SRobert Watson 		goto out;
309c86ca022SRobert Watson #endif
310ae1add4eSEdward Tomasz Napierala 	error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
311c86ca022SRobert Watson #ifdef MAC
312c86ca022SRobert Watson out:
313c86ca022SRobert Watson #endif
314b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
3154e1123c7SRobert Watson 	vn_finished_write(mp);
31691f37dcbSRobert Watson 	return (error);
31791f37dcbSRobert Watson }
31891f37dcbSRobert Watson 
31991f37dcbSRobert Watson /*
32091f37dcbSRobert Watson  * Given a vnode, check whether an ACL is appropriate for it
321f9070809SRobert Watson  *
322f9070809SRobert Watson  * XXXRW: No vnode lock held so can't audit vnode state...?
32391f37dcbSRobert Watson  */
32491f37dcbSRobert Watson static int
vacl_aclcheck(struct thread * td,struct vnode * vp,acl_type_t type,const struct acl * aclp)325b40ce416SJulian Elischer vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
326aff4f2d3SBrooks Davis     const struct acl *aclp)
32791f37dcbSRobert Watson {
328b998d381SEdward Tomasz Napierala 	struct acl *inkernelacl;
32991f37dcbSRobert Watson 	int error;
33091f37dcbSRobert Watson 
331b998d381SEdward Tomasz Napierala 	inkernelacl = acl_alloc(M_WAITOK);
332ae1add4eSEdward Tomasz Napierala 	error = acl_copyin(aclp, inkernelacl, type);
333da9ce28eSEdward Tomasz Napierala 	if (error != 0)
334b998d381SEdward Tomasz Napierala 		goto out;
3356bb58cddSEdward Tomasz Napierala 	error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl,
3366bb58cddSEdward Tomasz Napierala 	    td->td_ucred, td);
337b998d381SEdward Tomasz Napierala out:
338b998d381SEdward Tomasz Napierala 	acl_free(inkernelacl);
33991f37dcbSRobert Watson 	return (error);
34091f37dcbSRobert Watson }
34191f37dcbSRobert Watson 
34291f37dcbSRobert Watson /*
343b0c521e2SRobert Watson  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
344b0c521e2SRobert Watson  * need to lock, as the vacl_ code will get/release any locks required.
34591f37dcbSRobert Watson  */
34691f37dcbSRobert Watson 
34791f37dcbSRobert Watson /*
34891f37dcbSRobert Watson  * Given a file path, get an ACL for it
34991f37dcbSRobert Watson  */
35091f37dcbSRobert Watson int
sys___acl_get_file(struct thread * td,struct __acl_get_file_args * uap)3518451d0ddSKip Macy sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
35291f37dcbSRobert Watson {
35391f37dcbSRobert Watson 
354aff4f2d3SBrooks Davis 	return (kern___acl_get_path(td, uap->path, uap->type, uap->aclp,
355aff4f2d3SBrooks Davis 	    FOLLOW));
35691f37dcbSRobert Watson }
35791f37dcbSRobert Watson 
35891f37dcbSRobert Watson /*
3593c67c23bSRobert Watson  * Given a file path, get an ACL for it; don't follow links.
3603c67c23bSRobert Watson  */
3613c67c23bSRobert Watson int
sys___acl_get_link(struct thread * td,struct __acl_get_link_args * uap)3628451d0ddSKip Macy sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
3633c67c23bSRobert Watson {
364aff4f2d3SBrooks Davis 
365aff4f2d3SBrooks Davis 	return(kern___acl_get_path(td, uap->path, uap->type, uap->aclp,
366aff4f2d3SBrooks Davis 	    NOFOLLOW));
367aff4f2d3SBrooks Davis }
368aff4f2d3SBrooks Davis 
369aff4f2d3SBrooks Davis static int
kern___acl_get_path(struct thread * td,const char * path,acl_type_t type,struct acl * aclp,int follow)370aff4f2d3SBrooks Davis kern___acl_get_path(struct thread *td, const char *path, acl_type_t type,
371aff4f2d3SBrooks Davis     struct acl *aclp, int follow)
372aff4f2d3SBrooks Davis {
3733c67c23bSRobert Watson 	struct nameidata nd;
3745050aa86SKonstantin Belousov 	int error;
3753c67c23bSRobert Watson 
3767e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path);
3773c67c23bSRobert Watson 	error = namei(&nd);
3783c67c23bSRobert Watson 	if (error == 0) {
379aff4f2d3SBrooks Davis 		error = vacl_get_acl(td, nd.ni_vp, type, aclp);
38085dac03eSMateusz Guzik 		vrele(nd.ni_vp);
38185dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
3823c67c23bSRobert Watson 	}
3833c67c23bSRobert Watson 	return (error);
3843c67c23bSRobert Watson }
3853c67c23bSRobert Watson 
3863c67c23bSRobert Watson /*
3870c14ff0eSRobert Watson  * Given a file path, set an ACL for it.
38891f37dcbSRobert Watson  */
38991f37dcbSRobert Watson int
sys___acl_set_file(struct thread * td,struct __acl_set_file_args * uap)3908451d0ddSKip Macy sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
39191f37dcbSRobert Watson {
39291f37dcbSRobert Watson 
393aff4f2d3SBrooks Davis 	return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp,
394aff4f2d3SBrooks Davis 	    FOLLOW));
39591f37dcbSRobert Watson }
39691f37dcbSRobert Watson 
39791f37dcbSRobert Watson /*
3983c67c23bSRobert Watson  * Given a file path, set an ACL for it; don't follow links.
3993c67c23bSRobert Watson  */
4003c67c23bSRobert Watson int
sys___acl_set_link(struct thread * td,struct __acl_set_link_args * uap)4018451d0ddSKip Macy sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
4023c67c23bSRobert Watson {
403aff4f2d3SBrooks Davis 
404aff4f2d3SBrooks Davis 	return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp,
405aff4f2d3SBrooks Davis 	    NOFOLLOW));
406aff4f2d3SBrooks Davis }
407aff4f2d3SBrooks Davis 
408aff4f2d3SBrooks Davis static int
kern___acl_set_path(struct thread * td,const char * path,acl_type_t type,const struct acl * aclp,int follow)409aff4f2d3SBrooks Davis kern___acl_set_path(struct thread *td, const char *path,
410aff4f2d3SBrooks Davis     acl_type_t type, const struct acl *aclp, int follow)
411aff4f2d3SBrooks Davis {
4123c67c23bSRobert Watson 	struct nameidata nd;
4135050aa86SKonstantin Belousov 	int error;
4143c67c23bSRobert Watson 
4157e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path);
4163c67c23bSRobert Watson 	error = namei(&nd);
4173c67c23bSRobert Watson 	if (error == 0) {
418aff4f2d3SBrooks Davis 		error = vacl_set_acl(td, nd.ni_vp, type, aclp);
41985dac03eSMateusz Guzik 		vrele(nd.ni_vp);
42085dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
4213c67c23bSRobert Watson 	}
4223c67c23bSRobert Watson 	return (error);
4233c67c23bSRobert Watson }
4243c67c23bSRobert Watson 
4253c67c23bSRobert Watson /*
426b5368498SRobert Watson  * Given a file descriptor, get an ACL for it.
42791f37dcbSRobert Watson  */
42891f37dcbSRobert Watson int
sys___acl_get_fd(struct thread * td,struct __acl_get_fd_args * uap)4298451d0ddSKip Macy sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
43091f37dcbSRobert Watson {
43191f37dcbSRobert Watson 	struct file *fp;
4327008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
4335050aa86SKonstantin Belousov 	int error;
43491f37dcbSRobert Watson 
435f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
4367a292504SKonstantin Belousov 	error = getvnode_path(td, uap->filedes,
437e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_ACL_GET), &fp);
438f708f4d1SMatthew Dillon 	if (error == 0) {
4393b6d9652SPoul-Henning Kamp 		error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
440426da3bcSAlfred Perlstein 		fdrop(fp, td);
441f708f4d1SMatthew Dillon 	}
44291f37dcbSRobert Watson 	return (error);
44391f37dcbSRobert Watson }
44491f37dcbSRobert Watson 
44591f37dcbSRobert Watson /*
446b5368498SRobert Watson  * Given a file descriptor, set an ACL for it.
44791f37dcbSRobert Watson  */
44891f37dcbSRobert Watson int
sys___acl_set_fd(struct thread * td,struct __acl_set_fd_args * uap)4498451d0ddSKip Macy sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
45091f37dcbSRobert Watson {
45191f37dcbSRobert Watson 	struct file *fp;
4527008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
4535050aa86SKonstantin Belousov 	int error;
45491f37dcbSRobert Watson 
455f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
4564da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
457e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_ACL_SET), &fp);
458f708f4d1SMatthew Dillon 	if (error == 0) {
4593b6d9652SPoul-Henning Kamp 		error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
460426da3bcSAlfred Perlstein 		fdrop(fp, td);
461f708f4d1SMatthew Dillon 	}
46291f37dcbSRobert Watson 	return (error);
46391f37dcbSRobert Watson }
46491f37dcbSRobert Watson 
46591f37dcbSRobert Watson /*
46691f37dcbSRobert Watson  * Given a file path, delete an ACL from it.
46791f37dcbSRobert Watson  */
46891f37dcbSRobert Watson int
sys___acl_delete_file(struct thread * td,struct __acl_delete_file_args * uap)4698451d0ddSKip Macy sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
47091f37dcbSRobert Watson {
47191f37dcbSRobert Watson 
472aff4f2d3SBrooks Davis 	return (kern___acl_delete_path(td, uap->path, uap->type, FOLLOW));
47391f37dcbSRobert Watson }
47491f37dcbSRobert Watson 
47591f37dcbSRobert Watson /*
4763c67c23bSRobert Watson  * Given a file path, delete an ACL from it; don't follow links.
4773c67c23bSRobert Watson  */
4783c67c23bSRobert Watson int
sys___acl_delete_link(struct thread * td,struct __acl_delete_link_args * uap)4798451d0ddSKip Macy sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
4803c67c23bSRobert Watson {
481aff4f2d3SBrooks Davis 
482aff4f2d3SBrooks Davis 	return (kern___acl_delete_path(td, uap->path, uap->type, NOFOLLOW));
483aff4f2d3SBrooks Davis }
484aff4f2d3SBrooks Davis 
485aff4f2d3SBrooks Davis static int
kern___acl_delete_path(struct thread * td,const char * path,acl_type_t type,int follow)486aff4f2d3SBrooks Davis kern___acl_delete_path(struct thread *td, const char *path,
487aff4f2d3SBrooks Davis     acl_type_t type, int follow)
488aff4f2d3SBrooks Davis {
4893c67c23bSRobert Watson 	struct nameidata nd;
4905050aa86SKonstantin Belousov 	int error;
4913c67c23bSRobert Watson 
4927e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path);
4933c67c23bSRobert Watson 	error = namei(&nd);
4943c67c23bSRobert Watson 	if (error == 0) {
495aff4f2d3SBrooks Davis 		error = vacl_delete(td, nd.ni_vp, type);
49685dac03eSMateusz Guzik 		vrele(nd.ni_vp);
49785dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
4983c67c23bSRobert Watson 	}
4993c67c23bSRobert Watson 	return (error);
5003c67c23bSRobert Watson }
5013c67c23bSRobert Watson 
5023c67c23bSRobert Watson /*
50391f37dcbSRobert Watson  * Given a file path, delete an ACL from it.
50491f37dcbSRobert Watson  */
50591f37dcbSRobert Watson int
sys___acl_delete_fd(struct thread * td,struct __acl_delete_fd_args * uap)5068451d0ddSKip Macy sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
50791f37dcbSRobert Watson {
50891f37dcbSRobert Watson 	struct file *fp;
5097008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
5105050aa86SKonstantin Belousov 	int error;
51191f37dcbSRobert Watson 
512f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
5134da8456fSMateusz Guzik 	error = getvnode(td, uap->filedes,
514e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_ACL_DELETE), &fp);
515f708f4d1SMatthew Dillon 	if (error == 0) {
5163b6d9652SPoul-Henning Kamp 		error = vacl_delete(td, fp->f_vnode, uap->type);
517426da3bcSAlfred Perlstein 		fdrop(fp, td);
518f708f4d1SMatthew Dillon 	}
51991f37dcbSRobert Watson 	return (error);
52091f37dcbSRobert Watson }
52191f37dcbSRobert Watson 
52291f37dcbSRobert Watson /*
5230c14ff0eSRobert Watson  * Given a file path, check an ACL for it.
52491f37dcbSRobert Watson  */
52591f37dcbSRobert Watson int
sys___acl_aclcheck_file(struct thread * td,struct __acl_aclcheck_file_args * uap)5268451d0ddSKip Macy sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
52791f37dcbSRobert Watson {
52891f37dcbSRobert Watson 
529aff4f2d3SBrooks Davis 	return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
530aff4f2d3SBrooks Davis 	    FOLLOW));
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
sys___acl_aclcheck_link(struct thread * td,struct __acl_aclcheck_link_args * uap)5378451d0ddSKip Macy sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
5383c67c23bSRobert Watson {
539aff4f2d3SBrooks Davis 	return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp,
540aff4f2d3SBrooks Davis 	    NOFOLLOW));
541aff4f2d3SBrooks Davis }
542aff4f2d3SBrooks Davis 
543aff4f2d3SBrooks Davis static int
kern___acl_aclcheck_path(struct thread * td,const char * path,acl_type_t type,struct acl * aclp,int follow)544aff4f2d3SBrooks Davis kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type,
545aff4f2d3SBrooks Davis     struct acl *aclp, int follow)
546aff4f2d3SBrooks Davis {
5477a172809SEdward Tomasz Napierala 	struct nameidata nd;
5485050aa86SKonstantin Belousov 	int error;
5493c67c23bSRobert Watson 
5507e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path);
5513c67c23bSRobert Watson 	error = namei(&nd);
5523c67c23bSRobert Watson 	if (error == 0) {
553aff4f2d3SBrooks Davis 		error = vacl_aclcheck(td, nd.ni_vp, type, aclp);
55485dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
5553c67c23bSRobert Watson 	}
5563c67c23bSRobert Watson 	return (error);
5573c67c23bSRobert Watson }
5583c67c23bSRobert Watson 
5593c67c23bSRobert Watson /*
5600c14ff0eSRobert Watson  * Given a file descriptor, check an ACL for it.
56191f37dcbSRobert Watson  */
56291f37dcbSRobert Watson int
sys___acl_aclcheck_fd(struct thread * td,struct __acl_aclcheck_fd_args * uap)5638451d0ddSKip Macy sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
56491f37dcbSRobert Watson {
56591f37dcbSRobert Watson 	struct file *fp;
5667008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
5675050aa86SKonstantin Belousov 	int error;
56891f37dcbSRobert Watson 
569f9070809SRobert Watson 	AUDIT_ARG_FD(uap->filedes);
5707a292504SKonstantin Belousov 	error = getvnode_path(td, uap->filedes,
571e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_ACL_CHECK), &fp);
572f708f4d1SMatthew Dillon 	if (error == 0) {
5733b6d9652SPoul-Henning Kamp 		error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
574426da3bcSAlfred Perlstein 		fdrop(fp, td);
575f708f4d1SMatthew Dillon 	}
57691f37dcbSRobert Watson 	return (error);
57791f37dcbSRobert Watson }
578d1dfd921SChristian S.J. Peron 
579b998d381SEdward Tomasz Napierala struct acl *
acl_alloc(int flags)580b998d381SEdward Tomasz Napierala acl_alloc(int flags)
581b998d381SEdward Tomasz Napierala {
582b998d381SEdward Tomasz Napierala 	struct acl *aclp;
583b998d381SEdward Tomasz Napierala 
584e0ee7589SEdward Tomasz Napierala 	aclp = malloc(sizeof(*aclp), M_ACL, flags);
5858ddc3590SEdward Tomasz Napierala 	if (aclp == NULL)
5868ddc3590SEdward Tomasz Napierala 		return (NULL);
5878ddc3590SEdward Tomasz Napierala 
588ae1add4eSEdward Tomasz Napierala 	aclp->acl_maxcnt = ACL_MAX_ENTRIES;
589b998d381SEdward Tomasz Napierala 
590b998d381SEdward Tomasz Napierala 	return (aclp);
591b998d381SEdward Tomasz Napierala }
592b998d381SEdward Tomasz Napierala 
593b998d381SEdward Tomasz Napierala void
acl_free(struct acl * aclp)594b998d381SEdward Tomasz Napierala acl_free(struct acl *aclp)
595b998d381SEdward Tomasz Napierala {
596b998d381SEdward Tomasz Napierala 
597e0ee7589SEdward Tomasz Napierala 	free(aclp, M_ACL);
598b998d381SEdward Tomasz Napierala }
599