191f37dcbSRobert Watson /*- 2e4256d1eSRobert Watson * Copyright (c) 1999-2006 Robert N. M. Watson 391f37dcbSRobert Watson * All rights reserved. 491f37dcbSRobert Watson * 56d878543SRobert Watson * This software was developed by Robert Watson for the TrustedBSD Project. 66d878543SRobert Watson * 791f37dcbSRobert Watson * Redistribution and use in source and binary forms, with or without 891f37dcbSRobert Watson * modification, are permitted provided that the following conditions 991f37dcbSRobert Watson * are met: 1091f37dcbSRobert Watson * 1. Redistributions of source code must retain the above copyright 1191f37dcbSRobert Watson * notice, this list of conditions and the following disclaimer. 1291f37dcbSRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 1391f37dcbSRobert Watson * notice, this list of conditions and the following disclaimer in the 1491f37dcbSRobert Watson * documentation and/or other materials provided with the distribution. 1591f37dcbSRobert Watson * 1691f37dcbSRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1791f37dcbSRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1891f37dcbSRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1991f37dcbSRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2091f37dcbSRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2191f37dcbSRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2291f37dcbSRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2391f37dcbSRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2491f37dcbSRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2591f37dcbSRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2691f37dcbSRobert Watson * SUCH DAMAGE. 2791f37dcbSRobert Watson */ 2891f37dcbSRobert Watson /* 295293465fSRobert Watson * Developed by the TrustedBSD Project. 30e4256d1eSRobert Watson * 31e4256d1eSRobert Watson * ACL system calls and other functions common across different ACL types. 32e4256d1eSRobert Watson * Type-specific routines go into subr_acl_<type>.c. 3391f37dcbSRobert Watson */ 3491f37dcbSRobert Watson 35677b542eSDavid E. O'Brien #include <sys/cdefs.h> 36677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 37677b542eSDavid E. O'Brien 3891f37dcbSRobert Watson #include <sys/param.h> 3991f37dcbSRobert Watson #include <sys/systm.h> 4091f37dcbSRobert Watson #include <sys/sysproto.h> 4157b4252eSKonstantin Belousov #include <sys/fcntl.h> 4291f37dcbSRobert Watson #include <sys/kernel.h> 4391f37dcbSRobert Watson #include <sys/malloc.h> 4442e7197fSChristian S.J. Peron #include <sys/mount.h> 4591f37dcbSRobert Watson #include <sys/vnode.h> 4691f37dcbSRobert Watson #include <sys/lock.h> 47f708f4d1SMatthew Dillon #include <sys/mutex.h> 4891f37dcbSRobert Watson #include <sys/namei.h> 4991f37dcbSRobert Watson #include <sys/file.h> 5013438f68SAlfred Perlstein #include <sys/filedesc.h> 5191f37dcbSRobert Watson #include <sys/proc.h> 5291f37dcbSRobert Watson #include <sys/sysent.h> 5391f37dcbSRobert Watson #include <sys/acl.h> 5491f37dcbSRobert Watson 55aed55708SRobert Watson #include <security/mac/mac_framework.h> 56aed55708SRobert Watson 57ae1add4eSEdward Tomasz Napierala CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES); 58ae1add4eSEdward Tomasz Napierala 59ae1add4eSEdward Tomasz Napierala MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists"); 6091f37dcbSRobert Watson 61cbeb8402SRobert Watson static int vacl_set_acl(struct thread *td, struct vnode *vp, 62cbeb8402SRobert Watson acl_type_t type, struct acl *aclp); 63cbeb8402SRobert Watson static int vacl_get_acl(struct thread *td, struct vnode *vp, 64cbeb8402SRobert Watson acl_type_t type, struct acl *aclp); 65b40ce416SJulian Elischer static int vacl_aclcheck(struct thread *td, struct vnode *vp, 66b114e127SRobert Watson acl_type_t type, struct acl *aclp); 6791f37dcbSRobert Watson 68ae1add4eSEdward Tomasz Napierala int 69ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest) 70ae1add4eSEdward Tomasz Napierala { 71ae1add4eSEdward Tomasz Napierala int i; 72ae1add4eSEdward Tomasz Napierala 73ae1add4eSEdward Tomasz Napierala if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) 74ae1add4eSEdward Tomasz Napierala return (EINVAL); 75ae1add4eSEdward Tomasz Napierala 76ae1add4eSEdward Tomasz Napierala bzero(dest, sizeof(*dest)); 77ae1add4eSEdward Tomasz Napierala 78ae1add4eSEdward Tomasz Napierala dest->acl_cnt = source->acl_cnt; 79ae1add4eSEdward Tomasz Napierala dest->acl_maxcnt = ACL_MAX_ENTRIES; 80ae1add4eSEdward Tomasz Napierala 81ae1add4eSEdward Tomasz Napierala for (i = 0; i < dest->acl_cnt; i++) { 82ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 83ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 84ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 85ae1add4eSEdward Tomasz Napierala } 86ae1add4eSEdward Tomasz Napierala 87ae1add4eSEdward Tomasz Napierala return (0); 88ae1add4eSEdward Tomasz Napierala } 89ae1add4eSEdward Tomasz Napierala 90ae1add4eSEdward Tomasz Napierala int 91ae1add4eSEdward Tomasz Napierala acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest) 92ae1add4eSEdward Tomasz Napierala { 93ae1add4eSEdward Tomasz Napierala int i; 94ae1add4eSEdward Tomasz Napierala 95ae1add4eSEdward Tomasz Napierala if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) 96ae1add4eSEdward Tomasz Napierala return (EINVAL); 97ae1add4eSEdward Tomasz Napierala 98ae1add4eSEdward Tomasz Napierala bzero(dest, sizeof(*dest)); 99ae1add4eSEdward Tomasz Napierala 100ae1add4eSEdward Tomasz Napierala dest->acl_cnt = source->acl_cnt; 101ae1add4eSEdward Tomasz Napierala 102ae1add4eSEdward Tomasz Napierala for (i = 0; i < dest->acl_cnt; i++) { 103ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 104ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 105ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 106ae1add4eSEdward Tomasz Napierala } 107ae1add4eSEdward Tomasz Napierala 108ae1add4eSEdward Tomasz Napierala return (0); 109ae1add4eSEdward Tomasz Napierala } 110ae1add4eSEdward Tomasz Napierala 111ae1add4eSEdward Tomasz Napierala /* 112ae1add4eSEdward Tomasz Napierala * At one time, "struct ACL" was extended in order to add support for NFSv4 113ae1add4eSEdward Tomasz Napierala * ACLs. Instead of creating compatibility versions of all the ACL-related 114ae1add4eSEdward Tomasz Napierala * syscalls, they were left intact. It's possible to find out what the code 115ae1add4eSEdward Tomasz Napierala * calling these syscalls (libc) expects basing on "type" argument - if it's 116ae1add4eSEdward Tomasz Napierala * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were 117ae1add4eSEdward Tomasz Napierala * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct 118ae1add4eSEdward Tomasz Napierala * oldacl". If it's something else, then it's the new "struct acl". In the 119ae1add4eSEdward Tomasz Napierala * latter case, the routines below just copyin/copyout the contents. In the 120ae1add4eSEdward Tomasz Napierala * former case, they copyin the "struct oldacl" and convert it to the new 121ae1add4eSEdward Tomasz Napierala * format. 122ae1add4eSEdward Tomasz Napierala */ 123ae1add4eSEdward Tomasz Napierala static int 124ae1add4eSEdward Tomasz Napierala acl_copyin(void *user_acl, struct acl *kernel_acl, acl_type_t type) 125ae1add4eSEdward Tomasz Napierala { 126ae1add4eSEdward Tomasz Napierala int error; 127ae1add4eSEdward Tomasz Napierala struct oldacl old; 128ae1add4eSEdward Tomasz Napierala 129ae1add4eSEdward Tomasz Napierala switch (type) { 130ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 131ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 132ae1add4eSEdward Tomasz Napierala error = copyin(user_acl, &old, sizeof(old)); 133ae1add4eSEdward Tomasz Napierala if (error != 0) 134ae1add4eSEdward Tomasz Napierala break; 135ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(&old, kernel_acl); 136ae1add4eSEdward Tomasz Napierala break; 137ae1add4eSEdward Tomasz Napierala 138ae1add4eSEdward Tomasz Napierala default: 139ae1add4eSEdward Tomasz Napierala error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl)); 140ae1add4eSEdward Tomasz Napierala if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES) 141ae1add4eSEdward Tomasz Napierala return (EINVAL); 142ae1add4eSEdward Tomasz Napierala } 143ae1add4eSEdward Tomasz Napierala 144ae1add4eSEdward Tomasz Napierala return (error); 145ae1add4eSEdward Tomasz Napierala } 146ae1add4eSEdward Tomasz Napierala 147ae1add4eSEdward Tomasz Napierala static int 148ae1add4eSEdward Tomasz Napierala acl_copyout(struct acl *kernel_acl, void *user_acl, acl_type_t type) 149ae1add4eSEdward Tomasz Napierala { 150ae1add4eSEdward Tomasz Napierala int error; 151ae1add4eSEdward Tomasz Napierala struct oldacl old; 152ae1add4eSEdward Tomasz Napierala 153ae1add4eSEdward Tomasz Napierala switch (type) { 154ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 155ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 156ae1add4eSEdward Tomasz Napierala error = acl_copy_acl_into_oldacl(kernel_acl, &old); 157ae1add4eSEdward Tomasz Napierala if (error != 0) 158ae1add4eSEdward Tomasz Napierala break; 159ae1add4eSEdward Tomasz Napierala 160ae1add4eSEdward Tomasz Napierala error = copyout(&old, user_acl, sizeof(old)); 161ae1add4eSEdward Tomasz Napierala break; 162ae1add4eSEdward Tomasz Napierala 163ae1add4eSEdward Tomasz Napierala default: 164d5e0b215SEdward Tomasz Napierala if (fuword32((char *)user_acl + 165ae1add4eSEdward Tomasz Napierala offsetof(struct acl, acl_maxcnt)) != ACL_MAX_ENTRIES) 166ae1add4eSEdward Tomasz Napierala return (EINVAL); 167ae1add4eSEdward Tomasz Napierala 168ae1add4eSEdward Tomasz Napierala error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl)); 169ae1add4eSEdward Tomasz Napierala } 170ae1add4eSEdward Tomasz Napierala 171ae1add4eSEdward Tomasz Napierala return (error); 172ae1add4eSEdward Tomasz Napierala } 173ae1add4eSEdward Tomasz Napierala 174ae1add4eSEdward Tomasz Napierala /* 175ae1add4eSEdward Tomasz Napierala * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new" 176ae1add4eSEdward Tomasz Napierala * counterpart. It's required for old (pre-NFS4 ACLs) libc to work 177ae1add4eSEdward Tomasz Napierala * with new kernel. Fixing 'type' for old binaries with new libc 178ae1add4eSEdward Tomasz Napierala * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold(). 179ae1add4eSEdward Tomasz Napierala */ 180ae1add4eSEdward Tomasz Napierala static int 181ae1add4eSEdward Tomasz Napierala acl_type_unold(int type) 182ae1add4eSEdward Tomasz Napierala { 183ae1add4eSEdward Tomasz Napierala switch (type) { 184ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 185ae1add4eSEdward Tomasz Napierala return (ACL_TYPE_ACCESS); 186ae1add4eSEdward Tomasz Napierala 187ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 188ae1add4eSEdward Tomasz Napierala return (ACL_TYPE_DEFAULT); 189ae1add4eSEdward Tomasz Napierala 190ae1add4eSEdward Tomasz Napierala default: 191ae1add4eSEdward Tomasz Napierala return (type); 192ae1add4eSEdward Tomasz Napierala } 193ae1add4eSEdward Tomasz Napierala } 194ae1add4eSEdward Tomasz Napierala 19591f37dcbSRobert Watson /* 196b0c521e2SRobert Watson * These calls wrap the real vnode operations, and are called by the syscall 197b0c521e2SRobert Watson * code once the syscall has converted the path or file descriptor to a vnode 198b0c521e2SRobert Watson * (unlocked). The aclp pointer is assumed still to point to userland, so 199b0c521e2SRobert Watson * this should not be consumed within the kernel except by syscall code. 200b0c521e2SRobert Watson * Other code should directly invoke VOP_{SET,GET}ACL. 20191f37dcbSRobert Watson */ 20291f37dcbSRobert Watson 20391f37dcbSRobert Watson /* 20491f37dcbSRobert Watson * Given a vnode, set its ACL. 20591f37dcbSRobert Watson */ 20691f37dcbSRobert Watson static int 207b40ce416SJulian Elischer vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, 20891f37dcbSRobert Watson struct acl *aclp) 20991f37dcbSRobert Watson { 210b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 2114e1123c7SRobert Watson struct mount *mp; 21291f37dcbSRobert Watson int error; 21391f37dcbSRobert Watson 214b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 215ae1add4eSEdward Tomasz Napierala error = acl_copyin(aclp, inkernelacl, type); 216da9ce28eSEdward Tomasz Napierala if (error != 0) 217b998d381SEdward Tomasz Napierala goto out; 2184e1123c7SRobert Watson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 2194e1123c7SRobert Watson if (error != 0) 220b998d381SEdward Tomasz Napierala goto out; 221cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 222c86ca022SRobert Watson #ifdef MAC 223b998d381SEdward Tomasz Napierala error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl); 224c86ca022SRobert Watson if (error != 0) 225b998d381SEdward Tomasz Napierala goto out_unlock; 226c86ca022SRobert Watson #endif 227ae1add4eSEdward Tomasz Napierala error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl, 228ae1add4eSEdward Tomasz Napierala td->td_ucred, td); 229c86ca022SRobert Watson #ifdef MAC 230b998d381SEdward Tomasz Napierala out_unlock: 231c86ca022SRobert Watson #endif 23222db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 2334e1123c7SRobert Watson vn_finished_write(mp); 234b998d381SEdward Tomasz Napierala out: 235b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 23691f37dcbSRobert Watson return (error); 23791f37dcbSRobert Watson } 23891f37dcbSRobert Watson 23991f37dcbSRobert Watson /* 24091f37dcbSRobert Watson * Given a vnode, get its ACL. 24191f37dcbSRobert Watson */ 24291f37dcbSRobert Watson static int 243b40ce416SJulian Elischer vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type, 24491f37dcbSRobert Watson struct acl *aclp) 24591f37dcbSRobert Watson { 246b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 24791f37dcbSRobert Watson int error; 24891f37dcbSRobert Watson 249b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 250cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 251c86ca022SRobert Watson #ifdef MAC 25230d239bcSRobert Watson error = mac_vnode_check_getacl(td->td_ucred, vp, type); 253c86ca022SRobert Watson if (error != 0) 254c86ca022SRobert Watson goto out; 255c86ca022SRobert Watson #endif 256ae1add4eSEdward Tomasz Napierala error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl, 257ae1add4eSEdward Tomasz Napierala td->td_ucred, td); 258ae1add4eSEdward Tomasz Napierala 259c86ca022SRobert Watson #ifdef MAC 260c86ca022SRobert Watson out: 261c86ca022SRobert Watson #endif 26222db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 26391f37dcbSRobert Watson if (error == 0) 264ae1add4eSEdward Tomasz Napierala error = acl_copyout(inkernelacl, aclp, type); 265b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 26691f37dcbSRobert Watson return (error); 26791f37dcbSRobert Watson } 26891f37dcbSRobert Watson 26991f37dcbSRobert Watson /* 27091f37dcbSRobert Watson * Given a vnode, delete its ACL. 27191f37dcbSRobert Watson */ 27291f37dcbSRobert Watson static int 273b40ce416SJulian Elischer vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type) 27491f37dcbSRobert Watson { 2754e1123c7SRobert Watson struct mount *mp; 27691f37dcbSRobert Watson int error; 27791f37dcbSRobert Watson 2784e1123c7SRobert Watson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 279da9ce28eSEdward Tomasz Napierala if (error != 0) 2804e1123c7SRobert Watson return (error); 281cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 282c86ca022SRobert Watson #ifdef MAC 28330d239bcSRobert Watson error = mac_vnode_check_deleteacl(td->td_ucred, vp, type); 284da9ce28eSEdward Tomasz Napierala if (error != 0) 285c86ca022SRobert Watson goto out; 286c86ca022SRobert Watson #endif 287ae1add4eSEdward Tomasz Napierala error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td); 288c86ca022SRobert Watson #ifdef MAC 289c86ca022SRobert Watson out: 290c86ca022SRobert Watson #endif 29122db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 2924e1123c7SRobert Watson vn_finished_write(mp); 29391f37dcbSRobert Watson return (error); 29491f37dcbSRobert Watson } 29591f37dcbSRobert Watson 29691f37dcbSRobert Watson /* 29791f37dcbSRobert Watson * Given a vnode, check whether an ACL is appropriate for it 29891f37dcbSRobert Watson */ 29991f37dcbSRobert Watson static int 300b40ce416SJulian Elischer vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, 30191f37dcbSRobert Watson struct acl *aclp) 30291f37dcbSRobert Watson { 303b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 30491f37dcbSRobert Watson int error; 30591f37dcbSRobert Watson 306b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 307ae1add4eSEdward Tomasz Napierala error = acl_copyin(aclp, inkernelacl, type); 308da9ce28eSEdward Tomasz Napierala if (error != 0) 309b998d381SEdward Tomasz Napierala goto out; 310b998d381SEdward Tomasz Napierala error = VOP_ACLCHECK(vp, type, inkernelacl, td->td_ucred, td); 311b998d381SEdward Tomasz Napierala out: 312b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 31391f37dcbSRobert Watson return (error); 31491f37dcbSRobert Watson } 31591f37dcbSRobert Watson 31691f37dcbSRobert Watson /* 317b0c521e2SRobert Watson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. Don't 318b0c521e2SRobert Watson * need to lock, as the vacl_ code will get/release any locks required. 31991f37dcbSRobert Watson */ 32091f37dcbSRobert Watson 32191f37dcbSRobert Watson /* 32291f37dcbSRobert Watson * Given a file path, get an ACL for it 32391f37dcbSRobert Watson */ 32491f37dcbSRobert Watson int 325b40ce416SJulian Elischer __acl_get_file(struct thread *td, struct __acl_get_file_args *uap) 32691f37dcbSRobert Watson { 32791f37dcbSRobert Watson struct nameidata nd; 32842e7197fSChristian S.J. Peron int vfslocked, error; 32991f37dcbSRobert Watson 33042e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 33191f37dcbSRobert Watson error = namei(&nd); 33242e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 333f708f4d1SMatthew Dillon if (error == 0) { 334f97182acSAlfred Perlstein error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 33591f37dcbSRobert Watson NDFREE(&nd, 0); 336f708f4d1SMatthew Dillon } 33742e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 33891f37dcbSRobert Watson return (error); 33991f37dcbSRobert Watson } 34091f37dcbSRobert Watson 34191f37dcbSRobert Watson /* 3423c67c23bSRobert Watson * Given a file path, get an ACL for it; don't follow links. 3433c67c23bSRobert Watson */ 3443c67c23bSRobert Watson int 3453c67c23bSRobert Watson __acl_get_link(struct thread *td, struct __acl_get_link_args *uap) 3463c67c23bSRobert Watson { 3473c67c23bSRobert Watson struct nameidata nd; 34842e7197fSChristian S.J. Peron int vfslocked, error; 3493c67c23bSRobert Watson 35042e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 3513c67c23bSRobert Watson error = namei(&nd); 35242e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 3533c67c23bSRobert Watson if (error == 0) { 3543c67c23bSRobert Watson error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 3553c67c23bSRobert Watson NDFREE(&nd, 0); 3563c67c23bSRobert Watson } 35742e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 3583c67c23bSRobert Watson return (error); 3593c67c23bSRobert Watson } 3603c67c23bSRobert Watson 3613c67c23bSRobert Watson /* 3620c14ff0eSRobert Watson * Given a file path, set an ACL for it. 36391f37dcbSRobert Watson */ 36491f37dcbSRobert Watson int 365b40ce416SJulian Elischer __acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 36691f37dcbSRobert Watson { 36791f37dcbSRobert Watson struct nameidata nd; 36842e7197fSChristian S.J. Peron int vfslocked, error; 36991f37dcbSRobert Watson 37042e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 37191f37dcbSRobert Watson error = namei(&nd); 37242e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 373f708f4d1SMatthew Dillon if (error == 0) { 374f97182acSAlfred Perlstein error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 37591f37dcbSRobert Watson NDFREE(&nd, 0); 376f708f4d1SMatthew Dillon } 37742e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 37891f37dcbSRobert Watson return (error); 37991f37dcbSRobert Watson } 38091f37dcbSRobert Watson 38191f37dcbSRobert Watson /* 3823c67c23bSRobert Watson * Given a file path, set an ACL for it; don't follow links. 3833c67c23bSRobert Watson */ 3843c67c23bSRobert Watson int 3853c67c23bSRobert Watson __acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 3863c67c23bSRobert Watson { 3873c67c23bSRobert Watson struct nameidata nd; 38842e7197fSChristian S.J. Peron int vfslocked, error; 3893c67c23bSRobert Watson 39042e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 3913c67c23bSRobert Watson error = namei(&nd); 39242e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 3933c67c23bSRobert Watson if (error == 0) { 3943c67c23bSRobert Watson error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 3953c67c23bSRobert Watson NDFREE(&nd, 0); 3963c67c23bSRobert Watson } 39742e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 3983c67c23bSRobert Watson return (error); 3993c67c23bSRobert Watson } 4003c67c23bSRobert Watson 4013c67c23bSRobert Watson /* 402b5368498SRobert Watson * Given a file descriptor, get an ACL for it. 40391f37dcbSRobert Watson */ 40491f37dcbSRobert Watson int 405b40ce416SJulian Elischer __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) 40691f37dcbSRobert Watson { 40791f37dcbSRobert Watson struct file *fp; 40842e7197fSChristian S.J. Peron int vfslocked, error; 40991f37dcbSRobert Watson 410d1e405c5SAlfred Perlstein error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 411f708f4d1SMatthew Dillon if (error == 0) { 41242e7197fSChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 4133b6d9652SPoul-Henning Kamp error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); 414426da3bcSAlfred Perlstein fdrop(fp, td); 41542e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 416f708f4d1SMatthew Dillon } 41791f37dcbSRobert Watson return (error); 41891f37dcbSRobert Watson } 41991f37dcbSRobert Watson 42091f37dcbSRobert Watson /* 421b5368498SRobert Watson * Given a file descriptor, set an ACL for it. 42291f37dcbSRobert Watson */ 42391f37dcbSRobert Watson int 424b40ce416SJulian Elischer __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) 42591f37dcbSRobert Watson { 42691f37dcbSRobert Watson struct file *fp; 42742e7197fSChristian S.J. Peron int vfslocked, error; 42891f37dcbSRobert Watson 429d1e405c5SAlfred Perlstein error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 430f708f4d1SMatthew Dillon if (error == 0) { 43142e7197fSChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 4323b6d9652SPoul-Henning Kamp error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); 433426da3bcSAlfred Perlstein fdrop(fp, td); 43442e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 435f708f4d1SMatthew Dillon } 43691f37dcbSRobert Watson return (error); 43791f37dcbSRobert Watson } 43891f37dcbSRobert Watson 43991f37dcbSRobert Watson /* 44091f37dcbSRobert Watson * Given a file path, delete an ACL from it. 44191f37dcbSRobert Watson */ 44291f37dcbSRobert Watson int 443b40ce416SJulian Elischer __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) 44491f37dcbSRobert Watson { 44591f37dcbSRobert Watson struct nameidata nd; 44642e7197fSChristian S.J. Peron int vfslocked, error; 44791f37dcbSRobert Watson 44842e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 44991f37dcbSRobert Watson error = namei(&nd); 45042e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 451f708f4d1SMatthew Dillon if (error == 0) { 452d1e405c5SAlfred Perlstein error = vacl_delete(td, nd.ni_vp, uap->type); 45391f37dcbSRobert Watson NDFREE(&nd, 0); 454f708f4d1SMatthew Dillon } 45542e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 45691f37dcbSRobert Watson return (error); 45791f37dcbSRobert Watson } 45891f37dcbSRobert Watson 45991f37dcbSRobert Watson /* 4603c67c23bSRobert Watson * Given a file path, delete an ACL from it; don't follow links. 4613c67c23bSRobert Watson */ 4623c67c23bSRobert Watson int 4633c67c23bSRobert Watson __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) 4643c67c23bSRobert Watson { 4653c67c23bSRobert Watson struct nameidata nd; 46642e7197fSChristian S.J. Peron int vfslocked, error; 4673c67c23bSRobert Watson 46842e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 4693c67c23bSRobert Watson error = namei(&nd); 47042e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 4713c67c23bSRobert Watson if (error == 0) { 4723c67c23bSRobert Watson error = vacl_delete(td, nd.ni_vp, uap->type); 4733c67c23bSRobert Watson NDFREE(&nd, 0); 4743c67c23bSRobert Watson } 47542e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 4763c67c23bSRobert Watson return (error); 4773c67c23bSRobert Watson } 4783c67c23bSRobert Watson 4793c67c23bSRobert Watson /* 48091f37dcbSRobert Watson * Given a file path, delete an ACL from it. 48191f37dcbSRobert Watson */ 48291f37dcbSRobert Watson int 483b40ce416SJulian Elischer __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) 48491f37dcbSRobert Watson { 48591f37dcbSRobert Watson struct file *fp; 48642e7197fSChristian S.J. Peron int vfslocked, error; 48791f37dcbSRobert Watson 488d1e405c5SAlfred Perlstein error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 489f708f4d1SMatthew Dillon if (error == 0) { 49042e7197fSChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 4913b6d9652SPoul-Henning Kamp error = vacl_delete(td, fp->f_vnode, uap->type); 492426da3bcSAlfred Perlstein fdrop(fp, td); 49342e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 494f708f4d1SMatthew Dillon } 49591f37dcbSRobert Watson return (error); 49691f37dcbSRobert Watson } 49791f37dcbSRobert Watson 49891f37dcbSRobert Watson /* 4990c14ff0eSRobert Watson * Given a file path, check an ACL for it. 50091f37dcbSRobert Watson */ 50191f37dcbSRobert Watson int 502b40ce416SJulian Elischer __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) 50391f37dcbSRobert Watson { 50491f37dcbSRobert Watson struct nameidata nd; 50542e7197fSChristian S.J. Peron int vfslocked, error; 50691f37dcbSRobert Watson 50742e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 50891f37dcbSRobert Watson error = namei(&nd); 50942e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 510f708f4d1SMatthew Dillon if (error == 0) { 511f97182acSAlfred Perlstein error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 51291f37dcbSRobert Watson NDFREE(&nd, 0); 513f708f4d1SMatthew Dillon } 51442e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 51591f37dcbSRobert Watson return (error); 51691f37dcbSRobert Watson } 51791f37dcbSRobert Watson 51891f37dcbSRobert Watson /* 5193c67c23bSRobert Watson * Given a file path, check an ACL for it; don't follow links. 5203c67c23bSRobert Watson */ 5213c67c23bSRobert Watson int 5223c67c23bSRobert Watson __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) 5233c67c23bSRobert Watson { 5247a172809SEdward Tomasz Napierala struct nameidata nd; 52542e7197fSChristian S.J. Peron int vfslocked, error; 5263c67c23bSRobert Watson 52742e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 5283c67c23bSRobert Watson error = namei(&nd); 52942e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 5303c67c23bSRobert Watson if (error == 0) { 5313c67c23bSRobert Watson error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 5323c67c23bSRobert Watson NDFREE(&nd, 0); 5333c67c23bSRobert Watson } 53442e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 5353c67c23bSRobert Watson return (error); 5363c67c23bSRobert Watson } 5373c67c23bSRobert Watson 5383c67c23bSRobert Watson /* 5390c14ff0eSRobert Watson * Given a file descriptor, check an ACL for it. 54091f37dcbSRobert Watson */ 54191f37dcbSRobert Watson int 542b40ce416SJulian Elischer __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) 54391f37dcbSRobert Watson { 54491f37dcbSRobert Watson struct file *fp; 54542e7197fSChristian S.J. Peron int vfslocked, error; 54691f37dcbSRobert Watson 547d1e405c5SAlfred Perlstein error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 548f708f4d1SMatthew Dillon if (error == 0) { 54942e7197fSChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 5503b6d9652SPoul-Henning Kamp error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); 551426da3bcSAlfred Perlstein fdrop(fp, td); 55242e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 553f708f4d1SMatthew Dillon } 55491f37dcbSRobert Watson return (error); 55591f37dcbSRobert Watson } 556d1dfd921SChristian S.J. Peron 557b998d381SEdward Tomasz Napierala struct acl * 558b998d381SEdward Tomasz Napierala acl_alloc(int flags) 559b998d381SEdward Tomasz Napierala { 560b998d381SEdward Tomasz Napierala struct acl *aclp; 561b998d381SEdward Tomasz Napierala 562e0ee7589SEdward Tomasz Napierala aclp = malloc(sizeof(*aclp), M_ACL, flags); 563ae1add4eSEdward Tomasz Napierala aclp->acl_maxcnt = ACL_MAX_ENTRIES; 564b998d381SEdward Tomasz Napierala 565b998d381SEdward Tomasz Napierala return (aclp); 566b998d381SEdward Tomasz Napierala } 567b998d381SEdward Tomasz Napierala 568b998d381SEdward Tomasz Napierala void 569b998d381SEdward Tomasz Napierala acl_free(struct acl *aclp) 570b998d381SEdward Tomasz Napierala { 571b998d381SEdward Tomasz Napierala 572e0ee7589SEdward Tomasz Napierala free(aclp, M_ACL); 573b998d381SEdward Tomasz Napierala } 574