genfs_vnops.c revision 1.211 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