1 /*- 2 * Copyright (c) 1999-2003 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by Robert Watson for the TrustedBSD Project. 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 * Support for POSIX.1e access control lists: UFS-specific support functions. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 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 49 #include <ufs/ufs/quota.h> 50 #include <ufs/ufs/inode.h> 51 #include <ufs/ufs/acl.h> 52 #include <ufs/ufs/extattr.h> 53 #include <ufs/ufs/dir.h> 54 #include <ufs/ufs/ufsmount.h> 55 #include <ufs/ufs/ufs_extern.h> 56 #include <ufs/ffs/fs.h> 57 58 #ifdef UFS_ACL 59 60 /* 61 * Synchronize an ACL and an inode by copying over appropriate inode fields 62 * to the passed ACL. Assumes an ACL that would satisfy acl_posix1e_check(), 63 * and may panic if not. 64 */ 65 void 66 ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl) 67 { 68 struct acl_entry *acl_mask, *acl_group_obj; 69 int i; 70 71 /* 72 * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK 73 * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is 74 * present. 75 */ 76 acl_mask = NULL; 77 acl_group_obj = NULL; 78 for (i = 0; i < acl->acl_cnt; i++) { 79 switch (acl->acl_entry[i].ae_tag) { 80 case ACL_USER_OBJ: 81 acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( 82 ACL_USER_OBJ, ip->i_mode); 83 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 84 break; 85 86 case ACL_GROUP_OBJ: 87 acl_group_obj = &acl->acl_entry[i]; 88 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 89 break; 90 91 case ACL_OTHER: 92 acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( 93 ACL_OTHER, ip->i_mode); 94 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 95 break; 96 97 case ACL_MASK: 98 acl_mask = &acl->acl_entry[i]; 99 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 100 break; 101 102 case ACL_USER: 103 case ACL_GROUP: 104 break; 105 106 default: 107 panic("ufs_sync_acl_from_inode(): bad ae_tag"); 108 } 109 } 110 111 if (acl_group_obj == NULL) 112 panic("ufs_sync_acl_from_inode(): no ACL_GROUP_OBJ"); 113 114 if (acl_mask == NULL) { 115 /* 116 * There is no ACL_MASK, so update ACL_GROUP_OBJ. 117 */ 118 acl_group_obj->ae_perm = acl_posix1e_mode_to_perm( 119 ACL_GROUP_OBJ, ip->i_mode); 120 } else { 121 /* 122 * Update the ACL_MASK entry instead of ACL_GROUP_OBJ. 123 */ 124 acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ, 125 ip->i_mode); 126 } 127 } 128 129 /* 130 * Calculate what the inode mode should look like based on an authoritative 131 * ACL for the inode. Replace only the fields in the inode that the ACL 132 * can represent. 133 */ 134 void 135 ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip) 136 { 137 138 ip->i_mode &= ACL_PRESERVE_MASK; 139 ip->i_mode |= acl_posix1e_acl_to_mode(acl); 140 DIP_SET(ip, i_mode, ip->i_mode); 141 } 142 143 /* 144 * Retrieve NFSv4 ACL, skipping access checks. Must be used in UFS code 145 * instead of VOP_GETACL() when we don't want to be restricted by the user 146 * not having ACL_READ_ACL permission, e.g. when calculating inherited ACL 147 * or in ufs_vnops.c:ufs_accessx(). 148 */ 149 int 150 ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) 151 { 152 int error, len; 153 struct inode *ip = VTOI(vp); 154 155 len = sizeof(*aclp); 156 bzero(aclp, len); 157 158 error = vn_extattr_get(vp, IO_NODELOCKED, 159 NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, 160 &len, (char *) aclp, td); 161 aclp->acl_maxcnt = ACL_MAX_ENTRIES; 162 if (error == ENOATTR) { 163 /* 164 * Legitimately no ACL set on object, purely 165 * emulate it through the inode. 166 */ 167 acl_nfs4_sync_acl_from_mode(aclp, ip->i_mode, ip->i_uid); 168 169 return (0); 170 } 171 172 if (error) 173 return (error); 174 175 if (len != sizeof(*aclp)) { 176 /* 177 * A short (or long) read, meaning that for 178 * some reason the ACL is corrupted. Return 179 * EPERM since the object DAC protections 180 * are unsafe. 181 */ 182 printf("ufs_getacl_nfs4(): Loaded invalid ACL (" 183 "%d bytes), inumber %d on %s\n", len, 184 ip->i_number, ip->i_fs->fs_fsmnt); 185 186 return (EPERM); 187 } 188 189 error = acl_nfs4_check(aclp, vp->v_type == VDIR); 190 if (error) { 191 printf("ufs_getacl_nfs4(): Loaded invalid ACL " 192 "(failed acl_nfs4_check), inumber %d on %s\n", 193 ip->i_number, ip->i_fs->fs_fsmnt); 194 195 return (EPERM); 196 } 197 198 return (0); 199 } 200 201 static int 202 ufs_getacl_nfs4(struct vop_getacl_args *ap) 203 { 204 int error; 205 206 if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) 207 return (EINVAL); 208 209 error = VOP_ACCESSX(ap->a_vp, VREAD_ACL, ap->a_td->td_ucred, ap->a_td); 210 if (error) 211 return (error); 212 213 error = ufs_getacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td); 214 215 return (error); 216 } 217 218 /* 219 * Read POSIX.1e ACL from an EA. Return error if its not found 220 * or if any other error has occured. 221 */ 222 static int 223 ufs_get_oldacl(acl_type_t type, struct oldacl *old, struct vnode *vp, 224 struct thread *td) 225 { 226 int error, len; 227 struct inode *ip = VTOI(vp); 228 229 len = sizeof(*old); 230 231 switch (type) { 232 case ACL_TYPE_ACCESS: 233 error = vn_extattr_get(vp, IO_NODELOCKED, 234 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 235 POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) old, 236 td); 237 break; 238 case ACL_TYPE_DEFAULT: 239 if (vp->v_type != VDIR) 240 return (EINVAL); 241 error = vn_extattr_get(vp, IO_NODELOCKED, 242 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 243 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len, (char *) old, 244 td); 245 break; 246 default: 247 return (EINVAL); 248 } 249 250 if (error != 0) 251 return (error); 252 253 if (len != sizeof(*old)) { 254 /* 255 * A short (or long) read, meaning that for some reason 256 * the ACL is corrupted. Return EPERM since the object 257 * DAC protections are unsafe. 258 */ 259 printf("ufs_get_oldacl(): Loaded invalid ACL " 260 "(len = %d), inumber %d on %s\n", len, 261 ip->i_number, ip->i_fs->fs_fsmnt); 262 return (EPERM); 263 } 264 265 return (0); 266 } 267 268 /* 269 * Retrieve the ACL on a file. 270 * 271 * As part of the ACL is stored in the inode, and the rest in an EA, 272 * assemble both into a final ACL product. Right now this is not done 273 * very efficiently. 274 */ 275 static int 276 ufs_getacl_posix1e(struct vop_getacl_args *ap) 277 { 278 struct inode *ip = VTOI(ap->a_vp); 279 int error; 280 struct oldacl *old; 281 282 /* 283 * XXX: If ufs_getacl() should work on file systems not supporting 284 * ACLs, remove this check. 285 */ 286 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 287 return (EINVAL); 288 289 old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); 290 291 /* 292 * Attempt to retrieve the ACL from the extended attributes. 293 */ 294 error = ufs_get_oldacl(ap->a_type, old, ap->a_vp, ap->a_td); 295 switch (error) { 296 /* 297 * XXX: If ufs_getacl() should work on filesystems 298 * without the EA configured, add case EOPNOTSUPP here. 299 */ 300 case ENOATTR: 301 switch (ap->a_type) { 302 case ACL_TYPE_ACCESS: 303 /* 304 * Legitimately no ACL set on object, purely 305 * emulate it through the inode. These fields will 306 * be updated when the ACL is synchronized with 307 * the inode later. 308 */ 309 old->acl_cnt = 3; 310 old->acl_entry[0].ae_tag = ACL_USER_OBJ; 311 old->acl_entry[0].ae_id = ACL_UNDEFINED_ID; 312 old->acl_entry[0].ae_perm = ACL_PERM_NONE; 313 old->acl_entry[1].ae_tag = ACL_GROUP_OBJ; 314 old->acl_entry[1].ae_id = ACL_UNDEFINED_ID; 315 old->acl_entry[1].ae_perm = ACL_PERM_NONE; 316 old->acl_entry[2].ae_tag = ACL_OTHER; 317 old->acl_entry[2].ae_id = ACL_UNDEFINED_ID; 318 old->acl_entry[2].ae_perm = ACL_PERM_NONE; 319 break; 320 321 case ACL_TYPE_DEFAULT: 322 /* 323 * Unlike ACL_TYPE_ACCESS, there is no relationship 324 * between the inode contents and the ACL, and it is 325 * therefore possible for the request for the ACL 326 * to fail since the ACL is undefined. In this 327 * situation, return success and an empty ACL, 328 * as required by POSIX.1e. 329 */ 330 old->acl_cnt = 0; 331 break; 332 } 333 /* FALLTHROUGH */ 334 case 0: 335 error = acl_copy_oldacl_into_acl(old, ap->a_aclp); 336 if (error != 0) 337 break; 338 339 if (ap->a_type == ACL_TYPE_ACCESS) 340 ufs_sync_acl_from_inode(ip, ap->a_aclp); 341 default: 342 break; 343 } 344 345 free(old, M_ACL); 346 return (error); 347 } 348 349 int 350 ufs_getacl(ap) 351 struct vop_getacl_args /* { 352 struct vnode *vp; 353 acl_type_t type; 354 struct acl *aclp; 355 struct ucred *cred; 356 struct thread *td; 357 } */ *ap; 358 { 359 360 if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) 361 return (EOPNOTSUPP); 362 363 if (ap->a_type == ACL_TYPE_NFS4) 364 return (ufs_getacl_nfs4(ap)); 365 366 return (ufs_getacl_posix1e(ap)); 367 } 368 369 /* 370 * Set NFSv4 ACL without doing any access checking. This is required 371 * e.g. by the UFS code that implements ACL inheritance, or from 372 * ufs_vnops.c:ufs_chmod(), as some of the checks have to be skipped 373 * in that case, and others are redundant. 374 */ 375 int 376 ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) 377 { 378 int error; 379 mode_t mode; 380 struct inode *ip = VTOI(vp); 381 382 KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0, 383 ("invalid ACL passed to ufs_setacl_nfs4_internal")); 384 385 if (acl_nfs4_is_trivial(aclp, ip->i_uid)) { 386 error = vn_extattr_rm(vp, IO_NODELOCKED, 387 NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, td); 388 389 /* 390 * An attempt to remove ACL from a file that didn't have 391 * any extended entries is not an error. 392 */ 393 if (error == ENOATTR) 394 error = 0; 395 396 } else { 397 error = vn_extattr_set(vp, IO_NODELOCKED, 398 NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, 399 sizeof(*aclp), (char *) aclp, td); 400 } 401 402 /* 403 * Map lack of attribute definition in UFS_EXTATTR into lack of 404 * support for ACLs on the filesystem. 405 */ 406 if (error == ENOATTR) 407 return (EOPNOTSUPP); 408 409 if (error) 410 return (error); 411 412 mode = ip->i_mode; 413 414 acl_nfs4_sync_mode_from_acl(&mode, aclp); 415 416 ip->i_mode &= ACL_PRESERVE_MASK; 417 ip->i_mode |= mode; 418 DIP_SET(ip, i_mode, ip->i_mode); 419 ip->i_flag |= IN_CHANGE; 420 421 VN_KNOTE_UNLOCKED(vp, NOTE_ATTRIB); 422 423 return (0); 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 ip->i_flag |= IN_CHANGE; 592 } 593 594 VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB); 595 return (0); 596 } 597 598 int 599 ufs_setacl(ap) 600 struct vop_setacl_args /* { 601 struct vnode *vp; 602 acl_type_t type; 603 struct acl *aclp; 604 struct ucred *cred; 605 struct thread *td; 606 } */ *ap; 607 { 608 if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) 609 return (EOPNOTSUPP); 610 611 if (ap->a_type == ACL_TYPE_NFS4) 612 return (ufs_setacl_nfs4(ap)); 613 614 return (ufs_setacl_posix1e(ap)); 615 } 616 617 static int 618 ufs_aclcheck_nfs4(struct vop_aclcheck_args *ap) 619 { 620 int is_directory = 0; 621 622 if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) 623 return (EINVAL); 624 625 /* 626 * With NFSv4 ACLs, chmod(2) may need to add additional entries. 627 * Make sure it has enough room for that - splitting every entry 628 * into two and appending "canonical six" entries at the end. 629 */ 630 if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) 631 return (ENOSPC); 632 633 if (ap->a_vp->v_type == VDIR) 634 is_directory = 1; 635 636 return (acl_nfs4_check(ap->a_aclp, is_directory)); 637 } 638 639 static int 640 ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap) 641 { 642 643 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 644 return (EINVAL); 645 646 /* 647 * Verify we understand this type of ACL, and that it applies 648 * to this kind of object. 649 * Rely on the acl_posix1e_check() routine to verify the contents. 650 */ 651 switch(ap->a_type) { 652 case ACL_TYPE_ACCESS: 653 break; 654 655 case ACL_TYPE_DEFAULT: 656 if (ap->a_vp->v_type != VDIR) 657 return (EINVAL); 658 break; 659 660 default: 661 return (EINVAL); 662 } 663 664 if (ap->a_aclp->acl_cnt > OLDACL_MAX_ENTRIES) 665 return (EINVAL); 666 667 return (acl_posix1e_check(ap->a_aclp)); 668 } 669 670 /* 671 * Check the validity of an ACL for a file. 672 */ 673 int 674 ufs_aclcheck(ap) 675 struct vop_aclcheck_args /* { 676 struct vnode *vp; 677 acl_type_t type; 678 struct acl *aclp; 679 struct ucred *cred; 680 struct thread *td; 681 } */ *ap; 682 { 683 684 if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) 685 return (EOPNOTSUPP); 686 687 if (ap->a_type == ACL_TYPE_NFS4) 688 return (ufs_aclcheck_nfs4(ap)); 689 690 return (ufs_aclcheck_posix1e(ap)); 691 } 692 693 #endif /* !UFS_ACL */ 694