vfs_acl.c revision 167211
154803Srwatson/*- 2160146Srwatson * Copyright (c) 1999-2006 Robert N. M. Watson 354803Srwatson * All rights reserved. 454803Srwatson * 585845Srwatson * This software was developed by Robert Watson for the TrustedBSD Project. 685845Srwatson * 754803Srwatson * Redistribution and use in source and binary forms, with or without 854803Srwatson * modification, are permitted provided that the following conditions 954803Srwatson * are met: 1054803Srwatson * 1. Redistributions of source code must retain the above copyright 1154803Srwatson * notice, this list of conditions and the following disclaimer. 1254803Srwatson * 2. Redistributions in binary form must reproduce the above copyright 1354803Srwatson * notice, this list of conditions and the following disclaimer in the 1454803Srwatson * documentation and/or other materials provided with the distribution. 1554803Srwatson * 1654803Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1754803Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1854803Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1954803Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2054803Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2154803Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2254803Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2354803Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2454803Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2554803Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2654803Srwatson * SUCH DAMAGE. 2754803Srwatson */ 2854803Srwatson/* 2973890Srwatson * Developed by the TrustedBSD Project. 30160146Srwatson * 31160146Srwatson * ACL system calls and other functions common across different ACL types. 32160146Srwatson * Type-specific routines go into subr_acl_<type>.c. 3354803Srwatson */ 3454803Srwatson 35116182Sobrien#include <sys/cdefs.h> 36116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_acl.c 167211 2007-03-04 22:36:48Z rwatson $"); 37116182Sobrien 38101122Srwatson#include "opt_mac.h" 39101122Srwatson 4054803Srwatson#include <sys/param.h> 4154803Srwatson#include <sys/systm.h> 4254803Srwatson#include <sys/sysproto.h> 4354803Srwatson#include <sys/kernel.h> 4454803Srwatson#include <sys/malloc.h> 45150262Scsjp#include <sys/mount.h> 4654803Srwatson#include <sys/vnode.h> 4754803Srwatson#include <sys/lock.h> 4882713Sdillon#include <sys/mutex.h> 4954803Srwatson#include <sys/namei.h> 5054803Srwatson#include <sys/file.h> 51108524Salfred#include <sys/filedesc.h> 5254803Srwatson#include <sys/proc.h> 5354803Srwatson#include <sys/sysent.h> 5454803Srwatson#include <sys/acl.h> 5554803Srwatson 56163606Srwatson#include <security/mac/mac_framework.h> 57163606Srwatson 58149811Scsjp#include <vm/uma.h> 5954803Srwatson 60149811Scsjpuma_zone_t acl_zone; 6198927Srwatsonstatic int vacl_set_acl(struct thread *td, struct vnode *vp, 6298927Srwatson acl_type_t type, struct acl *aclp); 6398927Srwatsonstatic int vacl_get_acl(struct thread *td, struct vnode *vp, 6498927Srwatson acl_type_t type, struct acl *aclp); 6585582Srwatsonstatic int vacl_aclcheck(struct thread *td, struct vnode *vp, 6698927Srwatson acl_type_t type, struct acl *aclp); 6754803Srwatson 6854803Srwatson/* 69165983Srwatson * These calls wrap the real vnode operations, and are called by the syscall 70165983Srwatson * code once the syscall has converted the path or file descriptor to a vnode 71165983Srwatson * (unlocked). The aclp pointer is assumed still to point to userland, so 72165983Srwatson * this should not be consumed within the kernel except by syscall code. 73165983Srwatson * Other code should directly invoke VOP_{SET,GET}ACL. 7454803Srwatson */ 7554803Srwatson 7654803Srwatson/* 7754803Srwatson * Given a vnode, set its ACL. 7854803Srwatson */ 7954803Srwatsonstatic int 8085582Srwatsonvacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, 8156272Srwatson struct acl *aclp) 8254803Srwatson{ 8354803Srwatson struct acl inkernacl; 8490202Srwatson struct mount *mp; 8554803Srwatson int error; 8654803Srwatson 8754803Srwatson error = copyin(aclp, &inkernacl, sizeof(struct acl)); 8854803Srwatson if (error) 8954803Srwatson return(error); 9090202Srwatson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 9190202Srwatson if (error != 0) 9290202Srwatson return (error); 9391406Sjhb VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 9483366Sjulian vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 95101122Srwatson#ifdef MAC 96101122Srwatson error = mac_check_vnode_setacl(td->td_ucred, vp, type, &inkernacl); 97101122Srwatson if (error != 0) 98101122Srwatson goto out; 99101122Srwatson#endif 10091406Sjhb error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td); 101101122Srwatson#ifdef MAC 102101122Srwatsonout: 103101122Srwatson#endif 10483366Sjulian VOP_UNLOCK(vp, 0, td); 10590202Srwatson vn_finished_write(mp); 10671699Sjhb return(error); 10754803Srwatson} 10854803Srwatson 10954803Srwatson/* 11054803Srwatson * Given a vnode, get its ACL. 11154803Srwatson */ 11254803Srwatsonstatic int 11385582Srwatsonvacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type, 11454803Srwatson struct acl *aclp) 11554803Srwatson{ 11654803Srwatson struct acl inkernelacl; 11754803Srwatson int error; 11854803Srwatson 11991406Sjhb VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 12083366Sjulian vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 121101122Srwatson#ifdef MAC 122101122Srwatson error = mac_check_vnode_getacl(td->td_ucred, vp, type); 123101122Srwatson if (error != 0) 124101122Srwatson goto out; 125101122Srwatson#endif 12691406Sjhb error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td); 127101122Srwatson#ifdef MAC 128101122Srwatsonout: 129101122Srwatson#endif 13083366Sjulian VOP_UNLOCK(vp, 0, td); 13154803Srwatson if (error == 0) 13254803Srwatson error = copyout(&inkernelacl, aclp, sizeof(struct acl)); 13354803Srwatson return (error); 13454803Srwatson} 13554803Srwatson 13654803Srwatson/* 13754803Srwatson * Given a vnode, delete its ACL. 13854803Srwatson */ 13954803Srwatsonstatic int 14085582Srwatsonvacl_delete(struct thread *td, struct vnode *vp, acl_type_t type) 14154803Srwatson{ 14290202Srwatson struct mount *mp; 14354803Srwatson int error; 14454803Srwatson 14590202Srwatson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 14690202Srwatson if (error) 14790202Srwatson return (error); 14891406Sjhb VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 14983366Sjulian vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 150101122Srwatson#ifdef MAC 151101122Srwatson error = mac_check_vnode_deleteacl(td->td_ucred, vp, type); 152101122Srwatson if (error) 153101122Srwatson goto out; 154101122Srwatson#endif 155101122Srwatson error = VOP_SETACL(vp, type, 0, td->td_ucred, td); 156101122Srwatson#ifdef MAC 157101122Srwatsonout: 158101122Srwatson#endif 15983366Sjulian VOP_UNLOCK(vp, 0, td); 16090202Srwatson vn_finished_write(mp); 16154803Srwatson return (error); 16254803Srwatson} 16354803Srwatson 16454803Srwatson/* 16554803Srwatson * Given a vnode, check whether an ACL is appropriate for it 16654803Srwatson */ 16754803Srwatsonstatic int 16885582Srwatsonvacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, 16954803Srwatson struct acl *aclp) 17054803Srwatson{ 17154803Srwatson struct acl inkernelacl; 17254803Srwatson int error; 17354803Srwatson 17454803Srwatson error = copyin(aclp, &inkernelacl, sizeof(struct acl)); 17554803Srwatson if (error) 17654803Srwatson return(error); 17791406Sjhb error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td); 17854803Srwatson return (error); 17954803Srwatson} 18054803Srwatson 18154803Srwatson/* 182165983Srwatson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. Don't 183165983Srwatson * need to lock, as the vacl_ code will get/release any locks required. 18454803Srwatson */ 18554803Srwatson 18654803Srwatson/* 18754803Srwatson * Given a file path, get an ACL for it 18854803Srwatson */ 18954803Srwatsonint 19085582Srwatson__acl_get_file(struct thread *td, struct __acl_get_file_args *uap) 19154803Srwatson{ 19254803Srwatson struct nameidata nd; 193150262Scsjp int vfslocked, error; 19454803Srwatson 195150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 19654803Srwatson error = namei(&nd); 197150262Scsjp vfslocked = NDHASGIANT(&nd); 19882713Sdillon if (error == 0) { 199107855Salfred error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 20082713Sdillon NDFREE(&nd, 0); 20182713Sdillon } 202150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 20354803Srwatson return (error); 20454803Srwatson} 20554803Srwatson 20654803Srwatson/* 207108407Srwatson * Given a file path, get an ACL for it; don't follow links. 208108407Srwatson */ 209108407Srwatsonint 210108407Srwatson__acl_get_link(struct thread *td, struct __acl_get_link_args *uap) 211108407Srwatson{ 212108407Srwatson struct nameidata nd; 213150262Scsjp int vfslocked, error; 214108407Srwatson 215150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 216108407Srwatson error = namei(&nd); 217150262Scsjp vfslocked = NDHASGIANT(&nd); 218108407Srwatson if (error == 0) { 219108407Srwatson error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 220108407Srwatson NDFREE(&nd, 0); 221108407Srwatson } 222150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 223108407Srwatson return (error); 224108407Srwatson} 225108407Srwatson 226108407Srwatson/* 227167211Srwatson * Given a file path, set an ACL for it. 22854803Srwatson */ 22954803Srwatsonint 23085582Srwatson__acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 23154803Srwatson{ 23254803Srwatson struct nameidata nd; 233150262Scsjp int vfslocked, error; 23454803Srwatson 235150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 23654803Srwatson error = namei(&nd); 237150262Scsjp vfslocked = NDHASGIANT(&nd); 23882713Sdillon if (error == 0) { 239107855Salfred error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 24082713Sdillon NDFREE(&nd, 0); 24182713Sdillon } 242150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 24354803Srwatson return (error); 24454803Srwatson} 24554803Srwatson 24654803Srwatson/* 247108407Srwatson * Given a file path, set an ACL for it; don't follow links. 248108407Srwatson */ 249108407Srwatsonint 250108407Srwatson__acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 251108407Srwatson{ 252108407Srwatson struct nameidata nd; 253150262Scsjp int vfslocked, error; 254108407Srwatson 255150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 256108407Srwatson error = namei(&nd); 257150262Scsjp vfslocked = NDHASGIANT(&nd); 258108407Srwatson if (error == 0) { 259108407Srwatson error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 260108407Srwatson NDFREE(&nd, 0); 261108407Srwatson } 262150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 263108407Srwatson return (error); 264108407Srwatson} 265108407Srwatson 266108407Srwatson/* 26754803Srwatson * Given a file descriptor, get an ACL for it 26854803Srwatson */ 26954803Srwatsonint 27085582Srwatson__acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) 27154803Srwatson{ 27254803Srwatson struct file *fp; 273150262Scsjp int vfslocked, error; 27454803Srwatson 275107849Salfred error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 27682713Sdillon if (error == 0) { 277150262Scsjp vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 278116678Sphk error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); 27989306Salfred fdrop(fp, td); 280150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 28182713Sdillon } 28282713Sdillon return (error); 28354803Srwatson} 28454803Srwatson 28554803Srwatson/* 28654803Srwatson * Given a file descriptor, set an ACL for it 28754803Srwatson */ 28854803Srwatsonint 28985582Srwatson__acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) 29054803Srwatson{ 29154803Srwatson struct file *fp; 292150262Scsjp int vfslocked, error; 29354803Srwatson 294107849Salfred error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 29582713Sdillon if (error == 0) { 296150262Scsjp vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 297116678Sphk error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); 29889306Salfred fdrop(fp, td); 299150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 30082713Sdillon } 30182713Sdillon return (error); 30254803Srwatson} 30354803Srwatson 30454803Srwatson/* 30554803Srwatson * Given a file path, delete an ACL from it. 30654803Srwatson */ 30754803Srwatsonint 30885582Srwatson__acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) 30954803Srwatson{ 31054803Srwatson struct nameidata nd; 311150262Scsjp int vfslocked, error; 31254803Srwatson 313150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 31454803Srwatson error = namei(&nd); 315150262Scsjp vfslocked = NDHASGIANT(&nd); 31682713Sdillon if (error == 0) { 317107849Salfred error = vacl_delete(td, nd.ni_vp, uap->type); 31882713Sdillon NDFREE(&nd, 0); 31982713Sdillon } 320150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 32154803Srwatson return (error); 32254803Srwatson} 32354803Srwatson 32454803Srwatson/* 325108407Srwatson * Given a file path, delete an ACL from it; don't follow links. 326108407Srwatson */ 327108407Srwatsonint 328108407Srwatson__acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) 329108407Srwatson{ 330108407Srwatson struct nameidata nd; 331150262Scsjp int vfslocked, error; 332108407Srwatson 333150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 334108407Srwatson error = namei(&nd); 335150262Scsjp vfslocked = NDHASGIANT(&nd); 336108407Srwatson if (error == 0) { 337108407Srwatson error = vacl_delete(td, nd.ni_vp, uap->type); 338108407Srwatson NDFREE(&nd, 0); 339108407Srwatson } 340150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 341108407Srwatson return (error); 342108407Srwatson} 343108407Srwatson 344108407Srwatson/* 34554803Srwatson * Given a file path, delete an ACL from it. 34654803Srwatson */ 34754803Srwatsonint 34885582Srwatson__acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) 34954803Srwatson{ 35054803Srwatson struct file *fp; 351150262Scsjp int vfslocked, error; 35254803Srwatson 353107849Salfred error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 35482713Sdillon if (error == 0) { 355150262Scsjp vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 356116678Sphk error = vacl_delete(td, fp->f_vnode, uap->type); 35789306Salfred fdrop(fp, td); 358150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 35982713Sdillon } 36054803Srwatson return (error); 36154803Srwatson} 36254803Srwatson 36354803Srwatson/* 364167211Srwatson * Given a file path, check an ACL for it. 36554803Srwatson */ 36654803Srwatsonint 36785582Srwatson__acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) 36854803Srwatson{ 36954803Srwatson struct nameidata nd; 370150262Scsjp int vfslocked, error; 37154803Srwatson 372150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 37354803Srwatson error = namei(&nd); 374150262Scsjp vfslocked = NDHASGIANT(&nd); 37582713Sdillon if (error == 0) { 376107855Salfred error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 37782713Sdillon NDFREE(&nd, 0); 37882713Sdillon } 379150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 38054803Srwatson return (error); 38154803Srwatson} 38254803Srwatson 38354803Srwatson/* 384108407Srwatson * Given a file path, check an ACL for it; don't follow links. 385108407Srwatson */ 386108407Srwatsonint 387108407Srwatson__acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) 388108407Srwatson{ 389108407Srwatson struct nameidata nd; 390150262Scsjp int vfslocked, error; 391108407Srwatson 392150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 393108407Srwatson error = namei(&nd); 394150262Scsjp vfslocked = NDHASGIANT(&nd); 395108407Srwatson if (error == 0) { 396108407Srwatson error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 397108407Srwatson NDFREE(&nd, 0); 398108407Srwatson } 399150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 400108407Srwatson return (error); 401108407Srwatson} 402108407Srwatson 403108407Srwatson/* 404167211Srwatson * Given a file descriptor, check an ACL for it. 40554803Srwatson */ 40654803Srwatsonint 40785582Srwatson__acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) 40854803Srwatson{ 40954803Srwatson struct file *fp; 410150262Scsjp int vfslocked, error; 41154803Srwatson 412107849Salfred error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 41382713Sdillon if (error == 0) { 414150262Scsjp vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 415116678Sphk error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); 41689306Salfred fdrop(fp, td); 417150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 41882713Sdillon } 41982713Sdillon return (error); 42054803Srwatson} 421149811Scsjp 422149811Scsjp/* ARGUSED */ 423149811Scsjp 424149811Scsjpstatic void 425149811Scsjpaclinit(void *dummy __unused) 426149811Scsjp{ 427149811Scsjp 428149811Scsjp acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl), 429149811Scsjp NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 430149811Scsjp} 431149811ScsjpSYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL) 432