2 * Copyright (c) 2002-2005 Networks Associates Technology, Inc.
5 * This software was developed for the FreeBSD Project by Network Associates
6 * Laboratories, the Security Research Division of Network Associates, Inc.
7 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
8 * DARPA CHATS research program.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/param.h>
34 #include <sys/errno.h>
36 #include <sys/sysctl.h>
37 #include <sys/ucred.h>
38 #include <sys/mount.h>
40 #include <security/mac_bsdextended/mac_bsdextended.h>
51 * Text format for rules: rules contain subject and object elements, mode.
52 * The total form is "subject [s_element] object [o_element] mode [mode]".
53 * At least * one of a uid or gid entry must be present; both may also be
57 #define MIB "security.mac.bsdextended"
60 bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
64 struct statfs *mntbuf;
65 char *cur, type[sizeof(rule->mbr_object.mbo_type) * CHAR_BIT + 1];
67 int anymode, unknownmode, numfs, i, notdone;
72 len = snprintf(cur, left, "subject ");
73 if (len < 0 || len > left)
77 if (rule->mbr_subject.mbs_flags) {
78 if (rule->mbr_subject.mbs_neg == MBS_ALL_FLAGS) {
79 len = snprintf(cur, left, "not ");
80 if (len < 0 || len > left)
89 if (!notdone && (rule->mbr_subject.mbs_neg & MBO_UID_DEFINED)) {
90 len = snprintf(cur, left, "! ");
91 if (len < 0 || len > left)
96 if (rule->mbr_subject.mbs_flags & MBO_UID_DEFINED) {
97 pwd = getpwuid(rule->mbr_subject.mbs_uid_min);
99 len = snprintf(cur, left, "uid %s",
101 if (len < 0 || len > left)
106 len = snprintf(cur, left, "uid %u",
107 rule->mbr_subject.mbs_uid_min);
108 if (len < 0 || len > left)
113 if (rule->mbr_subject.mbs_uid_min !=
114 rule->mbr_subject.mbs_uid_max) {
115 pwd = getpwuid(rule->mbr_subject.mbs_uid_max);
117 len = snprintf(cur, left, ":%s ",
119 if (len < 0 || len > left)
124 len = snprintf(cur, left, ":%u ",
125 rule->mbr_subject.mbs_uid_max);
126 if (len < 0 || len > left)
132 len = snprintf(cur, left, " ");
133 if (len < 0 || len > left)
139 if (!notdone && (rule->mbr_subject.mbs_neg & MBO_GID_DEFINED)) {
140 len = snprintf(cur, left, "! ");
141 if (len < 0 || len > left)
146 if (rule->mbr_subject.mbs_flags & MBO_GID_DEFINED) {
147 grp = getgrgid(rule->mbr_subject.mbs_gid_min);
149 len = snprintf(cur, left, "gid %s",
151 if (len < 0 || len > left)
156 len = snprintf(cur, left, "gid %u",
157 rule->mbr_subject.mbs_gid_min);
158 if (len < 0 || len > left)
163 if (rule->mbr_subject.mbs_gid_min !=
164 rule->mbr_subject.mbs_gid_max) {
165 grp = getgrgid(rule->mbr_subject.mbs_gid_max);
167 len = snprintf(cur, left, ":%s ",
169 if (len < 0 || len > left)
174 len = snprintf(cur, left, ":%u ",
175 rule->mbr_subject.mbs_gid_max);
176 if (len < 0 || len > left)
182 len = snprintf(cur, left, " ");
183 if (len < 0 || len > left)
189 if (!notdone && (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)) {
190 len = snprintf(cur, left, "! ");
191 if (len < 0 || len > left)
196 if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
197 len = snprintf(cur, left, "jailid %d ",
198 rule->mbr_subject.mbs_prison);
199 if (len < 0 || len > left)
206 len = snprintf(cur, left, "object ");
207 if (len < 0 || len > left)
211 if (rule->mbr_object.mbo_flags) {
212 if (rule->mbr_object.mbo_neg == MBO_ALL_FLAGS) {
213 len = snprintf(cur, left, "not ");
214 if (len < 0 || len > left)
223 if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)) {
224 len = snprintf(cur, left, "! ");
225 if (len < 0 || len > left)
230 if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
231 pwd = getpwuid(rule->mbr_object.mbo_uid_min);
233 len = snprintf(cur, left, "uid %s",
235 if (len < 0 || len > left)
240 len = snprintf(cur, left, "uid %u",
241 rule->mbr_object.mbo_uid_min);
242 if (len < 0 || len > left)
247 if (rule->mbr_object.mbo_uid_min !=
248 rule->mbr_object.mbo_uid_max) {
249 pwd = getpwuid(rule->mbr_object.mbo_uid_max);
251 len = snprintf(cur, left, ":%s ",
253 if (len < 0 || len > left)
258 len = snprintf(cur, left, ":%u ",
259 rule->mbr_object.mbo_uid_max);
260 if (len < 0 || len > left)
266 len = snprintf(cur, left, " ");
267 if (len < 0 || len > left)
273 if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)) {
274 len = snprintf(cur, left, "! ");
275 if (len < 0 || len > left)
280 if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
281 grp = getgrgid(rule->mbr_object.mbo_gid_min);
283 len = snprintf(cur, left, "gid %s",
285 if (len < 0 || len > left)
290 len = snprintf(cur, left, "gid %u",
291 rule->mbr_object.mbo_gid_min);
292 if (len < 0 || len > left)
297 if (rule->mbr_object.mbo_gid_min !=
298 rule->mbr_object.mbo_gid_max) {
299 grp = getgrgid(rule->mbr_object.mbo_gid_max);
301 len = snprintf(cur, left, ":%s ",
303 if (len < 0 || len > left)
308 len = snprintf(cur, left, ":%u ",
309 rule->mbr_object.mbo_gid_max);
310 if (len < 0 || len > left)
316 len = snprintf(cur, left, " ");
317 if (len < 0 || len > left)
323 if (!notdone && (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)) {
324 len = snprintf(cur, left, "! ");
325 if (len < 0 || len > left)
330 if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
331 numfs = getmntinfo(&mntbuf, MNT_NOWAIT);
332 for (i = 0; i < numfs; i++)
333 if (memcmp(&(rule->mbr_object.mbo_fsid),
335 sizeof(mntbuf[i].f_fsid)) == 0)
337 len = snprintf(cur, left, "filesys %s ",
338 i == numfs ? "???" : mntbuf[i].f_mntonname);
339 if (len < 0 || len > left)
344 if (!notdone && (rule->mbr_object.mbo_neg & MBO_SUID)) {
345 len = snprintf(cur, left, "! ");
346 if (len < 0 || len > left)
351 if (rule->mbr_object.mbo_flags & MBO_SUID) {
352 len = snprintf(cur, left, "suid ");
353 if (len < 0 || len > left)
358 if (!notdone && (rule->mbr_object.mbo_neg & MBO_SGID)) {
359 len = snprintf(cur, left, "! ");
360 if (len < 0 || len > left)
365 if (rule->mbr_object.mbo_flags & MBO_SGID) {
366 len = snprintf(cur, left, "sgid ");
367 if (len < 0 || len > left)
372 if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)) {
373 len = snprintf(cur, left, "! ");
374 if (len < 0 || len > left)
379 if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
380 len = snprintf(cur, left, "uid_of_subject ");
381 if (len < 0 || len > left)
386 if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)) {
387 len = snprintf(cur, left, "! ");
388 if (len < 0 || len > left)
393 if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
394 len = snprintf(cur, left, "gid_of_subject ");
395 if (len < 0 || len > left)
400 if (!notdone && (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)) {
401 len = snprintf(cur, left, "! ");
402 if (len < 0 || len > left)
407 if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
409 if (rule->mbr_object.mbo_type & MBO_TYPE_REG)
411 if (rule->mbr_object.mbo_type & MBO_TYPE_DIR)
413 if (rule->mbr_object.mbo_type & MBO_TYPE_BLK)
415 if (rule->mbr_object.mbo_type & MBO_TYPE_CHR)
417 if (rule->mbr_object.mbo_type & MBO_TYPE_LNK)
419 if (rule->mbr_object.mbo_type & MBO_TYPE_SOCK)
421 if (rule->mbr_object.mbo_type & MBO_TYPE_FIFO)
423 if (rule->mbr_object.mbo_type == MBO_ALL_TYPE) {
428 len = snprintf(cur, left, "type %s ", type);
429 if (len < 0 || len > left)
436 len = snprintf(cur, left, "mode ");
437 if (len < 0 || len > left)
442 anymode = (rule->mbr_mode & MBI_ALLPERM);
443 unknownmode = (rule->mbr_mode & ~MBI_ALLPERM);
445 if (rule->mbr_mode & MBI_ADMIN) {
446 len = snprintf(cur, left, "a");
447 if (len < 0 || len > left)
453 if (rule->mbr_mode & MBI_READ) {
454 len = snprintf(cur, left, "r");
455 if (len < 0 || len > left)
461 if (rule->mbr_mode & MBI_STAT) {
462 len = snprintf(cur, left, "s");
463 if (len < 0 || len > left)
469 if (rule->mbr_mode & MBI_WRITE) {
470 len = snprintf(cur, left, "w");
471 if (len < 0 || len > left)
477 if (rule->mbr_mode & MBI_EXEC) {
478 len = snprintf(cur, left, "x");
479 if (len < 0 || len > left)
486 len = snprintf(cur, left, "n");
487 if (len < 0 || len > left)
494 len = snprintf(cur, left, "?");
495 if (len < 0 || len > left)
509 bsde_parse_uidrange(char *spec, uid_t *min, uid_t *max,
510 size_t buflen, char *errstr){
513 char *spec1, *spec2, *endp;
518 spec1 = strsep(&spec2, ":");
520 pwd = getpwnam(spec1);
524 value = strtoul(spec1, &endp, 10);
526 len = snprintf(errstr, buflen,
527 "invalid uid: '%s'", spec1);
538 pwd = getpwnam(spec2);
542 value = strtoul(spec2, &endp, 10);
544 len = snprintf(errstr, buflen,
545 "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;
567 spec1 = strsep(&spec2, ":");
569 grp = getgrnam(spec1);
573 value = strtoul(spec1, &endp, 10);
575 len = snprintf(errstr, buflen,
576 "invalid gid: '%s'", spec1);
587 grp = getgrnam(spec2);
591 value = strtoul(spec2, &endp, 10);
593 len = snprintf(errstr, buflen,
594 "invalid gid: '%s'", spec2);
607 bsde_parse_subject(int argc, char *argv[],
608 struct mac_bsdextended_subject *subject, size_t buflen, char *errstr)
611 int current, neg, nextnot;
613 uid_t uid_min, uid_max;
614 gid_t gid_min, gid_max;
624 if (strcmp("not", argv[current]) == 0) {
630 while (current < argc) {
631 if (strcmp(argv[current], "uid") == 0) {
632 if (current + 2 > argc) {
633 len = snprintf(errstr, buflen, "uid short");
636 if (flags & MBS_UID_DEFINED) {
637 len = snprintf(errstr, buflen, "one uid only");
640 if (bsde_parse_uidrange(argv[current+1],
641 &uid_min, &uid_max, buflen, errstr) < 0)
643 flags |= MBS_UID_DEFINED;
645 neg ^= MBS_UID_DEFINED;
649 } else if (strcmp(argv[current], "gid") == 0) {
650 if (current + 2 > argc) {
651 len = snprintf(errstr, buflen, "gid short");
654 if (flags & MBS_GID_DEFINED) {
655 len = snprintf(errstr, buflen, "one gid only");
658 if (bsde_parse_gidrange(argv[current+1],
659 &gid_min, &gid_max, buflen, errstr) < 0)
661 flags |= MBS_GID_DEFINED;
663 neg ^= MBS_GID_DEFINED;
667 } else if (strcmp(argv[current], "jailid") == 0) {
668 if (current + 2 > argc) {
669 len = snprintf(errstr, buflen, "prison short");
672 if (flags & MBS_PRISON_DEFINED) {
673 len = snprintf(errstr, buflen, "one jail only");
676 value = strtol(argv[current+1], &endp, 10);
678 len = snprintf(errstr, buflen,
679 "invalid jid: '%s'", argv[current+1]);
683 flags |= MBS_PRISON_DEFINED;
685 neg ^= MBS_PRISON_DEFINED;
689 } else if (strcmp(argv[current], "!") == 0) {
691 len = snprintf(errstr, buflen,
698 len = snprintf(errstr, buflen, "'%s' not expected",
704 subject->mbs_flags = flags;
706 subject->mbs_neg = MBS_ALL_FLAGS ^ neg;
708 subject->mbs_neg = neg;
709 if (flags & MBS_UID_DEFINED) {
710 subject->mbs_uid_min = uid_min;
711 subject->mbs_uid_max = uid_max;
713 if (flags & MBS_GID_DEFINED) {
714 subject->mbs_gid_min = gid_min;
715 subject->mbs_gid_max = gid_max;
717 if (flags & MBS_PRISON_DEFINED)
718 subject->mbs_prison = jid;
724 bsde_parse_type(char *spec, int *type, size_t buflen, char *errstr)
730 for (i = 0; i < strlen(spec); i++) {
734 *type |= MBO_TYPE_REG;
737 *type |= MBO_TYPE_DIR;
740 *type |= MBO_TYPE_BLK;
743 *type |= MBO_TYPE_CHR;
746 *type |= MBO_TYPE_LNK;
749 *type |= MBO_TYPE_SOCK;
752 *type |= MBO_TYPE_FIFO;
755 *type |= MBO_ALL_TYPE;
758 len = snprintf(errstr, buflen, "Unknown type code: %c",
768 bsde_parse_fsid(char *spec, struct fsid *fsid, size_t buflen, char *errstr)
773 if (statfs(spec, &buf) < 0) {
774 len = snprintf(errstr, buflen, "Unable to get id for %s: %s",
775 spec, strerror(errno));
785 bsde_parse_object(int argc, char *argv[],
786 struct mac_bsdextended_object *object, size_t buflen, char *errstr)
789 int current, neg, nextnot;
790 uid_t uid_min, uid_max;
791 gid_t gid_min, gid_max;
801 if (strcmp("not", argv[current]) == 0) {
807 while (current < argc) {
808 if (strcmp(argv[current], "uid") == 0) {
809 if (current + 2 > argc) {
810 len = snprintf(errstr, buflen, "uid short");
813 if (flags & MBO_UID_DEFINED) {
814 len = snprintf(errstr, buflen, "one uid only");
817 if (bsde_parse_uidrange(argv[current+1],
818 &uid_min, &uid_max, buflen, errstr) < 0)
820 flags |= MBO_UID_DEFINED;
822 neg ^= MBO_UID_DEFINED;
826 } else if (strcmp(argv[current], "gid") == 0) {
827 if (current + 2 > argc) {
828 len = snprintf(errstr, buflen, "gid short");
831 if (flags & MBO_GID_DEFINED) {
832 len = snprintf(errstr, buflen, "one gid only");
835 if (bsde_parse_gidrange(argv[current+1],
836 &gid_min, &gid_max, buflen, errstr) < 0)
838 flags |= MBO_GID_DEFINED;
840 neg ^= MBO_GID_DEFINED;
844 } else if (strcmp(argv[current], "filesys") == 0) {
845 if (current + 2 > argc) {
846 len = snprintf(errstr, buflen, "filesys short");
849 if (flags & MBO_FSID_DEFINED) {
850 len = snprintf(errstr, buflen, "one fsid only");
853 if (bsde_parse_fsid(argv[current+1], &fsid,
856 flags |= MBO_FSID_DEFINED;
858 neg ^= MBO_FSID_DEFINED;
862 } else if (strcmp(argv[current], "suid") == 0) {
869 } else if (strcmp(argv[current], "sgid") == 0) {
876 } else if (strcmp(argv[current], "uid_of_subject") == 0) {
877 flags |= MBO_UID_SUBJECT;
879 neg ^= MBO_UID_SUBJECT;
883 } else if (strcmp(argv[current], "gid_of_subject") == 0) {
884 flags |= MBO_GID_SUBJECT;
886 neg ^= MBO_GID_SUBJECT;
890 } else if (strcmp(argv[current], "type") == 0) {
891 if (current + 2 > argc) {
892 len = snprintf(errstr, buflen, "type short");
895 if (flags & MBO_TYPE_DEFINED) {
896 len = snprintf(errstr, buflen, "one type only");
899 if (bsde_parse_type(argv[current+1], &type,
902 flags |= MBO_TYPE_DEFINED;
904 neg ^= MBO_TYPE_DEFINED;
908 } else if (strcmp(argv[current], "!") == 0) {
910 len = snprintf(errstr, buflen,
917 len = snprintf(errstr, buflen, "'%s' not expected",
923 object->mbo_flags = flags;
925 object->mbo_neg = MBO_ALL_FLAGS ^ neg;
927 object->mbo_neg = neg;
928 if (flags & MBO_UID_DEFINED) {
929 object->mbo_uid_min = uid_min;
930 object->mbo_uid_max = uid_max;
932 if (flags & MBO_GID_DEFINED) {
933 object->mbo_gid_min = gid_min;
934 object->mbo_gid_max = gid_max;
936 if (flags & MBO_FSID_DEFINED)
937 object->mbo_fsid = fsid;
938 if (flags & MBO_TYPE_DEFINED)
939 object->mbo_type = type;
945 bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
952 len = snprintf(errstr, buflen, "mode expects mode value");
957 len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
962 for (i = 0; i < strlen(argv[0]); i++) {
963 switch (argv[0][i]) {
983 len = snprintf(errstr, buflen, "Unknown mode letter: %c",
993 bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
994 size_t buflen, char *errstr)
996 int subject, subject_elements, subject_elements_length;
997 int object, object_elements, object_elements_length;
998 int mode, mode_elements, mode_elements_length;
1002 bzero(rule, sizeof(*rule));
1005 len = snprintf(errstr, buflen, "Rule must begin with subject");
1009 if (strcmp(argv[0], "subject") != 0) {
1010 len = snprintf(errstr, buflen, "Rule must begin with subject");
1014 subject_elements = 1;
1016 /* Search forward for object. */
1019 for (i = 1; i < argc; i++)
1020 if (strcmp(argv[i], "object") == 0)
1024 len = snprintf(errstr, buflen, "Rule must contain an object");
1028 /* Search forward for mode. */
1030 for (i = object; i < argc; i++)
1031 if (strcmp(argv[i], "mode") == 0)
1035 len = snprintf(errstr, buflen, "Rule must contain mode");
1039 subject_elements_length = object - subject - 1;
1040 object_elements = object + 1;
1041 object_elements_length = mode - object_elements;
1042 mode_elements = mode + 1;
1043 mode_elements_length = argc - mode_elements;
1045 error = bsde_parse_subject(subject_elements_length,
1046 argv + subject_elements, &rule->mbr_subject, buflen, errstr);
1050 error = bsde_parse_object(object_elements_length,
1051 argv + object_elements, &rule->mbr_object, buflen, errstr);
1055 error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
1056 &rule->mbr_mode, buflen, errstr);
1064 bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
1065 size_t buflen, char *errstr)
1067 char *stringdup, *stringp, *argv[100], **ap;
1070 stringp = stringdup = strdup(string);
1071 while (*stringp == ' ' || *stringp == '\t')
1075 for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
1078 if (++ap >= &argv[100])
1082 error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
1090 bsde_get_mib(const char *string, int *name, size_t *namelen)
1096 error = sysctlnametomib(string, name, &len);
1105 bsde_check_version(size_t buflen, char *errstr)
1111 len = sizeof(version);
1112 error = sysctlbyname(MIB ".rule_version", &version, &len, NULL, 0);
1114 len = snprintf(errstr, buflen, "version check failed: %s",
1118 if (version != MB_VERSION) {
1119 len = snprintf(errstr, buflen, "module v%d != library v%d",
1120 version, MB_VERSION);
1127 bsde_get_rule_count(size_t buflen, char *errstr)
1133 len = sizeof(rule_count);
1134 error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0);
1136 len = snprintf(errstr, buflen, "%s", strerror(errno));
1139 if (len != sizeof(rule_count)) {
1140 len = snprintf(errstr, buflen, "Data error in %s.rule_count",
1145 return (rule_count);
1149 bsde_get_rule_slots(size_t buflen, char *errstr)
1155 len = sizeof(rule_slots);
1156 error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0);
1158 len = snprintf(errstr, buflen, "%s", strerror(errno));
1161 if (len != sizeof(rule_slots)) {
1162 len = snprintf(errstr, buflen, "Data error in %s.rule_slots",
1167 return (rule_slots);
1171 * Returns 0 for success;
1172 * Returns -1 for failure;
1173 * Returns -2 for not present
1176 bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
1183 if (bsde_check_version(errlen, errstr) != 0)
1187 error = bsde_get_mib(MIB ".rules", name, &len);
1189 len = snprintf(errstr, errlen, "%s: %s", MIB ".rules",
1194 size = sizeof(*rule);
1195 name[len] = rulenum;
1197 error = sysctl(name, len, rule, &size, NULL, 0);
1198 if (error == -1 && errno == ENOENT)
1201 len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
1202 rulenum, strerror(errno));
1204 } else if (size != sizeof(*rule)) {
1205 len = snprintf(errstr, errlen, "Data error in %s.%d: %s",
1206 MIB ".rules", rulenum, strerror(errno));
1214 bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
1216 struct mac_bsdextended_rule rule;
1221 if (bsde_check_version(buflen, errstr) != 0)
1225 error = bsde_get_mib(MIB ".rules", name, &len);
1227 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1232 name[len] = rulenum;
1235 error = sysctl(name, len, NULL, NULL, &rule, sizeof(rule));
1237 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1238 rulenum, strerror(errno));
1246 bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
1253 if (bsde_check_version(buflen, errstr) != 0)
1257 error = bsde_get_mib(MIB ".rules", name, &len);
1259 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1264 name[len] = rulenum;
1267 error = sysctl(name, len, NULL, NULL, rule, sizeof(*rule));
1269 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1270 rulenum, strerror(errno));
1278 bsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
1281 char charstr[BUFSIZ];
1284 int error, rule_slots;
1286 if (bsde_check_version(buflen, errstr) != 0)
1290 error = bsde_get_mib(MIB ".rules", name, &len);
1292 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1297 rule_slots = bsde_get_rule_slots(BUFSIZ, charstr);
1298 if (rule_slots == -1) {
1299 len = snprintf(errstr, buflen, "unable to get rule slots: %s",
1304 name[len] = rule_slots;
1307 error = sysctl(name, len, NULL, NULL, rule, sizeof(*rule));
1309 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1310 rule_slots, strerror(errno));
1314 if (rulenum != NULL)
1315 *rulenum = rule_slots;