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