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