xref: /freebsd/lib/libugidfw/ugidfw.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
146d1a925SRobert Watson /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni  *
4a6c2bc8bSRobert Watson  * Copyright (c) 2002-2005 Networks Associates Technology, Inc.
546d1a925SRobert Watson  * All rights reserved.
646d1a925SRobert Watson  *
70285334bSRobert Watson  * This software was developed for the FreeBSD Project by Network Associates
80285334bSRobert Watson  * Laboratories, the Security Research Division of Network Associates, Inc.
90285334bSRobert Watson  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
100285334bSRobert Watson  * DARPA CHATS research program.
1146d1a925SRobert Watson  *
1246d1a925SRobert Watson  * Redistribution and use in source and binary forms, with or without
1346d1a925SRobert Watson  * modification, are permitted provided that the following conditions
1446d1a925SRobert Watson  * are met:
1546d1a925SRobert Watson  * 1. Redistributions of source code must retain the above copyright
1646d1a925SRobert Watson  *    notice, this list of conditions and the following disclaimer.
1746d1a925SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
1846d1a925SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
1946d1a925SRobert Watson  *    documentation and/or other materials provided with the distribution.
2046d1a925SRobert Watson  *
2146d1a925SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2246d1a925SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2346d1a925SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2446d1a925SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2546d1a925SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2646d1a925SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2746d1a925SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2846d1a925SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2946d1a925SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3046d1a925SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3146d1a925SRobert Watson  * SUCH DAMAGE.
3246d1a925SRobert Watson  */
3346d1a925SRobert Watson #include <sys/param.h>
3446d1a925SRobert Watson #include <sys/errno.h>
35de68a320SJamie Gritton #include <sys/jail.h>
3646d1a925SRobert Watson #include <sys/time.h>
3746d1a925SRobert Watson #include <sys/sysctl.h>
3889ddbd45SDavid Malone #include <sys/ucred.h>
39de68a320SJamie Gritton #include <sys/uio.h>
4089ddbd45SDavid Malone #include <sys/mount.h>
4146d1a925SRobert Watson 
4246d1a925SRobert Watson #include <security/mac_bsdextended/mac_bsdextended.h>
4346d1a925SRobert Watson 
4446d1a925SRobert Watson #include <grp.h>
4546d1a925SRobert Watson #include <pwd.h>
4646d1a925SRobert Watson #include <stdio.h>
4746d1a925SRobert Watson #include <stdlib.h>
4846d1a925SRobert Watson #include <string.h>
4946d1a925SRobert Watson 
50912dd12aSRobert Watson #include "ugidfw.h"
5146d1a925SRobert Watson 
5246d1a925SRobert Watson /*
5346d1a925SRobert Watson  * Text format for rules: rules contain subject and object elements, mode.
5489ddbd45SDavid Malone  * The total form is "subject [s_element] object [o_element] mode [mode]".
5546d1a925SRobert Watson  * At least * one of a uid or gid entry must be present; both may also be
5646d1a925SRobert Watson  * present.
5746d1a925SRobert Watson  */
5846d1a925SRobert Watson 
5946d1a925SRobert Watson #define	MIB	"security.mac.bsdextended"
6046d1a925SRobert Watson 
6146d1a925SRobert Watson int
bsde_rule_to_string(struct mac_bsdextended_rule * rule,char * buf,size_t buflen)6246d1a925SRobert Watson bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
6346d1a925SRobert Watson {
6446d1a925SRobert Watson 	struct group *grp;
6546d1a925SRobert Watson 	struct passwd *pwd;
6689ddbd45SDavid Malone 	struct statfs *mntbuf;
6789ddbd45SDavid Malone 	char *cur, type[sizeof(rule->mbr_object.mbo_type) * CHAR_BIT + 1];
6846d1a925SRobert Watson 	size_t left, len;
69da1259f0SMarcelo Araujo 	int anymode, unknownmode, numfs, i, notdone;
7046d1a925SRobert Watson 
7146d1a925SRobert Watson 	cur = buf;
7246d1a925SRobert Watson 	left = buflen;
7346d1a925SRobert Watson 
7446d1a925SRobert Watson 	len = snprintf(cur, left, "subject ");
7546d1a925SRobert Watson 	if (len < 0 || len > left)
7646d1a925SRobert Watson 		goto truncated;
7746d1a925SRobert Watson 	left -= len;
7846d1a925SRobert Watson 	cur += len;
7989ddbd45SDavid Malone 	if (rule->mbr_subject.mbs_flags) {
8089ddbd45SDavid Malone 		if (rule->mbr_subject.mbs_neg == MBS_ALL_FLAGS) {
8146d1a925SRobert Watson 			len = snprintf(cur, left, "not ");
8246d1a925SRobert Watson 			if (len < 0 || len > left)
8346d1a925SRobert Watson 				goto truncated;
8446d1a925SRobert Watson 			left -= len;
8546d1a925SRobert Watson 			cur += len;
8689ddbd45SDavid Malone 			notdone = 1;
8789ddbd45SDavid Malone 		} else {
8889ddbd45SDavid Malone 			notdone = 0;
8946d1a925SRobert Watson 		}
9089ddbd45SDavid Malone 
9189ddbd45SDavid Malone 		if (!notdone && (rule->mbr_subject.mbs_neg & MBO_UID_DEFINED)) {
9289ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
9389ddbd45SDavid Malone 			if (len < 0 || len > left)
9489ddbd45SDavid Malone 				goto truncated;
9589ddbd45SDavid Malone 			left -= len;
9689ddbd45SDavid Malone 			cur += len;
9789ddbd45SDavid Malone 		}
9889ddbd45SDavid Malone 		if (rule->mbr_subject.mbs_flags & MBO_UID_DEFINED) {
9989ddbd45SDavid Malone 			pwd = getpwuid(rule->mbr_subject.mbs_uid_min);
10046d1a925SRobert Watson 			if (pwd != NULL) {
10146d1a925SRobert Watson 				len = snprintf(cur, left, "uid %s",
10246d1a925SRobert Watson 				    pwd->pw_name);
10346d1a925SRobert Watson 				if (len < 0 || len > left)
10446d1a925SRobert Watson 					goto truncated;
10546d1a925SRobert Watson 				left -= len;
10646d1a925SRobert Watson 				cur += len;
10746d1a925SRobert Watson 			} else {
10846d1a925SRobert Watson 				len = snprintf(cur, left, "uid %u",
10989ddbd45SDavid Malone 				    rule->mbr_subject.mbs_uid_min);
11089ddbd45SDavid Malone 				if (len < 0 || len > left)
11189ddbd45SDavid Malone 					goto truncated;
11289ddbd45SDavid Malone 				left -= len;
11389ddbd45SDavid Malone 				cur += len;
11489ddbd45SDavid Malone 			}
11589ddbd45SDavid Malone 			if (rule->mbr_subject.mbs_uid_min !=
11689ddbd45SDavid Malone 			    rule->mbr_subject.mbs_uid_max) {
11789ddbd45SDavid Malone 				pwd = getpwuid(rule->mbr_subject.mbs_uid_max);
11889ddbd45SDavid Malone 				if (pwd != NULL) {
11989ddbd45SDavid Malone 					len = snprintf(cur, left, ":%s ",
12089ddbd45SDavid Malone 					    pwd->pw_name);
12189ddbd45SDavid Malone 					if (len < 0 || len > left)
12289ddbd45SDavid Malone 						goto truncated;
12389ddbd45SDavid Malone 					left -= len;
12489ddbd45SDavid Malone 					cur += len;
12589ddbd45SDavid Malone 				} else {
12689ddbd45SDavid Malone 					len = snprintf(cur, left, ":%u ",
12789ddbd45SDavid Malone 					    rule->mbr_subject.mbs_uid_max);
12889ddbd45SDavid Malone 					if (len < 0 || len > left)
12989ddbd45SDavid Malone 						goto truncated;
13089ddbd45SDavid Malone 					left -= len;
13189ddbd45SDavid Malone 					cur += len;
13289ddbd45SDavid Malone 				}
13389ddbd45SDavid Malone 			} else {
13489ddbd45SDavid Malone 				len = snprintf(cur, left, " ");
13546d1a925SRobert Watson 				if (len < 0 || len > left)
13646d1a925SRobert Watson 					goto truncated;
13746d1a925SRobert Watson 				left -= len;
13846d1a925SRobert Watson 				cur += len;
13946d1a925SRobert Watson 			}
14046d1a925SRobert Watson 		}
14189ddbd45SDavid Malone 		if (!notdone && (rule->mbr_subject.mbs_neg & MBO_GID_DEFINED)) {
14289ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
14389ddbd45SDavid Malone 			if (len < 0 || len > left)
14489ddbd45SDavid Malone 				goto truncated;
14589ddbd45SDavid Malone 			left -= len;
14689ddbd45SDavid Malone 			cur += len;
14789ddbd45SDavid Malone 		}
14889ddbd45SDavid Malone 		if (rule->mbr_subject.mbs_flags & MBO_GID_DEFINED) {
14989ddbd45SDavid Malone 			grp = getgrgid(rule->mbr_subject.mbs_gid_min);
15046d1a925SRobert Watson 			if (grp != NULL) {
15146d1a925SRobert Watson 				len = snprintf(cur, left, "gid %s",
15246d1a925SRobert Watson 				    grp->gr_name);
15346d1a925SRobert Watson 				if (len < 0 || len > left)
15446d1a925SRobert Watson 					goto truncated;
15546d1a925SRobert Watson 				left -= len;
15646d1a925SRobert Watson 				cur += len;
15746d1a925SRobert Watson 			} else {
15846d1a925SRobert Watson 				len = snprintf(cur, left, "gid %u",
15989ddbd45SDavid Malone 				    rule->mbr_subject.mbs_gid_min);
16089ddbd45SDavid Malone 				if (len < 0 || len > left)
16189ddbd45SDavid Malone 					goto truncated;
16289ddbd45SDavid Malone 				left -= len;
16389ddbd45SDavid Malone 				cur += len;
16489ddbd45SDavid Malone 			}
16589ddbd45SDavid Malone 			if (rule->mbr_subject.mbs_gid_min !=
16689ddbd45SDavid Malone 			    rule->mbr_subject.mbs_gid_max) {
16789ddbd45SDavid Malone 				grp = getgrgid(rule->mbr_subject.mbs_gid_max);
16889ddbd45SDavid Malone 				if (grp != NULL) {
16989ddbd45SDavid Malone 					len = snprintf(cur, left, ":%s ",
17089ddbd45SDavid Malone 					    grp->gr_name);
17189ddbd45SDavid Malone 					if (len < 0 || len > left)
17289ddbd45SDavid Malone 						goto truncated;
17389ddbd45SDavid Malone 					left -= len;
17489ddbd45SDavid Malone 					cur += len;
17589ddbd45SDavid Malone 				} else {
17689ddbd45SDavid Malone 					len = snprintf(cur, left, ":%u ",
17789ddbd45SDavid Malone 					    rule->mbr_subject.mbs_gid_max);
17889ddbd45SDavid Malone 					if (len < 0 || len > left)
17989ddbd45SDavid Malone 						goto truncated;
18089ddbd45SDavid Malone 					left -= len;
18189ddbd45SDavid Malone 					cur += len;
18289ddbd45SDavid Malone 				}
18389ddbd45SDavid Malone 			} else {
18489ddbd45SDavid Malone 				len = snprintf(cur, left, " ");
18546d1a925SRobert Watson 				if (len < 0 || len > left)
18646d1a925SRobert Watson 					goto truncated;
18746d1a925SRobert Watson 				left -= len;
18846d1a925SRobert Watson 				cur += len;
18946d1a925SRobert Watson 			}
19046d1a925SRobert Watson 		}
19189ddbd45SDavid Malone 		if (!notdone && (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)) {
19289ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
19389ddbd45SDavid Malone 			if (len < 0 || len > left)
19489ddbd45SDavid Malone 				goto truncated;
19589ddbd45SDavid Malone 			left -= len;
19689ddbd45SDavid Malone 			cur += len;
19746d1a925SRobert Watson 		}
19889ddbd45SDavid Malone 		if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
19989ddbd45SDavid Malone 			len = snprintf(cur, left, "jailid %d ",
20089ddbd45SDavid Malone 			    rule->mbr_subject.mbs_prison);
20189ddbd45SDavid Malone 			if (len < 0 || len > left)
20289ddbd45SDavid Malone 				goto truncated;
20389ddbd45SDavid Malone 			left -= len;
20489ddbd45SDavid Malone 			cur += len;
20589ddbd45SDavid Malone 		}
20689ddbd45SDavid Malone 	}
20789ddbd45SDavid Malone 
20846d1a925SRobert Watson 	len = snprintf(cur, left, "object ");
20946d1a925SRobert Watson 	if (len < 0 || len > left)
21046d1a925SRobert Watson 		goto truncated;
21146d1a925SRobert Watson 	left -= len;
21246d1a925SRobert Watson 	cur += len;
21389ddbd45SDavid Malone 	if (rule->mbr_object.mbo_flags) {
21489ddbd45SDavid Malone 		if (rule->mbr_object.mbo_neg == MBO_ALL_FLAGS) {
21546d1a925SRobert Watson 			len = snprintf(cur, left, "not ");
21646d1a925SRobert Watson 			if (len < 0 || len > left)
21746d1a925SRobert Watson 				goto truncated;
21846d1a925SRobert Watson 			left -= len;
21946d1a925SRobert Watson 			cur += len;
22089ddbd45SDavid Malone 			notdone = 1;
22189ddbd45SDavid Malone 		} else {
22289ddbd45SDavid Malone 			notdone = 0;
22346d1a925SRobert Watson 		}
22489ddbd45SDavid Malone 
22589ddbd45SDavid Malone 		if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)) {
22689ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
22789ddbd45SDavid Malone 			if (len < 0 || len > left)
22889ddbd45SDavid Malone 				goto truncated;
22989ddbd45SDavid Malone 			left -= len;
23089ddbd45SDavid Malone 			cur += len;
23189ddbd45SDavid Malone 		}
23289ddbd45SDavid Malone 		if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
23389ddbd45SDavid Malone 			pwd = getpwuid(rule->mbr_object.mbo_uid_min);
23446d1a925SRobert Watson 			if (pwd != NULL) {
23546d1a925SRobert Watson 				len = snprintf(cur, left, "uid %s",
23646d1a925SRobert Watson 				    pwd->pw_name);
23746d1a925SRobert Watson 				if (len < 0 || len > left)
23846d1a925SRobert Watson 					goto truncated;
23946d1a925SRobert Watson 				left -= len;
24046d1a925SRobert Watson 				cur += len;
24146d1a925SRobert Watson 			} else {
24246d1a925SRobert Watson 				len = snprintf(cur, left, "uid %u",
24389ddbd45SDavid Malone 				    rule->mbr_object.mbo_uid_min);
24489ddbd45SDavid Malone 				if (len < 0 || len > left)
24589ddbd45SDavid Malone 					goto truncated;
24689ddbd45SDavid Malone 				left -= len;
24789ddbd45SDavid Malone 				cur += len;
24889ddbd45SDavid Malone 			}
24989ddbd45SDavid Malone 			if (rule->mbr_object.mbo_uid_min !=
25089ddbd45SDavid Malone 			    rule->mbr_object.mbo_uid_max) {
25189ddbd45SDavid Malone 				pwd = getpwuid(rule->mbr_object.mbo_uid_max);
25289ddbd45SDavid Malone 				if (pwd != NULL) {
25389ddbd45SDavid Malone 					len = snprintf(cur, left, ":%s ",
25489ddbd45SDavid Malone 					    pwd->pw_name);
25589ddbd45SDavid Malone 					if (len < 0 || len > left)
25689ddbd45SDavid Malone 						goto truncated;
25789ddbd45SDavid Malone 					left -= len;
25889ddbd45SDavid Malone 					cur += len;
25989ddbd45SDavid Malone 				} else {
26089ddbd45SDavid Malone 					len = snprintf(cur, left, ":%u ",
26189ddbd45SDavid Malone 					    rule->mbr_object.mbo_uid_max);
26289ddbd45SDavid Malone 					if (len < 0 || len > left)
26389ddbd45SDavid Malone 						goto truncated;
26489ddbd45SDavid Malone 					left -= len;
26589ddbd45SDavid Malone 					cur += len;
26689ddbd45SDavid Malone 				}
26789ddbd45SDavid Malone 			} else {
26889ddbd45SDavid Malone 				len = snprintf(cur, left, " ");
26989ddbd45SDavid Malone 				if (len < 0 || len > left)
27089ddbd45SDavid Malone 					goto truncated;
27146d1a925SRobert Watson 				left -= len;
27246d1a925SRobert Watson 				cur += len;
27346d1a925SRobert Watson 			}
27446d1a925SRobert Watson 		}
27589ddbd45SDavid Malone 		if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)) {
27689ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
27789ddbd45SDavid Malone 			if (len < 0 || len > left)
27889ddbd45SDavid Malone 				goto truncated;
27989ddbd45SDavid Malone 			left -= len;
28089ddbd45SDavid Malone 			cur += len;
28189ddbd45SDavid Malone 		}
28289ddbd45SDavid Malone 		if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
28389ddbd45SDavid Malone 			grp = getgrgid(rule->mbr_object.mbo_gid_min);
28446d1a925SRobert Watson 			if (grp != NULL) {
28546d1a925SRobert Watson 				len = snprintf(cur, left, "gid %s",
28646d1a925SRobert Watson 				    grp->gr_name);
28746d1a925SRobert Watson 				if (len < 0 || len > left)
28846d1a925SRobert Watson 					goto truncated;
28946d1a925SRobert Watson 				left -= len;
29046d1a925SRobert Watson 				cur += len;
29146d1a925SRobert Watson 			} else {
29246d1a925SRobert Watson 				len = snprintf(cur, left, "gid %u",
29389ddbd45SDavid Malone 				    rule->mbr_object.mbo_gid_min);
29446d1a925SRobert Watson 				if (len < 0 || len > left)
29546d1a925SRobert Watson 					goto truncated;
29646d1a925SRobert Watson 				left -= len;
29746d1a925SRobert Watson 				cur += len;
29846d1a925SRobert Watson 			}
29989ddbd45SDavid Malone 			if (rule->mbr_object.mbo_gid_min !=
30089ddbd45SDavid Malone 			    rule->mbr_object.mbo_gid_max) {
30189ddbd45SDavid Malone 				grp = getgrgid(rule->mbr_object.mbo_gid_max);
30289ddbd45SDavid Malone 				if (grp != NULL) {
30389ddbd45SDavid Malone 					len = snprintf(cur, left, ":%s ",
30489ddbd45SDavid Malone 					    grp->gr_name);
30589ddbd45SDavid Malone 					if (len < 0 || len > left)
30689ddbd45SDavid Malone 						goto truncated;
30789ddbd45SDavid Malone 					left -= len;
30889ddbd45SDavid Malone 					cur += len;
30989ddbd45SDavid Malone 				} else {
31089ddbd45SDavid Malone 					len = snprintf(cur, left, ":%u ",
31189ddbd45SDavid Malone 					    rule->mbr_object.mbo_gid_max);
31289ddbd45SDavid Malone 					if (len < 0 || len > left)
31389ddbd45SDavid Malone 						goto truncated;
31489ddbd45SDavid Malone 					left -= len;
31589ddbd45SDavid Malone 					cur += len;
31689ddbd45SDavid Malone 				}
31789ddbd45SDavid Malone 			} else {
31889ddbd45SDavid Malone 				len = snprintf(cur, left, " ");
31989ddbd45SDavid Malone 				if (len < 0 || len > left)
32089ddbd45SDavid Malone 					goto truncated;
32189ddbd45SDavid Malone 				left -= len;
32289ddbd45SDavid Malone 				cur += len;
32389ddbd45SDavid Malone 			}
32489ddbd45SDavid Malone 		}
32589ddbd45SDavid Malone 		if (!notdone && (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)) {
32689ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
32789ddbd45SDavid Malone 			if (len < 0 || len > left)
32889ddbd45SDavid Malone 				goto truncated;
32989ddbd45SDavid Malone 			left -= len;
33089ddbd45SDavid Malone 			cur += len;
33189ddbd45SDavid Malone 		}
33289ddbd45SDavid Malone 		if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
33389ddbd45SDavid Malone 			numfs = getmntinfo(&mntbuf, MNT_NOWAIT);
33489ddbd45SDavid Malone 			for (i = 0; i < numfs; i++)
335245bfd34SRyan Moeller 				if (fsidcmp(&rule->mbr_object.mbo_fsid,
336245bfd34SRyan Moeller 				    &mntbuf[i].f_fsid) == 0)
33789ddbd45SDavid Malone 					break;
33889ddbd45SDavid Malone 			len = snprintf(cur, left, "filesys %s ",
33989ddbd45SDavid Malone 			    i == numfs ? "???" : mntbuf[i].f_mntonname);
34089ddbd45SDavid Malone 			if (len < 0 || len > left)
34189ddbd45SDavid Malone 				goto truncated;
34289ddbd45SDavid Malone 			left -= len;
34389ddbd45SDavid Malone 			cur += len;
34489ddbd45SDavid Malone 		}
34589ddbd45SDavid Malone 		if (!notdone && (rule->mbr_object.mbo_neg & MBO_SUID)) {
34689ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
34789ddbd45SDavid Malone 			if (len < 0 || len > left)
34889ddbd45SDavid Malone 				goto truncated;
34989ddbd45SDavid Malone 			left -= len;
35089ddbd45SDavid Malone 			cur += len;
35189ddbd45SDavid Malone 		}
35289ddbd45SDavid Malone 		if (rule->mbr_object.mbo_flags & MBO_SUID) {
35389ddbd45SDavid Malone 			len = snprintf(cur, left, "suid ");
35489ddbd45SDavid Malone 			if (len < 0 || len > left)
35589ddbd45SDavid Malone 				goto truncated;
35689ddbd45SDavid Malone 			left -= len;
35789ddbd45SDavid Malone 			cur += len;
35889ddbd45SDavid Malone 		}
35989ddbd45SDavid Malone 		if (!notdone && (rule->mbr_object.mbo_neg & MBO_SGID)) {
36089ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
36189ddbd45SDavid Malone 			if (len < 0 || len > left)
36289ddbd45SDavid Malone 				goto truncated;
36389ddbd45SDavid Malone 			left -= len;
36489ddbd45SDavid Malone 			cur += len;
36589ddbd45SDavid Malone 		}
36689ddbd45SDavid Malone 		if (rule->mbr_object.mbo_flags & MBO_SGID) {
36789ddbd45SDavid Malone 			len = snprintf(cur, left, "sgid ");
36889ddbd45SDavid Malone 			if (len < 0 || len > left)
36989ddbd45SDavid Malone 				goto truncated;
37089ddbd45SDavid Malone 			left -= len;
37189ddbd45SDavid Malone 			cur += len;
37289ddbd45SDavid Malone 		}
37389ddbd45SDavid Malone 		if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)) {
37489ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
37589ddbd45SDavid Malone 			if (len < 0 || len > left)
37689ddbd45SDavid Malone 				goto truncated;
37789ddbd45SDavid Malone 			left -= len;
37889ddbd45SDavid Malone 			cur += len;
37989ddbd45SDavid Malone 		}
38089ddbd45SDavid Malone 		if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
38189ddbd45SDavid Malone 			len = snprintf(cur, left, "uid_of_subject ");
38289ddbd45SDavid Malone 			if (len < 0 || len > left)
38389ddbd45SDavid Malone 				goto truncated;
38489ddbd45SDavid Malone 			left -= len;
38589ddbd45SDavid Malone 			cur += len;
38689ddbd45SDavid Malone 		}
38789ddbd45SDavid Malone 		if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)) {
38889ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
38989ddbd45SDavid Malone 			if (len < 0 || len > left)
39089ddbd45SDavid Malone 				goto truncated;
39189ddbd45SDavid Malone 			left -= len;
39289ddbd45SDavid Malone 			cur += len;
39389ddbd45SDavid Malone 		}
39489ddbd45SDavid Malone 		if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
39589ddbd45SDavid Malone 			len = snprintf(cur, left, "gid_of_subject ");
39689ddbd45SDavid Malone 			if (len < 0 || len > left)
39789ddbd45SDavid Malone 				goto truncated;
39889ddbd45SDavid Malone 			left -= len;
39989ddbd45SDavid Malone 			cur += len;
40089ddbd45SDavid Malone 		}
40189ddbd45SDavid Malone 		if (!notdone && (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)) {
40289ddbd45SDavid Malone 			len = snprintf(cur, left, "! ");
40389ddbd45SDavid Malone 			if (len < 0 || len > left)
40489ddbd45SDavid Malone 				goto truncated;
40589ddbd45SDavid Malone 			left -= len;
40689ddbd45SDavid Malone 			cur += len;
40789ddbd45SDavid Malone 		}
40889ddbd45SDavid Malone 		if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
40989ddbd45SDavid Malone 			i = 0;
41089ddbd45SDavid Malone 			if (rule->mbr_object.mbo_type & MBO_TYPE_REG)
41189ddbd45SDavid Malone 				type[i++] = 'r';
41289ddbd45SDavid Malone 			if (rule->mbr_object.mbo_type & MBO_TYPE_DIR)
41389ddbd45SDavid Malone 				type[i++] = 'd';
41489ddbd45SDavid Malone 			if (rule->mbr_object.mbo_type & MBO_TYPE_BLK)
41589ddbd45SDavid Malone 				type[i++] = 'b';
41689ddbd45SDavid Malone 			if (rule->mbr_object.mbo_type & MBO_TYPE_CHR)
41789ddbd45SDavid Malone 				type[i++] = 'c';
41889ddbd45SDavid Malone 			if (rule->mbr_object.mbo_type & MBO_TYPE_LNK)
41989ddbd45SDavid Malone 				type[i++] = 'l';
42089ddbd45SDavid Malone 			if (rule->mbr_object.mbo_type & MBO_TYPE_SOCK)
42189ddbd45SDavid Malone 				type[i++] = 's';
42289ddbd45SDavid Malone 			if (rule->mbr_object.mbo_type & MBO_TYPE_FIFO)
42389ddbd45SDavid Malone 				type[i++] = 'p';
42489ddbd45SDavid Malone 			if (rule->mbr_object.mbo_type == MBO_ALL_TYPE) {
42589ddbd45SDavid Malone 				i = 0;
42689ddbd45SDavid Malone 				type[i++] = 'a';
42789ddbd45SDavid Malone 			}
42889ddbd45SDavid Malone 			type[i++] = '\0';
42989ddbd45SDavid Malone 			len = snprintf(cur, left, "type %s ", type);
43089ddbd45SDavid Malone 			if (len < 0 || len > left)
43189ddbd45SDavid Malone 				goto truncated;
43289ddbd45SDavid Malone 			left -= len;
43389ddbd45SDavid Malone 			cur += len;
43446d1a925SRobert Watson 		}
43546d1a925SRobert Watson 	}
43646d1a925SRobert Watson 
43746d1a925SRobert Watson 	len = snprintf(cur, left, "mode ");
43846d1a925SRobert Watson 	if (len < 0 || len > left)
43946d1a925SRobert Watson 		goto truncated;
44046d1a925SRobert Watson 	left -= len;
44146d1a925SRobert Watson 	cur += len;
44246d1a925SRobert Watson 
443f4194603SRobert Watson 	anymode = (rule->mbr_mode & MBI_ALLPERM);
444f4194603SRobert Watson 	unknownmode = (rule->mbr_mode & ~MBI_ALLPERM);
44546d1a925SRobert Watson 
446f4194603SRobert Watson 	if (rule->mbr_mode & MBI_ADMIN) {
44746d1a925SRobert Watson 		len = snprintf(cur, left, "a");
44846d1a925SRobert Watson 		if (len < 0 || len > left)
44946d1a925SRobert Watson 			goto truncated;
45046d1a925SRobert Watson 
45146d1a925SRobert Watson 		left -= len;
45246d1a925SRobert Watson 		cur += len;
45346d1a925SRobert Watson 	}
454f4194603SRobert Watson 	if (rule->mbr_mode & MBI_READ) {
45546d1a925SRobert Watson 		len = snprintf(cur, left, "r");
45646d1a925SRobert Watson 		if (len < 0 || len > left)
45746d1a925SRobert Watson 			goto truncated;
45846d1a925SRobert Watson 
45946d1a925SRobert Watson 		left -= len;
46046d1a925SRobert Watson 		cur += len;
46146d1a925SRobert Watson 	}
462f4194603SRobert Watson 	if (rule->mbr_mode & MBI_STAT) {
46346d1a925SRobert Watson 		len = snprintf(cur, left, "s");
46446d1a925SRobert Watson 		if (len < 0 || len > left)
46546d1a925SRobert Watson 			goto truncated;
46646d1a925SRobert Watson 
46746d1a925SRobert Watson 		left -= len;
46846d1a925SRobert Watson 		cur += len;
46946d1a925SRobert Watson 	}
470f4194603SRobert Watson 	if (rule->mbr_mode & MBI_WRITE) {
47146d1a925SRobert Watson 		len = snprintf(cur, left, "w");
47246d1a925SRobert Watson 		if (len < 0 || len > left)
47346d1a925SRobert Watson 			goto truncated;
47446d1a925SRobert Watson 
47546d1a925SRobert Watson 		left -= len;
47646d1a925SRobert Watson 		cur += len;
47746d1a925SRobert Watson 	}
478f4194603SRobert Watson 	if (rule->mbr_mode & MBI_EXEC) {
47946d1a925SRobert Watson 		len = snprintf(cur, left, "x");
48046d1a925SRobert Watson 		if (len < 0 || len > left)
48146d1a925SRobert Watson 			goto truncated;
48246d1a925SRobert Watson 
48346d1a925SRobert Watson 		left -= len;
48446d1a925SRobert Watson 		cur += len;
48546d1a925SRobert Watson 	}
48646d1a925SRobert Watson 	if (!anymode) {
48746d1a925SRobert Watson 		len = snprintf(cur, left, "n");
48846d1a925SRobert Watson 		if (len < 0 || len > left)
48946d1a925SRobert Watson 			goto truncated;
49046d1a925SRobert Watson 
49146d1a925SRobert Watson 		left -= len;
49246d1a925SRobert Watson 		cur += len;
49346d1a925SRobert Watson 	}
49446d1a925SRobert Watson 	if (unknownmode) {
49546d1a925SRobert Watson 		len = snprintf(cur, left, "?");
49646d1a925SRobert Watson 		if (len < 0 || len > left)
49746d1a925SRobert Watson 			goto truncated;
49846d1a925SRobert Watson 
49946d1a925SRobert Watson 		left -= len;
50046d1a925SRobert Watson 		cur += len;
50146d1a925SRobert Watson 	}
50246d1a925SRobert Watson 
50346d1a925SRobert Watson 	return (0);
50446d1a925SRobert Watson 
50546d1a925SRobert Watson truncated:
50646d1a925SRobert Watson 	return (-1);
50746d1a925SRobert Watson }
50846d1a925SRobert Watson 
509bf417062SMarcelo Araujo static int
bsde_parse_uidrange(char * spec,uid_t * min,uid_t * max,size_t buflen,char * errstr)51089ddbd45SDavid Malone bsde_parse_uidrange(char *spec, uid_t *min, uid_t *max,
51189ddbd45SDavid Malone     size_t buflen, char *errstr){
51246d1a925SRobert Watson 	struct passwd *pwd;
51389ddbd45SDavid Malone 	uid_t uid1, uid2;
51489ddbd45SDavid Malone 	char *spec1, *spec2, *endp;
51589ddbd45SDavid Malone 	unsigned long value;
51646d1a925SRobert Watson 
51789ddbd45SDavid Malone 	spec2 = spec;
51889ddbd45SDavid Malone 	spec1 = strsep(&spec2, ":");
51989ddbd45SDavid Malone 
52089ddbd45SDavid Malone 	pwd = getpwnam(spec1);
52189ddbd45SDavid Malone 	if (pwd != NULL)
52289ddbd45SDavid Malone 		uid1 = pwd->pw_uid;
52389ddbd45SDavid Malone 	else {
52489ddbd45SDavid Malone 		value = strtoul(spec1, &endp, 10);
52589ddbd45SDavid Malone 		if (*endp != '\0') {
526df6a67d6SEnji Cooper 			snprintf(errstr, buflen, "invalid uid: '%s'", spec1);
52746d1a925SRobert Watson 			return (-1);
52846d1a925SRobert Watson 		}
52989ddbd45SDavid Malone 		uid1 = value;
53089ddbd45SDavid Malone 	}
53189ddbd45SDavid Malone 
53289ddbd45SDavid Malone 	if (spec2 == NULL) {
53389ddbd45SDavid Malone 		*max = *min = uid1;
53489ddbd45SDavid Malone 		return (0);
53589ddbd45SDavid Malone 	}
53689ddbd45SDavid Malone 
53789ddbd45SDavid Malone 	pwd = getpwnam(spec2);
53889ddbd45SDavid Malone 	if (pwd != NULL)
53989ddbd45SDavid Malone 		uid2 = pwd->pw_uid;
54089ddbd45SDavid Malone 	else {
54189ddbd45SDavid Malone 		value = strtoul(spec2, &endp, 10);
54289ddbd45SDavid Malone 		if (*endp != '\0') {
543df6a67d6SEnji Cooper 			snprintf(errstr, buflen, "invalid uid: '%s'", spec2);
54489ddbd45SDavid Malone 			return (-1);
54589ddbd45SDavid Malone 		}
54689ddbd45SDavid Malone 		uid2 = value;
54789ddbd45SDavid Malone 	}
54889ddbd45SDavid Malone 
54989ddbd45SDavid Malone 	*min = uid1;
55089ddbd45SDavid Malone 	*max = uid2;
55189ddbd45SDavid Malone 
55289ddbd45SDavid Malone 	return (0);
55389ddbd45SDavid Malone }
55489ddbd45SDavid Malone 
555bf417062SMarcelo Araujo static int
bsde_parse_gidrange(char * spec,gid_t * min,gid_t * max,size_t buflen,char * errstr)55689ddbd45SDavid Malone bsde_parse_gidrange(char *spec, gid_t *min, gid_t *max,
55789ddbd45SDavid Malone     size_t buflen, char *errstr){
55889ddbd45SDavid Malone 	struct group *grp;
55989ddbd45SDavid Malone 	gid_t gid1, gid2;
56089ddbd45SDavid Malone 	char *spec1, *spec2, *endp;
56189ddbd45SDavid Malone 	unsigned long value;
56289ddbd45SDavid Malone 
56389ddbd45SDavid Malone 	spec2 = spec;
56489ddbd45SDavid Malone 	spec1 = strsep(&spec2, ":");
56589ddbd45SDavid Malone 
56689ddbd45SDavid Malone 	grp = getgrnam(spec1);
56789ddbd45SDavid Malone 	if (grp != NULL)
56889ddbd45SDavid Malone 		gid1 = grp->gr_gid;
56989ddbd45SDavid Malone 	else {
57089ddbd45SDavid Malone 		value = strtoul(spec1, &endp, 10);
57189ddbd45SDavid Malone 		if (*endp != '\0') {
572df6a67d6SEnji Cooper 			snprintf(errstr, buflen, "invalid gid: '%s'", spec1);
57389ddbd45SDavid Malone 			return (-1);
57489ddbd45SDavid Malone 		}
57589ddbd45SDavid Malone 		gid1 = value;
57689ddbd45SDavid Malone 	}
57789ddbd45SDavid Malone 
57889ddbd45SDavid Malone 	if (spec2 == NULL) {
57989ddbd45SDavid Malone 		*max = *min = gid1;
58089ddbd45SDavid Malone 		return (0);
58189ddbd45SDavid Malone 	}
58289ddbd45SDavid Malone 
58389ddbd45SDavid Malone 	grp = getgrnam(spec2);
58489ddbd45SDavid Malone 	if (grp != NULL)
58589ddbd45SDavid Malone 		gid2 = grp->gr_gid;
58689ddbd45SDavid Malone 	else {
58789ddbd45SDavid Malone 		value = strtoul(spec2, &endp, 10);
58889ddbd45SDavid Malone 		if (*endp != '\0') {
589df6a67d6SEnji Cooper 			snprintf(errstr, buflen, "invalid gid: '%s'", spec2);
59089ddbd45SDavid Malone 			return (-1);
59189ddbd45SDavid Malone 		}
59289ddbd45SDavid Malone 		gid2 = value;
59389ddbd45SDavid Malone 	}
59489ddbd45SDavid Malone 
59589ddbd45SDavid Malone 	*min = gid1;
59689ddbd45SDavid Malone 	*max = gid2;
59789ddbd45SDavid Malone 
59889ddbd45SDavid Malone 	return (0);
59989ddbd45SDavid Malone }
60089ddbd45SDavid Malone 
601bf417062SMarcelo Araujo static int
bsde_get_jailid(const char * name,size_t buflen,char * errstr)602de68a320SJamie Gritton bsde_get_jailid(const char *name, size_t buflen, char *errstr)
603de68a320SJamie Gritton {
604de68a320SJamie Gritton 	char *ep;
605de68a320SJamie Gritton 	int jid;
606de68a320SJamie Gritton 	struct iovec jiov[4];
607de68a320SJamie Gritton 
608de68a320SJamie Gritton 	/* Copy jail_getid(3) instead of messing with library dependancies */
609de68a320SJamie Gritton 	jid = strtoul(name, &ep, 10);
610de68a320SJamie Gritton 	if (*name && !*ep)
611de68a320SJamie Gritton 		return jid;
612de68a320SJamie Gritton 	jiov[0].iov_base = __DECONST(char *, "name");
613de68a320SJamie Gritton 	jiov[0].iov_len = sizeof("name");
614de68a320SJamie Gritton 	jiov[1].iov_len = strlen(name) + 1;
615de68a320SJamie Gritton 	jiov[1].iov_base = alloca(jiov[1].iov_len);
616de68a320SJamie Gritton 	strcpy(jiov[1].iov_base, name);
617de68a320SJamie Gritton 	if (errstr && buflen) {
618de68a320SJamie Gritton 		jiov[2].iov_base = __DECONST(char *, "errmsg");
619de68a320SJamie Gritton 		jiov[2].iov_len = sizeof("errmsg");
620de68a320SJamie Gritton 		jiov[3].iov_base = errstr;
621de68a320SJamie Gritton 		jiov[3].iov_len = buflen;
622de68a320SJamie Gritton 		errstr[0] = 0;
623de68a320SJamie Gritton 		jid = jail_get(jiov, 4, 0);
624de68a320SJamie Gritton 		if (jid < 0 && !errstr[0])
625de68a320SJamie Gritton 			snprintf(errstr, buflen, "jail_get: %s",
626de68a320SJamie Gritton 			    strerror(errno));
627de68a320SJamie Gritton 	} else
628de68a320SJamie Gritton 		jid = jail_get(jiov, 2, 0);
629de68a320SJamie Gritton 	return jid;
630de68a320SJamie Gritton }
631de68a320SJamie Gritton 
632de68a320SJamie Gritton static int
bsde_parse_subject(int argc,char * argv[],struct mac_bsdextended_subject * subject,size_t buflen,char * errstr)63389ddbd45SDavid Malone bsde_parse_subject(int argc, char *argv[],
63489ddbd45SDavid Malone     struct mac_bsdextended_subject *subject, size_t buflen, char *errstr)
63589ddbd45SDavid Malone {
63689ddbd45SDavid Malone 	int not_seen, flags;
63789ddbd45SDavid Malone 	int current, neg, nextnot;
63889ddbd45SDavid Malone 	uid_t uid_min, uid_max;
63989ddbd45SDavid Malone 	gid_t gid_min, gid_max;
640bf417062SMarcelo Araujo 	int jid = 0;
64146d1a925SRobert Watson 
64246d1a925SRobert Watson 	current = 0;
64389ddbd45SDavid Malone 	flags = 0;
64489ddbd45SDavid Malone 	neg = 0;
64589ddbd45SDavid Malone 	nextnot = 0;
64646d1a925SRobert Watson 
64789ddbd45SDavid Malone 	if (strcmp("not", argv[current]) == 0) {
64846d1a925SRobert Watson 		not_seen = 1;
64946d1a925SRobert Watson 		current++;
65046d1a925SRobert Watson 	} else
65146d1a925SRobert Watson 		not_seen = 0;
65246d1a925SRobert Watson 
65389ddbd45SDavid Malone 	while (current < argc) {
65489ddbd45SDavid Malone 		if (strcmp(argv[current], "uid") == 0) {
65546d1a925SRobert Watson 			if (current + 2 > argc) {
656df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "uid short");
65746d1a925SRobert Watson 				return (-1);
65846d1a925SRobert Watson 			}
65989ddbd45SDavid Malone 			if (flags & MBS_UID_DEFINED) {
660df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "one uid only");
66146d1a925SRobert Watson 				return (-1);
66246d1a925SRobert Watson 			}
66389ddbd45SDavid Malone 			if (bsde_parse_uidrange(argv[current+1],
66489ddbd45SDavid Malone 			    &uid_min, &uid_max, buflen, errstr) < 0)
66589ddbd45SDavid Malone 				return (-1);
66689ddbd45SDavid Malone 			flags |= MBS_UID_DEFINED;
66789ddbd45SDavid Malone 			if (nextnot) {
66889ddbd45SDavid Malone 				neg ^= MBS_UID_DEFINED;
66989ddbd45SDavid Malone 				nextnot = 0;
67046d1a925SRobert Watson 			}
67146d1a925SRobert Watson 			current += 2;
67289ddbd45SDavid Malone 		} else if (strcmp(argv[current], "gid") == 0) {
67346d1a925SRobert Watson 			if (current + 2 > argc) {
674df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "gid short");
67546d1a925SRobert Watson 				return (-1);
67646d1a925SRobert Watson 			}
67789ddbd45SDavid Malone 			if (flags & MBS_GID_DEFINED) {
678df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "one gid only");
67946d1a925SRobert Watson 				return (-1);
68046d1a925SRobert Watson 			}
68189ddbd45SDavid Malone 			if (bsde_parse_gidrange(argv[current+1],
68289ddbd45SDavid Malone 			    &gid_min, &gid_max, buflen, errstr) < 0)
68389ddbd45SDavid Malone 				return (-1);
68489ddbd45SDavid Malone 			flags |= MBS_GID_DEFINED;
68589ddbd45SDavid Malone 			if (nextnot) {
68689ddbd45SDavid Malone 				neg ^= MBS_GID_DEFINED;
68789ddbd45SDavid Malone 				nextnot = 0;
68846d1a925SRobert Watson 			}
68946d1a925SRobert Watson 			current += 2;
69089ddbd45SDavid Malone 		} else if (strcmp(argv[current], "jailid") == 0) {
69146d1a925SRobert Watson 			if (current + 2 > argc) {
692df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "prison short");
69346d1a925SRobert Watson 				return (-1);
69446d1a925SRobert Watson 			}
69589ddbd45SDavid Malone 			if (flags & MBS_PRISON_DEFINED) {
696df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "one jail only");
69789ddbd45SDavid Malone 				return (-1);
69889ddbd45SDavid Malone 			}
699de68a320SJamie Gritton 			jid = bsde_get_jailid(argv[current+1], buflen, errstr);
700de68a320SJamie Gritton 			if (jid < 0)
70146d1a925SRobert Watson 				return (-1);
70289ddbd45SDavid Malone 			flags |= MBS_PRISON_DEFINED;
70389ddbd45SDavid Malone 			if (nextnot) {
70489ddbd45SDavid Malone 				neg ^= MBS_PRISON_DEFINED;
70589ddbd45SDavid Malone 				nextnot = 0;
706a6c2bc8bSRobert Watson 			}
70746d1a925SRobert Watson 			current += 2;
70889ddbd45SDavid Malone 		} else if (strcmp(argv[current], "!") == 0) {
70989ddbd45SDavid Malone 			if (nextnot) {
710df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "double negative");
71146d1a925SRobert Watson 				return (-1);
71246d1a925SRobert Watson 			}
71389ddbd45SDavid Malone 			nextnot = 1;
71489ddbd45SDavid Malone 			current += 1;
71546d1a925SRobert Watson 		} else {
716df6a67d6SEnji Cooper 			snprintf(errstr, buflen, "'%s' not expected",
71746d1a925SRobert Watson 			    argv[current]);
71846d1a925SRobert Watson 			return (-1);
71946d1a925SRobert Watson 		}
72046d1a925SRobert Watson 	}
72146d1a925SRobert Watson 
72289ddbd45SDavid Malone 	subject->mbs_flags = flags;
72346d1a925SRobert Watson 	if (not_seen)
72489ddbd45SDavid Malone 		subject->mbs_neg = MBS_ALL_FLAGS ^ neg;
72589ddbd45SDavid Malone 	else
72689ddbd45SDavid Malone 		subject->mbs_neg = neg;
72789ddbd45SDavid Malone 	if (flags & MBS_UID_DEFINED) {
72889ddbd45SDavid Malone 		subject->mbs_uid_min = uid_min;
72989ddbd45SDavid Malone 		subject->mbs_uid_max = uid_max;
73089ddbd45SDavid Malone 	}
73189ddbd45SDavid Malone 	if (flags & MBS_GID_DEFINED) {
73289ddbd45SDavid Malone 		subject->mbs_gid_min = gid_min;
73389ddbd45SDavid Malone 		subject->mbs_gid_max = gid_max;
73489ddbd45SDavid Malone 	}
73589ddbd45SDavid Malone 	if (flags & MBS_PRISON_DEFINED)
73689ddbd45SDavid Malone 		subject->mbs_prison = jid;
73746d1a925SRobert Watson 
73889ddbd45SDavid Malone 	return (0);
73989ddbd45SDavid Malone }
74046d1a925SRobert Watson 
741bf417062SMarcelo Araujo static int
bsde_parse_type(char * spec,int * type,size_t buflen,char * errstr)74289ddbd45SDavid Malone bsde_parse_type(char *spec, int *type, size_t buflen, char *errstr)
74389ddbd45SDavid Malone {
74489ddbd45SDavid Malone 	int i;
74589ddbd45SDavid Malone 
74689ddbd45SDavid Malone 	*type = 0;
74789ddbd45SDavid Malone 	for (i = 0; i < strlen(spec); i++) {
74889ddbd45SDavid Malone 		switch (spec[i]) {
74989ddbd45SDavid Malone 		case 'r':
75089ddbd45SDavid Malone 		case '-':
75189ddbd45SDavid Malone 			*type |= MBO_TYPE_REG;
75289ddbd45SDavid Malone 			break;
75389ddbd45SDavid Malone 		case 'd':
75489ddbd45SDavid Malone 			*type |= MBO_TYPE_DIR;
75589ddbd45SDavid Malone 			break;
75689ddbd45SDavid Malone 		case 'b':
75789ddbd45SDavid Malone 			*type |= MBO_TYPE_BLK;
75889ddbd45SDavid Malone 			break;
75989ddbd45SDavid Malone 		case 'c':
76089ddbd45SDavid Malone 			*type |= MBO_TYPE_CHR;
76189ddbd45SDavid Malone 			break;
76289ddbd45SDavid Malone 		case 'l':
76389ddbd45SDavid Malone 			*type |= MBO_TYPE_LNK;
76489ddbd45SDavid Malone 			break;
76589ddbd45SDavid Malone 		case 's':
76689ddbd45SDavid Malone 			*type |= MBO_TYPE_SOCK;
76789ddbd45SDavid Malone 			break;
76889ddbd45SDavid Malone 		case 'p':
76989ddbd45SDavid Malone 			*type |= MBO_TYPE_FIFO;
77089ddbd45SDavid Malone 			break;
77189ddbd45SDavid Malone 		case 'a':
77289ddbd45SDavid Malone 			*type |= MBO_ALL_TYPE;
77389ddbd45SDavid Malone 			break;
77489ddbd45SDavid Malone 		default:
775df6a67d6SEnji Cooper 			snprintf(errstr, buflen, "Unknown type code: %c",
77689ddbd45SDavid Malone 			    spec[i]);
77789ddbd45SDavid Malone 			return (-1);
77889ddbd45SDavid Malone 		}
77989ddbd45SDavid Malone 	}
78089ddbd45SDavid Malone 
78189ddbd45SDavid Malone 	return (0);
78289ddbd45SDavid Malone }
78389ddbd45SDavid Malone 
784bf417062SMarcelo Araujo static int
bsde_parse_fsid(char * spec,struct fsid * fsid,size_t buflen,char * errstr)78589ddbd45SDavid Malone bsde_parse_fsid(char *spec, struct fsid *fsid, size_t buflen, char *errstr)
78689ddbd45SDavid Malone {
78789ddbd45SDavid Malone 	struct statfs buf;
78889ddbd45SDavid Malone 
78989ddbd45SDavid Malone 	if (statfs(spec, &buf) < 0) {
790df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "Unable to get id for %s: %s",
79189ddbd45SDavid Malone 		    spec, strerror(errno));
79289ddbd45SDavid Malone 		return (-1);
79389ddbd45SDavid Malone 	}
79489ddbd45SDavid Malone 
79589ddbd45SDavid Malone 	*fsid = buf.f_fsid;
79689ddbd45SDavid Malone 
79789ddbd45SDavid Malone 	return (0);
79889ddbd45SDavid Malone }
79989ddbd45SDavid Malone 
800bf417062SMarcelo Araujo static int
bsde_parse_object(int argc,char * argv[],struct mac_bsdextended_object * object,size_t buflen,char * errstr)80189ddbd45SDavid Malone bsde_parse_object(int argc, char *argv[],
80289ddbd45SDavid Malone     struct mac_bsdextended_object *object, size_t buflen, char *errstr)
80389ddbd45SDavid Malone {
80489ddbd45SDavid Malone 	int not_seen, flags;
80589ddbd45SDavid Malone 	int current, neg, nextnot;
806bf417062SMarcelo Araujo 	int type;
80789ddbd45SDavid Malone 	uid_t uid_min, uid_max;
80889ddbd45SDavid Malone 	gid_t gid_min, gid_max;
80989ddbd45SDavid Malone 	struct fsid fsid;
81089ddbd45SDavid Malone 
81189ddbd45SDavid Malone 	current = 0;
81289ddbd45SDavid Malone 	flags = 0;
81389ddbd45SDavid Malone 	neg = 0;
81489ddbd45SDavid Malone 	nextnot = 0;
815bf417062SMarcelo Araujo 	type = 0;
81689ddbd45SDavid Malone 
81789ddbd45SDavid Malone 	if (strcmp("not", argv[current]) == 0) {
81889ddbd45SDavid Malone 		not_seen = 1;
81989ddbd45SDavid Malone 		current++;
82046d1a925SRobert Watson 	} else
82189ddbd45SDavid Malone 		not_seen = 0;
82289ddbd45SDavid Malone 
82389ddbd45SDavid Malone 	while (current < argc) {
82489ddbd45SDavid Malone 		if (strcmp(argv[current], "uid") == 0) {
82589ddbd45SDavid Malone 			if (current + 2 > argc) {
826df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "uid short");
82789ddbd45SDavid Malone 				return (-1);
82889ddbd45SDavid Malone 			}
82989ddbd45SDavid Malone 			if (flags & MBO_UID_DEFINED) {
830df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "one uid only");
83189ddbd45SDavid Malone 				return (-1);
83289ddbd45SDavid Malone 			}
83389ddbd45SDavid Malone 			if (bsde_parse_uidrange(argv[current+1],
83489ddbd45SDavid Malone 			    &uid_min, &uid_max, buflen, errstr) < 0)
83589ddbd45SDavid Malone 				return (-1);
83689ddbd45SDavid Malone 			flags |= MBO_UID_DEFINED;
83789ddbd45SDavid Malone 			if (nextnot) {
83889ddbd45SDavid Malone 				neg ^= MBO_UID_DEFINED;
83989ddbd45SDavid Malone 				nextnot = 0;
84089ddbd45SDavid Malone 			}
84189ddbd45SDavid Malone 			current += 2;
84289ddbd45SDavid Malone 		} else if (strcmp(argv[current], "gid") == 0) {
84389ddbd45SDavid Malone 			if (current + 2 > argc) {
844df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "gid short");
84589ddbd45SDavid Malone 				return (-1);
84689ddbd45SDavid Malone 			}
84789ddbd45SDavid Malone 			if (flags & MBO_GID_DEFINED) {
848df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "one gid only");
84989ddbd45SDavid Malone 				return (-1);
85089ddbd45SDavid Malone 			}
85189ddbd45SDavid Malone 			if (bsde_parse_gidrange(argv[current+1],
85289ddbd45SDavid Malone 			    &gid_min, &gid_max, buflen, errstr) < 0)
85389ddbd45SDavid Malone 				return (-1);
85489ddbd45SDavid Malone 			flags |= MBO_GID_DEFINED;
85589ddbd45SDavid Malone 			if (nextnot) {
85689ddbd45SDavid Malone 				neg ^= MBO_GID_DEFINED;
85789ddbd45SDavid Malone 				nextnot = 0;
85889ddbd45SDavid Malone 			}
85989ddbd45SDavid Malone 			current += 2;
86089ddbd45SDavid Malone 		} else if (strcmp(argv[current], "filesys") == 0) {
86189ddbd45SDavid Malone 			if (current + 2 > argc) {
862df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "filesys short");
86389ddbd45SDavid Malone 				return (-1);
86489ddbd45SDavid Malone 			}
86589ddbd45SDavid Malone 			if (flags & MBO_FSID_DEFINED) {
866df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "one fsid only");
86789ddbd45SDavid Malone 				return (-1);
86889ddbd45SDavid Malone 			}
86989ddbd45SDavid Malone 			if (bsde_parse_fsid(argv[current+1], &fsid,
87089ddbd45SDavid Malone 			    buflen, errstr) < 0)
87189ddbd45SDavid Malone 				return (-1);
87289ddbd45SDavid Malone 			flags |= MBO_FSID_DEFINED;
87389ddbd45SDavid Malone 			if (nextnot) {
87489ddbd45SDavid Malone 				neg ^= MBO_FSID_DEFINED;
87589ddbd45SDavid Malone 				nextnot = 0;
87689ddbd45SDavid Malone 			}
87789ddbd45SDavid Malone 			current += 2;
87889ddbd45SDavid Malone 		} else if (strcmp(argv[current], "suid") == 0) {
87989ddbd45SDavid Malone 			flags |= MBO_SUID;
88089ddbd45SDavid Malone 			if (nextnot) {
88189ddbd45SDavid Malone 				neg ^= MBO_SUID;
88289ddbd45SDavid Malone 				nextnot = 0;
88389ddbd45SDavid Malone 			}
88489ddbd45SDavid Malone 			current += 1;
88589ddbd45SDavid Malone 		} else if (strcmp(argv[current], "sgid") == 0) {
88689ddbd45SDavid Malone 			flags |= MBO_SGID;
88789ddbd45SDavid Malone 			if (nextnot) {
88889ddbd45SDavid Malone 				neg ^= MBO_SGID;
88989ddbd45SDavid Malone 				nextnot = 0;
89089ddbd45SDavid Malone 			}
89189ddbd45SDavid Malone 			current += 1;
89289ddbd45SDavid Malone 		} else if (strcmp(argv[current], "uid_of_subject") == 0) {
89389ddbd45SDavid Malone 			flags |= MBO_UID_SUBJECT;
89489ddbd45SDavid Malone 			if (nextnot) {
89589ddbd45SDavid Malone 				neg ^= MBO_UID_SUBJECT;
89689ddbd45SDavid Malone 				nextnot = 0;
89789ddbd45SDavid Malone 			}
89889ddbd45SDavid Malone 			current += 1;
89989ddbd45SDavid Malone 		} else if (strcmp(argv[current], "gid_of_subject") == 0) {
90089ddbd45SDavid Malone 			flags |= MBO_GID_SUBJECT;
90189ddbd45SDavid Malone 			if (nextnot) {
90289ddbd45SDavid Malone 				neg ^= MBO_GID_SUBJECT;
90389ddbd45SDavid Malone 				nextnot = 0;
90489ddbd45SDavid Malone 			}
90589ddbd45SDavid Malone 			current += 1;
90689ddbd45SDavid Malone 		} else if (strcmp(argv[current], "type") == 0) {
90789ddbd45SDavid Malone 			if (current + 2 > argc) {
908df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "type short");
90989ddbd45SDavid Malone 				return (-1);
91089ddbd45SDavid Malone 			}
91189ddbd45SDavid Malone 			if (flags & MBO_TYPE_DEFINED) {
912df6a67d6SEnji Cooper 				snprintf(errstr, buflen, "one type only");
91389ddbd45SDavid Malone 				return (-1);
91489ddbd45SDavid Malone 			}
91589ddbd45SDavid Malone 			if (bsde_parse_type(argv[current+1], &type,
91689ddbd45SDavid Malone 			    buflen, errstr) < 0)
91789ddbd45SDavid Malone 				return (-1);
91889ddbd45SDavid Malone 			flags |= MBO_TYPE_DEFINED;
91989ddbd45SDavid Malone 			if (nextnot) {
92089ddbd45SDavid Malone 				neg ^= MBO_TYPE_DEFINED;
92189ddbd45SDavid Malone 				nextnot = 0;
92289ddbd45SDavid Malone 			}
92389ddbd45SDavid Malone 			current += 2;
92489ddbd45SDavid Malone 		} else if (strcmp(argv[current], "!") == 0) {
92589ddbd45SDavid Malone 			if (nextnot) {
926df6a67d6SEnji Cooper 				snprintf(errstr, buflen,
92789ddbd45SDavid Malone 				    "double negative'");
92889ddbd45SDavid Malone 				return (-1);
92989ddbd45SDavid Malone 			}
93089ddbd45SDavid Malone 			nextnot = 1;
93189ddbd45SDavid Malone 			current += 1;
93289ddbd45SDavid Malone 		} else {
933df6a67d6SEnji Cooper 			snprintf(errstr, buflen, "'%s' not expected",
93489ddbd45SDavid Malone 			    argv[current]);
93589ddbd45SDavid Malone 			return (-1);
93689ddbd45SDavid Malone 		}
93789ddbd45SDavid Malone 	}
93889ddbd45SDavid Malone 
93989ddbd45SDavid Malone 	object->mbo_flags = flags;
94089ddbd45SDavid Malone 	if (not_seen)
94189ddbd45SDavid Malone 		object->mbo_neg = MBO_ALL_FLAGS ^ neg;
94289ddbd45SDavid Malone 	else
94389ddbd45SDavid Malone 		object->mbo_neg = neg;
94489ddbd45SDavid Malone 	if (flags & MBO_UID_DEFINED) {
94589ddbd45SDavid Malone 		object->mbo_uid_min = uid_min;
94689ddbd45SDavid Malone 		object->mbo_uid_max = uid_max;
94789ddbd45SDavid Malone 	}
94889ddbd45SDavid Malone 	if (flags & MBO_GID_DEFINED) {
94989ddbd45SDavid Malone 		object->mbo_gid_min = gid_min;
95089ddbd45SDavid Malone 		object->mbo_gid_max = gid_max;
95189ddbd45SDavid Malone 	}
95289ddbd45SDavid Malone 	if (flags & MBO_FSID_DEFINED)
95389ddbd45SDavid Malone 		object->mbo_fsid = fsid;
95489ddbd45SDavid Malone 	if (flags & MBO_TYPE_DEFINED)
95589ddbd45SDavid Malone 		object->mbo_type = type;
95646d1a925SRobert Watson 
95746d1a925SRobert Watson 	return (0);
95846d1a925SRobert Watson }
95946d1a925SRobert Watson 
96046d1a925SRobert Watson int
bsde_parse_mode(int argc,char * argv[],mode_t * mode,size_t buflen,char * errstr)96146d1a925SRobert Watson bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
96246d1a925SRobert Watson     char *errstr)
96346d1a925SRobert Watson {
96446d1a925SRobert Watson 	int i;
96546d1a925SRobert Watson 
96646d1a925SRobert Watson 	if (argc == 0) {
967df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "mode expects mode value");
96846d1a925SRobert Watson 		return (-1);
96946d1a925SRobert Watson 	}
97046d1a925SRobert Watson 
97146d1a925SRobert Watson 	if (argc != 1) {
972df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
97346d1a925SRobert Watson 		return (-1);
97446d1a925SRobert Watson 	}
97546d1a925SRobert Watson 
97646d1a925SRobert Watson 	*mode = 0;
97746d1a925SRobert Watson 	for (i = 0; i < strlen(argv[0]); i++) {
97846d1a925SRobert Watson 		switch (argv[0][i]) {
97946d1a925SRobert Watson 		case 'a':
980f4194603SRobert Watson 			*mode |= MBI_ADMIN;
98146d1a925SRobert Watson 			break;
98246d1a925SRobert Watson 		case 'r':
983f4194603SRobert Watson 			*mode |= MBI_READ;
98446d1a925SRobert Watson 			break;
98546d1a925SRobert Watson 		case 's':
986f4194603SRobert Watson 			*mode |= MBI_STAT;
98746d1a925SRobert Watson 			break;
98846d1a925SRobert Watson 		case 'w':
989f4194603SRobert Watson 			*mode |= MBI_WRITE;
99046d1a925SRobert Watson 			break;
99146d1a925SRobert Watson 		case 'x':
992f4194603SRobert Watson 			*mode |= MBI_EXEC;
99346d1a925SRobert Watson 			break;
99446d1a925SRobert Watson 		case 'n':
99546d1a925SRobert Watson 			/* ignore */
99646d1a925SRobert Watson 			break;
99746d1a925SRobert Watson 		default:
998df6a67d6SEnji Cooper 			snprintf(errstr, buflen, "Unknown mode letter: %c",
99946d1a925SRobert Watson 			    argv[0][i]);
100046d1a925SRobert Watson 			return (-1);
100146d1a925SRobert Watson 		}
100246d1a925SRobert Watson 	}
100346d1a925SRobert Watson 
100446d1a925SRobert Watson 	return (0);
100546d1a925SRobert Watson }
100646d1a925SRobert Watson 
100746d1a925SRobert Watson int
bsde_parse_rule(int argc,char * argv[],struct mac_bsdextended_rule * rule,size_t buflen,char * errstr)100846d1a925SRobert Watson bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
100946d1a925SRobert Watson     size_t buflen, char *errstr)
101046d1a925SRobert Watson {
101146d1a925SRobert Watson 	int subject, subject_elements, subject_elements_length;
101246d1a925SRobert Watson 	int object, object_elements, object_elements_length;
101346d1a925SRobert Watson 	int mode, mode_elements, mode_elements_length;
101446d1a925SRobert Watson 	int error, i;
101546d1a925SRobert Watson 
101646d1a925SRobert Watson 	bzero(rule, sizeof(*rule));
101746d1a925SRobert Watson 
101846d1a925SRobert Watson 	if (argc < 1) {
1019df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "Rule must begin with subject");
102046d1a925SRobert Watson 		return (-1);
102146d1a925SRobert Watson 	}
102246d1a925SRobert Watson 
102346d1a925SRobert Watson 	if (strcmp(argv[0], "subject") != 0) {
1024df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "Rule must begin with subject");
102546d1a925SRobert Watson 		return (-1);
102646d1a925SRobert Watson 	}
102746d1a925SRobert Watson 	subject = 0;
102846d1a925SRobert Watson 	subject_elements = 1;
102946d1a925SRobert Watson 
103046d1a925SRobert Watson 	/* Search forward for object. */
103146d1a925SRobert Watson 
103246d1a925SRobert Watson 	object = -1;
103346d1a925SRobert Watson 	for (i = 1; i < argc; i++)
103446d1a925SRobert Watson 		if (strcmp(argv[i], "object") == 0)
103546d1a925SRobert Watson 			object = i;
103646d1a925SRobert Watson 
103746d1a925SRobert Watson 	if (object == -1) {
1038df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "Rule must contain an object");
103946d1a925SRobert Watson 		return (-1);
104046d1a925SRobert Watson 	}
104146d1a925SRobert Watson 
104246d1a925SRobert Watson 	/* Search forward for mode. */
104346d1a925SRobert Watson 	mode = -1;
104446d1a925SRobert Watson 	for (i = object; i < argc; i++)
104546d1a925SRobert Watson 		if (strcmp(argv[i], "mode") == 0)
104646d1a925SRobert Watson 			mode = i;
104746d1a925SRobert Watson 
104846d1a925SRobert Watson 	if (mode == -1) {
1049df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "Rule must contain mode");
105046d1a925SRobert Watson 		return (-1);
105146d1a925SRobert Watson 	}
105246d1a925SRobert Watson 
105346d1a925SRobert Watson 	subject_elements_length = object - subject - 1;
105446d1a925SRobert Watson 	object_elements = object + 1;
105546d1a925SRobert Watson 	object_elements_length = mode - object_elements;
105646d1a925SRobert Watson 	mode_elements = mode + 1;
105746d1a925SRobert Watson 	mode_elements_length = argc - mode_elements;
105846d1a925SRobert Watson 
105989ddbd45SDavid Malone 	error = bsde_parse_subject(subject_elements_length,
106046d1a925SRobert Watson 	    argv + subject_elements, &rule->mbr_subject, buflen, errstr);
106146d1a925SRobert Watson 	if (error)
106246d1a925SRobert Watson 		return (-1);
106346d1a925SRobert Watson 
106489ddbd45SDavid Malone 	error = bsde_parse_object(object_elements_length,
106546d1a925SRobert Watson 	    argv + object_elements, &rule->mbr_object, buflen, errstr);
106646d1a925SRobert Watson 	if (error)
106746d1a925SRobert Watson 		return (-1);
106846d1a925SRobert Watson 
106946d1a925SRobert Watson 	error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
107046d1a925SRobert Watson 	    &rule->mbr_mode, buflen, errstr);
107146d1a925SRobert Watson 	if (error)
107246d1a925SRobert Watson 		return (-1);
107346d1a925SRobert Watson 
107446d1a925SRobert Watson 	return (0);
107546d1a925SRobert Watson }
107646d1a925SRobert Watson 
107746d1a925SRobert Watson int
bsde_parse_rule_string(const char * string,struct mac_bsdextended_rule * rule,size_t buflen,char * errstr)107846d1a925SRobert Watson bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
107946d1a925SRobert Watson     size_t buflen, char *errstr)
108046d1a925SRobert Watson {
108189ddbd45SDavid Malone 	char *stringdup, *stringp, *argv[100], **ap;
108246d1a925SRobert Watson 	int argc, error;
108346d1a925SRobert Watson 
108446d1a925SRobert Watson 	stringp = stringdup = strdup(string);
108546d1a925SRobert Watson 	while (*stringp == ' ' || *stringp == '\t')
108646d1a925SRobert Watson 		stringp++;
108746d1a925SRobert Watson 
108846d1a925SRobert Watson 	argc = 0;
108946d1a925SRobert Watson 	for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
109046d1a925SRobert Watson 		argc++;
109146d1a925SRobert Watson 		if (**ap != '\0')
109289ddbd45SDavid Malone 			if (++ap >= &argv[100])
109346d1a925SRobert Watson 				break;
109446d1a925SRobert Watson 	}
109546d1a925SRobert Watson 
109646d1a925SRobert Watson 	error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
109746d1a925SRobert Watson 
109846d1a925SRobert Watson 	free(stringdup);
109946d1a925SRobert Watson 
110046d1a925SRobert Watson 	return (error);
110146d1a925SRobert Watson }
110246d1a925SRobert Watson 
110346d1a925SRobert Watson int
bsde_get_mib(const char * string,int * name,size_t * namelen)1104da30581eSRobert Watson bsde_get_mib(const char *string, int *name, size_t *namelen)
110546d1a925SRobert Watson {
1106da30581eSRobert Watson 	size_t len;
1107da30581eSRobert Watson 	int error;
110846d1a925SRobert Watson 
110946d1a925SRobert Watson 	len = *namelen;
111046d1a925SRobert Watson 	error = sysctlnametomib(string, name, &len);
111146d1a925SRobert Watson 	if (error)
111246d1a925SRobert Watson 		return (error);
111346d1a925SRobert Watson 
111446d1a925SRobert Watson 	*namelen = len;
111546d1a925SRobert Watson 	return (0);
111646d1a925SRobert Watson }
111746d1a925SRobert Watson 
1118bf417062SMarcelo Araujo static int
bsde_check_version(size_t buflen,char * errstr)111989ddbd45SDavid Malone bsde_check_version(size_t buflen, char *errstr)
112089ddbd45SDavid Malone {
112189ddbd45SDavid Malone 	size_t len;
112289ddbd45SDavid Malone 	int error;
112389ddbd45SDavid Malone 	int version;
112489ddbd45SDavid Malone 
112589ddbd45SDavid Malone 	len = sizeof(version);
112689ddbd45SDavid Malone 	error = sysctlbyname(MIB ".rule_version", &version, &len, NULL, 0);
112789ddbd45SDavid Malone 	if (error) {
1128df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "version check failed: %s",
112989ddbd45SDavid Malone 		    strerror(errno));
113089ddbd45SDavid Malone 		return (-1);
113189ddbd45SDavid Malone 	}
113289ddbd45SDavid Malone 	if (version != MB_VERSION) {
1133df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "module v%d != library v%d",
113489ddbd45SDavid Malone 		    version, MB_VERSION);
113589ddbd45SDavid Malone 		return (-1);
113689ddbd45SDavid Malone 	}
113789ddbd45SDavid Malone 	return (0);
113889ddbd45SDavid Malone }
113989ddbd45SDavid Malone 
114089ddbd45SDavid Malone int
bsde_get_rule_count(size_t buflen,char * errstr)114146d1a925SRobert Watson bsde_get_rule_count(size_t buflen, char *errstr)
114246d1a925SRobert Watson {
114346d1a925SRobert Watson 	size_t len;
114446d1a925SRobert Watson 	int error;
114546d1a925SRobert Watson 	int rule_count;
114646d1a925SRobert Watson 
114746d1a925SRobert Watson 	len = sizeof(rule_count);
11480f9a2306SBruce Evans 	error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0);
114946d1a925SRobert Watson 	if (error) {
1150df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "%s", strerror(errno));
115146d1a925SRobert Watson 		return (-1);
115246d1a925SRobert Watson 	}
115346d1a925SRobert Watson 	if (len != sizeof(rule_count)) {
1154df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "Data error in %s.rule_count",
115546d1a925SRobert Watson 		    MIB);
115646d1a925SRobert Watson 		return (-1);
115746d1a925SRobert Watson 	}
115846d1a925SRobert Watson 
115946d1a925SRobert Watson 	return (rule_count);
116046d1a925SRobert Watson }
116146d1a925SRobert Watson 
116246d1a925SRobert Watson int
bsde_get_rule_slots(size_t buflen,char * errstr)116346d1a925SRobert Watson bsde_get_rule_slots(size_t buflen, char *errstr)
116446d1a925SRobert Watson {
116546d1a925SRobert Watson 	size_t len;
116646d1a925SRobert Watson 	int error;
116746d1a925SRobert Watson 	int rule_slots;
116846d1a925SRobert Watson 
116946d1a925SRobert Watson 	len = sizeof(rule_slots);
11700f9a2306SBruce Evans 	error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0);
117146d1a925SRobert Watson 	if (error) {
1172df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "%s", strerror(errno));
117346d1a925SRobert Watson 		return (-1);
117446d1a925SRobert Watson 	}
117546d1a925SRobert Watson 	if (len != sizeof(rule_slots)) {
1176df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "Data error in %s.rule_slots", MIB);
117746d1a925SRobert Watson 		return (-1);
117846d1a925SRobert Watson 	}
117946d1a925SRobert Watson 
118046d1a925SRobert Watson 	return (rule_slots);
118146d1a925SRobert Watson }
118246d1a925SRobert Watson 
118346d1a925SRobert Watson /*
118446d1a925SRobert Watson  * Returns 0 for success;
118546d1a925SRobert Watson  * Returns -1 for failure;
118646d1a925SRobert Watson  * Returns -2 for not present
118746d1a925SRobert Watson  */
118846d1a925SRobert Watson int
bsde_get_rule(int rulenum,struct mac_bsdextended_rule * rule,size_t errlen,char * errstr)118946d1a925SRobert Watson bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
119046d1a925SRobert Watson     char *errstr)
119146d1a925SRobert Watson {
119246d1a925SRobert Watson 	int name[10];
119346d1a925SRobert Watson 	size_t len, size;
119446d1a925SRobert Watson 	int error;
119546d1a925SRobert Watson 
119689ddbd45SDavid Malone 	if (bsde_check_version(errlen, errstr) != 0)
119789ddbd45SDavid Malone 		return (-1);
119889ddbd45SDavid Malone 
119946d1a925SRobert Watson 	len = 10;
120046d1a925SRobert Watson 	error = bsde_get_mib(MIB ".rules", name, &len);
120146d1a925SRobert Watson 	if (error) {
1202df6a67d6SEnji Cooper 		snprintf(errstr, errlen, "%s: %s", MIB ".rules",
120346d1a925SRobert Watson 		    strerror(errno));
120446d1a925SRobert Watson 		return (-1);
120546d1a925SRobert Watson 	}
120646d1a925SRobert Watson 
120746d1a925SRobert Watson 	size = sizeof(*rule);
120846d1a925SRobert Watson 	name[len] = rulenum;
120946d1a925SRobert Watson 	len++;
121046d1a925SRobert Watson 	error = sysctl(name, len, rule, &size, NULL, 0);
121146d1a925SRobert Watson 	if (error  == -1 && errno == ENOENT)
121246d1a925SRobert Watson 		return (-2);
121346d1a925SRobert Watson 	if (error) {
1214df6a67d6SEnji Cooper 		snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
121546d1a925SRobert Watson 		    rulenum, strerror(errno));
121646d1a925SRobert Watson 		return (-1);
121746d1a925SRobert Watson 	} else if (size != sizeof(*rule)) {
1218df6a67d6SEnji Cooper 		snprintf(errstr, errlen, "Data error in %s.%d: %s",
121946d1a925SRobert Watson 		    MIB ".rules", rulenum, strerror(errno));
122046d1a925SRobert Watson 		return (-1);
122146d1a925SRobert Watson 	}
122246d1a925SRobert Watson 
122346d1a925SRobert Watson 	return (0);
122446d1a925SRobert Watson }
122546d1a925SRobert Watson 
122646d1a925SRobert Watson int
bsde_delete_rule(int rulenum,size_t buflen,char * errstr)122746d1a925SRobert Watson bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
122846d1a925SRobert Watson {
122946d1a925SRobert Watson 	struct mac_bsdextended_rule rule;
123046d1a925SRobert Watson 	int name[10];
1231da1259f0SMarcelo Araujo 	size_t len;
123246d1a925SRobert Watson 	int error;
123346d1a925SRobert Watson 
123489ddbd45SDavid Malone 	if (bsde_check_version(buflen, errstr) != 0)
123589ddbd45SDavid Malone 		return (-1);
123689ddbd45SDavid Malone 
123746d1a925SRobert Watson 	len = 10;
123846d1a925SRobert Watson 	error = bsde_get_mib(MIB ".rules", name, &len);
123946d1a925SRobert Watson 	if (error) {
1240df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "%s: %s", MIB ".rules",
124146d1a925SRobert Watson 		    strerror(errno));
124246d1a925SRobert Watson 		return (-1);
124346d1a925SRobert Watson 	}
124446d1a925SRobert Watson 
124546d1a925SRobert Watson 	name[len] = rulenum;
124646d1a925SRobert Watson 	len++;
124746d1a925SRobert Watson 
124866157b38SBryan Drewery 	error = sysctl(name, len, NULL, NULL, &rule, 0);
124946d1a925SRobert Watson 	if (error) {
1250df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
125146d1a925SRobert Watson 		    rulenum, strerror(errno));
125246d1a925SRobert Watson 		return (-1);
125346d1a925SRobert Watson 	}
125446d1a925SRobert Watson 
125546d1a925SRobert Watson 	return (0);
125646d1a925SRobert Watson }
125746d1a925SRobert Watson 
125846d1a925SRobert Watson int
bsde_set_rule(int rulenum,struct mac_bsdextended_rule * rule,size_t buflen,char * errstr)125946d1a925SRobert Watson bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
126046d1a925SRobert Watson     char *errstr)
126146d1a925SRobert Watson {
126246d1a925SRobert Watson 	int name[10];
1263a7c4e991SMarcelo Araujo 	size_t len;
126446d1a925SRobert Watson 	int error;
126546d1a925SRobert Watson 
126689ddbd45SDavid Malone 	if (bsde_check_version(buflen, errstr) != 0)
126789ddbd45SDavid Malone 		return (-1);
126889ddbd45SDavid Malone 
126946d1a925SRobert Watson 	len = 10;
127046d1a925SRobert Watson 	error = bsde_get_mib(MIB ".rules", name, &len);
127146d1a925SRobert Watson 	if (error) {
1272df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "%s: %s", MIB ".rules",
127346d1a925SRobert Watson 		    strerror(errno));
127446d1a925SRobert Watson 		return (-1);
127546d1a925SRobert Watson 	}
127646d1a925SRobert Watson 
127746d1a925SRobert Watson 	name[len] = rulenum;
127846d1a925SRobert Watson 	len++;
127946d1a925SRobert Watson 
1280a7c4e991SMarcelo Araujo 	error = sysctl(name, len, NULL, NULL, rule, sizeof(*rule));
128146d1a925SRobert Watson 	if (error) {
1282df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
128346d1a925SRobert Watson 		    rulenum, strerror(errno));
128446d1a925SRobert Watson 		return (-1);
128546d1a925SRobert Watson 	}
128646d1a925SRobert Watson 
128746d1a925SRobert Watson 	return (0);
128846d1a925SRobert Watson }
128947ab23aaSRobert Watson 
129047ab23aaSRobert Watson int
bsde_add_rule(int * rulenum,struct mac_bsdextended_rule * rule,size_t buflen,char * errstr)129147ab23aaSRobert Watson bsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
129247ab23aaSRobert Watson     char *errstr)
129347ab23aaSRobert Watson {
129447ab23aaSRobert Watson 	char charstr[BUFSIZ];
129547ab23aaSRobert Watson 	int name[10];
1296a7c4e991SMarcelo Araujo 	size_t len;
129747ab23aaSRobert Watson 	int error, rule_slots;
129847ab23aaSRobert Watson 
129989ddbd45SDavid Malone 	if (bsde_check_version(buflen, errstr) != 0)
130089ddbd45SDavid Malone 		return (-1);
130189ddbd45SDavid Malone 
130247ab23aaSRobert Watson 	len = 10;
130347ab23aaSRobert Watson 	error = bsde_get_mib(MIB ".rules", name, &len);
130447ab23aaSRobert Watson 	if (error) {
1305df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "%s: %s", MIB ".rules",
130647ab23aaSRobert Watson 		    strerror(errno));
130747ab23aaSRobert Watson 		return (-1);
130847ab23aaSRobert Watson 	}
130947ab23aaSRobert Watson 
131047ab23aaSRobert Watson 	rule_slots = bsde_get_rule_slots(BUFSIZ, charstr);
131147ab23aaSRobert Watson 	if (rule_slots == -1) {
1312df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "unable to get rule slots: %s",
131347ab23aaSRobert Watson 		    strerror(errno));
131447ab23aaSRobert Watson 		return (-1);
131547ab23aaSRobert Watson 	}
131647ab23aaSRobert Watson 
131747ab23aaSRobert Watson 	name[len] = rule_slots;
131847ab23aaSRobert Watson 	len++;
131947ab23aaSRobert Watson 
1320a7c4e991SMarcelo Araujo 	error = sysctl(name, len, NULL, NULL, rule, sizeof(*rule));
132147ab23aaSRobert Watson 	if (error) {
1322df6a67d6SEnji Cooper 		snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
132347ab23aaSRobert Watson 		    rule_slots, strerror(errno));
132447ab23aaSRobert Watson 		return (-1);
132547ab23aaSRobert Watson 	}
132647ab23aaSRobert Watson 
132747ab23aaSRobert Watson 	if (rulenum != NULL)
1328fbc822aeSPawel Jakub Dawidek 		*rulenum = rule_slots;
132947ab23aaSRobert Watson 
133047ab23aaSRobert Watson 	return (0);
133147ab23aaSRobert Watson }
1332