1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008-2010 Edward Tomasz Napieraa <trasz (at) FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * ACL support routines specific to NFSv4 access control lists. These are 31 * utility routines for code common across file systems implementing NFSv4 32 * ACLs. 33 */ 34 35 #ifdef _KERNEL 36 #include <sys/cdefs.h> 37 #if 0 38 __FBSDID("$FreeBSD: head/sys/kern/subr_acl_nfs4.c 341827 2018-12-11 19:32:16Z mjg $"); 39 #endif 40 __KERNEL_RCSID(0, "$NetBSD: subr_acl_nfs4.c,v 1.4 2026/01/04 02:10:18 riastradh Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/types.h> 44 45 #include <sys/acl.h> 46 #include <sys/errno.h> 47 #include <sys/kauth.h> 48 #include <sys/kernel.h> 49 #include <sys/module.h> 50 #include <sys/mount.h> 51 #include <sys/sdt.h> 52 #include <sys/stat.h> 53 #include <sys/sysctl.h> 54 #include <sys/systm.h> 55 #include <sys/vnode.h> 56 57 static void acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode); 58 59 #else 60 61 #include <sys/acl.h> 62 #include <sys/stat.h> 63 64 #include <assert.h> 65 #include <errno.h> 66 67 #define KASSERT(a) assert(a) 68 69 #endif /* !_KERNEL */ 70 71 #if 0 72 static int 73 _acl_entry_matches(struct acl_entry *ae, acl_tag_t tag, acl_perm_t perm, 74 acl_entry_type_t entry_type) 75 { 76 if (ae->ae_tag != tag) 77 return (0); 78 79 if (ae->ae_id != ACL_UNDEFINED_ID) 80 return (0); 81 82 if (ae->ae_perm != perm) 83 return (0); 84 85 if (ae->ae_entry_type != entry_type) 86 return (0); 87 88 if (ae->ae_flags != 0) 89 return (0); 90 91 return (1); 92 } 93 #endif 94 95 static struct acl_entry * 96 _acl_append(struct acl *aclp, acl_tag_t tag, acl_perm_t perm, 97 acl_entry_type_t entry_type) 98 { 99 struct acl_entry *ae; 100 101 KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES); 102 103 ae = &(aclp->acl_entry[aclp->acl_cnt]); 104 aclp->acl_cnt++; 105 106 ae->ae_tag = tag; 107 ae->ae_id = ACL_UNDEFINED_ID; 108 ae->ae_perm = perm; 109 ae->ae_entry_type = entry_type; 110 ae->ae_flags = 0; 111 112 return (ae); 113 } 114 115 #if 0 116 static struct acl_entry * 117 _acl_duplicate_entry(struct acl *aclp, unsigned int entry_index) 118 { 119 size_t i; 120 121 KASSERT(aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES); 122 123 for (i = aclp->acl_cnt; i > entry_index; i--) 124 aclp->acl_entry[i] = aclp->acl_entry[i - 1]; 125 126 aclp->acl_cnt++; 127 128 return (&(aclp->acl_entry[entry_index + 1])); 129 } 130 #endif 131 132 133 #ifdef _KERNEL 134 void 135 acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, 136 int file_owner_id) 137 { 138 139 acl_nfs4_trivial_from_mode(aclp, mode); 140 } 141 #endif /* _KERNEL */ 142 143 void 144 __acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp) 145 { 146 size_t i; 147 mode_t old_mode = *_mode, mode = 0, seen = 0; 148 const struct acl_entry *ae; 149 150 KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES); 151 152 /* 153 * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt 154 * 155 * 3.16.6.1. Recomputing mode upon SETATTR of ACL 156 */ 157 158 for (i = 0; i < aclp->acl_cnt; i++) { 159 ae = &(aclp->acl_entry[i]); 160 161 if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 162 ae->ae_entry_type != ACL_ENTRY_TYPE_DENY) 163 continue; 164 165 if (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY) 166 continue; 167 168 if (ae->ae_tag == ACL_USER_OBJ) { 169 if ((ae->ae_perm & ACL_READ_DATA) && 170 ((seen & S_IRUSR) == 0)) { 171 seen |= S_IRUSR; 172 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 173 mode |= S_IRUSR; 174 } 175 if ((ae->ae_perm & ACL_WRITE_DATA) && 176 ((seen & S_IWUSR) == 0)) { 177 seen |= S_IWUSR; 178 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 179 mode |= S_IWUSR; 180 } 181 if ((ae->ae_perm & ACL_EXECUTE) && 182 ((seen & S_IXUSR) == 0)) { 183 seen |= S_IXUSR; 184 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 185 mode |= S_IXUSR; 186 } 187 } else if (ae->ae_tag == ACL_GROUP_OBJ) { 188 if ((ae->ae_perm & ACL_READ_DATA) && 189 ((seen & S_IRGRP) == 0)) { 190 seen |= S_IRGRP; 191 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 192 mode |= S_IRGRP; 193 } 194 if ((ae->ae_perm & ACL_WRITE_DATA) && 195 ((seen & S_IWGRP) == 0)) { 196 seen |= S_IWGRP; 197 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 198 mode |= S_IWGRP; 199 } 200 if ((ae->ae_perm & ACL_EXECUTE) && 201 ((seen & S_IXGRP) == 0)) { 202 seen |= S_IXGRP; 203 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 204 mode |= S_IXGRP; 205 } 206 } else if (ae->ae_tag == ACL_EVERYONE) { 207 if (ae->ae_perm & ACL_READ_DATA) { 208 if ((seen & S_IRUSR) == 0) { 209 seen |= S_IRUSR; 210 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 211 mode |= S_IRUSR; 212 } 213 if ((seen & S_IRGRP) == 0) { 214 seen |= S_IRGRP; 215 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 216 mode |= S_IRGRP; 217 } 218 if ((seen & S_IROTH) == 0) { 219 seen |= S_IROTH; 220 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 221 mode |= S_IROTH; 222 } 223 } 224 if (ae->ae_perm & ACL_WRITE_DATA) { 225 if ((seen & S_IWUSR) == 0) { 226 seen |= S_IWUSR; 227 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 228 mode |= S_IWUSR; 229 } 230 if ((seen & S_IWGRP) == 0) { 231 seen |= S_IWGRP; 232 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 233 mode |= S_IWGRP; 234 } 235 if ((seen & S_IWOTH) == 0) { 236 seen |= S_IWOTH; 237 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 238 mode |= S_IWOTH; 239 } 240 } 241 if (ae->ae_perm & ACL_EXECUTE) { 242 if ((seen & S_IXUSR) == 0) { 243 seen |= S_IXUSR; 244 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 245 mode |= S_IXUSR; 246 } 247 if ((seen & S_IXGRP) == 0) { 248 seen |= S_IXGRP; 249 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 250 mode |= S_IXGRP; 251 } 252 if ((seen & S_IXOTH) == 0) { 253 seen |= S_IXOTH; 254 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW) 255 mode |= S_IXOTH; 256 } 257 } 258 } 259 } 260 261 *_mode = mode | (old_mode & ACL_PRESERVE_MASK); 262 } 263 264 /* 265 * Populate the ACL with entries inherited from parent_aclp. 266 */ 267 static void 268 /*ARGSUSED*/ 269 acl_nfs4_inherit_entries(const struct acl *parent_aclp, 270 struct acl *child_aclp, mode_t mode, int file_owner_id, 271 int is_directory) 272 { 273 int flags, tag; 274 size_t i; 275 const struct acl_entry *parent_entry; 276 struct acl_entry *ae; 277 278 KASSERT(parent_aclp->acl_cnt <= ACL_MAX_ENTRIES); 279 280 for (i = 0; i < parent_aclp->acl_cnt; i++) { 281 parent_entry = &(parent_aclp->acl_entry[i]); 282 flags = parent_entry->ae_flags; 283 tag = parent_entry->ae_tag; 284 285 /* 286 * Don't inherit owner@, group@, or everyone@ entries. 287 */ 288 if (tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || 289 tag == ACL_EVERYONE) 290 continue; 291 292 /* 293 * Entry is not inheritable at all. 294 */ 295 if ((flags & (ACL_ENTRY_DIRECTORY_INHERIT | 296 ACL_ENTRY_FILE_INHERIT)) == 0) 297 continue; 298 299 /* 300 * We're creating a file, but ae is not inheritable 301 * by files. 302 */ 303 if (!is_directory && (flags & ACL_ENTRY_FILE_INHERIT) == 0) 304 continue; 305 306 /* 307 * Entry is inheritable only by files, but has NO_PROPAGATE 308 * flag set, and we're creating a directory, so it wouldn't 309 * propagate to any file in that directory anyway. 310 */ 311 if (is_directory && 312 (flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0 && 313 (flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)) 314 continue; 315 316 /* 317 * Entry qualifies for being inherited. 318 */ 319 KASSERT(child_aclp->acl_cnt + 1 <= ACL_MAX_ENTRIES); 320 ae = &(child_aclp->acl_entry[child_aclp->acl_cnt]); 321 *ae = *parent_entry; 322 child_aclp->acl_cnt++; 323 324 ae->ae_flags &= ~ACL_ENTRY_INHERIT_ONLY; 325 ae->ae_flags |= ACL_ENTRY_INHERITED; 326 327 /* 328 * If the type of the ACE is neither ALLOW nor DENY, 329 * then leave it as it is and proceed to the next one. 330 */ 331 if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 332 ae->ae_entry_type != ACL_ENTRY_TYPE_DENY) 333 continue; 334 335 /* 336 * If the ACL_ENTRY_NO_PROPAGATE_INHERIT is set, or if 337 * the object being created is not a directory, then clear 338 * the following flags: ACL_ENTRY_NO_PROPAGATE_INHERIT, 339 * ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT, 340 * ACL_ENTRY_INHERIT_ONLY. 341 */ 342 if (ae->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT || 343 !is_directory) { 344 ae->ae_flags &= ~(ACL_ENTRY_NO_PROPAGATE_INHERIT | 345 ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | 346 ACL_ENTRY_INHERIT_ONLY); 347 } 348 349 /* 350 * If the object is a directory and ACL_ENTRY_FILE_INHERIT 351 * is set, but ACL_ENTRY_DIRECTORY_INHERIT is not set, ensure 352 * that ACL_ENTRY_INHERIT_ONLY is set. 353 */ 354 if (is_directory && 355 (ae->ae_flags & ACL_ENTRY_FILE_INHERIT) && 356 ((ae->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) == 0)) { 357 ae->ae_flags |= ACL_ENTRY_INHERIT_ONLY; 358 } 359 360 if (ae->ae_entry_type == ACL_ENTRY_TYPE_ALLOW && 361 (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY) == 0) { 362 /* 363 * Some permissions must never be inherited. 364 */ 365 ae->ae_perm &= ~(ACL_WRITE_ACL | ACL_WRITE_OWNER | 366 ACL_WRITE_NAMED_ATTRS | ACL_WRITE_ATTRIBUTES); 367 368 /* 369 * Others must be masked according to the file mode. 370 */ 371 if ((mode & S_IRGRP) == 0) 372 ae->ae_perm &= ~ACL_READ_DATA; 373 if ((mode & S_IWGRP) == 0) 374 ae->ae_perm &= 375 ~(ACL_WRITE_DATA | ACL_APPEND_DATA); 376 if ((mode & S_IXGRP) == 0) 377 ae->ae_perm &= ~ACL_EXECUTE; 378 } 379 } 380 } 381 382 /* 383 * Calculate inherited ACL in a manner compatible with PSARC/2010/029. 384 * It's also being used to calculate a trivial ACL, by inheriting from 385 * a NULL ACL. 386 */ 387 static void 388 acl_nfs4_compute_inherited_acl_psarc(const struct acl *parent_aclp, 389 struct acl *aclp, mode_t mode, int file_owner_id, int is_directory) 390 { 391 acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0; 392 acl_perm_t user_allow, group_allow, everyone_allow; 393 394 KASSERT(aclp->acl_cnt == 0); 395 396 user_allow = group_allow = everyone_allow = ACL_READ_ACL | 397 ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE; 398 user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | 399 ACL_WRITE_NAMED_ATTRS; 400 401 if (mode & S_IRUSR) 402 user_allow |= ACL_READ_DATA; 403 if (mode & S_IWUSR) 404 user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 405 if (mode & S_IXUSR) 406 user_allow |= ACL_EXECUTE; 407 408 if (mode & S_IRGRP) 409 group_allow |= ACL_READ_DATA; 410 if (mode & S_IWGRP) 411 group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 412 if (mode & S_IXGRP) 413 group_allow |= ACL_EXECUTE; 414 415 if (mode & S_IROTH) 416 everyone_allow |= ACL_READ_DATA; 417 if (mode & S_IWOTH) 418 everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); 419 if (mode & S_IXOTH) 420 everyone_allow |= ACL_EXECUTE; 421 422 user_deny = ((group_allow | everyone_allow) & ~user_allow); 423 group_deny = everyone_allow & ~group_allow; 424 user_allow_first = group_deny & ~user_deny; 425 426 if (user_allow_first != 0) 427 _acl_append(aclp, ACL_USER_OBJ, user_allow_first, 428 ACL_ENTRY_TYPE_ALLOW); 429 if (user_deny != 0) 430 _acl_append(aclp, ACL_USER_OBJ, user_deny, 431 ACL_ENTRY_TYPE_DENY); 432 if (group_deny != 0) 433 _acl_append(aclp, ACL_GROUP_OBJ, group_deny, 434 ACL_ENTRY_TYPE_DENY); 435 436 if (parent_aclp != NULL) 437 acl_nfs4_inherit_entries(parent_aclp, aclp, mode, 438 file_owner_id, is_directory); 439 440 _acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW); 441 _acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW); 442 _acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW); 443 } 444 445 #ifdef _KERNEL 446 void 447 acl_nfs4_compute_inherited_acl(const struct acl *parent_aclp, 448 struct acl *child_aclp, mode_t mode, int file_owner_id, 449 int is_directory) 450 { 451 452 acl_nfs4_compute_inherited_acl_psarc(parent_aclp, child_aclp, 453 mode, file_owner_id, is_directory); 454 } 455 #endif /* _KERNEL */ 456 457 /* 458 * Calculate trivial ACL in a manner compatible with PSARC/2010/029. 459 * Note that this results in an ACL different from (but semantically 460 * equal to) the "canonical six" trivial ACL computed using algorithm 461 * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2. 462 */ 463 static void 464 acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode) 465 { 466 467 aclp->acl_cnt = 0; 468 acl_nfs4_compute_inherited_acl_psarc(NULL, aclp, mode, -1, -1); 469 } 470 471 #ifndef _KERNEL 472 /* 473 * This routine is used by libc to implement acl_strip_np(3) 474 * and acl_is_trivial_np(3). 475 */ 476 void 477 /*ARGSUSED*/ 478 __acl_nfs4_trivial_from_mode_libc(struct acl *aclp, int mode, int canonical_six) 479 { 480 481 aclp->acl_cnt = 0; 482 acl_nfs4_trivial_from_mode(aclp, mode); 483 } 484 #endif /* !_KERNEL */ 485 486 #ifdef _KERNEL 487 static int 488 _acls_are_equal(const struct acl *a, const struct acl *b) 489 { 490 int i; 491 const struct acl_entry *entrya, *entryb; 492 493 if (a->acl_cnt != b->acl_cnt) 494 return (0); 495 496 for (i = 0; i < b->acl_cnt; i++) { 497 entrya = &(a->acl_entry[i]); 498 entryb = &(b->acl_entry[i]); 499 500 if (entrya->ae_tag != entryb->ae_tag || 501 entrya->ae_id != entryb->ae_id || 502 entrya->ae_perm != entryb->ae_perm || 503 entrya->ae_entry_type != entryb->ae_entry_type || 504 entrya->ae_flags != entryb->ae_flags) 505 return (0); 506 } 507 508 return (1); 509 } 510 511 /* 512 * This routine is used to determine whether to remove extended attribute 513 * that stores ACL contents. 514 */ 515 int 516 acl_nfs4_is_trivial(const struct acl *aclp, int file_owner_id) 517 { 518 int trivial; 519 mode_t tmpmode = 0; 520 struct acl *tmpaclp; 521 522 if (aclp->acl_cnt > 6) 523 return (0); 524 525 /* 526 * Compute the mode from the ACL, then compute new ACL from that mode. 527 * If the ACLs are identical, then the ACL is trivial. 528 * 529 * XXX: I guess there is a faster way to do this. However, even 530 * this slow implementation significantly speeds things up 531 * for files that don't have non-trivial ACLs - it's critical 532 * for performance to not use EA when they are not needed. 533 * 534 * First try the PSARC/2010/029 semantics. 535 */ 536 tmpaclp = acl_alloc(KM_SLEEP); 537 __acl_nfs4_sync_mode_from_acl(&tmpmode, aclp); 538 acl_nfs4_trivial_from_mode(tmpaclp, tmpmode); 539 trivial = _acls_are_equal(aclp, tmpaclp); 540 if (trivial) { 541 acl_free(tmpaclp); 542 return (trivial); 543 } 544 545 /* 546 * Check if it's a draft-ietf-nfsv4-minorversion1-03.txt trivial ACL. 547 */ 548 acl_free(tmpaclp); 549 550 return (trivial); 551 } 552 553 int 554 acl_nfs4_check(const struct acl *aclp, int is_directory) 555 { 556 size_t i; 557 const struct acl_entry *ae; 558 559 /* 560 * The spec doesn't seem to say anything about ACL validity. 561 * It seems there is not much to do here. There is even no need 562 * to count "owner@" or "everyone@" (ACL_USER_OBJ and ACL_EVERYONE) 563 * entries, as there can be several of them and that's perfectly 564 * valid. There can be none of them too. Really. 565 */ 566 567 if (aclp->acl_cnt > ACL_MAX_ENTRIES || aclp->acl_cnt <= 0) 568 return SET_ERROR(EINVAL); 569 570 for (i = 0; i < aclp->acl_cnt; i++) { 571 ae = &(aclp->acl_entry[i]); 572 573 switch (ae->ae_tag) { 574 case ACL_USER_OBJ: 575 case ACL_GROUP_OBJ: 576 case ACL_EVERYONE: 577 if (ae->ae_id != ACL_UNDEFINED_ID) 578 return SET_ERROR(EINVAL); 579 break; 580 581 case ACL_USER: 582 case ACL_GROUP: 583 if (ae->ae_id == ACL_UNDEFINED_ID) 584 return SET_ERROR(EINVAL); 585 break; 586 587 default: 588 return SET_ERROR(EINVAL); 589 } 590 591 if ((ae->ae_perm | ACL_NFS4_PERM_BITS) != ACL_NFS4_PERM_BITS) 592 return SET_ERROR(EINVAL); 593 594 /* 595 * Disallow ACL_ENTRY_TYPE_AUDIT and ACL_ENTRY_TYPE_ALARM for now. 596 */ 597 if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 598 ae->ae_entry_type != ACL_ENTRY_TYPE_DENY) 599 return SET_ERROR(EINVAL); 600 601 if ((ae->ae_flags | ACL_FLAGS_BITS) != ACL_FLAGS_BITS) 602 return SET_ERROR(EINVAL); 603 604 /* Disallow unimplemented flags. */ 605 if (ae->ae_flags & (ACL_ENTRY_SUCCESSFUL_ACCESS | 606 ACL_ENTRY_FAILED_ACCESS)) 607 return SET_ERROR(EINVAL); 608 609 /* Disallow flags not allowed for ordinary files. */ 610 if (!is_directory) { 611 if (ae->ae_flags & (ACL_ENTRY_FILE_INHERIT | 612 ACL_ENTRY_DIRECTORY_INHERIT | 613 ACL_ENTRY_NO_PROPAGATE_INHERIT | ACL_ENTRY_INHERIT_ONLY)) 614 return SET_ERROR(EINVAL); 615 } 616 } 617 618 return 0; 619 } 620 #endif 621