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) 457