genfs_vnops.c revision 1.193.2.1 1 /* $NetBSD: genfs_vnops.c,v 1.193.2.1 2017/04/21 16:54:03 bouyer 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.193.2.1 2017/04/21 16:54:03 bouyer 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
78 #include <miscfs/genfs/genfs.h>
79 #include <miscfs/genfs/genfs_node.h>
80 #include <miscfs/specfs/specdev.h>
81
82 #include <uvm/uvm.h>
83 #include <uvm/uvm_pager.h>
84
85 static void filt_genfsdetach(struct knote *);
86 static int filt_genfsread(struct knote *, long);
87 static int filt_genfsvnode(struct knote *, long);
88
89 int
90 genfs_poll(void *v)
91 {
92 struct vop_poll_args /* {
93 struct vnode *a_vp;
94 int a_events;
95 struct lwp *a_l;
96 } */ *ap = v;
97
98 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
99 }
100
101 int
102 genfs_seek(void *v)
103 {
104 struct vop_seek_args /* {
105 struct vnode *a_vp;
106 off_t a_oldoff;
107 off_t a_newoff;
108 kauth_cred_t cred;
109 } */ *ap = v;
110
111 if (ap->a_newoff < 0)
112 return (EINVAL);
113
114 return (0);
115 }
116
117 int
118 genfs_abortop(void *v)
119 {
120 struct vop_abortop_args /* {
121 struct vnode *a_dvp;
122 struct componentname *a_cnp;
123 } */ *ap = v;
124
125 (void)ap;
126
127 return (0);
128 }
129
130 int
131 genfs_fcntl(void *v)
132 {
133 struct vop_fcntl_args /* {
134 struct vnode *a_vp;
135 u_int a_command;
136 void *a_data;
137 int a_fflag;
138 kauth_cred_t a_cred;
139 struct lwp *a_l;
140 } */ *ap = v;
141
142 if (ap->a_command == F_SETFL)
143 return (0);
144 else
145 return (EOPNOTSUPP);
146 }
147
148 /*ARGSUSED*/
149 int
150 genfs_badop(void *v)
151 {
152
153 panic("genfs: bad op");
154 }
155
156 /*ARGSUSED*/
157 int
158 genfs_nullop(void *v)
159 {
160
161 return (0);
162 }
163
164 /*ARGSUSED*/
165 int
166 genfs_einval(void *v)
167 {
168
169 return (EINVAL);
170 }
171
172 /*
173 * Called when an fs doesn't support a particular vop.
174 * This takes care to vrele, vput, or vunlock passed in vnodes
175 * and calls VOP_ABORTOP for a componentname (in non-rename VOP).
176 */
177 int
178 genfs_eopnotsupp(void *v)
179 {
180 struct vop_generic_args /*
181 struct vnodeop_desc *a_desc;
182 / * other random data follows, presumably * /
183 } */ *ap = v;
184 struct vnodeop_desc *desc = ap->a_desc;
185 struct vnode *vp, *vp_last = NULL;
186 int flags, i, j, offset_cnp, offset_vp;
187
188 KASSERT(desc->vdesc_offset != VOP_LOOKUP_DESCOFFSET);
189 KASSERT(desc->vdesc_offset != VOP_ABORTOP_DESCOFFSET);
190
191 /*
192 * Abort any componentname that lookup potentially left state in.
193 *
194 * As is logical, componentnames for VOP_RENAME are handled by
195 * the caller of VOP_RENAME. Yay, rename!
196 */
197 if (desc->vdesc_offset != VOP_RENAME_DESCOFFSET &&
198 (offset_vp = desc->vdesc_vp_offsets[0]) != VDESC_NO_OFFSET &&
199 (offset_cnp = desc->vdesc_componentname_offset) != VDESC_NO_OFFSET){
200 struct componentname *cnp;
201 struct vnode *dvp;
202
203 dvp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap);
204 cnp = *VOPARG_OFFSETTO(struct componentname **, offset_cnp, ap);
205
206 VOP_ABORTOP(dvp, cnp);
207 }
208
209 flags = desc->vdesc_flags;
210 for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) {
211 if ((offset_vp = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
212 break; /* stop at end of list */
213 if ((j = flags & VDESC_VP0_WILLPUT)) {
214 vp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap);
215
216 /* Skip if NULL */
217 if (!vp)
218 continue;
219
220 switch (j) {
221 case VDESC_VP0_WILLPUT:
222 /* Check for dvp == vp cases */
223 if (vp == vp_last)
224 vrele(vp);
225 else {
226 vput(vp);
227 vp_last = vp;
228 }
229 break;
230 case VDESC_VP0_WILLRELE:
231 vrele(vp);
232 break;
233 }
234 }
235 }
236
237 return (EOPNOTSUPP);
238 }
239
240 /*ARGSUSED*/
241 int
242 genfs_ebadf(void *v)
243 {
244
245 return (EBADF);
246 }
247
248 /* ARGSUSED */
249 int
250 genfs_enoioctl(void *v)
251 {
252
253 return (EPASSTHROUGH);
254 }
255
256
257 /*
258 * Eliminate all activity associated with the requested vnode
259 * and with all vnodes aliased to the requested vnode.
260 */
261 int
262 genfs_revoke(void *v)
263 {
264 struct vop_revoke_args /* {
265 struct vnode *a_vp;
266 int a_flags;
267 } */ *ap = v;
268
269 #ifdef DIAGNOSTIC
270 if ((ap->a_flags & REVOKEALL) == 0)
271 panic("genfs_revoke: not revokeall");
272 #endif
273 vrevoke(ap->a_vp);
274 return (0);
275 }
276
277 /*
278 * Lock the node (for deadfs).
279 */
280 int
281 genfs_deadlock(void *v)
282 {
283 struct vop_lock_args /* {
284 struct vnode *a_vp;
285 int a_flags;
286 } */ *ap = v;
287 vnode_t *vp = ap->a_vp;
288 vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
289 int flags = ap->a_flags;
290 krw_t op;
291 int error;
292
293 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER);
294 if (ISSET(flags, LK_NOWAIT)) {
295 if (! rw_tryenter(vip->vi_lock, op))
296 return EBUSY;
297 if (mutex_tryenter(vp->v_interlock)) {
298 error = vdead_check(vp, VDEAD_NOWAIT);
299 if (error == ENOENT && ISSET(flags, LK_RETRY))
300 error = 0;
301 mutex_exit(vp->v_interlock);
302 } else
303 error = EBUSY;
304 if (error)
305 rw_exit(vip->vi_lock);
306 return error;
307 }
308
309 rw_enter(vip->vi_lock, op);
310 mutex_enter(vp->v_interlock);
311 error = vdead_check(vp, VDEAD_NOWAIT);
312 if (error == EBUSY) {
313 rw_exit(vip->vi_lock);
314 error = vdead_check(vp, 0);
315 KASSERT(error == ENOENT);
316 mutex_exit(vp->v_interlock);
317 rw_enter(vip->vi_lock, op);
318 mutex_enter(vp->v_interlock);
319 }
320 KASSERT(error == ENOENT);
321 mutex_exit(vp->v_interlock);
322 if (! ISSET(flags, LK_RETRY)) {
323 rw_exit(vip->vi_lock);
324 return ENOENT;
325 }
326 return 0;
327 }
328
329 /*
330 * Unlock the node (for deadfs).
331 */
332 int
333 genfs_deadunlock(void *v)
334 {
335 struct vop_unlock_args /* {
336 struct vnode *a_vp;
337 } */ *ap = v;
338 vnode_t *vp = ap->a_vp;
339 vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
340
341 rw_exit(vip->vi_lock);
342
343 return 0;
344 }
345
346 /*
347 * Lock the node.
348 */
349 int
350 genfs_lock(void *v)
351 {
352 struct vop_lock_args /* {
353 struct vnode *a_vp;
354 int a_flags;
355 } */ *ap = v;
356 vnode_t *vp = ap->a_vp;
357 vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
358 struct mount *mp = vp->v_mount;
359 int flags = ap->a_flags;
360 krw_t op;
361 int error;
362
363 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER);
364 if (ISSET(flags, LK_NOWAIT)) {
365 if (fstrans_start_nowait(mp, FSTRANS_SHARED))
366 return EBUSY;
367 if (! rw_tryenter(vip->vi_lock, op)) {
368 fstrans_done(mp);
369 return EBUSY;
370 }
371 if (mutex_tryenter(vp->v_interlock)) {
372 error = vdead_check(vp, VDEAD_NOWAIT);
373 mutex_exit(vp->v_interlock);
374 } else
375 error = EBUSY;
376 if (error) {
377 rw_exit(vip->vi_lock);
378 fstrans_done(mp);
379 }
380 return error;
381 }
382
383 fstrans_start(mp, FSTRANS_SHARED);
384 rw_enter(vip->vi_lock, op);
385 mutex_enter(vp->v_interlock);
386 error = vdead_check(vp, VDEAD_NOWAIT);
387 if (error) {
388 rw_exit(vip->vi_lock);
389 fstrans_done(mp);
390 error = vdead_check(vp, 0);
391 KASSERT(error == ENOENT);
392 }
393 mutex_exit(vp->v_interlock);
394 return error;
395 }
396
397 /*
398 * Unlock the node.
399 */
400 int
401 genfs_unlock(void *v)
402 {
403 struct vop_unlock_args /* {
404 struct vnode *a_vp;
405 } */ *ap = v;
406 vnode_t *vp = ap->a_vp;
407 vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
408 struct mount *mp = vp->v_mount;
409
410 rw_exit(vip->vi_lock);
411 fstrans_done(mp);
412
413 return 0;
414 }
415
416 /*
417 * Return whether or not the node is locked.
418 */
419 int
420 genfs_islocked(void *v)
421 {
422 struct vop_islocked_args /* {
423 struct vnode *a_vp;
424 } */ *ap = v;
425 vnode_t *vp = ap->a_vp;
426 vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
427
428 if (rw_write_held(vip->vi_lock))
429 return LK_EXCLUSIVE;
430
431 if (rw_read_held(vip->vi_lock))
432 return LK_SHARED;
433
434 return 0;
435 }
436
437 /*
438 * Stubs to use when there is no locking to be done on the underlying object.
439 */
440 int
441 genfs_nolock(void *v)
442 {
443
444 return (0);
445 }
446
447 int
448 genfs_nounlock(void *v)
449 {
450
451 return (0);
452 }
453
454 int
455 genfs_noislocked(void *v)
456 {
457
458 return (0);
459 }
460
461 int
462 genfs_mmap(void *v)
463 {
464
465 return (0);
466 }
467
468 /*
469 * VOP_PUTPAGES() for vnodes which never have pages.
470 */
471
472 int
473 genfs_null_putpages(void *v)
474 {
475 struct vop_putpages_args /* {
476 struct vnode *a_vp;
477 voff_t a_offlo;
478 voff_t a_offhi;
479 int a_flags;
480 } */ *ap = v;
481 struct vnode *vp = ap->a_vp;
482
483 KASSERT(vp->v_uobj.uo_npages == 0);
484 mutex_exit(vp->v_interlock);
485 return (0);
486 }
487
488 void
489 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops)
490 {
491 struct genfs_node *gp = VTOG(vp);
492
493 rw_init(&gp->g_glock);
494 gp->g_op = ops;
495 }
496
497 void
498 genfs_node_destroy(struct vnode *vp)
499 {
500 struct genfs_node *gp = VTOG(vp);
501
502 rw_destroy(&gp->g_glock);
503 }
504
505 void
506 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
507 {
508 int bsize;
509
510 bsize = 1 << vp->v_mount->mnt_fs_bshift;
511 *eobp = (size + bsize - 1) & ~(bsize - 1);
512 }
513
514 static void
515 filt_genfsdetach(struct knote *kn)
516 {
517 struct vnode *vp = (struct vnode *)kn->kn_hook;
518
519 mutex_enter(vp->v_interlock);
520 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext);
521 mutex_exit(vp->v_interlock);
522 }
523
524 static int
525 filt_genfsread(struct knote *kn, long hint)
526 {
527 struct vnode *vp = (struct vnode *)kn->kn_hook;
528 int rv;
529
530 /*
531 * filesystem is gone, so set the EOF flag and schedule
532 * the knote for deletion.
533 */
534 switch (hint) {
535 case NOTE_REVOKE:
536 KASSERT(mutex_owned(vp->v_interlock));
537 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
538 return (1);
539 case 0:
540 mutex_enter(vp->v_interlock);
541 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
542 rv = (kn->kn_data != 0);
543 mutex_exit(vp->v_interlock);
544 return rv;
545 default:
546 KASSERT(mutex_owned(vp->v_interlock));
547 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
548 return (kn->kn_data != 0);
549 }
550 }
551
552 static int
553 filt_genfsvnode(struct knote *kn, long hint)
554 {
555 struct vnode *vp = (struct vnode *)kn->kn_hook;
556 int fflags;
557
558 switch (hint) {
559 case NOTE_REVOKE:
560 KASSERT(mutex_owned(vp->v_interlock));
561 kn->kn_flags |= EV_EOF;
562 if ((kn->kn_sfflags & hint) != 0)
563 kn->kn_fflags |= hint;
564 return (1);
565 case 0:
566 mutex_enter(vp->v_interlock);
567 fflags = kn->kn_fflags;
568 mutex_exit(vp->v_interlock);
569 break;
570 default:
571 KASSERT(mutex_owned(vp->v_interlock));
572 if ((kn->kn_sfflags & hint) != 0)
573 kn->kn_fflags |= hint;
574 fflags = kn->kn_fflags;
575 break;
576 }
577
578 return (fflags != 0);
579 }
580
581 static const struct filterops genfsread_filtops =
582 { 1, NULL, filt_genfsdetach, filt_genfsread };
583 static const struct filterops genfsvnode_filtops =
584 { 1, NULL, filt_genfsdetach, filt_genfsvnode };
585
586 int
587 genfs_kqfilter(void *v)
588 {
589 struct vop_kqfilter_args /* {
590 struct vnode *a_vp;
591 struct knote *a_kn;
592 } */ *ap = v;
593 struct vnode *vp;
594 struct knote *kn;
595
596 vp = ap->a_vp;
597 kn = ap->a_kn;
598 switch (kn->kn_filter) {
599 case EVFILT_READ:
600 kn->kn_fop = &genfsread_filtops;
601 break;
602 case EVFILT_VNODE:
603 kn->kn_fop = &genfsvnode_filtops;
604 break;
605 default:
606 return (EINVAL);
607 }
608
609 kn->kn_hook = vp;
610
611 mutex_enter(vp->v_interlock);
612 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext);
613 mutex_exit(vp->v_interlock);
614
615 return (0);
616 }
617
618 void
619 genfs_node_wrlock(struct vnode *vp)
620 {
621 struct genfs_node *gp = VTOG(vp);
622
623 rw_enter(&gp->g_glock, RW_WRITER);
624 }
625
626 void
627 genfs_node_rdlock(struct vnode *vp)
628 {
629 struct genfs_node *gp = VTOG(vp);
630
631 rw_enter(&gp->g_glock, RW_READER);
632 }
633
634 int
635 genfs_node_rdtrylock(struct vnode *vp)
636 {
637 struct genfs_node *gp = VTOG(vp);
638
639 return rw_tryenter(&gp->g_glock, RW_READER);
640 }
641
642 void
643 genfs_node_unlock(struct vnode *vp)
644 {
645 struct genfs_node *gp = VTOG(vp);
646
647 rw_exit(&gp->g_glock);
648 }
649
650 int
651 genfs_node_wrlocked(struct vnode *vp)
652 {
653 struct genfs_node *gp = VTOG(vp);
654
655 return rw_write_held(&gp->g_glock);
656 }
657
658 /*
659 * Do the usual access checking.
660 * file_mode, uid and gid are from the vnode in question,
661 * while acc_mode and cred are from the VOP_ACCESS parameter list
662 */
663 int
664 genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
665 mode_t acc_mode, kauth_cred_t cred)
666 {
667 mode_t mask;
668 int error, ismember;
669
670 mask = 0;
671
672 /* Otherwise, check the owner. */
673 if (kauth_cred_geteuid(cred) == uid) {
674 if (acc_mode & VEXEC)
675 mask |= S_IXUSR;
676 if (acc_mode & VREAD)
677 mask |= S_IRUSR;
678 if (acc_mode & VWRITE)
679 mask |= S_IWUSR;
680 return ((file_mode & mask) == mask ? 0 : EACCES);
681 }
682
683 /* Otherwise, check the groups. */
684 error = kauth_cred_ismember_gid(cred, gid, &ismember);
685 if (error)
686 return (error);
687 if (kauth_cred_getegid(cred) == gid || ismember) {
688 if (acc_mode & VEXEC)
689 mask |= S_IXGRP;
690 if (acc_mode & VREAD)
691 mask |= S_IRGRP;
692 if (acc_mode & VWRITE)
693 mask |= S_IWGRP;
694 return ((file_mode & mask) == mask ? 0 : EACCES);
695 }
696
697 /* Otherwise, check everyone else. */
698 if (acc_mode & VEXEC)
699 mask |= S_IXOTH;
700 if (acc_mode & VREAD)
701 mask |= S_IROTH;
702 if (acc_mode & VWRITE)
703 mask |= S_IWOTH;
704 return ((file_mode & mask) == mask ? 0 : EACCES);
705 }
706
707 /*
708 * Common routine to check if chmod() is allowed.
709 *
710 * Policy:
711 * - You must own the file, and
712 * - You must not set the "sticky" bit (meaningless, see chmod(2))
713 * - You must be a member of the group if you're trying to set the
714 * SGIDf bit
715 *
716 * cred - credentials of the invoker
717 * vp - vnode of the file-system object
718 * cur_uid, cur_gid - current uid/gid of the file-system object
719 * new_mode - new mode for the file-system object
720 *
721 * Returns 0 if the change is allowed, or an error value otherwise.
722 */
723 int
724 genfs_can_chmod(enum vtype type, kauth_cred_t cred, uid_t cur_uid,
725 gid_t cur_gid, mode_t new_mode)
726 {
727 int error;
728
729 /* The user must own the file. */
730 if (kauth_cred_geteuid(cred) != cur_uid)
731 return (EPERM);
732
733 /*
734 * Unprivileged users can't set the sticky bit on files.
735 */
736 if ((type != VDIR) && (new_mode & S_ISTXT))
737 return (EFTYPE);
738
739 /*
740 * If the invoker is trying to set the SGID bit on the file,
741 * check group membership.
742 */
743 if (new_mode & S_ISGID) {
744 int ismember;
745
746 error = kauth_cred_ismember_gid(cred, cur_gid,
747 &ismember);
748 if (error || !ismember)
749 return (EPERM);
750 }
751
752 return (0);
753 }
754
755 /*
756 * Common routine to check if chown() is allowed.
757 *
758 * Policy:
759 * - You must own the file, and
760 * - You must not try to change ownership, and
761 * - You must be member of the new group
762 *
763 * cred - credentials of the invoker
764 * cur_uid, cur_gid - current uid/gid of the file-system object
765 * new_uid, new_gid - target uid/gid of the file-system object
766 *
767 * Returns 0 if the change is allowed, or an error value otherwise.
768 */
769 int
770 genfs_can_chown(kauth_cred_t cred, uid_t cur_uid,
771 gid_t cur_gid, uid_t new_uid, gid_t new_gid)
772 {
773 int error, ismember;
774
775 /*
776 * You can only change ownership of a file if:
777 * You own the file and...
778 */
779 if (kauth_cred_geteuid(cred) == cur_uid) {
780 /*
781 * You don't try to change ownership, and...
782 */
783 if (new_uid != cur_uid)
784 return (EPERM);
785
786 /*
787 * You don't try to change group (no-op), or...
788 */
789 if (new_gid == cur_gid)
790 return (0);
791
792 /*
793 * Your effective gid is the new gid, or...
794 */
795 if (kauth_cred_getegid(cred) == new_gid)
796 return (0);
797
798 /*
799 * The new gid is one you're a member of.
800 */
801 ismember = 0;
802 error = kauth_cred_ismember_gid(cred, new_gid,
803 &ismember);
804 if (!error && ismember)
805 return (0);
806 }
807
808 return (EPERM);
809 }
810
811 int
812 genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid,
813 kauth_cred_t cred)
814 {
815 int error;
816
817 /* Must be owner, or... */
818 if (kauth_cred_geteuid(cred) == owner_uid)
819 return (0);
820
821 /* set the times to the current time, and... */
822 if ((vaflags & VA_UTIMES_NULL) == 0)
823 return (EPERM);
824
825 /* have write access. */
826 error = VOP_ACCESS(vp, VWRITE, cred);
827 if (error)
828 return (error);
829
830 return (0);
831 }
832
833 /*
834 * Common routine to check if chflags() is allowed.
835 *
836 * Policy:
837 * - You must own the file, and
838 * - You must not change system flags, and
839 * - You must not change flags on character/block devices.
840 *
841 * cred - credentials of the invoker
842 * owner_uid - uid of the file-system object
843 * changing_sysflags - true if the invoker wants to change system flags
844 */
845 int
846 genfs_can_chflags(kauth_cred_t cred, enum vtype type, uid_t owner_uid,
847 bool changing_sysflags)
848 {
849
850 /* The user must own the file. */
851 if (kauth_cred_geteuid(cred) != owner_uid) {
852 return EPERM;
853 }
854
855 if (changing_sysflags) {
856 return EPERM;
857 }
858
859 /*
860 * Unprivileged users cannot change the flags on devices, even if they
861 * own them.
862 */
863 if (type == VCHR || type == VBLK) {
864 return EPERM;
865 }
866
867 return 0;
868 }
869
870 /*
871 * Common "sticky" policy.
872 *
873 * When a directory is "sticky" (as determined by the caller), this
874 * function may help implementing the following policy:
875 * - Renaming a file in it is only possible if the user owns the directory
876 * or the file being renamed.
877 * - Deleting a file from it is only possible if the user owns the
878 * directory or the file being deleted.
879 */
880 int
881 genfs_can_sticky(kauth_cred_t cred, uid_t dir_uid, uid_t file_uid)
882 {
883 if (kauth_cred_geteuid(cred) != dir_uid &&
884 kauth_cred_geteuid(cred) != file_uid)
885 return EPERM;
886
887 return 0;
888 }
889
890 int
891 genfs_can_extattr(kauth_cred_t cred, int access_mode, vnode_t *vp,
892 const char *attr)
893 {
894 /* We can't allow privileged namespaces. */
895 if (strncasecmp(attr, "system", 6) == 0)
896 return EPERM;
897
898 return VOP_ACCESS(vp, access_mode, cred);
899 }
900