2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2002-2005 Networks Associates Technology, Inc.
7 * This software was developed for the FreeBSD Project by Network Associates
8 * Laboratories, the Security Research Division of Network Associates, Inc.
9 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
10 * DARPA CHATS research program.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/param.h>
36 #include <sys/errno.h>
39 #include <sys/sysctl.h>
40 #include <sys/ucred.h>
42 #include <sys/mount.h>
44 #include <security/mac_bsdextended/mac_bsdextended.h>
55 * Text format for rules: rules contain subject and object elements, mode.
56 * The total form is "subject [s_element] object [o_element] mode [mode]".
57 * At least * one of a uid or gid entry must be present; both may also be
61 #define MIB "security.mac.bsdextended"
64 bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
68 struct statfs *mntbuf;
69 char *cur, type[sizeof(rule->mbr_object.mbo_type) * CHAR_BIT + 1];
71 int anymode, unknownmode, numfs, i, notdone;
76 len = snprintf(cur, left, "subject ");
77 if (len < 0 || len > left)
81 if (rule->mbr_subject.mbs_flags) {
82 if (rule->mbr_subject.mbs_neg == MBS_ALL_FLAGS) {
83 len = snprintf(cur, left, "not ");
84 if (len < 0 || len > left)
93 if (!notdone && (rule->mbr_subject.mbs_neg & MBO_UID_DEFINED)) {
94 len = snprintf(cur, left, "! ");
95 if (len < 0 || len > left)
100 if (rule->mbr_subject.mbs_flags & MBO_UID_DEFINED) {
101 pwd = getpwuid(rule->mbr_subject.mbs_uid_min);
103 len = snprintf(cur, left, "uid %s",
105 if (len < 0 || len > left)
110 len = snprintf(cur, left, "uid %u",
111 rule->mbr_subject.mbs_uid_min);
112 if (len < 0 || len > left)
117 if (rule->mbr_subject.mbs_uid_min !=
118 rule->mbr_subject.mbs_uid_max) {
119 pwd = getpwuid(rule->mbr_subject.mbs_uid_max);
121 len = snprintf(cur, left, ":%s ",
123 if (len < 0 || len > left)
128 len = snprintf(cur, left, ":%u ",
129 rule->mbr_subject.mbs_uid_max);
130 if (len < 0 || len > left)
136 len = snprintf(cur, left, " ");
137 if (len < 0 || len > left)
143 if (!notdone && (rule->mbr_subject.mbs_neg & MBO_GID_DEFINED)) {
144 len = snprintf(cur, left, "! ");
145 if (len < 0 || len > left)
150 if (rule->mbr_subject.mbs_flags & MBO_GID_DEFINED) {
151 grp = getgrgid(rule->mbr_subject.mbs_gid_min);
153 len = snprintf(cur, left, "gid %s",
155 if (len < 0 || len > left)
160 len = snprintf(cur, left, "gid %u",
161 rule->mbr_subject.mbs_gid_min);
162 if (len < 0 || len > left)
167 if (rule->mbr_subject.mbs_gid_min !=
168 rule->mbr_subject.mbs_gid_max) {
169 grp = getgrgid(rule->mbr_subject.mbs_gid_max);
171 len = snprintf(cur, left, ":%s ",
173 if (len < 0 || len > left)
178 len = snprintf(cur, left, ":%u ",
179 rule->mbr_subject.mbs_gid_max);
180 if (len < 0 || len > left)
186 len = snprintf(cur, left, " ");
187 if (len < 0 || len > left)
193 if (!notdone && (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)) {
194 len = snprintf(cur, left, "! ");
195 if (len < 0 || len > left)
200 if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
201 len = snprintf(cur, left, "jailid %d ",
202 rule->mbr_subject.mbs_prison);
203 if (len < 0 || len > left)
210 len = snprintf(cur, left, "object ");
211 if (len < 0 || len > left)
215 if (rule->mbr_object.mbo_flags) {
216 if (rule->mbr_object.mbo_neg == MBO_ALL_FLAGS) {
217 len = snprintf(cur, left, "not ");
218 if (len < 0 || len > left)
227 if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)) {
228 len = snprintf(cur, left, "! ");
229 if (len < 0 || len > left)
234 if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
235 pwd = getpwuid(rule->mbr_object.mbo_uid_min);
237 len = snprintf(cur, left, "uid %s",
239 if (len < 0 || len > left)
244 len = snprintf(cur, left, "uid %u",
245 rule->mbr_object.mbo_uid_min);
246 if (len < 0 || len > left)
251 if (rule->mbr_object.mbo_uid_min !=
252 rule->mbr_object.mbo_uid_max) {
253 pwd = getpwuid(rule->mbr_object.mbo_uid_max);
255 len = snprintf(cur, left, ":%s ",
257 if (len < 0 || len > left)
262 len = snprintf(cur, left, ":%u ",
263 rule->mbr_object.mbo_uid_max);
264 if (len < 0 || len > left)
270 len = snprintf(cur, left, " ");
271 if (len < 0 || len > left)
277 if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)) {
278 len = snprintf(cur, left, "! ");
279 if (len < 0 || len > left)
284 if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
285 grp = getgrgid(rule->mbr_object.mbo_gid_min);
287 len = snprintf(cur, left, "gid %s",
289 if (len < 0 || len > left)
294 len = snprintf(cur, left, "gid %u",
295 rule->mbr_object.mbo_gid_min);
296 if (len < 0 || len > left)
301 if (rule->mbr_object.mbo_gid_min !=
302 rule->mbr_object.mbo_gid_max) {
303 grp = getgrgid(rule->mbr_object.mbo_gid_max);
305 len = snprintf(cur, left, ":%s ",
307 if (len < 0 || len > left)
312 len = snprintf(cur, left, ":%u ",
313 rule->mbr_object.mbo_gid_max);
314 if (len < 0 || len > left)
320 len = snprintf(cur, left, " ");
321 if (len < 0 || len > left)
327 if (!notdone && (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)) {
328 len = snprintf(cur, left, "! ");
329 if (len < 0 || len > left)
334 if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
335 numfs = getmntinfo(&mntbuf, MNT_NOWAIT);
336 for (i = 0; i < numfs; i++)
337 if (fsidcmp(&rule->mbr_object.mbo_fsid,
338 &mntbuf[i].f_fsid) == 0)
340 len = snprintf(cur, left, "filesys %s ",
341 i == numfs ? "???" : mntbuf[i].f_mntonname);
342 if (len < 0 || len > left)
347 if (!notdone && (rule->mbr_object.mbo_neg & MBO_SUID)) {
348 len = snprintf(cur, left, "! ");
349 if (len < 0 || len > left)
354 if (rule->mbr_object.mbo_flags & MBO_SUID) {
355 len = snprintf(cur, left, "suid ");
356 if (len < 0 || len > left)
361 if (!notdone && (rule->mbr_object.mbo_neg & MBO_SGID)) {
362 len = snprintf(cur, left, "! ");
363 if (len < 0 || len > left)
368 if (rule->mbr_object.mbo_flags & MBO_SGID) {
369 len = snprintf(cur, left, "sgid ");
370 if (len < 0 || len > left)
375 if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)) {
376 len = snprintf(cur, left, "! ");
377 if (len < 0 || len > left)
382 if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
383 len = snprintf(cur, left, "uid_of_subject ");
384 if (len < 0 || len > left)
389 if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)) {
390 len = snprintf(cur, left, "! ");
391 if (len < 0 || len > left)
396 if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
397 len = snprintf(cur, left, "gid_of_subject ");
398 if (len < 0 || len > left)
403 if (!notdone && (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)) {
404 len = snprintf(cur, left, "! ");
405 if (len < 0 || len > left)
410 if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
412 if (rule->mbr_object.mbo_type & MBO_TYPE_REG)
414 if (rule->mbr_object.mbo_type & MBO_TYPE_DIR)
416 if (rule->mbr_object.mbo_type & MBO_TYPE_BLK)
418 if (rule->mbr_object.mbo_type & MBO_TYPE_CHR)
420 if (rule->mbr_object.mbo_type & MBO_TYPE_LNK)
422 if (rule->mbr_object.mbo_type & MBO_TYPE_SOCK)
424 if (rule->mbr_object.mbo_type & MBO_TYPE_FIFO)
426 if (rule->mbr_object.mbo_type == MBO_ALL_TYPE) {
431 len = snprintf(cur, left, "type %s ", type);
432 if (len < 0 || len > left)
439 len = snprintf(cur, left, "mode ");
440 if (len < 0 || len > left)
445 anymode = (rule->mbr_mode & MBI_ALLPERM);
446 unknownmode = (rule->mbr_mode & ~MBI_ALLPERM);
448 if (rule->mbr_mode & MBI_ADMIN) {
449 len = snprintf(cur, left, "a");
450 if (len < 0 || len > left)
456 if (rule->mbr_mode & MBI_READ) {
457 len = snprintf(cur, left, "r");
458 if (len < 0 || len > left)
464 if (rule->mbr_mode & MBI_STAT) {
465 len = snprintf(cur, left, "s");
466 if (len < 0 || len > left)
472 if (rule->mbr_mode & MBI_WRITE) {
473 len = snprintf(cur, left, "w");
474 if (len < 0 || len > left)
480 if (rule->mbr_mode & MBI_EXEC) {
481 len = snprintf(cur, left, "x");
482 if (len < 0 || len > left)
489 len = snprintf(cur, left, "n");
490 if (len < 0 || len > left)
497 len = snprintf(cur, left, "?");
498 if (len < 0 || len > left)
512 bsde_parse_uidrange(char *spec, uid_t *min, uid_t *max,
513 size_t buflen, char *errstr){
516 char *spec1, *spec2, *endp;
520 spec1 = strsep(&spec2, ":");
522 pwd = getpwnam(spec1);
526 value = strtoul(spec1, &endp, 10);
528 snprintf(errstr, buflen, "invalid uid: '%s'", spec1);
539 pwd = getpwnam(spec2);
543 value = strtoul(spec2, &endp, 10);
545 snprintf(errstr, buflen, "invalid uid: '%s'", spec2);
558 bsde_parse_gidrange(char *spec, gid_t *min, gid_t *max,
559 size_t buflen, char *errstr){
562 char *spec1, *spec2, *endp;
566 spec1 = strsep(&spec2, ":");
568 grp = getgrnam(spec1);
572 value = strtoul(spec1, &endp, 10);
574 snprintf(errstr, buflen, "invalid gid: '%s'", spec1);
585 grp = getgrnam(spec2);
589 value = strtoul(spec2, &endp, 10);
591 snprintf(errstr, buflen, "invalid gid: '%s'", spec2);
604 bsde_get_jailid(const char *name, size_t buflen, char *errstr)
608 struct iovec jiov[4];
610 /* Copy jail_getid(3) instead of messing with library dependancies */
611 jid = strtoul(name, &ep, 10);
614 jiov[0].iov_base = __DECONST(char *, "name");
615 jiov[0].iov_len = sizeof("name");
616 jiov[1].iov_len = strlen(name) + 1;
617 jiov[1].iov_base = alloca(jiov[1].iov_len);
618 strcpy(jiov[1].iov_base, name);
619 if (errstr && buflen) {
620 jiov[2].iov_base = __DECONST(char *, "errmsg");
621 jiov[2].iov_len = sizeof("errmsg");
622 jiov[3].iov_base = errstr;
623 jiov[3].iov_len = buflen;
625 jid = jail_get(jiov, 4, 0);
626 if (jid < 0 && !errstr[0])
627 snprintf(errstr, buflen, "jail_get: %s",
630 jid = jail_get(jiov, 2, 0);
635 bsde_parse_subject(int argc, char *argv[],
636 struct mac_bsdextended_subject *subject, size_t buflen, char *errstr)
639 int current, neg, nextnot;
640 uid_t uid_min, uid_max;
641 gid_t gid_min, gid_max;
649 if (strcmp("not", argv[current]) == 0) {
655 while (current < argc) {
656 if (strcmp(argv[current], "uid") == 0) {
657 if (current + 2 > argc) {
658 snprintf(errstr, buflen, "uid short");
661 if (flags & MBS_UID_DEFINED) {
662 snprintf(errstr, buflen, "one uid only");
665 if (bsde_parse_uidrange(argv[current+1],
666 &uid_min, &uid_max, buflen, errstr) < 0)
668 flags |= MBS_UID_DEFINED;
670 neg ^= MBS_UID_DEFINED;
674 } else if (strcmp(argv[current], "gid") == 0) {
675 if (current + 2 > argc) {
676 snprintf(errstr, buflen, "gid short");
679 if (flags & MBS_GID_DEFINED) {
680 snprintf(errstr, buflen, "one gid only");
683 if (bsde_parse_gidrange(argv[current+1],
684 &gid_min, &gid_max, buflen, errstr) < 0)
686 flags |= MBS_GID_DEFINED;
688 neg ^= MBS_GID_DEFINED;
692 } else if (strcmp(argv[current], "jailid") == 0) {
693 if (current + 2 > argc) {
694 snprintf(errstr, buflen, "prison short");
697 if (flags & MBS_PRISON_DEFINED) {
698 snprintf(errstr, buflen, "one jail only");
701 jid = bsde_get_jailid(argv[current+1], buflen, errstr);
704 flags |= MBS_PRISON_DEFINED;
706 neg ^= MBS_PRISON_DEFINED;
710 } else if (strcmp(argv[current], "!") == 0) {
712 snprintf(errstr, buflen, "double negative");
718 snprintf(errstr, buflen, "'%s' not expected",
724 subject->mbs_flags = flags;
726 subject->mbs_neg = MBS_ALL_FLAGS ^ neg;
728 subject->mbs_neg = neg;
729 if (flags & MBS_UID_DEFINED) {
730 subject->mbs_uid_min = uid_min;
731 subject->mbs_uid_max = uid_max;
733 if (flags & MBS_GID_DEFINED) {
734 subject->mbs_gid_min = gid_min;
735 subject->mbs_gid_max = gid_max;
737 if (flags & MBS_PRISON_DEFINED)
738 subject->mbs_prison = jid;
744 bsde_parse_type(char *spec, int *type, size_t buflen, char *errstr)
749 for (i = 0; i < strlen(spec); i++) {
753 *type |= MBO_TYPE_REG;
756 *type |= MBO_TYPE_DIR;
759 *type |= MBO_TYPE_BLK;
762 *type |= MBO_TYPE_CHR;
765 *type |= MBO_TYPE_LNK;
768 *type |= MBO_TYPE_SOCK;
771 *type |= MBO_TYPE_FIFO;
774 *type |= MBO_ALL_TYPE;
777 snprintf(errstr, buflen, "Unknown type code: %c",
787 bsde_parse_fsid(char *spec, struct fsid *fsid, size_t buflen, char *errstr)
791 if (statfs(spec, &buf) < 0) {
792 snprintf(errstr, buflen, "Unable to get id for %s: %s",
793 spec, strerror(errno));
803 bsde_parse_object(int argc, char *argv[],
804 struct mac_bsdextended_object *object, size_t buflen, char *errstr)
807 int current, neg, nextnot;
809 uid_t uid_min, uid_max;
810 gid_t gid_min, gid_max;
819 if (strcmp("not", argv[current]) == 0) {
825 while (current < argc) {
826 if (strcmp(argv[current], "uid") == 0) {
827 if (current + 2 > argc) {
828 snprintf(errstr, buflen, "uid short");
831 if (flags & MBO_UID_DEFINED) {
832 snprintf(errstr, buflen, "one uid only");
835 if (bsde_parse_uidrange(argv[current+1],
836 &uid_min, &uid_max, buflen, errstr) < 0)
838 flags |= MBO_UID_DEFINED;
840 neg ^= MBO_UID_DEFINED;
844 } else if (strcmp(argv[current], "gid") == 0) {
845 if (current + 2 > argc) {
846 snprintf(errstr, buflen, "gid short");
849 if (flags & MBO_GID_DEFINED) {
850 snprintf(errstr, buflen, "one gid only");
853 if (bsde_parse_gidrange(argv[current+1],
854 &gid_min, &gid_max, buflen, errstr) < 0)
856 flags |= MBO_GID_DEFINED;
858 neg ^= MBO_GID_DEFINED;
862 } else if (strcmp(argv[current], "filesys") == 0) {
863 if (current + 2 > argc) {
864 snprintf(errstr, buflen, "filesys short");
867 if (flags & MBO_FSID_DEFINED) {
868 snprintf(errstr, buflen, "one fsid only");
871 if (bsde_parse_fsid(argv[current+1], &fsid,
874 flags |= MBO_FSID_DEFINED;
876 neg ^= MBO_FSID_DEFINED;
880 } else if (strcmp(argv[current], "suid") == 0) {
887 } else if (strcmp(argv[current], "sgid") == 0) {
894 } else if (strcmp(argv[current], "uid_of_subject") == 0) {
895 flags |= MBO_UID_SUBJECT;
897 neg ^= MBO_UID_SUBJECT;
901 } else if (strcmp(argv[current], "gid_of_subject") == 0) {
902 flags |= MBO_GID_SUBJECT;
904 neg ^= MBO_GID_SUBJECT;
908 } else if (strcmp(argv[current], "type") == 0) {
909 if (current + 2 > argc) {
910 snprintf(errstr, buflen, "type short");
913 if (flags & MBO_TYPE_DEFINED) {
914 snprintf(errstr, buflen, "one type only");
917 if (bsde_parse_type(argv[current+1], &type,
920 flags |= MBO_TYPE_DEFINED;
922 neg ^= MBO_TYPE_DEFINED;
926 } else if (strcmp(argv[current], "!") == 0) {
928 snprintf(errstr, buflen,
935 snprintf(errstr, buflen, "'%s' not expected",
941 object->mbo_flags = flags;
943 object->mbo_neg = MBO_ALL_FLAGS ^ neg;
945 object->mbo_neg = neg;
946 if (flags & MBO_UID_DEFINED) {
947 object->mbo_uid_min = uid_min;
948 object->mbo_uid_max = uid_max;
950 if (flags & MBO_GID_DEFINED) {
951 object->mbo_gid_min = gid_min;
952 object->mbo_gid_max = gid_max;
954 if (flags & MBO_FSID_DEFINED)
955 object->mbo_fsid = fsid;
956 if (flags & MBO_TYPE_DEFINED)
957 object->mbo_type = type;
963 bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
969 snprintf(errstr, buflen, "mode expects mode value");
974 snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
979 for (i = 0; i < strlen(argv[0]); i++) {
980 switch (argv[0][i]) {
1000 snprintf(errstr, buflen, "Unknown mode letter: %c",
1010 bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
1011 size_t buflen, char *errstr)
1013 int subject, subject_elements, subject_elements_length;
1014 int object, object_elements, object_elements_length;
1015 int mode, mode_elements, mode_elements_length;
1018 bzero(rule, sizeof(*rule));
1021 snprintf(errstr, buflen, "Rule must begin with subject");
1025 if (strcmp(argv[0], "subject") != 0) {
1026 snprintf(errstr, buflen, "Rule must begin with subject");
1030 subject_elements = 1;
1032 /* Search forward for object. */
1035 for (i = 1; i < argc; i++)
1036 if (strcmp(argv[i], "object") == 0)
1040 snprintf(errstr, buflen, "Rule must contain an object");
1044 /* Search forward for mode. */
1046 for (i = object; i < argc; i++)
1047 if (strcmp(argv[i], "mode") == 0)
1051 snprintf(errstr, buflen, "Rule must contain mode");
1055 subject_elements_length = object - subject - 1;
1056 object_elements = object + 1;
1057 object_elements_length = mode - object_elements;
1058 mode_elements = mode + 1;
1059 mode_elements_length = argc - mode_elements;
1061 error = bsde_parse_subject(subject_elements_length,
1062 argv + subject_elements, &rule->mbr_subject, buflen, errstr);
1066 error = bsde_parse_object(object_elements_length,
1067 argv + object_elements, &rule->mbr_object, buflen, errstr);
1071 error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
1072 &rule->mbr_mode, buflen, errstr);
1080 bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
1081 size_t buflen, char *errstr)
1083 char *stringdup, *stringp, *argv[100], **ap;
1086 stringp = stringdup = strdup(string);
1087 while (*stringp == ' ' || *stringp == '\t')
1091 for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
1094 if (++ap >= &argv[100])
1098 error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
1106 bsde_get_mib(const char *string, int *name, size_t *namelen)
1112 error = sysctlnametomib(string, name, &len);
1121 bsde_check_version(size_t buflen, char *errstr)
1127 len = sizeof(version);
1128 error = sysctlbyname(MIB ".rule_version", &version, &len, NULL, 0);
1130 snprintf(errstr, buflen, "version check failed: %s",
1134 if (version != MB_VERSION) {
1135 snprintf(errstr, buflen, "module v%d != library v%d",
1136 version, MB_VERSION);
1143 bsde_get_rule_count(size_t buflen, char *errstr)
1149 len = sizeof(rule_count);
1150 error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0);
1152 snprintf(errstr, buflen, "%s", strerror(errno));
1155 if (len != sizeof(rule_count)) {
1156 snprintf(errstr, buflen, "Data error in %s.rule_count",
1161 return (rule_count);
1165 bsde_get_rule_slots(size_t buflen, char *errstr)
1171 len = sizeof(rule_slots);
1172 error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0);
1174 snprintf(errstr, buflen, "%s", strerror(errno));
1177 if (len != sizeof(rule_slots)) {
1178 snprintf(errstr, buflen, "Data error in %s.rule_slots", MIB);
1182 return (rule_slots);
1186 * Returns 0 for success;
1187 * Returns -1 for failure;
1188 * Returns -2 for not present
1191 bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
1198 if (bsde_check_version(errlen, errstr) != 0)
1202 error = bsde_get_mib(MIB ".rules", name, &len);
1204 snprintf(errstr, errlen, "%s: %s", MIB ".rules",
1209 size = sizeof(*rule);
1210 name[len] = rulenum;
1212 error = sysctl(name, len, rule, &size, NULL, 0);
1213 if (error == -1 && errno == ENOENT)
1216 snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
1217 rulenum, strerror(errno));
1219 } else if (size != sizeof(*rule)) {
1220 snprintf(errstr, errlen, "Data error in %s.%d: %s",
1221 MIB ".rules", rulenum, strerror(errno));
1229 bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
1231 struct mac_bsdextended_rule rule;
1236 if (bsde_check_version(buflen, errstr) != 0)
1240 error = bsde_get_mib(MIB ".rules", name, &len);
1242 snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1247 name[len] = rulenum;
1250 error = sysctl(name, len, NULL, NULL, &rule, 0);
1252 snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1253 rulenum, strerror(errno));
1261 bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
1268 if (bsde_check_version(buflen, errstr) != 0)
1272 error = bsde_get_mib(MIB ".rules", name, &len);
1274 snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1279 name[len] = rulenum;
1282 error = sysctl(name, len, NULL, NULL, rule, sizeof(*rule));
1284 snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1285 rulenum, strerror(errno));
1293 bsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
1296 char charstr[BUFSIZ];
1299 int error, rule_slots;
1301 if (bsde_check_version(buflen, errstr) != 0)
1305 error = bsde_get_mib(MIB ".rules", name, &len);
1307 snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1312 rule_slots = bsde_get_rule_slots(BUFSIZ, charstr);
1313 if (rule_slots == -1) {
1314 snprintf(errstr, buflen, "unable to get rule slots: %s",
1319 name[len] = rule_slots;
1322 error = sysctl(name, len, NULL, NULL, rule, sizeof(*rule));
1324 snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1325 rule_slots, strerror(errno));
1329 if (rulenum != NULL)
1330 *rulenum = rule_slots;