xref: /freebsd/sys/security/mac_bsdextended/mac_bsdextended.c (revision e4e9813eb92cd7c4d4b819a8fbed5cbd3d92f5d8)
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/jail.h>
51 #include <sys/lock.h>
52 #include <sys/mac.h>
53 #include <sys/malloc.h>
54 #include <sys/mount.h>
55 #include <sys/mutex.h>
56 #include <sys/proc.h>
57 #include <sys/systm.h>
58 #include <sys/sysproto.h>
59 #include <sys/sysent.h>
60 #include <sys/vnode.h>
61 #include <sys/file.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/sysctl.h>
65 #include <sys/syslog.h>
66 #include <sys/ucred.h>
67 
68 #include <net/bpfdesc.h>
69 #include <net/if.h>
70 #include <net/if_types.h>
71 #include <net/if_var.h>
72 
73 #include <vm/vm.h>
74 
75 #include <sys/mac_policy.h>
76 
77 #include <security/mac_bsdextended/mac_bsdextended.h>
78 
79 static struct mtx mac_bsdextended_mtx;
80 
81 SYSCTL_DECL(_security_mac);
82 
83 SYSCTL_NODE(_security_mac, OID_AUTO, bsdextended, CTLFLAG_RW, 0,
84     "TrustedBSD extended BSD MAC policy controls");
85 
86 static int	mac_bsdextended_enabled = 1;
87 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, enabled, CTLFLAG_RW,
88     &mac_bsdextended_enabled, 0, "Enforce extended BSD policy");
89 TUNABLE_INT("security.mac.bsdextended.enabled", &mac_bsdextended_enabled);
90 
91 MALLOC_DEFINE(M_MACBSDEXTENDED, "mac_bsdextended", "BSD Extended MAC rule");
92 
93 #define	MAC_BSDEXTENDED_MAXRULES	250
94 static struct mac_bsdextended_rule *rules[MAC_BSDEXTENDED_MAXRULES];
95 static int rule_count = 0;
96 static int rule_slots = 0;
97 static int rule_version = MB_VERSION;
98 
99 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_count, CTLFLAG_RD,
100     &rule_count, 0, "Number of defined rules\n");
101 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_slots, CTLFLAG_RD,
102     &rule_slots, 0, "Number of used rule slots\n");
103 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_version, CTLFLAG_RD,
104     &rule_version, 0, "Version number for API\n");
105 
106 /*
107  * This is just used for logging purposes, eventually we would like
108  * to log much more then failed requests.
109  */
110 static int mac_bsdextended_logging;
111 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, logging, CTLFLAG_RW,
112     &mac_bsdextended_logging, 0, "Log failed authorization requests");
113 
114 /*
115  * This tunable is here for compatibility.  It will allow the user
116  * to switch between the new mode (first rule matches) and the old
117  * functionality (all rules match).
118  */
119 static int
120 mac_bsdextended_firstmatch_enabled;
121 SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, firstmatch_enabled,
122 	CTLFLAG_RW, &mac_bsdextended_firstmatch_enabled, 1,
123 	"Disable/enable match first rule functionality");
124 
125 static int
126 mac_bsdextended_rule_valid(struct mac_bsdextended_rule *rule)
127 {
128 
129 	if ((rule->mbr_subject.mbs_flags | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
130 		return (EINVAL);
131 
132 	if ((rule->mbr_subject.mbs_neg | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
133 		return (EINVAL);
134 
135 	if ((rule->mbr_object.mbo_flags | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
136 		return (EINVAL);
137 
138 	if ((rule->mbr_object.mbo_neg | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
139 		return (EINVAL);
140 
141 	if ((rule->mbr_object.mbo_neg | MBO_TYPE_DEFINED) &&
142 	    (rule->mbr_object.mbo_type | MBO_ALL_TYPE) != MBO_ALL_TYPE)
143 		return (EINVAL);
144 
145 	if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM)
146 		return (EINVAL);
147 
148 	return (0);
149 }
150 
151 static int
152 sysctl_rule(SYSCTL_HANDLER_ARGS)
153 {
154 	struct mac_bsdextended_rule temprule, *ruleptr;
155 	u_int namelen;
156 	int error, index, *name;
157 
158 	error = 0;
159 	name = (int *)arg1;
160 	namelen = arg2;
161 
162 	/* printf("bsdextended sysctl handler (namelen %d)\n", namelen); */
163 
164 	if (namelen != 1)
165 		return (EINVAL);
166 
167 	index = name[0];
168         if (index >= MAC_BSDEXTENDED_MAXRULES)
169 		return (ENOENT);
170 
171 	ruleptr = NULL;
172 	if (req->newptr && req->newlen != 0) {
173 		error = SYSCTL_IN(req, &temprule, sizeof(temprule));
174 		if (error)
175 			return (error);
176 		MALLOC(ruleptr, struct mac_bsdextended_rule *,
177 		    sizeof(*ruleptr), M_MACBSDEXTENDED, M_WAITOK | M_ZERO);
178 	}
179 
180 	mtx_lock(&mac_bsdextended_mtx);
181 
182 	if (req->oldptr) {
183 		if (index < 0 || index > rule_slots + 1) {
184 			error = ENOENT;
185 			goto out;
186 		}
187 		if (rules[index] == NULL) {
188 			error = ENOENT;
189 			goto out;
190 		}
191 		temprule = *rules[index];
192 	}
193 
194 	if (req->newptr && req->newlen == 0) {
195 		/* printf("deletion\n"); */
196 		KASSERT(ruleptr == NULL, ("sysctl_rule: ruleptr != NULL"));
197 		ruleptr = rules[index];
198 		if (ruleptr == NULL) {
199 			error = ENOENT;
200 			goto out;
201 		}
202 		rule_count--;
203 		rules[index] = NULL;
204 	} else if (req->newptr) {
205 		error = mac_bsdextended_rule_valid(&temprule);
206 		if (error)
207 			goto out;
208 
209 		if (rules[index] == NULL) {
210 			/* printf("addition\n"); */
211 			*ruleptr = temprule;
212 			rules[index] = ruleptr;
213 			ruleptr = NULL;
214 			if (index + 1 > rule_slots)
215 				rule_slots = index + 1;
216 			rule_count++;
217 		} else {
218 			/* printf("replacement\n"); */
219 			*rules[index] = temprule;
220 		}
221 	}
222 
223 out:
224 	mtx_unlock(&mac_bsdextended_mtx);
225 	if (ruleptr != NULL)
226 		FREE(ruleptr, M_MACBSDEXTENDED);
227 	if (req->oldptr && error == 0)
228 		error = SYSCTL_OUT(req, &temprule, sizeof(temprule));
229 
230 	return (error);
231 }
232 
233 SYSCTL_NODE(_security_mac_bsdextended, OID_AUTO, rules,
234     CTLFLAG_RW, sysctl_rule, "BSD extended MAC rules");
235 
236 static void
237 mac_bsdextended_init(struct mac_policy_conf *mpc)
238 {
239 
240 	/* Initialize ruleset lock. */
241 	mtx_init(&mac_bsdextended_mtx, "mac_bsdextended lock", NULL, MTX_DEF);
242 
243 	/* Register dynamic sysctl's for rules. */
244 }
245 
246 static void
247 mac_bsdextended_destroy(struct mac_policy_conf *mpc)
248 {
249 
250 	/* Destroy ruleset lock. */
251 	mtx_destroy(&mac_bsdextended_mtx);
252 
253 	/* Tear down sysctls. */
254 }
255 
256 static int
257 mac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
258     struct ucred *cred, struct vnode *vp, struct vattr *vap, int acc_mode)
259 {
260 	int match;
261 	int i;
262 
263 	/*
264 	 * Is there a subject match?
265 	 */
266 	mtx_assert(&mac_bsdextended_mtx, MA_OWNED);
267 	if (rule->mbr_subject.mbs_flags & MBS_UID_DEFINED) {
268 		match =  ((cred->cr_uid <= rule->mbr_subject.mbs_uid_max &&
269 		    cred->cr_uid >= rule->mbr_subject.mbs_uid_min) ||
270 		    (cred->cr_ruid <= rule->mbr_subject.mbs_uid_max &&
271 		    cred->cr_ruid >= rule->mbr_subject.mbs_uid_min) ||
272 		    (cred->cr_svuid <= rule->mbr_subject.mbs_uid_max &&
273 		    cred->cr_svuid >= rule->mbr_subject.mbs_uid_min));
274 
275 		if (rule->mbr_subject.mbs_neg & MBS_UID_DEFINED)
276 			match = !match;
277 
278 		if (!match)
279 			return (0);
280 	}
281 
282 	if (rule->mbr_subject.mbs_flags & MBS_GID_DEFINED) {
283 		match = ((cred->cr_rgid <= rule->mbr_subject.mbs_gid_max &&
284 		    cred->cr_rgid >= rule->mbr_subject.mbs_gid_min) ||
285 		    (cred->cr_svgid <= rule->mbr_subject.mbs_gid_max &&
286 		    cred->cr_svgid >= rule->mbr_subject.mbs_gid_min));
287 
288 		if (!match) {
289 			for (i = 0; i < cred->cr_ngroups; i++)
290 				if (cred->cr_groups[i]
291 				    <= rule->mbr_subject.mbs_gid_max &&
292 				    cred->cr_groups[i]
293 				    >= rule->mbr_subject.mbs_gid_min) {
294 					match = 1;
295 					break;
296 				}
297 		}
298 
299 		if (rule->mbr_subject.mbs_neg & MBS_GID_DEFINED)
300 			match = !match;
301 
302 		if (!match)
303 			return (0);
304 	}
305 
306 	if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
307 		match = (cred->cr_prison != NULL &&
308 		    cred->cr_prison->pr_id == rule->mbr_subject.mbs_prison);
309 
310 		if (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)
311 			match = !match;
312 
313 		if (!match)
314 			return (0);
315 	}
316 
317 	/*
318 	 * Is there an object match?
319 	 */
320 	if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
321 		match = (vap->va_uid <= rule->mbr_object.mbo_uid_max &&
322 		    vap->va_uid >= rule->mbr_object.mbo_uid_min);
323 
324 		if (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)
325 			match = !match;
326 
327 		if (!match)
328 			return (0);
329 	}
330 
331 	if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
332 		match = (vap->va_gid <= rule->mbr_object.mbo_gid_max &&
333 		    vap->va_gid >= rule->mbr_object.mbo_gid_min);
334 
335 		if (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)
336 			match = !match;
337 
338 		if (!match)
339 			return (0);
340 	}
341 
342 	if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
343 		match = (bcmp(&(vp->v_mount->mnt_stat.f_fsid),
344 		    &(rule->mbr_object.mbo_fsid),
345 		    sizeof(rule->mbr_object.mbo_fsid)) == 0);
346 
347 		if (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)
348 			match = !match;
349 
350 		if (!match)
351 			return 0;
352 	}
353 
354 	if (rule->mbr_object.mbo_flags & MBO_SUID) {
355 		match = (vap->va_mode & VSUID);
356 
357 		if (rule->mbr_object.mbo_neg & MBO_SUID)
358 			match = !match;
359 
360 		if (!match)
361 			return 0;
362 	}
363 
364 	if (rule->mbr_object.mbo_flags & MBO_SGID) {
365 		match = (vap->va_mode & VSGID);
366 
367 		if (rule->mbr_object.mbo_neg & MBO_SGID)
368 			match = !match;
369 
370 		if (!match)
371 			return 0;
372 	}
373 
374 	if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
375 		match = (vap->va_uid == cred->cr_uid ||
376 		    vap->va_uid == cred->cr_ruid ||
377 		    vap->va_uid == cred->cr_svuid);
378 
379 		if (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)
380 			match = !match;
381 
382 		if (!match)
383 			return 0;
384 	}
385 
386 	if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
387 		match = (groupmember(vap->va_gid, cred) ||
388 		    vap->va_gid == cred->cr_rgid ||
389 		    vap->va_gid == cred->cr_svgid);
390 
391 		if (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)
392 			match = !match;
393 
394 		if (!match)
395 			return 0;
396 	}
397 
398 	if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
399 		switch (vap->va_type) {
400 		case VREG:
401 			match = (rule->mbr_object.mbo_type & MBO_TYPE_REG);
402 			break;
403 		case VDIR:
404 			match = (rule->mbr_object.mbo_type & MBO_TYPE_DIR);
405 			break;
406 		case VBLK:
407 			match = (rule->mbr_object.mbo_type & MBO_TYPE_BLK);
408 			break;
409 		case VCHR:
410 			match = (rule->mbr_object.mbo_type & MBO_TYPE_CHR);
411 			break;
412 		case VLNK:
413 			match = (rule->mbr_object.mbo_type & MBO_TYPE_LNK);
414 			break;
415 		case VSOCK:
416 			match = (rule->mbr_object.mbo_type & MBO_TYPE_SOCK);
417 			break;
418 		case VFIFO:
419 			match = (rule->mbr_object.mbo_type & MBO_TYPE_FIFO);
420 			break;
421 		default:
422 			match = 0;
423 		}
424 
425 		if (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)
426 			match = !match;
427 
428 		if (!match)
429 			return 0;
430 	}
431 
432 	/*
433 	 * Is the access permitted?
434 	 */
435 	if ((rule->mbr_mode & acc_mode) != acc_mode) {
436 		if (mac_bsdextended_logging)
437 			log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d"
438 			    " on %d:%d failed. \n", cred->cr_ruid,
439 			    cred->cr_rgid, acc_mode, vap->va_uid, vap->va_gid);
440 		return (EACCES); /* Matching rule denies access */
441 	}
442 
443 	/*
444 	 * If the rule matched, permits access, and first match is enabled,
445 	 * return success.
446 	 */
447 	if (mac_bsdextended_firstmatch_enabled)
448 		return (EJUSTRETURN);
449 	else
450 		return(0);
451 }
452 
453 static int
454 mac_bsdextended_check(struct ucred *cred, struct vnode *vp, struct vattr *vap,
455     int acc_mode)
456 {
457 	int error, i;
458 
459 	if (suser_cred(cred, 0) == 0)
460 		return (0);
461 
462 	mtx_lock(&mac_bsdextended_mtx);
463 	for (i = 0; i < rule_slots; i++) {
464 		if (rules[i] == NULL)
465 			continue;
466 
467 		/*
468 		 * Since we do not separately handle append, map append to
469 		 * write.
470 		 */
471 		if (acc_mode & MBI_APPEND) {
472 			acc_mode &= ~MBI_APPEND;
473 			acc_mode |= MBI_WRITE;
474 		}
475 
476 		error = mac_bsdextended_rulecheck(rules[i], cred,
477 		    vp, vap, acc_mode);
478 		if (error == EJUSTRETURN)
479 			break;
480 		if (error) {
481 			mtx_unlock(&mac_bsdextended_mtx);
482 			return (error);
483 		}
484 	}
485 	mtx_unlock(&mac_bsdextended_mtx);
486 	return (0);
487 }
488 
489 static int
490 mac_bsdextended_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode)
491 {
492 	int error;
493 	struct vattr vap;
494 
495 	if (!mac_bsdextended_enabled)
496 		return (0);
497 
498 	error = VOP_GETATTR(vp, &vap, cred, curthread);
499 	if (error)
500 		return (error);
501 
502 	return (mac_bsdextended_check(cred, vp, &vap, acc_mode));
503 }
504 
505 static int
506 mac_bsdextended_check_system_swapon(struct ucred *cred, struct vnode *vp,
507     struct label *label)
508 {
509 
510 	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
511 }
512 
513 static int
514 mac_bsdextended_check_vnode_access(struct ucred *cred, struct vnode *vp,
515     struct label *label, int acc_mode)
516 {
517 
518 	return (mac_bsdextended_check_vp(cred, vp, acc_mode));
519 }
520 
521 static int
522 mac_bsdextended_check_vnode_chdir(struct ucred *cred, struct vnode *dvp,
523     struct label *dlabel)
524 {
525 
526 	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
527 }
528 
529 static int
530 mac_bsdextended_check_vnode_chroot(struct ucred *cred, struct vnode *dvp,
531     struct label *dlabel)
532 {
533 
534 	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
535 }
536 
537 static int
538 mac_bsdextended_check_create_vnode(struct ucred *cred, struct vnode *dvp,
539     struct label *dlabel, struct componentname *cnp, struct vattr *vap)
540 {
541 
542 	return (mac_bsdextended_check_vp(cred, dvp, MBI_WRITE));
543 }
544 
545 static int
546 mac_bsdextended_check_vnode_delete(struct ucred *cred, struct vnode *dvp,
547     struct label *dlabel, struct vnode *vp, struct label *label,
548     struct componentname *cnp)
549 {
550 	int error;
551 
552 	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
553 	if (error)
554 		return (error);
555 
556 	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
557 }
558 
559 static int
560 mac_bsdextended_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
561     struct label *label, acl_type_t type)
562 {
563 
564 	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
565 }
566 
567 static int
568 mac_bsdextended_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp,
569     struct label *label, int attrnamespace, const char *name)
570 {
571 
572 	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
573 }
574 
575 static int
576 mac_bsdextended_check_vnode_exec(struct ucred *cred, struct vnode *vp,
577     struct label *label, struct image_params *imgp,
578     struct label *execlabel)
579 {
580 
581 	return (mac_bsdextended_check_vp(cred, vp, MBI_READ|MBI_EXEC));
582 }
583 
584 static int
585 mac_bsdextended_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
586     struct label *label, acl_type_t type)
587 {
588 
589 	return (mac_bsdextended_check_vp(cred, vp, MBI_STAT));
590 }
591 
592 static int
593 mac_bsdextended_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
594     struct label *label, int attrnamespace, const char *name, struct uio *uio)
595 {
596 
597 	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
598 }
599 
600 static int
601 mac_bsdextended_check_vnode_link(struct ucred *cred, struct vnode *dvp,
602     struct label *dlabel, struct vnode *vp, struct label *label,
603     struct componentname *cnp)
604 {
605 	int error;
606 
607 	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
608 	if (error)
609 		return (error);
610 
611 	error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
612 	if (error)
613 		return (error);
614 	return (0);
615 }
616 
617 static int
618 mac_bsdextended_check_vnode_listextattr(struct ucred *cred, struct vnode *vp,
619     struct label *label, int attrnamespace)
620 {
621 
622 	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
623 }
624 
625 static int
626 mac_bsdextended_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
627     struct label *dlabel, struct componentname *cnp)
628 {
629 
630 	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
631 }
632 
633 static int
634 mac_bsdextended_check_vnode_open(struct ucred *cred, struct vnode *vp,
635     struct label *filelabel, int acc_mode)
636 {
637 
638 	return (mac_bsdextended_check_vp(cred, vp, acc_mode));
639 }
640 
641 static int
642 mac_bsdextended_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
643     struct label *dlabel)
644 {
645 
646 	return (mac_bsdextended_check_vp(cred, dvp, MBI_READ));
647 }
648 
649 static int
650 mac_bsdextended_check_vnode_readdlink(struct ucred *cred, struct vnode *vp,
651     struct label *label)
652 {
653 
654 	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
655 }
656 
657 static int
658 mac_bsdextended_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
659     struct label *dlabel, struct vnode *vp, struct label *label,
660     struct componentname *cnp)
661 {
662 	int error;
663 
664 	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
665 	if (error)
666 		return (error);
667 	error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
668 
669 	return (error);
670 }
671 
672 static int
673 mac_bsdextended_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
674     struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
675     struct componentname *cnp)
676 {
677 	int error;
678 
679 	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
680 	if (error)
681 		return (error);
682 
683 	if (vp != NULL)
684 		error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
685 
686 	return (error);
687 }
688 
689 static int
690 mac_bsdextended_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
691     struct label *label)
692 {
693 
694 	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
695 }
696 
697 static int
698 mac_bsdextended_check_setacl_vnode(struct ucred *cred, struct vnode *vp,
699     struct label *label, acl_type_t type, struct acl *acl)
700 {
701 
702 	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
703 }
704 
705 static int
706 mac_bsdextended_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
707     struct label *label, int attrnamespace, const char *name, struct uio *uio)
708 {
709 
710 	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
711 }
712 
713 static int
714 mac_bsdextended_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
715     struct label *label, u_long flags)
716 {
717 
718 	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
719 }
720 
721 static int
722 mac_bsdextended_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
723     struct label *label, mode_t mode)
724 {
725 
726 	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
727 }
728 
729 static int
730 mac_bsdextended_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
731     struct label *label, uid_t uid, gid_t gid)
732 {
733 
734 	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
735 }
736 
737 static int
738 mac_bsdextended_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
739     struct label *label, struct timespec atime, struct timespec utime)
740 {
741 
742 	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
743 }
744 
745 static int
746 mac_bsdextended_check_vnode_stat(struct ucred *active_cred,
747     struct ucred *file_cred, struct vnode *vp, struct label *label)
748 {
749 
750 	return (mac_bsdextended_check_vp(active_cred, vp, MBI_STAT));
751 }
752 
753 static struct mac_policy_ops mac_bsdextended_ops =
754 {
755 	.mpo_destroy = mac_bsdextended_destroy,
756 	.mpo_init = mac_bsdextended_init,
757 	.mpo_check_system_swapon = mac_bsdextended_check_system_swapon,
758 	.mpo_check_vnode_access = mac_bsdextended_check_vnode_access,
759 	.mpo_check_vnode_chdir = mac_bsdextended_check_vnode_chdir,
760 	.mpo_check_vnode_chroot = mac_bsdextended_check_vnode_chroot,
761 	.mpo_check_vnode_create = mac_bsdextended_check_create_vnode,
762 	.mpo_check_vnode_delete = mac_bsdextended_check_vnode_delete,
763 	.mpo_check_vnode_deleteacl = mac_bsdextended_check_vnode_deleteacl,
764 	.mpo_check_vnode_deleteextattr = mac_bsdextended_check_vnode_deleteextattr,
765 	.mpo_check_vnode_exec = mac_bsdextended_check_vnode_exec,
766 	.mpo_check_vnode_getacl = mac_bsdextended_check_vnode_getacl,
767 	.mpo_check_vnode_getextattr = mac_bsdextended_check_vnode_getextattr,
768 	.mpo_check_vnode_link = mac_bsdextended_check_vnode_link,
769 	.mpo_check_vnode_listextattr = mac_bsdextended_check_vnode_listextattr,
770 	.mpo_check_vnode_lookup = mac_bsdextended_check_vnode_lookup,
771 	.mpo_check_vnode_open = mac_bsdextended_check_vnode_open,
772 	.mpo_check_vnode_readdir = mac_bsdextended_check_vnode_readdir,
773 	.mpo_check_vnode_readlink = mac_bsdextended_check_vnode_readdlink,
774 	.mpo_check_vnode_rename_from = mac_bsdextended_check_vnode_rename_from,
775 	.mpo_check_vnode_rename_to = mac_bsdextended_check_vnode_rename_to,
776 	.mpo_check_vnode_revoke = mac_bsdextended_check_vnode_revoke,
777 	.mpo_check_vnode_setacl = mac_bsdextended_check_setacl_vnode,
778 	.mpo_check_vnode_setextattr = mac_bsdextended_check_vnode_setextattr,
779 	.mpo_check_vnode_setflags = mac_bsdextended_check_vnode_setflags,
780 	.mpo_check_vnode_setmode = mac_bsdextended_check_vnode_setmode,
781 	.mpo_check_vnode_setowner = mac_bsdextended_check_vnode_setowner,
782 	.mpo_check_vnode_setutimes = mac_bsdextended_check_vnode_setutimes,
783 	.mpo_check_vnode_stat = mac_bsdextended_check_vnode_stat,
784 };
785 
786 MAC_POLICY_SET(&mac_bsdextended_ops, mac_bsdextended,
787     "TrustedBSD MAC/BSD Extended", MPC_LOADTIME_FLAG_UNLOADOK, NULL);
788