FreeBSD/Linux Kernel Cross Reference
sys/kern/vfs_acl.c
1 /*-
2 * Copyright (c) 1999-2006 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * This software was developed by Robert Watson for the TrustedBSD Project.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 /*
29 * Developed by the TrustedBSD Project.
30 *
31 * ACL system calls and other functions common across different ACL types.
32 * Type-specific routines go into subr_acl_<type>.c.
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include "opt_mac.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/sysproto.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/mount.h>
46 #include <sys/vnode.h>
47 #include <sys/lock.h>
48 #include <sys/mutex.h>
49 #include <sys/namei.h>
50 #include <sys/file.h>
51 #include <sys/filedesc.h>
52 #include <sys/proc.h>
53 #include <sys/sysent.h>
54 #include <sys/acl.h>
55
56 #include <security/mac/mac_framework.h>
57
58 #include <vm/uma.h>
59
60 uma_zone_t acl_zone;
61 static int vacl_set_acl(struct thread *td, struct vnode *vp,
62 acl_type_t type, struct acl *aclp);
63 static int vacl_get_acl(struct thread *td, struct vnode *vp,
64 acl_type_t type, struct acl *aclp);
65 static int vacl_aclcheck(struct thread *td, struct vnode *vp,
66 acl_type_t type, struct acl *aclp);
67
68 /*
69 * These calls wrap the real vnode operations, and are called by the syscall
70 * code once the syscall has converted the path or file descriptor to a vnode
71 * (unlocked). The aclp pointer is assumed still to point to userland, so
72 * this should not be consumed within the kernel except by syscall code.
73 * Other code should directly invoke VOP_{SET,GET}ACL.
74 */
75
76 /*
77 * Given a vnode, set its ACL.
78 */
79 static int
80 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
81 struct acl *aclp)
82 {
83 struct acl inkernacl;
84 struct mount *mp;
85 int error;
86
87 error = copyin(aclp, &inkernacl, sizeof(struct acl));
88 if (error)
89 return(error);
90 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
91 if (error != 0)
92 return (error);
93 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
94 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
95 #ifdef MAC
96 error = mac_check_vnode_setacl(td->td_ucred, vp, type, &inkernacl);
97 if (error != 0)
98 goto out;
99 #endif
100 error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td);
101 #ifdef MAC
102 out:
103 #endif
104 VOP_UNLOCK(vp, 0, td);
105 vn_finished_write(mp);
106 return(error);
107 }
108
109 /*
110 * Given a vnode, get its ACL.
111 */
112 static int
113 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
114 struct acl *aclp)
115 {
116 struct acl inkernelacl;
117 int error;
118
119 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
120 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
121 #ifdef MAC
122 error = mac_check_vnode_getacl(td->td_ucred, vp, type);
123 if (error != 0)
124 goto out;
125 #endif
126 error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td);
127 #ifdef MAC
128 out:
129 #endif
130 VOP_UNLOCK(vp, 0, td);
131 if (error == 0)
132 error = copyout(&inkernelacl, aclp, sizeof(struct acl));
133 return (error);
134 }
135
136 /*
137 * Given a vnode, delete its ACL.
138 */
139 static int
140 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
141 {
142 struct mount *mp;
143 int error;
144
145 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
146 if (error)
147 return (error);
148 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
149 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
150 #ifdef MAC
151 error = mac_check_vnode_deleteacl(td->td_ucred, vp, type);
152 if (error)
153 goto out;
154 #endif
155 error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
156 #ifdef MAC
157 out:
158 #endif
159 VOP_UNLOCK(vp, 0, td);
160 vn_finished_write(mp);
161 return (error);
162 }
163
164 /*
165 * Given a vnode, check whether an ACL is appropriate for it
166 */
167 static int
168 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
169 struct acl *aclp)
170 {
171 struct acl inkernelacl;
172 int error;
173
174 error = copyin(aclp, &inkernelacl, sizeof(struct acl));
175 if (error)
176 return(error);
177 error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td);
178 return (error);
179 }
180
181 /*
182 * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. Don't
183 * need to lock, as the vacl_ code will get/release any locks required.
184 */
185
186 /*
187 * Given a file path, get an ACL for it
188 */
189 int
190 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
191 {
192 struct nameidata nd;
193 int vfslocked, error;
194
195 NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
196 error = namei(&nd);
197 vfslocked = NDHASGIANT(&nd);
198 if (error == 0) {
199 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
200 NDFREE(&nd, 0);
201 }
202 VFS_UNLOCK_GIANT(vfslocked);
203 return (error);
204 }
205
206 /*
207 * Given a file path, get an ACL for it; don't follow links.
208 */
209 int
210 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
211 {
212 struct nameidata nd;
213 int vfslocked, error;
214
215 NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
216 error = namei(&nd);
217 vfslocked = NDHASGIANT(&nd);
218 if (error == 0) {
219 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
220 NDFREE(&nd, 0);
221 }
222 VFS_UNLOCK_GIANT(vfslocked);
223 return (error);
224 }
225
226 /*
227 * Given a file path, set an ACL for it.
228 */
229 int
230 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
231 {
232 struct nameidata nd;
233 int vfslocked, error;
234
235 NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
236 error = namei(&nd);
237 vfslocked = NDHASGIANT(&nd);
238 if (error == 0) {
239 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
240 NDFREE(&nd, 0);
241 }
242 VFS_UNLOCK_GIANT(vfslocked);
243 return (error);
244 }
245
246 /*
247 * Given a file path, set an ACL for it; don't follow links.
248 */
249 int
250 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
251 {
252 struct nameidata nd;
253 int vfslocked, error;
254
255 NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
256 error = namei(&nd);
257 vfslocked = NDHASGIANT(&nd);
258 if (error == 0) {
259 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
260 NDFREE(&nd, 0);
261 }
262 VFS_UNLOCK_GIANT(vfslocked);
263 return (error);
264 }
265
266 /*
267 * Given a file descriptor, get an ACL for it.
268 */
269 int
270 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
271 {
272 struct file *fp;
273 int vfslocked, error;
274
275 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
276 if (error == 0) {
277 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
278 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
279 fdrop(fp, td);
280 VFS_UNLOCK_GIANT(vfslocked);
281 }
282 return (error);
283 }
284
285 /*
286 * Given a file descriptor, set an ACL for it.
287 */
288 int
289 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
290 {
291 struct file *fp;
292 int vfslocked, error;
293
294 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
295 if (error == 0) {
296 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
297 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
298 fdrop(fp, td);
299 VFS_UNLOCK_GIANT(vfslocked);
300 }
301 return (error);
302 }
303
304 /*
305 * Given a file path, delete an ACL from it.
306 */
307 int
308 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
309 {
310 struct nameidata nd;
311 int vfslocked, error;
312
313 NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
314 error = namei(&nd);
315 vfslocked = NDHASGIANT(&nd);
316 if (error == 0) {
317 error = vacl_delete(td, nd.ni_vp, uap->type);
318 NDFREE(&nd, 0);
319 }
320 VFS_UNLOCK_GIANT(vfslocked);
321 return (error);
322 }
323
324 /*
325 * Given a file path, delete an ACL from it; don't follow links.
326 */
327 int
328 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
329 {
330 struct nameidata nd;
331 int vfslocked, error;
332
333 NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
334 error = namei(&nd);
335 vfslocked = NDHASGIANT(&nd);
336 if (error == 0) {
337 error = vacl_delete(td, nd.ni_vp, uap->type);
338 NDFREE(&nd, 0);
339 }
340 VFS_UNLOCK_GIANT(vfslocked);
341 return (error);
342 }
343
344 /*
345 * Given a file path, delete an ACL from it.
346 */
347 int
348 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
349 {
350 struct file *fp;
351 int vfslocked, error;
352
353 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
354 if (error == 0) {
355 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
356 error = vacl_delete(td, fp->f_vnode, uap->type);
357 fdrop(fp, td);
358 VFS_UNLOCK_GIANT(vfslocked);
359 }
360 return (error);
361 }
362
363 /*
364 * Given a file path, check an ACL for it.
365 */
366 int
367 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
368 {
369 struct nameidata nd;
370 int vfslocked, error;
371
372 NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
373 error = namei(&nd);
374 vfslocked = NDHASGIANT(&nd);
375 if (error == 0) {
376 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
377 NDFREE(&nd, 0);
378 }
379 VFS_UNLOCK_GIANT(vfslocked);
380 return (error);
381 }
382
383 /*
384 * Given a file path, check an ACL for it; don't follow links.
385 */
386 int
387 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
388 {
389 struct nameidata nd;
390 int vfslocked, error;
391
392 NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
393 error = namei(&nd);
394 vfslocked = NDHASGIANT(&nd);
395 if (error == 0) {
396 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
397 NDFREE(&nd, 0);
398 }
399 VFS_UNLOCK_GIANT(vfslocked);
400 return (error);
401 }
402
403 /*
404 * Given a file descriptor, check an ACL for it.
405 */
406 int
407 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
408 {
409 struct file *fp;
410 int vfslocked, error;
411
412 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
413 if (error == 0) {
414 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
415 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
416 fdrop(fp, td);
417 VFS_UNLOCK_GIANT(vfslocked);
418 }
419 return (error);
420 }
421
422 /* ARGUSED */
423
424 static void
425 aclinit(void *dummy __unused)
426 {
427
428 acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl),
429 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
430 }
431 SYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL)
Cache object: 50119cd4bee9839721304c53797e8531
|