1101206Srwatson/*-
2145140Srwatson * Copyright (c) 2002-2005 Networks Associates Technology, Inc.
3101206Srwatson * All rights reserved.
4101206Srwatson *
5106573Srwatson * This software was developed for the FreeBSD Project by Network Associates
6106573Srwatson * Laboratories, the Security Research Division of Network Associates, Inc.
7106573Srwatson * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
8106573Srwatson * DARPA CHATS research program.
9101206Srwatson *
10101206Srwatson * Redistribution and use in source and binary forms, with or without
11101206Srwatson * modification, are permitted provided that the following conditions
12101206Srwatson * are met:
13101206Srwatson * 1. Redistributions of source code must retain the above copyright
14101206Srwatson *    notice, this list of conditions and the following disclaimer.
15101206Srwatson * 2. Redistributions in binary form must reproduce the above copyright
16101206Srwatson *    notice, this list of conditions and the following disclaimer in the
17101206Srwatson *    documentation and/or other materials provided with the distribution.
18101206Srwatson *
19101206Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20101206Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21101206Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22101206Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23101206Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24101206Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25101206Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26101206Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27101206Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28101206Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29101206Srwatson * SUCH DAMAGE.
30101206Srwatson *
31101206Srwatson * $FreeBSD$
32101206Srwatson */
33101206Srwatson#include <sys/param.h>
34101206Srwatson#include <sys/errno.h>
35101206Srwatson#include <sys/time.h>
36101206Srwatson#include <sys/sysctl.h>
37157986Sdwmalone#include <sys/ucred.h>
38157986Sdwmalone#include <sys/mount.h>
39101206Srwatson
40101206Srwatson#include <security/mac_bsdextended/mac_bsdextended.h>
41101206Srwatson
42101206Srwatson#include <grp.h>
43101206Srwatson#include <pwd.h>
44101206Srwatson#include <stdio.h>
45101206Srwatson#include <stdlib.h>
46101206Srwatson#include <string.h>
47101206Srwatson
48101885Srwatson#include "ugidfw.h"
49101206Srwatson
50101206Srwatson/*
51145432Strhodes * Text format for rules: rules contain subject and object elements, mode.
52157986Sdwmalone * The total form is "subject [s_element] object [o_element] mode [mode]".
53101206Srwatson * At least * one of a uid or gid entry must be present; both may also be
54101206Srwatson * present.
55101206Srwatson */
56101206Srwatson
57101206Srwatson#define	MIB	"security.mac.bsdextended"
58101206Srwatson
59101206Srwatsonint
60101206Srwatsonbsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
61101206Srwatson{
62101206Srwatson	struct group *grp;
63101206Srwatson	struct passwd *pwd;
64157986Sdwmalone	struct statfs *mntbuf;
65157986Sdwmalone	char *cur, type[sizeof(rule->mbr_object.mbo_type) * CHAR_BIT + 1];
66101206Srwatson	size_t left, len;
67157986Sdwmalone	int anymode, unknownmode, truncated, numfs, i, notdone;
68101206Srwatson
69101206Srwatson	cur = buf;
70101206Srwatson	left = buflen;
71101206Srwatson	truncated = 0;
72101206Srwatson
73157986Sdwmalone	len = snprintf(cur, left, "subject ");
74157986Sdwmalone	if (len < 0 || len > left)
75157986Sdwmalone		goto truncated;
76157986Sdwmalone	left -= len;
77157986Sdwmalone	cur += len;
78157986Sdwmalone	if (rule->mbr_subject.mbs_flags) {
79157986Sdwmalone		if (rule->mbr_subject.mbs_neg == MBS_ALL_FLAGS) {
80101206Srwatson			len = snprintf(cur, left, "not ");
81101206Srwatson			if (len < 0 || len > left)
82101206Srwatson				goto truncated;
83101206Srwatson			left -= len;
84101206Srwatson			cur += len;
85157986Sdwmalone			notdone = 1;
86157986Sdwmalone		} else {
87157986Sdwmalone			notdone = 0;
88101206Srwatson		}
89157986Sdwmalone
90157986Sdwmalone		if (!notdone && (rule->mbr_subject.mbs_neg & MBO_UID_DEFINED)) {
91157986Sdwmalone			len = snprintf(cur, left, "! ");
92157986Sdwmalone			if (len < 0 || len > left)
93157986Sdwmalone				goto truncated;
94157986Sdwmalone			left -= len;
95157986Sdwmalone			cur += len;
96157986Sdwmalone		}
97157986Sdwmalone		if (rule->mbr_subject.mbs_flags & MBO_UID_DEFINED) {
98157986Sdwmalone			pwd = getpwuid(rule->mbr_subject.mbs_uid_min);
99101206Srwatson			if (pwd != NULL) {
100157986Sdwmalone				len = snprintf(cur, left, "uid %s",
101101206Srwatson				    pwd->pw_name);
102101206Srwatson				if (len < 0 || len > left)
103101206Srwatson					goto truncated;
104101206Srwatson				left -= len;
105101206Srwatson				cur += len;
106101206Srwatson			} else {
107157986Sdwmalone				len = snprintf(cur, left, "uid %u",
108157986Sdwmalone				    rule->mbr_subject.mbs_uid_min);
109101206Srwatson				if (len < 0 || len > left)
110101206Srwatson					goto truncated;
111101206Srwatson				left -= len;
112101206Srwatson				cur += len;
113101206Srwatson			}
114157986Sdwmalone			if (rule->mbr_subject.mbs_uid_min !=
115157986Sdwmalone			    rule->mbr_subject.mbs_uid_max) {
116157986Sdwmalone				pwd = getpwuid(rule->mbr_subject.mbs_uid_max);
117157986Sdwmalone				if (pwd != NULL) {
118157986Sdwmalone					len = snprintf(cur, left, ":%s ",
119157986Sdwmalone					    pwd->pw_name);
120157986Sdwmalone					if (len < 0 || len > left)
121157986Sdwmalone						goto truncated;
122157986Sdwmalone					left -= len;
123157986Sdwmalone					cur += len;
124157986Sdwmalone				} else {
125157986Sdwmalone					len = snprintf(cur, left, ":%u ",
126157986Sdwmalone					    rule->mbr_subject.mbs_uid_max);
127157986Sdwmalone					if (len < 0 || len > left)
128157986Sdwmalone						goto truncated;
129157986Sdwmalone					left -= len;
130157986Sdwmalone					cur += len;
131157986Sdwmalone				}
132157986Sdwmalone			} else {
133157986Sdwmalone				len = snprintf(cur, left, " ");
134157986Sdwmalone				if (len < 0 || len > left)
135157986Sdwmalone					goto truncated;
136157986Sdwmalone				left -= len;
137157986Sdwmalone				cur += len;
138157986Sdwmalone			}
139101206Srwatson		}
140157986Sdwmalone		if (!notdone && (rule->mbr_subject.mbs_neg & MBO_GID_DEFINED)) {
141157986Sdwmalone			len = snprintf(cur, left, "! ");
142157986Sdwmalone			if (len < 0 || len > left)
143157986Sdwmalone				goto truncated;
144157986Sdwmalone			left -= len;
145157986Sdwmalone			cur += len;
146157986Sdwmalone		}
147157986Sdwmalone		if (rule->mbr_subject.mbs_flags & MBO_GID_DEFINED) {
148157986Sdwmalone			grp = getgrgid(rule->mbr_subject.mbs_gid_min);
149101206Srwatson			if (grp != NULL) {
150157986Sdwmalone				len = snprintf(cur, left, "gid %s",
151101206Srwatson				    grp->gr_name);
152101206Srwatson				if (len < 0 || len > left)
153101206Srwatson					goto truncated;
154101206Srwatson				left -= len;
155101206Srwatson				cur += len;
156101206Srwatson			} else {
157157986Sdwmalone				len = snprintf(cur, left, "gid %u",
158157986Sdwmalone				    rule->mbr_subject.mbs_gid_min);
159101206Srwatson				if (len < 0 || len > left)
160101206Srwatson					goto truncated;
161101206Srwatson				left -= len;
162101206Srwatson				cur += len;
163101206Srwatson			}
164157986Sdwmalone			if (rule->mbr_subject.mbs_gid_min !=
165157986Sdwmalone			    rule->mbr_subject.mbs_gid_max) {
166157986Sdwmalone				grp = getgrgid(rule->mbr_subject.mbs_gid_max);
167157986Sdwmalone				if (grp != NULL) {
168157986Sdwmalone					len = snprintf(cur, left, ":%s ",
169157986Sdwmalone					    grp->gr_name);
170157986Sdwmalone					if (len < 0 || len > left)
171157986Sdwmalone						goto truncated;
172157986Sdwmalone					left -= len;
173157986Sdwmalone					cur += len;
174157986Sdwmalone				} else {
175157986Sdwmalone					len = snprintf(cur, left, ":%u ",
176157986Sdwmalone					    rule->mbr_subject.mbs_gid_max);
177157986Sdwmalone					if (len < 0 || len > left)
178157986Sdwmalone						goto truncated;
179157986Sdwmalone					left -= len;
180157986Sdwmalone					cur += len;
181157986Sdwmalone				}
182157986Sdwmalone			} else {
183157986Sdwmalone				len = snprintf(cur, left, " ");
184157986Sdwmalone				if (len < 0 || len > left)
185157986Sdwmalone					goto truncated;
186157986Sdwmalone				left -= len;
187157986Sdwmalone				cur += len;
188157986Sdwmalone			}
189101206Srwatson		}
190157986Sdwmalone		if (!notdone && (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)) {
191157986Sdwmalone			len = snprintf(cur, left, "! ");
192157986Sdwmalone			if (len < 0 || len > left)
193157986Sdwmalone				goto truncated;
194157986Sdwmalone			left -= len;
195157986Sdwmalone			cur += len;
196157986Sdwmalone		}
197157986Sdwmalone		if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
198157986Sdwmalone			len = snprintf(cur, left, "jailid %d ",
199157986Sdwmalone			    rule->mbr_subject.mbs_prison);
200157986Sdwmalone			if (len < 0 || len > left)
201157986Sdwmalone				goto truncated;
202157986Sdwmalone			left -= len;
203157986Sdwmalone			cur += len;
204157986Sdwmalone		}
205101206Srwatson	}
206101206Srwatson
207157986Sdwmalone	len = snprintf(cur, left, "object ");
208157986Sdwmalone	if (len < 0 || len > left)
209157986Sdwmalone		goto truncated;
210157986Sdwmalone	left -= len;
211157986Sdwmalone	cur += len;
212157986Sdwmalone	if (rule->mbr_object.mbo_flags) {
213157986Sdwmalone		if (rule->mbr_object.mbo_neg == MBO_ALL_FLAGS) {
214101206Srwatson			len = snprintf(cur, left, "not ");
215101206Srwatson			if (len < 0 || len > left)
216101206Srwatson				goto truncated;
217101206Srwatson			left -= len;
218101206Srwatson			cur += len;
219157986Sdwmalone			notdone = 1;
220157986Sdwmalone		} else {
221157986Sdwmalone			notdone = 0;
222101206Srwatson		}
223157986Sdwmalone
224157986Sdwmalone		if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)) {
225157986Sdwmalone			len = snprintf(cur, left, "! ");
226157986Sdwmalone			if (len < 0 || len > left)
227157986Sdwmalone				goto truncated;
228157986Sdwmalone			left -= len;
229157986Sdwmalone			cur += len;
230157986Sdwmalone		}
231157986Sdwmalone		if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
232157986Sdwmalone			pwd = getpwuid(rule->mbr_object.mbo_uid_min);
233101206Srwatson			if (pwd != NULL) {
234157986Sdwmalone				len = snprintf(cur, left, "uid %s",
235101206Srwatson				    pwd->pw_name);
236101206Srwatson				if (len < 0 || len > left)
237101206Srwatson					goto truncated;
238101206Srwatson				left -= len;
239101206Srwatson				cur += len;
240101206Srwatson			} else {
241157986Sdwmalone				len = snprintf(cur, left, "uid %u",
242157986Sdwmalone				    rule->mbr_object.mbo_uid_min);
243157986Sdwmalone				if (len < 0 || len > left)
244157986Sdwmalone					goto truncated;
245101206Srwatson				left -= len;
246101206Srwatson				cur += len;
247101206Srwatson			}
248157986Sdwmalone			if (rule->mbr_object.mbo_uid_min !=
249157986Sdwmalone			    rule->mbr_object.mbo_uid_max) {
250157986Sdwmalone				pwd = getpwuid(rule->mbr_object.mbo_uid_max);
251157986Sdwmalone				if (pwd != NULL) {
252157986Sdwmalone					len = snprintf(cur, left, ":%s ",
253157986Sdwmalone					    pwd->pw_name);
254157986Sdwmalone					if (len < 0 || len > left)
255157986Sdwmalone						goto truncated;
256157986Sdwmalone					left -= len;
257157986Sdwmalone					cur += len;
258157986Sdwmalone				} else {
259157986Sdwmalone					len = snprintf(cur, left, ":%u ",
260157986Sdwmalone					    rule->mbr_object.mbo_uid_max);
261157986Sdwmalone					if (len < 0 || len > left)
262157986Sdwmalone						goto truncated;
263157986Sdwmalone					left -= len;
264157986Sdwmalone					cur += len;
265157986Sdwmalone				}
266157986Sdwmalone			} else {
267157986Sdwmalone				len = snprintf(cur, left, " ");
268157986Sdwmalone				if (len < 0 || len > left)
269157986Sdwmalone					goto truncated;
270157986Sdwmalone				left -= len;
271157986Sdwmalone				cur += len;
272157986Sdwmalone			}
273101206Srwatson		}
274157986Sdwmalone		if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)) {
275157986Sdwmalone			len = snprintf(cur, left, "! ");
276157986Sdwmalone			if (len < 0 || len > left)
277157986Sdwmalone				goto truncated;
278157986Sdwmalone			left -= len;
279157986Sdwmalone			cur += len;
280157986Sdwmalone		}
281157986Sdwmalone		if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
282157986Sdwmalone			grp = getgrgid(rule->mbr_object.mbo_gid_min);
283101206Srwatson			if (grp != NULL) {
284157986Sdwmalone				len = snprintf(cur, left, "gid %s",
285101206Srwatson				    grp->gr_name);
286101206Srwatson				if (len < 0 || len > left)
287101206Srwatson					goto truncated;
288101206Srwatson				left -= len;
289101206Srwatson				cur += len;
290101206Srwatson			} else {
291157986Sdwmalone				len = snprintf(cur, left, "gid %u",
292157986Sdwmalone				    rule->mbr_object.mbo_gid_min);
293101206Srwatson				if (len < 0 || len > left)
294101206Srwatson					goto truncated;
295101206Srwatson				left -= len;
296101206Srwatson				cur += len;
297101206Srwatson			}
298157986Sdwmalone			if (rule->mbr_object.mbo_gid_min !=
299157986Sdwmalone			    rule->mbr_object.mbo_gid_max) {
300157986Sdwmalone				grp = getgrgid(rule->mbr_object.mbo_gid_max);
301157986Sdwmalone				if (grp != NULL) {
302157986Sdwmalone					len = snprintf(cur, left, ":%s ",
303157986Sdwmalone					    grp->gr_name);
304157986Sdwmalone					if (len < 0 || len > left)
305157986Sdwmalone						goto truncated;
306157986Sdwmalone					left -= len;
307157986Sdwmalone					cur += len;
308157986Sdwmalone				} else {
309157986Sdwmalone					len = snprintf(cur, left, ":%u ",
310157986Sdwmalone					    rule->mbr_object.mbo_gid_max);
311157986Sdwmalone					if (len < 0 || len > left)
312157986Sdwmalone						goto truncated;
313157986Sdwmalone					left -= len;
314157986Sdwmalone					cur += len;
315157986Sdwmalone				}
316157986Sdwmalone			} else {
317157986Sdwmalone				len = snprintf(cur, left, " ");
318157986Sdwmalone				if (len < 0 || len > left)
319157986Sdwmalone					goto truncated;
320157986Sdwmalone				left -= len;
321157986Sdwmalone				cur += len;
322157986Sdwmalone			}
323101206Srwatson		}
324157986Sdwmalone		if (!notdone && (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)) {
325157986Sdwmalone			len = snprintf(cur, left, "! ");
326157986Sdwmalone			if (len < 0 || len > left)
327157986Sdwmalone				goto truncated;
328157986Sdwmalone			left -= len;
329157986Sdwmalone			cur += len;
330157986Sdwmalone		}
331157986Sdwmalone		if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
332157986Sdwmalone			numfs = getmntinfo(&mntbuf, MNT_NOWAIT);
333157986Sdwmalone			for (i = 0; i < numfs; i++)
334157986Sdwmalone				if (memcmp(&(rule->mbr_object.mbo_fsid),
335157986Sdwmalone				    &(mntbuf[i].f_fsid),
336157986Sdwmalone				    sizeof(mntbuf[i].f_fsid)) == 0)
337157986Sdwmalone					break;
338157986Sdwmalone			len = snprintf(cur, left, "filesys %s ",
339157986Sdwmalone			    i == numfs ? "???" : mntbuf[i].f_mntonname);
340157986Sdwmalone			if (len < 0 || len > left)
341157986Sdwmalone				goto truncated;
342157986Sdwmalone			left -= len;
343157986Sdwmalone			cur += len;
344157986Sdwmalone		}
345157986Sdwmalone		if (!notdone && (rule->mbr_object.mbo_neg & MBO_SUID)) {
346157986Sdwmalone			len = snprintf(cur, left, "! ");
347157986Sdwmalone			if (len < 0 || len > left)
348157986Sdwmalone				goto truncated;
349157986Sdwmalone			left -= len;
350157986Sdwmalone			cur += len;
351157986Sdwmalone		}
352157986Sdwmalone		if (rule->mbr_object.mbo_flags & MBO_SUID) {
353157986Sdwmalone			len = snprintf(cur, left, "suid ");
354157986Sdwmalone			if (len < 0 || len > left)
355157986Sdwmalone				goto truncated;
356157986Sdwmalone			left -= len;
357157986Sdwmalone			cur += len;
358157986Sdwmalone		}
359157986Sdwmalone		if (!notdone && (rule->mbr_object.mbo_neg & MBO_SGID)) {
360157986Sdwmalone			len = snprintf(cur, left, "! ");
361157986Sdwmalone			if (len < 0 || len > left)
362157986Sdwmalone				goto truncated;
363157986Sdwmalone			left -= len;
364157986Sdwmalone			cur += len;
365157986Sdwmalone		}
366157986Sdwmalone		if (rule->mbr_object.mbo_flags & MBO_SGID) {
367157986Sdwmalone			len = snprintf(cur, left, "sgid ");
368157986Sdwmalone			if (len < 0 || len > left)
369157986Sdwmalone				goto truncated;
370157986Sdwmalone			left -= len;
371157986Sdwmalone			cur += len;
372157986Sdwmalone		}
373157986Sdwmalone		if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)) {
374157986Sdwmalone			len = snprintf(cur, left, "! ");
375157986Sdwmalone			if (len < 0 || len > left)
376157986Sdwmalone				goto truncated;
377157986Sdwmalone			left -= len;
378157986Sdwmalone			cur += len;
379157986Sdwmalone		}
380157986Sdwmalone		if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
381157986Sdwmalone			len = snprintf(cur, left, "uid_of_subject ");
382157986Sdwmalone			if (len < 0 || len > left)
383157986Sdwmalone				goto truncated;
384157986Sdwmalone			left -= len;
385157986Sdwmalone			cur += len;
386157986Sdwmalone		}
387157986Sdwmalone		if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)) {
388157986Sdwmalone			len = snprintf(cur, left, "! ");
389157986Sdwmalone			if (len < 0 || len > left)
390157986Sdwmalone				goto truncated;
391157986Sdwmalone			left -= len;
392157986Sdwmalone			cur += len;
393157986Sdwmalone		}
394157986Sdwmalone		if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
395157986Sdwmalone			len = snprintf(cur, left, "gid_of_subject ");
396157986Sdwmalone			if (len < 0 || len > left)
397157986Sdwmalone				goto truncated;
398157986Sdwmalone			left -= len;
399157986Sdwmalone			cur += len;
400157986Sdwmalone		}
401157986Sdwmalone		if (!notdone && (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)) {
402157986Sdwmalone			len = snprintf(cur, left, "! ");
403157986Sdwmalone			if (len < 0 || len > left)
404157986Sdwmalone				goto truncated;
405157986Sdwmalone			left -= len;
406157986Sdwmalone			cur += len;
407157986Sdwmalone		}
408157986Sdwmalone		if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
409157986Sdwmalone			i = 0;
410157986Sdwmalone			if (rule->mbr_object.mbo_type & MBO_TYPE_REG)
411157986Sdwmalone				type[i++] = 'r';
412157986Sdwmalone			if (rule->mbr_object.mbo_type & MBO_TYPE_DIR)
413157986Sdwmalone				type[i++] = 'd';
414157986Sdwmalone			if (rule->mbr_object.mbo_type & MBO_TYPE_BLK)
415157986Sdwmalone				type[i++] = 'b';
416157986Sdwmalone			if (rule->mbr_object.mbo_type & MBO_TYPE_CHR)
417157986Sdwmalone				type[i++] = 'c';
418157986Sdwmalone			if (rule->mbr_object.mbo_type & MBO_TYPE_LNK)
419157986Sdwmalone				type[i++] = 'l';
420157986Sdwmalone			if (rule->mbr_object.mbo_type & MBO_TYPE_SOCK)
421157986Sdwmalone				type[i++] = 's';
422157986Sdwmalone			if (rule->mbr_object.mbo_type & MBO_TYPE_FIFO)
423157986Sdwmalone				type[i++] = 'p';
424157986Sdwmalone			if (rule->mbr_object.mbo_type == MBO_ALL_TYPE) {
425157986Sdwmalone				i = 0;
426157986Sdwmalone				type[i++] = 'a';
427157986Sdwmalone			}
428157986Sdwmalone			type[i++] = '\0';
429157986Sdwmalone			len = snprintf(cur, left, "type %s ", type);
430157986Sdwmalone			if (len < 0 || len > left)
431157986Sdwmalone				goto truncated;
432157986Sdwmalone			left -= len;
433157986Sdwmalone			cur += len;
434157986Sdwmalone		}
435101206Srwatson	}
436101206Srwatson
437101206Srwatson	len = snprintf(cur, left, "mode ");
438101206Srwatson	if (len < 0 || len > left)
439101206Srwatson		goto truncated;
440101206Srwatson	left -= len;
441101206Srwatson	cur += len;
442101206Srwatson
443136740Srwatson	anymode = (rule->mbr_mode & MBI_ALLPERM);
444136740Srwatson	unknownmode = (rule->mbr_mode & ~MBI_ALLPERM);
445101206Srwatson
446136740Srwatson	if (rule->mbr_mode & MBI_ADMIN) {
447101206Srwatson		len = snprintf(cur, left, "a");
448101206Srwatson		if (len < 0 || len > left)
449101206Srwatson			goto truncated;
450101206Srwatson
451101206Srwatson		left -= len;
452101206Srwatson		cur += len;
453101206Srwatson	}
454136740Srwatson	if (rule->mbr_mode & MBI_READ) {
455101206Srwatson		len = snprintf(cur, left, "r");
456101206Srwatson		if (len < 0 || len > left)
457101206Srwatson			goto truncated;
458101206Srwatson
459101206Srwatson		left -= len;
460101206Srwatson		cur += len;
461101206Srwatson	}
462136740Srwatson	if (rule->mbr_mode & MBI_STAT) {
463101206Srwatson		len = snprintf(cur, left, "s");
464101206Srwatson		if (len < 0 || len > left)
465101206Srwatson			goto truncated;
466101206Srwatson
467101206Srwatson		left -= len;
468101206Srwatson		cur += len;
469101206Srwatson	}
470136740Srwatson	if (rule->mbr_mode & MBI_WRITE) {
471101206Srwatson		len = snprintf(cur, left, "w");
472101206Srwatson		if (len < 0 || len > left)
473101206Srwatson			goto truncated;
474101206Srwatson
475101206Srwatson		left -= len;
476101206Srwatson		cur += len;
477101206Srwatson	}
478136740Srwatson	if (rule->mbr_mode & MBI_EXEC) {
479101206Srwatson		len = snprintf(cur, left, "x");
480101206Srwatson		if (len < 0 || len > left)
481101206Srwatson			goto truncated;
482101206Srwatson
483101206Srwatson		left -= len;
484101206Srwatson		cur += len;
485101206Srwatson	}
486101206Srwatson	if (!anymode) {
487101206Srwatson		len = snprintf(cur, left, "n");
488101206Srwatson		if (len < 0 || len > left)
489101206Srwatson			goto truncated;
490101206Srwatson
491101206Srwatson		left -= len;
492101206Srwatson		cur += len;
493101206Srwatson	}
494101206Srwatson	if (unknownmode) {
495101206Srwatson		len = snprintf(cur, left, "?");
496101206Srwatson		if (len < 0 || len > left)
497101206Srwatson			goto truncated;
498101206Srwatson
499101206Srwatson		left -= len;
500101206Srwatson		cur += len;
501101206Srwatson	}
502101206Srwatson
503101206Srwatson	return (0);
504101206Srwatson
505101206Srwatsontruncated:
506101206Srwatson	return (-1);
507101206Srwatson}
508101206Srwatson
509101206Srwatsonint
510157986Sdwmalonebsde_parse_uidrange(char *spec, uid_t *min, uid_t *max,
511157986Sdwmalone    size_t buflen, char *errstr){
512101206Srwatson	struct passwd *pwd;
513157986Sdwmalone	uid_t uid1, uid2;
514157986Sdwmalone	char *spec1, *spec2, *endp;
515157986Sdwmalone	unsigned long value;
516101206Srwatson	size_t len;
517101206Srwatson
518157986Sdwmalone	spec2 = spec;
519157986Sdwmalone	spec1 = strsep(&spec2, ":");
520157986Sdwmalone
521157986Sdwmalone	pwd = getpwnam(spec1);
522157986Sdwmalone	if (pwd != NULL)
523157986Sdwmalone		uid1 = pwd->pw_uid;
524157986Sdwmalone	else {
525157986Sdwmalone		value = strtoul(spec1, &endp, 10);
526157986Sdwmalone		if (*endp != '\0') {
527157986Sdwmalone			len = snprintf(errstr, buflen,
528157986Sdwmalone			    "invalid uid: '%s'", spec1);
529157986Sdwmalone			return (-1);
530157986Sdwmalone		}
531157986Sdwmalone		uid1 = value;
532101206Srwatson	}
533101206Srwatson
534157986Sdwmalone	if (spec2 == NULL) {
535157986Sdwmalone		*max = *min = uid1;
536157986Sdwmalone		return (0);
537157986Sdwmalone	}
538157986Sdwmalone
539157986Sdwmalone	pwd = getpwnam(spec2);
540157986Sdwmalone	if (pwd != NULL)
541157986Sdwmalone		uid2 = pwd->pw_uid;
542157986Sdwmalone	else {
543157986Sdwmalone		value = strtoul(spec2, &endp, 10);
544157986Sdwmalone		if (*endp != '\0') {
545157986Sdwmalone			len = snprintf(errstr, buflen,
546157986Sdwmalone			    "invalid uid: '%s'", spec2);
547157986Sdwmalone			return (-1);
548157986Sdwmalone		}
549157986Sdwmalone		uid2 = value;
550157986Sdwmalone	}
551157986Sdwmalone
552157986Sdwmalone	*min = uid1;
553157986Sdwmalone	*max = uid2;
554157986Sdwmalone
555157986Sdwmalone	return (0);
556157986Sdwmalone}
557157986Sdwmalone
558157986Sdwmaloneint
559157986Sdwmalonebsde_parse_gidrange(char *spec, gid_t *min, gid_t *max,
560157986Sdwmalone    size_t buflen, char *errstr){
561157986Sdwmalone	struct group *grp;
562157986Sdwmalone	gid_t gid1, gid2;
563157986Sdwmalone	char *spec1, *spec2, *endp;
564157986Sdwmalone	unsigned long value;
565157986Sdwmalone	size_t len;
566157986Sdwmalone
567157986Sdwmalone	spec2 = spec;
568157986Sdwmalone	spec1 = strsep(&spec2, ":");
569157986Sdwmalone
570157986Sdwmalone	grp = getgrnam(spec1);
571157986Sdwmalone	if (grp != NULL)
572157986Sdwmalone		gid1 = grp->gr_gid;
573157986Sdwmalone	else {
574157986Sdwmalone		value = strtoul(spec1, &endp, 10);
575157986Sdwmalone		if (*endp != '\0') {
576157986Sdwmalone			len = snprintf(errstr, buflen,
577157986Sdwmalone			    "invalid gid: '%s'", spec1);
578157986Sdwmalone			return (-1);
579157986Sdwmalone		}
580157986Sdwmalone		gid1 = value;
581157986Sdwmalone	}
582157986Sdwmalone
583157986Sdwmalone	if (spec2 == NULL) {
584157986Sdwmalone		*max = *min = gid1;
585157986Sdwmalone		return (0);
586157986Sdwmalone	}
587157986Sdwmalone
588157986Sdwmalone	grp = getgrnam(spec2);
589157986Sdwmalone	if (grp != NULL)
590157986Sdwmalone		gid2 = grp->gr_gid;
591157986Sdwmalone	else {
592157986Sdwmalone		value = strtoul(spec2, &endp, 10);
593157986Sdwmalone		if (*endp != '\0') {
594157986Sdwmalone			len = snprintf(errstr, buflen,
595157986Sdwmalone			    "invalid gid: '%s'", spec2);
596157986Sdwmalone			return (-1);
597157986Sdwmalone		}
598157986Sdwmalone		gid2 = value;
599157986Sdwmalone	}
600157986Sdwmalone
601157986Sdwmalone	*min = gid1;
602157986Sdwmalone	*max = gid2;
603157986Sdwmalone
604157986Sdwmalone	return (0);
605157986Sdwmalone}
606157986Sdwmalone
607157986Sdwmaloneint
608157986Sdwmalonebsde_parse_subject(int argc, char *argv[],
609157986Sdwmalone    struct mac_bsdextended_subject *subject, size_t buflen, char *errstr)
610157986Sdwmalone{
611157986Sdwmalone	int not_seen, flags;
612157986Sdwmalone	int current, neg, nextnot;
613157986Sdwmalone	char *endp;
614157986Sdwmalone	uid_t uid_min, uid_max;
615157986Sdwmalone	gid_t gid_min, gid_max;
616157986Sdwmalone	int jid;
617157986Sdwmalone	size_t len;
618157986Sdwmalone	long value;
619157986Sdwmalone
620101206Srwatson	current = 0;
621157986Sdwmalone	flags = 0;
622157986Sdwmalone	neg = 0;
623157986Sdwmalone	nextnot = 0;
624101206Srwatson
625157986Sdwmalone	if (strcmp("not", argv[current]) == 0) {
626101206Srwatson		not_seen = 1;
627101206Srwatson		current++;
628101206Srwatson	} else
629101206Srwatson		not_seen = 0;
630101206Srwatson
631157986Sdwmalone	while (current < argc) {
632157986Sdwmalone		if (strcmp(argv[current], "uid") == 0) {
633157986Sdwmalone			if (current + 2 > argc) {
634157986Sdwmalone				len = snprintf(errstr, buflen, "uid short");
635157986Sdwmalone				return (-1);
636157986Sdwmalone			}
637157986Sdwmalone			if (flags & MBS_UID_DEFINED) {
638157986Sdwmalone				len = snprintf(errstr, buflen, "one uid only");
639157986Sdwmalone				return (-1);
640157986Sdwmalone			}
641157986Sdwmalone			if (bsde_parse_uidrange(argv[current+1],
642157986Sdwmalone			    &uid_min, &uid_max, buflen, errstr) < 0)
643157986Sdwmalone				return (-1);
644157986Sdwmalone			flags |= MBS_UID_DEFINED;
645157986Sdwmalone			if (nextnot) {
646157986Sdwmalone				neg ^= MBS_UID_DEFINED;
647157986Sdwmalone				nextnot = 0;
648157986Sdwmalone			}
649157986Sdwmalone			current += 2;
650157986Sdwmalone		} else if (strcmp(argv[current], "gid") == 0) {
651157986Sdwmalone			if (current + 2 > argc) {
652157986Sdwmalone				len = snprintf(errstr, buflen, "gid short");
653157986Sdwmalone				return (-1);
654157986Sdwmalone			}
655157986Sdwmalone			if (flags & MBS_GID_DEFINED) {
656157986Sdwmalone				len = snprintf(errstr, buflen, "one gid only");
657157986Sdwmalone				return (-1);
658157986Sdwmalone			}
659157986Sdwmalone			if (bsde_parse_gidrange(argv[current+1],
660157986Sdwmalone			    &gid_min, &gid_max, buflen, errstr) < 0)
661157986Sdwmalone				return (-1);
662157986Sdwmalone			flags |= MBS_GID_DEFINED;
663157986Sdwmalone			if (nextnot) {
664157986Sdwmalone				neg ^= MBS_GID_DEFINED;
665157986Sdwmalone				nextnot = 0;
666157986Sdwmalone			}
667157986Sdwmalone			current += 2;
668157986Sdwmalone		} else if (strcmp(argv[current], "jailid") == 0) {
669157986Sdwmalone			if (current + 2 > argc) {
670157986Sdwmalone				len = snprintf(errstr, buflen, "prison short");
671157986Sdwmalone				return (-1);
672157986Sdwmalone			}
673157986Sdwmalone			if (flags & MBS_PRISON_DEFINED) {
674157986Sdwmalone				len = snprintf(errstr, buflen, "one jail only");
675157986Sdwmalone				return (-1);
676157986Sdwmalone			}
677101206Srwatson			value = strtol(argv[current+1], &endp, 10);
678101206Srwatson			if (*endp != '\0') {
679101206Srwatson				len = snprintf(errstr, buflen,
680157986Sdwmalone				    "invalid jid: '%s'", argv[current+1]);
681101206Srwatson				return (-1);
682101206Srwatson			}
683157986Sdwmalone			jid = value;
684157986Sdwmalone			flags |= MBS_PRISON_DEFINED;
685157986Sdwmalone			if (nextnot) {
686157986Sdwmalone				neg ^= MBS_PRISON_DEFINED;
687157986Sdwmalone				nextnot = 0;
688157986Sdwmalone			}
689157986Sdwmalone			current += 2;
690157986Sdwmalone		} else if (strcmp(argv[current], "!") == 0) {
691157986Sdwmalone			if (nextnot) {
692101206Srwatson				len = snprintf(errstr, buflen,
693157986Sdwmalone				    "double negative");
694101206Srwatson				return (-1);
695101206Srwatson			}
696157986Sdwmalone			nextnot = 1;
697157986Sdwmalone			current += 1;
698157986Sdwmalone		} else {
699157986Sdwmalone			len = snprintf(errstr, buflen, "'%s' not expected",
700157986Sdwmalone			    argv[current]);
701157986Sdwmalone			return (-1);
702101206Srwatson		}
703157986Sdwmalone	}
704157986Sdwmalone
705157986Sdwmalone	subject->mbs_flags = flags;
706157986Sdwmalone	if (not_seen)
707157986Sdwmalone		subject->mbs_neg = MBS_ALL_FLAGS ^ neg;
708157986Sdwmalone	else
709157986Sdwmalone		subject->mbs_neg = neg;
710157986Sdwmalone	if (flags & MBS_UID_DEFINED) {
711157986Sdwmalone		subject->mbs_uid_min = uid_min;
712157986Sdwmalone		subject->mbs_uid_max = uid_max;
713157986Sdwmalone	}
714157986Sdwmalone	if (flags & MBS_GID_DEFINED) {
715157986Sdwmalone		subject->mbs_gid_min = gid_min;
716157986Sdwmalone		subject->mbs_gid_max = gid_max;
717157986Sdwmalone	}
718157986Sdwmalone	if (flags & MBS_PRISON_DEFINED)
719157986Sdwmalone		subject->mbs_prison = jid;
720157986Sdwmalone
721157986Sdwmalone	return (0);
722157986Sdwmalone}
723157986Sdwmalone
724157986Sdwmaloneint
725157986Sdwmalonebsde_parse_type(char *spec, int *type, size_t buflen, char *errstr)
726157986Sdwmalone{
727157986Sdwmalone	size_t len;
728157986Sdwmalone	int i;
729157986Sdwmalone
730157986Sdwmalone	*type = 0;
731157986Sdwmalone	for (i = 0; i < strlen(spec); i++) {
732157986Sdwmalone		switch (spec[i]) {
733157986Sdwmalone		case 'r':
734157986Sdwmalone		case '-':
735157986Sdwmalone			*type |= MBO_TYPE_REG;
736157986Sdwmalone			break;
737157986Sdwmalone		case 'd':
738157986Sdwmalone			*type |= MBO_TYPE_DIR;
739157986Sdwmalone			break;
740157986Sdwmalone		case 'b':
741157986Sdwmalone			*type |= MBO_TYPE_BLK;
742157986Sdwmalone			break;
743157986Sdwmalone		case 'c':
744157986Sdwmalone			*type |= MBO_TYPE_CHR;
745157986Sdwmalone			break;
746157986Sdwmalone		case 'l':
747157986Sdwmalone			*type |= MBO_TYPE_LNK;
748157986Sdwmalone			break;
749157986Sdwmalone		case 's':
750157986Sdwmalone			*type |= MBO_TYPE_SOCK;
751157986Sdwmalone			break;
752157986Sdwmalone		case 'p':
753157986Sdwmalone			*type |= MBO_TYPE_FIFO;
754157986Sdwmalone			break;
755157986Sdwmalone		case 'a':
756157986Sdwmalone			*type |= MBO_ALL_TYPE;
757157986Sdwmalone			break;
758157986Sdwmalone		default:
759157986Sdwmalone			len = snprintf(errstr, buflen, "Unknown type code: %c",
760157986Sdwmalone			    spec[i]);
761157986Sdwmalone			return (-1);
762157986Sdwmalone		}
763157986Sdwmalone	}
764157986Sdwmalone
765157986Sdwmalone	return (0);
766157986Sdwmalone}
767157986Sdwmalone
768157986Sdwmaloneint
769157986Sdwmalonebsde_parse_fsid(char *spec, struct fsid *fsid, size_t buflen, char *errstr)
770157986Sdwmalone{
771157986Sdwmalone	size_t len;
772157986Sdwmalone	struct statfs buf;
773157986Sdwmalone
774157986Sdwmalone	if (statfs(spec, &buf) < 0) {
775157986Sdwmalone		len = snprintf(errstr, buflen, "Unable to get id for %s: %s",
776157986Sdwmalone		    spec, strerror(errno));
777101206Srwatson		return (-1);
778101206Srwatson	}
779101206Srwatson
780157986Sdwmalone	*fsid = buf.f_fsid;
781157986Sdwmalone
782157986Sdwmalone	return (0);
783157986Sdwmalone}
784157986Sdwmalone
785157986Sdwmaloneint
786157986Sdwmalonebsde_parse_object(int argc, char *argv[],
787157986Sdwmalone    struct mac_bsdextended_object *object, size_t buflen, char *errstr)
788157986Sdwmalone{
789157986Sdwmalone	int not_seen, flags;
790157986Sdwmalone	int current, neg, nextnot;
791157986Sdwmalone	uid_t uid_min, uid_max;
792157986Sdwmalone	gid_t gid_min, gid_max;
793157986Sdwmalone	int type;
794157986Sdwmalone	struct fsid fsid;
795157986Sdwmalone	size_t len;
796157986Sdwmalone
797157986Sdwmalone	current = 0;
798157986Sdwmalone	flags = 0;
799157986Sdwmalone	neg = 0;
800157986Sdwmalone	nextnot = 0;
801157986Sdwmalone
802157986Sdwmalone	if (strcmp("not", argv[current]) == 0) {
803157986Sdwmalone		not_seen = 1;
804157986Sdwmalone		current++;
805157986Sdwmalone	} else
806157986Sdwmalone		not_seen = 0;
807157986Sdwmalone
808157986Sdwmalone	while (current < argc) {
809157986Sdwmalone		if (strcmp(argv[current], "uid") == 0) {
810157986Sdwmalone			if (current + 2 > argc) {
811157986Sdwmalone				len = snprintf(errstr, buflen, "uid short");
812101206Srwatson				return (-1);
813101206Srwatson			}
814157986Sdwmalone			if (flags & MBO_UID_DEFINED) {
815157986Sdwmalone				len = snprintf(errstr, buflen, "one uid only");
816157986Sdwmalone				return (-1);
817157986Sdwmalone			}
818157986Sdwmalone			if (bsde_parse_uidrange(argv[current+1],
819157986Sdwmalone			    &uid_min, &uid_max, buflen, errstr) < 0)
820157986Sdwmalone				return (-1);
821157986Sdwmalone			flags |= MBO_UID_DEFINED;
822157986Sdwmalone			if (nextnot) {
823157986Sdwmalone				neg ^= MBO_UID_DEFINED;
824157986Sdwmalone				nextnot = 0;
825157986Sdwmalone			}
826157986Sdwmalone			current += 2;
827157986Sdwmalone		} else if (strcmp(argv[current], "gid") == 0) {
828101206Srwatson			if (current + 2 > argc) {
829157986Sdwmalone				len = snprintf(errstr, buflen, "gid short");
830101206Srwatson				return (-1);
831101206Srwatson			}
832157986Sdwmalone			if (flags & MBO_GID_DEFINED) {
833157986Sdwmalone				len = snprintf(errstr, buflen, "one gid only");
834157986Sdwmalone				return (-1);
835101206Srwatson			}
836157986Sdwmalone			if (bsde_parse_gidrange(argv[current+1],
837157986Sdwmalone			    &gid_min, &gid_max, buflen, errstr) < 0)
838157986Sdwmalone				return (-1);
839157986Sdwmalone			flags |= MBO_GID_DEFINED;
840157986Sdwmalone			if (nextnot) {
841157986Sdwmalone				neg ^= MBO_GID_DEFINED;
842157986Sdwmalone				nextnot = 0;
843157986Sdwmalone			}
844101206Srwatson			current += 2;
845157986Sdwmalone		} else if (strcmp(argv[current], "filesys") == 0) {
846157986Sdwmalone			if (current + 2 > argc) {
847157986Sdwmalone				len = snprintf(errstr, buflen, "filesys short");
848101206Srwatson				return (-1);
849101206Srwatson			}
850157986Sdwmalone			if (flags & MBO_FSID_DEFINED) {
851157986Sdwmalone				len = snprintf(errstr, buflen, "one fsid only");
852157986Sdwmalone				return (-1);
853157986Sdwmalone			}
854157986Sdwmalone			if (bsde_parse_fsid(argv[current+1], &fsid,
855157986Sdwmalone			    buflen, errstr) < 0)
856157986Sdwmalone				return (-1);
857157986Sdwmalone			flags |= MBO_FSID_DEFINED;
858157986Sdwmalone			if (nextnot) {
859157986Sdwmalone				neg ^= MBO_FSID_DEFINED;
860157986Sdwmalone				nextnot = 0;
861157986Sdwmalone			}
862157986Sdwmalone			current += 2;
863157986Sdwmalone		} else if (strcmp(argv[current], "suid") == 0) {
864157986Sdwmalone			flags |= MBO_SUID;
865157986Sdwmalone			if (nextnot) {
866157986Sdwmalone				neg ^= MBO_SUID;
867157986Sdwmalone				nextnot = 0;
868157986Sdwmalone			}
869157986Sdwmalone			current += 1;
870157986Sdwmalone		} else if (strcmp(argv[current], "sgid") == 0) {
871157986Sdwmalone			flags |= MBO_SGID;
872157986Sdwmalone			if (nextnot) {
873157986Sdwmalone				neg ^= MBO_SGID;
874157986Sdwmalone				nextnot = 0;
875157986Sdwmalone			}
876157986Sdwmalone			current += 1;
877157986Sdwmalone		} else if (strcmp(argv[current], "uid_of_subject") == 0) {
878157986Sdwmalone			flags |= MBO_UID_SUBJECT;
879157986Sdwmalone			if (nextnot) {
880157986Sdwmalone				neg ^= MBO_UID_SUBJECT;
881157986Sdwmalone				nextnot = 0;
882157986Sdwmalone			}
883157986Sdwmalone			current += 1;
884157986Sdwmalone		} else if (strcmp(argv[current], "gid_of_subject") == 0) {
885157986Sdwmalone			flags |= MBO_GID_SUBJECT;
886157986Sdwmalone			if (nextnot) {
887157986Sdwmalone				neg ^= MBO_GID_SUBJECT;
888157986Sdwmalone				nextnot = 0;
889157986Sdwmalone			}
890157986Sdwmalone			current += 1;
891157986Sdwmalone		} else if (strcmp(argv[current], "type") == 0) {
892101206Srwatson			if (current + 2 > argc) {
893157986Sdwmalone				len = snprintf(errstr, buflen, "type short");
894101206Srwatson				return (-1);
895101206Srwatson			}
896157986Sdwmalone			if (flags & MBO_TYPE_DEFINED) {
897157986Sdwmalone				len = snprintf(errstr, buflen, "one type only");
898157986Sdwmalone				return (-1);
899101206Srwatson			}
900157986Sdwmalone			if (bsde_parse_type(argv[current+1], &type,
901157986Sdwmalone			    buflen, errstr) < 0)
902157986Sdwmalone				return (-1);
903157986Sdwmalone			flags |= MBO_TYPE_DEFINED;
904157986Sdwmalone			if (nextnot) {
905157986Sdwmalone				neg ^= MBO_TYPE_DEFINED;
906157986Sdwmalone				nextnot = 0;
907157986Sdwmalone			}
908101206Srwatson			current += 2;
909157986Sdwmalone		} else if (strcmp(argv[current], "!") == 0) {
910157986Sdwmalone			if (nextnot) {
911157986Sdwmalone				len = snprintf(errstr, buflen,
912157986Sdwmalone				    "double negative'");
913157986Sdwmalone				return (-1);
914157986Sdwmalone			}
915157986Sdwmalone			nextnot = 1;
916157986Sdwmalone			current += 1;
917101206Srwatson		} else {
918101206Srwatson			len = snprintf(errstr, buflen, "'%s' not expected",
919101206Srwatson			    argv[current]);
920101206Srwatson			return (-1);
921157986Sdwmalone		}
922101206Srwatson	}
923101206Srwatson
924157986Sdwmalone	object->mbo_flags = flags;
925157986Sdwmalone	if (not_seen)
926157986Sdwmalone		object->mbo_neg = MBO_ALL_FLAGS ^ neg;
927157986Sdwmalone	else
928157986Sdwmalone		object->mbo_neg = neg;
929157986Sdwmalone	if (flags & MBO_UID_DEFINED) {
930157986Sdwmalone		object->mbo_uid_min = uid_min;
931157986Sdwmalone		object->mbo_uid_max = uid_max;
932101206Srwatson	}
933157986Sdwmalone	if (flags & MBO_GID_DEFINED) {
934157986Sdwmalone		object->mbo_gid_min = gid_min;
935157986Sdwmalone		object->mbo_gid_max = gid_max;
936157986Sdwmalone	}
937157986Sdwmalone	if (flags & MBO_FSID_DEFINED)
938157986Sdwmalone		object->mbo_fsid = fsid;
939157986Sdwmalone	if (flags & MBO_TYPE_DEFINED)
940157986Sdwmalone		object->mbo_type = type;
941101206Srwatson
942101206Srwatson	return (0);
943101206Srwatson}
944101206Srwatson
945101206Srwatsonint
946101206Srwatsonbsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
947101206Srwatson    char *errstr)
948101206Srwatson{
949101206Srwatson	size_t len;
950101206Srwatson	int i;
951101206Srwatson
952101206Srwatson	if (argc == 0) {
953101206Srwatson		len = snprintf(errstr, buflen, "mode expects mode value");
954101206Srwatson		return (-1);
955101206Srwatson	}
956101206Srwatson
957101206Srwatson	if (argc != 1) {
958101206Srwatson		len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
959101206Srwatson		return (-1);
960101206Srwatson	}
961101206Srwatson
962101206Srwatson	*mode = 0;
963101206Srwatson	for (i = 0; i < strlen(argv[0]); i++) {
964101206Srwatson		switch (argv[0][i]) {
965101206Srwatson		case 'a':
966136740Srwatson			*mode |= MBI_ADMIN;
967101206Srwatson			break;
968101206Srwatson		case 'r':
969136740Srwatson			*mode |= MBI_READ;
970101206Srwatson			break;
971101206Srwatson		case 's':
972136740Srwatson			*mode |= MBI_STAT;
973101206Srwatson			break;
974101206Srwatson		case 'w':
975136740Srwatson			*mode |= MBI_WRITE;
976101206Srwatson			break;
977101206Srwatson		case 'x':
978136740Srwatson			*mode |= MBI_EXEC;
979101206Srwatson			break;
980101206Srwatson		case 'n':
981101206Srwatson			/* ignore */
982101206Srwatson			break;
983101206Srwatson		default:
984101206Srwatson			len = snprintf(errstr, buflen, "Unknown mode letter: %c",
985101206Srwatson			    argv[0][i]);
986101206Srwatson			return (-1);
987101206Srwatson		}
988101206Srwatson	}
989101206Srwatson
990101206Srwatson	return (0);
991101206Srwatson}
992101206Srwatson
993101206Srwatsonint
994101206Srwatsonbsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
995101206Srwatson    size_t buflen, char *errstr)
996101206Srwatson{
997101206Srwatson	int subject, subject_elements, subject_elements_length;
998101206Srwatson	int object, object_elements, object_elements_length;
999101206Srwatson	int mode, mode_elements, mode_elements_length;
1000101206Srwatson	int error, i;
1001101206Srwatson	size_t len;
1002101206Srwatson
1003101206Srwatson	bzero(rule, sizeof(*rule));
1004101206Srwatson
1005101206Srwatson	if (argc < 1) {
1006101206Srwatson		len = snprintf(errstr, buflen, "Rule must begin with subject");
1007101206Srwatson		return (-1);
1008101206Srwatson	}
1009101206Srwatson
1010101206Srwatson	if (strcmp(argv[0], "subject") != 0) {
1011101206Srwatson		len = snprintf(errstr, buflen, "Rule must begin with subject");
1012101206Srwatson		return (-1);
1013101206Srwatson	}
1014101206Srwatson	subject = 0;
1015101206Srwatson	subject_elements = 1;
1016101206Srwatson
1017101206Srwatson	/* Search forward for object. */
1018101206Srwatson
1019101206Srwatson	object = -1;
1020101206Srwatson	for (i = 1; i < argc; i++)
1021101206Srwatson		if (strcmp(argv[i], "object") == 0)
1022101206Srwatson			object = i;
1023101206Srwatson
1024101206Srwatson	if (object == -1) {
1025101206Srwatson		len = snprintf(errstr, buflen, "Rule must contain an object");
1026101206Srwatson		return (-1);
1027101206Srwatson	}
1028101206Srwatson
1029101206Srwatson	/* Search forward for mode. */
1030101206Srwatson	mode = -1;
1031101206Srwatson	for (i = object; i < argc; i++)
1032101206Srwatson		if (strcmp(argv[i], "mode") == 0)
1033101206Srwatson			mode = i;
1034101206Srwatson
1035101206Srwatson	if (mode == -1) {
1036101206Srwatson		len = snprintf(errstr, buflen, "Rule must contain mode");
1037101206Srwatson		return (-1);
1038101206Srwatson	}
1039101206Srwatson
1040101206Srwatson	subject_elements_length = object - subject - 1;
1041101206Srwatson	object_elements = object + 1;
1042101206Srwatson	object_elements_length = mode - object_elements;
1043101206Srwatson	mode_elements = mode + 1;
1044101206Srwatson	mode_elements_length = argc - mode_elements;
1045101206Srwatson
1046157986Sdwmalone	error = bsde_parse_subject(subject_elements_length,
1047101206Srwatson	    argv + subject_elements, &rule->mbr_subject, buflen, errstr);
1048101206Srwatson	if (error)
1049101206Srwatson		return (-1);
1050101206Srwatson
1051157986Sdwmalone	error = bsde_parse_object(object_elements_length,
1052101206Srwatson	    argv + object_elements, &rule->mbr_object, buflen, errstr);
1053101206Srwatson	if (error)
1054101206Srwatson		return (-1);
1055101206Srwatson
1056101206Srwatson	error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
1057101206Srwatson	    &rule->mbr_mode, buflen, errstr);
1058101206Srwatson	if (error)
1059101206Srwatson		return (-1);
1060101206Srwatson
1061101206Srwatson	return (0);
1062101206Srwatson}
1063101206Srwatson
1064101206Srwatsonint
1065101206Srwatsonbsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
1066101206Srwatson    size_t buflen, char *errstr)
1067101206Srwatson{
1068157986Sdwmalone	char *stringdup, *stringp, *argv[100], **ap;
1069101206Srwatson	int argc, error;
1070101206Srwatson
1071101206Srwatson	stringp = stringdup = strdup(string);
1072101206Srwatson	while (*stringp == ' ' || *stringp == '\t')
1073101206Srwatson		stringp++;
1074101206Srwatson
1075101206Srwatson	argc = 0;
1076101206Srwatson	for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
1077101206Srwatson		argc++;
1078101206Srwatson		if (**ap != '\0')
1079157986Sdwmalone			if (++ap >= &argv[100])
1080101206Srwatson				break;
1081101206Srwatson	}
1082101206Srwatson
1083101206Srwatson	error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
1084101206Srwatson
1085101206Srwatson	free(stringdup);
1086101206Srwatson
1087101206Srwatson	return (error);
1088101206Srwatson}
1089101206Srwatson
1090101206Srwatsonint
1091104038Srwatsonbsde_get_mib(const char *string, int *name, size_t *namelen)
1092101206Srwatson{
1093104038Srwatson	size_t len;
1094104038Srwatson	int error;
1095101206Srwatson
1096101206Srwatson	len = *namelen;
1097101206Srwatson	error = sysctlnametomib(string, name, &len);
1098101206Srwatson	if (error)
1099101206Srwatson		return (error);
1100101206Srwatson
1101101206Srwatson	*namelen = len;
1102101206Srwatson	return (0);
1103101206Srwatson}
1104101206Srwatson
1105101206Srwatsonint
1106157986Sdwmalonebsde_check_version(size_t buflen, char *errstr)
1107157986Sdwmalone{
1108157986Sdwmalone	size_t len;
1109157986Sdwmalone	int error;
1110157986Sdwmalone	int version;
1111157986Sdwmalone
1112157986Sdwmalone	len = sizeof(version);
1113157986Sdwmalone	error = sysctlbyname(MIB ".rule_version", &version, &len, NULL, 0);
1114157986Sdwmalone	if (error) {
1115157986Sdwmalone		len = snprintf(errstr, buflen, "version check failed: %s",
1116157986Sdwmalone		    strerror(errno));
1117157986Sdwmalone		return (-1);
1118157986Sdwmalone	}
1119157986Sdwmalone	if (version != MB_VERSION) {
1120157986Sdwmalone		len = snprintf(errstr, buflen, "module v%d != library v%d",
1121157986Sdwmalone		    version, MB_VERSION);
1122157986Sdwmalone		return (-1);
1123157986Sdwmalone	}
1124157986Sdwmalone	return (0);
1125157986Sdwmalone}
1126157986Sdwmalone
1127157986Sdwmaloneint
1128101206Srwatsonbsde_get_rule_count(size_t buflen, char *errstr)
1129101206Srwatson{
1130101206Srwatson	size_t len;
1131101206Srwatson	int error;
1132101206Srwatson	int rule_count;
1133101206Srwatson
1134101206Srwatson	len = sizeof(rule_count);
1135126835Sbde	error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0);
1136101206Srwatson	if (error) {
1137216953Semaste		len = snprintf(errstr, buflen, "%s", strerror(errno));
1138101206Srwatson		return (-1);
1139101206Srwatson	}
1140101206Srwatson	if (len != sizeof(rule_count)) {
1141101206Srwatson		len = snprintf(errstr, buflen, "Data error in %s.rule_count",
1142101206Srwatson		    MIB);
1143101206Srwatson		return (-1);
1144101206Srwatson	}
1145101206Srwatson
1146101206Srwatson	return (rule_count);
1147101206Srwatson}
1148101206Srwatson
1149101206Srwatsonint
1150101206Srwatsonbsde_get_rule_slots(size_t buflen, char *errstr)
1151101206Srwatson{
1152101206Srwatson	size_t len;
1153101206Srwatson	int error;
1154101206Srwatson	int rule_slots;
1155101206Srwatson
1156101206Srwatson	len = sizeof(rule_slots);
1157126835Sbde	error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0);
1158101206Srwatson	if (error) {
1159216953Semaste		len = snprintf(errstr, buflen, "%s", strerror(errno));
1160101206Srwatson		return (-1);
1161101206Srwatson	}
1162101206Srwatson	if (len != sizeof(rule_slots)) {
1163101206Srwatson		len = snprintf(errstr, buflen, "Data error in %s.rule_slots",
1164101206Srwatson		    MIB);
1165101206Srwatson		return (-1);
1166101206Srwatson	}
1167101206Srwatson
1168101206Srwatson	return (rule_slots);
1169101206Srwatson}
1170101206Srwatson
1171101206Srwatson/*
1172101206Srwatson * Returns 0 for success;
1173101206Srwatson * Returns -1 for failure;
1174101206Srwatson * Returns -2 for not present
1175101206Srwatson */
1176101206Srwatsonint
1177101206Srwatsonbsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
1178101206Srwatson    char *errstr)
1179101206Srwatson{
1180101206Srwatson	int name[10];
1181101206Srwatson	size_t len, size;
1182101206Srwatson	int error;
1183101206Srwatson
1184157986Sdwmalone	if (bsde_check_version(errlen, errstr) != 0)
1185157986Sdwmalone		return (-1);
1186157986Sdwmalone
1187101206Srwatson	len = 10;
1188101206Srwatson	error = bsde_get_mib(MIB ".rules", name, &len);
1189101206Srwatson	if (error) {
1190101206Srwatson		len = snprintf(errstr, errlen, "%s: %s", MIB ".rules",
1191101206Srwatson		    strerror(errno));
1192101206Srwatson		return (-1);
1193101206Srwatson	}
1194101206Srwatson
1195101206Srwatson	size = sizeof(*rule);
1196101206Srwatson	name[len] = rulenum;
1197101206Srwatson	len++;
1198101206Srwatson	error = sysctl(name, len, rule, &size, NULL, 0);
1199101206Srwatson	if (error  == -1 && errno == ENOENT)
1200101206Srwatson		return (-2);
1201101206Srwatson	if (error) {
1202101206Srwatson		len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
1203101206Srwatson		    rulenum, strerror(errno));
1204101206Srwatson		return (-1);
1205101206Srwatson	} else if (size != sizeof(*rule)) {
1206101206Srwatson		len = snprintf(errstr, errlen, "Data error in %s.%d: %s",
1207101206Srwatson		    MIB ".rules", rulenum, strerror(errno));
1208101206Srwatson		return (-1);
1209101206Srwatson	}
1210101206Srwatson
1211101206Srwatson	return (0);
1212101206Srwatson}
1213101206Srwatson
1214101206Srwatsonint
1215101206Srwatsonbsde_delete_rule(int rulenum, size_t buflen, char *errstr)
1216101206Srwatson{
1217101206Srwatson	struct mac_bsdextended_rule rule;
1218101206Srwatson	int name[10];
1219101206Srwatson	size_t len, size;
1220101206Srwatson	int error;
1221101206Srwatson
1222157986Sdwmalone	if (bsde_check_version(buflen, errstr) != 0)
1223157986Sdwmalone		return (-1);
1224157986Sdwmalone
1225101206Srwatson	len = 10;
1226101206Srwatson	error = bsde_get_mib(MIB ".rules", name, &len);
1227101206Srwatson	if (error) {
1228101206Srwatson		len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1229101206Srwatson		    strerror(errno));
1230101206Srwatson		return (-1);
1231101206Srwatson	}
1232101206Srwatson
1233101206Srwatson	name[len] = rulenum;
1234101206Srwatson	len++;
1235101206Srwatson
1236101206Srwatson	size = sizeof(rule);
1237101206Srwatson	error = sysctl(name, len, NULL, NULL, &rule, 0);
1238101206Srwatson	if (error) {
1239101206Srwatson		len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1240101206Srwatson		    rulenum, strerror(errno));
1241101206Srwatson		return (-1);
1242101206Srwatson	}
1243101206Srwatson
1244101206Srwatson	return (0);
1245101206Srwatson}
1246101206Srwatson
1247101206Srwatsonint
1248101206Srwatsonbsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
1249101206Srwatson    char *errstr)
1250101206Srwatson{
1251101206Srwatson	int name[10];
1252101206Srwatson	size_t len, size;
1253101206Srwatson	int error;
1254101206Srwatson
1255157986Sdwmalone	if (bsde_check_version(buflen, errstr) != 0)
1256157986Sdwmalone		return (-1);
1257157986Sdwmalone
1258101206Srwatson	len = 10;
1259101206Srwatson	error = bsde_get_mib(MIB ".rules", name, &len);
1260101206Srwatson	if (error) {
1261101206Srwatson		len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1262101206Srwatson		    strerror(errno));
1263101206Srwatson		return (-1);
1264101206Srwatson	}
1265101206Srwatson
1266101206Srwatson	name[len] = rulenum;
1267101206Srwatson	len++;
1268101206Srwatson
1269101206Srwatson	size = sizeof(*rule);
1270101206Srwatson	error = sysctl(name, len, NULL, NULL, rule, size);
1271101206Srwatson	if (error) {
1272101206Srwatson		len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1273101206Srwatson		    rulenum, strerror(errno));
1274101206Srwatson		return (-1);
1275101206Srwatson	}
1276101206Srwatson
1277101206Srwatson	return (0);
1278101206Srwatson}
1279126217Srwatson
1280126217Srwatsonint
1281126217Srwatsonbsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
1282126217Srwatson    char *errstr)
1283126217Srwatson{
1284126217Srwatson	char charstr[BUFSIZ];
1285126217Srwatson	int name[10];
1286126217Srwatson	size_t len, size;
1287126217Srwatson	int error, rule_slots;
1288126217Srwatson
1289157986Sdwmalone	if (bsde_check_version(buflen, errstr) != 0)
1290157986Sdwmalone		return (-1);
1291157986Sdwmalone
1292126217Srwatson	len = 10;
1293126217Srwatson	error = bsde_get_mib(MIB ".rules", name, &len);
1294126217Srwatson	if (error) {
1295126217Srwatson		len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1296126217Srwatson		    strerror(errno));
1297126217Srwatson		return (-1);
1298126217Srwatson	}
1299126217Srwatson
1300126217Srwatson	rule_slots = bsde_get_rule_slots(BUFSIZ, charstr);
1301126217Srwatson	if (rule_slots == -1) {
1302126217Srwatson		len = snprintf(errstr, buflen, "unable to get rule slots: %s",
1303126217Srwatson		    strerror(errno));
1304126217Srwatson		return (-1);
1305126217Srwatson	}
1306126217Srwatson
1307126217Srwatson	name[len] = rule_slots;
1308126217Srwatson	len++;
1309126217Srwatson
1310126217Srwatson	size = sizeof(*rule);
1311126217Srwatson	error = sysctl(name, len, NULL, NULL, rule, size);
1312126217Srwatson	if (error) {
1313126217Srwatson		len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1314126217Srwatson		    rule_slots, strerror(errno));
1315126217Srwatson		return (-1);
1316126217Srwatson	}
1317126217Srwatson
1318126217Srwatson	if (rulenum != NULL)
1319144210Spjd		*rulenum = rule_slots;
1320126217Srwatson
1321126217Srwatson	return (0);
1322126217Srwatson}
1323