subr_acl_posix1e.c revision 71500
1/*-
2 * Copyright (c) 1999, 2000 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/kern/subr_acl_posix1e.c 71500 2001-01-24 00:35:12Z jhb $
27 */
28
29/*
30 * Generic routines to support file system ACLs, at a syntactic level
31 * Semantics are the responsibility of the underlying file system
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/sysproto.h>
37#include <sys/kernel.h>
38#include <sys/malloc.h>
39#include <sys/vnode.h>
40#include <sys/lock.h>
41#include <sys/namei.h>
42#include <sys/file.h>
43#include <sys/proc.h>
44#include <sys/sysent.h>
45#include <sys/errno.h>
46#include <sys/stat.h>
47#include <sys/acl.h>
48
49static MALLOC_DEFINE(M_ACL, "acl", "access control list");
50
51static int	vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type,
52	    struct acl *aclp);
53static int	vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type,
54	    struct acl *aclp);
55static int	vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type,
56	    struct acl *aclp);
57
58/*
59 * These calls wrap the real vnode operations, and are called by the
60 * syscall code once the syscall has converted the path or file
61 * descriptor to a vnode (unlocked).  The aclp pointer is assumed
62 * still to point to userland, so this should not be consumed within
63 * the kernel except by syscall code.  Other code should directly
64 * invoke VOP_{SET,GET}ACL.
65 */
66
67/*
68 * Given a vnode, set its ACL.
69 */
70static int
71vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type,
72    struct acl *aclp)
73{
74	struct acl inkernacl;
75	struct ucred *uc;
76	int error;
77
78	error = copyin(aclp, &inkernacl, sizeof(struct acl));
79	if (error)
80		return(error);
81	PROC_LOCK(p);
82	uc = p->p_ucred;
83	crhold(uc);
84	PROC_UNLOCK(p);
85	VOP_LEASE(vp, p, uc, LEASE_WRITE);
86	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
87	error = VOP_SETACL(vp, type, &inkernacl, uc, p);
88	VOP_UNLOCK(vp, 0, p);
89	crfree(uc);
90	return (error);
91}
92
93/*
94 * Given a vnode, get its ACL.
95 */
96static int
97vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type,
98    struct acl *aclp)
99{
100	struct acl inkernelacl;
101	struct ucred *uc;
102	int error;
103
104	PROC_LOCK(p);
105	uc = p->p_ucred;
106	crhold(uc);
107	PROC_UNLOCK(p);
108	VOP_LEASE(vp, p, uc, LEASE_WRITE);
109	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
110	error = VOP_GETACL(vp, type, &inkernelacl, uc, p);
111	VOP_UNLOCK(vp, 0, p);
112	crfree(uc);
113	if (error == 0)
114		error = copyout(&inkernelacl, aclp, sizeof(struct acl));
115	return (error);
116}
117
118/*
119 * Given a vnode, delete its ACL.
120 */
121static int
122vacl_delete(struct proc *p, struct vnode *vp, acl_type_t type)
123{
124	struct ucred *uc;
125	int error;
126
127	PROC_LOCK(p);
128	uc = p->p_ucred;
129	crhold(uc);
130	PROC_UNLOCK(p);
131	VOP_LEASE(vp, p, uc, LEASE_WRITE);
132	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
133	error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, uc, p);
134	VOP_UNLOCK(vp, 0, p);
135	crfree(uc);
136	return (error);
137}
138
139/*
140 * Given a vnode, check whether an ACL is appropriate for it
141 */
142static int
143vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type,
144    struct acl *aclp)
145{
146	struct acl inkernelacl;
147	struct ucred *uc;
148	int error;
149
150	error = copyin(aclp, &inkernelacl, sizeof(struct acl));
151	if (error)
152		return(error);
153	PROC_LOCK(p);
154	uc = p->p_ucred;
155	crhold(uc);
156	PROC_UNLOCK(p);
157	error = VOP_ACLCHECK(vp, type, &inkernelacl, uc, p);
158	crfree(uc);
159	return (error);
160}
161
162/*
163 * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.
164 * Don't need to lock, as the vacl_ code will get/release any locks
165 * required.
166 */
167
168/*
169 * Given a file path, get an ACL for it
170 */
171int
172__acl_get_file(struct proc *p, struct __acl_get_file_args *uap)
173{
174	struct nameidata nd;
175	int error;
176
177	/* what flags are required here -- possible not LOCKLEAF? */
178	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
179	error = namei(&nd);
180	if (error)
181		return(error);
182	error = vacl_get_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
183	NDFREE(&nd, 0);
184	return (error);
185}
186
187/*
188 * Given a file path, set an ACL for it
189 */
190int
191__acl_set_file(struct proc *p, struct __acl_set_file_args *uap)
192{
193	struct nameidata nd;
194	int error;
195
196	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
197	error = namei(&nd);
198	if (error)
199		return(error);
200	error = vacl_set_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
201	NDFREE(&nd, 0);
202	return (error);
203}
204
205/*
206 * Given a file descriptor, get an ACL for it
207 */
208int
209__acl_get_fd(struct proc *p, struct __acl_get_fd_args *uap)
210{
211	struct file *fp;
212	int error;
213
214	error = getvnode(p->p_fd, SCARG(uap, filedes), &fp);
215	if (error)
216		return(error);
217	return vacl_get_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type),
218	    SCARG(uap, aclp));
219}
220
221/*
222 * Given a file descriptor, set an ACL for it
223 */
224int
225__acl_set_fd(struct proc *p, struct __acl_set_fd_args *uap)
226{
227	struct file *fp;
228	int error;
229
230	error = getvnode(p->p_fd, SCARG(uap, filedes), &fp);
231	if (error)
232		return(error);
233	return vacl_set_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type),
234	    SCARG(uap, aclp));
235}
236
237/*
238 * Given a file path, delete an ACL from it.
239 */
240int
241__acl_delete_file(struct proc *p, struct __acl_delete_file_args *uap)
242{
243	struct nameidata nd;
244	int error;
245
246	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
247	error = namei(&nd);
248	if (error)
249		return(error);
250	error = vacl_delete(p, nd.ni_vp, SCARG(uap, type));
251	NDFREE(&nd, 0);
252	return (error);
253}
254
255/*
256 * Given a file path, delete an ACL from it.
257 */
258int
259__acl_delete_fd(struct proc *p, struct __acl_delete_fd_args *uap)
260{
261	struct file *fp;
262	int error;
263
264	error = getvnode(p->p_fd, SCARG(uap, filedes), &fp);
265	if (error)
266		return(error);
267	error = vacl_delete(p, (struct vnode *)fp->f_data, SCARG(uap, type));
268	return (error);
269}
270
271/*
272 * Given a file path, check an ACL for it
273 */
274int
275__acl_aclcheck_file(struct proc *p, struct __acl_aclcheck_file_args *uap)
276{
277	struct nameidata	nd;
278	int	error;
279
280	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
281	error = namei(&nd);
282	if (error)
283		return(error);
284	error = vacl_aclcheck(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
285	NDFREE(&nd, 0);
286	return (error);
287}
288
289/*
290 * Given a file descriptor, check an ACL for it
291 */
292int
293__acl_aclcheck_fd(struct proc *p, struct __acl_aclcheck_fd_args *uap)
294{
295	struct file *fp;
296	int error;
297
298	error = getvnode(p->p_fd, SCARG(uap, filedes), &fp);
299	if (error)
300		return(error);
301	return vacl_aclcheck(p, (struct vnode *)fp->f_data, SCARG(uap, type),
302	    SCARG(uap, aclp));
303}
304