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>
37 #include <sys/sysctl.h>
38 #include <sys/ucred.h>
40 #include <sys/mount.h>
42 #include <security/mac_bsdextended/mac_bsdextended.h>
53 * Text format for rules: rules contain subject and object elements, mode.
54 * The total form is "subject [s_element] object [o_element] mode [mode]".
55 * At least * one of a uid or gid entry must be present; both may also be
59 #define MIB "security.mac.bsdextended"
62 bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
66 struct statfs *mntbuf;
67 char *cur, type[sizeof(rule->mbr_object.mbo_type) * CHAR_BIT + 1];
69 int anymode, unknownmode, numfs, i, notdone;
74 len = snprintf(cur, left, "subject ");
75 if (len < 0 || len > left)
79 if (rule->mbr_subject.mbs_flags) {
80 if (rule->mbr_subject.mbs_neg == MBS_ALL_FLAGS) {
81 len = snprintf(cur, left, "not ");
82 if (len < 0 || len > left)
91 if (!notdone && (rule->mbr_subject.mbs_neg & MBO_UID_DEFINED)) {
92 len = snprintf(cur, left, "! ");
93 if (len < 0 || len > left)
98 if (rule->mbr_subject.mbs_flags & MBO_UID_DEFINED) {
99 pwd = getpwuid(rule->mbr_subject.mbs_uid_min);
101 len = snprintf(cur, left, "uid %s",
103 if (len < 0 || len > left)
108 len = snprintf(cur, left, "uid %u",
109 rule->mbr_subject.mbs_uid_min);
110 if (len < 0 || len > left)
115 if (rule->mbr_subject.mbs_uid_min !=
116 rule->mbr_subject.mbs_uid_max) {
117 pwd = getpwuid(rule->mbr_subject.mbs_uid_max);
119 len = snprintf(cur, left, ":%s ",
121 if (len < 0 || len > left)
126 len = snprintf(cur, left, ":%u ",
127 rule->mbr_subject.mbs_uid_max);
128 if (len < 0 || len > left)
134 len = snprintf(cur, left, " ");
135 if (len < 0 || len > left)
141 if (!notdone && (rule->mbr_subject.mbs_neg & MBO_GID_DEFINED)) {
142 len = snprintf(cur, left, "! ");
143 if (len < 0 || len > left)
148 if (rule->mbr_subject.mbs_flags & MBO_GID_DEFINED) {
149 grp = getgrgid(rule->mbr_subject.mbs_gid_min);
151 len = snprintf(cur, left, "gid %s",
153 if (len < 0 || len > left)
158 len = snprintf(cur, left, "gid %u",
159 rule->mbr_subject.mbs_gid_min);
160 if (len < 0 || len > left)
165 if (rule->mbr_subject.mbs_gid_min !=
166 rule->mbr_subject.mbs_gid_max) {
167 grp = getgrgid(rule->mbr_subject.mbs_gid_max);
169 len = snprintf(cur, left, ":%s ",
171 if (len < 0 || len > left)
176 len = snprintf(cur, left, ":%u ",
177 rule->mbr_subject.mbs_gid_max);
178 if (len < 0 || len > left)
184 len = snprintf(cur, left, " ");
185 if (len < 0 || len > left)
191 if (!notdone && (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)) {
192 len = snprintf(cur, left, "! ");
193 if (len < 0 || len > left)
198 if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
199 len = snprintf(cur, left, "jailid %d ",
200 rule->mbr_subject.mbs_prison);
201 if (len < 0 || len > left)
208 len = snprintf(cur, left, "object ");
209 if (len < 0 || len > left)
213 if (rule->mbr_object.mbo_flags) {
214 if (rule->mbr_object.mbo_neg == MBO_ALL_FLAGS) {
215 len = snprintf(cur, left, "not ");
216 if (len < 0 || len > left)
225 if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)) {
226 len = snprintf(cur, left, "! ");
227 if (len < 0 || len > left)
232 if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
233 pwd = getpwuid(rule->mbr_object.mbo_uid_min);
235 len = snprintf(cur, left, "uid %s",
237 if (len < 0 || len > left)
242 len = snprintf(cur, left, "uid %u",
243 rule->mbr_object.mbo_uid_min);
244 if (len < 0 || len > left)
249 if (rule->mbr_object.mbo_uid_min !=
250 rule->mbr_object.mbo_uid_max) {
251 pwd = getpwuid(rule->mbr_object.mbo_uid_max);
253 len = snprintf(cur, left, ":%s ",
255 if (len < 0 || len > left)
260 len = snprintf(cur, left, ":%u ",
261 rule->mbr_object.mbo_uid_max);
262 if (len < 0 || len > left)
268 len = snprintf(cur, left, " ");
269 if (len < 0 || len > left)
275 if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)) {
276 len = snprintf(cur, left, "! ");
277 if (len < 0 || len > left)
282 if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
283 grp = getgrgid(rule->mbr_object.mbo_gid_min);
285 len = snprintf(cur, left, "gid %s",
287 if (len < 0 || len > left)
292 len = snprintf(cur, left, "gid %u",
293 rule->mbr_object.mbo_gid_min);
294 if (len < 0 || len > left)
299 if (rule->mbr_object.mbo_gid_min !=
300 rule->mbr_object.mbo_gid_max) {
301 grp = getgrgid(rule->mbr_object.mbo_gid_max);
303 len = snprintf(cur, left, ":%s ",
305 if (len < 0 || len > left)
310 len = snprintf(cur, left, ":%u ",
311 rule->mbr_object.mbo_gid_max);
312 if (len < 0 || len > left)
318 len = snprintf(cur, left, " ");
319 if (len < 0 || len > left)
325 if (!notdone && (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)) {
326 len = snprintf(cur, left, "! ");
327 if (len < 0 || len > left)
332 if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
333 numfs = getmntinfo(&mntbuf, MNT_NOWAIT);
334 for (i = 0; i < numfs; i++)
335 if (memcmp(&(rule->mbr_object.mbo_fsid),
337 sizeof(mntbuf[i].f_fsid)) == 0)
339 len = snprintf(cur, left, "filesys %s ",
340 i == numfs ? "???" : mntbuf[i].f_mntonname);
341 if (len < 0 || len > left)
346 if (!notdone && (rule->mbr_object.mbo_neg & MBO_SUID)) {
347 len = snprintf(cur, left, "! ");
348 if (len < 0 || len > left)
353 if (rule->mbr_object.mbo_flags & MBO_SUID) {
354 len = snprintf(cur, left, "suid ");
355 if (len < 0 || len > left)
360 if (!notdone && (rule->mbr_object.mbo_neg & MBO_SGID)) {
361 len = snprintf(cur, left, "! ");
362 if (len < 0 || len > left)
367 if (rule->mbr_object.mbo_flags & MBO_SGID) {
368 len = snprintf(cur, left, "sgid ");
369 if (len < 0 || len > left)
374 if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)) {
375 len = snprintf(cur, left, "! ");
376 if (len < 0 || len > left)
381 if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
382 len = snprintf(cur, left, "uid_of_subject ");
383 if (len < 0 || len > left)
388 if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)) {
389 len = snprintf(cur, left, "! ");
390 if (len < 0 || len > left)
395 if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
396 len = snprintf(cur, left, "gid_of_subject ");
397 if (len < 0 || len > left)
402 if (!notdone && (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)) {
403 len = snprintf(cur, left, "! ");
404 if (len < 0 || len > left)
409 if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
411 if (rule->mbr_object.mbo_type & MBO_TYPE_REG)
413 if (rule->mbr_object.mbo_type & MBO_TYPE_DIR)
415 if (rule->mbr_object.mbo_type & MBO_TYPE_BLK)
417 if (rule->mbr_object.mbo_type & MBO_TYPE_CHR)
419 if (rule->mbr_object.mbo_type & MBO_TYPE_LNK)
421 if (rule->mbr_object.mbo_type & MBO_TYPE_SOCK)
423 if (rule->mbr_object.mbo_type & MBO_TYPE_FIFO)
425 if (rule->mbr_object.mbo_type == MBO_ALL_TYPE) {
430 len = snprintf(cur, left, "type %s ", type);
431 if (len < 0 || len > left)
438 len = snprintf(cur, left, "mode ");
439 if (len < 0 || len > left)
444 anymode = (rule->mbr_mode & MBI_ALLPERM);
445 unknownmode = (rule->mbr_mode & ~MBI_ALLPERM);
447 if (rule->mbr_mode & MBI_ADMIN) {
448 len = snprintf(cur, left, "a");
449 if (len < 0 || len > left)
455 if (rule->mbr_mode & MBI_READ) {
456 len = snprintf(cur, left, "r");
457 if (len < 0 || len > left)
463 if (rule->mbr_mode & MBI_STAT) {
464 len = snprintf(cur, left, "s");
465 if (len < 0 || len > left)
471 if (rule->mbr_mode & MBI_WRITE) {
472 len = snprintf(cur, left, "w");
473 if (len < 0 || len > left)
479 if (rule->mbr_mode & MBI_EXEC) {
480 len = snprintf(cur, left, "x");
481 if (len < 0 || len > left)
488 len = snprintf(cur, left, "n");
489 if (len < 0 || len > left)
496 len = snprintf(cur, left, "?");
497 if (len < 0 || len > left)
511 bsde_parse_uidrange(char *spec, uid_t *min, uid_t *max,
512 size_t buflen, char *errstr){
515 char *spec1, *spec2, *endp;
519 spec1 = strsep(&spec2, ":");
521 pwd = getpwnam(spec1);
525 value = strtoul(spec1, &endp, 10);
527 snprintf(errstr, buflen, "invalid uid: '%s'", spec1);
538 pwd = getpwnam(spec2);
542 value = strtoul(spec2, &endp, 10);
544 snprintf(errstr, buflen, "invalid uid: '%s'", spec2);
557 bsde_parse_gidrange(char *spec, gid_t *min, gid_t *max,
558 size_t buflen, char *errstr){
561 char *spec1, *spec2, *endp;
565 spec1 = strsep(&spec2, ":");
567 grp = getgrnam(spec1);
571 value = strtoul(spec1, &endp, 10);
573 snprintf(errstr, buflen, "invalid gid: '%s'", spec1);
584 grp = getgrnam(spec2);
588 value = strtoul(spec2, &endp, 10);
590 snprintf(errstr, buflen, "invalid gid: '%s'", spec2);
603 bsde_get_jailid(const char *name, size_t buflen, char *errstr)
607 struct iovec jiov[4];
609 /* Copy jail_getid(3) instead of messing with library dependancies */
610 jid = strtoul(name, &ep, 10);
613 jiov[0].iov_base = __DECONST(char *, "name");
614 jiov[0].iov_len = sizeof("name");
615 jiov[1].iov_len = strlen(name) + 1;
616 jiov[1].iov_base = alloca(jiov[1].iov_len);
617 strcpy(jiov[1].iov_base, name);
618 if (errstr && buflen) {
619 jiov[2].iov_base = __DECONST(char *, "errmsg");
620 jiov[2].iov_len = sizeof("errmsg");
621 jiov[3].iov_base = errstr;
622 jiov[3].iov_len = buflen;
624 jid = jail_get(jiov, 4, 0);
625 if (jid < 0 && !errstr[0])
626 snprintf(errstr, buflen, "jail_get: %s",
629 jid = jail_get(jiov, 2, 0);
634 bsde_parse_subject(int argc, char *argv[],
635 struct mac_bsdextended_subject *subject, size_t buflen, char *errstr)
638 int current, neg, nextnot;
639 uid_t uid_min, uid_max;
640 gid_t gid_min, gid_max;
648 if (strcmp("not", argv[current]) == 0) {
654 while (current < argc) {
655 if (strcmp(argv[current], "uid") == 0) {
656 if (current + 2 > argc) {
657 snprintf(errstr, buflen, "uid short");
660 if (flags & MBS_UID_DEFINED) {
661 snprintf(errstr, buflen, "one uid only");
664 if (bsde_parse_uidrange(argv[current+1],
665 &uid_min, &uid_max, buflen, errstr) < 0)
667 flags |= MBS_UID_DEFINED;
669 neg ^= MBS_UID_DEFINED;
673 } else if (strcmp(argv[current], "gid") == 0) {
674 if (current + 2 > argc) {
675 snprintf(errstr, buflen, "gid short");
678 if (flags & MBS_GID_DEFINED) {
679 snprintf(errstr, buflen, "one gid only");
682 if (bsde_parse_gidrange(argv[current+1],
683 &gid_min, &gid_max, buflen, errstr) < 0)
685 flags |= MBS_GID_DEFINED;
687 neg ^= MBS_GID_DEFINED;
691 } else if (strcmp(argv[current], "jailid") == 0) {
692 if (current + 2 > argc) {
693 snprintf(errstr, buflen, "prison short");
696 if (flags & MBS_PRISON_DEFINED) {
697 snprintf(errstr, buflen, "one jail only");
700 jid = bsde_get_jailid(argv[current+1], buflen, errstr);
703 flags |= MBS_PRISON_DEFINED;
705 neg ^= MBS_PRISON_DEFINED;
709 } else if (strcmp(argv[current], "!") == 0) {
711 snprintf(errstr, buflen, "double negative");
717 snprintf(errstr, buflen, "'%s' not expected",
723 subject->mbs_flags = flags;
725 subject->mbs_neg = MBS_ALL_FLAGS ^ neg;
727 subject->mbs_neg = neg;
728 if (flags & MBS_UID_DEFINED) {
729 subject->mbs_uid_min = uid_min;
730 subject->mbs_uid_max = uid_max;
732 if (flags & MBS_GID_DEFINED) {
733 subject->mbs_gid_min = gid_min;
734 subject->mbs_gid_max = gid_max;
736 if (flags & MBS_PRISON_DEFINED)
737 subject->mbs_prison = jid;
743 bsde_parse_type(char *spec, int *type, size_t buflen, char *errstr)
748 for (i = 0; i < strlen(spec); i++) {
752 *type |= MBO_TYPE_REG;
755 *type |= MBO_TYPE_DIR;
758 *type |= MBO_TYPE_BLK;
761 *type |= MBO_TYPE_CHR;
764 *type |= MBO_TYPE_LNK;
767 *type |= MBO_TYPE_SOCK;
770 *type |= MBO_TYPE_FIFO;
773 *type |= MBO_ALL_TYPE;
776 snprintf(errstr, buflen, "Unknown type code: %c",
786 bsde_parse_fsid(char *spec, struct fsid *fsid, size_t buflen, char *errstr)
790 if (statfs(spec, &buf) < 0) {
791 snprintf(errstr, buflen, "Unable to get id for %s: %s",
792 spec, strerror(errno));
802 bsde_parse_object(int argc, char *argv[],
803 struct mac_bsdextended_object *object, size_t buflen, char *errstr)
806 int current, neg, nextnot;
808 uid_t uid_min, uid_max;
809 gid_t gid_min, gid_max;
818 if (strcmp("not", argv[current]) == 0) {
824 while (current < argc) {
825 if (strcmp(argv[current], "uid") == 0) {
826 if (current + 2 > argc) {
827 snprintf(errstr, buflen, "uid short");
830 if (flags & MBO_UID_DEFINED) {
831 snprintf(errstr, buflen, "one uid only");
834 if (bsde_parse_uidrange(argv[current+1],
835 &uid_min, &uid_max, buflen, errstr) < 0)
837 flags |= MBO_UID_DEFINED;
839 neg ^= MBO_UID_DEFINED;
843 } else if (strcmp(argv[current], "gid") == 0) {
844 if (current + 2 > argc) {
845 snprintf(errstr, buflen, "gid short");
848 if (flags & MBO_GID_DEFINED) {
849 snprintf(errstr, buflen, "one gid only");
852 if (bsde_parse_gidrange(argv[current+1],
853 &gid_min, &gid_max, buflen, errstr) < 0)
855 flags |= MBO_GID_DEFINED;
857 neg ^= MBO_GID_DEFINED;
861 } else if (strcmp(argv[current], "filesys") == 0) {
862 if (current + 2 > argc) {
863 snprintf(errstr, buflen, "filesys short");
866 if (flags & MBO_FSID_DEFINED) {
867 snprintf(errstr, buflen, "one fsid only");
870 if (bsde_parse_fsid(argv[current+1], &fsid,
873 flags |= MBO_FSID_DEFINED;
875 neg ^= MBO_FSID_DEFINED;
879 } else if (strcmp(argv[current], "suid") == 0) {
886 } else if (strcmp(argv[current], "sgid") == 0) {
893 } else if (strcmp(argv[current], "uid_of_subject") == 0) {
894 flags |= MBO_UID_SUBJECT;
896 neg ^= MBO_UID_SUBJECT;
900 } else if (strcmp(argv[current], "gid_of_subject") == 0) {
901 flags |= MBO_GID_SUBJECT;
903 neg ^= MBO_GID_SUBJECT;
907 } else if (strcmp(argv[current], "type") == 0) {
908 if (current + 2 > argc) {
909 snprintf(errstr, buflen, "type short");
912 if (flags & MBO_TYPE_DEFINED) {
913 snprintf(errstr, buflen, "one type only");
916 if (bsde_parse_type(argv[current+1], &type,
919 flags |= MBO_TYPE_DEFINED;
921 neg ^= MBO_TYPE_DEFINED;
925 } else if (strcmp(argv[current], "!") == 0) {
927 snprintf(errstr, buflen,
934 snprintf(errstr, buflen, "'%s' not expected",
940 object->mbo_flags = flags;
942 object->mbo_neg = MBO_ALL_FLAGS ^ neg;
944 object->mbo_neg = neg;
945 if (flags & MBO_UID_DEFINED) {
946 object->mbo_uid_min = uid_min;
947 object->mbo_uid_max = uid_max;
949 if (flags & MBO_GID_DEFINED) {
950 object->mbo_gid_min = gid_min;
951 object->mbo_gid_max = gid_max;
953 if (flags & MBO_FSID_DEFINED)
954 object->mbo_fsid = fsid;
955 if (flags & MBO_TYPE_DEFINED)
956 object->mbo_type = type;
962 bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
968 snprintf(errstr, buflen, "mode expects mode value");
973 snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
978 for (i = 0; i < strlen(argv[0]); i++) {
979 switch (argv[0][i]) {
999 snprintf(errstr, buflen, "Unknown mode letter: %c",
1009 bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
1010 size_t buflen, char *errstr)
1012 int subject, subject_elements, subject_elements_length;
1013 int object, object_elements, object_elements_length;
1014 int mode, mode_elements, mode_elements_length;
1017 bzero(rule, sizeof(*rule));
1020 snprintf(errstr, buflen, "Rule must begin with subject");
1024 if (strcmp(argv[0], "subject") != 0) {
1025 snprintf(errstr, buflen, "Rule must begin with subject");
1029 subject_elements = 1;
1031 /* Search forward for object. */
1034 for (i = 1; i < argc; i++)
1035 if (strcmp(argv[i], "object") == 0)
1039 snprintf(errstr, buflen, "Rule must contain an object");
1043 /* Search forward for mode. */
1045 for (i = object; i < argc; i++)
1046 if (strcmp(argv[i], "mode") == 0)
1050 snprintf(errstr, buflen, "Rule must contain mode");
1054 subject_elements_length = object - subject - 1;
1055 object_elements = object + 1;
1056 object_elements_length = mode - object_elements;
1057 mode_elements = mode + 1;
1058 mode_elements_length = argc - mode_elements;
1060 error = bsde_parse_subject(subject_elements_length,
1061 argv + subject_elements, &rule->mbr_subject, buflen, errstr);
1065 error = bsde_parse_object(object_elements_length,
1066 argv + object_elements, &rule->mbr_object, buflen, errstr);
1070 error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
1071 &rule->mbr_mode, buflen, errstr);
1079 bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
1080 size_t buflen, char *errstr)
1082 char *stringdup, *stringp, *argv[100], **ap;
1085 stringp = stringdup = strdup(string);
1086 while (*stringp == ' ' || *stringp == '\t')
1090 for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
1093 if (++ap >= &argv[100])
1097 error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
1105 bsde_get_mib(const char *string, int *name, size_t *namelen)
1111 error = sysctlnametomib(string, name, &len);
1120 bsde_check_version(size_t buflen, char *errstr)
1126 len = sizeof(version);
1127 error = sysctlbyname(MIB ".rule_version", &version, &len, NULL, 0);
1129 snprintf(errstr, buflen, "version check failed: %s",
1133 if (version != MB_VERSION) {
1134 snprintf(errstr, buflen, "module v%d != library v%d",
1135 version, MB_VERSION);
1142 bsde_get_rule_count(size_t buflen, char *errstr)
1148 len = sizeof(rule_count);
1149 error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0);
1151 snprintf(errstr, buflen, "%s", strerror(errno));
1154 if (len != sizeof(rule_count)) {
1155 snprintf(errstr, buflen, "Data error in %s.rule_count",
1160 return (rule_count);
1164 bsde_get_rule_slots(size_t buflen, char *errstr)
1170 len = sizeof(rule_slots);
1171 error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0);
1173 snprintf(errstr, buflen, "%s", strerror(errno));
1176 if (len != sizeof(rule_slots)) {
1177 snprintf(errstr, buflen, "Data error in %s.rule_slots", MIB);
1181 return (rule_slots);
1185 * Returns 0 for success;
1186 * Returns -1 for failure;
1187 * Returns -2 for not present
1190 bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
1197 if (bsde_check_version(errlen, errstr) != 0)
1201 error = bsde_get_mib(MIB ".rules", name, &len);
1203 snprintf(errstr, errlen, "%s: %s", MIB ".rules",
1208 size = sizeof(*rule);
1209 name[len] = rulenum;
1211 error = sysctl(name, len, rule, &size, NULL, 0);
1212 if (error == -1 && errno == ENOENT)
1215 snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
1216 rulenum, strerror(errno));
1218 } else if (size != sizeof(*rule)) {
1219 snprintf(errstr, errlen, "Data error in %s.%d: %s",
1220 MIB ".rules", rulenum, strerror(errno));
1228 bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
1230 struct mac_bsdextended_rule rule;
1235 if (bsde_check_version(buflen, errstr) != 0)
1239 error = bsde_get_mib(MIB ".rules", name, &len);
1241 snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1246 name[len] = rulenum;
1249 error = sysctl(name, len, NULL, NULL, &rule, 0);
1251 snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1252 rulenum, strerror(errno));
1260 bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
1267 if (bsde_check_version(buflen, errstr) != 0)
1271 error = bsde_get_mib(MIB ".rules", name, &len);
1273 snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1278 name[len] = rulenum;
1281 error = sysctl(name, len, NULL, NULL, rule, sizeof(*rule));
1283 snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1284 rulenum, strerror(errno));
1292 bsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
1295 char charstr[BUFSIZ];
1298 int error, rule_slots;
1300 if (bsde_check_version(buflen, errstr) != 0)
1304 error = bsde_get_mib(MIB ".rules", name, &len);
1306 snprintf(errstr, buflen, "%s: %s", MIB ".rules",
1311 rule_slots = bsde_get_rule_slots(BUFSIZ, charstr);
1312 if (rule_slots == -1) {
1313 snprintf(errstr, buflen, "unable to get rule slots: %s",
1318 name[len] = rule_slots;
1321 error = sysctl(name, len, NULL, NULL, rule, sizeof(*rule));
1323 snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
1324 rule_slots, strerror(errno));
1328 if (rulenum != NULL)
1329 *rulenum = rule_slots;