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 __FBSDID("$FreeBSD$"); 37 38 #include "opt_ufs.h" 39 #include "opt_quota.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/stat.h> 44 #include <sys/mount.h> 45 #include <sys/vnode.h> 46 #include <sys/types.h> 47 #include <sys/acl.h> 48 #include <sys/event.h> 49 #include <sys/extattr.h> 50 #include <sys/proc.h> 51 52 #include <ufs/ufs/quota.h> 53 #include <ufs/ufs/inode.h> 54 #include <ufs/ufs/acl.h> 55 #include <ufs/ufs/extattr.h> 56 #include <ufs/ufs/dir.h> 57 #include <ufs/ufs/ufsmount.h> 58 #include <ufs/ufs/ufs_extern.h> 59 #include <ufs/ffs/fs.h> 60 61 #ifdef UFS_ACL 62 63 FEATURE(ufs_acl, "ACL support for UFS"); 64 65 /* 66 * Synchronize an ACL and an inode by copying over appropriate inode fields 67 * to the passed ACL. Assumes an ACL that would satisfy acl_posix1e_check(), 68 * and may panic if not. 69 */ 70 void 71 ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl) 72 { 73 struct acl_entry *acl_mask, *acl_group_obj; 74 int i; 75 76 /* 77 * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK 78 * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is 79 * present. 80 */ 81 acl_mask = NULL; 82 acl_group_obj = NULL; 83 for (i = 0; i < acl->acl_cnt; i++) { 84 switch (acl->acl_entry[i].ae_tag) { 85 case ACL_USER_OBJ: 86 acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( 87 ACL_USER_OBJ, ip->i_mode); 88 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 89 break; 90 91 case ACL_GROUP_OBJ: 92 acl_group_obj = &acl->acl_entry[i]; 93 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 94 break; 95 96 case ACL_OTHER: 97 acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( 98 ACL_OTHER, ip->i_mode); 99 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 100 break; 101 102 case ACL_MASK: 103 acl_mask = &acl->acl_entry[i]; 104 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 105 break; 106 107 case ACL_USER: 108 case ACL_GROUP: 109 break; 110 111 default: 112 panic("ufs_sync_acl_from_inode(): bad ae_tag"); 113 } 114 } 115 116 if (acl_group_obj == NULL) 117 panic("ufs_sync_acl_from_inode(): no ACL_GROUP_OBJ"); 118 119 if (acl_mask == NULL) { 120 /* 121 * There is no ACL_MASK, so update ACL_GROUP_OBJ. 122 */ 123 acl_group_obj->ae_perm = acl_posix1e_mode_to_perm( 124 ACL_GROUP_OBJ, ip->i_mode); 125 } else { 126 /* 127 * Update the ACL_MASK entry instead of ACL_GROUP_OBJ. 128 */ 129 acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ, 130 ip->i_mode); 131 } 132 } 133 134 /* 135 * Calculate what the inode mode should look like based on an authoritative 136 * ACL for the inode. Replace only the fields in the inode that the ACL 137 * can represent. 138 */ 139 void 140 ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip) 141 { 142 143 ip->i_mode &= ACL_PRESERVE_MASK; 144 ip->i_mode |= acl_posix1e_acl_to_mode(acl); 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(ap) 356 struct vop_getacl_args /* { 357 struct vnode *vp; 358 acl_type_t type; 359 struct acl *aclp; 360 struct ucred *cred; 361 struct thread *td; 362 } */ *ap; 363 { 364 365 if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) 366 return (EOPNOTSUPP); 367 368 if (ap->a_type == ACL_TYPE_NFS4) 369 return (ufs_getacl_nfs4(ap)); 370 371 return (ufs_getacl_posix1e(ap)); 372 } 373 374 /* 375 * Set NFSv4 ACL without doing any access checking. This is required 376 * e.g. by the UFS code that implements ACL inheritance, or from 377 * ufs_vnops.c:ufs_chmod(), as some of the checks have to be skipped 378 * in that case, and others are redundant. 379 */ 380 int 381 ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) 382 { 383 int error; 384 mode_t mode; 385 struct inode *ip = VTOI(vp); 386 387 KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0, 388 ("invalid ACL passed to ufs_setacl_nfs4_internal")); 389 390 if (acl_nfs4_is_trivial(aclp, ip->i_uid)) { 391 error = vn_extattr_rm(vp, IO_NODELOCKED, 392 NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, td); 393 394 /* 395 * An attempt to remove ACL from a file that didn't have 396 * any extended entries is not an error. 397 */ 398 if (error == ENOATTR) 399 error = 0; 400 401 } else { 402 error = vn_extattr_set(vp, IO_NODELOCKED, 403 NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, 404 sizeof(*aclp), (char *) aclp, td); 405 } 406 407 /* 408 * Map lack of attribute definition in UFS_EXTATTR into lack of 409 * support for ACLs on the filesystem. 410 */ 411 if (error == ENOATTR) 412 return (EOPNOTSUPP); 413 414 if (error) 415 return (error); 416 417 mode = ip->i_mode; 418 419 acl_nfs4_sync_mode_from_acl(&mode, aclp); 420 421 ip->i_mode &= ACL_PRESERVE_MASK; 422 ip->i_mode |= mode; 423 DIP_SET(ip, i_mode, ip->i_mode); 424 ip->i_flag |= IN_CHANGE; 425 426 VN_KNOTE_UNLOCKED(vp, NOTE_ATTRIB); 427 428 error = UFS_UPDATE(vp, 0); 429 return (error); 430 } 431 432 static int 433 ufs_setacl_nfs4(struct vop_setacl_args *ap) 434 { 435 int error; 436 struct inode *ip = VTOI(ap->a_vp); 437 438 if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) 439 return (EINVAL); 440 441 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 442 return (EROFS); 443 444 if (ap->a_aclp == NULL) 445 return (EINVAL); 446 447 error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred, 448 ap->a_td); 449 if (error) 450 return (error); 451 452 /* 453 * Authorize the ACL operation. 454 */ 455 if (ip->i_flags & (IMMUTABLE | APPEND)) 456 return (EPERM); 457 458 /* 459 * Must hold VWRITE_ACL or have appropriate privilege. 460 */ 461 if ((error = VOP_ACCESSX(ap->a_vp, VWRITE_ACL, ap->a_cred, ap->a_td))) 462 return (error); 463 464 /* 465 * With NFSv4 ACLs, chmod(2) may need to add additional entries. 466 * Make sure it has enough room for that - splitting every entry 467 * into two and appending "canonical six" entries at the end. 468 */ 469 if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) 470 return (ENOSPC); 471 472 error = ufs_setacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td); 473 474 return (error); 475 } 476 477 /* 478 * Set the ACL on a file. 479 * 480 * As part of the ACL is stored in the inode, and the rest in an EA, 481 * this is necessarily non-atomic, and has complex authorization. 482 * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(), 483 * a fair number of different access checks may be required to go ahead 484 * with the operation at all. 485 */ 486 static int 487 ufs_setacl_posix1e(struct vop_setacl_args *ap) 488 { 489 struct inode *ip = VTOI(ap->a_vp); 490 int error; 491 struct oldacl *old; 492 493 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 494 return (EINVAL); 495 496 /* 497 * If this is a set operation rather than a delete operation, 498 * invoke VOP_ACLCHECK() on the passed ACL to determine if it is 499 * valid for the target. This will include a check on ap->a_type. 500 */ 501 if (ap->a_aclp != NULL) { 502 /* 503 * Set operation. 504 */ 505 error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, 506 ap->a_cred, ap->a_td); 507 if (error != 0) 508 return (error); 509 } else { 510 /* 511 * Delete operation. 512 * POSIX.1e allows only deletion of the default ACL on a 513 * directory (ACL_TYPE_DEFAULT). 514 */ 515 if (ap->a_type != ACL_TYPE_DEFAULT) 516 return (EINVAL); 517 if (ap->a_vp->v_type != VDIR) 518 return (ENOTDIR); 519 } 520 521 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 522 return (EROFS); 523 524 /* 525 * Authorize the ACL operation. 526 */ 527 if (ip->i_flags & (IMMUTABLE | APPEND)) 528 return (EPERM); 529 530 /* 531 * Must hold VADMIN (be file owner) or have appropriate privilege. 532 */ 533 if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td))) 534 return (error); 535 536 switch(ap->a_type) { 537 case ACL_TYPE_ACCESS: 538 old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); 539 error = acl_copy_acl_into_oldacl(ap->a_aclp, old); 540 if (error == 0) { 541 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, 542 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 543 POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*old), 544 (char *) old, ap->a_td); 545 } 546 free(old, M_ACL); 547 break; 548 549 case ACL_TYPE_DEFAULT: 550 if (ap->a_aclp == NULL) { 551 error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED, 552 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 553 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td); 554 /* 555 * Attempting to delete a non-present default ACL 556 * will return success for portability purposes. 557 * (TRIX) 558 * 559 * XXX: Note that since we can't distinguish 560 * "that EA is not supported" from "that EA is not 561 * defined", the success case here overlaps the 562 * the ENOATTR->EOPNOTSUPP case below. 563 */ 564 if (error == ENOATTR) 565 error = 0; 566 } else { 567 old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); 568 error = acl_copy_acl_into_oldacl(ap->a_aclp, old); 569 if (error == 0) { 570 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, 571 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 572 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, 573 sizeof(*old), (char *) old, ap->a_td); 574 } 575 free(old, M_ACL); 576 } 577 break; 578 579 default: 580 error = EINVAL; 581 } 582 /* 583 * Map lack of attribute definition in UFS_EXTATTR into lack of 584 * support for ACLs on the filesystem. 585 */ 586 if (error == ENOATTR) 587 return (EOPNOTSUPP); 588 if (error != 0) 589 return (error); 590 591 if (ap->a_type == ACL_TYPE_ACCESS) { 592 /* 593 * Now that the EA is successfully updated, update the 594 * inode and mark it as changed. 595 */ 596 ufs_sync_inode_from_acl(ap->a_aclp, ip); 597 ip->i_flag |= IN_CHANGE; 598 error = UFS_UPDATE(ap->a_vp, 0); 599 } 600 601 VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB); 602 return (error); 603 } 604 605 int 606 ufs_setacl(ap) 607 struct vop_setacl_args /* { 608 struct vnode *vp; 609 acl_type_t type; 610 struct acl *aclp; 611 struct ucred *cred; 612 struct thread *td; 613 } */ *ap; 614 { 615 if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) 616 return (EOPNOTSUPP); 617 618 if (ap->a_type == ACL_TYPE_NFS4) 619 return (ufs_setacl_nfs4(ap)); 620 621 return (ufs_setacl_posix1e(ap)); 622 } 623 624 static int 625 ufs_aclcheck_nfs4(struct vop_aclcheck_args *ap) 626 { 627 int is_directory = 0; 628 629 if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) 630 return (EINVAL); 631 632 /* 633 * With NFSv4 ACLs, chmod(2) may need to add additional entries. 634 * Make sure it has enough room for that - splitting every entry 635 * into two and appending "canonical six" entries at the end. 636 */ 637 if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) 638 return (ENOSPC); 639 640 if (ap->a_vp->v_type == VDIR) 641 is_directory = 1; 642 643 return (acl_nfs4_check(ap->a_aclp, is_directory)); 644 } 645 646 static int 647 ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap) 648 { 649 650 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 651 return (EINVAL); 652 653 /* 654 * Verify we understand this type of ACL, and that it applies 655 * to this kind of object. 656 * Rely on the acl_posix1e_check() routine to verify the contents. 657 */ 658 switch(ap->a_type) { 659 case ACL_TYPE_ACCESS: 660 break; 661 662 case ACL_TYPE_DEFAULT: 663 if (ap->a_vp->v_type != VDIR) 664 return (EINVAL); 665 break; 666 667 default: 668 return (EINVAL); 669 } 670 671 if (ap->a_aclp->acl_cnt > OLDACL_MAX_ENTRIES) 672 return (EINVAL); 673 674 return (acl_posix1e_check(ap->a_aclp)); 675 } 676 677 /* 678 * Check the validity of an ACL for a file. 679 */ 680 int 681 ufs_aclcheck(ap) 682 struct vop_aclcheck_args /* { 683 struct vnode *vp; 684 acl_type_t type; 685 struct acl *aclp; 686 struct ucred *cred; 687 struct thread *td; 688 } */ *ap; 689 { 690 691 if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) 692 return (EOPNOTSUPP); 693 694 if (ap->a_type == ACL_TYPE_NFS4) 695 return (ufs_aclcheck_nfs4(ap)); 696 697 return (ufs_aclcheck_posix1e(ap)); 698 } 699 700 #endif /* !UFS_ACL */ 701