ugidfw.c revision 106573
1101206Srwatson/*-
2101206Srwatson * Copyright (c) 2002 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: head/lib/libugidfw/ugidfw.c 106573 2002-11-07 20:37:04Z rwatson $
32101206Srwatson */
33101206Srwatson#include <sys/param.h>
34101206Srwatson#include <sys/errno.h>
35101206Srwatson#include <sys/time.h>
36101206Srwatson#include <sys/sysctl.h>
37101206Srwatson#include <sys/vnode.h>
38101206Srwatson
39101206Srwatson#include <security/mac_bsdextended/mac_bsdextended.h>
40101206Srwatson
41101206Srwatson#include <grp.h>
42101206Srwatson#include <pwd.h>
43101206Srwatson#include <stdio.h>
44101206Srwatson#include <stdlib.h>
45101206Srwatson#include <string.h>
46101206Srwatson
47101885Srwatson#include "ugidfw.h"
48101206Srwatson
49101206Srwatson/*
50101206Srwatson * Text format for rules: rules contain subjectand object elements, mode.
51101206Srwatson * Each element takes the form "[not] [uid number] [gid number]".
52101206Srwatson * The total form is "subject [element] object [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;
64101206Srwatson	char *cur;
65101206Srwatson	size_t left, len;
66101206Srwatson	int anymode, unknownmode, truncated;
67101206Srwatson
68101206Srwatson	cur = buf;
69101206Srwatson	left = buflen;
70101206Srwatson	truncated = 0;
71101206Srwatson
72101206Srwatson	if (rule->mbr_subject.mbi_flags & (MBI_UID_DEFINED |
73101206Srwatson	    MBI_GID_DEFINED)) {
74101206Srwatson		len = snprintf(cur, left, "subject ");
75101206Srwatson		if (len < 0 || len > left)
76101206Srwatson			goto truncated;
77101206Srwatson		left -= len;
78101206Srwatson		cur += len;
79101206Srwatson
80101206Srwatson		if (rule->mbr_subject.mbi_flags & MBI_NEGATED) {
81101206Srwatson			len = snprintf(cur, left, "not ");
82101206Srwatson			if (len < 0 || len > left)
83101206Srwatson				goto truncated;
84101206Srwatson			left -= len;
85101206Srwatson			cur += len;
86101206Srwatson		}
87101206Srwatson		if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
88101206Srwatson			pwd = getpwuid(rule->mbr_subject.mbi_uid);
89101206Srwatson			if (pwd != NULL) {
90101206Srwatson				len = snprintf(cur, left, "uid %s ",
91101206Srwatson				    pwd->pw_name);
92101206Srwatson				if (len < 0 || len > left)
93101206Srwatson					goto truncated;
94101206Srwatson				left -= len;
95101206Srwatson				cur += len;
96101206Srwatson			} else {
97101206Srwatson				len = snprintf(cur, left, "uid %u ",
98101206Srwatson				    rule->mbr_subject.mbi_uid);
99101206Srwatson				if (len < 0 || len > left)
100101206Srwatson					goto truncated;
101101206Srwatson				left -= len;
102101206Srwatson				cur += len;
103101206Srwatson			}
104101206Srwatson		}
105101206Srwatson		if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
106101206Srwatson			grp = getgrgid(rule->mbr_subject.mbi_gid);
107101206Srwatson			if (grp != NULL) {
108101206Srwatson				len = snprintf(cur, left, "gid %s ",
109101206Srwatson				    grp->gr_name);
110101206Srwatson				if (len < 0 || len > left)
111101206Srwatson					goto truncated;
112101206Srwatson				left -= len;
113101206Srwatson				cur += len;
114101206Srwatson			} else {
115101206Srwatson				len = snprintf(cur, left, "gid %u ",
116101206Srwatson				    rule->mbr_subject.mbi_gid);
117101206Srwatson				if (len < 0 || len > left)
118101206Srwatson					goto truncated;
119101206Srwatson				left -= len;
120101206Srwatson				cur += len;
121101206Srwatson			}
122101206Srwatson		}
123101206Srwatson	}
124101206Srwatson	if (rule->mbr_object.mbi_flags & (MBI_UID_DEFINED |
125101206Srwatson	    MBI_GID_DEFINED)) {
126101206Srwatson		len = snprintf(cur, left, "object ");
127101206Srwatson		if (len < 0 || len > left)
128101206Srwatson			goto truncated;
129101206Srwatson		left -= len;
130101206Srwatson		cur += len;
131101206Srwatson
132101206Srwatson		if (rule->mbr_object.mbi_flags & MBI_NEGATED) {
133101206Srwatson			len = snprintf(cur, left, "not ");
134101206Srwatson			if (len < 0 || len > left)
135101206Srwatson				goto truncated;
136101206Srwatson			left -= len;
137101206Srwatson			cur += len;
138101206Srwatson		}
139101206Srwatson		if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
140101206Srwatson			pwd = getpwuid(rule->mbr_object.mbi_uid);
141101206Srwatson			if (pwd != NULL) {
142101206Srwatson				len = snprintf(cur, left, "uid %s ",
143101206Srwatson				    pwd->pw_name);
144101206Srwatson				if (len < 0 || len > left)
145101206Srwatson					goto truncated;
146101206Srwatson				left -= len;
147101206Srwatson				cur += len;
148101206Srwatson			} else {
149101206Srwatson				len = snprintf(cur, left, "uid %u ",
150101206Srwatson				    rule->mbr_object.mbi_uid);
151101206Srwatson				left -= len;
152101206Srwatson				cur += len;
153101206Srwatson			}
154101206Srwatson		}
155101206Srwatson		if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
156101206Srwatson			grp = getgrgid(rule->mbr_object.mbi_gid);
157101206Srwatson			if (grp != NULL) {
158101206Srwatson				len = snprintf(cur, left, "gid %s ",
159101206Srwatson				    grp->gr_name);
160101206Srwatson				if (len < 0 || len > left)
161101206Srwatson					goto truncated;
162101206Srwatson				left -= len;
163101206Srwatson				cur += len;
164101206Srwatson			} else {
165101206Srwatson				len = snprintf(cur, left, "gid %u ",
166101206Srwatson				    rule->mbr_object.mbi_gid);
167101206Srwatson				if (len < 0 || len > left)
168101206Srwatson					goto truncated;
169101206Srwatson				left -= len;
170101206Srwatson				cur += len;
171101206Srwatson			}
172101206Srwatson		}
173101206Srwatson	}
174101206Srwatson
175101206Srwatson	len = snprintf(cur, left, "mode ");
176101206Srwatson	if (len < 0 || len > left)
177101206Srwatson		goto truncated;
178101206Srwatson	left -= len;
179101206Srwatson	cur += len;
180101206Srwatson
181101206Srwatson	anymode = (rule->mbr_mode & VALLPERM);
182101206Srwatson	unknownmode = (rule->mbr_mode & ~VALLPERM);
183101206Srwatson
184101206Srwatson	if (rule->mbr_mode & VADMIN) {
185101206Srwatson		len = snprintf(cur, left, "a");
186101206Srwatson		if (len < 0 || len > left)
187101206Srwatson			goto truncated;
188101206Srwatson
189101206Srwatson		left -= len;
190101206Srwatson		cur += len;
191101206Srwatson	}
192101206Srwatson	if (rule->mbr_mode & VREAD) {
193101206Srwatson		len = snprintf(cur, left, "r");
194101206Srwatson		if (len < 0 || len > left)
195101206Srwatson			goto truncated;
196101206Srwatson
197101206Srwatson		left -= len;
198101206Srwatson		cur += len;
199101206Srwatson	}
200101206Srwatson	if (rule->mbr_mode & VSTAT) {
201101206Srwatson		len = snprintf(cur, left, "s");
202101206Srwatson		if (len < 0 || len > left)
203101206Srwatson			goto truncated;
204101206Srwatson
205101206Srwatson		left -= len;
206101206Srwatson		cur += len;
207101206Srwatson	}
208101206Srwatson	if (rule->mbr_mode & VWRITE) {
209101206Srwatson		len = snprintf(cur, left, "w");
210101206Srwatson		if (len < 0 || len > left)
211101206Srwatson			goto truncated;
212101206Srwatson
213101206Srwatson		left -= len;
214101206Srwatson		cur += len;
215101206Srwatson	}
216101206Srwatson	if (rule->mbr_mode & VEXEC) {
217101206Srwatson		len = snprintf(cur, left, "x");
218101206Srwatson		if (len < 0 || len > left)
219101206Srwatson			goto truncated;
220101206Srwatson
221101206Srwatson		left -= len;
222101206Srwatson		cur += len;
223101206Srwatson	}
224101206Srwatson	if (!anymode) {
225101206Srwatson		len = snprintf(cur, left, "n");
226101206Srwatson		if (len < 0 || len > left)
227101206Srwatson			goto truncated;
228101206Srwatson
229101206Srwatson		left -= len;
230101206Srwatson		cur += len;
231101206Srwatson	}
232101206Srwatson	if (unknownmode) {
233101206Srwatson		len = snprintf(cur, left, "?");
234101206Srwatson		if (len < 0 || len > left)
235101206Srwatson			goto truncated;
236101206Srwatson
237101206Srwatson		left -= len;
238101206Srwatson		cur += len;
239101206Srwatson	}
240101206Srwatson
241101206Srwatson	return (0);
242101206Srwatson
243101206Srwatsontruncated:
244101206Srwatson	return (-1);
245101206Srwatson}
246101206Srwatson
247101206Srwatsonint
248101206Srwatsonbsde_parse_identity(int argc, char *argv[],
249101206Srwatson    struct mac_bsdextended_identity *identity, size_t buflen, char *errstr)
250101206Srwatson{
251101206Srwatson	struct group *grp;
252101206Srwatson	struct passwd *pwd;
253101206Srwatson	int uid_seen, gid_seen, not_seen;
254101206Srwatson	int current;
255101206Srwatson	char *endp;
256101206Srwatson	long value;
257101206Srwatson	uid_t uid;
258101206Srwatson	gid_t gid;
259101206Srwatson	size_t len;
260101206Srwatson
261101206Srwatson	if (argc == 0) {
262101206Srwatson		len = snprintf(errstr, buflen, "Identity must not be empty");
263101206Srwatson		return (-1);
264101206Srwatson	}
265101206Srwatson
266101206Srwatson	current = 0;
267101206Srwatson
268101206Srwatson	/* First element might be "not". */
269101206Srwatson	if (strcmp("not", argv[0]) == 0) {
270101206Srwatson		not_seen = 1;
271101206Srwatson		current++;
272101206Srwatson	} else
273101206Srwatson		not_seen = 0;
274101206Srwatson
275101206Srwatson	if (current >= argc) {
276101206Srwatson		len = snprintf(errstr, buflen, "Identity short");
277101206Srwatson		return (-1);
278101206Srwatson	}
279101206Srwatson
280101206Srwatson	uid_seen = 0;
281101206Srwatson	uid = 0;
282101206Srwatson	gid_seen = 0;
283101206Srwatson	gid = 0;
284101206Srwatson
285101206Srwatson	/* First phrase: uid [uid] or gid[gid]. */
286101206Srwatson	if (strcmp("uid", argv[current]) == 0) {
287101206Srwatson		if (current + 2 > argc) {
288101206Srwatson			len = snprintf(errstr, buflen, "uid short");
289101206Srwatson			return (-1);
290101206Srwatson		}
291101206Srwatson		pwd = getpwnam(argv[current+1]);
292101206Srwatson		if (pwd != NULL)
293101206Srwatson			uid = pwd->pw_uid;
294101206Srwatson		else {
295101206Srwatson			value = strtol(argv[current+1], &endp, 10);
296101206Srwatson			if (*endp != '\0') {
297101206Srwatson				len = snprintf(errstr, buflen,
298101206Srwatson				    "invalid uid: '%s'",
299101206Srwatson				    argv[current+1]);
300101206Srwatson				return (-1);
301101206Srwatson			}
302101206Srwatson			uid = value;
303101206Srwatson		}
304101206Srwatson		uid_seen = 1;
305101206Srwatson		current += 2;
306101206Srwatson	} else if (strcmp("gid", argv[current]) == 0) {
307101206Srwatson		if (current + 2 > argc) {
308101206Srwatson			len = snprintf(errstr, buflen, "gid short");
309101206Srwatson			return (-1);
310101206Srwatson		}
311101206Srwatson		grp = getgrnam(argv[current+1]);
312101206Srwatson		if (grp != NULL)
313101206Srwatson			gid = grp->gr_gid;
314101206Srwatson		else {
315101206Srwatson			value = strtol(argv[current+1], &endp, 10);
316101206Srwatson			if (*endp != '\0') {
317101206Srwatson				len = snprintf(errstr, buflen,
318101206Srwatson				    "invalid gid: '%s'",
319101206Srwatson				    argv[current+1]);
320101206Srwatson				return (-1);
321101206Srwatson			}
322101206Srwatson			gid = value;
323101206Srwatson		}
324101206Srwatson		gid_seen = 1;
325101206Srwatson		current += 2;
326101206Srwatson	} else {
327101206Srwatson		len = snprintf(errstr, buflen, "'%s' not expected",
328101206Srwatson		    argv[current]);
329101206Srwatson		return (-1);
330101206Srwatson	}
331101206Srwatson
332101206Srwatson	/* Onto optional second phrase. */
333101206Srwatson	if (current + 1 < argc) {
334101206Srwatson		/* Second phrase: uid [uid] or gid [gid], but not a repeat. */
335101206Srwatson		if (strcmp("uid", argv[current]) == 0) {
336101206Srwatson			if (uid_seen) {
337101206Srwatson				len = snprintf(errstr, buflen,
338101206Srwatson				    "Only one uid permitted per identity clause");
339101206Srwatson				return (-1);
340101206Srwatson			}
341101206Srwatson			if (current + 2 > argc) {
342101206Srwatson				len = snprintf(errstr, buflen, "uid short");
343101206Srwatson				return (-1);
344101206Srwatson			}
345101206Srwatson			value = strtol(argv[current+1], &endp, 10);
346101206Srwatson			if (*endp != '\0') {
347101206Srwatson				len = snprintf(errstr, buflen, "invalid uid: '%s'",
348101206Srwatson				    argv[current+1]);
349101206Srwatson				return (-1);
350101206Srwatson			}
351101206Srwatson			uid = value;
352101206Srwatson			uid_seen = 1;
353101206Srwatson			current += 2;
354101206Srwatson		} else if (strcmp("gid", argv[current]) == 0) {
355101206Srwatson			if (gid_seen) {
356101206Srwatson				len = snprintf(errstr, buflen,
357101206Srwatson				    "Only one gid permitted per identity clause");
358101206Srwatson				return (-1);
359101206Srwatson			}
360101206Srwatson			if (current + 2 > argc) {
361101206Srwatson				len = snprintf(errstr, buflen, "gid short");
362101206Srwatson				return (-1);
363101206Srwatson			}
364101206Srwatson			value = strtol(argv[current+1], &endp, 10);
365101206Srwatson			if (*endp != '\0') {
366101206Srwatson				len = snprintf(errstr, buflen, "invalid gid: '%s'",
367101206Srwatson				    argv[current+1]);
368101206Srwatson				return (-1);
369101206Srwatson			}
370101206Srwatson			gid = value;
371101206Srwatson			gid_seen = 1;
372101206Srwatson			current += 2;
373101206Srwatson		} else {
374101206Srwatson			len = snprintf(errstr, buflen, "'%s' not expected",
375101206Srwatson			    argv[current]);
376101206Srwatson			return (-1);
377101206Srwatson		}
378101206Srwatson	}
379101206Srwatson
380101206Srwatson	if (current +1 < argc) {
381101206Srwatson		len = snprintf(errstr, buflen, "'%s' not expected",
382101206Srwatson		    argv[current]);
383101206Srwatson		return (-1);
384101206Srwatson	}
385101206Srwatson
386101206Srwatson	/* Fill out the identity. */
387101206Srwatson	identity->mbi_flags = 0;
388101206Srwatson
389101206Srwatson	if (not_seen)
390101206Srwatson		identity->mbi_flags |= MBI_NEGATED;
391101206Srwatson
392101206Srwatson	if (uid_seen) {
393101206Srwatson		identity->mbi_flags |= MBI_UID_DEFINED;
394101206Srwatson		identity->mbi_uid = uid;
395101206Srwatson	} else
396101206Srwatson		identity->mbi_uid = 0;
397101206Srwatson
398101206Srwatson	if (gid_seen) {
399101206Srwatson		identity->mbi_flags |= MBI_GID_DEFINED;
400101206Srwatson		identity->mbi_gid = gid;
401101206Srwatson	} else
402101206Srwatson		identity->mbi_gid = 0;
403101206Srwatson
404101206Srwatson	return (0);
405101206Srwatson}
406101206Srwatson
407101206Srwatsonint
408101206Srwatsonbsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
409101206Srwatson    char *errstr)
410101206Srwatson{
411101206Srwatson	size_t len;
412101206Srwatson	int i;
413101206Srwatson
414101206Srwatson	if (argc == 0) {
415101206Srwatson		len = snprintf(errstr, buflen, "mode expects mode value");
416101206Srwatson		return (-1);
417101206Srwatson	}
418101206Srwatson
419101206Srwatson	if (argc != 1) {
420101206Srwatson		len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
421101206Srwatson		return (-1);
422101206Srwatson	}
423101206Srwatson
424101206Srwatson	*mode = 0;
425101206Srwatson	for (i = 0; i < strlen(argv[0]); i++) {
426101206Srwatson		switch (argv[0][i]) {
427101206Srwatson		case 'a':
428101206Srwatson			*mode |= VADMIN;
429101206Srwatson			break;
430101206Srwatson		case 'r':
431101206Srwatson			*mode |= VREAD;
432101206Srwatson			break;
433101206Srwatson		case 's':
434101206Srwatson			*mode |= VSTAT;
435101206Srwatson			break;
436101206Srwatson		case 'w':
437101206Srwatson			*mode |= VWRITE;
438101206Srwatson			break;
439101206Srwatson		case 'x':
440101206Srwatson			*mode |= VEXEC;
441101206Srwatson			break;
442101206Srwatson		case 'n':
443101206Srwatson			/* ignore */
444101206Srwatson			break;
445101206Srwatson		default:
446101206Srwatson			len = snprintf(errstr, buflen, "Unknown mode letter: %c",
447101206Srwatson			    argv[0][i]);
448101206Srwatson			return (-1);
449101206Srwatson		}
450101206Srwatson	}
451101206Srwatson
452101206Srwatson	return (0);
453101206Srwatson}
454101206Srwatson
455101206Srwatsonint
456101206Srwatsonbsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
457101206Srwatson    size_t buflen, char *errstr)
458101206Srwatson{
459101206Srwatson	int subject, subject_elements, subject_elements_length;
460101206Srwatson	int object, object_elements, object_elements_length;
461101206Srwatson	int mode, mode_elements, mode_elements_length;
462101206Srwatson	int error, i;
463101206Srwatson	size_t len;
464101206Srwatson
465101206Srwatson	bzero(rule, sizeof(*rule));
466101206Srwatson
467101206Srwatson	if (argc < 1) {
468101206Srwatson		len = snprintf(errstr, buflen, "Rule must begin with subject");
469101206Srwatson		return (-1);
470101206Srwatson	}
471101206Srwatson
472101206Srwatson	if (strcmp(argv[0], "subject") != 0) {
473101206Srwatson		len = snprintf(errstr, buflen, "Rule must begin with subject");
474101206Srwatson		return (-1);
475101206Srwatson	}
476101206Srwatson	subject = 0;
477101206Srwatson	subject_elements = 1;
478101206Srwatson
479101206Srwatson	/* Search forward for object. */
480101206Srwatson
481101206Srwatson	object = -1;
482101206Srwatson	for (i = 1; i < argc; i++)
483101206Srwatson		if (strcmp(argv[i], "object") == 0)
484101206Srwatson			object = i;
485101206Srwatson
486101206Srwatson	if (object == -1) {
487101206Srwatson		len = snprintf(errstr, buflen, "Rule must contain an object");
488101206Srwatson		return (-1);
489101206Srwatson	}
490101206Srwatson
491101206Srwatson	/* Search forward for mode. */
492101206Srwatson	mode = -1;
493101206Srwatson	for (i = object; i < argc; i++)
494101206Srwatson		if (strcmp(argv[i], "mode") == 0)
495101206Srwatson			mode = i;
496101206Srwatson
497101206Srwatson	if (mode == -1) {
498101206Srwatson		len = snprintf(errstr, buflen, "Rule must contain mode");
499101206Srwatson		return (-1);
500101206Srwatson	}
501101206Srwatson
502101206Srwatson	subject_elements_length = object - subject - 1;
503101206Srwatson	object_elements = object + 1;
504101206Srwatson	object_elements_length = mode - object_elements;
505101206Srwatson	mode_elements = mode + 1;
506101206Srwatson	mode_elements_length = argc - mode_elements;
507101206Srwatson
508101206Srwatson	error = bsde_parse_identity(subject_elements_length,
509101206Srwatson	    argv + subject_elements, &rule->mbr_subject, buflen, errstr);
510101206Srwatson	if (error)
511101206Srwatson		return (-1);
512101206Srwatson
513101206Srwatson	error = bsde_parse_identity(object_elements_length,
514101206Srwatson	    argv + object_elements, &rule->mbr_object, buflen, errstr);
515101206Srwatson	if (error)
516101206Srwatson		return (-1);
517101206Srwatson
518101206Srwatson	error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
519101206Srwatson	    &rule->mbr_mode, buflen, errstr);
520101206Srwatson	if (error)
521101206Srwatson		return (-1);
522101206Srwatson
523101206Srwatson	return (0);
524101206Srwatson}
525101206Srwatson
526101206Srwatsonint
527101206Srwatsonbsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
528101206Srwatson    size_t buflen, char *errstr)
529101206Srwatson{
530101206Srwatson	char *stringdup, *stringp, *argv[20], **ap;
531101206Srwatson	int argc, error;
532101206Srwatson
533101206Srwatson	stringp = stringdup = strdup(string);
534101206Srwatson	while (*stringp == ' ' || *stringp == '\t')
535101206Srwatson		stringp++;
536101206Srwatson
537101206Srwatson	argc = 0;
538101206Srwatson	for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
539101206Srwatson		argc++;
540101206Srwatson		if (**ap != '\0')
541101206Srwatson			if (++ap >= &argv[20])
542101206Srwatson				break;
543101206Srwatson	}
544101206Srwatson
545101206Srwatson	error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
546101206Srwatson
547101206Srwatson	free(stringdup);
548101206Srwatson
549101206Srwatson	return (error);
550101206Srwatson}
551101206Srwatson
552101206Srwatsonint
553104038Srwatsonbsde_get_mib(const char *string, int *name, size_t *namelen)
554101206Srwatson{
555104038Srwatson	size_t len;
556104038Srwatson	int error;
557101206Srwatson
558101206Srwatson	len = *namelen;
559101206Srwatson	error = sysctlnametomib(string, name, &len);
560101206Srwatson	if (error)
561101206Srwatson		return (error);
562101206Srwatson
563101206Srwatson	*namelen = len;
564101206Srwatson	return (0);
565101206Srwatson}
566101206Srwatson
567101206Srwatsonint
568101206Srwatsonbsde_get_rule_count(size_t buflen, char *errstr)
569101206Srwatson{
570101206Srwatson	size_t len;
571101206Srwatson	int error;
572101206Srwatson	int rule_count;
573101206Srwatson
574101206Srwatson	len = sizeof(rule_count);
575101206Srwatson	error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, NULL);
576101206Srwatson	if (error) {
577101206Srwatson		len = snprintf(errstr, buflen, strerror(errno));
578101206Srwatson		return (-1);
579101206Srwatson	}
580101206Srwatson	if (len != sizeof(rule_count)) {
581101206Srwatson		len = snprintf(errstr, buflen, "Data error in %s.rule_count",
582101206Srwatson		    MIB);
583101206Srwatson		return (-1);
584101206Srwatson	}
585101206Srwatson
586101206Srwatson	return (rule_count);
587101206Srwatson}
588101206Srwatson
589101206Srwatsonint
590101206Srwatsonbsde_get_rule_slots(size_t buflen, char *errstr)
591101206Srwatson{
592101206Srwatson	size_t len;
593101206Srwatson	int error;
594101206Srwatson	int rule_slots;
595101206Srwatson
596101206Srwatson	len = sizeof(rule_slots);
597101206Srwatson	error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL,
598101206Srwatson	    NULL);
599101206Srwatson	if (error) {
600101206Srwatson		len = snprintf(errstr, buflen, strerror(errno));
601101206Srwatson		return (-1);
602101206Srwatson	}
603101206Srwatson	if (len != sizeof(rule_slots)) {
604101206Srwatson		len = snprintf(errstr, buflen, "Data error in %s.rule_slots",
605101206Srwatson		    MIB);
606101206Srwatson		return (-1);
607101206Srwatson	}
608101206Srwatson
609101206Srwatson	return (rule_slots);
610101206Srwatson}
611101206Srwatson
612101206Srwatson/*
613101206Srwatson * Returns 0 for success;
614101206Srwatson * Returns -1 for failure;
615101206Srwatson * Returns -2 for not present
616101206Srwatson */
617101206Srwatsonint
618101206Srwatsonbsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
619101206Srwatson    char *errstr)
620101206Srwatson{
621101206Srwatson	int name[10];
622101206Srwatson	size_t len, size;
623101206Srwatson	int error;
624101206Srwatson
625101206Srwatson	len = 10;
626101206Srwatson	error = bsde_get_mib(MIB ".rules", name, &len);
627101206Srwatson	if (error) {
628101206Srwatson		len = snprintf(errstr, errlen, "%s: %s", MIB ".rules",
629101206Srwatson		    strerror(errno));
630101206Srwatson		return (-1);
631101206Srwatson	}
632101206Srwatson
633101206Srwatson	size = sizeof(*rule);
634101206Srwatson	name[len] = rulenum;
635101206Srwatson	len++;
636101206Srwatson	error = sysctl(name, len, rule, &size, NULL, 0);
637101206Srwatson	if (error  == -1 && errno == ENOENT)
638101206Srwatson		return (-2);
639101206Srwatson	if (error) {
640101206Srwatson		len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
641101206Srwatson		    rulenum, strerror(errno));
642101206Srwatson		return (-1);
643101206Srwatson	} else if (size != sizeof(*rule)) {
644101206Srwatson		len = snprintf(errstr, errlen, "Data error in %s.%d: %s",
645101206Srwatson		    MIB ".rules", rulenum, strerror(errno));
646101206Srwatson		return (-1);
647101206Srwatson	}
648101206Srwatson
649101206Srwatson	return (0);
650101206Srwatson}
651101206Srwatson
652101206Srwatsonint
653101206Srwatsonbsde_delete_rule(int rulenum, size_t buflen, char *errstr)
654101206Srwatson{
655101206Srwatson	struct mac_bsdextended_rule rule;
656101206Srwatson	int name[10];
657101206Srwatson	size_t len, size;
658101206Srwatson	int error;
659101206Srwatson
660101206Srwatson	len = 10;
661101206Srwatson	error = bsde_get_mib(MIB ".rules", name, &len);
662101206Srwatson	if (error) {
663101206Srwatson		len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
664101206Srwatson		    strerror(errno));
665101206Srwatson		return (-1);
666101206Srwatson	}
667101206Srwatson
668101206Srwatson	name[len] = rulenum;
669101206Srwatson	len++;
670101206Srwatson
671101206Srwatson	size = sizeof(rule);
672101206Srwatson	error = sysctl(name, len, NULL, NULL, &rule, 0);
673101206Srwatson	if (error) {
674101206Srwatson		len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
675101206Srwatson		    rulenum, strerror(errno));
676101206Srwatson		return (-1);
677101206Srwatson	}
678101206Srwatson
679101206Srwatson	return (0);
680101206Srwatson}
681101206Srwatson
682101206Srwatsonint
683101206Srwatsonbsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
684101206Srwatson    char *errstr)
685101206Srwatson{
686101206Srwatson	int name[10];
687101206Srwatson	size_t len, size;
688101206Srwatson	int error;
689101206Srwatson
690101206Srwatson	len = 10;
691101206Srwatson	error = bsde_get_mib(MIB ".rules", name, &len);
692101206Srwatson	if (error) {
693101206Srwatson		len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
694101206Srwatson		    strerror(errno));
695101206Srwatson		return (-1);
696101206Srwatson	}
697101206Srwatson
698101206Srwatson	name[len] = rulenum;
699101206Srwatson	len++;
700101206Srwatson
701101206Srwatson	size = sizeof(*rule);
702101206Srwatson	error = sysctl(name, len, NULL, NULL, rule, size);
703101206Srwatson	if (error) {
704101206Srwatson		len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
705101206Srwatson		    rulenum, strerror(errno));
706101206Srwatson		return (-1);
707101206Srwatson	}
708101206Srwatson
709101206Srwatson	return (0);
710101206Srwatson}
711