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