1/* $NetBSD: genfs_vnops.c,v 1.192 2014/03/24 13:42:40 hannken 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.192 2014/03/24 13:42:40 hannken 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.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
85static void filt_genfsdetach(struct knote *);
86static int filt_genfsread(struct knote *, long);
87static int filt_genfsvnode(struct knote *, long);
88
89int
90genfs_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
101int
102genfs_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
117int
118genfs_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
130int
131genfs_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*/
149int
150genfs_badop(void *v)
151{
152
153 panic("genfs: bad op");
154}
155
156/*ARGSUSED*/
157int
158genfs_nullop(void *v)
159{
160
161 return (0);
162}
163
164/*ARGSUSED*/
165int
166genfs_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 */
177int
178genfs_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_WILLUNLOCK:
231 VOP_UNLOCK(vp);
232 break;
233 case VDESC_VP0_WILLRELE:
234 vrele(vp);
235 break;
236 }
237 }
238 }
239
240 return (EOPNOTSUPP);
241}
242
243/*ARGSUSED*/
244int
245genfs_ebadf(void *v)
246{
247
248 return (EBADF);
249}
250
251/* ARGSUSED */
252int
253genfs_enoioctl(void *v)
254{
255
256 return (EPASSTHROUGH);
257}
258
259
260/*
261 * Eliminate all activity associated with the requested vnode
262 * and with all vnodes aliased to the requested vnode.
263 */
264int
265genfs_revoke(void *v)
266{
267 struct vop_revoke_args /* {
268 struct vnode *a_vp;
269 int a_flags;
270 } */ *ap = v;
271
272#ifdef DIAGNOSTIC
273 if ((ap->a_flags & REVOKEALL) == 0)
274 panic("genfs_revoke: not revokeall");
275#endif
276 vrevoke(ap->a_vp);
277 return (0);
278}
279
280/*
281 * Lock the node (for deadfs).
282 */
283int
284genfs_deadlock(void *v)
285{
286 struct vop_lock_args /* {
287 struct vnode *a_vp;
288 int a_flags;
289 } */ *ap = v;
290 struct vnode *vp = ap->a_vp;
291 int flags = ap->a_flags;
292 krw_t op;
293 int error;
294
295 op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER);
296 if (ISSET(flags, LK_NOWAIT)) {
297 if (! rw_tryenter(&vp->v_lock, op))
298 return EBUSY;
299 if (mutex_tryenter(vp->v_interlock)) {
300 error = vdead_check(vp, VDEAD_NOWAIT);
301 if (error == ENOENT && ISSET(flags, LK_RETRY))
302 error = 0;
303 mutex_exit(vp->v_interlock);
304 } else
305 error = EBUSY;
306 if (error)
307 rw_exit(&vp->v_lock);
308 return error;
309 }
310
311 rw_enter(&vp->v_lock, op);
312 mutex_enter(vp->v_interlock);
313 error = vdead_check(vp, VDEAD_NOWAIT);
314 if (error == EBUSY) {
315 rw_exit(&vp->v_lock);
316 error = vdead_check(vp, 0);
317 KASSERT(error == ENOENT);
318 mutex_exit(vp->v_interlock);
319 rw_enter(&vp->v_lock, op);
320 mutex_enter(vp->v_interlock);
321 }
322 KASSERT(error == ENOENT);
323 mutex_exit(vp->v_interlock);
324 if (! ISSET(flags, LK_RETRY)) {
325 rw_exit(&vp->v_lock);
326 return ENOENT;
327 }
328 return 0;
329}
330
331/*
332 * Unlock the node (for deadfs).
333 */
334int
335genfs_deadunlock(void *v)
336{
337 struct vop_unlock_args /* {
338 struct vnode *a_vp;
339 } */ *ap = v;
340 struct vnode *vp = ap->a_vp;
341
342 rw_exit(&vp->v_lock);
343
344 return 0;
345}
346
347/*
348 * Lock the node.
349 */
350int
351genfs_lock(void *v)
352{
353 struct vop_lock_args /* {
354 struct vnode *a_vp;
355 int a_flags;
356 } */ *ap = v;
357 struct vnode *vp = ap->a_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(&vp->v_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(&vp->v_lock);
378 fstrans_done(mp);
379 }
380 return error;
381 }
382
383 fstrans_start(mp, FSTRANS_SHARED);
384 rw_enter(&vp->v_lock, op);
385 mutex_enter(vp->v_interlock);
386 error = vdead_check(vp, VDEAD_NOWAIT);
387 if (error) {
388 rw_exit(&vp->v_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 */
400int
401genfs_unlock(void *v)
402{
403 struct vop_unlock_args /* {
404 struct vnode *a_vp;
405 } */ *ap = v;
406 struct vnode *vp = ap->a_vp;
407 struct mount *mp = vp->v_mount;
408
409 rw_exit(&vp->v_lock);
410 fstrans_done(mp);
411
412 return 0;
413}
414
415/*
416 * Return whether or not the node is locked.
417 */
418int
419genfs_islocked(void *v)
420{
421 struct vop_islocked_args /* {
422 struct vnode *a_vp;
423 } */ *ap = v;
424 struct vnode *vp = ap->a_vp;
425
426 if (rw_write_held(&vp->v_lock))
427 return LK_EXCLUSIVE;
428
429 if (rw_read_held(&vp->v_lock))
430 return LK_SHARED;
431
432 return 0;
433}
434
435/*
436 * Stubs to use when there is no locking to be done on the underlying object.
437 */
438int
439genfs_nolock(void *v)
440{
441
442 return (0);
443}
444
445int
446genfs_nounlock(void *v)
447{
448
449 return (0);
450}
451
452int
453genfs_noislocked(void *v)
454{
455
456 return (0);
457}
458
459int
460genfs_mmap(void *v)
461{
462
463 return (0);
464}
465
466/*
467 * VOP_PUTPAGES() for vnodes which never have pages.
468 */
469
470int
471genfs_null_putpages(void *v)
472{
473 struct vop_putpages_args /* {
474 struct vnode *a_vp;
475 voff_t a_offlo;
476 voff_t a_offhi;
477 int a_flags;
478 } */ *ap = v;
479 struct vnode *vp = ap->a_vp;
480
481 KASSERT(vp->v_uobj.uo_npages == 0);
482 mutex_exit(vp->v_interlock);
483 return (0);
484}
485
486void
487genfs_node_init(struct vnode *vp, const struct genfs_ops *ops)
488{
489 struct genfs_node *gp = VTOG(vp);
490
491 rw_init(&gp->g_glock);
492 gp->g_op = ops;
493}
494
495void
496genfs_node_destroy(struct vnode *vp)
497{
498 struct genfs_node *gp = VTOG(vp);
499
500 rw_destroy(&gp->g_glock);
501}
502
503void
504genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
505{
506 int bsize;
507
508 bsize = 1 << vp->v_mount->mnt_fs_bshift;
509 *eobp = (size + bsize - 1) & ~(bsize - 1);
510}
511
512static void
513filt_genfsdetach(struct knote *kn)
514{
515 struct vnode *vp = (struct vnode *)kn->kn_hook;
516
517 mutex_enter(vp->v_interlock);
518 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext);
519 mutex_exit(vp->v_interlock);
520}
521
522static int
523filt_genfsread(struct knote *kn, long hint)
524{
525 struct vnode *vp = (struct vnode *)kn->kn_hook;
526 int rv;
527
528 /*
529 * filesystem is gone, so set the EOF flag and schedule
530 * the knote for deletion.
531 */
532 switch (hint) {
533 case NOTE_REVOKE:
534 KASSERT(mutex_owned(vp->v_interlock));
535 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
536 return (1);
537 case 0:
538 mutex_enter(vp->v_interlock);
539 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
540 rv = (kn->kn_data != 0);
541 mutex_exit(vp->v_interlock);
542 return rv;
543 default:
544 KASSERT(mutex_owned(vp->v_interlock));
545 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
546 return (kn->kn_data != 0);
547 }
548}
549
550static int
551filt_genfsvnode(struct knote *kn, long hint)
552{
553 struct vnode *vp = (struct vnode *)kn->kn_hook;
554 int fflags;
555
556 switch (hint) {
557 case NOTE_REVOKE:
558 KASSERT(mutex_owned(vp->v_interlock));
559 kn->kn_flags |= EV_EOF;
560 if ((kn->kn_sfflags & hint) != 0)
561 kn->kn_fflags |= hint;
562 return (1);
563 case 0:
564 mutex_enter(vp->v_interlock);
565 fflags = kn->kn_fflags;
566 mutex_exit(vp->v_interlock);
567 break;
568 default:
569 KASSERT(mutex_owned(vp->v_interlock));
570 if ((kn->kn_sfflags & hint) != 0)
571 kn->kn_fflags |= hint;
572 fflags = kn->kn_fflags;
573 break;
574 }
575
576 return (fflags != 0);
577}
578
579static const struct filterops genfsread_filtops =
580 { 1, NULL, filt_genfsdetach, filt_genfsread };
581static const struct filterops genfsvnode_filtops =
582 { 1, NULL, filt_genfsdetach, filt_genfsvnode };
583
584int
585genfs_kqfilter(void *v)
586{
587 struct vop_kqfilter_args /* {
588 struct vnode *a_vp;
589 struct knote *a_kn;
590 } */ *ap = v;
591 struct vnode *vp;
592 struct knote *kn;
593
594 vp = ap->a_vp;
595 kn = ap->a_kn;
596 switch (kn->kn_filter) {
597 case EVFILT_READ:
598 kn->kn_fop = &genfsread_filtops;
599 break;
600 case EVFILT_VNODE:
601 kn->kn_fop = &genfsvnode_filtops;
602 break;
603 default:
604 return (EINVAL);
605 }
606
607 kn->kn_hook = vp;
608
609 mutex_enter(vp->v_interlock);
610 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext);
611 mutex_exit(vp->v_interlock);
612
613 return (0);
614}
615
616void
617genfs_node_wrlock(struct vnode *vp)
618{
619 struct genfs_node *gp = VTOG(vp);
620
621 rw_enter(&gp->g_glock, RW_WRITER);
622}
623
624void
625genfs_node_rdlock(struct vnode *vp)
626{
627 struct genfs_node *gp = VTOG(vp);
628
629 rw_enter(&gp->g_glock, RW_READER);
630}
631
632int
633genfs_node_rdtrylock(struct vnode *vp)
634{
635 struct genfs_node *gp = VTOG(vp);
636
637 return rw_tryenter(&gp->g_glock, RW_READER);
638}
639
640void
641genfs_node_unlock(struct vnode *vp)
642{
643 struct genfs_node *gp = VTOG(vp);
644
645 rw_exit(&gp->g_glock);
646}
647
648int
649genfs_node_wrlocked(struct vnode *vp)
650{
651 struct genfs_node *gp = VTOG(vp);
652
653 return rw_write_held(&gp->g_glock);
654}
655
656/*
657 * Do the usual access checking.
658 * file_mode, uid and gid are from the vnode in question,
659 * while acc_mode and cred are from the VOP_ACCESS parameter list
660 */
661int
662genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
663 mode_t acc_mode, kauth_cred_t cred)
664{
665 mode_t mask;
666 int error, ismember;
667
668 mask = 0;
669
670 /* Otherwise, check the owner. */
671 if (kauth_cred_geteuid(cred) == uid) {
672 if (acc_mode & VEXEC)
673 mask |= S_IXUSR;
674 if (acc_mode & VREAD)
675 mask |= S_IRUSR;
676 if (acc_mode & VWRITE)
677 mask |= S_IWUSR;
678 return ((file_mode & mask) == mask ? 0 : EACCES);
679 }
680
681 /* Otherwise, check the groups. */
682 error = kauth_cred_ismember_gid(cred, gid, &ismember);
683 if (error)
684 return (error);
685 if (kauth_cred_getegid(cred) == gid || ismember) {
686 if (acc_mode & VEXEC)
687 mask |= S_IXGRP;
688 if (acc_mode & VREAD)
689 mask |= S_IRGRP;
690 if (acc_mode & VWRITE)
691 mask |= S_IWGRP;
692 return ((file_mode & mask) == mask ? 0 : EACCES);
693 }
694
695 /* Otherwise, check everyone else. */
696 if (acc_mode & VEXEC)
697 mask |= S_IXOTH;
698 if (acc_mode & VREAD)
699 mask |= S_IROTH;
700 if (acc_mode & VWRITE)
701 mask |= S_IWOTH;
702 return ((file_mode & mask) == mask ? 0 : EACCES);
703}
704
705/*
706 * Common routine to check if chmod() is allowed.
707 *
708 * Policy:
709 * - You must own the file, and
710 * - You must not set the "sticky" bit (meaningless, see chmod(2))
711 * - You must be a member of the group if you're trying to set the
712 * SGIDf bit
713 *
714 * cred - credentials of the invoker
715 * vp - vnode of the file-system object
716 * cur_uid, cur_gid - current uid/gid of the file-system object
717 * new_mode - new mode for the file-system object
718 *
719 * Returns 0 if the change is allowed, or an error value otherwise.
720 */
721int
722genfs_can_chmod(enum vtype type, kauth_cred_t cred, uid_t cur_uid,
723 gid_t cur_gid, mode_t new_mode)
724{
725 int error;
726
727 /* The user must own the file. */
728 if (kauth_cred_geteuid(cred) != cur_uid)
729 return (EPERM);
730
731 /*
732 * Unprivileged users can't set the sticky bit on files.
733 */
734 if ((type != VDIR) && (new_mode & S_ISTXT))
735 return (EFTYPE);
736
737 /*
738 * If the invoker is trying to set the SGID bit on the file,
739 * check group membership.
740 */
741 if (new_mode & S_ISGID) {
742 int ismember;
743
744 error = kauth_cred_ismember_gid(cred, cur_gid,
745 &ismember);
746 if (error || !ismember)
747 return (EPERM);
748 }
749
750 return (0);
751}
752
753/*
754 * Common routine to check if chown() is allowed.
755 *
756 * Policy:
757 * - You must own the file, and
758 * - You must not try to change ownership, and
759 * - You must be member of the new group
760 *
761 * cred - credentials of the invoker
762 * cur_uid, cur_gid - current uid/gid of the file-system object
763 * new_uid, new_gid - target uid/gid of the file-system object
764 *
765 * Returns 0 if the change is allowed, or an error value otherwise.
766 */
767int
768genfs_can_chown(kauth_cred_t cred, uid_t cur_uid,
769 gid_t cur_gid, uid_t new_uid, gid_t new_gid)
770{
771 int error, ismember;
772
773 /*
774 * You can only change ownership of a file if:
775 * You own the file and...
776 */
777 if (kauth_cred_geteuid(cred) == cur_uid) {
778 /*
779 * You don't try to change ownership, and...
780 */
781 if (new_uid != cur_uid)
782 return (EPERM);
783
784 /*
785 * You don't try to change group (no-op), or...
786 */
787 if (new_gid == cur_gid)
788 return (0);
789
790 /*
791 * Your effective gid is the new gid, or...
792 */
793 if (kauth_cred_getegid(cred) == new_gid)
794 return (0);
795
796 /*
797 * The new gid is one you're a member of.
798 */
799 ismember = 0;
800 error = kauth_cred_ismember_gid(cred, new_gid,
801 &ismember);
802 if (!error && ismember)
803 return (0);
804 }
805
806 return (EPERM);
807}
808
809int
810genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid,
811 kauth_cred_t cred)
812{
813 int error;
814
815 /* Must be owner, or... */
816 if (kauth_cred_geteuid(cred) == owner_uid)
817 return (0);
818
819 /* set the times to the current time, and... */
820 if ((vaflags & VA_UTIMES_NULL) == 0)
821 return (EPERM);
822
823 /* have write access. */
824 error = VOP_ACCESS(vp, VWRITE, cred);
825 if (error)
826 return (error);
827
828 return (0);
829}
830
831/*
832 * Common routine to check if chflags() is allowed.
833 *
834 * Policy:
835 * - You must own the file, and
836 * - You must not change system flags, and
837 * - You must not change flags on character/block devices.
838 *
839 * cred - credentials of the invoker
840 * owner_uid - uid of the file-system object
841 * changing_sysflags - true if the invoker wants to change system flags
842 */
843int
844genfs_can_chflags(kauth_cred_t cred, enum vtype type, uid_t owner_uid,
845 bool changing_sysflags)
846{
847
848 /* The user must own the file. */
849 if (kauth_cred_geteuid(cred) != owner_uid) {
850 return EPERM;
851 }
852
853 if (changing_sysflags) {
854 return EPERM;
855 }
856
857 /*
858 * Unprivileged users cannot change the flags on devices, even if they
859 * own them.
860 */
861 if (type == VCHR || type == VBLK) {
862 return EPERM;
863 }
864
865 return 0;
866}
867
868/*
869 * Common "sticky" policy.
870 *
871 * When a directory is "sticky" (as determined by the caller), this
872 * function may help implementing the following policy:
873 * - Renaming a file in it is only possible if the user owns the directory
874 * or the file being renamed.
875 * - Deleting a file from it is only possible if the user owns the
876 * directory or the file being deleted.
877 */
878int
879genfs_can_sticky(kauth_cred_t cred, uid_t dir_uid, uid_t file_uid)
880{
881 if (kauth_cred_geteuid(cred) != dir_uid &&
882 kauth_cred_geteuid(cred) != file_uid)
883 return EPERM;
884
885 return 0;
886}
887
888int
889genfs_can_extattr(kauth_cred_t cred, int access_mode, vnode_t *vp,
890 const char *attr)
891{
892 /* We can't allow privileged namespaces. */
893 if (strncasecmp(attr, "system", 6) == 0)
894 return EPERM;
895
896 return VOP_ACCESS(vp, access_mode, cred);
897}
898