vfs_acl.c revision 177785
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 177785 2008-03-31 12:01:21Z kib $"); 37116182Sobrien 38101122Srwatson#include "opt_mac.h" 39101122Srwatson 4054803Srwatson#include <sys/param.h> 4154803Srwatson#include <sys/systm.h> 4254803Srwatson#include <sys/sysproto.h> 43177785Skib#include <sys/fcntl.h> 4454803Srwatson#include <sys/kernel.h> 4554803Srwatson#include <sys/malloc.h> 46150262Scsjp#include <sys/mount.h> 4754803Srwatson#include <sys/vnode.h> 4854803Srwatson#include <sys/lock.h> 4982713Sdillon#include <sys/mutex.h> 5054803Srwatson#include <sys/namei.h> 5154803Srwatson#include <sys/file.h> 52108524Salfred#include <sys/filedesc.h> 5354803Srwatson#include <sys/proc.h> 5454803Srwatson#include <sys/sysent.h> 5554803Srwatson#include <sys/acl.h> 5654803Srwatson 57163606Srwatson#include <security/mac/mac_framework.h> 58163606Srwatson 59149811Scsjp#include <vm/uma.h> 6054803Srwatson 61149811Scsjpuma_zone_t acl_zone; 6298927Srwatsonstatic int vacl_set_acl(struct thread *td, struct vnode *vp, 6398927Srwatson acl_type_t type, struct acl *aclp); 6498927Srwatsonstatic int vacl_get_acl(struct thread *td, struct vnode *vp, 6598927Srwatson acl_type_t type, struct acl *aclp); 6685582Srwatsonstatic int vacl_aclcheck(struct thread *td, struct vnode *vp, 6798927Srwatson acl_type_t type, struct acl *aclp); 6854803Srwatson 6954803Srwatson/* 70165983Srwatson * These calls wrap the real vnode operations, and are called by the syscall 71165983Srwatson * code once the syscall has converted the path or file descriptor to a vnode 72165983Srwatson * (unlocked). The aclp pointer is assumed still to point to userland, so 73165983Srwatson * this should not be consumed within the kernel except by syscall code. 74165983Srwatson * Other code should directly invoke VOP_{SET,GET}ACL. 7554803Srwatson */ 7654803Srwatson 7754803Srwatson/* 7854803Srwatson * Given a vnode, set its ACL. 7954803Srwatson */ 8054803Srwatsonstatic int 8185582Srwatsonvacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, 8256272Srwatson struct acl *aclp) 8354803Srwatson{ 8454803Srwatson struct acl inkernacl; 8590202Srwatson struct mount *mp; 8654803Srwatson int error; 8754803Srwatson 8854803Srwatson error = copyin(aclp, &inkernacl, sizeof(struct acl)); 8954803Srwatson if (error) 9054803Srwatson return(error); 9190202Srwatson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 9290202Srwatson if (error != 0) 9390202Srwatson return (error); 9491406Sjhb VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 95175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 96101122Srwatson#ifdef MAC 97172930Srwatson error = mac_vnode_check_setacl(td->td_ucred, vp, type, &inkernacl); 98101122Srwatson if (error != 0) 99101122Srwatson goto out; 100101122Srwatson#endif 10191406Sjhb error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td); 102101122Srwatson#ifdef MAC 103101122Srwatsonout: 104101122Srwatson#endif 105175294Sattilio VOP_UNLOCK(vp, 0); 10690202Srwatson vn_finished_write(mp); 10771699Sjhb return(error); 10854803Srwatson} 10954803Srwatson 11054803Srwatson/* 11154803Srwatson * Given a vnode, get its ACL. 11254803Srwatson */ 11354803Srwatsonstatic int 11485582Srwatsonvacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type, 11554803Srwatson struct acl *aclp) 11654803Srwatson{ 11754803Srwatson struct acl inkernelacl; 11854803Srwatson int error; 11954803Srwatson 12091406Sjhb VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 121175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 122101122Srwatson#ifdef MAC 123172930Srwatson error = mac_vnode_check_getacl(td->td_ucred, vp, type); 124101122Srwatson if (error != 0) 125101122Srwatson goto out; 126101122Srwatson#endif 12791406Sjhb error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td); 128101122Srwatson#ifdef MAC 129101122Srwatsonout: 130101122Srwatson#endif 131175294Sattilio VOP_UNLOCK(vp, 0); 13254803Srwatson if (error == 0) 13354803Srwatson error = copyout(&inkernelacl, aclp, sizeof(struct acl)); 13454803Srwatson return (error); 13554803Srwatson} 13654803Srwatson 13754803Srwatson/* 13854803Srwatson * Given a vnode, delete its ACL. 13954803Srwatson */ 14054803Srwatsonstatic int 14185582Srwatsonvacl_delete(struct thread *td, struct vnode *vp, acl_type_t type) 14254803Srwatson{ 14390202Srwatson struct mount *mp; 14454803Srwatson int error; 14554803Srwatson 14690202Srwatson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 14790202Srwatson if (error) 14890202Srwatson return (error); 14991406Sjhb VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 150175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 151101122Srwatson#ifdef MAC 152172930Srwatson error = mac_vnode_check_deleteacl(td->td_ucred, vp, type); 153101122Srwatson if (error) 154101122Srwatson goto out; 155101122Srwatson#endif 156101122Srwatson error = VOP_SETACL(vp, type, 0, td->td_ucred, td); 157101122Srwatson#ifdef MAC 158101122Srwatsonout: 159101122Srwatson#endif 160175294Sattilio VOP_UNLOCK(vp, 0); 16190202Srwatson vn_finished_write(mp); 16254803Srwatson return (error); 16354803Srwatson} 16454803Srwatson 16554803Srwatson/* 16654803Srwatson * Given a vnode, check whether an ACL is appropriate for it 16754803Srwatson */ 16854803Srwatsonstatic int 16985582Srwatsonvacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, 17054803Srwatson struct acl *aclp) 17154803Srwatson{ 17254803Srwatson struct acl inkernelacl; 17354803Srwatson int error; 17454803Srwatson 17554803Srwatson error = copyin(aclp, &inkernelacl, sizeof(struct acl)); 17654803Srwatson if (error) 17754803Srwatson return(error); 17891406Sjhb error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td); 17954803Srwatson return (error); 18054803Srwatson} 18154803Srwatson 18254803Srwatson/* 183165983Srwatson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. Don't 184165983Srwatson * need to lock, as the vacl_ code will get/release any locks required. 18554803Srwatson */ 18654803Srwatson 18754803Srwatson/* 18854803Srwatson * Given a file path, get an ACL for it 18954803Srwatson */ 19054803Srwatsonint 19185582Srwatson__acl_get_file(struct thread *td, struct __acl_get_file_args *uap) 19254803Srwatson{ 19354803Srwatson struct nameidata nd; 194150262Scsjp int vfslocked, error; 19554803Srwatson 196150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 19754803Srwatson error = namei(&nd); 198150262Scsjp vfslocked = NDHASGIANT(&nd); 19982713Sdillon if (error == 0) { 200107855Salfred error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 20182713Sdillon NDFREE(&nd, 0); 20282713Sdillon } 203150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 20454803Srwatson return (error); 20554803Srwatson} 20654803Srwatson 20754803Srwatson/* 208108407Srwatson * Given a file path, get an ACL for it; don't follow links. 209108407Srwatson */ 210108407Srwatsonint 211108407Srwatson__acl_get_link(struct thread *td, struct __acl_get_link_args *uap) 212108407Srwatson{ 213108407Srwatson struct nameidata nd; 214150262Scsjp int vfslocked, error; 215108407Srwatson 216150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 217108407Srwatson error = namei(&nd); 218150262Scsjp vfslocked = NDHASGIANT(&nd); 219108407Srwatson if (error == 0) { 220108407Srwatson error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 221108407Srwatson NDFREE(&nd, 0); 222108407Srwatson } 223150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 224108407Srwatson return (error); 225108407Srwatson} 226108407Srwatson 227108407Srwatson/* 228167211Srwatson * Given a file path, set an ACL for it. 22954803Srwatson */ 23054803Srwatsonint 23185582Srwatson__acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 23254803Srwatson{ 23354803Srwatson struct nameidata nd; 234150262Scsjp int vfslocked, error; 23554803Srwatson 236150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 23754803Srwatson error = namei(&nd); 238150262Scsjp vfslocked = NDHASGIANT(&nd); 23982713Sdillon if (error == 0) { 240107855Salfred error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 24182713Sdillon NDFREE(&nd, 0); 24282713Sdillon } 243150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 24454803Srwatson return (error); 24554803Srwatson} 24654803Srwatson 24754803Srwatson/* 248108407Srwatson * Given a file path, set an ACL for it; don't follow links. 249108407Srwatson */ 250108407Srwatsonint 251108407Srwatson__acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 252108407Srwatson{ 253108407Srwatson struct nameidata nd; 254150262Scsjp int vfslocked, error; 255108407Srwatson 256150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 257108407Srwatson error = namei(&nd); 258150262Scsjp vfslocked = NDHASGIANT(&nd); 259108407Srwatson if (error == 0) { 260108407Srwatson error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 261108407Srwatson NDFREE(&nd, 0); 262108407Srwatson } 263150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 264108407Srwatson return (error); 265108407Srwatson} 266108407Srwatson 267108407Srwatson/* 268167234Srwatson * Given a file descriptor, get an ACL for it. 26954803Srwatson */ 27054803Srwatsonint 27185582Srwatson__acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) 27254803Srwatson{ 27354803Srwatson struct file *fp; 274150262Scsjp int vfslocked, error; 27554803Srwatson 276107849Salfred error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 27782713Sdillon if (error == 0) { 278150262Scsjp vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 279116678Sphk error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); 28089306Salfred fdrop(fp, td); 281150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 28282713Sdillon } 28382713Sdillon return (error); 28454803Srwatson} 28554803Srwatson 28654803Srwatson/* 287167234Srwatson * Given a file descriptor, set an ACL for it. 28854803Srwatson */ 28954803Srwatsonint 29085582Srwatson__acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) 29154803Srwatson{ 29254803Srwatson struct file *fp; 293150262Scsjp int vfslocked, error; 29454803Srwatson 295107849Salfred error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 29682713Sdillon if (error == 0) { 297150262Scsjp vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 298116678Sphk error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); 29989306Salfred fdrop(fp, td); 300150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 30182713Sdillon } 30282713Sdillon return (error); 30354803Srwatson} 30454803Srwatson 30554803Srwatson/* 30654803Srwatson * Given a file path, delete an ACL from it. 30754803Srwatson */ 30854803Srwatsonint 30985582Srwatson__acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) 31054803Srwatson{ 31154803Srwatson struct nameidata nd; 312150262Scsjp int vfslocked, error; 31354803Srwatson 314150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 31554803Srwatson error = namei(&nd); 316150262Scsjp vfslocked = NDHASGIANT(&nd); 31782713Sdillon if (error == 0) { 318107849Salfred error = vacl_delete(td, nd.ni_vp, uap->type); 31982713Sdillon NDFREE(&nd, 0); 32082713Sdillon } 321150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 32254803Srwatson return (error); 32354803Srwatson} 32454803Srwatson 32554803Srwatson/* 326108407Srwatson * Given a file path, delete an ACL from it; don't follow links. 327108407Srwatson */ 328108407Srwatsonint 329108407Srwatson__acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) 330108407Srwatson{ 331108407Srwatson struct nameidata nd; 332150262Scsjp int vfslocked, error; 333108407Srwatson 334150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 335108407Srwatson error = namei(&nd); 336150262Scsjp vfslocked = NDHASGIANT(&nd); 337108407Srwatson if (error == 0) { 338108407Srwatson error = vacl_delete(td, nd.ni_vp, uap->type); 339108407Srwatson NDFREE(&nd, 0); 340108407Srwatson } 341150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 342108407Srwatson return (error); 343108407Srwatson} 344108407Srwatson 345108407Srwatson/* 34654803Srwatson * Given a file path, delete an ACL from it. 34754803Srwatson */ 34854803Srwatsonint 34985582Srwatson__acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) 35054803Srwatson{ 35154803Srwatson struct file *fp; 352150262Scsjp int vfslocked, error; 35354803Srwatson 354107849Salfred error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 35582713Sdillon if (error == 0) { 356150262Scsjp vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 357116678Sphk error = vacl_delete(td, fp->f_vnode, uap->type); 35889306Salfred fdrop(fp, td); 359150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 36082713Sdillon } 36154803Srwatson return (error); 36254803Srwatson} 36354803Srwatson 36454803Srwatson/* 365167211Srwatson * Given a file path, check an ACL for it. 36654803Srwatson */ 36754803Srwatsonint 36885582Srwatson__acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) 36954803Srwatson{ 37054803Srwatson struct nameidata nd; 371150262Scsjp int vfslocked, error; 37254803Srwatson 373150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 37454803Srwatson error = namei(&nd); 375150262Scsjp vfslocked = NDHASGIANT(&nd); 37682713Sdillon if (error == 0) { 377107855Salfred error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 37882713Sdillon NDFREE(&nd, 0); 37982713Sdillon } 380150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 38154803Srwatson return (error); 38254803Srwatson} 38354803Srwatson 38454803Srwatson/* 385108407Srwatson * Given a file path, check an ACL for it; don't follow links. 386108407Srwatson */ 387108407Srwatsonint 388108407Srwatson__acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) 389108407Srwatson{ 390108407Srwatson struct nameidata nd; 391150262Scsjp int vfslocked, error; 392108407Srwatson 393150262Scsjp NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 394108407Srwatson error = namei(&nd); 395150262Scsjp vfslocked = NDHASGIANT(&nd); 396108407Srwatson if (error == 0) { 397108407Srwatson error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 398108407Srwatson NDFREE(&nd, 0); 399108407Srwatson } 400150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 401108407Srwatson return (error); 402108407Srwatson} 403108407Srwatson 404108407Srwatson/* 405167211Srwatson * Given a file descriptor, check an ACL for it. 40654803Srwatson */ 40754803Srwatsonint 40885582Srwatson__acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) 40954803Srwatson{ 41054803Srwatson struct file *fp; 411150262Scsjp int vfslocked, error; 41254803Srwatson 413107849Salfred error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 41482713Sdillon if (error == 0) { 415150262Scsjp vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 416116678Sphk error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); 41789306Salfred fdrop(fp, td); 418150262Scsjp VFS_UNLOCK_GIANT(vfslocked); 41982713Sdillon } 42082713Sdillon return (error); 42154803Srwatson} 422149811Scsjp 423149811Scsjp/* ARGUSED */ 424149811Scsjp 425149811Scsjpstatic void 426149811Scsjpaclinit(void *dummy __unused) 427149811Scsjp{ 428149811Scsjp 429149811Scsjp acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl), 430149811Scsjp NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 431149811Scsjp} 432177253SrwatsonSYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL); 433