xref: /freebsd/sys/security/mac_bsdextended/mac_bsdextended.c (revision 263d6a7ece4f357d01b3152c39e5d36043f877bb)
1 /*-
2  * Copyright (c) 2005 Tom Rhodes
3  * Copyright (c) 1999-2002 Robert N. M. Watson
4  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5  * All rights reserved.
6  *
7  * This software was developed by Robert Watson for the TrustedBSD Project.
8  * It was later enhanced by Tom Rhodes for the TrustedBSD Project.
9  *
10  * This software was developed for the FreeBSD Project in part by Network
11  * Associates Laboratories, the Security Research Division of Network
12  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13  * as part of the DARPA CHATS research program.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * $FreeBSD$
37  */
38 
39 /*
40  * Developed by the TrustedBSD Project.
41  * "BSD Extended" MAC policy, allowing the administrator to impose
42  * mandatory rules regarding users and some system objects.
43  */
44 
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/acl.h>
48 #include <sys/conf.h>
49 #include <sys/kernel.h>
50 #include <sys/lock.h>
51 #include <sys/mac.h>
52 #include <sys/malloc.h>
53 #include <sys/mount.h>
54 #include <sys/mutex.h>
55 #include <sys/proc.h>
56 #include <sys/systm.h>
57 #include <sys/sysproto.h>
58 #include <sys/sysent.h>
59 #include <sys/vnode.h>
60 #include <sys/file.h>
61 #include <sys/socket.h>
62 #include <sys/socketvar.h>
63 #include <sys/sysctl.h>
64 #include <sys/syslog.h>
65 
66 #include <net/bpfdesc.h>
67 #include <net/if.h>
68 #include <net/if_types.h>
69 #include <net/if_var.h>
70 
71 #include <vm/vm.h>
72 
73 #include <sys/mac_policy.h>
74 
75 #include <security/mac_bsdextended/mac_bsdextended.h>
76 
77 static struct mtx mac_bsdextended_mtx;
78 
79 SYSCTL_DECL(_security_mac);
80 
81 SYSCTL_NODE(_security_mac, OID_AUTO, bsdextended, CTLFLAG_RW, 0,
82     "TrustedBSD extended BSD MAC policy controls");
83 
84 static int	mac_bsdextended_enabled = 1;
85 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, enabled, CTLFLAG_RW,
86     &mac_bsdextended_enabled, 0, "Enforce extended BSD policy");
87 TUNABLE_INT("security.mac.bsdextended.enabled", &mac_bsdextended_enabled);
88 
89 MALLOC_DEFINE(M_MACBSDEXTENDED, "mac_bsdextended", "BSD Extended MAC rule");
90 
91 #define	MAC_BSDEXTENDED_MAXRULES	250
92 static struct mac_bsdextended_rule *rules[MAC_BSDEXTENDED_MAXRULES];
93 static int rule_count = 0;
94 static int rule_slots = 0;
95 
96 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_count, CTLFLAG_RD,
97     &rule_count, 0, "Number of defined rules\n");
98 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_slots, CTLFLAG_RD,
99     &rule_slots, 0, "Number of used rule slots\n");
100 
101 /*
102  * This is just used for logging purposes, eventually we would like
103  * to log much more then failed requests.
104  */
105 static int mac_bsdextended_logging;
106 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, logging, CTLFLAG_RW,
107     &mac_bsdextended_logging, 0, "Log failed authorization requests");
108 
109 /*
110  * This tunable is here for compatibility.  It will allow the user
111  * to switch between the new mode (first rule matches) and the old
112  * functionality (all rules match).
113  */
114 static int
115 mac_bsdextended_firstmatch_enabled;
116 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, firstmatch_enabled,
117 	CTLFLAG_RW, &mac_bsdextended_firstmatch_enabled, 1,
118 	"Disable/enable match first rule functionality");
119 
120 static int
121 mac_bsdextended_rule_valid(struct mac_bsdextended_rule *rule)
122 {
123 
124 	if ((rule->mbr_subject.mbi_flags | MBI_BITS) != MBI_BITS)
125 		return (EINVAL);
126 
127 	if ((rule->mbr_object.mbi_flags | MBI_BITS) != MBI_BITS)
128 		return (EINVAL);
129 
130 	if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM)
131 		return (EINVAL);
132 
133 	return (0);
134 }
135 
136 static int
137 sysctl_rule(SYSCTL_HANDLER_ARGS)
138 {
139 	struct mac_bsdextended_rule temprule, *ruleptr;
140 	u_int namelen;
141 	int error, index, *name;
142 
143 	error = 0;
144 	name = (int *)arg1;
145 	namelen = arg2;
146 
147 	/* printf("bsdextended sysctl handler (namelen %d)\n", namelen); */
148 
149 	if (namelen != 1)
150 		return (EINVAL);
151 
152 	index = name[0];
153         if (index > MAC_BSDEXTENDED_MAXRULES)
154 		return (ENOENT);
155 
156 	ruleptr = NULL;
157 	if (req->newptr && req->newlen != 0) {
158 		error = SYSCTL_IN(req, &temprule, sizeof(temprule));
159 		if (error)
160 			return (error);
161 		MALLOC(ruleptr, struct mac_bsdextended_rule *,
162 		    sizeof(*ruleptr), M_MACBSDEXTENDED, M_WAITOK | M_ZERO);
163 	}
164 
165 	mtx_lock(&mac_bsdextended_mtx);
166 
167 	if (req->oldptr) {
168 		if (index < 0 || index > rule_slots + 1) {
169 			error = ENOENT;
170 			goto out;
171 		}
172 		if (rules[index] == NULL) {
173 			error = ENOENT;
174 			goto out;
175 		}
176 		temprule = *rules[index];
177 	}
178 
179 	if (req->newptr && req->newlen == 0) {
180 		/* printf("deletion\n"); */
181 		KASSERT(ruleptr == NULL, ("sysctl_rule: ruleptr != NULL"));
182 		ruleptr = rules[index];
183 		if (ruleptr == NULL) {
184 			error = ENOENT;
185 			goto out;
186 		}
187 		rule_count--;
188 		rules[index] = NULL;
189 	} else if (req->newptr) {
190 		error = mac_bsdextended_rule_valid(&temprule);
191 		if (error)
192 			goto out;
193 
194 		if (rules[index] == NULL) {
195 			/* printf("addition\n"); */
196 			*ruleptr = temprule;
197 			rules[index] = ruleptr;
198 			ruleptr = NULL;
199 			if (index + 1 > rule_slots)
200 				rule_slots = index + 1;
201 			rule_count++;
202 		} else {
203 			/* printf("replacement\n"); */
204 			*rules[index] = temprule;
205 		}
206 	}
207 
208 out:
209 	mtx_unlock(&mac_bsdextended_mtx);
210 	if (ruleptr != NULL)
211 		FREE(ruleptr, M_MACBSDEXTENDED);
212 	if (req->oldptr && error == 0) {
213 		error = SYSCTL_OUT(req, &temprule, sizeof(temprule));
214 		if (error)
215 			return (error);
216 	}
217 
218 	return (0);
219 }
220 
221 SYSCTL_NODE(_security_mac_bsdextended, OID_AUTO, rules,
222     CTLFLAG_RW, sysctl_rule, "BSD extended MAC rules");
223 
224 static void
225 mac_bsdextended_init(struct mac_policy_conf *mpc)
226 {
227 
228 	/* Initialize ruleset lock. */
229 	mtx_init(&mac_bsdextended_mtx, "mac_bsdextended lock", NULL, MTX_DEF);
230 
231 	/* Register dynamic sysctl's for rules. */
232 }
233 
234 static void
235 mac_bsdextended_destroy(struct mac_policy_conf *mpc)
236 {
237 
238 	/* Destroy ruleset lock. */
239 	mtx_destroy(&mac_bsdextended_mtx);
240 
241 	/* Tear down sysctls. */
242 }
243 
244 static int
245 mac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
246     struct ucred *cred, uid_t object_uid, gid_t object_gid, int acc_mode)
247 {
248 	int match;
249 
250 	/*
251 	 * Is there a subject match?
252 	 */
253 	mtx_assert(&mac_bsdextended_mtx, MA_OWNED);
254 	if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
255 		match =  (rule->mbr_subject.mbi_uid == cred->cr_uid ||
256 		    rule->mbr_subject.mbi_uid == cred->cr_ruid ||
257 		    rule->mbr_subject.mbi_uid == cred->cr_svuid);
258 
259 		if (rule->mbr_subject.mbi_flags & MBI_NEGATED)
260 			match = !match;
261 
262 		if (!match)
263 			return (0);
264 	}
265 
266 	if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
267 		match = (groupmember(rule->mbr_subject.mbi_gid, cred) ||
268 		    rule->mbr_subject.mbi_gid == cred->cr_rgid ||
269 		    rule->mbr_subject.mbi_gid == cred->cr_svgid);
270 
271 		if (rule->mbr_subject.mbi_flags & MBI_NEGATED)
272 			match = !match;
273 
274 		if (!match)
275 			return (0);
276 	}
277 
278 	/*
279 	 * Is there an object match?
280 	 */
281 	if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
282 		match = (rule->mbr_object.mbi_uid == object_uid);
283 
284 		if (rule->mbr_object.mbi_flags & MBI_NEGATED)
285 			match = !match;
286 
287 		if (!match)
288 			return (0);
289 	}
290 
291 	if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
292 		match = (rule->mbr_object.mbi_gid == object_gid);
293 
294 		if (rule->mbr_object.mbi_flags & MBI_NEGATED)
295 			match = !match;
296 
297 		if (!match)
298 			return (0);
299 	}
300 
301 	/*
302 	 * Is the access permitted?
303 	 */
304 	if ((rule->mbr_mode & acc_mode) != acc_mode) {
305 		if (mac_bsdextended_logging)
306 			log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d"
307 			    " on %d:%d failed. \n", cred->cr_ruid,
308 			    cred->cr_rgid, acc_mode, object_uid, object_gid);
309 		return (EACCES); /* Matching rule denies access */
310 	}
311 
312 	/*
313 	 * If the rule matched, permits access, and first match is enabled,
314 	 * return success.
315 	 */
316 	if (mac_bsdextended_firstmatch_enabled)
317 		return (EJUSTRETURN);
318 	else
319 		return(0);
320 }
321 
322 static int
323 mac_bsdextended_check(struct ucred *cred, uid_t object_uid, gid_t object_gid,
324     int acc_mode)
325 {
326 	int error, i;
327 
328 	if (suser_cred(cred, 0) == 0)
329 		return (0);
330 
331 	mtx_lock(&mac_bsdextended_mtx);
332 	for (i = 0; i < rule_slots; i++) {
333 		if (rules[i] == NULL)
334 			continue;
335 
336 		/*
337 		 * Since we do not separately handle append, map append to
338 		 * write.
339 		 */
340 		if (acc_mode & MBI_APPEND) {
341 			acc_mode &= ~MBI_APPEND;
342 			acc_mode |= MBI_WRITE;
343 		}
344 
345 		error = mac_bsdextended_rulecheck(rules[i], cred, object_uid,
346 		    object_gid, acc_mode);
347 		if (error == EJUSTRETURN)
348 			break;
349 		if (error) {
350 			mtx_unlock(&mac_bsdextended_mtx);
351 			return (error);
352 		}
353 	}
354 	mtx_unlock(&mac_bsdextended_mtx);
355 	return (0);
356 }
357 
358 static int
359 mac_bsdextended_check_system_swapon(struct ucred *cred, struct vnode *vp,
360     struct label *label)
361 {
362 	struct vattr vap;
363 	int error;
364 
365 	if (!mac_bsdextended_enabled)
366 		return (0);
367 
368 	error = VOP_GETATTR(vp, &vap, cred, curthread);
369 	if (error)
370 		return (error);
371 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
372 	    MBI_WRITE));
373 }
374 
375 static int
376 mac_bsdextended_check_vnode_access(struct ucred *cred, struct vnode *vp,
377     struct label *label, int acc_mode)
378 {
379 	struct vattr vap;
380 	int error;
381 
382 	if (!mac_bsdextended_enabled)
383 		return (0);
384 
385 	error = VOP_GETATTR(vp, &vap, cred, curthread);
386 	if (error)
387 		return (error);
388 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid, acc_mode));
389 }
390 
391 static int
392 mac_bsdextended_check_vnode_chdir(struct ucred *cred, struct vnode *dvp,
393     struct label *dlabel)
394 {
395 	struct vattr vap;
396 	int error;
397 
398 	if (!mac_bsdextended_enabled)
399 		return (0);
400 
401 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
402 	if (error)
403 		return (error);
404 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
405 	    MBI_EXEC));
406 }
407 
408 static int
409 mac_bsdextended_check_vnode_chroot(struct ucred *cred, struct vnode *dvp,
410     struct label *dlabel)
411 {
412 	struct vattr vap;
413 	int error;
414 
415 	if (!mac_bsdextended_enabled)
416 		return (0);
417 
418 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
419 	if (error)
420 		return (error);
421 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
422 	    MBI_EXEC));
423 }
424 
425 static int
426 mac_bsdextended_check_create_vnode(struct ucred *cred, struct vnode *dvp,
427     struct label *dlabel, struct componentname *cnp, struct vattr *vap)
428 {
429 	struct vattr dvap;
430 	int error;
431 
432 	if (!mac_bsdextended_enabled)
433 		return (0);
434 
435 	error = VOP_GETATTR(dvp, &dvap, cred, curthread);
436 	if (error)
437 		return (error);
438 	return (mac_bsdextended_check(cred, dvap.va_uid, dvap.va_gid,
439 	    MBI_WRITE));
440 }
441 
442 static int
443 mac_bsdextended_check_vnode_delete(struct ucred *cred, struct vnode *dvp,
444     struct label *dlabel, struct vnode *vp, struct label *label,
445     struct componentname *cnp)
446 {
447 	struct vattr vap;
448 	int error;
449 
450 	if (!mac_bsdextended_enabled)
451 		return (0);
452 
453 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
454 	if (error)
455 		return (error);
456 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
457 	    MBI_WRITE);
458 	if (error)
459 		return (error);
460 
461 	error = VOP_GETATTR(vp, &vap, cred, curthread);
462 	if (error)
463 		return (error);
464 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
465 	    MBI_WRITE));
466 }
467 
468 static int
469 mac_bsdextended_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
470     struct label *label, acl_type_t type)
471 {
472 	struct vattr vap;
473 	int error;
474 
475 	if (!mac_bsdextended_enabled)
476 		return (0);
477 
478 	error = VOP_GETATTR(vp, &vap, cred, curthread);
479 	if (error)
480 		return (error);
481 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
482 	    MBI_ADMIN));
483 }
484 
485 static int
486 mac_bsdextended_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp,
487     struct label *label, int attrnamespace, const char *name)
488 {
489 	struct vattr vap;
490 	int error;
491 
492 	if (!mac_bsdextended_enabled)
493 		return (0);
494 
495 	error = VOP_GETATTR(vp, &vap, cred, curthread);
496 	if (error)
497 		return (error);
498 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
499 	    MBI_WRITE));
500 }
501 
502 static int
503 mac_bsdextended_check_vnode_exec(struct ucred *cred, struct vnode *vp,
504     struct label *label, struct image_params *imgp,
505     struct label *execlabel)
506 {
507 	struct vattr vap;
508 	int error;
509 
510 	if (!mac_bsdextended_enabled)
511 		return (0);
512 
513 	error = VOP_GETATTR(vp, &vap, cred, curthread);
514 	if (error)
515 		return (error);
516 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
517 	    MBI_READ|MBI_EXEC));
518 }
519 
520 static int
521 mac_bsdextended_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
522     struct label *label, acl_type_t type)
523 {
524 	struct vattr vap;
525 	int error;
526 
527 	if (!mac_bsdextended_enabled)
528 		return (0);
529 
530 	error = VOP_GETATTR(vp, &vap, cred, curthread);
531 	if (error)
532 		return (error);
533 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
534 	    MBI_STAT));
535 }
536 
537 static int
538 mac_bsdextended_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
539     struct label *label, int attrnamespace, const char *name, struct uio *uio)
540 {
541 	struct vattr vap;
542 	int error;
543 
544 	if (!mac_bsdextended_enabled)
545 		return (0);
546 
547 	error = VOP_GETATTR(vp, &vap, cred, curthread);
548 	if (error)
549 		return (error);
550 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
551 	    MBI_READ));
552 }
553 
554 static int
555 mac_bsdextended_check_vnode_link(struct ucred *cred, struct vnode *dvp,
556     struct label *dlabel, struct vnode *vp, struct label *label,
557     struct componentname *cnp)
558 {
559 	struct vattr vap;
560 	int error;
561 
562 	if (!mac_bsdextended_enabled)
563 		return (0);
564 
565 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
566 	if (error)
567 		return (error);
568 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
569 	    MBI_WRITE);
570 	if (error)
571 		return (error);
572 
573 	error = VOP_GETATTR(vp, &vap, cred, curthread);
574 	if (error)
575 		return (error);
576 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
577 	    MBI_WRITE);
578 	if (error)
579 		return (error);
580 	return (0);
581 }
582 
583 static int
584 mac_bsdextended_check_vnode_listextattr(struct ucred *cred, struct vnode *vp,
585     struct label *label, int attrnamespace)
586 {
587 	struct vattr vap;
588 	int error;
589 
590 	if (!mac_bsdextended_enabled)
591 		return (0);
592 
593 	error = VOP_GETATTR(vp, &vap, cred, curthread);
594 	if (error)
595 		return (error);
596 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
597 	    MBI_READ));
598 }
599 
600 static int
601 mac_bsdextended_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
602     struct label *dlabel, struct componentname *cnp)
603 {
604 	struct vattr vap;
605 	int error;
606 
607 	if (!mac_bsdextended_enabled)
608 		return (0);
609 
610 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
611 	if (error)
612 		return (error);
613 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
614 	    MBI_EXEC));
615 }
616 
617 static int
618 mac_bsdextended_check_vnode_open(struct ucred *cred, struct vnode *vp,
619     struct label *filelabel, int acc_mode)
620 {
621 	struct vattr vap;
622 	int error;
623 
624 	if (!mac_bsdextended_enabled)
625 		return (0);
626 
627 	error = VOP_GETATTR(vp, &vap, cred, curthread);
628 	if (error)
629 		return (error);
630 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid, acc_mode));
631 }
632 
633 static int
634 mac_bsdextended_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
635     struct label *dlabel)
636 {
637 	struct vattr vap;
638 	int error;
639 
640 	if (!mac_bsdextended_enabled)
641 		return (0);
642 
643 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
644 	if (error)
645 		return (error);
646 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
647 	    MBI_READ));
648 }
649 
650 static int
651 mac_bsdextended_check_vnode_readdlink(struct ucred *cred, struct vnode *vp,
652     struct label *label)
653 {
654 	struct vattr vap;
655 	int error;
656 
657 	if (!mac_bsdextended_enabled)
658 		return (0);
659 
660 	error = VOP_GETATTR(vp, &vap, cred, curthread);
661 	if (error)
662 		return (error);
663 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
664 	    MBI_READ));
665 }
666 
667 static int
668 mac_bsdextended_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
669     struct label *dlabel, struct vnode *vp, struct label *label,
670     struct componentname *cnp)
671 {
672 	struct vattr vap;
673 	int error;
674 
675 	if (!mac_bsdextended_enabled)
676 		return (0);
677 
678 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
679 	if (error)
680 		return (error);
681 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
682 	    MBI_WRITE);
683 	if (error)
684 		return (error);
685 	error = VOP_GETATTR(vp, &vap, cred, curthread);
686 	if (error)
687 		return (error);
688 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
689 	    MBI_WRITE);
690 
691 	return (error);
692 }
693 
694 static int
695 mac_bsdextended_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
696     struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
697     struct componentname *cnp)
698 {
699 	struct vattr vap;
700 	int error;
701 
702 	if (!mac_bsdextended_enabled)
703 		return (0);
704 
705 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
706 	if (error)
707 		return (error);
708 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
709 	    MBI_WRITE);
710 	if (error)
711 		return (error);
712 
713 	if (vp != NULL) {
714 		error = VOP_GETATTR(vp, &vap, cred, curthread);
715 		if (error)
716 			return (error);
717 		error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
718 		    MBI_WRITE);
719 	}
720 
721 	return (error);
722 }
723 
724 static int
725 mac_bsdextended_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
726     struct label *label)
727 {
728 	struct vattr vap;
729 	int error;
730 
731 	if (!mac_bsdextended_enabled)
732 		return (0);
733 
734 	error = VOP_GETATTR(vp, &vap, cred, curthread);
735 	if (error)
736 		return (error);
737 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
738 	    MBI_ADMIN));
739 }
740 
741 static int
742 mac_bsdextended_check_setacl_vnode(struct ucred *cred, struct vnode *vp,
743     struct label *label, acl_type_t type, struct acl *acl)
744 {
745 	struct vattr vap;
746 	int error;
747 
748 	if (!mac_bsdextended_enabled)
749 		return (0);
750 
751 	error = VOP_GETATTR(vp, &vap, cred, curthread);
752 	if (error)
753 		return (error);
754 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
755 	    MBI_ADMIN));
756 }
757 
758 static int
759 mac_bsdextended_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
760     struct label *label, int attrnamespace, const char *name, struct uio *uio)
761 {
762 	struct vattr vap;
763 	int error;
764 
765 	if (!mac_bsdextended_enabled)
766 		return (0);
767 
768 	error = VOP_GETATTR(vp, &vap, cred, curthread);
769 	if (error)
770 		return (error);
771 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
772 	    MBI_WRITE));
773 }
774 
775 static int
776 mac_bsdextended_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
777     struct label *label, u_long flags)
778 {
779 	struct vattr vap;
780 	int error;
781 
782 	if (!mac_bsdextended_enabled)
783 		return (0);
784 
785 	error = VOP_GETATTR(vp, &vap, cred, curthread);
786 	if (error)
787 		return (error);
788 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
789 	    MBI_ADMIN));
790 }
791 
792 static int
793 mac_bsdextended_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
794     struct label *label, mode_t mode)
795 {
796 	struct vattr vap;
797 	int error;
798 
799 	if (!mac_bsdextended_enabled)
800 		return (0);
801 
802 	error = VOP_GETATTR(vp, &vap, cred, curthread);
803 	if (error)
804 		return (error);
805 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
806 	    MBI_ADMIN));
807 }
808 
809 static int
810 mac_bsdextended_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
811     struct label *label, uid_t uid, gid_t gid)
812 {
813 	struct vattr vap;
814 	int error;
815 
816 	if (!mac_bsdextended_enabled)
817 		return (0);
818 
819 	error = VOP_GETATTR(vp, &vap, cred, curthread);
820 	if (error)
821 		return (error);
822 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
823 	   MBI_ADMIN));
824 }
825 
826 static int
827 mac_bsdextended_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
828     struct label *label, struct timespec atime, struct timespec utime)
829 {
830 	struct vattr vap;
831 	int error;
832 
833 	if (!mac_bsdextended_enabled)
834 		return (0);
835 
836 	error = VOP_GETATTR(vp, &vap, cred, curthread);
837 	if (error)
838 		return (error);
839 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
840 	    MBI_ADMIN));
841 }
842 
843 static int
844 mac_bsdextended_check_vnode_stat(struct ucred *active_cred,
845     struct ucred *file_cred, struct vnode *vp, struct label *label)
846 {
847 	struct vattr vap;
848 	int error;
849 
850 	if (!mac_bsdextended_enabled)
851 		return (0);
852 
853 	error = VOP_GETATTR(vp, &vap, active_cred, curthread);
854 	if (error)
855 		return (error);
856 	return (mac_bsdextended_check(active_cred, vap.va_uid, vap.va_gid,
857 	    MBI_STAT));
858 }
859 
860 static struct mac_policy_ops mac_bsdextended_ops =
861 {
862 	.mpo_destroy = mac_bsdextended_destroy,
863 	.mpo_init = mac_bsdextended_init,
864 	.mpo_check_system_swapon = mac_bsdextended_check_system_swapon,
865 	.mpo_check_vnode_access = mac_bsdextended_check_vnode_access,
866 	.mpo_check_vnode_chdir = mac_bsdextended_check_vnode_chdir,
867 	.mpo_check_vnode_chroot = mac_bsdextended_check_vnode_chroot,
868 	.mpo_check_vnode_create = mac_bsdextended_check_create_vnode,
869 	.mpo_check_vnode_delete = mac_bsdextended_check_vnode_delete,
870 	.mpo_check_vnode_deleteacl = mac_bsdextended_check_vnode_deleteacl,
871 	.mpo_check_vnode_deleteextattr = mac_bsdextended_check_vnode_deleteextattr,
872 	.mpo_check_vnode_exec = mac_bsdextended_check_vnode_exec,
873 	.mpo_check_vnode_getacl = mac_bsdextended_check_vnode_getacl,
874 	.mpo_check_vnode_getextattr = mac_bsdextended_check_vnode_getextattr,
875 	.mpo_check_vnode_link = mac_bsdextended_check_vnode_link,
876 	.mpo_check_vnode_listextattr = mac_bsdextended_check_vnode_listextattr,
877 	.mpo_check_vnode_lookup = mac_bsdextended_check_vnode_lookup,
878 	.mpo_check_vnode_open = mac_bsdextended_check_vnode_open,
879 	.mpo_check_vnode_readdir = mac_bsdextended_check_vnode_readdir,
880 	.mpo_check_vnode_readlink = mac_bsdextended_check_vnode_readdlink,
881 	.mpo_check_vnode_rename_from = mac_bsdextended_check_vnode_rename_from,
882 	.mpo_check_vnode_rename_to = mac_bsdextended_check_vnode_rename_to,
883 	.mpo_check_vnode_revoke = mac_bsdextended_check_vnode_revoke,
884 	.mpo_check_vnode_setacl = mac_bsdextended_check_setacl_vnode,
885 	.mpo_check_vnode_setextattr = mac_bsdextended_check_vnode_setextattr,
886 	.mpo_check_vnode_setflags = mac_bsdextended_check_vnode_setflags,
887 	.mpo_check_vnode_setmode = mac_bsdextended_check_vnode_setmode,
888 	.mpo_check_vnode_setowner = mac_bsdextended_check_vnode_setowner,
889 	.mpo_check_vnode_setutimes = mac_bsdextended_check_vnode_setutimes,
890 	.mpo_check_vnode_stat = mac_bsdextended_check_vnode_stat,
891 };
892 
893 MAC_POLICY_SET(&mac_bsdextended_ops, mac_bsdextended,
894     "TrustedBSD MAC/BSD Extended", MPC_LOADTIME_FLAG_UNLOADOK, NULL);
895