]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/vfs_acl.c
Merge libpcap 1.0.0.
[FreeBSD/FreeBSD.git] / 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/fcntl.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/mount.h>
47 #include <sys/vnode.h>
48 #include <sys/lock.h>
49 #include <sys/mutex.h>
50 #include <sys/namei.h>
51 #include <sys/file.h>
52 #include <sys/filedesc.h>
53 #include <sys/proc.h>
54 #include <sys/sysent.h>
55 #include <sys/acl.h>
56
57 #include <security/mac/mac_framework.h>
58
59 #include <vm/uma.h>
60
61 uma_zone_t      acl_zone;
62 static int      vacl_set_acl(struct thread *td, struct vnode *vp,
63                     acl_type_t type, struct acl *aclp);
64 static int      vacl_get_acl(struct thread *td, struct vnode *vp,
65                     acl_type_t type, struct acl *aclp);
66 static int      vacl_aclcheck(struct thread *td, struct vnode *vp,
67                     acl_type_t type, struct acl *aclp);
68
69 /*
70  * These calls wrap the real vnode operations, and are called by the syscall
71  * code once the syscall has converted the path or file descriptor to a vnode
72  * (unlocked).  The aclp pointer is assumed still to point to userland, so
73  * this should not be consumed within the kernel except by syscall code.
74  * Other code should directly invoke VOP_{SET,GET}ACL.
75  */
76
77 /*
78  * Given a vnode, set its ACL.
79  */
80 static int
81 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
82     struct acl *aclp)
83 {
84         struct acl inkernacl;
85         struct mount *mp;
86         int error;
87
88         error = copyin(aclp, &inkernacl, sizeof(struct acl));
89         if (error)
90                 return(error);
91         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
92         if (error != 0)
93                 return (error);
94         VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
95         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
96 #ifdef MAC
97         error = mac_vnode_check_setacl(td->td_ucred, vp, type, &inkernacl);
98         if (error != 0)
99                 goto out;
100 #endif
101         error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td);
102 #ifdef MAC
103 out:
104 #endif
105         VOP_UNLOCK(vp, 0);
106         vn_finished_write(mp);
107         return(error);
108 }
109
110 /*
111  * Given a vnode, get its ACL.
112  */
113 static int
114 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
115     struct acl *aclp)
116 {
117         struct acl inkernelacl;
118         int error;
119
120         VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
121         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
122 #ifdef MAC
123         error = mac_vnode_check_getacl(td->td_ucred, vp, type);
124         if (error != 0)
125                 goto out;
126 #endif
127         error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td);
128 #ifdef MAC
129 out:
130 #endif
131         VOP_UNLOCK(vp, 0);
132         if (error == 0)
133                 error = copyout(&inkernelacl, aclp, sizeof(struct acl));
134         return (error);
135 }
136
137 /*
138  * Given a vnode, delete its ACL.
139  */
140 static int
141 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
142 {
143         struct mount *mp;
144         int error;
145
146         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
147         if (error)
148                 return (error);
149         VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
150         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
151 #ifdef MAC
152         error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
153         if (error)
154                 goto out;
155 #endif
156         error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
157 #ifdef MAC
158 out:
159 #endif
160         VOP_UNLOCK(vp, 0);
161         vn_finished_write(mp);
162         return (error);
163 }
164
165 /*
166  * Given a vnode, check whether an ACL is appropriate for it
167  */
168 static int
169 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
170     struct acl *aclp)
171 {
172         struct acl inkernelacl;
173         int error;
174
175         error = copyin(aclp, &inkernelacl, sizeof(struct acl));
176         if (error)
177                 return(error);
178         error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td);
179         return (error);
180 }
181
182 /*
183  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
184  * need to lock, as the vacl_ code will get/release any locks required.
185  */
186
187 /*
188  * Given a file path, get an ACL for it
189  */
190 int
191 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
192 {
193         struct nameidata nd;
194         int vfslocked, error;
195
196         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
197         error = namei(&nd);
198         vfslocked = NDHASGIANT(&nd);
199         if (error == 0) {
200                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
201                 NDFREE(&nd, 0);
202         }
203         VFS_UNLOCK_GIANT(vfslocked);
204         return (error);
205 }
206
207 /*
208  * Given a file path, get an ACL for it; don't follow links.
209  */
210 int
211 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
212 {
213         struct nameidata nd;
214         int vfslocked, error;
215
216         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
217         error = namei(&nd);
218         vfslocked = NDHASGIANT(&nd);
219         if (error == 0) {
220                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
221                 NDFREE(&nd, 0);
222         }
223         VFS_UNLOCK_GIANT(vfslocked);
224         return (error);
225 }
226
227 /*
228  * Given a file path, set an ACL for it.
229  */
230 int
231 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
232 {
233         struct nameidata nd;
234         int vfslocked, error;
235
236         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
237         error = namei(&nd);
238         vfslocked = NDHASGIANT(&nd);
239         if (error == 0) {
240                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
241                 NDFREE(&nd, 0);
242         }
243         VFS_UNLOCK_GIANT(vfslocked);
244         return (error);
245 }
246
247 /*
248  * Given a file path, set an ACL for it; don't follow links.
249  */
250 int
251 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
252 {
253         struct nameidata nd;
254         int vfslocked, error;
255
256         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
257         error = namei(&nd);
258         vfslocked = NDHASGIANT(&nd);
259         if (error == 0) {
260                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
261                 NDFREE(&nd, 0);
262         }
263         VFS_UNLOCK_GIANT(vfslocked);
264         return (error);
265 }
266
267 /*
268  * Given a file descriptor, get an ACL for it.
269  */
270 int
271 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
272 {
273         struct file *fp;
274         int vfslocked, error;
275
276         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
277         if (error == 0) {
278                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
279                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
280                 fdrop(fp, td);
281                 VFS_UNLOCK_GIANT(vfslocked);
282         }
283         return (error);
284 }
285
286 /*
287  * Given a file descriptor, set an ACL for it.
288  */
289 int
290 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
291 {
292         struct file *fp;
293         int vfslocked, error;
294
295         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
296         if (error == 0) {
297                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
298                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
299                 fdrop(fp, td);
300                 VFS_UNLOCK_GIANT(vfslocked);
301         }
302         return (error);
303 }
304
305 /*
306  * Given a file path, delete an ACL from it.
307  */
308 int
309 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
310 {
311         struct nameidata nd;
312         int vfslocked, error;
313
314         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
315         error = namei(&nd);
316         vfslocked = NDHASGIANT(&nd);
317         if (error == 0) {
318                 error = vacl_delete(td, nd.ni_vp, uap->type);
319                 NDFREE(&nd, 0);
320         }
321         VFS_UNLOCK_GIANT(vfslocked);
322         return (error);
323 }
324
325 /*
326  * Given a file path, delete an ACL from it; don't follow links.
327  */
328 int
329 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
330 {
331         struct nameidata nd;
332         int vfslocked, error;
333
334         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
335         error = namei(&nd);
336         vfslocked = NDHASGIANT(&nd);
337         if (error == 0) {
338                 error = vacl_delete(td, nd.ni_vp, uap->type);
339                 NDFREE(&nd, 0);
340         }
341         VFS_UNLOCK_GIANT(vfslocked);
342         return (error);
343 }
344
345 /*
346  * Given a file path, delete an ACL from it.
347  */
348 int
349 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
350 {
351         struct file *fp;
352         int vfslocked, error;
353
354         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
355         if (error == 0) {
356                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
357                 error = vacl_delete(td, fp->f_vnode, uap->type);
358                 fdrop(fp, td);
359                 VFS_UNLOCK_GIANT(vfslocked);
360         }
361         return (error);
362 }
363
364 /*
365  * Given a file path, check an ACL for it.
366  */
367 int
368 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
369 {
370         struct nameidata        nd;
371         int vfslocked, error;
372
373         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
374         error = namei(&nd);
375         vfslocked = NDHASGIANT(&nd);
376         if (error == 0) {
377                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
378                 NDFREE(&nd, 0);
379         }
380         VFS_UNLOCK_GIANT(vfslocked);
381         return (error);
382 }
383
384 /*
385  * Given a file path, check an ACL for it; don't follow links.
386  */
387 int
388 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
389 {
390         struct nameidata        nd;
391         int vfslocked, error;
392
393         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
394         error = namei(&nd);
395         vfslocked = NDHASGIANT(&nd);
396         if (error == 0) {
397                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
398                 NDFREE(&nd, 0);
399         }
400         VFS_UNLOCK_GIANT(vfslocked);
401         return (error);
402 }
403
404 /*
405  * Given a file descriptor, check an ACL for it.
406  */
407 int
408 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
409 {
410         struct file *fp;
411         int vfslocked, error;
412
413         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
414         if (error == 0) {
415                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
416                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
417                 fdrop(fp, td);
418                 VFS_UNLOCK_GIANT(vfslocked);
419         }
420         return (error);
421 }
422
423 /* ARGUSED */
424
425 static void
426 aclinit(void *dummy __unused)
427 {
428
429         acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl),
430             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
431 }
432 SYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL);