191f37dcbSRobert Watson /*- 28a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 38a36da99SPedro F. Giffuni * 4f9070809SRobert Watson * Copyright (c) 1999-2006, 2016-2017 Robert N. M. Watson 591f37dcbSRobert Watson * All rights reserved. 691f37dcbSRobert Watson * 76d878543SRobert Watson * This software was developed by Robert Watson for the TrustedBSD Project. 86d878543SRobert Watson * 9f9070809SRobert Watson * Portions of this software were developed by BAE Systems, the University of 10f9070809SRobert Watson * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 11f9070809SRobert Watson * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 12f9070809SRobert Watson * Computing (TC) research program. 13f9070809SRobert Watson * 1491f37dcbSRobert Watson * Redistribution and use in source and binary forms, with or without 1591f37dcbSRobert Watson * modification, are permitted provided that the following conditions 1691f37dcbSRobert Watson * are met: 1791f37dcbSRobert Watson * 1. Redistributions of source code must retain the above copyright 1891f37dcbSRobert Watson * notice, this list of conditions and the following disclaimer. 1991f37dcbSRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 2091f37dcbSRobert Watson * notice, this list of conditions and the following disclaimer in the 2191f37dcbSRobert Watson * documentation and/or other materials provided with the distribution. 2291f37dcbSRobert Watson * 2391f37dcbSRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2491f37dcbSRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2591f37dcbSRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2691f37dcbSRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2791f37dcbSRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2891f37dcbSRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2991f37dcbSRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3091f37dcbSRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3191f37dcbSRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3291f37dcbSRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3391f37dcbSRobert Watson * SUCH DAMAGE. 3491f37dcbSRobert Watson */ 3591f37dcbSRobert Watson /* 365293465fSRobert Watson * Developed by the TrustedBSD Project. 37e4256d1eSRobert Watson * 38e4256d1eSRobert Watson * ACL system calls and other functions common across different ACL types. 39e4256d1eSRobert Watson * Type-specific routines go into subr_acl_<type>.c. 4091f37dcbSRobert Watson */ 4191f37dcbSRobert Watson 42677b542eSDavid E. O'Brien #include <sys/cdefs.h> 43677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 44677b542eSDavid E. O'Brien 4591f37dcbSRobert Watson #include <sys/param.h> 4691f37dcbSRobert Watson #include <sys/systm.h> 4791f37dcbSRobert Watson #include <sys/sysproto.h> 484a144410SRobert Watson #include <sys/capsicum.h> 4957b4252eSKonstantin Belousov #include <sys/fcntl.h> 5091f37dcbSRobert Watson #include <sys/kernel.h> 5191f37dcbSRobert Watson #include <sys/malloc.h> 5242e7197fSChristian S.J. Peron #include <sys/mount.h> 5391f37dcbSRobert Watson #include <sys/vnode.h> 5491f37dcbSRobert Watson #include <sys/lock.h> 55f708f4d1SMatthew Dillon #include <sys/mutex.h> 5691f37dcbSRobert Watson #include <sys/namei.h> 5791f37dcbSRobert Watson #include <sys/file.h> 5813438f68SAlfred Perlstein #include <sys/filedesc.h> 5991f37dcbSRobert Watson #include <sys/proc.h> 6091f37dcbSRobert Watson #include <sys/acl.h> 6191f37dcbSRobert Watson 62f9070809SRobert Watson #include <security/audit/audit.h> 63aed55708SRobert Watson #include <security/mac/mac_framework.h> 64aed55708SRobert Watson 65ae1add4eSEdward Tomasz Napierala CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES); 66ae1add4eSEdward Tomasz Napierala 67ae1add4eSEdward Tomasz Napierala MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists"); 6891f37dcbSRobert Watson 69aff4f2d3SBrooks Davis static int kern___acl_aclcheck_path(struct thread *td, const char *path, 70aff4f2d3SBrooks Davis acl_type_t type, struct acl *aclp, int follow); 71aff4f2d3SBrooks Davis static int kern___acl_delete_path(struct thread *td, const char *path, 72aff4f2d3SBrooks Davis acl_type_t type, int follow); 73aff4f2d3SBrooks Davis static int kern___acl_get_path(struct thread *td, const char *path, 74aff4f2d3SBrooks Davis acl_type_t type, struct acl *aclp, int follow); 75aff4f2d3SBrooks Davis static int kern___acl_set_path(struct thread *td, const char *path, 76aff4f2d3SBrooks Davis acl_type_t type, const struct acl *aclp, int follow); 77cbeb8402SRobert Watson static int vacl_set_acl(struct thread *td, struct vnode *vp, 78aff4f2d3SBrooks Davis acl_type_t type, const struct acl *aclp); 79cbeb8402SRobert Watson static int vacl_get_acl(struct thread *td, struct vnode *vp, 80cbeb8402SRobert Watson acl_type_t type, struct acl *aclp); 81b40ce416SJulian Elischer static int vacl_aclcheck(struct thread *td, struct vnode *vp, 82aff4f2d3SBrooks Davis acl_type_t type, const struct acl *aclp); 8391f37dcbSRobert Watson 84ae1add4eSEdward Tomasz Napierala int 85ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest) 86ae1add4eSEdward Tomasz Napierala { 87ae1add4eSEdward Tomasz Napierala int i; 88ae1add4eSEdward Tomasz Napierala 89ae1add4eSEdward Tomasz Napierala if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) 90ae1add4eSEdward Tomasz Napierala return (EINVAL); 91ae1add4eSEdward Tomasz Napierala 92ae1add4eSEdward Tomasz Napierala bzero(dest, sizeof(*dest)); 93ae1add4eSEdward Tomasz Napierala 94ae1add4eSEdward Tomasz Napierala dest->acl_cnt = source->acl_cnt; 95ae1add4eSEdward Tomasz Napierala dest->acl_maxcnt = ACL_MAX_ENTRIES; 96ae1add4eSEdward Tomasz Napierala 97ae1add4eSEdward Tomasz Napierala for (i = 0; i < dest->acl_cnt; i++) { 98ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 99ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 100ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 101ae1add4eSEdward Tomasz Napierala } 102ae1add4eSEdward Tomasz Napierala 103ae1add4eSEdward Tomasz Napierala return (0); 104ae1add4eSEdward Tomasz Napierala } 105ae1add4eSEdward Tomasz Napierala 106ae1add4eSEdward Tomasz Napierala int 107ae1add4eSEdward Tomasz Napierala acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest) 108ae1add4eSEdward Tomasz Napierala { 109ae1add4eSEdward Tomasz Napierala int i; 110ae1add4eSEdward Tomasz Napierala 111ce9d79aaSEdward Tomasz Napierala if (source->acl_cnt > OLDACL_MAX_ENTRIES) 112ae1add4eSEdward Tomasz Napierala return (EINVAL); 113ae1add4eSEdward Tomasz Napierala 114ae1add4eSEdward Tomasz Napierala bzero(dest, sizeof(*dest)); 115ae1add4eSEdward Tomasz Napierala 116ae1add4eSEdward Tomasz Napierala dest->acl_cnt = source->acl_cnt; 117ae1add4eSEdward Tomasz Napierala 118ae1add4eSEdward Tomasz Napierala for (i = 0; i < dest->acl_cnt; i++) { 119ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 120ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 121ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 122ae1add4eSEdward Tomasz Napierala } 123ae1add4eSEdward Tomasz Napierala 124ae1add4eSEdward Tomasz Napierala return (0); 125ae1add4eSEdward Tomasz Napierala } 126ae1add4eSEdward Tomasz Napierala 127ae1add4eSEdward Tomasz Napierala /* 128ae1add4eSEdward Tomasz Napierala * At one time, "struct ACL" was extended in order to add support for NFSv4 129ae1add4eSEdward Tomasz Napierala * ACLs. Instead of creating compatibility versions of all the ACL-related 130ae1add4eSEdward Tomasz Napierala * syscalls, they were left intact. It's possible to find out what the code 131ae1add4eSEdward Tomasz Napierala * calling these syscalls (libc) expects basing on "type" argument - if it's 132ae1add4eSEdward Tomasz Napierala * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were 133ae1add4eSEdward Tomasz Napierala * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct 134ae1add4eSEdward Tomasz Napierala * oldacl". If it's something else, then it's the new "struct acl". In the 135ae1add4eSEdward Tomasz Napierala * latter case, the routines below just copyin/copyout the contents. In the 136ae1add4eSEdward Tomasz Napierala * former case, they copyin the "struct oldacl" and convert it to the new 137ae1add4eSEdward Tomasz Napierala * format. 138ae1add4eSEdward Tomasz Napierala */ 139ae1add4eSEdward Tomasz Napierala static int 140aff4f2d3SBrooks Davis acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type) 141ae1add4eSEdward Tomasz Napierala { 142ae1add4eSEdward Tomasz Napierala int error; 143ae1add4eSEdward Tomasz Napierala struct oldacl old; 144ae1add4eSEdward Tomasz Napierala 145ae1add4eSEdward Tomasz Napierala switch (type) { 146ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 147ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 148ae1add4eSEdward Tomasz Napierala error = copyin(user_acl, &old, sizeof(old)); 149ae1add4eSEdward Tomasz Napierala if (error != 0) 150ae1add4eSEdward Tomasz Napierala break; 151ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(&old, kernel_acl); 152ae1add4eSEdward Tomasz Napierala break; 153ae1add4eSEdward Tomasz Napierala 154ae1add4eSEdward Tomasz Napierala default: 155ae1add4eSEdward Tomasz Napierala error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl)); 156ae1add4eSEdward Tomasz Napierala if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES) 157ae1add4eSEdward Tomasz Napierala return (EINVAL); 158ae1add4eSEdward Tomasz Napierala } 159ae1add4eSEdward Tomasz Napierala 160ae1add4eSEdward Tomasz Napierala return (error); 161ae1add4eSEdward Tomasz Napierala } 162ae1add4eSEdward Tomasz Napierala 163ae1add4eSEdward Tomasz Napierala static int 164aff4f2d3SBrooks Davis acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type) 165ae1add4eSEdward Tomasz Napierala { 1660a2c94b8SKonstantin Belousov uint32_t am; 167ae1add4eSEdward Tomasz Napierala int error; 168ae1add4eSEdward Tomasz Napierala struct oldacl old; 169ae1add4eSEdward Tomasz Napierala 170ae1add4eSEdward Tomasz Napierala switch (type) { 171ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 172ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 173ae1add4eSEdward Tomasz Napierala error = acl_copy_acl_into_oldacl(kernel_acl, &old); 174ae1add4eSEdward Tomasz Napierala if (error != 0) 175ae1add4eSEdward Tomasz Napierala break; 176ae1add4eSEdward Tomasz Napierala 177ae1add4eSEdward Tomasz Napierala error = copyout(&old, user_acl, sizeof(old)); 178ae1add4eSEdward Tomasz Napierala break; 179ae1add4eSEdward Tomasz Napierala 180ae1add4eSEdward Tomasz Napierala default: 1810a2c94b8SKonstantin Belousov error = fueword32((char *)user_acl + 1820a2c94b8SKonstantin Belousov offsetof(struct acl, acl_maxcnt), &am); 1830a2c94b8SKonstantin Belousov if (error == -1) 1840a2c94b8SKonstantin Belousov return (EFAULT); 1850a2c94b8SKonstantin Belousov if (am != ACL_MAX_ENTRIES) 186ae1add4eSEdward Tomasz Napierala return (EINVAL); 187ae1add4eSEdward Tomasz Napierala 188ae1add4eSEdward Tomasz Napierala error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl)); 189ae1add4eSEdward Tomasz Napierala } 190ae1add4eSEdward Tomasz Napierala 191ae1add4eSEdward Tomasz Napierala return (error); 192ae1add4eSEdward Tomasz Napierala } 193ae1add4eSEdward Tomasz Napierala 194ae1add4eSEdward Tomasz Napierala /* 195ae1add4eSEdward Tomasz Napierala * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new" 1966bb58cddSEdward Tomasz Napierala * counterpart. It's required for old (pre-NFSv4 ACLs) libc to work 197ae1add4eSEdward Tomasz Napierala * with new kernel. Fixing 'type' for old binaries with new libc 198ae1add4eSEdward Tomasz Napierala * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold(). 199ae1add4eSEdward Tomasz Napierala */ 200ae1add4eSEdward Tomasz Napierala static int 201ae1add4eSEdward Tomasz Napierala acl_type_unold(int type) 202ae1add4eSEdward Tomasz Napierala { 203ae1add4eSEdward Tomasz Napierala switch (type) { 204ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 205ae1add4eSEdward Tomasz Napierala return (ACL_TYPE_ACCESS); 206ae1add4eSEdward Tomasz Napierala 207ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 208ae1add4eSEdward Tomasz Napierala return (ACL_TYPE_DEFAULT); 209ae1add4eSEdward Tomasz Napierala 210ae1add4eSEdward Tomasz Napierala default: 211ae1add4eSEdward Tomasz Napierala return (type); 212ae1add4eSEdward Tomasz Napierala } 213ae1add4eSEdward Tomasz Napierala } 214ae1add4eSEdward Tomasz Napierala 21591f37dcbSRobert Watson /* 216b0c521e2SRobert Watson * These calls wrap the real vnode operations, and are called by the syscall 217b0c521e2SRobert Watson * code once the syscall has converted the path or file descriptor to a vnode 218b0c521e2SRobert Watson * (unlocked). The aclp pointer is assumed still to point to userland, so 219b0c521e2SRobert Watson * this should not be consumed within the kernel except by syscall code. 220b0c521e2SRobert Watson * Other code should directly invoke VOP_{SET,GET}ACL. 22191f37dcbSRobert Watson */ 22291f37dcbSRobert Watson 22391f37dcbSRobert Watson /* 22491f37dcbSRobert Watson * Given a vnode, set its ACL. 22591f37dcbSRobert Watson */ 22691f37dcbSRobert Watson static int 227b40ce416SJulian Elischer vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, 228aff4f2d3SBrooks Davis const struct acl *aclp) 22991f37dcbSRobert Watson { 230b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 2314e1123c7SRobert Watson struct mount *mp; 23291f37dcbSRobert Watson int error; 23391f37dcbSRobert Watson 234f9070809SRobert Watson AUDIT_ARG_VALUE(type); 235b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 236ae1add4eSEdward Tomasz Napierala error = acl_copyin(aclp, inkernelacl, type); 237da9ce28eSEdward Tomasz Napierala if (error != 0) 238b998d381SEdward Tomasz Napierala goto out; 239a75d1dddSMateusz Guzik error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); 2404e1123c7SRobert Watson if (error != 0) 241b998d381SEdward Tomasz Napierala goto out; 242cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 243f9070809SRobert Watson AUDIT_ARG_VNODE1(vp); 244c86ca022SRobert Watson #ifdef MAC 245b998d381SEdward Tomasz Napierala error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl); 246c86ca022SRobert Watson if (error != 0) 247b998d381SEdward Tomasz Napierala goto out_unlock; 248c86ca022SRobert Watson #endif 249ae1add4eSEdward Tomasz Napierala error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl, 250ae1add4eSEdward Tomasz Napierala td->td_ucred, td); 251c86ca022SRobert Watson #ifdef MAC 252b998d381SEdward Tomasz Napierala out_unlock: 253c86ca022SRobert Watson #endif 254b249ce48SMateusz Guzik VOP_UNLOCK(vp); 2554e1123c7SRobert Watson vn_finished_write(mp); 256b998d381SEdward Tomasz Napierala out: 257b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 25891f37dcbSRobert Watson return (error); 25991f37dcbSRobert Watson } 26091f37dcbSRobert Watson 26191f37dcbSRobert Watson /* 26291f37dcbSRobert Watson * Given a vnode, get its ACL. 26391f37dcbSRobert Watson */ 26491f37dcbSRobert Watson static int 265b40ce416SJulian Elischer vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type, 26691f37dcbSRobert Watson struct acl *aclp) 26791f37dcbSRobert Watson { 268b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 26991f37dcbSRobert Watson int error; 27091f37dcbSRobert Watson 271f9070809SRobert Watson AUDIT_ARG_VALUE(type); 27223c053d6SSergey Kandaurov inkernelacl = acl_alloc(M_WAITOK | M_ZERO); 273cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 274f9070809SRobert Watson AUDIT_ARG_VNODE1(vp); 275c86ca022SRobert Watson #ifdef MAC 27630d239bcSRobert Watson error = mac_vnode_check_getacl(td->td_ucred, vp, type); 277c86ca022SRobert Watson if (error != 0) 278c86ca022SRobert Watson goto out; 279c86ca022SRobert Watson #endif 280ae1add4eSEdward Tomasz Napierala error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl, 281ae1add4eSEdward Tomasz Napierala td->td_ucred, td); 282ae1add4eSEdward Tomasz Napierala 283c86ca022SRobert Watson #ifdef MAC 284c86ca022SRobert Watson out: 285c86ca022SRobert Watson #endif 286b249ce48SMateusz Guzik VOP_UNLOCK(vp); 28791f37dcbSRobert Watson if (error == 0) 288ae1add4eSEdward Tomasz Napierala error = acl_copyout(inkernelacl, aclp, type); 289b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 29091f37dcbSRobert Watson return (error); 29191f37dcbSRobert Watson } 29291f37dcbSRobert Watson 29391f37dcbSRobert Watson /* 29491f37dcbSRobert Watson * Given a vnode, delete its ACL. 29591f37dcbSRobert Watson */ 29691f37dcbSRobert Watson static int 297b40ce416SJulian Elischer vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type) 29891f37dcbSRobert Watson { 2994e1123c7SRobert Watson struct mount *mp; 30091f37dcbSRobert Watson int error; 30191f37dcbSRobert Watson 302f9070809SRobert Watson AUDIT_ARG_VALUE(type); 303a75d1dddSMateusz Guzik error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); 304da9ce28eSEdward Tomasz Napierala if (error != 0) 3054e1123c7SRobert Watson return (error); 306cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 307f9070809SRobert Watson AUDIT_ARG_VNODE1(vp); 308c86ca022SRobert Watson #ifdef MAC 30930d239bcSRobert Watson error = mac_vnode_check_deleteacl(td->td_ucred, vp, type); 310da9ce28eSEdward Tomasz Napierala if (error != 0) 311c86ca022SRobert Watson goto out; 312c86ca022SRobert Watson #endif 313ae1add4eSEdward Tomasz Napierala error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td); 314c86ca022SRobert Watson #ifdef MAC 315c86ca022SRobert Watson out: 316c86ca022SRobert Watson #endif 317b249ce48SMateusz Guzik VOP_UNLOCK(vp); 3184e1123c7SRobert Watson vn_finished_write(mp); 31991f37dcbSRobert Watson return (error); 32091f37dcbSRobert Watson } 32191f37dcbSRobert Watson 32291f37dcbSRobert Watson /* 32391f37dcbSRobert Watson * Given a vnode, check whether an ACL is appropriate for it 324f9070809SRobert Watson * 325f9070809SRobert Watson * XXXRW: No vnode lock held so can't audit vnode state...? 32691f37dcbSRobert Watson */ 32791f37dcbSRobert Watson static int 328b40ce416SJulian Elischer vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, 329aff4f2d3SBrooks Davis const struct acl *aclp) 33091f37dcbSRobert Watson { 331b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 33291f37dcbSRobert Watson int error; 33391f37dcbSRobert Watson 334b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 335ae1add4eSEdward Tomasz Napierala error = acl_copyin(aclp, inkernelacl, type); 336da9ce28eSEdward Tomasz Napierala if (error != 0) 337b998d381SEdward Tomasz Napierala goto out; 3386bb58cddSEdward Tomasz Napierala error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl, 3396bb58cddSEdward Tomasz Napierala td->td_ucred, td); 340b998d381SEdward Tomasz Napierala out: 341b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 34291f37dcbSRobert Watson return (error); 34391f37dcbSRobert Watson } 34491f37dcbSRobert Watson 34591f37dcbSRobert Watson /* 346b0c521e2SRobert Watson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. Don't 347b0c521e2SRobert Watson * need to lock, as the vacl_ code will get/release any locks required. 34891f37dcbSRobert Watson */ 34991f37dcbSRobert Watson 35091f37dcbSRobert Watson /* 35191f37dcbSRobert Watson * Given a file path, get an ACL for it 35291f37dcbSRobert Watson */ 35391f37dcbSRobert Watson int 3548451d0ddSKip Macy sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap) 35591f37dcbSRobert Watson { 35691f37dcbSRobert Watson 357aff4f2d3SBrooks Davis return (kern___acl_get_path(td, uap->path, uap->type, uap->aclp, 358aff4f2d3SBrooks Davis FOLLOW)); 35991f37dcbSRobert Watson } 36091f37dcbSRobert Watson 36191f37dcbSRobert Watson /* 3623c67c23bSRobert Watson * Given a file path, get an ACL for it; don't follow links. 3633c67c23bSRobert Watson */ 3643c67c23bSRobert Watson int 3658451d0ddSKip Macy sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap) 3663c67c23bSRobert Watson { 367aff4f2d3SBrooks Davis 368aff4f2d3SBrooks Davis return(kern___acl_get_path(td, uap->path, uap->type, uap->aclp, 369aff4f2d3SBrooks Davis NOFOLLOW)); 370aff4f2d3SBrooks Davis } 371aff4f2d3SBrooks Davis 372aff4f2d3SBrooks Davis static int 373aff4f2d3SBrooks Davis kern___acl_get_path(struct thread *td, const char *path, acl_type_t type, 374aff4f2d3SBrooks Davis struct acl *aclp, int follow) 375aff4f2d3SBrooks Davis { 3763c67c23bSRobert Watson struct nameidata nd; 3775050aa86SKonstantin Belousov int error; 3783c67c23bSRobert Watson 3797e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); 3803c67c23bSRobert Watson error = namei(&nd); 3813c67c23bSRobert Watson if (error == 0) { 382aff4f2d3SBrooks Davis error = vacl_get_acl(td, nd.ni_vp, type, aclp); 383*85dac03eSMateusz Guzik vrele(nd.ni_vp); 384*85dac03eSMateusz Guzik NDFREE_PNBUF(&nd); 3853c67c23bSRobert Watson } 3863c67c23bSRobert Watson return (error); 3873c67c23bSRobert Watson } 3883c67c23bSRobert Watson 3893c67c23bSRobert Watson /* 3900c14ff0eSRobert Watson * Given a file path, set an ACL for it. 39191f37dcbSRobert Watson */ 39291f37dcbSRobert Watson int 3938451d0ddSKip Macy sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 39491f37dcbSRobert Watson { 39591f37dcbSRobert Watson 396aff4f2d3SBrooks Davis return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, 397aff4f2d3SBrooks Davis FOLLOW)); 39891f37dcbSRobert Watson } 39991f37dcbSRobert Watson 40091f37dcbSRobert Watson /* 4013c67c23bSRobert Watson * Given a file path, set an ACL for it; don't follow links. 4023c67c23bSRobert Watson */ 4033c67c23bSRobert Watson int 4048451d0ddSKip Macy sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 4053c67c23bSRobert Watson { 406aff4f2d3SBrooks Davis 407aff4f2d3SBrooks Davis return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, 408aff4f2d3SBrooks Davis NOFOLLOW)); 409aff4f2d3SBrooks Davis } 410aff4f2d3SBrooks Davis 411aff4f2d3SBrooks Davis static int 412aff4f2d3SBrooks Davis kern___acl_set_path(struct thread *td, const char *path, 413aff4f2d3SBrooks Davis acl_type_t type, const struct acl *aclp, int follow) 414aff4f2d3SBrooks Davis { 4153c67c23bSRobert Watson struct nameidata nd; 4165050aa86SKonstantin Belousov int error; 4173c67c23bSRobert Watson 4187e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); 4193c67c23bSRobert Watson error = namei(&nd); 4203c67c23bSRobert Watson if (error == 0) { 421aff4f2d3SBrooks Davis error = vacl_set_acl(td, nd.ni_vp, type, aclp); 422*85dac03eSMateusz Guzik vrele(nd.ni_vp); 423*85dac03eSMateusz Guzik NDFREE_PNBUF(&nd); 4243c67c23bSRobert Watson } 4253c67c23bSRobert Watson return (error); 4263c67c23bSRobert Watson } 4273c67c23bSRobert Watson 4283c67c23bSRobert Watson /* 429b5368498SRobert Watson * Given a file descriptor, get an ACL for it. 43091f37dcbSRobert Watson */ 43191f37dcbSRobert Watson int 4328451d0ddSKip Macy sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) 43391f37dcbSRobert Watson { 43491f37dcbSRobert Watson struct file *fp; 4357008be5bSPawel Jakub Dawidek cap_rights_t rights; 4365050aa86SKonstantin Belousov int error; 43791f37dcbSRobert Watson 438f9070809SRobert Watson AUDIT_ARG_FD(uap->filedes); 4394da8456fSMateusz Guzik error = getvnode(td, uap->filedes, 440e126c5a3SMateusz Guzik cap_rights_init_one(&rights, CAP_ACL_GET), &fp); 441f708f4d1SMatthew Dillon if (error == 0) { 4423b6d9652SPoul-Henning Kamp error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); 443426da3bcSAlfred Perlstein fdrop(fp, td); 444f708f4d1SMatthew Dillon } 44591f37dcbSRobert Watson return (error); 44691f37dcbSRobert Watson } 44791f37dcbSRobert Watson 44891f37dcbSRobert Watson /* 449b5368498SRobert Watson * Given a file descriptor, set an ACL for it. 45091f37dcbSRobert Watson */ 45191f37dcbSRobert Watson int 4528451d0ddSKip Macy sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) 45391f37dcbSRobert Watson { 45491f37dcbSRobert Watson struct file *fp; 4557008be5bSPawel Jakub Dawidek cap_rights_t rights; 4565050aa86SKonstantin Belousov int error; 45791f37dcbSRobert Watson 458f9070809SRobert Watson AUDIT_ARG_FD(uap->filedes); 4594da8456fSMateusz Guzik error = getvnode(td, uap->filedes, 460e126c5a3SMateusz Guzik cap_rights_init_one(&rights, CAP_ACL_SET), &fp); 461f708f4d1SMatthew Dillon if (error == 0) { 4623b6d9652SPoul-Henning Kamp error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); 463426da3bcSAlfred Perlstein fdrop(fp, td); 464f708f4d1SMatthew Dillon } 46591f37dcbSRobert Watson return (error); 46691f37dcbSRobert Watson } 46791f37dcbSRobert Watson 46891f37dcbSRobert Watson /* 46991f37dcbSRobert Watson * Given a file path, delete an ACL from it. 47091f37dcbSRobert Watson */ 47191f37dcbSRobert Watson int 4728451d0ddSKip Macy sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) 47391f37dcbSRobert Watson { 47491f37dcbSRobert Watson 475aff4f2d3SBrooks Davis return (kern___acl_delete_path(td, uap->path, uap->type, FOLLOW)); 47691f37dcbSRobert Watson } 47791f37dcbSRobert Watson 47891f37dcbSRobert Watson /* 4793c67c23bSRobert Watson * Given a file path, delete an ACL from it; don't follow links. 4803c67c23bSRobert Watson */ 4813c67c23bSRobert Watson int 4828451d0ddSKip Macy sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) 4833c67c23bSRobert Watson { 484aff4f2d3SBrooks Davis 485aff4f2d3SBrooks Davis return (kern___acl_delete_path(td, uap->path, uap->type, NOFOLLOW)); 486aff4f2d3SBrooks Davis } 487aff4f2d3SBrooks Davis 488aff4f2d3SBrooks Davis static int 489aff4f2d3SBrooks Davis kern___acl_delete_path(struct thread *td, const char *path, 490aff4f2d3SBrooks Davis acl_type_t type, int follow) 491aff4f2d3SBrooks Davis { 4923c67c23bSRobert Watson struct nameidata nd; 4935050aa86SKonstantin Belousov int error; 4943c67c23bSRobert Watson 4957e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path); 4963c67c23bSRobert Watson error = namei(&nd); 4973c67c23bSRobert Watson if (error == 0) { 498aff4f2d3SBrooks Davis error = vacl_delete(td, nd.ni_vp, type); 499*85dac03eSMateusz Guzik vrele(nd.ni_vp); 500*85dac03eSMateusz Guzik NDFREE_PNBUF(&nd); 5013c67c23bSRobert Watson } 5023c67c23bSRobert Watson return (error); 5033c67c23bSRobert Watson } 5043c67c23bSRobert Watson 5053c67c23bSRobert Watson /* 50691f37dcbSRobert Watson * Given a file path, delete an ACL from it. 50791f37dcbSRobert Watson */ 50891f37dcbSRobert Watson int 5098451d0ddSKip Macy sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) 51091f37dcbSRobert Watson { 51191f37dcbSRobert Watson struct file *fp; 5127008be5bSPawel Jakub Dawidek cap_rights_t rights; 5135050aa86SKonstantin Belousov int error; 51491f37dcbSRobert Watson 515f9070809SRobert Watson AUDIT_ARG_FD(uap->filedes); 5164da8456fSMateusz Guzik error = getvnode(td, uap->filedes, 517e126c5a3SMateusz Guzik cap_rights_init_one(&rights, CAP_ACL_DELETE), &fp); 518f708f4d1SMatthew Dillon if (error == 0) { 5193b6d9652SPoul-Henning Kamp error = vacl_delete(td, fp->f_vnode, uap->type); 520426da3bcSAlfred Perlstein fdrop(fp, td); 521f708f4d1SMatthew Dillon } 52291f37dcbSRobert Watson return (error); 52391f37dcbSRobert Watson } 52491f37dcbSRobert Watson 52591f37dcbSRobert Watson /* 5260c14ff0eSRobert Watson * Given a file path, check an ACL for it. 52791f37dcbSRobert Watson */ 52891f37dcbSRobert Watson int 5298451d0ddSKip Macy sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) 53091f37dcbSRobert Watson { 53191f37dcbSRobert Watson 532aff4f2d3SBrooks Davis return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp, 533aff4f2d3SBrooks Davis FOLLOW)); 53491f37dcbSRobert Watson } 53591f37dcbSRobert Watson 53691f37dcbSRobert Watson /* 5373c67c23bSRobert Watson * Given a file path, check an ACL for it; don't follow links. 5383c67c23bSRobert Watson */ 5393c67c23bSRobert Watson int 5408451d0ddSKip Macy sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) 5413c67c23bSRobert Watson { 542aff4f2d3SBrooks Davis return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp, 543aff4f2d3SBrooks Davis NOFOLLOW)); 544aff4f2d3SBrooks Davis } 545aff4f2d3SBrooks Davis 546aff4f2d3SBrooks Davis static int 547aff4f2d3SBrooks Davis kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type, 548aff4f2d3SBrooks Davis struct acl *aclp, int follow) 549aff4f2d3SBrooks Davis { 5507a172809SEdward Tomasz Napierala struct nameidata nd; 5515050aa86SKonstantin Belousov int error; 5523c67c23bSRobert Watson 5537e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path); 5543c67c23bSRobert Watson error = namei(&nd); 5553c67c23bSRobert Watson if (error == 0) { 556aff4f2d3SBrooks Davis error = vacl_aclcheck(td, nd.ni_vp, type, aclp); 557*85dac03eSMateusz Guzik NDFREE_PNBUF(&nd); 5583c67c23bSRobert Watson } 5593c67c23bSRobert Watson return (error); 5603c67c23bSRobert Watson } 5613c67c23bSRobert Watson 5623c67c23bSRobert Watson /* 5630c14ff0eSRobert Watson * Given a file descriptor, check an ACL for it. 56491f37dcbSRobert Watson */ 56591f37dcbSRobert Watson int 5668451d0ddSKip Macy sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) 56791f37dcbSRobert Watson { 56891f37dcbSRobert Watson struct file *fp; 5697008be5bSPawel Jakub Dawidek cap_rights_t rights; 5705050aa86SKonstantin Belousov int error; 57191f37dcbSRobert Watson 572f9070809SRobert Watson AUDIT_ARG_FD(uap->filedes); 5734da8456fSMateusz Guzik error = getvnode(td, uap->filedes, 574e126c5a3SMateusz Guzik cap_rights_init_one(&rights, CAP_ACL_CHECK), &fp); 575f708f4d1SMatthew Dillon if (error == 0) { 5763b6d9652SPoul-Henning Kamp error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); 577426da3bcSAlfred Perlstein fdrop(fp, td); 578f708f4d1SMatthew Dillon } 57991f37dcbSRobert Watson return (error); 58091f37dcbSRobert Watson } 581d1dfd921SChristian S.J. Peron 582b998d381SEdward Tomasz Napierala struct acl * 583b998d381SEdward Tomasz Napierala acl_alloc(int flags) 584b998d381SEdward Tomasz Napierala { 585b998d381SEdward Tomasz Napierala struct acl *aclp; 586b998d381SEdward Tomasz Napierala 587e0ee7589SEdward Tomasz Napierala aclp = malloc(sizeof(*aclp), M_ACL, flags); 5888ddc3590SEdward Tomasz Napierala if (aclp == NULL) 5898ddc3590SEdward Tomasz Napierala return (NULL); 5908ddc3590SEdward Tomasz Napierala 591ae1add4eSEdward Tomasz Napierala aclp->acl_maxcnt = ACL_MAX_ENTRIES; 592b998d381SEdward Tomasz Napierala 593b998d381SEdward Tomasz Napierala return (aclp); 594b998d381SEdward Tomasz Napierala } 595b998d381SEdward Tomasz Napierala 596b998d381SEdward Tomasz Napierala void 597b998d381SEdward Tomasz Napierala acl_free(struct acl *aclp) 598b998d381SEdward Tomasz Napierala { 599b998d381SEdward Tomasz Napierala 600e0ee7589SEdward Tomasz Napierala free(aclp, M_ACL); 601b998d381SEdward Tomasz Napierala } 602