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