ugidfw_system.c revision 164033
1101099Srwatson/*-
2145412Strhodes * Copyright (c) 2005 Tom Rhodes
3126097Srwatson * Copyright (c) 1999-2002 Robert N. M. Watson
4145412Strhodes * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5101099Srwatson * All rights reserved.
6101099Srwatson *
7101099Srwatson * This software was developed by Robert Watson for the TrustedBSD Project.
8145412Strhodes * It was later enhanced by Tom Rhodes for the TrustedBSD Project.
9101099Srwatson *
10106393Srwatson * This software was developed for the FreeBSD Project in part by Network
11106393Srwatson * Associates Laboratories, the Security Research Division of Network
12106393Srwatson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13106393Srwatson * as part of the DARPA CHATS research program.
14101099Srwatson *
15101099Srwatson * Redistribution and use in source and binary forms, with or without
16101099Srwatson * modification, are permitted provided that the following conditions
17101099Srwatson * are met:
18101099Srwatson * 1. Redistributions of source code must retain the above copyright
19101099Srwatson *    notice, this list of conditions and the following disclaimer.
20101099Srwatson * 2. Redistributions in binary form must reproduce the above copyright
21101099Srwatson *    notice, this list of conditions and the following disclaimer in the
22101099Srwatson *    documentation and/or other materials provided with the distribution.
23101099Srwatson *
24101099Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25101099Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26101099Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27101099Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28101099Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29101099Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30101099Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31101099Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32101099Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33101099Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34101099Srwatson * SUCH DAMAGE.
35101099Srwatson *
36101099Srwatson * $FreeBSD: head/sys/security/mac_bsdextended/mac_bsdextended.c 164033 2006-11-06 13:42:10Z rwatson $
37101099Srwatson */
38136774Srwatson
39101099Srwatson/*
40101099Srwatson * Developed by the TrustedBSD Project.
41101099Srwatson * "BSD Extended" MAC policy, allowing the administrator to impose
42101099Srwatson * mandatory rules regarding users and some system objects.
43101099Srwatson */
44101099Srwatson
45101099Srwatson#include <sys/types.h>
46101099Srwatson#include <sys/param.h>
47101099Srwatson#include <sys/acl.h>
48101099Srwatson#include <sys/conf.h>
49101099Srwatson#include <sys/kernel.h>
50157986Sdwmalone#include <sys/jail.h>
51145412Strhodes#include <sys/lock.h>
52101099Srwatson#include <sys/mac.h>
53101099Srwatson#include <sys/malloc.h>
54101099Srwatson#include <sys/mount.h>
55145412Strhodes#include <sys/mutex.h>
56101099Srwatson#include <sys/proc.h>
57101099Srwatson#include <sys/systm.h>
58101099Srwatson#include <sys/sysproto.h>
59101099Srwatson#include <sys/sysent.h>
60101099Srwatson#include <sys/vnode.h>
61101099Srwatson#include <sys/file.h>
62101099Srwatson#include <sys/socket.h>
63101099Srwatson#include <sys/socketvar.h>
64101099Srwatson#include <sys/sysctl.h>
65134132Strhodes#include <sys/syslog.h>
66157986Sdwmalone#include <sys/ucred.h>
67101099Srwatson
68101099Srwatson#include <net/bpfdesc.h>
69101099Srwatson#include <net/if.h>
70101099Srwatson#include <net/if_types.h>
71101099Srwatson#include <net/if_var.h>
72101099Srwatson
73101099Srwatson#include <vm/vm.h>
74101099Srwatson
75101099Srwatson#include <sys/mac_policy.h>
76101099Srwatson
77101099Srwatson#include <security/mac_bsdextended/mac_bsdextended.h>
78101099Srwatson
79145412Strhodesstatic struct mtx mac_bsdextended_mtx;
80145412Strhodes
81101099SrwatsonSYSCTL_DECL(_security_mac);
82101099Srwatson
83101099SrwatsonSYSCTL_NODE(_security_mac, OID_AUTO, bsdextended, CTLFLAG_RW, 0,
84101099Srwatson    "TrustedBSD extended BSD MAC policy controls");
85101099Srwatson
86101099Srwatsonstatic int	mac_bsdextended_enabled = 1;
87101099SrwatsonSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, enabled, CTLFLAG_RW,
88101099Srwatson    &mac_bsdextended_enabled, 0, "Enforce extended BSD policy");
89101099SrwatsonTUNABLE_INT("security.mac.bsdextended.enabled", &mac_bsdextended_enabled);
90101099Srwatson
91101099SrwatsonMALLOC_DEFINE(M_MACBSDEXTENDED, "mac_bsdextended", "BSD Extended MAC rule");
92101099Srwatson
93101099Srwatson#define	MAC_BSDEXTENDED_MAXRULES	250
94101099Srwatsonstatic struct mac_bsdextended_rule *rules[MAC_BSDEXTENDED_MAXRULES];
95101099Srwatsonstatic int rule_count = 0;
96101099Srwatsonstatic int rule_slots = 0;
97157986Sdwmalonestatic int rule_version = MB_VERSION;
98101099Srwatson
99101099SrwatsonSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_count, CTLFLAG_RD,
100101099Srwatson    &rule_count, 0, "Number of defined rules\n");
101101099SrwatsonSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_slots, CTLFLAG_RD,
102101099Srwatson    &rule_slots, 0, "Number of used rule slots\n");
103157986SdwmaloneSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_version, CTLFLAG_RD,
104157986Sdwmalone    &rule_version, 0, "Version number for API\n");
105101099Srwatson
106134132Strhodes/*
107145412Strhodes * This is just used for logging purposes, eventually we would like
108134132Strhodes * to log much more then failed requests.
109134132Strhodes */
110134132Strhodesstatic int mac_bsdextended_logging;
111134132StrhodesSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, logging, CTLFLAG_RW,
112134132Strhodes    &mac_bsdextended_logging, 0, "Log failed authorization requests");
113134132Strhodes
114134132Strhodes/*
115134131Strhodes * This tunable is here for compatibility.  It will allow the user
116134131Strhodes * to switch between the new mode (first rule matches) and the old
117134131Strhodes * functionality (all rules match).
118134131Strhodes */
119101099Srwatsonstatic int
120134131Strhodesmac_bsdextended_firstmatch_enabled;
121134131StrhodesSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, firstmatch_enabled,
122135039Strhodes	CTLFLAG_RW, &mac_bsdextended_firstmatch_enabled, 1,
123134131Strhodes	"Disable/enable match first rule functionality");
124134131Strhodes
125134131Strhodesstatic int
126101099Srwatsonmac_bsdextended_rule_valid(struct mac_bsdextended_rule *rule)
127101099Srwatson{
128101099Srwatson
129157986Sdwmalone	if ((rule->mbr_subject.mbs_flags | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
130101099Srwatson		return (EINVAL);
131101099Srwatson
132157986Sdwmalone	if ((rule->mbr_subject.mbs_neg | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
133101099Srwatson		return (EINVAL);
134101099Srwatson
135157986Sdwmalone	if ((rule->mbr_object.mbo_flags | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
136157986Sdwmalone		return (EINVAL);
137157986Sdwmalone
138157986Sdwmalone	if ((rule->mbr_object.mbo_neg | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
139157986Sdwmalone		return (EINVAL);
140157986Sdwmalone
141157986Sdwmalone	if ((rule->mbr_object.mbo_neg | MBO_TYPE_DEFINED) &&
142157986Sdwmalone	    (rule->mbr_object.mbo_type | MBO_ALL_TYPE) != MBO_ALL_TYPE)
143157986Sdwmalone		return (EINVAL);
144157986Sdwmalone
145136739Srwatson	if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM)
146101099Srwatson		return (EINVAL);
147101099Srwatson
148101099Srwatson	return (0);
149101099Srwatson}
150101099Srwatson
151101099Srwatsonstatic int
152101099Srwatsonsysctl_rule(SYSCTL_HANDLER_ARGS)
153101099Srwatson{
154101099Srwatson	struct mac_bsdextended_rule temprule, *ruleptr;
155101099Srwatson	u_int namelen;
156101099Srwatson	int error, index, *name;
157101099Srwatson
158145412Strhodes	error = 0;
159101099Srwatson	name = (int *)arg1;
160101099Srwatson	namelen = arg2;
161101099Srwatson
162101099Srwatson	/* printf("bsdextended sysctl handler (namelen %d)\n", namelen); */
163101099Srwatson
164101099Srwatson	if (namelen != 1)
165101099Srwatson		return (EINVAL);
166101099Srwatson
167101099Srwatson	index = name[0];
168154386Scsjp        if (index >= MAC_BSDEXTENDED_MAXRULES)
169101099Srwatson		return (ENOENT);
170101099Srwatson
171145412Strhodes	ruleptr = NULL;
172145412Strhodes	if (req->newptr && req->newlen != 0) {
173145412Strhodes		error = SYSCTL_IN(req, &temprule, sizeof(temprule));
174101099Srwatson		if (error)
175101099Srwatson			return (error);
176145412Strhodes		MALLOC(ruleptr, struct mac_bsdextended_rule *,
177145412Strhodes		    sizeof(*ruleptr), M_MACBSDEXTENDED, M_WAITOK | M_ZERO);
178101099Srwatson	}
179101099Srwatson
180145412Strhodes	mtx_lock(&mac_bsdextended_mtx);
181145412Strhodes
182145412Strhodes	if (req->oldptr) {
183145412Strhodes		if (index < 0 || index > rule_slots + 1) {
184145412Strhodes			error = ENOENT;
185145412Strhodes			goto out;
186101099Srwatson		}
187145412Strhodes		if (rules[index] == NULL) {
188145412Strhodes			error = ENOENT;
189145412Strhodes			goto out;
190145412Strhodes		}
191145412Strhodes		temprule = *rules[index];
192145412Strhodes	}
193101099Srwatson
194145412Strhodes	if (req->newptr && req->newlen == 0) {
195145412Strhodes		/* printf("deletion\n"); */
196145412Strhodes		KASSERT(ruleptr == NULL, ("sysctl_rule: ruleptr != NULL"));
197145412Strhodes		ruleptr = rules[index];
198145412Strhodes		if (ruleptr == NULL) {
199145412Strhodes			error = ENOENT;
200145412Strhodes			goto out;
201145412Strhodes		}
202145412Strhodes		rule_count--;
203145412Strhodes		rules[index] = NULL;
204145412Strhodes	} else if (req->newptr) {
205101099Srwatson		error = mac_bsdextended_rule_valid(&temprule);
206101099Srwatson		if (error)
207145412Strhodes			goto out;
208101099Srwatson
209101099Srwatson		if (rules[index] == NULL) {
210101099Srwatson			/* printf("addition\n"); */
211101099Srwatson			*ruleptr = temprule;
212101099Srwatson			rules[index] = ruleptr;
213145412Strhodes			ruleptr = NULL;
214145412Strhodes			if (index + 1 > rule_slots)
215145412Strhodes				rule_slots = index + 1;
216101099Srwatson			rule_count++;
217101099Srwatson		} else {
218101099Srwatson			/* printf("replacement\n"); */
219101099Srwatson			*rules[index] = temprule;
220101099Srwatson		}
221101099Srwatson	}
222101099Srwatson
223145412Strhodesout:
224145412Strhodes	mtx_unlock(&mac_bsdextended_mtx);
225145412Strhodes	if (ruleptr != NULL)
226145412Strhodes		FREE(ruleptr, M_MACBSDEXTENDED);
227148482Strhodes	if (req->oldptr && error == 0)
228145412Strhodes		error = SYSCTL_OUT(req, &temprule, sizeof(temprule));
229145412Strhodes
230148482Strhodes	return (error);
231101099Srwatson}
232101099Srwatson
233101099SrwatsonSYSCTL_NODE(_security_mac_bsdextended, OID_AUTO, rules,
234101099Srwatson    CTLFLAG_RW, sysctl_rule, "BSD extended MAC rules");
235101099Srwatson
236101099Srwatsonstatic void
237101099Srwatsonmac_bsdextended_init(struct mac_policy_conf *mpc)
238101099Srwatson{
239101099Srwatson
240101099Srwatson	/* Initialize ruleset lock. */
241145412Strhodes	mtx_init(&mac_bsdextended_mtx, "mac_bsdextended lock", NULL, MTX_DEF);
242145412Strhodes
243101099Srwatson	/* Register dynamic sysctl's for rules. */
244101099Srwatson}
245101099Srwatson
246101099Srwatsonstatic void
247101099Srwatsonmac_bsdextended_destroy(struct mac_policy_conf *mpc)
248101099Srwatson{
249101099Srwatson
250145412Strhodes	/* Destroy ruleset lock. */
251145412Strhodes	mtx_destroy(&mac_bsdextended_mtx);
252145412Strhodes
253101099Srwatson	/* Tear down sysctls. */
254101099Srwatson}
255101099Srwatson
256101099Srwatsonstatic int
257101099Srwatsonmac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
258157986Sdwmalone    struct ucred *cred, struct vnode *vp, struct vattr *vap, int acc_mode)
259101099Srwatson{
260101099Srwatson	int match;
261157986Sdwmalone	int i;
262101099Srwatson
263101099Srwatson	/*
264101099Srwatson	 * Is there a subject match?
265101099Srwatson	 */
266145412Strhodes	mtx_assert(&mac_bsdextended_mtx, MA_OWNED);
267157986Sdwmalone	if (rule->mbr_subject.mbs_flags & MBS_UID_DEFINED) {
268157986Sdwmalone		match =  ((cred->cr_uid <= rule->mbr_subject.mbs_uid_max &&
269157986Sdwmalone		    cred->cr_uid >= rule->mbr_subject.mbs_uid_min) ||
270157986Sdwmalone		    (cred->cr_ruid <= rule->mbr_subject.mbs_uid_max &&
271157986Sdwmalone		    cred->cr_ruid >= rule->mbr_subject.mbs_uid_min) ||
272157986Sdwmalone		    (cred->cr_svuid <= rule->mbr_subject.mbs_uid_max &&
273157986Sdwmalone		    cred->cr_svuid >= rule->mbr_subject.mbs_uid_min));
274101099Srwatson
275157986Sdwmalone		if (rule->mbr_subject.mbs_neg & MBS_UID_DEFINED)
276101099Srwatson			match = !match;
277101099Srwatson
278101099Srwatson		if (!match)
279101099Srwatson			return (0);
280101099Srwatson	}
281101099Srwatson
282157986Sdwmalone	if (rule->mbr_subject.mbs_flags & MBS_GID_DEFINED) {
283157986Sdwmalone		match = ((cred->cr_rgid <= rule->mbr_subject.mbs_gid_max &&
284157986Sdwmalone		    cred->cr_rgid >= rule->mbr_subject.mbs_gid_min) ||
285157986Sdwmalone		    (cred->cr_svgid <= rule->mbr_subject.mbs_gid_max &&
286157986Sdwmalone		    cred->cr_svgid >= rule->mbr_subject.mbs_gid_min));
287101099Srwatson
288157986Sdwmalone		if (!match) {
289157986Sdwmalone			for (i = 0; i < cred->cr_ngroups; i++)
290157986Sdwmalone				if (cred->cr_groups[i]
291157986Sdwmalone				    <= rule->mbr_subject.mbs_gid_max &&
292157986Sdwmalone				    cred->cr_groups[i]
293157986Sdwmalone				    >= rule->mbr_subject.mbs_gid_min) {
294157986Sdwmalone					match = 1;
295157986Sdwmalone					break;
296157986Sdwmalone				}
297157986Sdwmalone		}
298157986Sdwmalone
299157986Sdwmalone		if (rule->mbr_subject.mbs_neg & MBS_GID_DEFINED)
300101099Srwatson			match = !match;
301101099Srwatson
302101099Srwatson		if (!match)
303101099Srwatson			return (0);
304101099Srwatson	}
305101099Srwatson
306157986Sdwmalone	if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
307157986Sdwmalone		match = (cred->cr_prison != NULL &&
308157986Sdwmalone		    cred->cr_prison->pr_id == rule->mbr_subject.mbs_prison);
309157986Sdwmalone
310157986Sdwmalone		if (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)
311157986Sdwmalone			match = !match;
312157986Sdwmalone
313157986Sdwmalone		if (!match)
314157986Sdwmalone			return (0);
315157986Sdwmalone	}
316157986Sdwmalone
317101099Srwatson	/*
318101099Srwatson	 * Is there an object match?
319101099Srwatson	 */
320157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
321157986Sdwmalone		match = (vap->va_uid <= rule->mbr_object.mbo_uid_max &&
322157986Sdwmalone		    vap->va_uid >= rule->mbr_object.mbo_uid_min);
323101099Srwatson
324157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)
325101099Srwatson			match = !match;
326101099Srwatson
327101099Srwatson		if (!match)
328101099Srwatson			return (0);
329101099Srwatson	}
330101099Srwatson
331157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
332157986Sdwmalone		match = (vap->va_gid <= rule->mbr_object.mbo_gid_max &&
333157986Sdwmalone		    vap->va_gid >= rule->mbr_object.mbo_gid_min);
334101099Srwatson
335157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)
336101099Srwatson			match = !match;
337101099Srwatson
338101099Srwatson		if (!match)
339101099Srwatson			return (0);
340101099Srwatson	}
341101099Srwatson
342157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
343157986Sdwmalone		match = (bcmp(&(vp->v_mount->mnt_stat.f_fsid),
344157986Sdwmalone		    &(rule->mbr_object.mbo_fsid),
345157986Sdwmalone		    sizeof(rule->mbr_object.mbo_fsid)) == 0);
346157986Sdwmalone
347157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)
348157986Sdwmalone			match = !match;
349157986Sdwmalone
350157986Sdwmalone		if (!match)
351157986Sdwmalone			return 0;
352157986Sdwmalone	}
353157986Sdwmalone
354157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_SUID) {
355157986Sdwmalone		match = (vap->va_mode & VSUID);
356157986Sdwmalone
357157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_SUID)
358157986Sdwmalone			match = !match;
359157986Sdwmalone
360157986Sdwmalone		if (!match)
361157986Sdwmalone			return 0;
362157986Sdwmalone	}
363157986Sdwmalone
364157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_SGID) {
365157986Sdwmalone		match = (vap->va_mode & VSGID);
366157986Sdwmalone
367157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_SGID)
368157986Sdwmalone			match = !match;
369157986Sdwmalone
370157986Sdwmalone		if (!match)
371157986Sdwmalone			return 0;
372157986Sdwmalone	}
373157986Sdwmalone
374157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
375157986Sdwmalone		match = (vap->va_uid == cred->cr_uid ||
376157986Sdwmalone		    vap->va_uid == cred->cr_ruid ||
377157986Sdwmalone		    vap->va_uid == cred->cr_svuid);
378157986Sdwmalone
379157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)
380157986Sdwmalone			match = !match;
381157986Sdwmalone
382157986Sdwmalone		if (!match)
383157986Sdwmalone			return 0;
384157986Sdwmalone	}
385157986Sdwmalone
386157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
387157986Sdwmalone		match = (groupmember(vap->va_gid, cred) ||
388157986Sdwmalone		    vap->va_gid == cred->cr_rgid ||
389157986Sdwmalone		    vap->va_gid == cred->cr_svgid);
390157986Sdwmalone
391157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)
392157986Sdwmalone			match = !match;
393157986Sdwmalone
394157986Sdwmalone		if (!match)
395157986Sdwmalone			return 0;
396157986Sdwmalone	}
397157986Sdwmalone
398157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
399157986Sdwmalone		switch (vap->va_type) {
400157986Sdwmalone		case VREG:
401157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_REG);
402157986Sdwmalone			break;
403157986Sdwmalone		case VDIR:
404157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_DIR);
405157986Sdwmalone			break;
406157986Sdwmalone		case VBLK:
407157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_BLK);
408157986Sdwmalone			break;
409157986Sdwmalone		case VCHR:
410157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_CHR);
411157986Sdwmalone			break;
412157986Sdwmalone		case VLNK:
413157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_LNK);
414157986Sdwmalone			break;
415157986Sdwmalone		case VSOCK:
416157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_SOCK);
417157986Sdwmalone			break;
418157986Sdwmalone		case VFIFO:
419157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_FIFO);
420157986Sdwmalone			break;
421157986Sdwmalone		default:
422157986Sdwmalone			match = 0;
423157986Sdwmalone		}
424157986Sdwmalone
425157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)
426157986Sdwmalone			match = !match;
427157986Sdwmalone
428157986Sdwmalone		if (!match)
429157986Sdwmalone			return 0;
430157986Sdwmalone	}
431157986Sdwmalone
432101099Srwatson	/*
433101099Srwatson	 * Is the access permitted?
434101099Srwatson	 */
435101099Srwatson	if ((rule->mbr_mode & acc_mode) != acc_mode) {
436134132Strhodes		if (mac_bsdextended_logging)
437134132Strhodes			log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d"
438134132Strhodes			    " on %d:%d failed. \n", cred->cr_ruid,
439157986Sdwmalone			    cred->cr_rgid, acc_mode, vap->va_uid, vap->va_gid);
440134132Strhodes		return (EACCES); /* Matching rule denies access */
441101099Srwatson	}
442145412Strhodes
443134131Strhodes	/*
444145412Strhodes	 * If the rule matched, permits access, and first match is enabled,
445145412Strhodes	 * return success.
446134131Strhodes	 */
447134131Strhodes	if (mac_bsdextended_firstmatch_enabled)
448134131Strhodes		return (EJUSTRETURN);
449134131Strhodes	else
450134131Strhodes		return(0);
451101099Srwatson}
452101099Srwatson
453101099Srwatsonstatic int
454157986Sdwmalonemac_bsdextended_check(struct ucred *cred, struct vnode *vp, struct vattr *vap,
455106212Srwatson    int acc_mode)
456101099Srwatson{
457101099Srwatson	int error, i;
458101099Srwatson
459164033Srwatson	/*
460164033Srwatson	 * XXXRW: More specific privilege selection needed?
461164033Srwatson	 */
462132563Srwatson	if (suser_cred(cred, 0) == 0)
463132563Srwatson		return (0);
464132563Srwatson
465145412Strhodes	mtx_lock(&mac_bsdextended_mtx);
466101099Srwatson	for (i = 0; i < rule_slots; i++) {
467101099Srwatson		if (rules[i] == NULL)
468101099Srwatson			continue;
469101099Srwatson
470108376Srwatson		/*
471145412Strhodes		 * Since we do not separately handle append, map append to
472108376Srwatson		 * write.
473108376Srwatson		 */
474136739Srwatson		if (acc_mode & MBI_APPEND) {
475136739Srwatson			acc_mode &= ~MBI_APPEND;
476136739Srwatson			acc_mode |= MBI_WRITE;
477108376Srwatson		}
478108376Srwatson
479157986Sdwmalone		error = mac_bsdextended_rulecheck(rules[i], cred,
480157986Sdwmalone		    vp, vap, acc_mode);
481134131Strhodes		if (error == EJUSTRETURN)
482134131Strhodes			break;
483145412Strhodes		if (error) {
484145412Strhodes			mtx_unlock(&mac_bsdextended_mtx);
485101099Srwatson			return (error);
486145412Strhodes		}
487101099Srwatson	}
488145412Strhodes	mtx_unlock(&mac_bsdextended_mtx);
489101099Srwatson	return (0);
490101099Srwatson}
491101099Srwatson
492101099Srwatsonstatic int
493156300Sdwmalonemac_bsdextended_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode)
494112575Srwatson{
495156300Sdwmalone	int error;
496112575Srwatson	struct vattr vap;
497112575Srwatson
498112575Srwatson	if (!mac_bsdextended_enabled)
499112575Srwatson		return (0);
500112575Srwatson
501112575Srwatson	error = VOP_GETATTR(vp, &vap, cred, curthread);
502112575Srwatson	if (error)
503112575Srwatson		return (error);
504156300Sdwmalone
505157986Sdwmalone	return (mac_bsdextended_check(cred, vp, &vap, acc_mode));
506112575Srwatson}
507112575Srwatson
508112575Srwatsonstatic int
509156300Sdwmalonemac_bsdextended_check_system_swapon(struct ucred *cred, struct vnode *vp,
510156300Sdwmalone    struct label *label)
511156300Sdwmalone{
512156300Sdwmalone
513156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
514156300Sdwmalone}
515156300Sdwmalone
516156300Sdwmalonestatic int
517101099Srwatsonmac_bsdextended_check_vnode_access(struct ucred *cred, struct vnode *vp,
518106212Srwatson    struct label *label, int acc_mode)
519101099Srwatson{
520101099Srwatson
521156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, acc_mode));
522101099Srwatson}
523101099Srwatson
524101099Srwatsonstatic int
525101099Srwatsonmac_bsdextended_check_vnode_chdir(struct ucred *cred, struct vnode *dvp,
526101099Srwatson    struct label *dlabel)
527101099Srwatson{
528101099Srwatson
529156300Sdwmalone	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
530101099Srwatson}
531101099Srwatson
532101099Srwatsonstatic int
533101099Srwatsonmac_bsdextended_check_vnode_chroot(struct ucred *cred, struct vnode *dvp,
534101099Srwatson    struct label *dlabel)
535101099Srwatson{
536101099Srwatson
537156300Sdwmalone	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
538101099Srwatson}
539101099Srwatson
540101099Srwatsonstatic int
541101099Srwatsonmac_bsdextended_check_create_vnode(struct ucred *cred, struct vnode *dvp,
542101099Srwatson    struct label *dlabel, struct componentname *cnp, struct vattr *vap)
543101099Srwatson{
544101099Srwatson
545156300Sdwmalone	return (mac_bsdextended_check_vp(cred, dvp, MBI_WRITE));
546101099Srwatson}
547101099Srwatson
548101099Srwatsonstatic int
549101099Srwatsonmac_bsdextended_check_vnode_delete(struct ucred *cred, struct vnode *dvp,
550101099Srwatson    struct label *dlabel, struct vnode *vp, struct label *label,
551101099Srwatson    struct componentname *cnp)
552101099Srwatson{
553101099Srwatson	int error;
554101099Srwatson
555156300Sdwmalone	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
556101099Srwatson	if (error)
557101099Srwatson		return (error);
558101099Srwatson
559156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
560101099Srwatson}
561101099Srwatson
562101099Srwatsonstatic int
563101099Srwatsonmac_bsdextended_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
564101099Srwatson    struct label *label, acl_type_t type)
565101099Srwatson{
566101099Srwatson
567156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
568101099Srwatson}
569101099Srwatson
570101099Srwatsonstatic int
571119202Srwatsonmac_bsdextended_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp,
572119202Srwatson    struct label *label, int attrnamespace, const char *name)
573119202Srwatson{
574119202Srwatson
575156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
576119202Srwatson}
577119202Srwatson
578119202Srwatsonstatic int
579101099Srwatsonmac_bsdextended_check_vnode_exec(struct ucred *cred, struct vnode *vp,
580106648Srwatson    struct label *label, struct image_params *imgp,
581106648Srwatson    struct label *execlabel)
582101099Srwatson{
583101099Srwatson
584156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_READ|MBI_EXEC));
585101099Srwatson}
586101099Srwatson
587101099Srwatsonstatic int
588101099Srwatsonmac_bsdextended_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
589101099Srwatson    struct label *label, acl_type_t type)
590101099Srwatson{
591101099Srwatson
592156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_STAT));
593101099Srwatson}
594101099Srwatson
595101099Srwatsonstatic int
596101099Srwatsonmac_bsdextended_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
597101099Srwatson    struct label *label, int attrnamespace, const char *name, struct uio *uio)
598101099Srwatson{
599101099Srwatson
600156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
601101099Srwatson}
602101099Srwatson
603101099Srwatsonstatic int
604104530Srwatsonmac_bsdextended_check_vnode_link(struct ucred *cred, struct vnode *dvp,
605104530Srwatson    struct label *dlabel, struct vnode *vp, struct label *label,
606104530Srwatson    struct componentname *cnp)
607104530Srwatson{
608104530Srwatson	int error;
609104530Srwatson
610156300Sdwmalone	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
611104530Srwatson	if (error)
612104530Srwatson		return (error);
613104530Srwatson
614156300Sdwmalone	error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
615104530Srwatson	if (error)
616104530Srwatson		return (error);
617104530Srwatson	return (0);
618104530Srwatson}
619104530Srwatson
620104530Srwatsonstatic int
621119202Srwatsonmac_bsdextended_check_vnode_listextattr(struct ucred *cred, struct vnode *vp,
622119202Srwatson    struct label *label, int attrnamespace)
623119202Srwatson{
624119202Srwatson
625156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
626119202Srwatson}
627119202Srwatson
628119202Srwatsonstatic int
629101099Srwatsonmac_bsdextended_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
630101099Srwatson    struct label *dlabel, struct componentname *cnp)
631101099Srwatson{
632117247Srwatson
633156300Sdwmalone	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
634101099Srwatson}
635101099Srwatson
636101099Srwatsonstatic int
637101099Srwatsonmac_bsdextended_check_vnode_open(struct ucred *cred, struct vnode *vp,
638106212Srwatson    struct label *filelabel, int acc_mode)
639101099Srwatson{
640101099Srwatson
641156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, acc_mode));
642101099Srwatson}
643101099Srwatson
644101099Srwatsonstatic int
645101099Srwatsonmac_bsdextended_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
646101099Srwatson    struct label *dlabel)
647101099Srwatson{
648101099Srwatson
649156300Sdwmalone	return (mac_bsdextended_check_vp(cred, dvp, MBI_READ));
650101099Srwatson}
651101099Srwatson
652101099Srwatsonstatic int
653101099Srwatsonmac_bsdextended_check_vnode_readdlink(struct ucred *cred, struct vnode *vp,
654101099Srwatson    struct label *label)
655101099Srwatson{
656101099Srwatson
657156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
658101099Srwatson}
659101099Srwatson
660101099Srwatsonstatic int
661101099Srwatsonmac_bsdextended_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
662101099Srwatson    struct label *dlabel, struct vnode *vp, struct label *label,
663101099Srwatson    struct componentname *cnp)
664101099Srwatson{
665101099Srwatson	int error;
666101099Srwatson
667156300Sdwmalone	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
668101099Srwatson	if (error)
669101099Srwatson		return (error);
670156300Sdwmalone	error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
671101099Srwatson
672101099Srwatson	return (error);
673101099Srwatson}
674101099Srwatson
675101099Srwatsonstatic int
676101099Srwatsonmac_bsdextended_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
677101099Srwatson    struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
678101099Srwatson    struct componentname *cnp)
679101099Srwatson{
680101099Srwatson	int error;
681101099Srwatson
682156300Sdwmalone	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
683101099Srwatson	if (error)
684101099Srwatson		return (error);
685101099Srwatson
686156300Sdwmalone	if (vp != NULL)
687156300Sdwmalone		error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
688101099Srwatson
689101099Srwatson	return (error);
690101099Srwatson}
691101099Srwatson
692101099Srwatsonstatic int
693101099Srwatsonmac_bsdextended_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
694101099Srwatson    struct label *label)
695101099Srwatson{
696101099Srwatson
697156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
698101099Srwatson}
699101099Srwatson
700101099Srwatsonstatic int
701101099Srwatsonmac_bsdextended_check_setacl_vnode(struct ucred *cred, struct vnode *vp,
702101099Srwatson    struct label *label, acl_type_t type, struct acl *acl)
703101099Srwatson{
704101099Srwatson
705156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
706101099Srwatson}
707101099Srwatson
708101099Srwatsonstatic int
709101099Srwatsonmac_bsdextended_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
710101099Srwatson    struct label *label, int attrnamespace, const char *name, struct uio *uio)
711101099Srwatson{
712101099Srwatson
713156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
714101099Srwatson}
715101099Srwatson
716101099Srwatsonstatic int
717101099Srwatsonmac_bsdextended_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
718101099Srwatson    struct label *label, u_long flags)
719101099Srwatson{
720101099Srwatson
721156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
722101099Srwatson}
723101099Srwatson
724101099Srwatsonstatic int
725101099Srwatsonmac_bsdextended_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
726101099Srwatson    struct label *label, mode_t mode)
727101099Srwatson{
728101099Srwatson
729156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
730101099Srwatson}
731101099Srwatson
732101099Srwatsonstatic int
733101099Srwatsonmac_bsdextended_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
734101099Srwatson    struct label *label, uid_t uid, gid_t gid)
735101099Srwatson{
736101099Srwatson
737156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
738101099Srwatson}
739101099Srwatson
740101099Srwatsonstatic int
741101099Srwatsonmac_bsdextended_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
742101099Srwatson    struct label *label, struct timespec atime, struct timespec utime)
743101099Srwatson{
744101099Srwatson
745156300Sdwmalone	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
746101099Srwatson}
747101099Srwatson
748101099Srwatsonstatic int
749102129Srwatsonmac_bsdextended_check_vnode_stat(struct ucred *active_cred,
750102129Srwatson    struct ucred *file_cred, struct vnode *vp, struct label *label)
751101099Srwatson{
752101099Srwatson
753156300Sdwmalone	return (mac_bsdextended_check_vp(active_cred, vp, MBI_STAT));
754101099Srwatson}
755101099Srwatson
756106217Srwatsonstatic struct mac_policy_ops mac_bsdextended_ops =
757101099Srwatson{
758106217Srwatson	.mpo_destroy = mac_bsdextended_destroy,
759106217Srwatson	.mpo_init = mac_bsdextended_init,
760112575Srwatson	.mpo_check_system_swapon = mac_bsdextended_check_system_swapon,
761106217Srwatson	.mpo_check_vnode_access = mac_bsdextended_check_vnode_access,
762106217Srwatson	.mpo_check_vnode_chdir = mac_bsdextended_check_vnode_chdir,
763106217Srwatson	.mpo_check_vnode_chroot = mac_bsdextended_check_vnode_chroot,
764106217Srwatson	.mpo_check_vnode_create = mac_bsdextended_check_create_vnode,
765106217Srwatson	.mpo_check_vnode_delete = mac_bsdextended_check_vnode_delete,
766106217Srwatson	.mpo_check_vnode_deleteacl = mac_bsdextended_check_vnode_deleteacl,
767119202Srwatson	.mpo_check_vnode_deleteextattr = mac_bsdextended_check_vnode_deleteextattr,
768106217Srwatson	.mpo_check_vnode_exec = mac_bsdextended_check_vnode_exec,
769106217Srwatson	.mpo_check_vnode_getacl = mac_bsdextended_check_vnode_getacl,
770106217Srwatson	.mpo_check_vnode_getextattr = mac_bsdextended_check_vnode_getextattr,
771106217Srwatson	.mpo_check_vnode_link = mac_bsdextended_check_vnode_link,
772119202Srwatson	.mpo_check_vnode_listextattr = mac_bsdextended_check_vnode_listextattr,
773106217Srwatson	.mpo_check_vnode_lookup = mac_bsdextended_check_vnode_lookup,
774106217Srwatson	.mpo_check_vnode_open = mac_bsdextended_check_vnode_open,
775106217Srwatson	.mpo_check_vnode_readdir = mac_bsdextended_check_vnode_readdir,
776106217Srwatson	.mpo_check_vnode_readlink = mac_bsdextended_check_vnode_readdlink,
777106217Srwatson	.mpo_check_vnode_rename_from = mac_bsdextended_check_vnode_rename_from,
778106217Srwatson	.mpo_check_vnode_rename_to = mac_bsdextended_check_vnode_rename_to,
779106217Srwatson	.mpo_check_vnode_revoke = mac_bsdextended_check_vnode_revoke,
780106217Srwatson	.mpo_check_vnode_setacl = mac_bsdextended_check_setacl_vnode,
781106217Srwatson	.mpo_check_vnode_setextattr = mac_bsdextended_check_vnode_setextattr,
782106217Srwatson	.mpo_check_vnode_setflags = mac_bsdextended_check_vnode_setflags,
783106217Srwatson	.mpo_check_vnode_setmode = mac_bsdextended_check_vnode_setmode,
784106217Srwatson	.mpo_check_vnode_setowner = mac_bsdextended_check_vnode_setowner,
785106217Srwatson	.mpo_check_vnode_setutimes = mac_bsdextended_check_vnode_setutimes,
786106217Srwatson	.mpo_check_vnode_stat = mac_bsdextended_check_vnode_stat,
787101099Srwatson};
788101099Srwatson
789112717SrwatsonMAC_POLICY_SET(&mac_bsdextended_ops, mac_bsdextended,
790101099Srwatson    "TrustedBSD MAC/BSD Extended", MPC_LOADTIME_FLAG_UNLOADOK, NULL);
791