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