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