1 /* $NetBSD: genfs_vnops.c,v 1.211 2021/06/29 22:34:08 dholland 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.211 2021/06/29 22:34:08 dholland 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 mutex_enter(vp->v_interlock); 511 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext); 512 mutex_exit(vp->v_interlock); 513 } 514 515 static int 516 filt_genfsread(struct knote *kn, long hint) 517 { 518 struct vnode *vp = (struct vnode *)kn->kn_hook; 519 int rv; 520 521 /* 522 * filesystem is gone, so set the EOF flag and schedule 523 * the knote for deletion. 524 */ 525 switch (hint) { 526 case NOTE_REVOKE: 527 KASSERT(mutex_owned(vp->v_interlock)); 528 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 529 return (1); 530 case 0: 531 mutex_enter(vp->v_interlock); 532 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 533 rv = (kn->kn_data != 0); 534 mutex_exit(vp->v_interlock); 535 return rv; 536 default: 537 KASSERT(mutex_owned(vp->v_interlock)); 538 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 539 return (kn->kn_data != 0); 540 } 541 } 542 543 static int 544 filt_genfswrite(struct knote *kn, long hint) 545 { 546 struct vnode *vp = (struct vnode *)kn->kn_hook; 547 548 /* 549 * filesystem is gone, so set the EOF flag and schedule 550 * the knote for deletion. 551 */ 552 switch (hint) { 553 case NOTE_REVOKE: 554 KASSERT(mutex_owned(vp->v_interlock)); 555 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 556 return (1); 557 case 0: 558 mutex_enter(vp->v_interlock); 559 kn->kn_data = 0; 560 mutex_exit(vp->v_interlock); 561 return 1; 562 default: 563 KASSERT(mutex_owned(vp->v_interlock)); 564 kn->kn_data = 0; 565 return 1; 566 } 567 } 568 569 static int 570 filt_genfsvnode(struct knote *kn, long hint) 571 { 572 struct vnode *vp = (struct vnode *)kn->kn_hook; 573 int fflags; 574 575 switch (hint) { 576 case NOTE_REVOKE: 577 KASSERT(mutex_owned(vp->v_interlock)); 578 kn->kn_flags |= EV_EOF; 579 if ((kn->kn_sfflags & hint) != 0) 580 kn->kn_fflags |= hint; 581 return (1); 582 case 0: 583 mutex_enter(vp->v_interlock); 584 fflags = kn->kn_fflags; 585 mutex_exit(vp->v_interlock); 586 break; 587 default: 588 KASSERT(mutex_owned(vp->v_interlock)); 589 if ((kn->kn_sfflags & hint) != 0) 590 kn->kn_fflags |= hint; 591 fflags = kn->kn_fflags; 592 break; 593 } 594 595 return (fflags != 0); 596 } 597 598 static const struct filterops genfsread_filtops = { 599 .f_isfd = 1, 600 .f_attach = NULL, 601 .f_detach = filt_genfsdetach, 602 .f_event = filt_genfsread, 603 }; 604 605 static const struct filterops genfswrite_filtops = { 606 .f_isfd = 1, 607 .f_attach = NULL, 608 .f_detach = filt_genfsdetach, 609 .f_event = filt_genfswrite, 610 }; 611 612 static const struct filterops genfsvnode_filtops = { 613 .f_isfd = 1, 614 .f_attach = NULL, 615 .f_detach = filt_genfsdetach, 616 .f_event = filt_genfsvnode, 617 }; 618 619 int 620 genfs_kqfilter(void *v) 621 { 622 struct vop_kqfilter_args /* { 623 struct vnode *a_vp; 624 struct knote *a_kn; 625 } */ *ap = v; 626 struct vnode *vp; 627 struct knote *kn; 628 629 vp = ap->a_vp; 630 kn = ap->a_kn; 631 switch (kn->kn_filter) { 632 case EVFILT_READ: 633 kn->kn_fop = &genfsread_filtops; 634 break; 635 case EVFILT_WRITE: 636 kn->kn_fop = &genfswrite_filtops; 637 break; 638 case EVFILT_VNODE: 639 kn->kn_fop = &genfsvnode_filtops; 640 break; 641 default: 642 return (EINVAL); 643 } 644 645 kn->kn_hook = vp; 646 647 mutex_enter(vp->v_interlock); 648 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext); 649 mutex_exit(vp->v_interlock); 650 651 return (0); 652 } 653 654 void 655 genfs_node_wrlock(struct vnode *vp) 656 { 657 struct genfs_node *gp = VTOG(vp); 658 659 rw_enter(&gp->g_glock, RW_WRITER); 660 } 661 662 void 663 genfs_node_rdlock(struct vnode *vp) 664 { 665 struct genfs_node *gp = VTOG(vp); 666 667 rw_enter(&gp->g_glock, RW_READER); 668 } 669 670 int 671 genfs_node_rdtrylock(struct vnode *vp) 672 { 673 struct genfs_node *gp = VTOG(vp); 674 675 return rw_tryenter(&gp->g_glock, RW_READER); 676 } 677 678 void 679 genfs_node_unlock(struct vnode *vp) 680 { 681 struct genfs_node *gp = VTOG(vp); 682 683 rw_exit(&gp->g_glock); 684 } 685 686 int 687 genfs_node_wrlocked(struct vnode *vp) 688 { 689 struct genfs_node *gp = VTOG(vp); 690 691 return rw_write_held(&gp->g_glock); 692 } 693 694 static int 695 groupmember(gid_t gid, kauth_cred_t cred) 696 { 697 int ismember; 698 int error = kauth_cred_ismember_gid(cred, gid, &ismember); 699 if (error) 700 return error; 701 if (kauth_cred_getegid(cred) == gid || ismember) 702 return 0; 703 return -1; 704 } 705 706 /* 707 * Common filesystem object access control check routine. Accepts a 708 * vnode, cred, uid, gid, mode, acl, requested access mode. 709 * Returns 0 on success, or an errno on failure. 710 */ 711 int 712 genfs_can_access(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, gid_t file_gid, 713 mode_t file_mode, struct acl *acl, accmode_t accmode) 714 { 715 accmode_t dac_granted; 716 int error; 717 718 KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0); 719 KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE)); 720 721 /* 722 * Look for a normal, non-privileged way to access the file/directory 723 * as requested. If it exists, go with that. 724 */ 725 726 dac_granted = 0; 727 728 /* Check the owner. */ 729 if (kauth_cred_geteuid(cred) == file_uid) { 730 dac_granted |= VADMIN; 731 if (file_mode & S_IXUSR) 732 dac_granted |= VEXEC; 733 if (file_mode & S_IRUSR) 734 dac_granted |= VREAD; 735 if (file_mode & S_IWUSR) 736 dac_granted |= (VWRITE | VAPPEND); 737 738 goto privchk; 739 } 740 741 /* Otherwise, check the groups (first match) */ 742 /* Otherwise, check the groups. */ 743 error = groupmember(file_gid, cred); 744 if (error > 0) 745 return error; 746 if (error == 0) { 747 if (file_mode & S_IXGRP) 748 dac_granted |= VEXEC; 749 if (file_mode & S_IRGRP) 750 dac_granted |= VREAD; 751 if (file_mode & S_IWGRP) 752 dac_granted |= (VWRITE | VAPPEND); 753 754 goto privchk; 755 } 756 757 /* Otherwise, check everyone else. */ 758 if (file_mode & S_IXOTH) 759 dac_granted |= VEXEC; 760 if (file_mode & S_IROTH) 761 dac_granted |= VREAD; 762 if (file_mode & S_IWOTH) 763 dac_granted |= (VWRITE | VAPPEND); 764 765 privchk: 766 if ((accmode & dac_granted) == accmode) 767 return 0; 768 769 return (accmode & VADMIN) ? EPERM : EACCES; 770 } 771 772 /* 773 * Implement a version of genfs_can_access() that understands POSIX.1e ACL 774 * semantics; 775 * the access ACL has already been prepared for evaluation by the file system 776 * and is passed via 'uid', 'gid', and 'acl'. Return 0 on success, else an 777 * errno value. 778 */ 779 int 780 genfs_can_access_acl_posix1e(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, 781 gid_t file_gid, mode_t file_mode, struct acl *acl, accmode_t accmode) 782 { 783 struct acl_entry *acl_other, *acl_mask; 784 accmode_t dac_granted; 785 accmode_t acl_mask_granted; 786 int group_matched, i; 787 int error; 788 789 KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0); 790 KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE)); 791 792 /* 793 * The owner matches if the effective uid associated with the 794 * credential matches that of the ACL_USER_OBJ entry. While we're 795 * doing the first scan, also cache the location of the ACL_MASK and 796 * ACL_OTHER entries, preventing some future iterations. 797 */ 798 acl_mask = acl_other = NULL; 799 for (i = 0; i < acl->acl_cnt; i++) { 800 struct acl_entry *ae = &acl->acl_entry[i]; 801 switch (ae->ae_tag) { 802 case ACL_USER_OBJ: 803 if (kauth_cred_geteuid(cred) != file_uid) 804 break; 805 dac_granted = 0; 806 dac_granted |= VADMIN; 807 if (ae->ae_perm & ACL_EXECUTE) 808 dac_granted |= VEXEC; 809 if (ae->ae_perm & ACL_READ) 810 dac_granted |= VREAD; 811 if (ae->ae_perm & ACL_WRITE) 812 dac_granted |= (VWRITE | VAPPEND); 813 goto out; 814 815 case ACL_MASK: 816 acl_mask = ae; 817 break; 818 819 case ACL_OTHER: 820 acl_other = ae; 821 break; 822 823 default: 824 break; 825 } 826 } 827 828 /* 829 * An ACL_OTHER entry should always exist in a valid access ACL. If 830 * it doesn't, then generate a serious failure. For now, this means 831 * a debugging message and EPERM, but in the future should probably 832 * be a panic. 833 */ 834 if (acl_other == NULL) { 835 /* 836 * XXX This should never happen 837 */ 838 printf("%s: ACL_OTHER missing\n", __func__); 839 return EPERM; 840 } 841 842 /* 843 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are 844 * masked by an ACL_MASK entry, if any. As such, first identify the 845 * ACL_MASK field, then iterate through identifying potential user 846 * matches, then group matches. If there is no ACL_MASK, assume that 847 * the mask allows all requests to succeed. 848 */ 849 if (acl_mask != NULL) { 850 acl_mask_granted = 0; 851 if (acl_mask->ae_perm & ACL_EXECUTE) 852 acl_mask_granted |= VEXEC; 853 if (acl_mask->ae_perm & ACL_READ) 854 acl_mask_granted |= VREAD; 855 if (acl_mask->ae_perm & ACL_WRITE) 856 acl_mask_granted |= (VWRITE | VAPPEND); 857 } else 858 acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND; 859 860 /* 861 * Check ACL_USER ACL entries. There will either be one or no 862 * matches; if there is one, we accept or rejected based on the 863 * match; otherwise, we continue on to groups. 864 */ 865 for (i = 0; i < acl->acl_cnt; i++) { 866 struct acl_entry *ae = &acl->acl_entry[i]; 867 switch (ae->ae_tag) { 868 case ACL_USER: 869 if (kauth_cred_geteuid(cred) != ae->ae_id) 870 break; 871 dac_granted = 0; 872 if (ae->ae_perm & ACL_EXECUTE) 873 dac_granted |= VEXEC; 874 if (ae->ae_perm & ACL_READ) 875 dac_granted |= VREAD; 876 if (ae->ae_perm & ACL_WRITE) 877 dac_granted |= (VWRITE | VAPPEND); 878 dac_granted &= acl_mask_granted; 879 goto out; 880 } 881 } 882 883 /* 884 * Group match is best-match, not first-match, so find a "best" 885 * match. Iterate across, testing each potential group match. Make 886 * sure we keep track of whether we found a match or not, so that we 887 * know if we should try again with any available privilege, or if we 888 * should move on to ACL_OTHER. 889 */ 890 group_matched = 0; 891 for (i = 0; i < acl->acl_cnt; i++) { 892 struct acl_entry *ae = &acl->acl_entry[i]; 893 switch (ae->ae_tag) { 894 case ACL_GROUP_OBJ: 895 error = groupmember(file_gid, cred); 896 if (error > 0) 897 return error; 898 if (error) 899 break; 900 dac_granted = 0; 901 if (ae->ae_perm & ACL_EXECUTE) 902 dac_granted |= VEXEC; 903 if (ae->ae_perm & ACL_READ) 904 dac_granted |= VREAD; 905 if (ae->ae_perm & ACL_WRITE) 906 dac_granted |= (VWRITE | VAPPEND); 907 dac_granted &= acl_mask_granted; 908 909 if ((accmode & dac_granted) == accmode) 910 return 0; 911 912 group_matched = 1; 913 break; 914 915 case ACL_GROUP: 916 error = groupmember(ae->ae_id, cred); 917 if (error > 0) 918 return error; 919 if (error) 920 break; 921 dac_granted = 0; 922 if (ae->ae_perm & ACL_EXECUTE) 923 dac_granted |= VEXEC; 924 if (ae->ae_perm & ACL_READ) 925 dac_granted |= VREAD; 926 if (ae->ae_perm & ACL_WRITE) 927 dac_granted |= (VWRITE | VAPPEND); 928 dac_granted &= acl_mask_granted; 929 930 if ((accmode & dac_granted) == accmode) 931 return 0; 932 933 group_matched = 1; 934 break; 935 936 default: 937 break; 938 } 939 } 940 941 if (group_matched == 1) { 942 /* 943 * There was a match, but it did not grant rights via pure 944 * DAC. Try again, this time with privilege. 945 */ 946 for (i = 0; i < acl->acl_cnt; i++) { 947 struct acl_entry *ae = &acl->acl_entry[i]; 948 switch (ae->ae_tag) { 949 case ACL_GROUP_OBJ: 950 error = groupmember(file_gid, cred); 951 if (error > 0) 952 return error; 953 if (error) 954 break; 955 dac_granted = 0; 956 if (ae->ae_perm & ACL_EXECUTE) 957 dac_granted |= VEXEC; 958 if (ae->ae_perm & ACL_READ) 959 dac_granted |= VREAD; 960 if (ae->ae_perm & ACL_WRITE) 961 dac_granted |= (VWRITE | VAPPEND); 962 dac_granted &= acl_mask_granted; 963 goto out; 964 965 case ACL_GROUP: 966 error = groupmember(ae->ae_id, cred); 967 if (error > 0) 968 return error; 969 if (error) 970 break; 971 dac_granted = 0; 972 if (ae->ae_perm & ACL_EXECUTE) 973 dac_granted |= VEXEC; 974 if (ae->ae_perm & ACL_READ) 975 dac_granted |= VREAD; 976 if (ae->ae_perm & ACL_WRITE) 977 dac_granted |= (VWRITE | VAPPEND); 978 dac_granted &= acl_mask_granted; 979 980 goto out; 981 default: 982 break; 983 } 984 } 985 /* 986 * Even with privilege, group membership was not sufficient. 987 * Return failure. 988 */ 989 dac_granted = 0; 990 goto out; 991 } 992 993 /* 994 * Fall back on ACL_OTHER. ACL_MASK is not applied to ACL_OTHER. 995 */ 996 dac_granted = 0; 997 if (acl_other->ae_perm & ACL_EXECUTE) 998 dac_granted |= VEXEC; 999 if (acl_other->ae_perm & ACL_READ) 1000 dac_granted |= VREAD; 1001 if (acl_other->ae_perm & ACL_WRITE) 1002 dac_granted |= (VWRITE | VAPPEND); 1003 1004 out: 1005 if ((accmode & dac_granted) == accmode) 1006 return 0; 1007 return (accmode & VADMIN) ? EPERM : EACCES; 1008 } 1009 1010 static struct { 1011 accmode_t accmode; 1012 int mask; 1013 } accmode2mask[] = { 1014 { VREAD, ACL_READ_DATA }, 1015 { VWRITE, ACL_WRITE_DATA }, 1016 { VAPPEND, ACL_APPEND_DATA }, 1017 { VEXEC, ACL_EXECUTE }, 1018 { VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS }, 1019 { VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS }, 1020 { VDELETE_CHILD, ACL_DELETE_CHILD }, 1021 { VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES }, 1022 { VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES }, 1023 { VDELETE, ACL_DELETE }, 1024 { VREAD_ACL, ACL_READ_ACL }, 1025 { VWRITE_ACL, ACL_WRITE_ACL }, 1026 { VWRITE_OWNER, ACL_WRITE_OWNER }, 1027 { VSYNCHRONIZE, ACL_SYNCHRONIZE }, 1028 { 0, 0 }, 1029 }; 1030 1031 static int 1032 _access_mask_from_accmode(accmode_t accmode) 1033 { 1034 int access_mask = 0, i; 1035 1036 for (i = 0; accmode2mask[i].accmode != 0; i++) { 1037 if (accmode & accmode2mask[i].accmode) 1038 access_mask |= accmode2mask[i].mask; 1039 } 1040 1041 /* 1042 * VAPPEND is just a modifier for VWRITE; if the caller asked 1043 * for 'VAPPEND | VWRITE', we want to check for ACL_APPEND_DATA only. 1044 */ 1045 if (access_mask & ACL_APPEND_DATA) 1046 access_mask &= ~ACL_WRITE_DATA; 1047 1048 return (access_mask); 1049 } 1050 1051 /* 1052 * Return 0, iff access is allowed, 1 otherwise. 1053 */ 1054 static int 1055 _acl_denies(const struct acl *aclp, int access_mask, kauth_cred_t cred, 1056 int file_uid, int file_gid, int *denied_explicitly) 1057 { 1058 int i, error; 1059 const struct acl_entry *ae; 1060 1061 if (denied_explicitly != NULL) 1062 *denied_explicitly = 0; 1063 1064 KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES); 1065 1066 for (i = 0; i < aclp->acl_cnt; i++) { 1067 ae = &(aclp->acl_entry[i]); 1068 1069 if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW && 1070 ae->ae_entry_type != ACL_ENTRY_TYPE_DENY) 1071 continue; 1072 if (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY) 1073 continue; 1074 switch (ae->ae_tag) { 1075 case ACL_USER_OBJ: 1076 if (kauth_cred_geteuid(cred) != file_uid) 1077 continue; 1078 break; 1079 case ACL_USER: 1080 if (kauth_cred_geteuid(cred) != ae->ae_id) 1081 continue; 1082 break; 1083 case ACL_GROUP_OBJ: 1084 error = groupmember(file_gid, cred); 1085 if (error > 0) 1086 return error; 1087 if (error != 0) 1088 continue; 1089 break; 1090 case ACL_GROUP: 1091 error = groupmember(ae->ae_id, cred); 1092 if (error > 0) 1093 return error; 1094 if (error != 0) 1095 continue; 1096 break; 1097 default: 1098 KASSERT(ae->ae_tag == ACL_EVERYONE); 1099 } 1100 1101 if (ae->ae_entry_type == ACL_ENTRY_TYPE_DENY) { 1102 if (ae->ae_perm & access_mask) { 1103 if (denied_explicitly != NULL) 1104 *denied_explicitly = 1; 1105 return (1); 1106 } 1107 } 1108 1109 access_mask &= ~(ae->ae_perm); 1110 if (access_mask == 0) 1111 return (0); 1112 } 1113 1114 if (access_mask == 0) 1115 return (0); 1116 1117 return (1); 1118 } 1119 1120 int 1121 genfs_can_access_acl_nfs4(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, 1122 gid_t file_gid, mode_t file_mode, struct acl *aclp, accmode_t accmode) 1123 { 1124 int denied, explicitly_denied, access_mask, is_directory, 1125 must_be_owner = 0; 1126 file_mode = 0; 1127 1128 KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND | 1129 VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS | 1130 VDELETE_CHILD | VREAD_ATTRIBUTES | VWRITE_ATTRIBUTES | VDELETE | 1131 VREAD_ACL | VWRITE_ACL | VWRITE_OWNER | VSYNCHRONIZE)) == 0); 1132 KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE)); 1133 1134 if (accmode & VADMIN) 1135 must_be_owner = 1; 1136 1137 /* 1138 * Ignore VSYNCHRONIZE permission. 1139 */ 1140 accmode &= ~VSYNCHRONIZE; 1141 1142 access_mask = _access_mask_from_accmode(accmode); 1143 1144 if (vp && vp->v_type == VDIR) 1145 is_directory = 1; 1146 else 1147 is_directory = 0; 1148 1149 /* 1150 * File owner is always allowed to read and write the ACL 1151 * and basic attributes. This is to prevent a situation 1152 * where user would change ACL in a way that prevents him 1153 * from undoing the change. 1154 */ 1155 if (kauth_cred_geteuid(cred) == file_uid) 1156 access_mask &= ~(ACL_READ_ACL | ACL_WRITE_ACL | 1157 ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES); 1158 1159 /* 1160 * Ignore append permission for regular files; use write 1161 * permission instead. 1162 */ 1163 if (!is_directory && (access_mask & ACL_APPEND_DATA)) { 1164 access_mask &= ~ACL_APPEND_DATA; 1165 access_mask |= ACL_WRITE_DATA; 1166 } 1167 1168 denied = _acl_denies(aclp, access_mask, cred, file_uid, file_gid, 1169 &explicitly_denied); 1170 1171 if (must_be_owner) { 1172 if (kauth_cred_geteuid(cred) != file_uid) 1173 denied = EPERM; 1174 } 1175 1176 /* 1177 * For VEXEC, ensure that at least one execute bit is set for 1178 * non-directories. We have to check the mode here to stay 1179 * consistent with execve(2). See the test in 1180 * exec_check_permissions(). 1181 */ 1182 __acl_nfs4_sync_mode_from_acl(&file_mode, aclp); 1183 if (!denied && !is_directory && (accmode & VEXEC) && 1184 (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) 1185 denied = EACCES; 1186 1187 if (!denied) 1188 return (0); 1189 1190 /* 1191 * Access failed. Iff it was not denied explicitly and 1192 * VEXPLICIT_DENY flag was specified, allow access. 1193 */ 1194 if ((accmode & VEXPLICIT_DENY) && explicitly_denied == 0) 1195 return (0); 1196 1197 accmode &= ~VEXPLICIT_DENY; 1198 1199 if (accmode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE)) 1200 denied = EPERM; 1201 else 1202 denied = EACCES; 1203 1204 return (denied); 1205 } 1206 1207 /* 1208 * Common routine to check if chmod() is allowed. 1209 * 1210 * Policy: 1211 * - You must own the file, and 1212 * - You must not set the "sticky" bit (meaningless, see chmod(2)) 1213 * - You must be a member of the group if you're trying to set the 1214 * SGIDf bit 1215 * 1216 * vp - vnode of the file-system object 1217 * cred - credentials of the invoker 1218 * cur_uid, cur_gid - current uid/gid of the file-system object 1219 * new_mode - new mode for the file-system object 1220 * 1221 * Returns 0 if the change is allowed, or an error value otherwise. 1222 */ 1223 int 1224 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 1225 gid_t cur_gid, mode_t new_mode) 1226 { 1227 int error; 1228 1229 /* 1230 * To modify the permissions on a file, must possess VADMIN 1231 * for that file. 1232 */ 1233 if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred)) != 0) 1234 return (error); 1235 1236 /* 1237 * Unprivileged users can't set the sticky bit on files. 1238 */ 1239 if ((vp->v_type != VDIR) && (new_mode & S_ISTXT)) 1240 return (EFTYPE); 1241 1242 /* 1243 * If the invoker is trying to set the SGID bit on the file, 1244 * check group membership. 1245 */ 1246 if (new_mode & S_ISGID) { 1247 int ismember; 1248 1249 error = kauth_cred_ismember_gid(cred, cur_gid, 1250 &ismember); 1251 if (error || !ismember) 1252 return (EPERM); 1253 } 1254 1255 /* 1256 * Deny setting setuid if we are not the file owner. 1257 */ 1258 if ((new_mode & S_ISUID) && cur_uid != kauth_cred_geteuid(cred)) 1259 return (EPERM); 1260 1261 return (0); 1262 } 1263 1264 /* 1265 * Common routine to check if chown() is allowed. 1266 * 1267 * Policy: 1268 * - You must own the file, and 1269 * - You must not try to change ownership, and 1270 * - You must be member of the new group 1271 * 1272 * vp - vnode 1273 * cred - credentials of the invoker 1274 * cur_uid, cur_gid - current uid/gid of the file-system object 1275 * new_uid, new_gid - target uid/gid of the file-system object 1276 * 1277 * Returns 0 if the change is allowed, or an error value otherwise. 1278 */ 1279 int 1280 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 1281 gid_t cur_gid, uid_t new_uid, gid_t new_gid) 1282 { 1283 int error, ismember; 1284 1285 /* 1286 * To modify the ownership of a file, must possess VADMIN for that 1287 * file. 1288 */ 1289 if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred)) != 0) 1290 return (error); 1291 1292 /* 1293 * You can only change ownership of a file if: 1294 * You own the file and... 1295 */ 1296 if (kauth_cred_geteuid(cred) == cur_uid) { 1297 /* 1298 * You don't try to change ownership, and... 1299 */ 1300 if (new_uid != cur_uid) 1301 return (EPERM); 1302 1303 /* 1304 * You don't try to change group (no-op), or... 1305 */ 1306 if (new_gid == cur_gid) 1307 return (0); 1308 1309 /* 1310 * Your effective gid is the new gid, or... 1311 */ 1312 if (kauth_cred_getegid(cred) == new_gid) 1313 return (0); 1314 1315 /* 1316 * The new gid is one you're a member of. 1317 */ 1318 ismember = 0; 1319 error = kauth_cred_ismember_gid(cred, new_gid, 1320 &ismember); 1321 if (!error && ismember) 1322 return (0); 1323 } 1324 1325 return (EPERM); 1326 } 1327 1328 int 1329 genfs_can_chtimes(vnode_t *vp, kauth_cred_t cred, uid_t owner_uid, 1330 u_int vaflags) 1331 { 1332 int error; 1333 /* 1334 * Grant permission if the caller is the owner of the file, or 1335 * the super-user, or has ACL_WRITE_ATTRIBUTES permission on 1336 * on the file. If the time pointer is null, then write 1337 * permission on the file is also sufficient. 1338 * 1339 * From NFSv4.1, draft 21, 6.2.1.3.1, Discussion of Mask Attributes: 1340 * A user having ACL_WRITE_DATA or ACL_WRITE_ATTRIBUTES 1341 * will be allowed to set the times [..] to the current 1342 * server time. 1343 */ 1344 if ((error = VOP_ACCESSX(vp, VWRITE_ATTRIBUTES, cred)) != 0) 1345 return (vaflags & VA_UTIMES_NULL) == 0 ? EPERM : EACCES; 1346 1347 /* Must be owner, or... */ 1348 if (kauth_cred_geteuid(cred) == owner_uid) 1349 return (0); 1350 1351 /* set the times to the current time, and... */ 1352 if ((vaflags & VA_UTIMES_NULL) == 0) 1353 return (EPERM); 1354 1355 /* have write access. */ 1356 error = VOP_ACCESS(vp, VWRITE, cred); 1357 if (error) 1358 return (error); 1359 1360 return (0); 1361 } 1362 1363 /* 1364 * Common routine to check if chflags() is allowed. 1365 * 1366 * Policy: 1367 * - You must own the file, and 1368 * - You must not change system flags, and 1369 * - You must not change flags on character/block devices. 1370 * 1371 * vp - vnode 1372 * cred - credentials of the invoker 1373 * owner_uid - uid of the file-system object 1374 * changing_sysflags - true if the invoker wants to change system flags 1375 */ 1376 int 1377 genfs_can_chflags(vnode_t *vp, kauth_cred_t cred, 1378 uid_t owner_uid, bool changing_sysflags) 1379 { 1380 1381 /* The user must own the file. */ 1382 if (kauth_cred_geteuid(cred) != owner_uid) { 1383 return EPERM; 1384 } 1385 1386 if (changing_sysflags) { 1387 return EPERM; 1388 } 1389 1390 /* 1391 * Unprivileged users cannot change the flags on devices, even if they 1392 * own them. 1393 */ 1394 if (vp->v_type == VCHR || vp->v_type == VBLK) { 1395 return EPERM; 1396 } 1397 1398 return 0; 1399 } 1400 1401 /* 1402 * Common "sticky" policy. 1403 * 1404 * When a directory is "sticky" (as determined by the caller), this 1405 * function may help implementing the following policy: 1406 * - Renaming a file in it is only possible if the user owns the directory 1407 * or the file being renamed. 1408 * - Deleting a file from it is only possible if the user owns the 1409 * directory or the file being deleted. 1410 */ 1411 int 1412 genfs_can_sticky(vnode_t *vp, kauth_cred_t cred, uid_t dir_uid, uid_t file_uid) 1413 { 1414 if (kauth_cred_geteuid(cred) != dir_uid && 1415 kauth_cred_geteuid(cred) != file_uid) 1416 return EPERM; 1417 1418 return 0; 1419 } 1420 1421 int 1422 genfs_can_extattr(vnode_t *vp, kauth_cred_t cred, accmode_t accmode, 1423 int attrnamespace) 1424 { 1425 /* 1426 * Kernel-invoked always succeeds. 1427 */ 1428 if (cred == NOCRED) 1429 return 0; 1430 1431 switch (attrnamespace) { 1432 case EXTATTR_NAMESPACE_SYSTEM: 1433 return kauth_authorize_system(cred, KAUTH_SYSTEM_FS_EXTATTR, 1434 0, vp->v_mount, NULL, NULL); 1435 case EXTATTR_NAMESPACE_USER: 1436 return VOP_ACCESS(vp, accmode, cred); 1437 default: 1438 return EPERM; 1439 } 1440 } 1441 1442 int 1443 genfs_access(void *v) 1444 { 1445 struct vop_access_args *ap = v; 1446 1447 KASSERT((ap->a_accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | 1448 VAPPEND)) == 0); 1449 1450 return VOP_ACCESSX(ap->a_vp, ap->a_accmode, ap->a_cred); 1451 } 1452 1453 int 1454 genfs_accessx(void *v) 1455 { 1456 struct vop_accessx_args *ap = v; 1457 int error; 1458 accmode_t accmode = ap->a_accmode; 1459 error = vfs_unixify_accmode(&accmode); 1460 if (error != 0) 1461 return error; 1462 1463 if (accmode == 0) 1464 return 0; 1465 1466 return VOP_ACCESS(ap->a_vp, accmode, ap->a_cred); 1467 } 1468 1469 /* 1470 * genfs_pathconf: 1471 * 1472 * Standard implementation of POSIX pathconf, to get information about limits 1473 * for a filesystem. 1474 * Override per filesystem for the case where the filesystem has smaller 1475 * limits. 1476 */ 1477 int 1478 genfs_pathconf(void *v) 1479 { 1480 struct vop_pathconf_args *ap = v; 1481 1482 switch (ap->a_name) { 1483 case _PC_PATH_MAX: 1484 *ap->a_retval = PATH_MAX; 1485 return 0; 1486 case _PC_ACL_EXTENDED: 1487 case _PC_ACL_NFS4: 1488 *ap->a_retval = 0; 1489 return 0; 1490 default: 1491 return EINVAL; 1492 } 1493 } 1494