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