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>
38 #include <security/mac_bsdextended/mac_bsdextended.h>
49 * Text format for rules: rules contain subject and object elements, mode.
50 * Each element takes the form "[not] [uid number] [gid number]".
51 * The total form is "subject [element] object [element] mode [mode]".
52 * At least * one of a uid or gid entry must be present; both may also be
56 #define MIB "security.mac.bsdextended"
59 bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
65 int anymode, unknownmode, truncated;
71 if (rule->mbr_subject.mbi_flags & (MBI_UID_DEFINED |
73 len = snprintf(cur, left, "subject ");
74 if (len < 0 || len > left)
79 if (rule->mbr_subject.mbi_flags & MBI_NEGATED) {
80 len = snprintf(cur, left, "not ");
81 if (len < 0 || len > left)
86 if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
87 pwd = getpwuid(rule->mbr_subject.mbi_uid);
89 len = snprintf(cur, left, "uid %s ",
91 if (len < 0 || len > left)
96 len = snprintf(cur, left, "uid %u ",
97 rule->mbr_subject.mbi_uid);
98 if (len < 0 || len > left)
104 if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
105 grp = getgrgid(rule->mbr_subject.mbi_gid);
107 len = snprintf(cur, left, "gid %s ",
109 if (len < 0 || len > left)
114 len = snprintf(cur, left, "gid %u ",
115 rule->mbr_subject.mbi_gid);
116 if (len < 0 || len > left)
123 if (rule->mbr_object.mbi_flags & (MBI_UID_DEFINED |
125 len = snprintf(cur, left, "object ");
126 if (len < 0 || len > left)
131 if (rule->mbr_object.mbi_flags & MBI_NEGATED) {
132 len = snprintf(cur, left, "not ");
133 if (len < 0 || len > left)
138 if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
139 pwd = getpwuid(rule->mbr_object.mbi_uid);
141 len = snprintf(cur, left, "uid %s ",
143 if (len < 0 || len > left)
148 len = snprintf(cur, left, "uid %u ",
149 rule->mbr_object.mbi_uid);
154 if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
155 grp = getgrgid(rule->mbr_object.mbi_gid);
157 len = snprintf(cur, left, "gid %s ",
159 if (len < 0 || len > left)
164 len = snprintf(cur, left, "gid %u ",
165 rule->mbr_object.mbi_gid);
166 if (len < 0 || len > left)
174 len = snprintf(cur, left, "mode ");
175 if (len < 0 || len > left)
180 anymode = (rule->mbr_mode & MBI_ALLPERM);
181 unknownmode = (rule->mbr_mode & ~MBI_ALLPERM);
183 if (rule->mbr_mode & MBI_ADMIN) {
184 len = snprintf(cur, left, "a");
185 if (len < 0 || len > left)
191 if (rule->mbr_mode & MBI_READ) {
192 len = snprintf(cur, left, "r");
193 if (len < 0 || len > left)
199 if (rule->mbr_mode & MBI_STAT) {
200 len = snprintf(cur, left, "s");
201 if (len < 0 || len > left)
207 if (rule->mbr_mode & MBI_WRITE) {
208 len = snprintf(cur, left, "w");
209 if (len < 0 || len > left)
215 if (rule->mbr_mode & MBI_EXEC) {
216 len = snprintf(cur, left, "x");
217 if (len < 0 || len > left)
224 len = snprintf(cur, left, "n");
225 if (len < 0 || len > left)
232 len = snprintf(cur, left, "?");
233 if (len < 0 || len > left)
247 bsde_parse_identity(int argc, char *argv[],
248 struct mac_bsdextended_identity *identity, size_t buflen, char *errstr)
252 int uid_seen, gid_seen, not_seen;
261 len = snprintf(errstr, buflen, "Identity must not be empty");
267 /* First element might be "not". */
268 if (strcmp("not", argv[0]) == 0) {
274 if (current >= argc) {
275 len = snprintf(errstr, buflen, "Identity short");
284 /* First phrase: uid [uid] or gid [gid]. */
285 if (strcmp("uid", argv[current]) == 0) {
286 if (current + 2 > argc) {
287 len = snprintf(errstr, buflen, "uid short");
290 pwd = getpwnam(argv[current+1]);
294 value = strtol(argv[current+1], &endp, 10);
296 len = snprintf(errstr, buflen,
305 } else if (strcmp("gid", argv[current]) == 0) {
306 if (current + 2 > argc) {
307 len = snprintf(errstr, buflen, "gid short");
310 grp = getgrnam(argv[current+1]);
314 value = strtol(argv[current+1], &endp, 10);
316 len = snprintf(errstr, buflen,
326 len = snprintf(errstr, buflen, "'%s' not expected",
331 /* Onto optional second phrase. */
332 if (current + 1 < argc) {
333 /* Second phrase: uid [uid] or gid [gid], but not a repeat. */
334 if (strcmp("uid", argv[current]) == 0) {
336 len = snprintf(errstr, buflen,
337 "Only one uid permitted per identity clause");
340 if (current + 2 > argc) {
341 len = snprintf(errstr, buflen, "uid short");
344 pwd = getpwnam(argv[current+1]);
348 value = strtol(argv[current+1], &endp, 10);
350 len = snprintf(errstr, buflen,
359 } else if (strcmp("gid", argv[current]) == 0) {
361 len = snprintf(errstr, buflen,
362 "Only one gid permitted per identity clause");
365 if (current + 2 > argc) {
366 len = snprintf(errstr, buflen, "gid short");
369 grp = getgrnam(argv[current+1]);
373 value = strtol(argv[current+1], &endp, 10);
375 len = snprintf(errstr, buflen,
385 len = snprintf(errstr, buflen, "'%s' not expected",
391 if (current +1 < argc) {
392 len = snprintf(errstr, buflen, "'%s' not expected",
397 /* Fill out the identity. */
398 identity->mbi_flags = 0;
401 identity->mbi_flags |= MBI_NEGATED;
404 identity->mbi_flags |= MBI_UID_DEFINED;
405 identity->mbi_uid = uid;
407 identity->mbi_uid = 0;
410 identity->mbi_flags |= MBI_GID_DEFINED;
411 identity->mbi_gid = gid;
413 identity->mbi_gid = 0;
419 bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
426 len = snprintf(errstr, buflen, "mode expects mode value");
431 len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
436 for (i = 0; i < strlen(argv[0]); i++) {
437 switch (argv[0][i]) {
457 len = snprintf(errstr, buflen, "Unknown mode letter: %c",
467 bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
468 size_t buflen, char *errstr)
470 int subject, subject_elements, subject_elements_length;
471 int object, object_elements, object_elements_length;
472 int mode, mode_elements, mode_elements_length;
476 bzero(rule, sizeof(*rule));
479 len = snprintf(errstr, buflen, "Rule must begin with subject");
483 if (strcmp(argv[0], "subject") != 0) {
484 len = snprintf(errstr, buflen, "Rule must begin with subject");
488 subject_elements = 1;
490 /* Search forward for object. */
493 for (i = 1; i < argc; i++)
494 if (strcmp(argv[i], "object") == 0)
498 len = snprintf(errstr, buflen, "Rule must contain an object");
502 /* Search forward for mode. */
504 for (i = object; i < argc; i++)
505 if (strcmp(argv[i], "mode") == 0)
509 len = snprintf(errstr, buflen, "Rule must contain mode");
513 subject_elements_length = object - subject - 1;
514 object_elements = object + 1;
515 object_elements_length = mode - object_elements;
516 mode_elements = mode + 1;
517 mode_elements_length = argc - mode_elements;
519 error = bsde_parse_identity(subject_elements_length,
520 argv + subject_elements, &rule->mbr_subject, buflen, errstr);
524 error = bsde_parse_identity(object_elements_length,
525 argv + object_elements, &rule->mbr_object, buflen, errstr);
529 error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
530 &rule->mbr_mode, buflen, errstr);
538 bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
539 size_t buflen, char *errstr)
541 char *stringdup, *stringp, *argv[20], **ap;
544 stringp = stringdup = strdup(string);
545 while (*stringp == ' ' || *stringp == '\t')
549 for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
552 if (++ap >= &argv[20])
556 error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
564 bsde_get_mib(const char *string, int *name, size_t *namelen)
570 error = sysctlnametomib(string, name, &len);
579 bsde_get_rule_count(size_t buflen, char *errstr)
585 len = sizeof(rule_count);
586 error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0);
588 len = snprintf(errstr, buflen, strerror(errno));
591 if (len != sizeof(rule_count)) {
592 len = snprintf(errstr, buflen, "Data error in %s.rule_count",
601 bsde_get_rule_slots(size_t buflen, char *errstr)
607 len = sizeof(rule_slots);
608 error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0);
610 len = snprintf(errstr, buflen, strerror(errno));
613 if (len != sizeof(rule_slots)) {
614 len = snprintf(errstr, buflen, "Data error in %s.rule_slots",
623 * Returns 0 for success;
624 * Returns -1 for failure;
625 * Returns -2 for not present
628 bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
636 error = bsde_get_mib(MIB ".rules", name, &len);
638 len = snprintf(errstr, errlen, "%s: %s", MIB ".rules",
643 size = sizeof(*rule);
646 error = sysctl(name, len, rule, &size, NULL, 0);
647 if (error == -1 && errno == ENOENT)
650 len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
651 rulenum, strerror(errno));
653 } else if (size != sizeof(*rule)) {
654 len = snprintf(errstr, errlen, "Data error in %s.%d: %s",
655 MIB ".rules", rulenum, strerror(errno));
663 bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
665 struct mac_bsdextended_rule rule;
671 error = bsde_get_mib(MIB ".rules", name, &len);
673 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
682 error = sysctl(name, len, NULL, NULL, &rule, 0);
684 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
685 rulenum, strerror(errno));
693 bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
701 error = bsde_get_mib(MIB ".rules", name, &len);
703 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
711 size = sizeof(*rule);
712 error = sysctl(name, len, NULL, NULL, rule, size);
714 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
715 rulenum, strerror(errno));
723 bsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
726 char charstr[BUFSIZ];
729 int error, rule_slots;
732 error = bsde_get_mib(MIB ".rules", name, &len);
734 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
739 rule_slots = bsde_get_rule_slots(BUFSIZ, charstr);
740 if (rule_slots == -1) {
741 len = snprintf(errstr, buflen, "unable to get rule slots: %s",
746 name[len] = rule_slots;
749 size = sizeof(*rule);
750 error = sysctl(name, len, NULL, NULL, rule, size);
752 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
753 rule_slots, strerror(errno));
758 *rulenum = rule_slots;