xref: /freebsd/sys/security/mac_bsdextended/mac_bsdextended.c (revision 262e143bd46171a6415a5b28af260a5efa2a3db8)
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 
215 	return (error);
216 }
217 
218 SYSCTL_NODE(_security_mac_bsdextended, OID_AUTO, rules,
219     CTLFLAG_RW, sysctl_rule, "BSD extended MAC rules");
220 
221 static void
222 mac_bsdextended_init(struct mac_policy_conf *mpc)
223 {
224 
225 	/* Initialize ruleset lock. */
226 	mtx_init(&mac_bsdextended_mtx, "mac_bsdextended lock", NULL, MTX_DEF);
227 
228 	/* Register dynamic sysctl's for rules. */
229 }
230 
231 static void
232 mac_bsdextended_destroy(struct mac_policy_conf *mpc)
233 {
234 
235 	/* Destroy ruleset lock. */
236 	mtx_destroy(&mac_bsdextended_mtx);
237 
238 	/* Tear down sysctls. */
239 }
240 
241 static int
242 mac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
243     struct ucred *cred, uid_t object_uid, gid_t object_gid, int acc_mode)
244 {
245 	int match;
246 
247 	/*
248 	 * Is there a subject match?
249 	 */
250 	mtx_assert(&mac_bsdextended_mtx, MA_OWNED);
251 	if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
252 		match =  (rule->mbr_subject.mbi_uid == cred->cr_uid ||
253 		    rule->mbr_subject.mbi_uid == cred->cr_ruid ||
254 		    rule->mbr_subject.mbi_uid == cred->cr_svuid);
255 
256 		if (rule->mbr_subject.mbi_flags & MBI_NEGATED)
257 			match = !match;
258 
259 		if (!match)
260 			return (0);
261 	}
262 
263 	if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
264 		match = (groupmember(rule->mbr_subject.mbi_gid, cred) ||
265 		    rule->mbr_subject.mbi_gid == cred->cr_rgid ||
266 		    rule->mbr_subject.mbi_gid == cred->cr_svgid);
267 
268 		if (rule->mbr_subject.mbi_flags & MBI_NEGATED)
269 			match = !match;
270 
271 		if (!match)
272 			return (0);
273 	}
274 
275 	/*
276 	 * Is there an object match?
277 	 */
278 	if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
279 		match = (rule->mbr_object.mbi_uid == object_uid);
280 
281 		if (rule->mbr_object.mbi_flags & MBI_NEGATED)
282 			match = !match;
283 
284 		if (!match)
285 			return (0);
286 	}
287 
288 	if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
289 		match = (rule->mbr_object.mbi_gid == object_gid);
290 
291 		if (rule->mbr_object.mbi_flags & MBI_NEGATED)
292 			match = !match;
293 
294 		if (!match)
295 			return (0);
296 	}
297 
298 	/*
299 	 * Is the access permitted?
300 	 */
301 	if ((rule->mbr_mode & acc_mode) != acc_mode) {
302 		if (mac_bsdextended_logging)
303 			log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d"
304 			    " on %d:%d failed. \n", cred->cr_ruid,
305 			    cred->cr_rgid, acc_mode, object_uid, object_gid);
306 		return (EACCES); /* Matching rule denies access */
307 	}
308 
309 	/*
310 	 * If the rule matched, permits access, and first match is enabled,
311 	 * return success.
312 	 */
313 	if (mac_bsdextended_firstmatch_enabled)
314 		return (EJUSTRETURN);
315 	else
316 		return(0);
317 }
318 
319 static int
320 mac_bsdextended_check(struct ucred *cred, uid_t object_uid, gid_t object_gid,
321     int acc_mode)
322 {
323 	int error, i;
324 
325 	if (suser_cred(cred, 0) == 0)
326 		return (0);
327 
328 	mtx_lock(&mac_bsdextended_mtx);
329 	for (i = 0; i < rule_slots; i++) {
330 		if (rules[i] == NULL)
331 			continue;
332 
333 		/*
334 		 * Since we do not separately handle append, map append to
335 		 * write.
336 		 */
337 		if (acc_mode & MBI_APPEND) {
338 			acc_mode &= ~MBI_APPEND;
339 			acc_mode |= MBI_WRITE;
340 		}
341 
342 		error = mac_bsdextended_rulecheck(rules[i], cred, object_uid,
343 		    object_gid, acc_mode);
344 		if (error == EJUSTRETURN)
345 			break;
346 		if (error) {
347 			mtx_unlock(&mac_bsdextended_mtx);
348 			return (error);
349 		}
350 	}
351 	mtx_unlock(&mac_bsdextended_mtx);
352 	return (0);
353 }
354 
355 static int
356 mac_bsdextended_check_system_swapon(struct ucred *cred, struct vnode *vp,
357     struct label *label)
358 {
359 	struct vattr vap;
360 	int error;
361 
362 	if (!mac_bsdextended_enabled)
363 		return (0);
364 
365 	error = VOP_GETATTR(vp, &vap, cred, curthread);
366 	if (error)
367 		return (error);
368 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
369 	    MBI_WRITE));
370 }
371 
372 static int
373 mac_bsdextended_check_vnode_access(struct ucred *cred, struct vnode *vp,
374     struct label *label, int acc_mode)
375 {
376 	struct vattr vap;
377 	int error;
378 
379 	if (!mac_bsdextended_enabled)
380 		return (0);
381 
382 	error = VOP_GETATTR(vp, &vap, cred, curthread);
383 	if (error)
384 		return (error);
385 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid, acc_mode));
386 }
387 
388 static int
389 mac_bsdextended_check_vnode_chdir(struct ucred *cred, struct vnode *dvp,
390     struct label *dlabel)
391 {
392 	struct vattr vap;
393 	int error;
394 
395 	if (!mac_bsdextended_enabled)
396 		return (0);
397 
398 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
399 	if (error)
400 		return (error);
401 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
402 	    MBI_EXEC));
403 }
404 
405 static int
406 mac_bsdextended_check_vnode_chroot(struct ucred *cred, struct vnode *dvp,
407     struct label *dlabel)
408 {
409 	struct vattr vap;
410 	int error;
411 
412 	if (!mac_bsdextended_enabled)
413 		return (0);
414 
415 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
416 	if (error)
417 		return (error);
418 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
419 	    MBI_EXEC));
420 }
421 
422 static int
423 mac_bsdextended_check_create_vnode(struct ucred *cred, struct vnode *dvp,
424     struct label *dlabel, struct componentname *cnp, struct vattr *vap)
425 {
426 	struct vattr dvap;
427 	int error;
428 
429 	if (!mac_bsdextended_enabled)
430 		return (0);
431 
432 	error = VOP_GETATTR(dvp, &dvap, cred, curthread);
433 	if (error)
434 		return (error);
435 	return (mac_bsdextended_check(cred, dvap.va_uid, dvap.va_gid,
436 	    MBI_WRITE));
437 }
438 
439 static int
440 mac_bsdextended_check_vnode_delete(struct ucred *cred, struct vnode *dvp,
441     struct label *dlabel, struct vnode *vp, struct label *label,
442     struct componentname *cnp)
443 {
444 	struct vattr vap;
445 	int error;
446 
447 	if (!mac_bsdextended_enabled)
448 		return (0);
449 
450 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
451 	if (error)
452 		return (error);
453 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
454 	    MBI_WRITE);
455 	if (error)
456 		return (error);
457 
458 	error = VOP_GETATTR(vp, &vap, cred, curthread);
459 	if (error)
460 		return (error);
461 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
462 	    MBI_WRITE));
463 }
464 
465 static int
466 mac_bsdextended_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
467     struct label *label, acl_type_t type)
468 {
469 	struct vattr vap;
470 	int error;
471 
472 	if (!mac_bsdextended_enabled)
473 		return (0);
474 
475 	error = VOP_GETATTR(vp, &vap, cred, curthread);
476 	if (error)
477 		return (error);
478 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
479 	    MBI_ADMIN));
480 }
481 
482 static int
483 mac_bsdextended_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp,
484     struct label *label, int attrnamespace, const char *name)
485 {
486 	struct vattr vap;
487 	int error;
488 
489 	if (!mac_bsdextended_enabled)
490 		return (0);
491 
492 	error = VOP_GETATTR(vp, &vap, cred, curthread);
493 	if (error)
494 		return (error);
495 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
496 	    MBI_WRITE));
497 }
498 
499 static int
500 mac_bsdextended_check_vnode_exec(struct ucred *cred, struct vnode *vp,
501     struct label *label, struct image_params *imgp,
502     struct label *execlabel)
503 {
504 	struct vattr vap;
505 	int error;
506 
507 	if (!mac_bsdextended_enabled)
508 		return (0);
509 
510 	error = VOP_GETATTR(vp, &vap, cred, curthread);
511 	if (error)
512 		return (error);
513 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
514 	    MBI_READ|MBI_EXEC));
515 }
516 
517 static int
518 mac_bsdextended_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
519     struct label *label, acl_type_t type)
520 {
521 	struct vattr vap;
522 	int error;
523 
524 	if (!mac_bsdextended_enabled)
525 		return (0);
526 
527 	error = VOP_GETATTR(vp, &vap, cred, curthread);
528 	if (error)
529 		return (error);
530 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
531 	    MBI_STAT));
532 }
533 
534 static int
535 mac_bsdextended_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
536     struct label *label, int attrnamespace, const char *name, struct uio *uio)
537 {
538 	struct vattr vap;
539 	int error;
540 
541 	if (!mac_bsdextended_enabled)
542 		return (0);
543 
544 	error = VOP_GETATTR(vp, &vap, cred, curthread);
545 	if (error)
546 		return (error);
547 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
548 	    MBI_READ));
549 }
550 
551 static int
552 mac_bsdextended_check_vnode_link(struct ucred *cred, struct vnode *dvp,
553     struct label *dlabel, struct vnode *vp, struct label *label,
554     struct componentname *cnp)
555 {
556 	struct vattr vap;
557 	int error;
558 
559 	if (!mac_bsdextended_enabled)
560 		return (0);
561 
562 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
563 	if (error)
564 		return (error);
565 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
566 	    MBI_WRITE);
567 	if (error)
568 		return (error);
569 
570 	error = VOP_GETATTR(vp, &vap, cred, curthread);
571 	if (error)
572 		return (error);
573 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
574 	    MBI_WRITE);
575 	if (error)
576 		return (error);
577 	return (0);
578 }
579 
580 static int
581 mac_bsdextended_check_vnode_listextattr(struct ucred *cred, struct vnode *vp,
582     struct label *label, int attrnamespace)
583 {
584 	struct vattr vap;
585 	int error;
586 
587 	if (!mac_bsdextended_enabled)
588 		return (0);
589 
590 	error = VOP_GETATTR(vp, &vap, cred, curthread);
591 	if (error)
592 		return (error);
593 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
594 	    MBI_READ));
595 }
596 
597 static int
598 mac_bsdextended_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
599     struct label *dlabel, struct componentname *cnp)
600 {
601 	struct vattr vap;
602 	int error;
603 
604 	if (!mac_bsdextended_enabled)
605 		return (0);
606 
607 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
608 	if (error)
609 		return (error);
610 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
611 	    MBI_EXEC));
612 }
613 
614 static int
615 mac_bsdextended_check_vnode_open(struct ucred *cred, struct vnode *vp,
616     struct label *filelabel, int acc_mode)
617 {
618 	struct vattr vap;
619 	int error;
620 
621 	if (!mac_bsdextended_enabled)
622 		return (0);
623 
624 	error = VOP_GETATTR(vp, &vap, cred, curthread);
625 	if (error)
626 		return (error);
627 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid, acc_mode));
628 }
629 
630 static int
631 mac_bsdextended_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
632     struct label *dlabel)
633 {
634 	struct vattr vap;
635 	int error;
636 
637 	if (!mac_bsdextended_enabled)
638 		return (0);
639 
640 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
641 	if (error)
642 		return (error);
643 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
644 	    MBI_READ));
645 }
646 
647 static int
648 mac_bsdextended_check_vnode_readdlink(struct ucred *cred, struct vnode *vp,
649     struct label *label)
650 {
651 	struct vattr vap;
652 	int error;
653 
654 	if (!mac_bsdextended_enabled)
655 		return (0);
656 
657 	error = VOP_GETATTR(vp, &vap, cred, curthread);
658 	if (error)
659 		return (error);
660 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
661 	    MBI_READ));
662 }
663 
664 static int
665 mac_bsdextended_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
666     struct label *dlabel, struct vnode *vp, struct label *label,
667     struct componentname *cnp)
668 {
669 	struct vattr vap;
670 	int error;
671 
672 	if (!mac_bsdextended_enabled)
673 		return (0);
674 
675 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
676 	if (error)
677 		return (error);
678 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
679 	    MBI_WRITE);
680 	if (error)
681 		return (error);
682 	error = VOP_GETATTR(vp, &vap, cred, curthread);
683 	if (error)
684 		return (error);
685 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
686 	    MBI_WRITE);
687 
688 	return (error);
689 }
690 
691 static int
692 mac_bsdextended_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
693     struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
694     struct componentname *cnp)
695 {
696 	struct vattr vap;
697 	int error;
698 
699 	if (!mac_bsdextended_enabled)
700 		return (0);
701 
702 	error = VOP_GETATTR(dvp, &vap, cred, curthread);
703 	if (error)
704 		return (error);
705 	error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
706 	    MBI_WRITE);
707 	if (error)
708 		return (error);
709 
710 	if (vp != NULL) {
711 		error = VOP_GETATTR(vp, &vap, cred, curthread);
712 		if (error)
713 			return (error);
714 		error = mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
715 		    MBI_WRITE);
716 	}
717 
718 	return (error);
719 }
720 
721 static int
722 mac_bsdextended_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
723     struct label *label)
724 {
725 	struct vattr vap;
726 	int error;
727 
728 	if (!mac_bsdextended_enabled)
729 		return (0);
730 
731 	error = VOP_GETATTR(vp, &vap, cred, curthread);
732 	if (error)
733 		return (error);
734 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
735 	    MBI_ADMIN));
736 }
737 
738 static int
739 mac_bsdextended_check_setacl_vnode(struct ucred *cred, struct vnode *vp,
740     struct label *label, acl_type_t type, struct acl *acl)
741 {
742 	struct vattr vap;
743 	int error;
744 
745 	if (!mac_bsdextended_enabled)
746 		return (0);
747 
748 	error = VOP_GETATTR(vp, &vap, cred, curthread);
749 	if (error)
750 		return (error);
751 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
752 	    MBI_ADMIN));
753 }
754 
755 static int
756 mac_bsdextended_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
757     struct label *label, int attrnamespace, const char *name, struct uio *uio)
758 {
759 	struct vattr vap;
760 	int error;
761 
762 	if (!mac_bsdextended_enabled)
763 		return (0);
764 
765 	error = VOP_GETATTR(vp, &vap, cred, curthread);
766 	if (error)
767 		return (error);
768 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
769 	    MBI_WRITE));
770 }
771 
772 static int
773 mac_bsdextended_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
774     struct label *label, u_long flags)
775 {
776 	struct vattr vap;
777 	int error;
778 
779 	if (!mac_bsdextended_enabled)
780 		return (0);
781 
782 	error = VOP_GETATTR(vp, &vap, cred, curthread);
783 	if (error)
784 		return (error);
785 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
786 	    MBI_ADMIN));
787 }
788 
789 static int
790 mac_bsdextended_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
791     struct label *label, mode_t mode)
792 {
793 	struct vattr vap;
794 	int error;
795 
796 	if (!mac_bsdextended_enabled)
797 		return (0);
798 
799 	error = VOP_GETATTR(vp, &vap, cred, curthread);
800 	if (error)
801 		return (error);
802 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
803 	    MBI_ADMIN));
804 }
805 
806 static int
807 mac_bsdextended_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
808     struct label *label, uid_t uid, gid_t gid)
809 {
810 	struct vattr vap;
811 	int error;
812 
813 	if (!mac_bsdextended_enabled)
814 		return (0);
815 
816 	error = VOP_GETATTR(vp, &vap, cred, curthread);
817 	if (error)
818 		return (error);
819 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
820 	   MBI_ADMIN));
821 }
822 
823 static int
824 mac_bsdextended_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
825     struct label *label, struct timespec atime, struct timespec utime)
826 {
827 	struct vattr vap;
828 	int error;
829 
830 	if (!mac_bsdextended_enabled)
831 		return (0);
832 
833 	error = VOP_GETATTR(vp, &vap, cred, curthread);
834 	if (error)
835 		return (error);
836 	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
837 	    MBI_ADMIN));
838 }
839 
840 static int
841 mac_bsdextended_check_vnode_stat(struct ucred *active_cred,
842     struct ucred *file_cred, struct vnode *vp, struct label *label)
843 {
844 	struct vattr vap;
845 	int error;
846 
847 	if (!mac_bsdextended_enabled)
848 		return (0);
849 
850 	error = VOP_GETATTR(vp, &vap, active_cred, curthread);
851 	if (error)
852 		return (error);
853 	return (mac_bsdextended_check(active_cred, vap.va_uid, vap.va_gid,
854 	    MBI_STAT));
855 }
856 
857 static struct mac_policy_ops mac_bsdextended_ops =
858 {
859 	.mpo_destroy = mac_bsdextended_destroy,
860 	.mpo_init = mac_bsdextended_init,
861 	.mpo_check_system_swapon = mac_bsdextended_check_system_swapon,
862 	.mpo_check_vnode_access = mac_bsdextended_check_vnode_access,
863 	.mpo_check_vnode_chdir = mac_bsdextended_check_vnode_chdir,
864 	.mpo_check_vnode_chroot = mac_bsdextended_check_vnode_chroot,
865 	.mpo_check_vnode_create = mac_bsdextended_check_create_vnode,
866 	.mpo_check_vnode_delete = mac_bsdextended_check_vnode_delete,
867 	.mpo_check_vnode_deleteacl = mac_bsdextended_check_vnode_deleteacl,
868 	.mpo_check_vnode_deleteextattr = mac_bsdextended_check_vnode_deleteextattr,
869 	.mpo_check_vnode_exec = mac_bsdextended_check_vnode_exec,
870 	.mpo_check_vnode_getacl = mac_bsdextended_check_vnode_getacl,
871 	.mpo_check_vnode_getextattr = mac_bsdextended_check_vnode_getextattr,
872 	.mpo_check_vnode_link = mac_bsdextended_check_vnode_link,
873 	.mpo_check_vnode_listextattr = mac_bsdextended_check_vnode_listextattr,
874 	.mpo_check_vnode_lookup = mac_bsdextended_check_vnode_lookup,
875 	.mpo_check_vnode_open = mac_bsdextended_check_vnode_open,
876 	.mpo_check_vnode_readdir = mac_bsdextended_check_vnode_readdir,
877 	.mpo_check_vnode_readlink = mac_bsdextended_check_vnode_readdlink,
878 	.mpo_check_vnode_rename_from = mac_bsdextended_check_vnode_rename_from,
879 	.mpo_check_vnode_rename_to = mac_bsdextended_check_vnode_rename_to,
880 	.mpo_check_vnode_revoke = mac_bsdextended_check_vnode_revoke,
881 	.mpo_check_vnode_setacl = mac_bsdextended_check_setacl_vnode,
882 	.mpo_check_vnode_setextattr = mac_bsdextended_check_vnode_setextattr,
883 	.mpo_check_vnode_setflags = mac_bsdextended_check_vnode_setflags,
884 	.mpo_check_vnode_setmode = mac_bsdextended_check_vnode_setmode,
885 	.mpo_check_vnode_setowner = mac_bsdextended_check_vnode_setowner,
886 	.mpo_check_vnode_setutimes = mac_bsdextended_check_vnode_setutimes,
887 	.mpo_check_vnode_stat = mac_bsdextended_check_vnode_stat,
888 };
889 
890 MAC_POLICY_SET(&mac_bsdextended_ops, mac_bsdextended,
891     "TrustedBSD MAC/BSD Extended", MPC_LOADTIME_FLAG_UNLOADOK, NULL);
892