1 /* $NetBSD: genfs_vnops.c,v 1.209 2020/08/07 18:14:21 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 1982, 1986, 1989, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. Neither the name of the University nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 * 57 */ 58 59 #include <sys/cdefs.h> 60 __KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.209 2020/08/07 18:14:21 christos Exp $"); 61 62 #include <sys/param.h> 63 #include <sys/systm.h> 64 #include <sys/proc.h> 65 #include <sys/kernel.h> 66 #include <sys/mount.h> 67 #include <sys/fstrans.h> 68 #include <sys/namei.h> 69 #include <sys/vnode_impl.h> 70 #include <sys/fcntl.h> 71 #include <sys/kmem.h> 72 #include <sys/poll.h> 73 #include <sys/mman.h> 74 #include <sys/file.h> 75 #include <sys/kauth.h> 76 #include <sys/stat.h> 77 #include <sys/extattr.h> 78 79 #include <miscfs/genfs/genfs.h> 80 #include <miscfs/genfs/genfs_node.h> 81 #include <miscfs/specfs/specdev.h> 82 83 #include <uvm/uvm.h> 84 #include <uvm/uvm_pager.h> 85 86 static void filt_genfsdetach(struct knote *); 87 static int filt_genfsread(struct knote *, long); 88 static int filt_genfsvnode(struct knote *, long); 89 90 int 91 genfs_poll(void *v) 92 { 93 struct vop_poll_args /* { 94 struct vnode *a_vp; 95 int a_events; 96 struct lwp *a_l; 97 } */ *ap = v; 98 99 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 100 } 101 102 int 103 genfs_seek(void *v) 104 { 105 struct vop_seek_args /* { 106 struct vnode *a_vp; 107 off_t a_oldoff; 108 off_t a_newoff; 109 kauth_cred_t cred; 110 } */ *ap = v; 111 112 if (ap->a_newoff < 0) 113 return (EINVAL); 114 115 return (0); 116 } 117 118 int 119 genfs_abortop(void *v) 120 { 121 struct vop_abortop_args /* { 122 struct vnode *a_dvp; 123 struct componentname *a_cnp; 124 } */ *ap = v; 125 126 (void)ap; 127 128 return (0); 129 } 130 131 int 132 genfs_fcntl(void *v) 133 { 134 struct vop_fcntl_args /* { 135 struct vnode *a_vp; 136 u_int a_command; 137 void *a_data; 138 int a_fflag; 139 kauth_cred_t a_cred; 140 struct lwp *a_l; 141 } */ *ap = v; 142 143 if (ap->a_command == F_SETFL) 144 return (0); 145 else 146 return (EOPNOTSUPP); 147 } 148 149 /*ARGSUSED*/ 150 int 151 genfs_badop(void *v) 152 { 153 154 panic("genfs: bad op"); 155 } 156 157 /*ARGSUSED*/ 158 int 159 genfs_nullop(void *v) 160 { 161 162 return (0); 163 } 164 165 /*ARGSUSED*/ 166 int 167 genfs_einval(void *v) 168 { 169 170 return (EINVAL); 171 } 172 173 /* 174 * Called when an fs doesn't support a particular vop. 175 * This takes care to vrele, vput, or vunlock passed in vnodes 176 * and calls VOP_ABORTOP for a componentname (in non-rename VOP). 177 */ 178 int 179 genfs_eopnotsupp(void *v) 180 { 181 struct vop_generic_args /* 182 struct vnodeop_desc *a_desc; 183 / * other random data follows, presumably * / 184 } */ *ap = v; 185 struct vnodeop_desc *desc = ap->a_desc; 186 struct vnode *vp, *vp_last = NULL; 187 int flags, i, j, offset_cnp, offset_vp; 188 189 KASSERT(desc->vdesc_offset != VOP_LOOKUP_DESCOFFSET); 190 KASSERT(desc->vdesc_offset != VOP_ABORTOP_DESCOFFSET); 191 192 /* 193 * Abort any componentname that lookup potentially left state in. 194 * 195 * As is logical, componentnames for VOP_RENAME are handled by 196 * the caller of VOP_RENAME. Yay, rename! 197 */ 198 if (desc->vdesc_offset != VOP_RENAME_DESCOFFSET && 199 (offset_vp = desc->vdesc_vp_offsets[0]) != VDESC_NO_OFFSET && 200 (offset_cnp = desc->vdesc_componentname_offset) != VDESC_NO_OFFSET){ 201 struct componentname *cnp; 202 struct vnode *dvp; 203 204 dvp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap); 205 cnp = *VOPARG_OFFSETTO(struct componentname **, offset_cnp, ap); 206 207 VOP_ABORTOP(dvp, cnp); 208 } 209 210 flags = desc->vdesc_flags; 211 for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) { 212 if ((offset_vp = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET) 213 break; /* stop at end of list */ 214 if ((j = flags & VDESC_VP0_WILLPUT)) { 215 vp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap); 216 217 /* Skip if NULL */ 218 if (!vp) 219 continue; 220 221 switch (j) { 222 case VDESC_VP0_WILLPUT: 223 /* Check for dvp == vp cases */ 224 if (vp == vp_last) 225 vrele(vp); 226 else { 227 vput(vp); 228 vp_last = vp; 229 } 230 break; 231 case VDESC_VP0_WILLRELE: 232 vrele(vp); 233 break; 234 } 235 } 236 } 237 238 return (EOPNOTSUPP); 239 } 240 241 /*ARGSUSED*/ 242 int 243 genfs_ebadf(void *v) 244 { 245 246 return (EBADF); 247 } 248 249 /* ARGSUSED */ 250 int 251 genfs_enoioctl(void *v) 252 { 253 254 return (EPASSTHROUGH); 255 } 256 257 258 /* 259 * Eliminate all activity associated with the requested vnode 260 * and with all vnodes aliased to the requested vnode. 261 */ 262 int 263 genfs_revoke(void *v) 264 { 265 struct vop_revoke_args /* { 266 struct vnode *a_vp; 267 int a_flags; 268 } */ *ap = v; 269 270 #ifdef DIAGNOSTIC 271 if ((ap->a_flags & REVOKEALL) == 0) 272 panic("genfs_revoke: not revokeall"); 273 #endif 274 vrevoke(ap->a_vp); 275 return (0); 276 } 277 278 /* 279 * Lock the node (for deadfs). 280 */ 281 int 282 genfs_deadlock(void *v) 283 { 284 struct vop_lock_args /* { 285 struct vnode *a_vp; 286 int a_flags; 287 } */ *ap = v; 288 vnode_t *vp = ap->a_vp; 289 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 290 int flags = ap->a_flags; 291 krw_t op; 292 293 if (! ISSET(flags, LK_RETRY)) 294 return ENOENT; 295 296 if (ISSET(flags, LK_DOWNGRADE)) { 297 rw_downgrade(&vip->vi_lock); 298 } else if (ISSET(flags, LK_UPGRADE)) { 299 KASSERT(ISSET(flags, LK_NOWAIT)); 300 if (!rw_tryupgrade(&vip->vi_lock)) { 301 return EBUSY; 302 } 303 } else if ((flags & (LK_EXCLUSIVE | LK_SHARED)) != 0) { 304 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER); 305 if (ISSET(flags, LK_NOWAIT)) { 306 if (!rw_tryenter(&vip->vi_lock, op)) 307 return EBUSY; 308 } else { 309 rw_enter(&vip->vi_lock, op); 310 } 311 } 312 VSTATE_ASSERT_UNLOCKED(vp, VS_RECLAIMED); 313 return 0; 314 } 315 316 /* 317 * Unlock the node (for deadfs). 318 */ 319 int 320 genfs_deadunlock(void *v) 321 { 322 struct vop_unlock_args /* { 323 struct vnode *a_vp; 324 } */ *ap = v; 325 vnode_t *vp = ap->a_vp; 326 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 327 328 rw_exit(&vip->vi_lock); 329 330 return 0; 331 } 332 333 /* 334 * Lock the node. 335 */ 336 int 337 genfs_lock(void *v) 338 { 339 struct vop_lock_args /* { 340 struct vnode *a_vp; 341 int a_flags; 342 } */ *ap = v; 343 vnode_t *vp = ap->a_vp; 344 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 345 int flags = ap->a_flags; 346 krw_t op; 347 348 if (ISSET(flags, LK_DOWNGRADE)) { 349 rw_downgrade(&vip->vi_lock); 350 } else if (ISSET(flags, LK_UPGRADE)) { 351 KASSERT(ISSET(flags, LK_NOWAIT)); 352 if (!rw_tryupgrade(&vip->vi_lock)) { 353 return EBUSY; 354 } 355 } else if ((flags & (LK_EXCLUSIVE | LK_SHARED)) != 0) { 356 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER); 357 if (ISSET(flags, LK_NOWAIT)) { 358 if (!rw_tryenter(&vip->vi_lock, op)) 359 return EBUSY; 360 } else { 361 rw_enter(&vip->vi_lock, op); 362 } 363 } 364 VSTATE_ASSERT_UNLOCKED(vp, VS_ACTIVE); 365 return 0; 366 } 367 368 /* 369 * Unlock the node. 370 */ 371 int 372 genfs_unlock(void *v) 373 { 374 struct vop_unlock_args /* { 375 struct vnode *a_vp; 376 } */ *ap = v; 377 vnode_t *vp = ap->a_vp; 378 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 379 380 rw_exit(&vip->vi_lock); 381 382 return 0; 383 } 384 385 /* 386 * Return whether or not the node is locked. 387 */ 388 int 389 genfs_islocked(void *v) 390 { 391 struct vop_islocked_args /* { 392 struct vnode *a_vp; 393 } */ *ap = v; 394 vnode_t *vp = ap->a_vp; 395 vnode_impl_t *vip = VNODE_TO_VIMPL(vp); 396 397 if (rw_write_held(&vip->vi_lock)) 398 return LK_EXCLUSIVE; 399 400 if (rw_read_held(&vip->vi_lock)) 401 return LK_SHARED; 402 403 return 0; 404 } 405 406 /* 407 * Stubs to use when there is no locking to be done on the underlying object. 408 */ 409 int 410 genfs_nolock(void *v) 411 { 412 413 return (0); 414 } 415 416 int 417 genfs_nounlock(void *v) 418 { 419 420 return (0); 421 } 422 423 int 424 genfs_noislocked(void *v) 425 { 426 427 return (0); 428 } 429 430 int 431 genfs_mmap(void *v) 432 { 433 434 return (0); 435 } 436 437 /* 438 * VOP_PUTPAGES() for vnodes which never have pages. 439 */ 440 441 int 442 genfs_null_putpages(void *v) 443 { 444 struct vop_putpages_args /* { 445 struct vnode *a_vp; 446 voff_t a_offlo; 447 voff_t a_offhi; 448 int a_flags; 449 } */ *ap = v; 450 struct vnode *vp = ap->a_vp; 451 452 KASSERT(vp->v_uobj.uo_npages == 0); 453 rw_exit(vp->v_uobj.vmobjlock); 454 return (0); 455 } 456 457 void 458 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops) 459 { 460 struct genfs_node *gp = VTOG(vp); 461 462 rw_init(&gp->g_glock); 463 gp->g_op = ops; 464 } 465 466 void 467 genfs_node_destroy(struct vnode *vp) 468 { 469 struct genfs_node *gp = VTOG(vp); 470 471 rw_destroy(&gp->g_glock); 472 } 473 474 void 475 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 476 { 477 int bsize; 478 479 bsize = 1 << vp->v_mount->mnt_fs_bshift; 480 *eobp = (size + bsize - 1) & ~(bsize - 1); 481 } 482 483 static void 484 filt_genfsdetach(struct knote *kn) 485 { 486 struct vnode *vp = (struct vnode *)kn->kn_hook; 487 488 mutex_enter(vp->v_interlock); 489 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext); 490 mutex_exit(vp->v_interlock); 491 } 492 493 static int 494 filt_genfsread(struct knote *kn, long hint) 495 { 496 struct vnode *vp = (struct vnode *)kn->kn_hook; 497 int rv; 498 499 /* 500 * filesystem is gone, so set the EOF flag and schedule 501 * the knote for deletion. 502 */ 503 switch (hint) { 504 case NOTE_REVOKE: 505 KASSERT(mutex_owned(vp->v_interlock)); 506 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 507 return (1); 508 case 0: 509 mutex_enter(vp->v_interlock); 510 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 511 rv = (kn->kn_data != 0); 512 mutex_exit(vp->v_interlock); 513 return rv; 514 default: 515 KASSERT(mutex_owned(vp->v_interlock)); 516 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 517 return (kn->kn_data != 0); 518 } 519 } 520 521 static int 522 filt_genfswrite(struct knote *kn, long hint) 523 { 524 struct vnode *vp = (struct vnode *)kn->kn_hook; 525 526 /* 527 * filesystem is gone, so set the EOF flag and schedule 528 * the knote for deletion. 529 */ 530 switch (hint) { 531 case NOTE_REVOKE: 532 KASSERT(mutex_owned(vp->v_interlock)); 533 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 534 return (1); 535 case 0: 536 mutex_enter(vp->v_interlock); 537 kn->kn_data = 0; 538 mutex_exit(vp->v_interlock); 539 return 1; 540 default: 541 KASSERT(mutex_owned(vp->v_interlock)); 542 kn->kn_data = 0; 543 return 1; 544 } 545 } 546 547 static int 548 filt_genfsvnode(struct knote *kn, long hint) 549 { 550 struct vnode *vp = (struct vnode *)kn->kn_hook; 551 int fflags; 552 553 switch (hint) { 554 case NOTE_REVOKE: 555 KASSERT(mutex_owned(vp->v_interlock)); 556 kn->kn_flags |= EV_EOF; 557 if ((kn->kn_sfflags & hint) != 0) 558 kn->kn_fflags |= hint; 559 return (1); 560 case 0: 561 mutex_enter(vp->v_interlock); 562 fflags = kn->kn_fflags; 563 mutex_exit(vp->v_interlock); 564 break; 565 default: 566 KASSERT(mutex_owned(vp->v_interlock)); 567 if ((kn->kn_sfflags & hint) != 0) 568 kn->kn_fflags |= hint; 569 fflags = kn->kn_fflags; 570 break; 571 } 572 573 return (fflags != 0); 574 } 575 576 static const struct filterops genfsread_filtops = { 577 .f_isfd = 1, 578 .f_attach = NULL, 579 .f_detach = filt_genfsdetach, 580 .f_event = filt_genfsread, 581 }; 582 583 static const struct filterops genfswrite_filtops = { 584 .f_isfd = 1, 585 .f_attach = NULL, 586 .f_detach = filt_genfsdetach, 587 .f_event = filt_genfswrite, 588 }; 589 590 static const struct filterops genfsvnode_filtops = { 591 .f_isfd = 1, 592 .f_attach = NULL, 593 .f_detach = filt_genfsdetach, 594 .f_event = filt_genfsvnode, 595 }; 596 597 int 598 genfs_kqfilter(void *v) 599 { 600 struct vop_kqfilter_args /* { 601 struct vnode *a_vp; 602 struct knote *a_kn; 603 } */ *ap = v; 604 struct vnode *vp; 605 struct knote *kn; 606 607 vp = ap->a_vp; 608 kn = ap->a_kn; 609 switch (kn->kn_filter) { 610 case EVFILT_READ: 611 kn->kn_fop = &genfsread_filtops; 612 break; 613 case EVFILT_WRITE: 614 kn->kn_fop = &genfswrite_filtops; 615 break; 616 case EVFILT_VNODE: 617 kn->kn_fop = &genfsvnode_filtops; 618 break; 619 default: 620 return (EINVAL); 621 } 622 623 kn->kn_hook = vp; 624 625 mutex_enter(vp->v_interlock); 626 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext); 627 mutex_exit(vp->v_interlock); 628 629 return (0); 630 } 631 632 void 633 genfs_node_wrlock(struct vnode *vp) 634 { 635 struct genfs_node *gp = VTOG(vp); 636 637 rw_enter(&gp->g_glock, RW_WRITER); 638 } 639 640 void 641 genfs_node_rdlock(struct vnode *vp) 642 { 643 struct genfs_node *gp = VTOG(vp); 644 645 rw_enter(&gp->g_glock, RW_READER); 646 } 647 648 int 649 genfs_node_rdtrylock(struct vnode *vp) 650 { 651 struct genfs_node *gp = VTOG(vp); 652 653 return rw_tryenter(&gp->g_glock, RW_READER); 654 } 655 656 void 657 genfs_node_unlock(struct vnode *vp) 658 { 659 struct genfs_node *gp = VTOG(vp); 660 661 rw_exit(&gp->g_glock); 662 } 663 664 int 665 genfs_node_wrlocked(struct vnode *vp) 666 { 667 struct genfs_node *gp = VTOG(vp); 668 669 return rw_write_held(&gp->g_glock); 670 } 671 672 static int 673 groupmember(gid_t gid, kauth_cred_t cred) 674 { 675 int ismember; 676 int error = kauth_cred_ismember_gid(cred, gid, &ismember); 677 if (error) 678 return error; 679 if (kauth_cred_getegid(cred) == gid || ismember) 680 return 0; 681 return -1; 682 } 683 684 /* 685 * Common filesystem object access control check routine. Accepts a 686 * vnode, cred, uid, gid, mode, acl, requested access mode. 687 * Returns 0 on success, or an errno on failure. 688 */ 689 int 690 genfs_can_access(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, gid_t file_gid, 691 mode_t file_mode, struct acl *acl, accmode_t accmode) 692 { 693 accmode_t dac_granted; 694 int error; 695 696 KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0); 697 KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE)); 698 699 /* 700 * Look for a normal, non-privileged way to access the file/directory 701 * as requested. If it exists, go with that. 702 */ 703 704 dac_granted = 0; 705 706 /* Check the owner. */ 707 if (kauth_cred_geteuid(cred) == file_uid) { 708 dac_granted |= VADMIN; 709 if (file_mode & S_IXUSR) 710 dac_granted |= VEXEC; 711 if (file_mode & S_IRUSR) 712 dac_granted |= VREAD; 713 if (file_mode & S_IWUSR) 714 dac_granted |= (VWRITE | VAPPEND); 715 716 goto privchk; 717 } 718 719 /* Otherwise, check the groups (first match) */ 720 /* Otherwise, check the groups. */ 721 error = groupmember(file_gid, cred); 722 if (error > 0) 723 return error; 724 if (error == 0) { 725 if (file_mode & S_IXGRP) 726 dac_granted |= VEXEC; 727 if (file_mode & S_IRGRP) 728 dac_granted |= VREAD; 729 if (file_mode & S_IWGRP) 730 dac_granted |= (VWRITE | VAPPEND); 731 732 goto privchk; 733 } 734 735 /* Otherwise, check everyone else. */ 736 if (file_mode & S_IXOTH) 737 dac_granted |= VEXEC; 738 if (file_mode & S_IROTH) 739 dac_granted |= VREAD; 740 if (file_mode & S_IWOTH) 741 dac_granted |= (VWRITE | VAPPEND); 742 743 privchk: 744 if ((accmode & dac_granted) == accmode) 745 return 0; 746 747 return (accmode & VADMIN) ? EPERM : EACCES; 748 } 749 750 /* 751 * Implement a version of genfs_can_access() that understands POSIX.1e ACL 752 * semantics; 753 * the access ACL has already been prepared for evaluation by the file system 754 * and is passed via 'uid', 'gid', and 'acl'. Return 0 on success, else an 755 * errno value. 756 */ 757 int 758 genfs_can_access_acl_posix1e(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, 759 gid_t file_gid, mode_t file_mode, struct acl *acl, accmode_t accmode) 760 { 761 struct acl_entry *acl_other, *acl_mask; 762 accmode_t dac_granted; 763 accmode_t acl_mask_granted; 764 int group_matched, i; 765 int error; 766 767 KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0); 768 KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE)); 769 770 /* 771 * The owner matches if the effective uid associated with the 772 * credential matches that of the ACL_USER_OBJ entry. While we're 773 * doing the first scan, also cache the location of the ACL_MASK and 774 * ACL_OTHER entries, preventing some future iterations. 775 */ 776 acl_mask = acl_other = NULL; 777 for (i = 0; i < acl->acl_cnt; i++) { 778 struct acl_entry *ae = &acl->acl_entry[i]; 779 switch (ae->ae_tag) { 780 case ACL_USER_OBJ: 781 if (kauth_cred_geteuid(cred) != file_uid) 782 break; 783 dac_granted = 0; 784 dac_granted |= VADMIN; 785 if (ae->ae_perm & ACL_EXECUTE) 786 dac_granted |= VEXEC; 787 if (ae->ae_perm & ACL_READ) 788 dac_granted |= VREAD; 789 if (ae->ae_perm & ACL_WRITE) 790 dac_granted |= (VWRITE | VAPPEND); 791 goto out; 792 793 case ACL_MASK: 794 acl_mask = ae; 795 break; 796 797 case ACL_OTHER: 798 acl_other = ae; 799 break; 800 801 default: 802 break; 803 } 804 } 805 806 /* 807 * An ACL_OTHER entry should always exist in a valid access ACL. If 808 * it doesn't, then generate a serious failure. For now, this means 809 * a debugging message and EPERM, but in the future should probably 810 * be a panic. 811 */ 812 if (acl_other == NULL) { 813 /* 814 * XXX This should never happen 815 */ 816 printf("%s: ACL_OTHER missing\n", __func__); 817 return EPERM; 818 } 819 820 /* 821 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are 822 * masked by an ACL_MASK entry, if any. As such, first identify the 823 * ACL_MASK field, then iterate through identifying potential user 824 * matches, then group matches. If there is no ACL_MASK, assume that 825 * the mask allows all requests to succeed. 826 */ 827 if (acl_mask != NULL) { 828 acl_mask_granted = 0; 829 if (acl_mask->ae_perm & ACL_EXECUTE) 830 acl_mask_granted |= VEXEC; 831 if (acl_mask->ae_perm & ACL_READ) 832 acl_mask_granted |= VREAD; 833 if (acl_mask->ae_perm & ACL_WRITE) 834 acl_mask_granted |= (VWRITE | VAPPEND); 835 } else 836 acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND; 837 838 /* 839 * Check ACL_USER ACL entries. There will either be one or no 840 * matches; if there is one, we accept or rejected based on the 841 * match; otherwise, we continue on to groups. 842 */ 843 for (i = 0; i < acl->acl_cnt; i++) { 844 struct acl_entry *ae = &acl->acl_entry[i]; 845 switch (ae->ae_tag) { 846 case ACL_USER: 847 if (kauth_cred_geteuid(cred) != ae->ae_id) 848 break; 849 dac_granted = 0; 850 if (ae->ae_perm & ACL_EXECUTE) 851 dac_granted |= VEXEC; 852 if (ae->ae_perm & ACL_READ) 853 dac_granted |= VREAD; 854 if (ae->ae_perm & ACL_WRITE) 855 dac_granted |= (VWRITE | VAPPEND); 856 dac_granted &= acl_mask_granted; 857 goto out; 858 } 859 } 860 861 /* 862 * Group match is best-match, not first-match, so find a "best" 863 * match. Iterate across, testing each potential group match. Make 864 * sure we keep track of whether we found a match or not, so that we 865 * know if we should try again with any available privilege, or if we 866 * should move on to ACL_OTHER. 867 */ 868 group_matched = 0; 869 for (i = 0; i < acl->acl_cnt; i++) { 870 struct acl_entry *ae = &acl->acl_entry[i]; 871 switch (ae->ae_tag) { 872 case ACL_GROUP_OBJ: 873 error = groupmember(file_gid, cred); 874 if (error > 0) 875 return error; 876 if (error) 877 break; 878 dac_granted = 0; 879 if (ae->ae_perm & ACL_EXECUTE) 880 dac_granted |= VEXEC; 881 if (ae->ae_perm & ACL_READ) 882 dac_granted |= VREAD; 883 if (ae->ae_perm & ACL_WRITE) 884 dac_granted |= (VWRITE | VAPPEND); 885 dac_granted &= acl_mask_granted; 886 887 if ((accmode & dac_granted) == accmode) 888 return 0; 889 890 group_matched = 1; 891 break; 892 893 case ACL_GROUP: 894 error = groupmember(ae->ae_id, cred); 895 if (error > 0) 896 return error; 897 if (error) 898 break; 899 dac_granted = 0; 900 if (ae->ae_perm & ACL_EXECUTE) 901 dac_granted |= VEXEC; 902 if (ae->ae_perm & ACL_READ) 903 dac_granted |= VREAD; 904 if (ae->ae_perm & ACL_WRITE) 905 dac_granted |= (VWRITE | VAPPEND); 906 dac_granted &= acl_mask_granted; 907 908 if ((accmode & dac_granted) == accmode) 909 return 0; 910 911 group_matched = 1; 912 break; 913 914 default: 915 break; 916 } 917 } 918 919 if (group_matched == 1) { 920 /* 921 * There was a match, but it did not grant rights via pure 922 * DAC. Try again, this time with privilege. 923 */ 924 for (i = 0; i < acl->acl_cnt; i++) { 925 struct acl_entry *ae = &acl->acl_entry[i]; 926 switch (ae->ae_tag) { 927 case ACL_GROUP_OBJ: 928 error = groupmember(file_gid, cred); 929 if (error > 0) 930 return error; 931 if (error) 932 break; 933 dac_granted = 0; 934 if (ae->ae_perm & ACL_EXECUTE) 935 dac_granted |= VEXEC; 936 if (ae->ae_perm & ACL_READ) 937 dac_granted |= VREAD; 938 if (ae->ae_perm & ACL_WRITE) 939 dac_granted |= (VWRITE | VAPPEND); 940 dac_granted &= acl_mask_granted; 941 goto out; 942 943 case ACL_GROUP: 944 error = groupmember(ae->ae_id, cred); 945 if (error > 0) 946 return error; 947 if (error) 948 break; 949 dac_granted = 0; 950 if (ae->ae_perm & ACL_EXECUTE) 951 dac_granted |= VEXEC; 952 if (ae->ae_perm & ACL_READ) 953 dac_granted |= VREAD; 954 if (ae->ae_perm & ACL_WRITE) 955 dac_granted |= (VWRITE | VAPPEND); 956 dac_granted &= acl_mask_granted; 957 958 goto out; 959 default: 960 break; 961 } 962 } 963 /* 964 * Even with privilege, group membership was not sufficient. 965 * Return failure. 966 */ 967 dac_granted = 0; 968 goto out; 969 } 970 971 /* 972 * Fall back on ACL_OTHER. ACL_MASK is not applied to ACL_OTHER. 973 */ 974 dac_granted = 0; 975 if (acl_other->ae_perm & ACL_EXECUTE) 976 dac_granted |= VEXEC; 977 if (acl_other->ae_perm & ACL_READ) 978 dac_granted |= VREAD; 979 if (acl_other->ae_perm & ACL_WRITE) 980 dac_granted |= (VWRITE | VAPPEND); 981 982 out: 983 if ((accmode & dac_granted) == accmode) 984 return 0; 985 return (accmode & VADMIN) ? EPERM : EACCES; 986 } 987 988 static struct { 989 accmode_t accmode; 990 int mask; 991 } accmode2mask[] = { 992 { VREAD, ACL_READ_DATA }, 993 { VWRITE, ACL_WRITE_DATA }, 994 { VAPPEND, ACL_APPEND_DATA }, 995 { VEXEC, ACL_EXECUTE }, 996 { VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS }, 997 { VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS }, 998 { VDELETE_CHILD, ACL_DELETE_CHILD }, 999 { VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES }, 1000 { VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES }, 1001 { VDELETE, ACL_DELETE }, 1002 { VREAD_ACL, ACL_READ_ACL }, 1003 { VWRITE_ACL, ACL_WRITE_ACL }, 1004 { VWRITE_OWNER, ACL_WRITE_OWNER }, 1005 { VSYNCHRONIZE, ACL_SYNCHRONIZE }, 1006 { 0, 0 }, 1007 }; 1008 1009 static int 1010 _access_mask_from_accmode(accmode_t accmode) 1011 { 1012 int access_mask = 0, i; 1013 1014 for (i = 0; accmode2mask[i].accmode != 0; i++) { 1015 if (accmode & accmode2mask[i].accmode) 1016 access_mask |= accmode2mask[i].mask; 1017 } 1018 1019 /* 1020 * VAPPEND is just a modifier for VWRITE; if the caller asked 1021 * for 'VAPPEND | VWRITE', we want to check for ACL_APPEND_DATA only. 1022 */ 1023 if (access_mask & ACL_APPEND_DATA) 1024 access_mask &= ~ACL_WRITE_DATA; 1025 1026 return (access_mask); 1027 } 1028 1029 /* 1030 * Return 0, iff access is allowed, 1 otherwise. 1031 */ 1032 static int 1033 _acl_denies(const struct acl *aclp, int access_mask, kauth_cred_t cred, 1034 int file_uid, int file_gid, int *denied_explicitly) 1035 { 1036 int i, error; 1037 const struct acl_entry *ae; 1038 1039 if (denied_explicitly != NULL) 1040 *denied_explicitly = 0; 1041 1042 KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES); 1043 1044 for (i = 0; i < aclp->acl_cnt; i++) { 1045 ae = &(aclp->acl_entry[i]); 1046 1047 if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 1048 ae->ae_entry_type != ACL_ENTRY_TYPE_DENY) 1049 continue; 1050 if (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY) 1051 continue; 1052 switch (ae->ae_tag) { 1053 case ACL_USER_OBJ: 1054 if (kauth_cred_geteuid(cred) != file_uid) 1055 continue; 1056 break; 1057 case ACL_USER: 1058 if (kauth_cred_geteuid(cred) != ae->ae_id) 1059 continue; 1060 break; 1061 case ACL_GROUP_OBJ: 1062 error = groupmember(file_gid, cred); 1063 if (error > 0) 1064 return error; 1065 if (error != 0) 1066 continue; 1067 break; 1068 case ACL_GROUP: 1069 error = groupmember(ae->ae_id, cred); 1070 if (error > 0) 1071 return error; 1072 if (error != 0) 1073 continue; 1074 break; 1075 default: 1076 KASSERT(ae->ae_tag == ACL_EVERYONE); 1077 } 1078 1079 if (ae->ae_entry_type == ACL_ENTRY_TYPE_DENY) { 1080 if (ae->ae_perm & access_mask) { 1081 if (denied_explicitly != NULL) 1082 *denied_explicitly = 1; 1083 return (1); 1084 } 1085 } 1086 1087 access_mask &= ~(ae->ae_perm); 1088 if (access_mask == 0) 1089 return (0); 1090 } 1091 1092 if (access_mask == 0) 1093 return (0); 1094 1095 return (1); 1096 } 1097 1098 int 1099 genfs_can_access_acl_nfs4(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, 1100 gid_t file_gid, mode_t file_mode, struct acl *aclp, accmode_t accmode) 1101 { 1102 int denied, explicitly_denied, access_mask, is_directory, 1103 must_be_owner = 0; 1104 file_mode = 0; 1105 1106 KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND | 1107 VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS | 1108 VDELETE_CHILD | VREAD_ATTRIBUTES | VWRITE_ATTRIBUTES | VDELETE | 1109 VREAD_ACL | VWRITE_ACL | VWRITE_OWNER | VSYNCHRONIZE)) == 0); 1110 KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE)); 1111 1112 if (accmode & VADMIN) 1113 must_be_owner = 1; 1114 1115 /* 1116 * Ignore VSYNCHRONIZE permission. 1117 */ 1118 accmode &= ~VSYNCHRONIZE; 1119 1120 access_mask = _access_mask_from_accmode(accmode); 1121 1122 if (vp && vp->v_type == VDIR) 1123 is_directory = 1; 1124 else 1125 is_directory = 0; 1126 1127 /* 1128 * File owner is always allowed to read and write the ACL 1129 * and basic attributes. This is to prevent a situation 1130 * where user would change ACL in a way that prevents him 1131 * from undoing the change. 1132 */ 1133 if (kauth_cred_geteuid(cred) == file_uid) 1134 access_mask &= ~(ACL_READ_ACL | ACL_WRITE_ACL | 1135 ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES); 1136 1137 /* 1138 * Ignore append permission for regular files; use write 1139 * permission instead. 1140 */ 1141 if (!is_directory && (access_mask & ACL_APPEND_DATA)) { 1142 access_mask &= ~ACL_APPEND_DATA; 1143 access_mask |= ACL_WRITE_DATA; 1144 } 1145 1146 denied = _acl_denies(aclp, access_mask, cred, file_uid, file_gid, 1147 &explicitly_denied); 1148 1149 if (must_be_owner) { 1150 if (kauth_cred_geteuid(cred) != file_uid) 1151 denied = EPERM; 1152 } 1153 1154 /* 1155 * For VEXEC, ensure that at least one execute bit is set for 1156 * non-directories. We have to check the mode here to stay 1157 * consistent with execve(2). See the test in 1158 * exec_check_permissions(). 1159 */ 1160 __acl_nfs4_sync_mode_from_acl(&file_mode, aclp); 1161 if (!denied && !is_directory && (accmode & VEXEC) && 1162 (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) 1163 denied = EACCES; 1164 1165 if (!denied) 1166 return (0); 1167 1168 /* 1169 * Access failed. Iff it was not denied explicitly and 1170 * VEXPLICIT_DENY flag was specified, allow access. 1171 */ 1172 if ((accmode & VEXPLICIT_DENY) && explicitly_denied == 0) 1173 return (0); 1174 1175 accmode &= ~VEXPLICIT_DENY; 1176 1177 if (accmode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE)) 1178 denied = EPERM; 1179 else 1180 denied = EACCES; 1181 1182 return (denied); 1183 } 1184 1185 /* 1186 * Common routine to check if chmod() is allowed. 1187 * 1188 * Policy: 1189 * - You must own the file, and 1190 * - You must not set the "sticky" bit (meaningless, see chmod(2)) 1191 * - You must be a member of the group if you're trying to set the 1192 * SGIDf bit 1193 * 1194 * vp - vnode of the file-system object 1195 * cred - credentials of the invoker 1196 * cur_uid, cur_gid - current uid/gid of the file-system object 1197 * new_mode - new mode for the file-system object 1198 * 1199 * Returns 0 if the change is allowed, or an error value otherwise. 1200 */ 1201 int 1202 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 1203 gid_t cur_gid, mode_t new_mode) 1204 { 1205 int error; 1206 1207 /* 1208 * To modify the permissions on a file, must possess VADMIN 1209 * for that file. 1210 */ 1211 if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred)) != 0) 1212 return (error); 1213 1214 /* 1215 * Unprivileged users can't set the sticky bit on files. 1216 */ 1217 if ((vp->v_type != VDIR) && (new_mode & S_ISTXT)) 1218 return (EFTYPE); 1219 1220 /* 1221 * If the invoker is trying to set the SGID bit on the file, 1222 * check group membership. 1223 */ 1224 if (new_mode & S_ISGID) { 1225 int ismember; 1226 1227 error = kauth_cred_ismember_gid(cred, cur_gid, 1228 &ismember); 1229 if (error || !ismember) 1230 return (EPERM); 1231 } 1232 1233 /* 1234 * Deny setting setuid if we are not the file owner. 1235 */ 1236 if ((new_mode & S_ISUID) && cur_uid != kauth_cred_geteuid(cred)) 1237 return (EPERM); 1238 1239 return (0); 1240 } 1241 1242 /* 1243 * Common routine to check if chown() is allowed. 1244 * 1245 * Policy: 1246 * - You must own the file, and 1247 * - You must not try to change ownership, and 1248 * - You must be member of the new group 1249 * 1250 * vp - vnode 1251 * cred - credentials of the invoker 1252 * cur_uid, cur_gid - current uid/gid of the file-system object 1253 * new_uid, new_gid - target uid/gid of the file-system object 1254 * 1255 * Returns 0 if the change is allowed, or an error value otherwise. 1256 */ 1257 int 1258 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 1259 gid_t cur_gid, uid_t new_uid, gid_t new_gid) 1260 { 1261 int error, ismember; 1262 1263 /* 1264 * To modify the ownership of a file, must possess VADMIN for that 1265 * file. 1266 */ 1267 if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred)) != 0) 1268 return (error); 1269 1270 /* 1271 * You can only change ownership of a file if: 1272 * You own the file and... 1273 */ 1274 if (kauth_cred_geteuid(cred) == cur_uid) { 1275 /* 1276 * You don't try to change ownership, and... 1277 */ 1278 if (new_uid != cur_uid) 1279 return (EPERM); 1280 1281 /* 1282 * You don't try to change group (no-op), or... 1283 */ 1284 if (new_gid == cur_gid) 1285 return (0); 1286 1287 /* 1288 * Your effective gid is the new gid, or... 1289 */ 1290 if (kauth_cred_getegid(cred) == new_gid) 1291 return (0); 1292 1293 /* 1294 * The new gid is one you're a member of. 1295 */ 1296 ismember = 0; 1297 error = kauth_cred_ismember_gid(cred, new_gid, 1298 &ismember); 1299 if (!error && ismember) 1300 return (0); 1301 } 1302 1303 return (EPERM); 1304 } 1305 1306 int 1307 genfs_can_chtimes(vnode_t *vp, kauth_cred_t cred, uid_t owner_uid, 1308 u_int vaflags) 1309 { 1310 int error; 1311 /* 1312 * Grant permission if the caller is the owner of the file, or 1313 * the super-user, or has ACL_WRITE_ATTRIBUTES permission on 1314 * on the file. If the time pointer is null, then write 1315 * permission on the file is also sufficient. 1316 * 1317 * From NFSv4.1, draft 21, 6.2.1.3.1, Discussion of Mask Attributes: 1318 * A user having ACL_WRITE_DATA or ACL_WRITE_ATTRIBUTES 1319 * will be allowed to set the times [..] to the current 1320 * server time. 1321 */ 1322 if ((error = VOP_ACCESSX(vp, VWRITE_ATTRIBUTES, cred)) != 0) 1323 return (vaflags & VA_UTIMES_NULL) == 0 ? EPERM : EACCES; 1324 1325 /* Must be owner, or... */ 1326 if (kauth_cred_geteuid(cred) == owner_uid) 1327 return (0); 1328 1329 /* set the times to the current time, and... */ 1330 if ((vaflags & VA_UTIMES_NULL) == 0) 1331 return (EPERM); 1332 1333 /* have write access. */ 1334 error = VOP_ACCESS(vp, VWRITE, cred); 1335 if (error) 1336 return (error); 1337 1338 return (0); 1339 } 1340 1341 /* 1342 * Common routine to check if chflags() is allowed. 1343 * 1344 * Policy: 1345 * - You must own the file, and 1346 * - You must not change system flags, and 1347 * - You must not change flags on character/block devices. 1348 * 1349 * vp - vnode 1350 * cred - credentials of the invoker 1351 * owner_uid - uid of the file-system object 1352 * changing_sysflags - true if the invoker wants to change system flags 1353 */ 1354 int 1355 genfs_can_chflags(vnode_t *vp, kauth_cred_t cred, 1356 uid_t owner_uid, bool changing_sysflags) 1357 { 1358 1359 /* The user must own the file. */ 1360 if (kauth_cred_geteuid(cred) != owner_uid) { 1361 return EPERM; 1362 } 1363 1364 if (changing_sysflags) { 1365 return EPERM; 1366 } 1367 1368 /* 1369 * Unprivileged users cannot change the flags on devices, even if they 1370 * own them. 1371 */ 1372 if (vp->v_type == VCHR || vp->v_type == VBLK) { 1373 return EPERM; 1374 } 1375 1376 return 0; 1377 } 1378 1379 /* 1380 * Common "sticky" policy. 1381 * 1382 * When a directory is "sticky" (as determined by the caller), this 1383 * function may help implementing the following policy: 1384 * - Renaming a file in it is only possible if the user owns the directory 1385 * or the file being renamed. 1386 * - Deleting a file from it is only possible if the user owns the 1387 * directory or the file being deleted. 1388 */ 1389 int 1390 genfs_can_sticky(vnode_t *vp, kauth_cred_t cred, uid_t dir_uid, uid_t file_uid) 1391 { 1392 if (kauth_cred_geteuid(cred) != dir_uid && 1393 kauth_cred_geteuid(cred) != file_uid) 1394 return EPERM; 1395 1396 return 0; 1397 } 1398 1399 int 1400 genfs_can_extattr(vnode_t *vp, kauth_cred_t cred, accmode_t accmode, 1401 int attrnamespace) 1402 { 1403 /* 1404 * Kernel-invoked always succeeds. 1405 */ 1406 if (cred == NOCRED) 1407 return 0; 1408 1409 switch (attrnamespace) { 1410 case EXTATTR_NAMESPACE_SYSTEM: 1411 return kauth_authorize_system(cred, KAUTH_SYSTEM_FS_EXTATTR, 1412 0, vp->v_mount, NULL, NULL); 1413 case EXTATTR_NAMESPACE_USER: 1414 return VOP_ACCESS(vp, accmode, cred); 1415 default: 1416 return EPERM; 1417 } 1418 } 1419 1420 int 1421 genfs_access(void *v) 1422 { 1423 struct vop_access_args *ap = v; 1424 1425 KASSERT((ap->a_accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | 1426 VAPPEND)) == 0); 1427 1428 return VOP_ACCESSX(ap->a_vp, ap->a_accmode, ap->a_cred); 1429 } 1430 1431 int 1432 genfs_accessx(void *v) 1433 { 1434 struct vop_accessx_args *ap = v; 1435 int error; 1436 accmode_t accmode = ap->a_accmode; 1437 error = vfs_unixify_accmode(&accmode); 1438 if (error != 0) 1439 return error; 1440 1441 if (accmode == 0) 1442 return 0; 1443 1444 return VOP_ACCESS(ap->a_vp, accmode, ap->a_cred); 1445 } 1446 1447 /* 1448 * genfs_pathconf: 1449 * 1450 * Standard implementation of POSIX pathconf, to get information about limits 1451 * for a filesystem. 1452 * Override per filesystem for the case where the filesystem has smaller 1453 * limits. 1454 */ 1455 int 1456 genfs_pathconf(void *v) 1457 { 1458 struct vop_pathconf_args *ap = v; 1459 1460 switch (ap->a_name) { 1461 case _PC_PATH_MAX: 1462 *ap->a_retval = PATH_MAX; 1463 return 0; 1464 case _PC_ACL_EXTENDED: 1465 case _PC_ACL_NFS4: 1466 *ap->a_retval = 0; 1467 return 0; 1468 default: 1469 return EINVAL; 1470 } 1471 } 1472