]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/kern/vfs_acl.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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/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);