1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1999-2003 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * This software was developed by Robert Watson for the TrustedBSD Project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * Support for POSIX.1e access control lists: UFS-specific support functions. 33 */ 34 35 #include <sys/cdefs.h> 36 #if 0 37 __FBSDID("$FreeBSD: head/sys/ufs/ufs/ufs_acl.c 356669 2020-01-13 02:31:51Z mjg $"); 38 #endif 39 __KERNEL_RCSID(0, "$NetBSD: ufs_acl.c,v 1.5 2023/02/22 21:49:45 riastradh Exp $"); 40 41 #if defined(_KERNEL_OPT) 42 #include "opt_ffs.h" 43 #include "opt_quota.h" 44 #include "opt_wapbl.h" 45 #endif 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/stat.h> 50 #include <sys/mount.h> 51 #include <sys/vnode.h> 52 #include <sys/wapbl.h> 53 #include <sys/types.h> 54 #include <sys/acl.h> 55 #include <sys/event.h> 56 #include <sys/extattr.h> 57 #include <sys/proc.h> 58 59 #include <ufs/ufs/quota.h> 60 #include <ufs/ufs/inode.h> 61 #include <ufs/ufs/acl.h> 62 #include <ufs/ufs/extattr.h> 63 #include <ufs/ufs/dir.h> 64 #include <ufs/ufs/ufsmount.h> 65 #include <ufs/ufs/ufs_extern.h> 66 #include <ufs/ufs/ufs_wapbl.h> 67 68 #include <ufs/ffs/fs.h> 69 70 #ifdef UFS_ACL 71 72 /* 73 * Synchronize an ACL and an inode by copying over appropriate inode fields 74 * to the passed ACL. Assumes an ACL that would satisfy acl_posix1e_check(), 75 * and may panic if not. 76 */ 77 void 78 ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl) 79 { 80 struct acl_entry *acl_mask, *acl_group_obj; 81 int i; 82 83 /* 84 * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK 85 * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is 86 * present. 87 */ 88 acl_mask = NULL; 89 acl_group_obj = NULL; 90 for (i = 0; i < acl->acl_cnt; i++) { 91 switch (acl->acl_entry[i].ae_tag) { 92 case ACL_USER_OBJ: 93 acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( 94 ACL_USER_OBJ, ip->i_mode); 95 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 96 break; 97 98 case ACL_GROUP_OBJ: 99 acl_group_obj = &acl->acl_entry[i]; 100 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 101 break; 102 103 case ACL_OTHER: 104 acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( 105 ACL_OTHER, ip->i_mode); 106 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 107 break; 108 109 case ACL_MASK: 110 acl_mask = &acl->acl_entry[i]; 111 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 112 break; 113 114 case ACL_USER: 115 case ACL_GROUP: 116 break; 117 118 default: 119 panic("ufs_sync_acl_from_inode(): bad ae_tag"); 120 } 121 } 122 123 if (acl_group_obj == NULL) 124 panic("ufs_sync_acl_from_inode(): no ACL_GROUP_OBJ"); 125 126 if (acl_mask == NULL) { 127 /* 128 * There is no ACL_MASK, so update ACL_GROUP_OBJ. 129 */ 130 acl_group_obj->ae_perm = acl_posix1e_mode_to_perm( 131 ACL_GROUP_OBJ, ip->i_mode); 132 } else { 133 /* 134 * Update the ACL_MASK entry instead of ACL_GROUP_OBJ. 135 */ 136 acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ, 137 ip->i_mode); 138 } 139 } 140 141 /* 142 * Calculate what the inode mode should look like based on an authoritative 143 * ACL for the inode. Replace only the fields in the inode that the ACL 144 * can represent. 145 */ 146 void 147 ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip) 148 { 149 150 ip->i_mode &= ACL_PRESERVE_MASK; 151 ip->i_mode |= acl_posix1e_acl_to_mode(acl); 152 DIP_ASSIGN(ip, mode, ip->i_mode); 153 } 154 155 /* 156 * Retrieve NFSv4 ACL, skipping access checks. Must be used in UFS code 157 * instead of VOP_GETACL() when we don't want to be restricted by the user 158 * not having ACL_READ_ACL permission, e.g. when calculating inherited ACL 159 * or in ufs_vnops.c:ufs_accessx(). 160 */ 161 int 162 ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct lwp *l) 163 { 164 int error; 165 size_t len; 166 struct inode *ip = VTOI(vp); 167 168 len = sizeof(*aclp); 169 bzero(aclp, len); 170 171 error = vn_extattr_get(vp, IO_NODELOCKED, 172 NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, &len, aclp, l); 173 aclp->acl_maxcnt = ACL_MAX_ENTRIES; 174 if (error == ENOATTR) { 175 /* 176 * Legitimately no ACL set on object, purely 177 * emulate it through the inode. 178 */ 179 acl_nfs4_sync_acl_from_mode(aclp, ip->i_mode, ip->i_uid); 180 181 return (0); 182 } 183 184 if (error) 185 return (error); 186 187 if (len != sizeof(*aclp)) { 188 /* 189 * A short (or long) read, meaning that for 190 * some reason the ACL is corrupted. Return 191 * EPERM since the object DAC protections 192 * are unsafe. 193 */ 194 printf("%s: Loaded invalid ACL (" 195 "%zu bytes), inumber %ju on %s\n", __func__, len, 196 (uintmax_t)ip->i_number, ip->i_fs->fs_fsmnt); 197 198 return (EPERM); 199 } 200 201 error = acl_nfs4_check(aclp, vp->v_type == VDIR); 202 if (error) { 203 printf("%s: Loaded invalid ACL " 204 "(failed acl_nfs4_check), inumber %ju on %s\n", __func__, 205 (uintmax_t)ip->i_number, ip->i_fs->fs_fsmnt); 206 207 return (EPERM); 208 } 209 210 return (0); 211 } 212 213 static int 214 ufs_getacl_nfs4(struct vop_getacl_args *ap, struct lwp *l) 215 { 216 int error; 217 218 if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) 219 return (EINVAL); 220 221 error = VOP_ACCESSX(ap->a_vp, VREAD_ACL, ap->a_cred); 222 if (error) 223 return (error); 224 225 error = ufs_getacl_nfs4_internal(ap->a_vp, ap->a_aclp, l); 226 227 return (error); 228 } 229 230 /* 231 * Read POSIX.1e ACL from an EA. Return error if its not found 232 * or if any other error has occurred. 233 */ 234 static int 235 ufs_get_oldacl(acl_type_t type, struct oldacl *old, struct vnode *vp, 236 struct lwp *l) 237 { 238 int error; 239 size_t len; 240 struct inode *ip = VTOI(vp); 241 242 len = sizeof(*old); 243 244 switch (type) { 245 case ACL_TYPE_ACCESS: 246 error = vn_extattr_get(vp, IO_NODELOCKED, 247 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 248 POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, old, l); 249 break; 250 case ACL_TYPE_DEFAULT: 251 if (vp->v_type != VDIR) 252 return (EINVAL); 253 error = vn_extattr_get(vp, IO_NODELOCKED, 254 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 255 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len, old, l); 256 break; 257 default: 258 return (EINVAL); 259 } 260 261 if (error != 0) 262 return (error); 263 264 if (len != sizeof(*old)) { 265 /* 266 * A short (or long) read, meaning that for some reason 267 * the ACL is corrupted. Return EPERM since the object 268 * DAC protections are unsafe. 269 */ 270 printf("%s: Loaded invalid ACL " 271 "(len = %zu), inumber %ju on %s\n", __func__, len, 272 (uintmax_t)ip->i_number, ip->i_fs->fs_fsmnt); 273 return (EPERM); 274 } 275 276 return (0); 277 } 278 279 /* 280 * Retrieve the ACL on a file. 281 * 282 * As part of the ACL is stored in the inode, and the rest in an EA, 283 * assemble both into a final ACL product. Right now this is not done 284 * very efficiently. 285 */ 286 static int 287 ufs_getacl_posix1e(struct vop_getacl_args *ap, struct lwp *l) 288 { 289 struct inode *ip = VTOI(ap->a_vp); 290 int error; 291 struct oldacl *old; 292 293 /* 294 * XXX: If ufs_getacl() should work on file systems not supporting 295 * ACLs, remove this check. 296 */ 297 if ((ap->a_vp->v_mount->mnt_flag & MNT_POSIX1EACLS) == 0) 298 return (EINVAL); 299 300 old = kmem_zalloc(sizeof(*old), KM_SLEEP); 301 302 /* 303 * Attempt to retrieve the ACL from the extended attributes. 304 */ 305 error = ufs_get_oldacl(ap->a_type, old, ap->a_vp, l); 306 switch (error) { 307 /* 308 * XXX: If ufs_getacl() should work on filesystems 309 * without the EA configured, add case EOPNOTSUPP here. 310 */ 311 case ENOATTR: 312 switch (ap->a_type) { 313 case ACL_TYPE_ACCESS: 314 /* 315 * Legitimately no ACL set on object, purely 316 * emulate it through the inode. These fields will 317 * be updated when the ACL is synchronized with 318 * the inode later. 319 */ 320 old->acl_cnt = 3; 321 old->acl_entry[0].ae_tag = ACL_USER_OBJ; 322 old->acl_entry[0].ae_id = ACL_UNDEFINED_ID; 323 old->acl_entry[0].ae_perm = ACL_PERM_NONE; 324 old->acl_entry[1].ae_tag = ACL_GROUP_OBJ; 325 old->acl_entry[1].ae_id = ACL_UNDEFINED_ID; 326 old->acl_entry[1].ae_perm = ACL_PERM_NONE; 327 old->acl_entry[2].ae_tag = ACL_OTHER; 328 old->acl_entry[2].ae_id = ACL_UNDEFINED_ID; 329 old->acl_entry[2].ae_perm = ACL_PERM_NONE; 330 break; 331 332 case ACL_TYPE_DEFAULT: 333 /* 334 * Unlike ACL_TYPE_ACCESS, there is no relationship 335 * between the inode contents and the ACL, and it is 336 * therefore possible for the request for the ACL 337 * to fail since the ACL is undefined. In this 338 * situation, return success and an empty ACL, 339 * as required by POSIX.1e. 340 */ 341 old->acl_cnt = 0; 342 break; 343 } 344 /* FALLTHROUGH */ 345 case 0: 346 error = acl_copy_oldacl_into_acl(old, ap->a_aclp); 347 if (error != 0) 348 break; 349 350 if (ap->a_type == ACL_TYPE_ACCESS) 351 ufs_sync_acl_from_inode(ip, ap->a_aclp); 352 default: 353 break; 354 } 355 356 kmem_free(old, sizeof(*old)); 357 return (error); 358 } 359 360 int 361 ufs_getacl(void *v) 362 { 363 struct vop_getacl_args *ap = v; 364 365 if ((ap->a_vp->v_mount->mnt_flag & (MNT_POSIX1EACLS | MNT_NFS4ACLS)) == 0) 366 return (EOPNOTSUPP); 367 368 if (ap->a_type == ACL_TYPE_NFS4) 369 return (ufs_getacl_nfs4(ap, curlwp)); 370 371 return (ufs_getacl_posix1e(ap, curlwp)); 372 } 373 374 /* 375 * Set NFSv4 ACL without doing any access checking. This is required 376 * e.g. by the UFS code that implements ACL inheritance, or from 377 * ufs_vnops.c:ufs_chmod(), as some of the checks have to be skipped 378 * in that case, and others are redundant. 379 */ 380 int 381 ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, 382 struct lwp *l, bool lock) 383 { 384 int error; 385 mode_t mode; 386 struct inode *ip = VTOI(vp); 387 388 KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0); 389 390 if (acl_nfs4_is_trivial(aclp, ip->i_uid)) { 391 error = vn_extattr_rm(vp, IO_NODELOCKED, 392 NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, l); 393 /* 394 * An attempt to remove ACL from a file that didn't have 395 * any extended entries is not an error. 396 */ 397 if (error == ENOATTR) 398 error = 0; 399 400 } else { 401 error = vn_extattr_set(vp, IO_NODELOCKED, 402 NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, 403 sizeof(*aclp), aclp, l); 404 } 405 406 /* 407 * Map lack of attribute definition in UFS_EXTATTR into lack of 408 * support for ACLs on the filesystem. 409 */ 410 if (error == ENOATTR) 411 return (EOPNOTSUPP); 412 413 if (error) 414 return (error); 415 416 mode = ip->i_mode; 417 418 __acl_nfs4_sync_mode_from_acl(&mode, aclp); 419 420 if (lock && (error = UFS_WAPBL_BEGIN(vp->v_mount)) != 0) 421 return error; 422 423 ip->i_mode &= ACL_PRESERVE_MASK; 424 ip->i_mode |= mode; 425 DIP_ASSIGN(ip, mode, ip->i_mode); 426 ip->i_flag |= IN_CHANGE; 427 428 error = UFS_UPDATE(vp, NULL, NULL, 0); 429 if (lock) 430 UFS_WAPBL_END(vp->v_mount); 431 432 return (error); 433 } 434 435 static int 436 ufs_setacl_nfs4(struct vop_setacl_args *ap, struct lwp *l) 437 { 438 int error; 439 struct inode *ip = VTOI(ap->a_vp); 440 441 if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) 442 return (EINVAL); 443 444 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 445 return (EROFS); 446 447 if (ap->a_aclp == NULL) 448 return (EINVAL); 449 450 error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred); 451 if (error) 452 return (error); 453 454 /* 455 * Authorize the ACL operation. 456 */ 457 if (ip->i_flags & (IMMUTABLE | APPEND)) 458 return (EPERM); 459 460 /* 461 * Must hold VWRITE_ACL or have appropriate privilege. 462 */ 463 if ((error = VOP_ACCESSX(ap->a_vp, VWRITE_ACL, l->l_cred))) 464 return (error); 465 466 /* 467 * With NFSv4 ACLs, chmod(2) may need to add additional entries. 468 * Make sure it has enough room for that - splitting every entry 469 * into two and appending "canonical six" entries at the end. 470 */ 471 if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) 472 return (ENOSPC); 473 474 error = ufs_setacl_nfs4_internal(ap->a_vp, ap->a_aclp, l, true); 475 476 return (error); 477 } 478 479 /* 480 * Set the ACL on a file. 481 * 482 * As part of the ACL is stored in the inode, and the rest in an EA, 483 * this is necessarily non-atomic, and has complex authorization. 484 * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(), 485 * a fair number of different access checks may be required to go ahead 486 * with the operation at all. 487 */ 488 int 489 ufs_setacl_posix1e(struct vnode *vp, int type, struct acl *aclp, 490 kauth_cred_t cred, struct lwp *l) 491 { 492 struct inode *ip = VTOI(vp); 493 int error; 494 struct oldacl *old; 495 496 if ((vp->v_mount->mnt_flag & MNT_POSIX1EACLS) == 0) 497 return (EINVAL); 498 499 /* 500 * If this is a set operation rather than a delete operation, 501 * invoke VOP_ACLCHECK() on the passed ACL to determine if it is 502 * valid for the target. This will include a check on ap->a_type. 503 */ 504 if (aclp != NULL) { 505 /* 506 * Set operation. 507 */ 508 error = VOP_ACLCHECK(vp, type, aclp, cred); 509 if (error != 0) 510 return (error); 511 } else { 512 /* 513 * Delete operation. 514 * POSIX.1e allows only deletion of the default ACL on a 515 * directory (ACL_TYPE_DEFAULT). 516 */ 517 if (type != ACL_TYPE_DEFAULT) 518 return (EINVAL); 519 if (vp->v_type != VDIR) 520 return (ENOTDIR); 521 } 522 523 if (vp->v_mount->mnt_flag & MNT_RDONLY) 524 return (EROFS); 525 526 /* 527 * Authorize the ACL operation. 528 */ 529 if (ip->i_flags & (IMMUTABLE | APPEND)) 530 return (EPERM); 531 532 /* 533 * Must hold VADMIN (be file owner) or have appropriate privilege. 534 */ 535 if ((error = VOP_ACCESS(vp, VADMIN, cred))) 536 return (error); 537 538 switch(type) { 539 case ACL_TYPE_ACCESS: 540 old = kmem_zalloc(sizeof(*old), KM_SLEEP); 541 error = acl_copy_acl_into_oldacl(aclp, old); 542 if (error == 0) { 543 error = vn_extattr_set(vp, IO_NODELOCKED, 544 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 545 POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*old), 546 old, l); 547 } 548 kmem_free(old, sizeof(*old)); 549 break; 550 551 case ACL_TYPE_DEFAULT: 552 if (aclp == NULL) { 553 error = vn_extattr_rm(vp, IO_NODELOCKED, 554 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 555 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, l); 556 /* 557 * Attempting to delete a non-present default ACL 558 * will return success for portability purposes. 559 * (TRIX) 560 * 561 * XXX: Note that since we can't distinguish 562 * "that EA is not supported" from "that EA is not 563 * defined", the success case here overlaps the 564 * the ENOATTR->EOPNOTSUPP case below. 565 */ 566 if (error == ENOATTR) 567 error = 0; 568 } else { 569 old = kmem_zalloc(sizeof(*old), KM_SLEEP); 570 error = acl_copy_acl_into_oldacl(aclp, old); 571 if (error == 0) { 572 error = vn_extattr_set(vp, IO_NODELOCKED, 573 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 574 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, 575 sizeof(*old), (char *) old, l); 576 } 577 kmem_free(old, sizeof(*old)); 578 } 579 break; 580 581 default: 582 error = EINVAL; 583 } 584 /* 585 * Map lack of attribute definition in UFS_EXTATTR into lack of 586 * support for ACLs on the filesystem. 587 */ 588 if (error == ENOATTR) 589 return (EOPNOTSUPP); 590 if (error != 0) 591 return (error); 592 593 if (type == ACL_TYPE_ACCESS) { 594 /* 595 * Now that the EA is successfully updated, update the 596 * inode and mark it as changed. 597 */ 598 if ((error = UFS_WAPBL_BEGIN(vp->v_mount)) != 0) 599 return error; 600 601 ufs_sync_inode_from_acl(aclp, ip); 602 ip->i_flag |= IN_CHANGE; 603 error = UFS_UPDATE(vp, NULL, NULL, 0); 604 605 UFS_WAPBL_END(vp->v_mount); 606 } 607 608 return (error); 609 } 610 611 int 612 ufs_setacl(void *v) 613 { 614 struct vop_setacl_args *ap = v; 615 if ((ap->a_vp->v_mount->mnt_flag & (MNT_POSIX1EACLS | MNT_NFS4ACLS)) == 0) 616 return (EOPNOTSUPP); 617 618 if (ap->a_type == ACL_TYPE_NFS4) 619 return ufs_setacl_nfs4(ap, curlwp); 620 621 return ufs_setacl_posix1e(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred, 622 curlwp); 623 } 624 625 static int 626 ufs_aclcheck_nfs4(struct vop_aclcheck_args *ap, struct lwp *l) 627 { 628 int is_directory = 0; 629 630 if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) 631 return (EINVAL); 632 633 /* 634 * With NFSv4 ACLs, chmod(2) may need to add additional entries. 635 * Make sure it has enough room for that - splitting every entry 636 * into two and appending "canonical six" entries at the end. 637 */ 638 if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) 639 return (ENOSPC); 640 641 if (ap->a_vp->v_type == VDIR) 642 is_directory = 1; 643 644 return (acl_nfs4_check(ap->a_aclp, is_directory)); 645 } 646 647 static int 648 ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap, struct lwp *l) 649 { 650 651 if ((ap->a_vp->v_mount->mnt_flag & MNT_POSIX1EACLS) == 0) 652 return (EINVAL); 653 654 /* 655 * Verify we understand this type of ACL, and that it applies 656 * to this kind of object. 657 * Rely on the acl_posix1e_check() routine to verify the contents. 658 */ 659 switch(ap->a_type) { 660 case ACL_TYPE_ACCESS: 661 break; 662 663 case ACL_TYPE_DEFAULT: 664 if (ap->a_vp->v_type != VDIR) 665 return (EINVAL); 666 break; 667 668 default: 669 return (EINVAL); 670 } 671 672 if (ap->a_aclp->acl_cnt > OLDACL_MAX_ENTRIES) 673 return (EINVAL); 674 675 return (acl_posix1e_check(ap->a_aclp)); 676 } 677 678 /* 679 * Check the validity of an ACL for a file. 680 */ 681 int 682 ufs_aclcheck(void *v) 683 { 684 struct vop_aclcheck_args *ap = v; 685 686 if ((ap->a_vp->v_mount->mnt_flag & (MNT_POSIX1EACLS | MNT_NFS4ACLS)) == 0) 687 return (EOPNOTSUPP); 688 689 if (ap->a_type == ACL_TYPE_NFS4) 690 return ufs_aclcheck_nfs4(ap, curlwp); 691 692 return ufs_aclcheck_posix1e(ap, curlwp); 693 } 694 695 #endif /* !UFS_ACL */ 696