]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_acl.c
This commit was generated by cvs2svn to compensate for changes in r164146,
[FreeBSD/FreeBSD.git] / sys / kern / kern_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 
70  * syscall code once the syscall has converted the path or file
71  * descriptor to a vnode (unlocked).  The aclp pointer is assumed
72  * still to point to userland, so this should not be consumed within
73  * the kernel except by syscall code.  Other code should directly
74  * 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, td);
96 #ifdef MAC
97         error = mac_check_vnode_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, td);
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, td);
122 #ifdef MAC
123         error = mac_check_vnode_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, td);
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, td);
151 #ifdef MAC
152         error = mac_check_vnode_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, td);
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.
184  * Don't need to lock, as the vacl_ code will get/release any locks
185  * required.
186  */
187
188 /*
189  * Given a file path, get an ACL for it
190  *
191  * MPSAFE
192  */
193 int
194 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
195 {
196         struct nameidata nd;
197         int vfslocked, error;
198
199         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
200         error = namei(&nd);
201         vfslocked = NDHASGIANT(&nd);
202         if (error == 0) {
203                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
204                 NDFREE(&nd, 0);
205         }
206         VFS_UNLOCK_GIANT(vfslocked);
207         return (error);
208 }
209
210 /*
211  * Given a file path, get an ACL for it; don't follow links.
212  *
213  * MPSAFE
214  */
215 int
216 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
217 {
218         struct nameidata nd;
219         int vfslocked, error;
220
221         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
222         error = namei(&nd);
223         vfslocked = NDHASGIANT(&nd);
224         if (error == 0) {
225                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
226                 NDFREE(&nd, 0);
227         }
228         VFS_UNLOCK_GIANT(vfslocked);
229         return (error);
230 }
231
232 /*
233  * Given a file path, set an ACL for it
234  *
235  * MPSAFE
236  */
237 int
238 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
239 {
240         struct nameidata nd;
241         int vfslocked, error;
242
243         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
244         error = namei(&nd);
245         vfslocked = NDHASGIANT(&nd);
246         if (error == 0) {
247                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
248                 NDFREE(&nd, 0);
249         }
250         VFS_UNLOCK_GIANT(vfslocked);
251         return (error);
252 }
253
254 /*
255  * Given a file path, set an ACL for it; don't follow links.
256  *
257  * MPSAFE
258  */
259 int
260 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
261 {
262         struct nameidata nd;
263         int vfslocked, error;
264
265         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
266         error = namei(&nd);
267         vfslocked = NDHASGIANT(&nd);
268         if (error == 0) {
269                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
270                 NDFREE(&nd, 0);
271         }
272         VFS_UNLOCK_GIANT(vfslocked);
273         return (error);
274 }
275
276 /*
277  * Given a file descriptor, get an ACL for it
278  *
279  * MPSAFE
280  */
281 int
282 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
283 {
284         struct file *fp;
285         int vfslocked, error;
286
287         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
288         if (error == 0) {
289                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
290                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
291                 fdrop(fp, td);
292                 VFS_UNLOCK_GIANT(vfslocked);
293         }
294         return (error);
295 }
296
297 /*
298  * Given a file descriptor, set an ACL for it
299  *
300  * MPSAFE
301  */
302 int
303 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
304 {
305         struct file *fp;
306         int vfslocked, error;
307
308         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
309         if (error == 0) {
310                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
311                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
312                 fdrop(fp, td);
313                 VFS_UNLOCK_GIANT(vfslocked);
314         }
315         return (error);
316 }
317
318 /*
319  * Given a file path, delete an ACL from it.
320  *
321  * MPSAFE
322  */
323 int
324 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
325 {
326         struct nameidata nd;
327         int vfslocked, error;
328
329         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
330         error = namei(&nd);
331         vfslocked = NDHASGIANT(&nd);
332         if (error == 0) {
333                 error = vacl_delete(td, nd.ni_vp, uap->type);
334                 NDFREE(&nd, 0);
335         }
336         VFS_UNLOCK_GIANT(vfslocked);
337         return (error);
338 }
339
340 /*
341  * Given a file path, delete an ACL from it; don't follow links.
342  *
343  * MPSAFE
344  */
345 int
346 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
347 {
348         struct nameidata nd;
349         int vfslocked, error;
350
351         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
352         error = namei(&nd);
353         vfslocked = NDHASGIANT(&nd);
354         if (error == 0) {
355                 error = vacl_delete(td, nd.ni_vp, uap->type);
356                 NDFREE(&nd, 0);
357         }
358         VFS_UNLOCK_GIANT(vfslocked);
359         return (error);
360 }
361
362 /*
363  * Given a file path, delete an ACL from it.
364  *
365  * MPSAFE
366  */
367 int
368 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
369 {
370         struct file *fp;
371         int vfslocked, error;
372
373         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
374         if (error == 0) {
375                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
376                 error = vacl_delete(td, fp->f_vnode, uap->type);
377                 fdrop(fp, td);
378                 VFS_UNLOCK_GIANT(vfslocked);
379         }
380         return (error);
381 }
382
383 /*
384  * Given a file path, check an ACL for it
385  *
386  * MPSAFE
387  */
388 int
389 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
390 {
391         struct nameidata        nd;
392         int vfslocked, error;
393
394         NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
395         error = namei(&nd);
396         vfslocked = NDHASGIANT(&nd);
397         if (error == 0) {
398                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
399                 NDFREE(&nd, 0);
400         }
401         VFS_UNLOCK_GIANT(vfslocked);
402         return (error);
403 }
404
405 /*
406  * Given a file path, check an ACL for it; don't follow links.
407  *
408  * MPSAFE
409  */
410 int
411 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
412 {
413         struct nameidata        nd;
414         int vfslocked, error;
415
416         NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
417         error = namei(&nd);
418         vfslocked = NDHASGIANT(&nd);
419         if (error == 0) {
420                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
421                 NDFREE(&nd, 0);
422         }
423         VFS_UNLOCK_GIANT(vfslocked);
424         return (error);
425 }
426
427 /*
428  * Given a file descriptor, check an ACL for it
429  *
430  * MPSAFE
431  */
432 int
433 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
434 {
435         struct file *fp;
436         int vfslocked, error;
437
438         error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
439         if (error == 0) {
440                 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
441                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
442                 fdrop(fp, td);
443                 VFS_UNLOCK_GIANT(vfslocked);
444         }
445         return (error);
446 }
447
448 /* ARGUSED */
449
450 static void
451 aclinit(void *dummy __unused)
452 {
453
454         acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl),
455             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
456 }
457 SYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL)