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 38c86ca022SRobert Watson #include "opt_mac.h" 39c86ca022SRobert Watson 4091f37dcbSRobert Watson #include <sys/param.h> 4191f37dcbSRobert Watson #include <sys/systm.h> 4291f37dcbSRobert Watson #include <sys/sysproto.h> 4357b4252eSKonstantin Belousov #include <sys/fcntl.h> 4491f37dcbSRobert Watson #include <sys/kernel.h> 4591f37dcbSRobert Watson #include <sys/malloc.h> 4642e7197fSChristian S.J. Peron #include <sys/mount.h> 4791f37dcbSRobert Watson #include <sys/vnode.h> 4891f37dcbSRobert Watson #include <sys/lock.h> 49f708f4d1SMatthew Dillon #include <sys/mutex.h> 5091f37dcbSRobert Watson #include <sys/namei.h> 5191f37dcbSRobert Watson #include <sys/file.h> 5213438f68SAlfred Perlstein #include <sys/filedesc.h> 5391f37dcbSRobert Watson #include <sys/proc.h> 5491f37dcbSRobert Watson #include <sys/sysent.h> 5591f37dcbSRobert Watson #include <sys/acl.h> 5691f37dcbSRobert Watson 57aed55708SRobert Watson #include <security/mac/mac_framework.h> 58aed55708SRobert Watson 59ae1add4eSEdward Tomasz Napierala CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES); 60ae1add4eSEdward Tomasz Napierala 61ae1add4eSEdward Tomasz Napierala MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists"); 6291f37dcbSRobert Watson 63cbeb8402SRobert Watson static int vacl_set_acl(struct thread *td, struct vnode *vp, 64cbeb8402SRobert Watson acl_type_t type, struct acl *aclp); 65cbeb8402SRobert Watson static int vacl_get_acl(struct thread *td, struct vnode *vp, 66cbeb8402SRobert Watson acl_type_t type, struct acl *aclp); 67b40ce416SJulian Elischer static int vacl_aclcheck(struct thread *td, struct vnode *vp, 68b114e127SRobert Watson acl_type_t type, struct acl *aclp); 6991f37dcbSRobert Watson 70ae1add4eSEdward Tomasz Napierala int 71ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest) 72ae1add4eSEdward Tomasz Napierala { 73ae1add4eSEdward Tomasz Napierala int i; 74ae1add4eSEdward Tomasz Napierala 75ae1add4eSEdward Tomasz Napierala if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) 76ae1add4eSEdward Tomasz Napierala return (EINVAL); 77ae1add4eSEdward Tomasz Napierala 78ae1add4eSEdward Tomasz Napierala bzero(dest, sizeof(*dest)); 79ae1add4eSEdward Tomasz Napierala 80ae1add4eSEdward Tomasz Napierala dest->acl_cnt = source->acl_cnt; 81ae1add4eSEdward Tomasz Napierala dest->acl_maxcnt = ACL_MAX_ENTRIES; 82ae1add4eSEdward Tomasz Napierala 83ae1add4eSEdward Tomasz Napierala for (i = 0; i < dest->acl_cnt; i++) { 84ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 85ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 86ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 87ae1add4eSEdward Tomasz Napierala } 88ae1add4eSEdward Tomasz Napierala 89ae1add4eSEdward Tomasz Napierala return (0); 90ae1add4eSEdward Tomasz Napierala } 91ae1add4eSEdward Tomasz Napierala 92ae1add4eSEdward Tomasz Napierala int 93ae1add4eSEdward Tomasz Napierala acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest) 94ae1add4eSEdward Tomasz Napierala { 95ae1add4eSEdward Tomasz Napierala int i; 96ae1add4eSEdward Tomasz Napierala 97ae1add4eSEdward Tomasz Napierala if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) 98ae1add4eSEdward Tomasz Napierala return (EINVAL); 99ae1add4eSEdward Tomasz Napierala 100ae1add4eSEdward Tomasz Napierala bzero(dest, sizeof(*dest)); 101ae1add4eSEdward Tomasz Napierala 102ae1add4eSEdward Tomasz Napierala dest->acl_cnt = source->acl_cnt; 103ae1add4eSEdward Tomasz Napierala 104ae1add4eSEdward Tomasz Napierala for (i = 0; i < dest->acl_cnt; i++) { 105ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 106ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 107ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 108ae1add4eSEdward Tomasz Napierala } 109ae1add4eSEdward Tomasz Napierala 110ae1add4eSEdward Tomasz Napierala return (0); 111ae1add4eSEdward Tomasz Napierala } 112ae1add4eSEdward Tomasz Napierala 113ae1add4eSEdward Tomasz Napierala /* 114ae1add4eSEdward Tomasz Napierala * At one time, "struct ACL" was extended in order to add support for NFSv4 115ae1add4eSEdward Tomasz Napierala * ACLs. Instead of creating compatibility versions of all the ACL-related 116ae1add4eSEdward Tomasz Napierala * syscalls, they were left intact. It's possible to find out what the code 117ae1add4eSEdward Tomasz Napierala * calling these syscalls (libc) expects basing on "type" argument - if it's 118ae1add4eSEdward Tomasz Napierala * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were 119ae1add4eSEdward Tomasz Napierala * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct 120ae1add4eSEdward Tomasz Napierala * oldacl". If it's something else, then it's the new "struct acl". In the 121ae1add4eSEdward Tomasz Napierala * latter case, the routines below just copyin/copyout the contents. In the 122ae1add4eSEdward Tomasz Napierala * former case, they copyin the "struct oldacl" and convert it to the new 123ae1add4eSEdward Tomasz Napierala * format. 124ae1add4eSEdward Tomasz Napierala */ 125ae1add4eSEdward Tomasz Napierala static int 126ae1add4eSEdward Tomasz Napierala acl_copyin(void *user_acl, struct acl *kernel_acl, acl_type_t type) 127ae1add4eSEdward Tomasz Napierala { 128ae1add4eSEdward Tomasz Napierala int error; 129ae1add4eSEdward Tomasz Napierala struct oldacl old; 130ae1add4eSEdward Tomasz Napierala 131ae1add4eSEdward Tomasz Napierala switch (type) { 132ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 133ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 134ae1add4eSEdward Tomasz Napierala error = copyin(user_acl, &old, sizeof(old)); 135ae1add4eSEdward Tomasz Napierala if (error != 0) 136ae1add4eSEdward Tomasz Napierala break; 137ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(&old, kernel_acl); 138ae1add4eSEdward Tomasz Napierala break; 139ae1add4eSEdward Tomasz Napierala 140ae1add4eSEdward Tomasz Napierala default: 141ae1add4eSEdward Tomasz Napierala error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl)); 142ae1add4eSEdward Tomasz Napierala if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES) 143ae1add4eSEdward Tomasz Napierala return (EINVAL); 144ae1add4eSEdward Tomasz Napierala } 145ae1add4eSEdward Tomasz Napierala 146ae1add4eSEdward Tomasz Napierala return (error); 147ae1add4eSEdward Tomasz Napierala } 148ae1add4eSEdward Tomasz Napierala 149ae1add4eSEdward Tomasz Napierala static int 150ae1add4eSEdward Tomasz Napierala acl_copyout(struct acl *kernel_acl, void *user_acl, acl_type_t type) 151ae1add4eSEdward Tomasz Napierala { 152ae1add4eSEdward Tomasz Napierala int error; 153ae1add4eSEdward Tomasz Napierala struct oldacl old; 154ae1add4eSEdward Tomasz Napierala 155ae1add4eSEdward Tomasz Napierala switch (type) { 156ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 157ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 158ae1add4eSEdward Tomasz Napierala error = acl_copy_acl_into_oldacl(kernel_acl, &old); 159ae1add4eSEdward Tomasz Napierala if (error != 0) 160ae1add4eSEdward Tomasz Napierala break; 161ae1add4eSEdward Tomasz Napierala 162ae1add4eSEdward Tomasz Napierala error = copyout(&old, user_acl, sizeof(old)); 163ae1add4eSEdward Tomasz Napierala break; 164ae1add4eSEdward Tomasz Napierala 165ae1add4eSEdward Tomasz Napierala default: 166ae1add4eSEdward Tomasz Napierala if (fuword((char *)user_acl + 167ae1add4eSEdward Tomasz Napierala offsetof(struct acl, acl_maxcnt)) != ACL_MAX_ENTRIES) 168ae1add4eSEdward Tomasz Napierala return (EINVAL); 169ae1add4eSEdward Tomasz Napierala 170ae1add4eSEdward Tomasz Napierala error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl)); 171ae1add4eSEdward Tomasz Napierala } 172ae1add4eSEdward Tomasz Napierala 173ae1add4eSEdward Tomasz Napierala return (error); 174ae1add4eSEdward Tomasz Napierala } 175ae1add4eSEdward Tomasz Napierala 176ae1add4eSEdward Tomasz Napierala /* 177ae1add4eSEdward Tomasz Napierala * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new" 178ae1add4eSEdward Tomasz Napierala * counterpart. It's required for old (pre-NFS4 ACLs) libc to work 179ae1add4eSEdward Tomasz Napierala * with new kernel. Fixing 'type' for old binaries with new libc 180ae1add4eSEdward Tomasz Napierala * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold(). 181ae1add4eSEdward Tomasz Napierala */ 182ae1add4eSEdward Tomasz Napierala static int 183ae1add4eSEdward Tomasz Napierala acl_type_unold(int type) 184ae1add4eSEdward Tomasz Napierala { 185ae1add4eSEdward Tomasz Napierala switch (type) { 186ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 187ae1add4eSEdward Tomasz Napierala return (ACL_TYPE_ACCESS); 188ae1add4eSEdward Tomasz Napierala 189ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 190ae1add4eSEdward Tomasz Napierala return (ACL_TYPE_DEFAULT); 191ae1add4eSEdward Tomasz Napierala 192ae1add4eSEdward Tomasz Napierala default: 193ae1add4eSEdward Tomasz Napierala return (type); 194ae1add4eSEdward Tomasz Napierala } 195ae1add4eSEdward Tomasz Napierala } 196ae1add4eSEdward Tomasz Napierala 19791f37dcbSRobert Watson /* 198b0c521e2SRobert Watson * These calls wrap the real vnode operations, and are called by the syscall 199b0c521e2SRobert Watson * code once the syscall has converted the path or file descriptor to a vnode 200b0c521e2SRobert Watson * (unlocked). The aclp pointer is assumed still to point to userland, so 201b0c521e2SRobert Watson * this should not be consumed within the kernel except by syscall code. 202b0c521e2SRobert Watson * Other code should directly invoke VOP_{SET,GET}ACL. 20391f37dcbSRobert Watson */ 20491f37dcbSRobert Watson 20591f37dcbSRobert Watson /* 20691f37dcbSRobert Watson * Given a vnode, set its ACL. 20791f37dcbSRobert Watson */ 20891f37dcbSRobert Watson static int 209b40ce416SJulian Elischer vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, 21091f37dcbSRobert Watson struct acl *aclp) 21191f37dcbSRobert Watson { 212b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 2134e1123c7SRobert Watson struct mount *mp; 21491f37dcbSRobert Watson int error; 21591f37dcbSRobert Watson 216b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 217ae1add4eSEdward Tomasz Napierala error = acl_copyin(aclp, inkernelacl, type); 21891f37dcbSRobert Watson if (error) 219b998d381SEdward Tomasz Napierala goto out; 2204e1123c7SRobert Watson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 2214e1123c7SRobert Watson if (error != 0) 222b998d381SEdward Tomasz Napierala goto out; 223cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 224c86ca022SRobert Watson #ifdef MAC 225b998d381SEdward Tomasz Napierala error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl); 226c86ca022SRobert Watson if (error != 0) 227b998d381SEdward Tomasz Napierala goto out_unlock; 228c86ca022SRobert Watson #endif 229ae1add4eSEdward Tomasz Napierala error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl, 230ae1add4eSEdward Tomasz Napierala td->td_ucred, td); 231c86ca022SRobert Watson #ifdef MAC 232b998d381SEdward Tomasz Napierala out_unlock: 233c86ca022SRobert Watson #endif 23422db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 2354e1123c7SRobert Watson vn_finished_write(mp); 236b998d381SEdward Tomasz Napierala out: 237b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 23891f37dcbSRobert Watson return(error); 23991f37dcbSRobert Watson } 24091f37dcbSRobert Watson 24191f37dcbSRobert Watson /* 24291f37dcbSRobert Watson * Given a vnode, get its ACL. 24391f37dcbSRobert Watson */ 24491f37dcbSRobert Watson static int 245b40ce416SJulian Elischer vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type, 24691f37dcbSRobert Watson struct acl *aclp) 24791f37dcbSRobert Watson { 248b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 24991f37dcbSRobert Watson int error; 25091f37dcbSRobert Watson 251b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 252cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 253c86ca022SRobert Watson #ifdef MAC 25430d239bcSRobert Watson error = mac_vnode_check_getacl(td->td_ucred, vp, type); 255c86ca022SRobert Watson if (error != 0) 256c86ca022SRobert Watson goto out; 257c86ca022SRobert Watson #endif 258ae1add4eSEdward Tomasz Napierala error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl, 259ae1add4eSEdward Tomasz Napierala td->td_ucred, td); 260ae1add4eSEdward Tomasz Napierala 261c86ca022SRobert Watson #ifdef MAC 262c86ca022SRobert Watson out: 263c86ca022SRobert Watson #endif 26422db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 26591f37dcbSRobert Watson if (error == 0) 266ae1add4eSEdward Tomasz Napierala error = acl_copyout(inkernelacl, aclp, type); 267b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 26891f37dcbSRobert Watson return (error); 26991f37dcbSRobert Watson } 27091f37dcbSRobert Watson 27191f37dcbSRobert Watson /* 27291f37dcbSRobert Watson * Given a vnode, delete its ACL. 27391f37dcbSRobert Watson */ 27491f37dcbSRobert Watson static int 275b40ce416SJulian Elischer vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type) 27691f37dcbSRobert Watson { 2774e1123c7SRobert Watson struct mount *mp; 27891f37dcbSRobert Watson int error; 27991f37dcbSRobert Watson 2804e1123c7SRobert Watson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 2814e1123c7SRobert Watson if (error) 2824e1123c7SRobert Watson return (error); 283cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 284c86ca022SRobert Watson #ifdef MAC 28530d239bcSRobert Watson error = mac_vnode_check_deleteacl(td->td_ucred, vp, type); 286c86ca022SRobert Watson if (error) 287c86ca022SRobert Watson goto out; 288c86ca022SRobert Watson #endif 289ae1add4eSEdward Tomasz Napierala error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td); 290c86ca022SRobert Watson #ifdef MAC 291c86ca022SRobert Watson out: 292c86ca022SRobert Watson #endif 29322db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 2944e1123c7SRobert Watson vn_finished_write(mp); 29591f37dcbSRobert Watson return (error); 29691f37dcbSRobert Watson } 29791f37dcbSRobert Watson 29891f37dcbSRobert Watson /* 29991f37dcbSRobert Watson * Given a vnode, check whether an ACL is appropriate for it 30091f37dcbSRobert Watson */ 30191f37dcbSRobert Watson static int 302b40ce416SJulian Elischer vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, 30391f37dcbSRobert Watson struct acl *aclp) 30491f37dcbSRobert Watson { 305b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 30691f37dcbSRobert Watson int error; 30791f37dcbSRobert Watson 308b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 309ae1add4eSEdward Tomasz Napierala error = acl_copyin(aclp, inkernelacl, type); 31091f37dcbSRobert Watson if (error) 311b998d381SEdward Tomasz Napierala goto out; 312b998d381SEdward Tomasz Napierala error = VOP_ACLCHECK(vp, type, inkernelacl, td->td_ucred, td); 313b998d381SEdward Tomasz Napierala out: 314b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 31591f37dcbSRobert Watson return (error); 31691f37dcbSRobert Watson } 31791f37dcbSRobert Watson 31891f37dcbSRobert Watson /* 319b0c521e2SRobert Watson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. Don't 320b0c521e2SRobert Watson * need to lock, as the vacl_ code will get/release any locks required. 32191f37dcbSRobert Watson */ 32291f37dcbSRobert Watson 32391f37dcbSRobert Watson /* 32491f37dcbSRobert Watson * Given a file path, get an ACL for it 32591f37dcbSRobert Watson */ 32691f37dcbSRobert Watson int 327b40ce416SJulian Elischer __acl_get_file(struct thread *td, struct __acl_get_file_args *uap) 32891f37dcbSRobert Watson { 32991f37dcbSRobert Watson struct nameidata nd; 33042e7197fSChristian S.J. Peron int vfslocked, error; 33191f37dcbSRobert Watson 33242e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 33391f37dcbSRobert Watson error = namei(&nd); 33442e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 335f708f4d1SMatthew Dillon if (error == 0) { 336f97182acSAlfred Perlstein error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 33791f37dcbSRobert Watson NDFREE(&nd, 0); 338f708f4d1SMatthew Dillon } 33942e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 34091f37dcbSRobert Watson return (error); 34191f37dcbSRobert Watson } 34291f37dcbSRobert Watson 34391f37dcbSRobert Watson /* 3443c67c23bSRobert Watson * Given a file path, get an ACL for it; don't follow links. 3453c67c23bSRobert Watson */ 3463c67c23bSRobert Watson int 3473c67c23bSRobert Watson __acl_get_link(struct thread *td, struct __acl_get_link_args *uap) 3483c67c23bSRobert Watson { 3493c67c23bSRobert Watson struct nameidata nd; 35042e7197fSChristian S.J. Peron int vfslocked, error; 3513c67c23bSRobert Watson 35242e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 3533c67c23bSRobert Watson error = namei(&nd); 35442e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 3553c67c23bSRobert Watson if (error == 0) { 3563c67c23bSRobert Watson error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 3573c67c23bSRobert Watson NDFREE(&nd, 0); 3583c67c23bSRobert Watson } 35942e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 3603c67c23bSRobert Watson return (error); 3613c67c23bSRobert Watson } 3623c67c23bSRobert Watson 3633c67c23bSRobert Watson /* 3640c14ff0eSRobert Watson * Given a file path, set an ACL for it. 36591f37dcbSRobert Watson */ 36691f37dcbSRobert Watson int 367b40ce416SJulian Elischer __acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 36891f37dcbSRobert Watson { 36991f37dcbSRobert Watson struct nameidata nd; 37042e7197fSChristian S.J. Peron int vfslocked, error; 37191f37dcbSRobert Watson 37242e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 37391f37dcbSRobert Watson error = namei(&nd); 37442e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 375f708f4d1SMatthew Dillon if (error == 0) { 376f97182acSAlfred Perlstein error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 37791f37dcbSRobert Watson NDFREE(&nd, 0); 378f708f4d1SMatthew Dillon } 37942e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 38091f37dcbSRobert Watson return (error); 38191f37dcbSRobert Watson } 38291f37dcbSRobert Watson 38391f37dcbSRobert Watson /* 3843c67c23bSRobert Watson * Given a file path, set an ACL for it; don't follow links. 3853c67c23bSRobert Watson */ 3863c67c23bSRobert Watson int 3873c67c23bSRobert Watson __acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 3883c67c23bSRobert Watson { 3893c67c23bSRobert Watson struct nameidata nd; 39042e7197fSChristian S.J. Peron int vfslocked, error; 3913c67c23bSRobert Watson 39242e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 3933c67c23bSRobert Watson error = namei(&nd); 39442e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 3953c67c23bSRobert Watson if (error == 0) { 3963c67c23bSRobert Watson error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 3973c67c23bSRobert Watson NDFREE(&nd, 0); 3983c67c23bSRobert Watson } 39942e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 4003c67c23bSRobert Watson return (error); 4013c67c23bSRobert Watson } 4023c67c23bSRobert Watson 4033c67c23bSRobert Watson /* 404b5368498SRobert Watson * Given a file descriptor, get an ACL for it. 40591f37dcbSRobert Watson */ 40691f37dcbSRobert Watson int 407b40ce416SJulian Elischer __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) 40891f37dcbSRobert Watson { 40991f37dcbSRobert Watson struct file *fp; 41042e7197fSChristian S.J. Peron int vfslocked, error; 41191f37dcbSRobert Watson 412d1e405c5SAlfred Perlstein error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 413f708f4d1SMatthew Dillon if (error == 0) { 41442e7197fSChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 4153b6d9652SPoul-Henning Kamp error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); 416426da3bcSAlfred Perlstein fdrop(fp, td); 41742e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 418f708f4d1SMatthew Dillon } 41991f37dcbSRobert Watson return (error); 42091f37dcbSRobert Watson } 42191f37dcbSRobert Watson 42291f37dcbSRobert Watson /* 423b5368498SRobert Watson * Given a file descriptor, set an ACL for it. 42491f37dcbSRobert Watson */ 42591f37dcbSRobert Watson int 426b40ce416SJulian Elischer __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) 42791f37dcbSRobert Watson { 42891f37dcbSRobert Watson struct file *fp; 42942e7197fSChristian S.J. Peron int vfslocked, error; 43091f37dcbSRobert Watson 431d1e405c5SAlfred Perlstein error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 432f708f4d1SMatthew Dillon if (error == 0) { 43342e7197fSChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 4343b6d9652SPoul-Henning Kamp error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); 435426da3bcSAlfred Perlstein fdrop(fp, td); 43642e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 437f708f4d1SMatthew Dillon } 43891f37dcbSRobert Watson return (error); 43991f37dcbSRobert Watson } 44091f37dcbSRobert Watson 44191f37dcbSRobert Watson /* 44291f37dcbSRobert Watson * Given a file path, delete an ACL from it. 44391f37dcbSRobert Watson */ 44491f37dcbSRobert Watson int 445b40ce416SJulian Elischer __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) 44691f37dcbSRobert Watson { 44791f37dcbSRobert Watson struct nameidata nd; 44842e7197fSChristian S.J. Peron int vfslocked, error; 44991f37dcbSRobert Watson 45042e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 45191f37dcbSRobert Watson error = namei(&nd); 45242e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 453f708f4d1SMatthew Dillon if (error == 0) { 454d1e405c5SAlfred Perlstein error = vacl_delete(td, nd.ni_vp, uap->type); 45591f37dcbSRobert Watson NDFREE(&nd, 0); 456f708f4d1SMatthew Dillon } 45742e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 45891f37dcbSRobert Watson return (error); 45991f37dcbSRobert Watson } 46091f37dcbSRobert Watson 46191f37dcbSRobert Watson /* 4623c67c23bSRobert Watson * Given a file path, delete an ACL from it; don't follow links. 4633c67c23bSRobert Watson */ 4643c67c23bSRobert Watson int 4653c67c23bSRobert Watson __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) 4663c67c23bSRobert Watson { 4673c67c23bSRobert Watson struct nameidata nd; 46842e7197fSChristian S.J. Peron int vfslocked, error; 4693c67c23bSRobert Watson 47042e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 4713c67c23bSRobert Watson error = namei(&nd); 47242e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 4733c67c23bSRobert Watson if (error == 0) { 4743c67c23bSRobert Watson error = vacl_delete(td, nd.ni_vp, uap->type); 4753c67c23bSRobert Watson NDFREE(&nd, 0); 4763c67c23bSRobert Watson } 47742e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 4783c67c23bSRobert Watson return (error); 4793c67c23bSRobert Watson } 4803c67c23bSRobert Watson 4813c67c23bSRobert Watson /* 48291f37dcbSRobert Watson * Given a file path, delete an ACL from it. 48391f37dcbSRobert Watson */ 48491f37dcbSRobert Watson int 485b40ce416SJulian Elischer __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) 48691f37dcbSRobert Watson { 48791f37dcbSRobert Watson struct file *fp; 48842e7197fSChristian S.J. Peron int vfslocked, error; 48991f37dcbSRobert Watson 490d1e405c5SAlfred Perlstein error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 491f708f4d1SMatthew Dillon if (error == 0) { 49242e7197fSChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 4933b6d9652SPoul-Henning Kamp error = vacl_delete(td, fp->f_vnode, uap->type); 494426da3bcSAlfred Perlstein fdrop(fp, td); 49542e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 496f708f4d1SMatthew Dillon } 49791f37dcbSRobert Watson return (error); 49891f37dcbSRobert Watson } 49991f37dcbSRobert Watson 50091f37dcbSRobert Watson /* 5010c14ff0eSRobert Watson * Given a file path, check an ACL for it. 50291f37dcbSRobert Watson */ 50391f37dcbSRobert Watson int 504b40ce416SJulian Elischer __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) 50591f37dcbSRobert Watson { 50691f37dcbSRobert Watson struct nameidata nd; 50742e7197fSChristian S.J. Peron int vfslocked, error; 50891f37dcbSRobert Watson 50942e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td); 51091f37dcbSRobert Watson error = namei(&nd); 51142e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 512f708f4d1SMatthew Dillon if (error == 0) { 513f97182acSAlfred Perlstein error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 51491f37dcbSRobert Watson NDFREE(&nd, 0); 515f708f4d1SMatthew Dillon } 51642e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 51791f37dcbSRobert Watson return (error); 51891f37dcbSRobert Watson } 51991f37dcbSRobert Watson 52091f37dcbSRobert Watson /* 5213c67c23bSRobert Watson * Given a file path, check an ACL for it; don't follow links. 5223c67c23bSRobert Watson */ 5233c67c23bSRobert Watson int 5243c67c23bSRobert Watson __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) 5253c67c23bSRobert Watson { 5263c67c23bSRobert Watson struct nameidata nd; 52742e7197fSChristian S.J. Peron int vfslocked, error; 5283c67c23bSRobert Watson 52942e7197fSChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td); 5303c67c23bSRobert Watson error = namei(&nd); 53142e7197fSChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 5323c67c23bSRobert Watson if (error == 0) { 5333c67c23bSRobert Watson error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 5343c67c23bSRobert Watson NDFREE(&nd, 0); 5353c67c23bSRobert Watson } 53642e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 5373c67c23bSRobert Watson return (error); 5383c67c23bSRobert Watson } 5393c67c23bSRobert Watson 5403c67c23bSRobert Watson /* 5410c14ff0eSRobert Watson * Given a file descriptor, check an ACL for it. 54291f37dcbSRobert Watson */ 54391f37dcbSRobert Watson int 544b40ce416SJulian Elischer __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) 54591f37dcbSRobert Watson { 54691f37dcbSRobert Watson struct file *fp; 54742e7197fSChristian S.J. Peron int vfslocked, error; 54891f37dcbSRobert Watson 549d1e405c5SAlfred Perlstein error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 550f708f4d1SMatthew Dillon if (error == 0) { 55142e7197fSChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 5523b6d9652SPoul-Henning Kamp error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); 553426da3bcSAlfred Perlstein fdrop(fp, td); 55442e7197fSChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 555f708f4d1SMatthew Dillon } 55691f37dcbSRobert Watson return (error); 55791f37dcbSRobert Watson } 558d1dfd921SChristian S.J. Peron 559b998d381SEdward Tomasz Napierala struct acl * 560b998d381SEdward Tomasz Napierala acl_alloc(int flags) 561b998d381SEdward Tomasz Napierala { 562b998d381SEdward Tomasz Napierala struct acl *aclp; 563b998d381SEdward Tomasz Napierala 564e0ee7589SEdward Tomasz Napierala aclp = malloc(sizeof(*aclp), M_ACL, flags); 565ae1add4eSEdward Tomasz Napierala aclp->acl_maxcnt = ACL_MAX_ENTRIES; 566b998d381SEdward Tomasz Napierala 567b998d381SEdward Tomasz Napierala return (aclp); 568b998d381SEdward Tomasz Napierala } 569b998d381SEdward Tomasz Napierala 570b998d381SEdward Tomasz Napierala void 571b998d381SEdward Tomasz Napierala acl_free(struct acl *aclp) 572b998d381SEdward Tomasz Napierala { 573b998d381SEdward Tomasz Napierala 574e0ee7589SEdward Tomasz Napierala free(aclp, M_ACL); 575b998d381SEdward Tomasz Napierala } 576