Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /*- |
2 | * Copyright (c) 1999, 2000 Robert N. M. Watson | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * | |
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
24 | * SUCH DAMAGE. | |
25 | * | |
26 | * $FreeBSD: src/sys/kern/kern_acl.c,v 1.2.2.1 2000/07/28 18:48:16 rwatson Exp $ | |
dadab5e9 | 27 | * $DragonFly: src/sys/kern/kern_acl.c,v 1.4 2003/06/25 03:55:57 dillon Exp $ |
984263bc MD |
28 | */ |
29 | ||
30 | /* | |
31 | * Generic routines to support file system ACLs, at a syntactic level | |
32 | * Semantics are the responsibility of the underlying file system | |
33 | */ | |
34 | ||
35 | #include <sys/param.h> | |
36 | #include <sys/systm.h> | |
37 | #include <sys/sysproto.h> | |
38 | #include <sys/kernel.h> | |
39 | #include <sys/malloc.h> | |
40 | #include <sys/vnode.h> | |
41 | #include <sys/lock.h> | |
dadab5e9 | 42 | #include <sys/proc.h> |
984263bc MD |
43 | #include <sys/namei.h> |
44 | #include <sys/file.h> | |
984263bc MD |
45 | #include <sys/sysent.h> |
46 | #include <sys/errno.h> | |
47 | #include <sys/stat.h> | |
48 | #include <sys/acl.h> | |
49 | ||
50 | static MALLOC_DEFINE(M_ACL, "acl", "access control list"); | |
51 | ||
41c20dac MD |
52 | static int vacl_set_acl(struct vnode *vp, acl_type_t type, struct acl *aclp); |
53 | static int vacl_get_acl(struct vnode *vp, acl_type_t type, struct acl *aclp); | |
54 | static int vacl_aclcheck(struct vnode *vp, acl_type_t type, struct acl *aclp); | |
984263bc MD |
55 | |
56 | /* | |
57 | * These calls wrap the real vnode operations, and are called by the | |
58 | * syscall code once the syscall has converted the path or file | |
59 | * descriptor to a vnode (unlocked). The aclp pointer is assumed | |
60 | * still to point to userland, so this should not be consumed within | |
61 | * the kernel except by syscall code. Other code should directly | |
62 | * invoke VOP_{SET,GET}ACL. | |
63 | */ | |
64 | ||
65 | /* | |
66 | * Given a vnode, set its ACL. | |
67 | */ | |
68 | static int | |
41c20dac | 69 | vacl_set_acl(struct vnode *vp, acl_type_t type, struct acl *aclp) |
984263bc | 70 | { |
dadab5e9 | 71 | struct thread *td = curthread; |
984263bc | 72 | struct acl inkernacl; |
dadab5e9 | 73 | struct ucred *ucred; |
984263bc MD |
74 | int error; |
75 | ||
76 | error = copyin(aclp, &inkernacl, sizeof(struct acl)); | |
77 | if (error) | |
78 | return(error); | |
dadab5e9 MD |
79 | KKASSERT(td->td_proc); |
80 | ucred = td->td_proc->p_ucred; | |
81 | ||
82 | VOP_LEASE(vp, td, ucred, LEASE_WRITE); | |
83 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); | |
84 | error = VOP_SETACL(vp, type, &inkernacl, ucred, td); | |
85 | VOP_UNLOCK(vp, 0, td); | |
984263bc MD |
86 | return(error); |
87 | } | |
88 | ||
89 | /* | |
90 | * Given a vnode, get its ACL. | |
91 | */ | |
92 | static int | |
41c20dac | 93 | vacl_get_acl(struct vnode *vp, acl_type_t type, struct acl *aclp) |
984263bc | 94 | { |
dadab5e9 | 95 | struct thread *td = curthread; |
984263bc | 96 | struct acl inkernelacl; |
dadab5e9 | 97 | struct ucred *ucred; |
984263bc MD |
98 | int error; |
99 | ||
dadab5e9 MD |
100 | KKASSERT(td->td_proc); |
101 | ucred = td->td_proc->p_ucred; | |
102 | error = VOP_GETACL(vp, type, &inkernelacl, ucred, td); | |
984263bc MD |
103 | if (error == 0) |
104 | error = copyout(&inkernelacl, aclp, sizeof(struct acl)); | |
105 | return (error); | |
106 | } | |
107 | ||
108 | /* | |
109 | * Given a vnode, delete its ACL. | |
110 | */ | |
111 | static int | |
41c20dac | 112 | vacl_delete(struct vnode *vp, acl_type_t type) |
984263bc | 113 | { |
dadab5e9 MD |
114 | struct thread *td = curthread; |
115 | struct ucred *ucred; | |
984263bc MD |
116 | int error; |
117 | ||
dadab5e9 MD |
118 | KKASSERT(td->td_proc); |
119 | ucred = td->td_proc->p_ucred; | |
120 | VOP_LEASE(vp, td, ucred, LEASE_WRITE); | |
121 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); | |
122 | error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, ucred, td); | |
123 | VOP_UNLOCK(vp, 0, td); | |
984263bc MD |
124 | return (error); |
125 | } | |
126 | ||
127 | /* | |
128 | * Given a vnode, check whether an ACL is appropriate for it | |
129 | */ | |
130 | static int | |
41c20dac | 131 | vacl_aclcheck(struct vnode *vp, acl_type_t type, struct acl *aclp) |
984263bc | 132 | { |
dadab5e9 MD |
133 | struct thread *td = curthread; |
134 | struct ucred *ucred; | |
984263bc MD |
135 | struct acl inkernelacl; |
136 | int error; | |
137 | ||
dadab5e9 MD |
138 | KKASSERT(td->td_proc); |
139 | ucred = td->td_proc->p_ucred; | |
984263bc MD |
140 | error = copyin(aclp, &inkernelacl, sizeof(struct acl)); |
141 | if (error) | |
142 | return(error); | |
dadab5e9 | 143 | error = VOP_ACLCHECK(vp, type, &inkernelacl, ucred, td); |
984263bc MD |
144 | return (error); |
145 | } | |
146 | ||
147 | /* | |
148 | * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. | |
149 | * Don't need to lock, as the vacl_ code will get/release any locks | |
150 | * required. | |
151 | */ | |
152 | ||
153 | /* | |
154 | * Given a file path, get an ACL for it | |
155 | */ | |
156 | int | |
41c20dac | 157 | __acl_get_file(struct __acl_get_file_args *uap) |
984263bc | 158 | { |
dadab5e9 | 159 | struct thread *td = curthread; |
984263bc MD |
160 | struct nameidata nd; |
161 | int error; | |
162 | ||
163 | /* what flags are required here -- possible not LOCKLEAF? */ | |
dadab5e9 | 164 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); |
984263bc MD |
165 | error = namei(&nd); |
166 | if (error) | |
167 | return(error); | |
41c20dac | 168 | error = vacl_get_acl(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); |
984263bc MD |
169 | NDFREE(&nd, 0); |
170 | return (error); | |
171 | } | |
172 | ||
173 | /* | |
174 | * Given a file path, set an ACL for it | |
175 | */ | |
176 | int | |
41c20dac | 177 | __acl_set_file(struct __acl_set_file_args *uap) |
984263bc | 178 | { |
dadab5e9 | 179 | struct thread *td = curthread; |
984263bc MD |
180 | struct nameidata nd; |
181 | int error; | |
182 | ||
dadab5e9 | 183 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); |
984263bc MD |
184 | error = namei(&nd); |
185 | if (error) | |
186 | return(error); | |
41c20dac | 187 | error = vacl_set_acl(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); |
984263bc MD |
188 | NDFREE(&nd, 0); |
189 | return (error); | |
190 | } | |
191 | ||
192 | /* | |
193 | * Given a file descriptor, get an ACL for it | |
194 | */ | |
195 | int | |
41c20dac | 196 | __acl_get_fd(struct __acl_get_fd_args *uap) |
984263bc | 197 | { |
dadab5e9 | 198 | struct thread *td = curthread; |
984263bc MD |
199 | struct file *fp; |
200 | int error; | |
201 | ||
dadab5e9 MD |
202 | KKASSERT(td->td_proc); |
203 | error = getvnode(td->td_proc->p_fd, SCARG(uap, filedes), &fp); | |
984263bc MD |
204 | if (error) |
205 | return(error); | |
41c20dac | 206 | return vacl_get_acl((struct vnode *)fp->f_data, SCARG(uap, type), |
984263bc MD |
207 | SCARG(uap, aclp)); |
208 | } | |
209 | ||
210 | /* | |
211 | * Given a file descriptor, set an ACL for it | |
212 | */ | |
213 | int | |
41c20dac | 214 | __acl_set_fd(struct __acl_set_fd_args *uap) |
984263bc | 215 | { |
dadab5e9 | 216 | struct thread *td = curthread; |
984263bc MD |
217 | struct file *fp; |
218 | int error; | |
219 | ||
dadab5e9 MD |
220 | KKASSERT(td->td_proc); |
221 | error = getvnode(td->td_proc->p_fd, SCARG(uap, filedes), &fp); | |
984263bc MD |
222 | if (error) |
223 | return(error); | |
41c20dac | 224 | return vacl_set_acl((struct vnode *)fp->f_data, SCARG(uap, type), |
984263bc MD |
225 | SCARG(uap, aclp)); |
226 | } | |
227 | ||
228 | /* | |
229 | * Given a file path, delete an ACL from it. | |
230 | */ | |
231 | int | |
41c20dac | 232 | __acl_delete_file(struct __acl_delete_file_args *uap) |
984263bc | 233 | { |
dadab5e9 | 234 | struct thread *td = curthread; |
984263bc MD |
235 | struct nameidata nd; |
236 | int error; | |
237 | ||
dadab5e9 | 238 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); |
984263bc MD |
239 | error = namei(&nd); |
240 | if (error) | |
241 | return(error); | |
41c20dac | 242 | error = vacl_delete(nd.ni_vp, SCARG(uap, type)); |
984263bc MD |
243 | NDFREE(&nd, 0); |
244 | return (error); | |
245 | } | |
246 | ||
247 | /* | |
248 | * Given a file path, delete an ACL from it. | |
249 | */ | |
250 | int | |
41c20dac | 251 | __acl_delete_fd(struct __acl_delete_fd_args *uap) |
984263bc | 252 | { |
dadab5e9 | 253 | struct thread *td = curthread; |
984263bc MD |
254 | struct file *fp; |
255 | int error; | |
256 | ||
dadab5e9 MD |
257 | KKASSERT(td->td_proc); |
258 | error = getvnode(td->td_proc->p_fd, SCARG(uap, filedes), &fp); | |
984263bc MD |
259 | if (error) |
260 | return(error); | |
41c20dac | 261 | error = vacl_delete((struct vnode *)fp->f_data, SCARG(uap, type)); |
984263bc MD |
262 | return (error); |
263 | } | |
264 | ||
265 | /* | |
266 | * Given a file path, check an ACL for it | |
267 | */ | |
268 | int | |
41c20dac | 269 | __acl_aclcheck_file(struct __acl_aclcheck_file_args *uap) |
984263bc | 270 | { |
dadab5e9 | 271 | struct thread *td = curthread; |
984263bc MD |
272 | struct nameidata nd; |
273 | int error; | |
274 | ||
dadab5e9 | 275 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); |
984263bc MD |
276 | error = namei(&nd); |
277 | if (error) | |
278 | return(error); | |
41c20dac | 279 | error = vacl_aclcheck(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); |
984263bc MD |
280 | NDFREE(&nd, 0); |
281 | return (error); | |
282 | } | |
283 | ||
284 | /* | |
285 | * Given a file descriptor, check an ACL for it | |
286 | */ | |
287 | int | |
41c20dac | 288 | __acl_aclcheck_fd(struct __acl_aclcheck_fd_args *uap) |
984263bc | 289 | { |
dadab5e9 | 290 | struct thread *td = curthread; |
984263bc MD |
291 | struct file *fp; |
292 | int error; | |
293 | ||
dadab5e9 MD |
294 | KKASSERT(td->td_proc); |
295 | error = getvnode(td->td_proc->p_fd, SCARG(uap, filedes), &fp); | |
984263bc MD |
296 | if (error) |
297 | return(error); | |
41c20dac | 298 | return vacl_aclcheck((struct vnode *)fp->f_data, SCARG(uap, type), |
984263bc MD |
299 | SCARG(uap, aclp)); |
300 | } |