1193850Strasz/*- 2216413Strasz * Copyright (c) 2008-2010 Edward Tomasz Napiera��a <trasz@FreeBSD.org> 3193850Strasz * All rights reserved. 4193850Strasz * 5193850Strasz * Redistribution and use in source and binary forms, with or without 6193850Strasz * modification, are permitted provided that the following conditions 7193850Strasz * are met: 8193850Strasz * 1. Redistributions of source code must retain the above copyright 9193850Strasz * notice, this list of conditions and the following disclaimer. 10193850Strasz * 2. Redistributions in binary form must reproduce the above copyright 11193850Strasz * notice, this list of conditions and the following disclaimer in the 12193850Strasz * documentation and/or other materials provided with the distribution. 13193850Strasz * 14193850Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15193850Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16193850Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17193850Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18193850Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19193850Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20193850Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21193850Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22193850Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23193850Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24193850Strasz * SUCH DAMAGE. 25193850Strasz */ 26193850Strasz 27193850Strasz/* 28193850Strasz * ACL support routines specific to NFSv4 access control lists. These are 29193850Strasz * utility routines for code common across file systems implementing NFSv4 30193850Strasz * ACLs. 31193850Strasz */ 32193850Strasz 33193850Strasz#ifdef _KERNEL 34193850Strasz#include <sys/cdefs.h> 35193850Strasz__FBSDID("$FreeBSD: releng/10.3/sys/kern/subr_acl_nfs4.c 290893 2015-11-15 23:54:34Z ngie $"); 36193850Strasz 37193850Strasz#include <sys/param.h> 38232936Sadrian#include <sys/kernel.h> 39232936Sadrian#include <sys/module.h> 40193850Strasz#include <sys/systm.h> 41193850Strasz#include <sys/mount.h> 42193850Strasz#include <sys/priv.h> 43193850Strasz#include <sys/vnode.h> 44193850Strasz#include <sys/errno.h> 45193850Strasz#include <sys/stat.h> 46216413Strasz#include <sys/sysctl.h> 47193850Strasz#include <sys/acl.h> 48193850Strasz#else 49193850Strasz#include <errno.h> 50193850Strasz#include <assert.h> 51193850Strasz#include <sys/acl.h> 52193850Strasz#include <sys/stat.h> 53193850Strasz#define KASSERT(a, b) assert(a) 54193850Strasz#define CTASSERT(a) 55193850Strasz 56216413Strasz#endif /* !_KERNEL */ 57216413Strasz 58219878Strasz#ifdef _KERNEL 59219878Strasz 60219878Straszstatic void acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode); 61219878Strasz 62219880Straszstatic int acl_nfs4_old_semantics = 0; 63216413Strasz 64216413StraszSYSCTL_INT(_vfs, OID_AUTO, acl_nfs4_old_semantics, CTLFLAG_RW, 65219880Strasz &acl_nfs4_old_semantics, 0, "Use pre-PSARC/2010/029 NFSv4 ACL semantics"); 66216413Strasz 67197405Straszstatic struct { 68197405Strasz accmode_t accmode; 69197405Strasz int mask; 70197405Strasz} accmode2mask[] = {{VREAD, ACL_READ_DATA}, 71197405Strasz {VWRITE, ACL_WRITE_DATA}, 72197405Strasz {VAPPEND, ACL_APPEND_DATA}, 73197405Strasz {VEXEC, ACL_EXECUTE}, 74197405Strasz {VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, 75197405Strasz {VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, 76197405Strasz {VDELETE_CHILD, ACL_DELETE_CHILD}, 77197405Strasz {VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES}, 78197405Strasz {VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, 79197405Strasz {VDELETE, ACL_DELETE}, 80197405Strasz {VREAD_ACL, ACL_READ_ACL}, 81197405Strasz {VWRITE_ACL, ACL_WRITE_ACL}, 82197405Strasz {VWRITE_OWNER, ACL_WRITE_OWNER}, 83197405Strasz {VSYNCHRONIZE, ACL_SYNCHRONIZE}, 84197405Strasz {0, 0}}; 85197405Strasz 86193850Straszstatic int 87197405Strasz_access_mask_from_accmode(accmode_t accmode) 88197405Strasz{ 89197405Strasz int access_mask = 0, i; 90197405Strasz 91197405Strasz for (i = 0; accmode2mask[i].accmode != 0; i++) { 92197405Strasz if (accmode & accmode2mask[i].accmode) 93197405Strasz access_mask |= accmode2mask[i].mask; 94197405Strasz } 95197405Strasz 96200723Strasz /* 97200723Strasz * VAPPEND is just a modifier for VWRITE; if the caller asked 98200723Strasz * for 'VAPPEND | VWRITE', we want to check for ACL_APPEND_DATA only. 99200723Strasz */ 100200723Strasz if (access_mask & ACL_APPEND_DATA) 101200723Strasz access_mask &= ~ACL_WRITE_DATA; 102200723Strasz 103197405Strasz return (access_mask); 104197405Strasz} 105197405Strasz 106197405Strasz/* 107197405Strasz * Return 0, iff access is allowed, 1 otherwise. 108197405Strasz */ 109197405Straszstatic int 110197405Strasz_acl_denies(const struct acl *aclp, int access_mask, struct ucred *cred, 111197405Strasz int file_uid, int file_gid, int *denied_explicitly) 112197405Strasz{ 113197405Strasz int i; 114197405Strasz const struct acl_entry *entry; 115197405Strasz 116197405Strasz if (denied_explicitly != NULL) 117197405Strasz *denied_explicitly = 0; 118197405Strasz 119197405Strasz KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES, 120197405Strasz ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); 121197405Strasz 122197405Strasz for (i = 0; i < aclp->acl_cnt; i++) { 123197405Strasz entry = &(aclp->acl_entry[i]); 124197405Strasz 125197405Strasz if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 126197405Strasz entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) 127197405Strasz continue; 128197405Strasz if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) 129197405Strasz continue; 130197405Strasz switch (entry->ae_tag) { 131197405Strasz case ACL_USER_OBJ: 132197405Strasz if (file_uid != cred->cr_uid) 133197405Strasz continue; 134197405Strasz break; 135197405Strasz case ACL_USER: 136197405Strasz if (entry->ae_id != cred->cr_uid) 137197405Strasz continue; 138197405Strasz break; 139197405Strasz case ACL_GROUP_OBJ: 140197405Strasz if (!groupmember(file_gid, cred)) 141197405Strasz continue; 142197405Strasz break; 143197405Strasz case ACL_GROUP: 144197405Strasz if (!groupmember(entry->ae_id, cred)) 145197405Strasz continue; 146197405Strasz break; 147197405Strasz default: 148197405Strasz KASSERT(entry->ae_tag == ACL_EVERYONE, 149197405Strasz ("entry->ae_tag == ACL_EVERYONE")); 150197405Strasz } 151197405Strasz 152197405Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_DENY) { 153197405Strasz if (entry->ae_perm & access_mask) { 154197405Strasz if (denied_explicitly != NULL) 155197405Strasz *denied_explicitly = 1; 156197405Strasz return (1); 157197405Strasz } 158197405Strasz } 159197405Strasz 160197405Strasz access_mask &= ~(entry->ae_perm); 161197405Strasz if (access_mask == 0) 162197405Strasz return (0); 163197405Strasz } 164197405Strasz 165234385Strasz if (access_mask == 0) 166234385Strasz return (0); 167234385Strasz 168197405Strasz return (1); 169197405Strasz} 170197405Strasz 171197405Straszint 172197405Straszvaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid, 173197405Strasz struct acl *aclp, accmode_t accmode, struct ucred *cred, int *privused) 174197405Strasz{ 175197405Strasz accmode_t priv_granted = 0; 176197405Strasz int denied, explicitly_denied, access_mask, is_directory, 177197405Strasz must_be_owner = 0; 178214522Strasz mode_t file_mode = 0; 179197405Strasz 180201019Strasz KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND | 181201019Strasz VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS | 182201019Strasz VDELETE_CHILD | VREAD_ATTRIBUTES | VWRITE_ATTRIBUTES | VDELETE | 183201019Strasz VREAD_ACL | VWRITE_ACL | VWRITE_OWNER | VSYNCHRONIZE)) == 0, 184201019Strasz ("invalid bit in accmode")); 185201019Strasz KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE), 186201019Strasz ("VAPPEND without VWRITE")); 187201019Strasz 188197405Strasz if (privused != NULL) 189197405Strasz *privused = 0; 190197405Strasz 191197405Strasz if (accmode & VADMIN) 192197405Strasz must_be_owner = 1; 193197405Strasz 194197405Strasz /* 195197405Strasz * Ignore VSYNCHRONIZE permission. 196197405Strasz */ 197197405Strasz accmode &= ~VSYNCHRONIZE; 198197405Strasz 199197405Strasz access_mask = _access_mask_from_accmode(accmode); 200197405Strasz 201197405Strasz if (type == VDIR) 202197405Strasz is_directory = 1; 203197405Strasz else 204197405Strasz is_directory = 0; 205197405Strasz 206197405Strasz /* 207197405Strasz * File owner is always allowed to read and write the ACL 208197405Strasz * and basic attributes. This is to prevent a situation 209197405Strasz * where user would change ACL in a way that prevents him 210197405Strasz * from undoing the change. 211197405Strasz */ 212197405Strasz if (file_uid == cred->cr_uid) 213197405Strasz access_mask &= ~(ACL_READ_ACL | ACL_WRITE_ACL | 214197405Strasz ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES); 215197405Strasz 216197405Strasz /* 217197405Strasz * Ignore append permission for regular files; use write 218197405Strasz * permission instead. 219197405Strasz */ 220197405Strasz if (!is_directory && (access_mask & ACL_APPEND_DATA)) { 221197405Strasz access_mask &= ~ACL_APPEND_DATA; 222197405Strasz access_mask |= ACL_WRITE_DATA; 223197405Strasz } 224197405Strasz 225197405Strasz denied = _acl_denies(aclp, access_mask, cred, file_uid, file_gid, 226197405Strasz &explicitly_denied); 227197405Strasz 228197405Strasz if (must_be_owner) { 229197405Strasz if (file_uid != cred->cr_uid) 230197405Strasz denied = EPERM; 231197405Strasz } 232197405Strasz 233212002Sjh /* 234212002Sjh * For VEXEC, ensure that at least one execute bit is set for 235212002Sjh * non-directories. We have to check the mode here to stay 236212002Sjh * consistent with execve(2). See the test in 237212002Sjh * exec_check_permissions(). 238212002Sjh */ 239212002Sjh acl_nfs4_sync_mode_from_acl(&file_mode, aclp); 240212002Sjh if (!denied && !is_directory && (accmode & VEXEC) && 241212002Sjh (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) 242212002Sjh denied = EACCES; 243212002Sjh 244197405Strasz if (!denied) 245197405Strasz return (0); 246197405Strasz 247197405Strasz /* 248197405Strasz * Access failed. Iff it was not denied explicitly and 249197405Strasz * VEXPLICIT_DENY flag was specified, allow access. 250197405Strasz */ 251197405Strasz if ((accmode & VEXPLICIT_DENY) && explicitly_denied == 0) 252197405Strasz return (0); 253197405Strasz 254197405Strasz accmode &= ~VEXPLICIT_DENY; 255197405Strasz 256197405Strasz /* 257197405Strasz * No match. Try to use privileges, if there are any. 258197405Strasz */ 259197405Strasz if (is_directory) { 260197405Strasz if ((accmode & VEXEC) && !priv_check_cred(cred, 261197405Strasz PRIV_VFS_LOOKUP, 0)) 262197405Strasz priv_granted |= VEXEC; 263197405Strasz } else { 264212002Sjh /* 265212002Sjh * Ensure that at least one execute bit is on. Otherwise, 266212002Sjh * a privileged user will always succeed, and we don't want 267212002Sjh * this to happen unless the file really is executable. 268212002Sjh */ 269212002Sjh if ((accmode & VEXEC) && (file_mode & 270212002Sjh (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 && 271212002Sjh !priv_check_cred(cred, PRIV_VFS_EXEC, 0)) 272197405Strasz priv_granted |= VEXEC; 273197405Strasz } 274197405Strasz 275197405Strasz if ((accmode & VREAD) && !priv_check_cred(cred, PRIV_VFS_READ, 0)) 276197405Strasz priv_granted |= VREAD; 277197405Strasz 278197405Strasz if ((accmode & (VWRITE | VAPPEND | VDELETE_CHILD)) && 279197405Strasz !priv_check_cred(cred, PRIV_VFS_WRITE, 0)) 280197405Strasz priv_granted |= (VWRITE | VAPPEND | VDELETE_CHILD); 281197405Strasz 282197405Strasz if ((accmode & VADMIN_PERMS) && 283197405Strasz !priv_check_cred(cred, PRIV_VFS_ADMIN, 0)) 284197405Strasz priv_granted |= VADMIN_PERMS; 285197405Strasz 286197405Strasz if ((accmode & VSTAT_PERMS) && 287197405Strasz !priv_check_cred(cred, PRIV_VFS_STAT, 0)) 288197405Strasz priv_granted |= VSTAT_PERMS; 289197405Strasz 290197405Strasz if ((accmode & priv_granted) == accmode) { 291197405Strasz if (privused != NULL) 292197405Strasz *privused = 1; 293197405Strasz 294197405Strasz return (0); 295197405Strasz } 296197405Strasz 297197405Strasz if (accmode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE)) 298197405Strasz denied = EPERM; 299197405Strasz else 300197405Strasz denied = EACCES; 301197405Strasz 302197405Strasz return (denied); 303197405Strasz} 304197405Strasz#endif /* _KERNEL */ 305197405Strasz 306197405Straszstatic int 307193850Strasz_acl_entry_matches(struct acl_entry *entry, acl_tag_t tag, acl_perm_t perm, 308193850Strasz acl_entry_type_t entry_type) 309193850Strasz{ 310193850Strasz if (entry->ae_tag != tag) 311193850Strasz return (0); 312193850Strasz 313193850Strasz if (entry->ae_id != ACL_UNDEFINED_ID) 314193850Strasz return (0); 315193850Strasz 316193850Strasz if (entry->ae_perm != perm) 317193850Strasz return (0); 318193850Strasz 319193850Strasz if (entry->ae_entry_type != entry_type) 320193850Strasz return (0); 321193850Strasz 322193850Strasz if (entry->ae_flags != 0) 323193850Strasz return (0); 324193850Strasz 325193850Strasz return (1); 326193850Strasz} 327193850Strasz 328193850Straszstatic struct acl_entry * 329193850Strasz_acl_append(struct acl *aclp, acl_tag_t tag, acl_perm_t perm, 330193850Strasz acl_entry_type_t entry_type) 331193850Strasz{ 332193850Strasz struct acl_entry *entry; 333193850Strasz 334193850Strasz KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, 335193850Strasz ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); 336193850Strasz 337193850Strasz entry = &(aclp->acl_entry[aclp->acl_cnt]); 338193850Strasz aclp->acl_cnt++; 339193850Strasz 340193850Strasz entry->ae_tag = tag; 341193850Strasz entry->ae_id = ACL_UNDEFINED_ID; 342193850Strasz entry->ae_perm = perm; 343193850Strasz entry->ae_entry_type = entry_type; 344193850Strasz entry->ae_flags = 0; 345193850Strasz 346193850Strasz return (entry); 347193850Strasz} 348193850Strasz 349193850Straszstatic struct acl_entry * 350193850Strasz_acl_duplicate_entry(struct acl *aclp, int entry_index) 351193850Strasz{ 352193850Strasz int i; 353193850Strasz 354193850Strasz KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, 355193850Strasz ("aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); 356193850Strasz 357193850Strasz for (i = aclp->acl_cnt; i > entry_index; i--) 358193850Strasz aclp->acl_entry[i] = aclp->acl_entry[i - 1]; 359193850Strasz 360193850Strasz aclp->acl_cnt++; 361193850Strasz 362193850Strasz return (&(aclp->acl_entry[entry_index + 1])); 363193850Strasz} 364193850Strasz 365216413Straszstatic void 366216413Straszacl_nfs4_sync_acl_from_mode_draft(struct acl *aclp, mode_t mode, 367216413Strasz int file_owner_id) 368212906Strasz{ 369193850Strasz int i, meets, must_append; 370193850Strasz struct acl_entry *entry, *copy, *previous, 371193850Strasz *a1, *a2, *a3, *a4, *a5, *a6; 372193850Strasz mode_t amode; 373193850Strasz const int READ = 04; 374193850Strasz const int WRITE = 02; 375193850Strasz const int EXEC = 01; 376193850Strasz 377193850Strasz KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES, 378193850Strasz ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); 379193850Strasz 380193850Strasz /* 381193850Strasz * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 382193850Strasz * 383193850Strasz * 3.16.6.3. Applying a Mode to an Existing ACL 384193850Strasz */ 385193850Strasz 386193850Strasz /* 387193850Strasz * 1. For each ACE: 388193850Strasz */ 389193850Strasz for (i = 0; i < aclp->acl_cnt; i++) { 390193850Strasz entry = &(aclp->acl_entry[i]); 391193850Strasz 392193850Strasz /* 393193850Strasz * 1.1. If the type is neither ALLOW or DENY - skip. 394193850Strasz */ 395193850Strasz if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 396193850Strasz entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) 397193850Strasz continue; 398193850Strasz 399193850Strasz /* 400193850Strasz * 1.2. If ACL_ENTRY_INHERIT_ONLY is set - skip. 401193850Strasz */ 402193850Strasz if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) 403193850Strasz continue; 404193850Strasz 405193850Strasz /* 406193850Strasz * 1.3. If ACL_ENTRY_FILE_INHERIT or ACL_ENTRY_DIRECTORY_INHERIT 407193850Strasz * are set: 408193850Strasz */ 409193850Strasz if (entry->ae_flags & 410193850Strasz (ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT)) { 411193850Strasz /* 412193850Strasz * 1.3.1. A copy of the current ACE is made, and placed 413193850Strasz * in the ACL immediately following the current 414193850Strasz * ACE. 415193850Strasz */ 416193850Strasz copy = _acl_duplicate_entry(aclp, i); 417193850Strasz 418193850Strasz /* 419193850Strasz * 1.3.2. In the first ACE, the flag 420193850Strasz * ACL_ENTRY_INHERIT_ONLY is set. 421193850Strasz */ 422193850Strasz entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; 423193850Strasz 424193850Strasz /* 425193850Strasz * 1.3.3. In the second ACE, the following flags 426193850Strasz * are cleared: 427193850Strasz * ACL_ENTRY_FILE_INHERIT, 428193850Strasz * ACL_ENTRY_DIRECTORY_INHERIT, 429193850Strasz * ACL_ENTRY_NO_PROPAGATE_INHERIT. 430193850Strasz */ 431193850Strasz copy->ae_flags &= ~(ACL_ENTRY_FILE_INHERIT | 432193850Strasz ACL_ENTRY_DIRECTORY_INHERIT | 433193850Strasz ACL_ENTRY_NO_PROPAGATE_INHERIT); 434193850Strasz 435193850Strasz /* 436193850Strasz * The algorithm continues on with the second ACE. 437193850Strasz */ 438193850Strasz i++; 439193850Strasz entry = copy; 440193850Strasz } 441193850Strasz 442193850Strasz /* 443193850Strasz * 1.4. If it's owner@, group@ or everyone@ entry, clear 444193850Strasz * ACL_READ_DATA, ACL_WRITE_DATA, ACL_APPEND_DATA 445193850Strasz * and ACL_EXECUTE. Continue to the next entry. 446193850Strasz */ 447193850Strasz if (entry->ae_tag == ACL_USER_OBJ || 448193850Strasz entry->ae_tag == ACL_GROUP_OBJ || 449193850Strasz entry->ae_tag == ACL_EVERYONE) { 450193850Strasz entry->ae_perm &= ~(ACL_READ_DATA | ACL_WRITE_DATA | 451193850Strasz ACL_APPEND_DATA | ACL_EXECUTE); 452193850Strasz continue; 453193850Strasz } 454193850Strasz 455193850Strasz /* 456193850Strasz * 1.5. Otherwise, if the "who" field did not match one 457193850Strasz * of OWNER@, GROUP@, EVERYONE@: 458193850Strasz * 459193850Strasz * 1.5.1. If the type is ALLOW, check the preceding ACE. 460193850Strasz * If it does not meet all of the following criteria: 461193850Strasz */ 462193850Strasz if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW) 463193850Strasz continue; 464193850Strasz 465193850Strasz meets = 0; 466193850Strasz if (i > 0) { 467193850Strasz meets = 1; 468193850Strasz previous = &(aclp->acl_entry[i - 1]); 469193850Strasz 470193850Strasz /* 471193850Strasz * 1.5.1.1. The type field is DENY, 472193850Strasz */ 473193850Strasz if (previous->ae_entry_type != ACL_ENTRY_TYPE_DENY) 474193850Strasz meets = 0; 475193850Strasz 476193850Strasz /* 477193850Strasz * 1.5.1.2. The "who" field is the same as the current 478193850Strasz * ACE, 479193850Strasz * 480193850Strasz * 1.5.1.3. The flag bit ACE4_IDENTIFIER_GROUP 481193850Strasz * is the same as it is in the current ACE, 482193850Strasz * and no other flag bits are set, 483193850Strasz */ 484193850Strasz if (previous->ae_id != entry->ae_id || 485193850Strasz previous->ae_tag != entry->ae_tag) 486193850Strasz meets = 0; 487193850Strasz 488193850Strasz if (previous->ae_flags) 489193850Strasz meets = 0; 490193850Strasz 491193850Strasz /* 492193850Strasz * 1.5.1.4. The mask bits are a subset of the mask bits 493193850Strasz * of the current ACE, and are also subset of 494193850Strasz * the following: ACL_READ_DATA, 495193850Strasz * ACL_WRITE_DATA, ACL_APPEND_DATA, ACL_EXECUTE 496193850Strasz */ 497193850Strasz if (previous->ae_perm & ~(entry->ae_perm)) 498193850Strasz meets = 0; 499193850Strasz 500193850Strasz if (previous->ae_perm & ~(ACL_READ_DATA | 501193850Strasz ACL_WRITE_DATA | ACL_APPEND_DATA | ACL_EXECUTE)) 502193850Strasz meets = 0; 503193850Strasz } 504193850Strasz 505193850Strasz if (!meets) { 506193850Strasz /* 507193850Strasz * Then the ACE of type DENY, with a who equal 508193850Strasz * to the current ACE, flag bits equal to 509193850Strasz * (<current ACE flags> & <ACE_IDENTIFIER_GROUP>) 510193850Strasz * and no mask bits, is prepended. 511193850Strasz */ 512193850Strasz previous = entry; 513193850Strasz entry = _acl_duplicate_entry(aclp, i); 514193850Strasz 515193850Strasz /* Adjust counter, as we've just added an entry. */ 516193850Strasz i++; 517193850Strasz 518193850Strasz previous->ae_tag = entry->ae_tag; 519193850Strasz previous->ae_id = entry->ae_id; 520193850Strasz previous->ae_flags = entry->ae_flags; 521193850Strasz previous->ae_perm = 0; 522193850Strasz previous->ae_entry_type = ACL_ENTRY_TYPE_DENY; 523193850Strasz } 524193850Strasz 525193850Strasz /* 526193850Strasz * 1.5.2. The following modifications are made to the prepended 527193850Strasz * ACE. The intent is to mask the following ACE 528193850Strasz * to disallow ACL_READ_DATA, ACL_WRITE_DATA, 529193850Strasz * ACL_APPEND_DATA, or ACL_EXECUTE, based upon the group 530193850Strasz * permissions of the new mode. As a special case, 531193850Strasz * if the ACE matches the current owner of the file, 532193850Strasz * the owner bits are used, rather than the group bits. 533193850Strasz * This is reflected in the algorithm below. 534193850Strasz */ 535193850Strasz amode = mode >> 3; 536193850Strasz 537193850Strasz /* 538193850Strasz * If ACE4_IDENTIFIER_GROUP is not set, and the "who" field 539193850Strasz * in ACE matches the owner of the file, we shift amode three 540193850Strasz * more bits, in order to have the owner permission bits 541193850Strasz * placed in the three low order bits of amode. 542193850Strasz */ 543193850Strasz if (entry->ae_tag == ACL_USER && entry->ae_id == file_owner_id) 544193850Strasz amode = amode >> 3; 545193850Strasz 546193850Strasz if (entry->ae_perm & ACL_READ_DATA) { 547193850Strasz if (amode & READ) 548193850Strasz previous->ae_perm &= ~ACL_READ_DATA; 549193850Strasz else 550193850Strasz previous->ae_perm |= ACL_READ_DATA; 551193850Strasz } 552193850Strasz 553193850Strasz if (entry->ae_perm & ACL_WRITE_DATA) { 554193850Strasz if (amode & WRITE) 555193850Strasz previous->ae_perm &= ~ACL_WRITE_DATA; 556193850Strasz else 557193850Strasz previous->ae_perm |= ACL_WRITE_DATA; 558193850Strasz } 559193850Strasz 560193850Strasz if (entry->ae_perm & ACL_APPEND_DATA) { 561193850Strasz if (amode & WRITE) 562193850Strasz previous->ae_perm &= ~ACL_APPEND_DATA; 563193850Strasz else 564193850Strasz previous->ae_perm |= ACL_APPEND_DATA; 565193850Strasz } 566193850Strasz 567193850Strasz if (entry->ae_perm & ACL_EXECUTE) { 568193850Strasz if (amode & EXEC) 569193850Strasz previous->ae_perm &= ~ACL_EXECUTE; 570193850Strasz else 571193850Strasz previous->ae_perm |= ACL_EXECUTE; 572193850Strasz } 573193850Strasz 574193850Strasz /* 575193850Strasz * 1.5.3. If ACE4_IDENTIFIER_GROUP is set in the flags 576193850Strasz * of the ALLOW ace: 577193850Strasz * 578193850Strasz * XXX: This point is not there in the Falkner's draft. 579193850Strasz */ 580193850Strasz if (entry->ae_tag == ACL_GROUP && 581193850Strasz entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) { 582193850Strasz mode_t extramode, ownermode; 583193850Strasz extramode = (mode >> 3) & 07; 584193850Strasz ownermode = mode >> 6; 585193850Strasz extramode &= ~ownermode; 586193850Strasz 587193850Strasz if (extramode) { 588193850Strasz if (extramode & READ) { 589193850Strasz entry->ae_perm &= ~ACL_READ_DATA; 590193850Strasz previous->ae_perm &= ~ACL_READ_DATA; 591193850Strasz } 592193850Strasz 593193850Strasz if (extramode & WRITE) { 594193850Strasz entry->ae_perm &= 595193850Strasz ~(ACL_WRITE_DATA | ACL_APPEND_DATA); 596193850Strasz previous->ae_perm &= 597193850Strasz ~(ACL_WRITE_DATA | ACL_APPEND_DATA); 598193850Strasz } 599193850Strasz 600193850Strasz if (extramode & EXEC) { 601193850Strasz entry->ae_perm &= ~ACL_EXECUTE; 602193850Strasz previous->ae_perm &= ~ACL_EXECUTE; 603193850Strasz } 604193850Strasz } 605193850Strasz } 606193850Strasz } 607193850Strasz 608193850Strasz /* 609193850Strasz * 2. If there at least six ACEs, the final six ACEs are examined. 610193850Strasz * If they are not equal to what we want, append six ACEs. 611193850Strasz */ 612193850Strasz must_append = 0; 613193850Strasz if (aclp->acl_cnt < 6) { 614193850Strasz must_append = 1; 615193850Strasz } else { 616193850Strasz a6 = &(aclp->acl_entry[aclp->acl_cnt - 1]); 617193850Strasz a5 = &(aclp->acl_entry[aclp->acl_cnt - 2]); 618193850Strasz a4 = &(aclp->acl_entry[aclp->acl_cnt - 3]); 619193850Strasz a3 = &(aclp->acl_entry[aclp->acl_cnt - 4]); 620193850Strasz a2 = &(aclp->acl_entry[aclp->acl_cnt - 5]); 621193850Strasz a1 = &(aclp->acl_entry[aclp->acl_cnt - 6]); 622193850Strasz 623193850Strasz if (!_acl_entry_matches(a1, ACL_USER_OBJ, 0, 624193850Strasz ACL_ENTRY_TYPE_DENY)) 625193850Strasz must_append = 1; 626193850Strasz if (!_acl_entry_matches(a2, ACL_USER_OBJ, ACL_WRITE_ACL | 627193850Strasz ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 628193850Strasz ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW)) 629193850Strasz must_append = 1; 630193850Strasz if (!_acl_entry_matches(a3, ACL_GROUP_OBJ, 0, 631193850Strasz ACL_ENTRY_TYPE_DENY)) 632193850Strasz must_append = 1; 633193850Strasz if (!_acl_entry_matches(a4, ACL_GROUP_OBJ, 0, 634193850Strasz ACL_ENTRY_TYPE_ALLOW)) 635193850Strasz must_append = 1; 636193850Strasz if (!_acl_entry_matches(a5, ACL_EVERYONE, ACL_WRITE_ACL | 637193850Strasz ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 638193850Strasz ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY)) 639193850Strasz must_append = 1; 640193850Strasz if (!_acl_entry_matches(a6, ACL_EVERYONE, ACL_READ_ACL | 641193850Strasz ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | 642193850Strasz ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW)) 643193850Strasz must_append = 1; 644193850Strasz } 645193850Strasz 646193850Strasz if (must_append) { 647193850Strasz KASSERT(aclp->acl_cnt + 6 <= ACL_MAX_ENTRIES, 648193850Strasz ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); 649193850Strasz 650193850Strasz a1 = _acl_append(aclp, ACL_USER_OBJ, 0, ACL_ENTRY_TYPE_DENY); 651193850Strasz a2 = _acl_append(aclp, ACL_USER_OBJ, ACL_WRITE_ACL | 652193850Strasz ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 653193850Strasz ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_ALLOW); 654193850Strasz a3 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_DENY); 655193850Strasz a4 = _acl_append(aclp, ACL_GROUP_OBJ, 0, ACL_ENTRY_TYPE_ALLOW); 656193850Strasz a5 = _acl_append(aclp, ACL_EVERYONE, ACL_WRITE_ACL | 657193850Strasz ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 658193850Strasz ACL_WRITE_NAMED_ATTRS, ACL_ENTRY_TYPE_DENY); 659193850Strasz a6 = _acl_append(aclp, ACL_EVERYONE, ACL_READ_ACL | 660193850Strasz ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | 661193850Strasz ACL_SYNCHRONIZE, ACL_ENTRY_TYPE_ALLOW); 662193850Strasz 663193850Strasz KASSERT(a1 != NULL && a2 != NULL && a3 != NULL && a4 != NULL && 664193850Strasz a5 != NULL && a6 != NULL, ("couldn't append to ACL.")); 665193850Strasz } 666193850Strasz 667193850Strasz /* 668193850Strasz * 3. The final six ACEs are adjusted according to the incoming mode. 669193850Strasz */ 670193850Strasz if (mode & S_IRUSR) 671193850Strasz a2->ae_perm |= ACL_READ_DATA; 672193850Strasz else 673193850Strasz a1->ae_perm |= ACL_READ_DATA; 674193850Strasz if (mode & S_IWUSR) 675193850Strasz a2->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 676193850Strasz else 677193850Strasz a1->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 678193850Strasz if (mode & S_IXUSR) 679193850Strasz a2->ae_perm |= ACL_EXECUTE; 680193850Strasz else 681193850Strasz a1->ae_perm |= ACL_EXECUTE; 682193850Strasz 683193850Strasz if (mode & S_IRGRP) 684193850Strasz a4->ae_perm |= ACL_READ_DATA; 685193850Strasz else 686193850Strasz a3->ae_perm |= ACL_READ_DATA; 687193850Strasz if (mode & S_IWGRP) 688193850Strasz a4->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 689193850Strasz else 690193850Strasz a3->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 691193850Strasz if (mode & S_IXGRP) 692193850Strasz a4->ae_perm |= ACL_EXECUTE; 693193850Strasz else 694193850Strasz a3->ae_perm |= ACL_EXECUTE; 695193850Strasz 696193850Strasz if (mode & S_IROTH) 697193850Strasz a6->ae_perm |= ACL_READ_DATA; 698193850Strasz else 699193850Strasz a5->ae_perm |= ACL_READ_DATA; 700193850Strasz if (mode & S_IWOTH) 701193850Strasz a6->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 702193850Strasz else 703193850Strasz a5->ae_perm |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 704193850Strasz if (mode & S_IXOTH) 705193850Strasz a6->ae_perm |= ACL_EXECUTE; 706193850Strasz else 707193850Strasz a5->ae_perm |= ACL_EXECUTE; 708193850Strasz} 709193850Strasz 710219878Strasz#ifdef _KERNEL 711193850Straszvoid 712216413Straszacl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, 713216413Strasz int file_owner_id) 714216413Strasz{ 715216413Strasz 716216413Strasz if (acl_nfs4_old_semantics) 717216413Strasz acl_nfs4_sync_acl_from_mode_draft(aclp, mode, file_owner_id); 718216413Strasz else 719216413Strasz acl_nfs4_trivial_from_mode(aclp, mode); 720216413Strasz} 721219878Strasz#endif /* _KERNEL */ 722216413Strasz 723216413Straszvoid 724193850Straszacl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp) 725193850Strasz{ 726193850Strasz int i; 727193850Strasz mode_t old_mode = *_mode, mode = 0, seen = 0; 728193850Strasz const struct acl_entry *entry; 729193850Strasz 730193850Strasz KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES, 731193850Strasz ("aclp->acl_cnt <= ACL_MAX_ENTRIES")); 732193850Strasz 733193850Strasz /* 734193850Strasz * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 735193850Strasz * 736193850Strasz * 3.16.6.1. Recomputing mode upon SETATTR of ACL 737193850Strasz */ 738193850Strasz 739193850Strasz for (i = 0; i < aclp->acl_cnt; i++) { 740193850Strasz entry = &(aclp->acl_entry[i]); 741193850Strasz 742193850Strasz if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 743193850Strasz entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) 744193850Strasz continue; 745193850Strasz 746193850Strasz if (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) 747193850Strasz continue; 748193850Strasz 749193850Strasz if (entry->ae_tag == ACL_USER_OBJ) { 750193850Strasz if ((entry->ae_perm & ACL_READ_DATA) && 751193850Strasz ((seen & S_IRUSR) == 0)) { 752193850Strasz seen |= S_IRUSR; 753193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 754193850Strasz mode |= S_IRUSR; 755193850Strasz } 756193850Strasz if ((entry->ae_perm & ACL_WRITE_DATA) && 757193850Strasz ((seen & S_IWUSR) == 0)) { 758193850Strasz seen |= S_IWUSR; 759193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 760193850Strasz mode |= S_IWUSR; 761193850Strasz } 762193850Strasz if ((entry->ae_perm & ACL_EXECUTE) && 763193850Strasz ((seen & S_IXUSR) == 0)) { 764193850Strasz seen |= S_IXUSR; 765193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 766193850Strasz mode |= S_IXUSR; 767193850Strasz } 768193850Strasz } else if (entry->ae_tag == ACL_GROUP_OBJ) { 769193850Strasz if ((entry->ae_perm & ACL_READ_DATA) && 770193850Strasz ((seen & S_IRGRP) == 0)) { 771193850Strasz seen |= S_IRGRP; 772193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 773193850Strasz mode |= S_IRGRP; 774193850Strasz } 775193850Strasz if ((entry->ae_perm & ACL_WRITE_DATA) && 776193850Strasz ((seen & S_IWGRP) == 0)) { 777193850Strasz seen |= S_IWGRP; 778193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 779193850Strasz mode |= S_IWGRP; 780193850Strasz } 781193850Strasz if ((entry->ae_perm & ACL_EXECUTE) && 782193850Strasz ((seen & S_IXGRP) == 0)) { 783193850Strasz seen |= S_IXGRP; 784193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 785193850Strasz mode |= S_IXGRP; 786193850Strasz } 787193850Strasz } else if (entry->ae_tag == ACL_EVERYONE) { 788193850Strasz if (entry->ae_perm & ACL_READ_DATA) { 789193850Strasz if ((seen & S_IRUSR) == 0) { 790193850Strasz seen |= S_IRUSR; 791193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 792193850Strasz mode |= S_IRUSR; 793193850Strasz } 794193850Strasz if ((seen & S_IRGRP) == 0) { 795193850Strasz seen |= S_IRGRP; 796193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 797193850Strasz mode |= S_IRGRP; 798193850Strasz } 799193850Strasz if ((seen & S_IROTH) == 0) { 800193850Strasz seen |= S_IROTH; 801193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 802193850Strasz mode |= S_IROTH; 803193850Strasz } 804193850Strasz } 805193850Strasz if (entry->ae_perm & ACL_WRITE_DATA) { 806193850Strasz if ((seen & S_IWUSR) == 0) { 807193850Strasz seen |= S_IWUSR; 808193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 809193850Strasz mode |= S_IWUSR; 810193850Strasz } 811193850Strasz if ((seen & S_IWGRP) == 0) { 812193850Strasz seen |= S_IWGRP; 813193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 814193850Strasz mode |= S_IWGRP; 815193850Strasz } 816193850Strasz if ((seen & S_IWOTH) == 0) { 817193850Strasz seen |= S_IWOTH; 818193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 819193850Strasz mode |= S_IWOTH; 820193850Strasz } 821193850Strasz } 822193850Strasz if (entry->ae_perm & ACL_EXECUTE) { 823193850Strasz if ((seen & S_IXUSR) == 0) { 824193850Strasz seen |= S_IXUSR; 825193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 826193850Strasz mode |= S_IXUSR; 827193850Strasz } 828193850Strasz if ((seen & S_IXGRP) == 0) { 829193850Strasz seen |= S_IXGRP; 830193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 831193850Strasz mode |= S_IXGRP; 832193850Strasz } 833193850Strasz if ((seen & S_IXOTH) == 0) { 834193850Strasz seen |= S_IXOTH; 835193850Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 836193850Strasz mode |= S_IXOTH; 837193850Strasz } 838193850Strasz } 839193850Strasz } 840193850Strasz } 841193850Strasz 842193850Strasz *_mode = mode | (old_mode & ACL_PRESERVE_MASK); 843193850Strasz} 844197405Strasz 845219878Strasz#ifdef _KERNEL 846216413Strasz/* 847216413Strasz * Calculate inherited ACL in a manner compatible with NFSv4 Minor Version 1, 848216413Strasz * draft-ietf-nfsv4-minorversion1-03.txt. 849216413Strasz */ 850216413Straszstatic void 851216413Straszacl_nfs4_compute_inherited_acl_draft(const struct acl *parent_aclp, 852197405Strasz struct acl *child_aclp, mode_t mode, int file_owner_id, 853197405Strasz int is_directory) 854197405Strasz{ 855197405Strasz int i, flags; 856197405Strasz const struct acl_entry *parent_entry; 857197405Strasz struct acl_entry *entry, *copy; 858197405Strasz 859197405Strasz KASSERT(child_aclp->acl_cnt == 0, ("child_aclp->acl_cnt == 0")); 860197405Strasz KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES, 861197405Strasz ("parent_aclp->acl_cnt <= ACL_MAX_ENTRIES")); 862197405Strasz 863197405Strasz /* 864197405Strasz * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 865197405Strasz * 866197405Strasz * 3.16.6.2. Applying the mode given to CREATE or OPEN 867197405Strasz * to an inherited ACL 868197405Strasz */ 869197405Strasz 870197405Strasz /* 871197405Strasz * 1. Form an ACL that is the concatenation of all inheritable ACEs. 872197405Strasz */ 873197405Strasz for (i = 0; i < parent_aclp->acl_cnt; i++) { 874197405Strasz parent_entry = &(parent_aclp->acl_entry[i]); 875197405Strasz flags = parent_entry->ae_flags; 876197405Strasz 877197405Strasz /* 878197405Strasz * Entry is not inheritable at all. 879197405Strasz */ 880197405Strasz if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT | 881197405Strasz ACL_ENTRY_FILE_INHERIT)) == 0) 882197405Strasz continue; 883197405Strasz 884197405Strasz /* 885197405Strasz * We're creating a file, but entry is not inheritable 886197405Strasz * by files. 887197405Strasz */ 888197405Strasz if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0) 889197405Strasz continue; 890197405Strasz 891197405Strasz /* 892197405Strasz * Entry is inheritable only by files, but has NO_PROPAGATE 893197405Strasz * flag set, and we're creating a directory, so it wouldn't 894197405Strasz * propagate to any file in that directory anyway. 895197405Strasz */ 896197405Strasz if (is_directory && 897197405Strasz (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 && 898197405Strasz (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)) 899197405Strasz continue; 900197405Strasz 901197405Strasz KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, 902197405Strasz ("child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); 903197405Strasz child_aclp->acl_entry[child_aclp->acl_cnt] = *parent_entry; 904197405Strasz child_aclp->acl_cnt++; 905197405Strasz } 906197405Strasz 907197405Strasz /* 908197405Strasz * 2. For each entry in the new ACL, adjust its flags, possibly 909197405Strasz * creating two entries in place of one. 910197405Strasz */ 911197405Strasz for (i = 0; i < child_aclp->acl_cnt; i++) { 912197405Strasz entry = &(child_aclp->acl_entry[i]); 913197405Strasz 914197405Strasz /* 915197405Strasz * This is not in the specification, but SunOS 916197405Strasz * apparently does that. 917197405Strasz */ 918197405Strasz if (((entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT) || 919197405Strasz !is_directory) && 920197405Strasz entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 921197405Strasz entry->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER); 922197405Strasz 923197405Strasz /* 924197405Strasz * 2.A. If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if the object 925197405Strasz * being created is not a directory, then clear the 926197405Strasz * following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT, 927197405Strasz * ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT, 928197405Strasz * ACL_ENTRY_INHERIT_ONLY. 929197405Strasz */ 930197405Strasz if (entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT || 931197405Strasz !is_directory) { 932197405Strasz entry->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT | 933197405Strasz ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | 934197405Strasz ACL_ENTRY_INHERIT_ONLY); 935197405Strasz 936197405Strasz /* 937197405Strasz * Continue on to the next ACE. 938197405Strasz */ 939197405Strasz continue; 940197405Strasz } 941197405Strasz 942197405Strasz /* 943197405Strasz * 2.B. If the object is a directory and ACL_ENTRY_FILE_INHERIT 944197405Strasz * is set, but ACL_ENTRY_NO_PROPAGATE_INHERIT is not set, ensure 945197405Strasz * that ACL_ENTRY_INHERIT_ONLY is set. Continue to the 946197405Strasz * next ACE. Otherwise... 947197405Strasz */ 948197405Strasz /* 949197405Strasz * XXX: Read it again and make sure what does the "otherwise" 950197405Strasz * apply to. 951197405Strasz */ 952197405Strasz if (is_directory && 953197405Strasz (entry->ae_flags & ACL_ENTRY_FILE_INHERIT) && 954197405Strasz ((entry->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) { 955197405Strasz entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; 956197405Strasz continue; 957197405Strasz } 958197405Strasz 959197405Strasz /* 960197405Strasz * 2.C. If the type of the ACE is neither ALLOW nor deny, 961197405Strasz * then continue. 962197405Strasz */ 963197405Strasz if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 964197405Strasz entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) 965197405Strasz continue; 966197405Strasz 967197405Strasz /* 968197405Strasz * 2.D. Copy the original ACE into a second, adjacent ACE. 969197405Strasz */ 970197405Strasz copy = _acl_duplicate_entry(child_aclp, i); 971197405Strasz 972197405Strasz /* 973197405Strasz * 2.E. On the first ACE, ensure that ACL_ENTRY_INHERIT_ONLY 974197405Strasz * is set. 975197405Strasz */ 976197405Strasz entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; 977197405Strasz 978197405Strasz /* 979197405Strasz * 2.F. On the second ACE, clear the following flags: 980197405Strasz * ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_FILE_INHERIT, 981197405Strasz * ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_INHERIT_ONLY. 982197405Strasz */ 983197405Strasz copy->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT | 984197405Strasz ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | 985197405Strasz ACL_ENTRY_INHERIT_ONLY); 986197405Strasz 987197405Strasz /* 988197405Strasz * 2.G. On the second ACE, if the type is ALLOW, 989197405Strasz * an implementation MAY clear the following 990197405Strasz * mask bits: ACL_WRITE_ACL, ACL_WRITE_OWNER. 991197405Strasz */ 992197405Strasz if (copy->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 993197405Strasz copy->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER); 994197405Strasz 995197405Strasz /* 996197405Strasz * Increment the counter to skip the copied entry. 997197405Strasz */ 998197405Strasz i++; 999197405Strasz } 1000197405Strasz 1001197405Strasz /* 1002197405Strasz * 3. To ensure that the mode is honored, apply the algorithm describe 1003197405Strasz * in Section 2.16.6.3, using the mode that is to be used for file 1004197405Strasz * creation. 1005197405Strasz */ 1006197405Strasz acl_nfs4_sync_acl_from_mode(child_aclp, mode, file_owner_id); 1007197405Strasz} 1008219878Strasz#endif /* _KERNEL */ 1009197405Strasz 1010216413Strasz/* 1011216413Strasz * Populate the ACL with entries inherited from parent_aclp. 1012216413Strasz */ 1013216413Straszstatic void 1014216413Straszacl_nfs4_inherit_entries(const struct acl *parent_aclp, 1015216413Strasz struct acl *child_aclp, mode_t mode, int file_owner_id, 1016216413Strasz int is_directory) 1017216413Strasz{ 1018216413Strasz int i, flags, tag; 1019216413Strasz const struct acl_entry *parent_entry; 1020216413Strasz struct acl_entry *entry; 1021216413Strasz 1022216413Strasz KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES, 1023216413Strasz ("parent_aclp->acl_cnt <= ACL_MAX_ENTRIES")); 1024216413Strasz 1025216413Strasz for (i = 0; i < parent_aclp->acl_cnt; i++) { 1026216413Strasz parent_entry = &(parent_aclp->acl_entry[i]); 1027216413Strasz flags = parent_entry->ae_flags; 1028216413Strasz tag = parent_entry->ae_tag; 1029216413Strasz 1030216413Strasz /* 1031216413Strasz * Don't inherit owner@, group@, or everyone@ entries. 1032216413Strasz */ 1033216413Strasz if (tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || 1034216413Strasz tag == ACL_EVERYONE) 1035216413Strasz continue; 1036216413Strasz 1037216413Strasz /* 1038216413Strasz * Entry is not inheritable at all. 1039216413Strasz */ 1040216413Strasz if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT | 1041216413Strasz ACL_ENTRY_FILE_INHERIT)) == 0) 1042216413Strasz continue; 1043216413Strasz 1044216413Strasz /* 1045216413Strasz * We're creating a file, but entry is not inheritable 1046216413Strasz * by files. 1047216413Strasz */ 1048216413Strasz if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0) 1049216413Strasz continue; 1050216413Strasz 1051216413Strasz /* 1052216413Strasz * Entry is inheritable only by files, but has NO_PROPAGATE 1053216413Strasz * flag set, and we're creating a directory, so it wouldn't 1054216413Strasz * propagate to any file in that directory anyway. 1055216413Strasz */ 1056216413Strasz if (is_directory && 1057216413Strasz (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 && 1058216413Strasz (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)) 1059216413Strasz continue; 1060216413Strasz 1061216413Strasz /* 1062216413Strasz * Entry qualifies for being inherited. 1063216413Strasz */ 1064216413Strasz KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES, 1065216413Strasz ("child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES")); 1066216413Strasz entry = &(child_aclp->acl_entry[child_aclp->acl_cnt]); 1067216413Strasz *entry = *parent_entry; 1068216413Strasz child_aclp->acl_cnt++; 1069216413Strasz 1070216413Strasz entry->ae_flags &= ~ACL_ENTRY_INHERIT_ONLY; 1071290893Sngie entry->ae_flags |= ACL_ENTRY_INHERITED; 1072216413Strasz 1073216413Strasz /* 1074216413Strasz * If the type of the ACE is neither ALLOW nor DENY, 1075216413Strasz * then leave it as it is and proceed to the next one. 1076216413Strasz */ 1077216413Strasz if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 1078216413Strasz entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) 1079216413Strasz continue; 1080216413Strasz 1081216413Strasz /* 1082216413Strasz * If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if 1083216413Strasz * the object being created is not a directory, then clear 1084216413Strasz * the following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT, 1085216413Strasz * ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT, 1086216413Strasz * ACL_ENTRY_INHERIT_ONLY. 1087216413Strasz */ 1088216413Strasz if (entry->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT || 1089216413Strasz !is_directory) { 1090216413Strasz entry->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT | 1091216413Strasz ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | 1092216413Strasz ACL_ENTRY_INHERIT_ONLY); 1093216413Strasz } 1094216413Strasz 1095216413Strasz /* 1096216413Strasz * If the object is a directory and ACL_ENTRY_FILE_INHERIT 1097216413Strasz * is set, but ACL_ENTRY_DIRECTORY_INHERIT is not set, ensure 1098216413Strasz * that ACL_ENTRY_INHERIT_ONLY is set. 1099216413Strasz */ 1100216413Strasz if (is_directory && 1101216413Strasz (entry->ae_flags & ACL_ENTRY_FILE_INHERIT) && 1102216413Strasz ((entry->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) { 1103216413Strasz entry->ae_flags |= ACL_ENTRY_INHERIT_ONLY; 1104216413Strasz } 1105216413Strasz 1106216413Strasz if (entry->ae_entry_type == ACL_ENTRY_TYPE_ALLOW && 1107216413Strasz (entry->ae_flags & ACL_ENTRY_INHERIT_ONLY) == 0) { 1108216413Strasz /* 1109216413Strasz * Some permissions must never be inherited. 1110216413Strasz */ 1111216413Strasz entry->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER | 1112216413Strasz ACL_WRITE_NAMED_ATTRS | ACL_WRITE_ATTRIBUTES); 1113216413Strasz 1114216413Strasz /* 1115216413Strasz * Others must be masked according to the file mode. 1116216413Strasz */ 1117216413Strasz if ((mode & S_IRGRP) == 0) 1118216413Strasz entry->ae_perm &= ~ACL_READ_DATA; 1119216413Strasz if ((mode & S_IWGRP) == 0) 1120216413Strasz entry->ae_perm &= 1121216413Strasz ~(ACL_WRITE_DATA | ACL_APPEND_DATA); 1122216413Strasz if ((mode & S_IXGRP) == 0) 1123216413Strasz entry->ae_perm &= ~ACL_EXECUTE; 1124216413Strasz } 1125216413Strasz } 1126216413Strasz} 1127216413Strasz 1128216413Strasz/* 1129216413Strasz * Calculate inherited ACL in a manner compatible with PSARC/2010/029. 1130216413Strasz * It's also being used to calculate a trivial ACL, by inheriting from 1131216413Strasz * a NULL ACL. 1132216413Strasz */ 1133216413Straszstatic void 1134216413Straszacl_nfs4_compute_inherited_acl_psarc(const struct acl *parent_aclp, 1135216413Strasz struct acl *aclp, mode_t mode, int file_owner_id, int is_directory) 1136216413Strasz{ 1137216413Strasz acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0; 1138216413Strasz acl_perm_t user_allow, group_allow, everyone_allow; 1139216413Strasz 1140216413Strasz KASSERT(aclp->acl_cnt == 0, ("aclp->acl_cnt == 0")); 1141216413Strasz 1142216413Strasz user_allow = group_allow = everyone_allow = ACL_READ_ACL | 1143216413Strasz ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE; 1144216413Strasz user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 1145216413Strasz ACL_WRITE_NAMED_ATTRS; 1146216413Strasz 1147216413Strasz if (mode & S_IRUSR) 1148216413Strasz user_allow |= ACL_READ_DATA; 1149216413Strasz if (mode & S_IWUSR) 1150216413Strasz user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 1151216413Strasz if (mode & S_IXUSR) 1152216413Strasz user_allow |= ACL_EXECUTE; 1153216413Strasz 1154216413Strasz if (mode & S_IRGRP) 1155216413Strasz group_allow |= ACL_READ_DATA; 1156216413Strasz if (mode & S_IWGRP) 1157216413Strasz group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 1158216413Strasz if (mode & S_IXGRP) 1159216413Strasz group_allow |= ACL_EXECUTE; 1160216413Strasz 1161216413Strasz if (mode & S_IROTH) 1162216413Strasz everyone_allow |= ACL_READ_DATA; 1163216413Strasz if (mode & S_IWOTH) 1164216413Strasz everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 1165216413Strasz if (mode & S_IXOTH) 1166216413Strasz everyone_allow |= ACL_EXECUTE; 1167216413Strasz 1168216413Strasz user_deny = ((group_allow | everyone_allow) & ~user_allow); 1169216413Strasz group_deny = everyone_allow & ~group_allow; 1170216413Strasz user_allow_first = group_deny & ~user_deny; 1171216413Strasz 1172216413Strasz if (user_allow_first != 0) 1173216413Strasz _acl_append(aclp, ACL_USER_OBJ, user_allow_first, 1174216413Strasz ACL_ENTRY_TYPE_ALLOW); 1175216413Strasz if (user_deny != 0) 1176216413Strasz _acl_append(aclp, ACL_USER_OBJ, user_deny, 1177216413Strasz ACL_ENTRY_TYPE_DENY); 1178216413Strasz if (group_deny != 0) 1179216413Strasz _acl_append(aclp, ACL_GROUP_OBJ, group_deny, 1180216413Strasz ACL_ENTRY_TYPE_DENY); 1181216413Strasz 1182216413Strasz if (parent_aclp != NULL) 1183216413Strasz acl_nfs4_inherit_entries(parent_aclp, aclp, mode, 1184216413Strasz file_owner_id, is_directory); 1185216413Strasz 1186216413Strasz _acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW); 1187216413Strasz _acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW); 1188216413Strasz _acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW); 1189216413Strasz} 1190216413Strasz 1191219878Strasz#ifdef _KERNEL 1192216413Straszvoid 1193216413Straszacl_nfs4_compute_inherited_acl(const struct acl *parent_aclp, 1194216413Strasz struct acl *child_aclp, mode_t mode, int file_owner_id, 1195216413Strasz int is_directory) 1196216413Strasz{ 1197216413Strasz 1198216413Strasz if (acl_nfs4_old_semantics) 1199216413Strasz acl_nfs4_compute_inherited_acl_draft(parent_aclp, child_aclp, 1200216413Strasz mode, file_owner_id, is_directory); 1201216413Strasz else 1202216413Strasz acl_nfs4_compute_inherited_acl_psarc(parent_aclp, child_aclp, 1203216413Strasz mode, file_owner_id, is_directory); 1204216413Strasz} 1205219878Strasz#endif /* _KERNEL */ 1206216413Strasz 1207216413Strasz/* 1208216413Strasz * Calculate trivial ACL in a manner compatible with PSARC/2010/029. 1209216413Strasz * Note that this results in an ACL different from (but semantically 1210216413Strasz * equal to) the "canonical six" trivial ACL computed using algorithm 1211216413Strasz * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2. 1212216413Strasz */ 1213219878Straszstatic void 1214216413Straszacl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode) 1215216413Strasz{ 1216216413Strasz 1217216413Strasz aclp->acl_cnt = 0; 1218216413Strasz acl_nfs4_compute_inherited_acl_psarc(NULL, aclp, mode, -1, -1); 1219216413Strasz} 1220216413Strasz 1221219878Strasz#ifndef _KERNEL 1222219878Strasz/* 1223219878Strasz * This routine is used by libc to implement acl_strip_np(3) 1224219878Strasz * and acl_is_trivial_np(3). 1225219878Strasz */ 1226219878Straszvoid 1227219878Straszacl_nfs4_trivial_from_mode_libc(struct acl *aclp, int mode, int canonical_six) 1228219878Strasz{ 1229219878Strasz 1230219878Strasz aclp->acl_cnt = 0; 1231219878Strasz if (canonical_six) 1232219878Strasz acl_nfs4_sync_acl_from_mode_draft(aclp, mode, -1); 1233219878Strasz else 1234219878Strasz acl_nfs4_trivial_from_mode(aclp, mode); 1235219878Strasz} 1236219878Strasz#endif /* !_KERNEL */ 1237219878Strasz 1238197405Strasz#ifdef _KERNEL 1239197405Straszstatic int 1240197405Strasz_acls_are_equal(const struct acl *a, const struct acl *b) 1241197405Strasz{ 1242197405Strasz int i; 1243197405Strasz const struct acl_entry *entrya, *entryb; 1244197405Strasz 1245197405Strasz if (a->acl_cnt != b->acl_cnt) 1246197405Strasz return (0); 1247197405Strasz 1248197405Strasz for (i = 0; i < b->acl_cnt; i++) { 1249197405Strasz entrya = &(a->acl_entry[i]); 1250197405Strasz entryb = &(b->acl_entry[i]); 1251197405Strasz 1252197405Strasz if (entrya->ae_tag != entryb->ae_tag || 1253197405Strasz entrya->ae_id != entryb->ae_id || 1254197405Strasz entrya->ae_perm != entryb->ae_perm || 1255197405Strasz entrya->ae_entry_type != entryb->ae_entry_type || 1256197405Strasz entrya->ae_flags != entryb->ae_flags) 1257197405Strasz return (0); 1258197405Strasz } 1259197405Strasz 1260197405Strasz return (1); 1261197405Strasz} 1262197405Strasz 1263197405Strasz/* 1264201495Strasz * This routine is used to determine whether to remove extended attribute 1265197405Strasz * that stores ACL contents. 1266197405Strasz */ 1267197405Straszint 1268197405Straszacl_nfs4_is_trivial(const struct acl *aclp, int file_owner_id) 1269197405Strasz{ 1270197405Strasz int trivial; 1271197405Strasz mode_t tmpmode = 0; 1272197405Strasz struct acl *tmpaclp; 1273197405Strasz 1274216413Strasz if (aclp->acl_cnt > 6) 1275197405Strasz return (0); 1276197405Strasz 1277197405Strasz /* 1278197405Strasz * Compute the mode from the ACL, then compute new ACL from that mode. 1279197405Strasz * If the ACLs are identical, then the ACL is trivial. 1280197405Strasz * 1281197405Strasz * XXX: I guess there is a faster way to do this. However, even 1282197405Strasz * this slow implementation significantly speeds things up 1283201495Strasz * for files that don't have non-trivial ACLs - it's critical 1284201495Strasz * for performance to not use EA when they are not needed. 1285216413Strasz * 1286216413Strasz * First try the PSARC/2010/029 semantics. 1287197405Strasz */ 1288197405Strasz tmpaclp = acl_alloc(M_WAITOK | M_ZERO); 1289197405Strasz acl_nfs4_sync_mode_from_acl(&tmpmode, aclp); 1290216413Strasz acl_nfs4_trivial_from_mode(tmpaclp, tmpmode); 1291197405Strasz trivial = _acls_are_equal(aclp, tmpaclp); 1292216413Strasz if (trivial) { 1293216413Strasz acl_free(tmpaclp); 1294216413Strasz return (trivial); 1295216413Strasz } 1296216413Strasz 1297216413Strasz /* 1298216413Strasz * Check if it's a draft-ietf-nfsv4-minorversion1-03.txt trivial ACL. 1299216413Strasz */ 1300216413Strasz tmpaclp->acl_cnt = 0; 1301216413Strasz acl_nfs4_sync_acl_from_mode_draft(tmpaclp, tmpmode, file_owner_id); 1302216413Strasz trivial = _acls_are_equal(aclp, tmpaclp); 1303197405Strasz acl_free(tmpaclp); 1304197405Strasz 1305197405Strasz return (trivial); 1306197405Strasz} 1307197405Strasz#endif /* _KERNEL */ 1308197405Strasz 1309197405Straszint 1310197405Straszacl_nfs4_check(const struct acl *aclp, int is_directory) 1311197405Strasz{ 1312197405Strasz int i; 1313197405Strasz const struct acl_entry *entry; 1314197405Strasz 1315197405Strasz /* 1316197405Strasz * The spec doesn't seem to say anything about ACL validity. 1317197405Strasz * It seems there is not much to do here. There is even no need 1318197405Strasz * to count "owner@" or "everyone@" (ACL_USER_OBJ and ACL_EVERYONE) 1319197405Strasz * entries, as there can be several of them and that's perfectly 1320197405Strasz * valid. There can be none of them too. Really. 1321197405Strasz */ 1322197405Strasz 1323197405Strasz if (aclp->acl_cnt > ACL_MAX_ENTRIES || aclp->acl_cnt <= 0) 1324197405Strasz return (EINVAL); 1325197405Strasz 1326197405Strasz for (i = 0; i < aclp->acl_cnt; i++) { 1327197405Strasz entry = &(aclp->acl_entry[i]); 1328197405Strasz 1329197405Strasz switch (entry->ae_tag) { 1330197405Strasz case ACL_USER_OBJ: 1331197405Strasz case ACL_GROUP_OBJ: 1332197405Strasz case ACL_EVERYONE: 1333197405Strasz if (entry->ae_id != ACL_UNDEFINED_ID) 1334197405Strasz return (EINVAL); 1335197405Strasz break; 1336197405Strasz 1337197405Strasz case ACL_USER: 1338197405Strasz case ACL_GROUP: 1339197405Strasz if (entry->ae_id == ACL_UNDEFINED_ID) 1340197405Strasz return (EINVAL); 1341197405Strasz break; 1342197405Strasz 1343197405Strasz default: 1344197405Strasz return (EINVAL); 1345197405Strasz } 1346197405Strasz 1347197405Strasz if ((entry->ae_perm | ACL_NFS4_PERM_BITS) != ACL_NFS4_PERM_BITS) 1348197405Strasz return (EINVAL); 1349197405Strasz 1350197405Strasz /* 1351197405Strasz * Disallow ACL_ENTRY_TYPE_AUDIT and ACL_ENTRY_TYPE_ALARM for now. 1352197405Strasz */ 1353197405Strasz if (entry->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 1354197405Strasz entry->ae_entry_type != ACL_ENTRY_TYPE_DENY) 1355197405Strasz return (EINVAL); 1356197405Strasz 1357197405Strasz if ((entry->ae_flags | ACL_FLAGS_BITS) != ACL_FLAGS_BITS) 1358197405Strasz return (EINVAL); 1359197405Strasz 1360197405Strasz /* Disallow unimplemented flags. */ 1361197405Strasz if (entry->ae_flags & (ACL_ENTRY_SUCCESSFUL_ACCESS | 1362197405Strasz ACL_ENTRY_FAILED_ACCESS)) 1363197405Strasz return (EINVAL); 1364197405Strasz 1365197405Strasz /* Disallow flags not allowed for ordinary files. */ 1366197405Strasz if (!is_directory) { 1367197405Strasz if (entry->ae_flags & (ACL_ENTRY_FILE_INHERIT | 1368197405Strasz ACL_ENTRY_DIRECTORY_INHERIT | 1369197405Strasz ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_INHERIT_ONLY)) 1370197405Strasz return (EINVAL); 1371197405Strasz } 1372197405Strasz } 1373197405Strasz 1374197405Strasz return (0); 1375197405Strasz} 1376232936Sadrian 1377232936Sadrian#ifdef _KERNEL 1378232936Sadrianstatic int 1379232936Sadrianacl_nfs4_modload(module_t module, int what, void *arg) 1380232936Sadrian{ 1381232936Sadrian int ret; 1382232936Sadrian 1383232936Sadrian ret = 0; 1384232936Sadrian 1385232936Sadrian switch (what) { 1386232936Sadrian case MOD_LOAD: 1387232936Sadrian case MOD_SHUTDOWN: 1388232936Sadrian break; 1389232936Sadrian 1390232936Sadrian case MOD_QUIESCE: 1391232936Sadrian /* XXX TODO */ 1392232936Sadrian ret = 0; 1393232936Sadrian break; 1394232936Sadrian 1395232936Sadrian case MOD_UNLOAD: 1396232936Sadrian /* XXX TODO */ 1397232936Sadrian ret = 0; 1398232936Sadrian break; 1399232936Sadrian default: 1400232936Sadrian ret = EINVAL; 1401232936Sadrian break; 1402232936Sadrian } 1403232936Sadrian 1404232936Sadrian return (ret); 1405232936Sadrian} 1406232936Sadrian 1407232936Sadrianstatic moduledata_t acl_nfs4_mod = { 1408232936Sadrian "acl_nfs4", 1409232936Sadrian acl_nfs4_modload, 1410232936Sadrian NULL 1411232936Sadrian}; 1412232936Sadrian 1413232936Sadrian/* 1414232936Sadrian * XXX TODO: which subsystem, order? 1415232936Sadrian */ 1416232936SadrianDECLARE_MODULE(acl_nfs4, acl_nfs4_mod, SI_SUB_VFS, SI_ORDER_FIRST); 1417232936SadrianMODULE_VERSION(acl_nfs4, 1); 1418232936Sadrian#endif /* _KERNEL */ 1419