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