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/sysent.h> 6191f37dcbSRobert Watson #include <sys/acl.h> 6291f37dcbSRobert Watson 63f9070809SRobert Watson #include <security/audit/audit.h> 64aed55708SRobert Watson #include <security/mac/mac_framework.h> 65aed55708SRobert Watson 66ae1add4eSEdward Tomasz Napierala CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES); 67ae1add4eSEdward Tomasz Napierala 68ae1add4eSEdward Tomasz Napierala MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists"); 6991f37dcbSRobert Watson 70aff4f2d3SBrooks Davis 71aff4f2d3SBrooks Davis static int kern___acl_aclcheck_path(struct thread *td, const char *path, 72aff4f2d3SBrooks Davis acl_type_t type, struct acl *aclp, int follow); 73aff4f2d3SBrooks Davis static int kern___acl_delete_path(struct thread *td, const char *path, 74aff4f2d3SBrooks Davis acl_type_t type, int follow); 75aff4f2d3SBrooks Davis static int kern___acl_get_path(struct thread *td, const char *path, 76aff4f2d3SBrooks Davis acl_type_t type, struct acl *aclp, int follow); 77aff4f2d3SBrooks Davis static int kern___acl_set_path(struct thread *td, const char *path, 78aff4f2d3SBrooks Davis acl_type_t type, const struct acl *aclp, int follow); 79cbeb8402SRobert Watson static int vacl_set_acl(struct thread *td, struct vnode *vp, 80aff4f2d3SBrooks Davis acl_type_t type, const struct acl *aclp); 81cbeb8402SRobert Watson static int vacl_get_acl(struct thread *td, struct vnode *vp, 82cbeb8402SRobert Watson acl_type_t type, struct acl *aclp); 83b40ce416SJulian Elischer static int vacl_aclcheck(struct thread *td, struct vnode *vp, 84aff4f2d3SBrooks Davis acl_type_t type, const struct acl *aclp); 8591f37dcbSRobert Watson 86ae1add4eSEdward Tomasz Napierala int 87ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest) 88ae1add4eSEdward Tomasz Napierala { 89ae1add4eSEdward Tomasz Napierala int i; 90ae1add4eSEdward Tomasz Napierala 91ae1add4eSEdward Tomasz Napierala if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) 92ae1add4eSEdward Tomasz Napierala return (EINVAL); 93ae1add4eSEdward Tomasz Napierala 94ae1add4eSEdward Tomasz Napierala bzero(dest, sizeof(*dest)); 95ae1add4eSEdward Tomasz Napierala 96ae1add4eSEdward Tomasz Napierala dest->acl_cnt = source->acl_cnt; 97ae1add4eSEdward Tomasz Napierala dest->acl_maxcnt = ACL_MAX_ENTRIES; 98ae1add4eSEdward Tomasz Napierala 99ae1add4eSEdward Tomasz Napierala for (i = 0; i < dest->acl_cnt; i++) { 100ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 101ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 102ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 103ae1add4eSEdward Tomasz Napierala } 104ae1add4eSEdward Tomasz Napierala 105ae1add4eSEdward Tomasz Napierala return (0); 106ae1add4eSEdward Tomasz Napierala } 107ae1add4eSEdward Tomasz Napierala 108ae1add4eSEdward Tomasz Napierala int 109ae1add4eSEdward Tomasz Napierala acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest) 110ae1add4eSEdward Tomasz Napierala { 111ae1add4eSEdward Tomasz Napierala int i; 112ae1add4eSEdward Tomasz Napierala 113ce9d79aaSEdward Tomasz Napierala if (source->acl_cnt > OLDACL_MAX_ENTRIES) 114ae1add4eSEdward Tomasz Napierala return (EINVAL); 115ae1add4eSEdward Tomasz Napierala 116ae1add4eSEdward Tomasz Napierala bzero(dest, sizeof(*dest)); 117ae1add4eSEdward Tomasz Napierala 118ae1add4eSEdward Tomasz Napierala dest->acl_cnt = source->acl_cnt; 119ae1add4eSEdward Tomasz Napierala 120ae1add4eSEdward Tomasz Napierala for (i = 0; i < dest->acl_cnt; i++) { 121ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 122ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 123ae1add4eSEdward Tomasz Napierala dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 124ae1add4eSEdward Tomasz Napierala } 125ae1add4eSEdward Tomasz Napierala 126ae1add4eSEdward Tomasz Napierala return (0); 127ae1add4eSEdward Tomasz Napierala } 128ae1add4eSEdward Tomasz Napierala 129ae1add4eSEdward Tomasz Napierala /* 130ae1add4eSEdward Tomasz Napierala * At one time, "struct ACL" was extended in order to add support for NFSv4 131ae1add4eSEdward Tomasz Napierala * ACLs. Instead of creating compatibility versions of all the ACL-related 132ae1add4eSEdward Tomasz Napierala * syscalls, they were left intact. It's possible to find out what the code 133ae1add4eSEdward Tomasz Napierala * calling these syscalls (libc) expects basing on "type" argument - if it's 134ae1add4eSEdward Tomasz Napierala * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were 135ae1add4eSEdward Tomasz Napierala * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct 136ae1add4eSEdward Tomasz Napierala * oldacl". If it's something else, then it's the new "struct acl". In the 137ae1add4eSEdward Tomasz Napierala * latter case, the routines below just copyin/copyout the contents. In the 138ae1add4eSEdward Tomasz Napierala * former case, they copyin the "struct oldacl" and convert it to the new 139ae1add4eSEdward Tomasz Napierala * format. 140ae1add4eSEdward Tomasz Napierala */ 141ae1add4eSEdward Tomasz Napierala static int 142aff4f2d3SBrooks Davis acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type) 143ae1add4eSEdward Tomasz Napierala { 144ae1add4eSEdward Tomasz Napierala int error; 145ae1add4eSEdward Tomasz Napierala struct oldacl old; 146ae1add4eSEdward Tomasz Napierala 147ae1add4eSEdward Tomasz Napierala switch (type) { 148ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 149ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 150ae1add4eSEdward Tomasz Napierala error = copyin(user_acl, &old, sizeof(old)); 151ae1add4eSEdward Tomasz Napierala if (error != 0) 152ae1add4eSEdward Tomasz Napierala break; 153ae1add4eSEdward Tomasz Napierala acl_copy_oldacl_into_acl(&old, kernel_acl); 154ae1add4eSEdward Tomasz Napierala break; 155ae1add4eSEdward Tomasz Napierala 156ae1add4eSEdward Tomasz Napierala default: 157ae1add4eSEdward Tomasz Napierala error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl)); 158ae1add4eSEdward Tomasz Napierala if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES) 159ae1add4eSEdward Tomasz Napierala return (EINVAL); 160ae1add4eSEdward Tomasz Napierala } 161ae1add4eSEdward Tomasz Napierala 162ae1add4eSEdward Tomasz Napierala return (error); 163ae1add4eSEdward Tomasz Napierala } 164ae1add4eSEdward Tomasz Napierala 165ae1add4eSEdward Tomasz Napierala static int 166aff4f2d3SBrooks Davis acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type) 167ae1add4eSEdward Tomasz Napierala { 1680a2c94b8SKonstantin Belousov uint32_t am; 169ae1add4eSEdward Tomasz Napierala int error; 170ae1add4eSEdward Tomasz Napierala struct oldacl old; 171ae1add4eSEdward Tomasz Napierala 172ae1add4eSEdward Tomasz Napierala switch (type) { 173ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 174ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 175ae1add4eSEdward Tomasz Napierala error = acl_copy_acl_into_oldacl(kernel_acl, &old); 176ae1add4eSEdward Tomasz Napierala if (error != 0) 177ae1add4eSEdward Tomasz Napierala break; 178ae1add4eSEdward Tomasz Napierala 179ae1add4eSEdward Tomasz Napierala error = copyout(&old, user_acl, sizeof(old)); 180ae1add4eSEdward Tomasz Napierala break; 181ae1add4eSEdward Tomasz Napierala 182ae1add4eSEdward Tomasz Napierala default: 1830a2c94b8SKonstantin Belousov error = fueword32((char *)user_acl + 1840a2c94b8SKonstantin Belousov offsetof(struct acl, acl_maxcnt), &am); 1850a2c94b8SKonstantin Belousov if (error == -1) 1860a2c94b8SKonstantin Belousov return (EFAULT); 1870a2c94b8SKonstantin Belousov if (am != ACL_MAX_ENTRIES) 188ae1add4eSEdward Tomasz Napierala return (EINVAL); 189ae1add4eSEdward Tomasz Napierala 190ae1add4eSEdward Tomasz Napierala error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl)); 191ae1add4eSEdward Tomasz Napierala } 192ae1add4eSEdward Tomasz Napierala 193ae1add4eSEdward Tomasz Napierala return (error); 194ae1add4eSEdward Tomasz Napierala } 195ae1add4eSEdward Tomasz Napierala 196ae1add4eSEdward Tomasz Napierala /* 197ae1add4eSEdward Tomasz Napierala * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new" 1986bb58cddSEdward Tomasz Napierala * counterpart. It's required for old (pre-NFSv4 ACLs) libc to work 199ae1add4eSEdward Tomasz Napierala * with new kernel. Fixing 'type' for old binaries with new libc 200ae1add4eSEdward Tomasz Napierala * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold(). 201ae1add4eSEdward Tomasz Napierala */ 202ae1add4eSEdward Tomasz Napierala static int 203ae1add4eSEdward Tomasz Napierala acl_type_unold(int type) 204ae1add4eSEdward Tomasz Napierala { 205ae1add4eSEdward Tomasz Napierala switch (type) { 206ae1add4eSEdward Tomasz Napierala case ACL_TYPE_ACCESS_OLD: 207ae1add4eSEdward Tomasz Napierala return (ACL_TYPE_ACCESS); 208ae1add4eSEdward Tomasz Napierala 209ae1add4eSEdward Tomasz Napierala case ACL_TYPE_DEFAULT_OLD: 210ae1add4eSEdward Tomasz Napierala return (ACL_TYPE_DEFAULT); 211ae1add4eSEdward Tomasz Napierala 212ae1add4eSEdward Tomasz Napierala default: 213ae1add4eSEdward Tomasz Napierala return (type); 214ae1add4eSEdward Tomasz Napierala } 215ae1add4eSEdward Tomasz Napierala } 216ae1add4eSEdward Tomasz Napierala 21791f37dcbSRobert Watson /* 218b0c521e2SRobert Watson * These calls wrap the real vnode operations, and are called by the syscall 219b0c521e2SRobert Watson * code once the syscall has converted the path or file descriptor to a vnode 220b0c521e2SRobert Watson * (unlocked). The aclp pointer is assumed still to point to userland, so 221b0c521e2SRobert Watson * this should not be consumed within the kernel except by syscall code. 222b0c521e2SRobert Watson * Other code should directly invoke VOP_{SET,GET}ACL. 22391f37dcbSRobert Watson */ 22491f37dcbSRobert Watson 22591f37dcbSRobert Watson /* 22691f37dcbSRobert Watson * Given a vnode, set its ACL. 22791f37dcbSRobert Watson */ 22891f37dcbSRobert Watson static int 229b40ce416SJulian Elischer vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, 230aff4f2d3SBrooks Davis const struct acl *aclp) 23191f37dcbSRobert Watson { 232b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 2334e1123c7SRobert Watson struct mount *mp; 23491f37dcbSRobert Watson int error; 23591f37dcbSRobert Watson 236f9070809SRobert Watson AUDIT_ARG_VALUE(type); 237b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 238ae1add4eSEdward Tomasz Napierala error = acl_copyin(aclp, inkernelacl, type); 239da9ce28eSEdward Tomasz Napierala if (error != 0) 240b998d381SEdward Tomasz Napierala goto out; 2414e1123c7SRobert Watson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 2424e1123c7SRobert Watson if (error != 0) 243b998d381SEdward Tomasz Napierala goto out; 244cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 245f9070809SRobert Watson AUDIT_ARG_VNODE1(vp); 246c86ca022SRobert Watson #ifdef MAC 247b998d381SEdward Tomasz Napierala error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl); 248c86ca022SRobert Watson if (error != 0) 249b998d381SEdward Tomasz Napierala goto out_unlock; 250c86ca022SRobert Watson #endif 251ae1add4eSEdward Tomasz Napierala error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl, 252ae1add4eSEdward Tomasz Napierala td->td_ucred, td); 253c86ca022SRobert Watson #ifdef MAC 254b998d381SEdward Tomasz Napierala out_unlock: 255c86ca022SRobert Watson #endif 256*b249ce48SMateusz Guzik VOP_UNLOCK(vp); 2574e1123c7SRobert Watson vn_finished_write(mp); 258b998d381SEdward Tomasz Napierala out: 259b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 26091f37dcbSRobert Watson return (error); 26191f37dcbSRobert Watson } 26291f37dcbSRobert Watson 26391f37dcbSRobert Watson /* 26491f37dcbSRobert Watson * Given a vnode, get its ACL. 26591f37dcbSRobert Watson */ 26691f37dcbSRobert Watson static int 267b40ce416SJulian Elischer vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type, 26891f37dcbSRobert Watson struct acl *aclp) 26991f37dcbSRobert Watson { 270b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 27191f37dcbSRobert Watson int error; 27291f37dcbSRobert Watson 273f9070809SRobert Watson AUDIT_ARG_VALUE(type); 27423c053d6SSergey Kandaurov inkernelacl = acl_alloc(M_WAITOK | M_ZERO); 275cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 276f9070809SRobert Watson AUDIT_ARG_VNODE1(vp); 277c86ca022SRobert Watson #ifdef MAC 27830d239bcSRobert Watson error = mac_vnode_check_getacl(td->td_ucred, vp, type); 279c86ca022SRobert Watson if (error != 0) 280c86ca022SRobert Watson goto out; 281c86ca022SRobert Watson #endif 282ae1add4eSEdward Tomasz Napierala error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl, 283ae1add4eSEdward Tomasz Napierala td->td_ucred, td); 284ae1add4eSEdward Tomasz Napierala 285c86ca022SRobert Watson #ifdef MAC 286c86ca022SRobert Watson out: 287c86ca022SRobert Watson #endif 288*b249ce48SMateusz Guzik VOP_UNLOCK(vp); 28991f37dcbSRobert Watson if (error == 0) 290ae1add4eSEdward Tomasz Napierala error = acl_copyout(inkernelacl, aclp, type); 291b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 29291f37dcbSRobert Watson return (error); 29391f37dcbSRobert Watson } 29491f37dcbSRobert Watson 29591f37dcbSRobert Watson /* 29691f37dcbSRobert Watson * Given a vnode, delete its ACL. 29791f37dcbSRobert Watson */ 29891f37dcbSRobert Watson static int 299b40ce416SJulian Elischer vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type) 30091f37dcbSRobert Watson { 3014e1123c7SRobert Watson struct mount *mp; 30291f37dcbSRobert Watson int error; 30391f37dcbSRobert Watson 304f9070809SRobert Watson AUDIT_ARG_VALUE(type); 3054e1123c7SRobert Watson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 306da9ce28eSEdward Tomasz Napierala if (error != 0) 3074e1123c7SRobert Watson return (error); 308cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 309f9070809SRobert Watson AUDIT_ARG_VNODE1(vp); 310c86ca022SRobert Watson #ifdef MAC 31130d239bcSRobert Watson error = mac_vnode_check_deleteacl(td->td_ucred, vp, type); 312da9ce28eSEdward Tomasz Napierala if (error != 0) 313c86ca022SRobert Watson goto out; 314c86ca022SRobert Watson #endif 315ae1add4eSEdward Tomasz Napierala error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td); 316c86ca022SRobert Watson #ifdef MAC 317c86ca022SRobert Watson out: 318c86ca022SRobert Watson #endif 319*b249ce48SMateusz Guzik VOP_UNLOCK(vp); 3204e1123c7SRobert Watson vn_finished_write(mp); 32191f37dcbSRobert Watson return (error); 32291f37dcbSRobert Watson } 32391f37dcbSRobert Watson 32491f37dcbSRobert Watson /* 32591f37dcbSRobert Watson * Given a vnode, check whether an ACL is appropriate for it 326f9070809SRobert Watson * 327f9070809SRobert Watson * XXXRW: No vnode lock held so can't audit vnode state...? 32891f37dcbSRobert Watson */ 32991f37dcbSRobert Watson static int 330b40ce416SJulian Elischer vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, 331aff4f2d3SBrooks Davis const struct acl *aclp) 33291f37dcbSRobert Watson { 333b998d381SEdward Tomasz Napierala struct acl *inkernelacl; 33491f37dcbSRobert Watson int error; 33591f37dcbSRobert Watson 336b998d381SEdward Tomasz Napierala inkernelacl = acl_alloc(M_WAITOK); 337ae1add4eSEdward Tomasz Napierala error = acl_copyin(aclp, inkernelacl, type); 338da9ce28eSEdward Tomasz Napierala if (error != 0) 339b998d381SEdward Tomasz Napierala goto out; 3406bb58cddSEdward Tomasz Napierala error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl, 3416bb58cddSEdward Tomasz Napierala td->td_ucred, td); 342b998d381SEdward Tomasz Napierala out: 343b998d381SEdward Tomasz Napierala acl_free(inkernelacl); 34491f37dcbSRobert Watson return (error); 34591f37dcbSRobert Watson } 34691f37dcbSRobert Watson 34791f37dcbSRobert Watson /* 348b0c521e2SRobert Watson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. Don't 349b0c521e2SRobert Watson * need to lock, as the vacl_ code will get/release any locks required. 35091f37dcbSRobert Watson */ 35191f37dcbSRobert Watson 35291f37dcbSRobert Watson /* 35391f37dcbSRobert Watson * Given a file path, get an ACL for it 35491f37dcbSRobert Watson */ 35591f37dcbSRobert Watson int 3568451d0ddSKip Macy sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap) 35791f37dcbSRobert Watson { 35891f37dcbSRobert Watson 359aff4f2d3SBrooks Davis return (kern___acl_get_path(td, uap->path, uap->type, uap->aclp, 360aff4f2d3SBrooks Davis FOLLOW)); 36191f37dcbSRobert Watson } 36291f37dcbSRobert Watson 36391f37dcbSRobert Watson /* 3643c67c23bSRobert Watson * Given a file path, get an ACL for it; don't follow links. 3653c67c23bSRobert Watson */ 3663c67c23bSRobert Watson int 3678451d0ddSKip Macy sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap) 3683c67c23bSRobert Watson { 369aff4f2d3SBrooks Davis 370aff4f2d3SBrooks Davis return(kern___acl_get_path(td, uap->path, uap->type, uap->aclp, 371aff4f2d3SBrooks Davis NOFOLLOW)); 372aff4f2d3SBrooks Davis } 373aff4f2d3SBrooks Davis 374aff4f2d3SBrooks Davis static int 375aff4f2d3SBrooks Davis kern___acl_get_path(struct thread *td, const char *path, acl_type_t type, 376aff4f2d3SBrooks Davis struct acl *aclp, int follow) 377aff4f2d3SBrooks Davis { 3783c67c23bSRobert Watson struct nameidata nd; 3795050aa86SKonstantin Belousov int error; 3803c67c23bSRobert Watson 381aff4f2d3SBrooks Davis NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td); 3823c67c23bSRobert Watson error = namei(&nd); 3833c67c23bSRobert Watson if (error == 0) { 384aff4f2d3SBrooks Davis error = vacl_get_acl(td, nd.ni_vp, type, aclp); 3853c67c23bSRobert Watson NDFREE(&nd, 0); 3863c67c23bSRobert Watson } 3873c67c23bSRobert Watson return (error); 3883c67c23bSRobert Watson } 3893c67c23bSRobert Watson 3903c67c23bSRobert Watson /* 3910c14ff0eSRobert Watson * Given a file path, set an ACL for it. 39291f37dcbSRobert Watson */ 39391f37dcbSRobert Watson int 3948451d0ddSKip Macy sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 39591f37dcbSRobert Watson { 39691f37dcbSRobert Watson 397aff4f2d3SBrooks Davis return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, 398aff4f2d3SBrooks Davis FOLLOW)); 39991f37dcbSRobert Watson } 40091f37dcbSRobert Watson 40191f37dcbSRobert Watson /* 4023c67c23bSRobert Watson * Given a file path, set an ACL for it; don't follow links. 4033c67c23bSRobert Watson */ 4043c67c23bSRobert Watson int 4058451d0ddSKip Macy sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 4063c67c23bSRobert Watson { 407aff4f2d3SBrooks Davis 408aff4f2d3SBrooks Davis return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, 409aff4f2d3SBrooks Davis NOFOLLOW)); 410aff4f2d3SBrooks Davis } 411aff4f2d3SBrooks Davis 412aff4f2d3SBrooks Davis static int 413aff4f2d3SBrooks Davis kern___acl_set_path(struct thread *td, const char *path, 414aff4f2d3SBrooks Davis acl_type_t type, const struct acl *aclp, int follow) 415aff4f2d3SBrooks Davis { 4163c67c23bSRobert Watson struct nameidata nd; 4175050aa86SKonstantin Belousov int error; 4183c67c23bSRobert Watson 419aff4f2d3SBrooks Davis NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td); 4203c67c23bSRobert Watson error = namei(&nd); 4213c67c23bSRobert Watson if (error == 0) { 422aff4f2d3SBrooks Davis error = vacl_set_acl(td, nd.ni_vp, type, aclp); 4233c67c23bSRobert Watson NDFREE(&nd, 0); 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, 4407008be5bSPawel Jakub Dawidek cap_rights_init(&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, 4607008be5bSPawel Jakub Dawidek cap_rights_init(&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 495aff4f2d3SBrooks Davis NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path, td); 4963c67c23bSRobert Watson error = namei(&nd); 4973c67c23bSRobert Watson if (error == 0) { 498aff4f2d3SBrooks Davis error = vacl_delete(td, nd.ni_vp, type); 4993c67c23bSRobert Watson NDFREE(&nd, 0); 5003c67c23bSRobert Watson } 5013c67c23bSRobert Watson return (error); 5023c67c23bSRobert Watson } 5033c67c23bSRobert Watson 5043c67c23bSRobert Watson /* 50591f37dcbSRobert Watson * Given a file path, delete an ACL from it. 50691f37dcbSRobert Watson */ 50791f37dcbSRobert Watson int 5088451d0ddSKip Macy sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) 50991f37dcbSRobert Watson { 51091f37dcbSRobert Watson struct file *fp; 5117008be5bSPawel Jakub Dawidek cap_rights_t rights; 5125050aa86SKonstantin Belousov int error; 51391f37dcbSRobert Watson 514f9070809SRobert Watson AUDIT_ARG_FD(uap->filedes); 5154da8456fSMateusz Guzik error = getvnode(td, uap->filedes, 5167008be5bSPawel Jakub Dawidek cap_rights_init(&rights, CAP_ACL_DELETE), &fp); 517f708f4d1SMatthew Dillon if (error == 0) { 5183b6d9652SPoul-Henning Kamp error = vacl_delete(td, fp->f_vnode, uap->type); 519426da3bcSAlfred Perlstein fdrop(fp, td); 520f708f4d1SMatthew Dillon } 52191f37dcbSRobert Watson return (error); 52291f37dcbSRobert Watson } 52391f37dcbSRobert Watson 52491f37dcbSRobert Watson /* 5250c14ff0eSRobert Watson * Given a file path, check an ACL for it. 52691f37dcbSRobert Watson */ 52791f37dcbSRobert Watson int 5288451d0ddSKip Macy sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) 52991f37dcbSRobert Watson { 53091f37dcbSRobert Watson 531aff4f2d3SBrooks Davis return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp, 532aff4f2d3SBrooks Davis FOLLOW)); 53391f37dcbSRobert Watson } 53491f37dcbSRobert Watson 53591f37dcbSRobert Watson /* 5363c67c23bSRobert Watson * Given a file path, check an ACL for it; don't follow links. 5373c67c23bSRobert Watson */ 5383c67c23bSRobert Watson int 5398451d0ddSKip Macy sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) 5403c67c23bSRobert Watson { 541aff4f2d3SBrooks Davis return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp, 542aff4f2d3SBrooks Davis NOFOLLOW)); 543aff4f2d3SBrooks Davis } 544aff4f2d3SBrooks Davis 545aff4f2d3SBrooks Davis static int 546aff4f2d3SBrooks Davis kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type, 547aff4f2d3SBrooks Davis struct acl *aclp, int follow) 548aff4f2d3SBrooks Davis { 5497a172809SEdward Tomasz Napierala struct nameidata nd; 5505050aa86SKonstantin Belousov int error; 5513c67c23bSRobert Watson 552aff4f2d3SBrooks Davis NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path, td); 5533c67c23bSRobert Watson error = namei(&nd); 5543c67c23bSRobert Watson if (error == 0) { 555aff4f2d3SBrooks Davis error = vacl_aclcheck(td, nd.ni_vp, type, aclp); 5563c67c23bSRobert Watson NDFREE(&nd, 0); 5573c67c23bSRobert Watson } 5583c67c23bSRobert Watson return (error); 5593c67c23bSRobert Watson } 5603c67c23bSRobert Watson 5613c67c23bSRobert Watson /* 5620c14ff0eSRobert Watson * Given a file descriptor, check an ACL for it. 56391f37dcbSRobert Watson */ 56491f37dcbSRobert Watson int 5658451d0ddSKip Macy sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) 56691f37dcbSRobert Watson { 56791f37dcbSRobert Watson struct file *fp; 5687008be5bSPawel Jakub Dawidek cap_rights_t rights; 5695050aa86SKonstantin Belousov int error; 57091f37dcbSRobert Watson 571f9070809SRobert Watson AUDIT_ARG_FD(uap->filedes); 5724da8456fSMateusz Guzik error = getvnode(td, uap->filedes, 5737008be5bSPawel Jakub Dawidek cap_rights_init(&rights, CAP_ACL_CHECK), &fp); 574f708f4d1SMatthew Dillon if (error == 0) { 5753b6d9652SPoul-Henning Kamp error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); 576426da3bcSAlfred Perlstein fdrop(fp, td); 577f708f4d1SMatthew Dillon } 57891f37dcbSRobert Watson return (error); 57991f37dcbSRobert Watson } 580d1dfd921SChristian S.J. Peron 581b998d381SEdward Tomasz Napierala struct acl * 582b998d381SEdward Tomasz Napierala acl_alloc(int flags) 583b998d381SEdward Tomasz Napierala { 584b998d381SEdward Tomasz Napierala struct acl *aclp; 585b998d381SEdward Tomasz Napierala 586e0ee7589SEdward Tomasz Napierala aclp = malloc(sizeof(*aclp), M_ACL, flags); 5878ddc3590SEdward Tomasz Napierala if (aclp == NULL) 5888ddc3590SEdward Tomasz Napierala return (NULL); 5898ddc3590SEdward Tomasz Napierala 590ae1add4eSEdward Tomasz Napierala aclp->acl_maxcnt = ACL_MAX_ENTRIES; 591b998d381SEdward Tomasz Napierala 592b998d381SEdward Tomasz Napierala return (aclp); 593b998d381SEdward Tomasz Napierala } 594b998d381SEdward Tomasz Napierala 595b998d381SEdward Tomasz Napierala void 596b998d381SEdward Tomasz Napierala acl_free(struct acl *aclp) 597b998d381SEdward Tomasz Napierala { 598b998d381SEdward Tomasz Napierala 599e0ee7589SEdward Tomasz Napierala free(aclp, M_ACL); 600b998d381SEdward Tomasz Napierala } 601