summaryrefslogtreecommitdiffstats
path: root/lib/libugidfw/ugidfw.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2002-08-02 07:07:35 +0000
committerrwatson <rwatson@FreeBSD.org>2002-08-02 07:07:35 +0000
commitb7b34f0249a032f6c94fa9df4cfae423ecc7e858 (patch)
treee87c80445768700c60db8fc03f43919fd5db3939 /lib/libugidfw/ugidfw.c
parentc75c0a4c248f5f063db09eefea72a22b79f9c471 (diff)
downloadFreeBSD-src-b7b34f0249a032f6c94fa9df4cfae423ecc7e858.zip
FreeBSD-src-b7b34f0249a032f6c94fa9df4cfae423ecc7e858.tar.gz
Introduce support for Mandatory Access Control and extensible
kernel access control. Provide a library to manage user file system firewall-like rules supported by the mac_bsdextended.ko security model. The kernel module exports the current rule set using sysctl, and this library provides a front end that includes support for retrieving and setting rules, as well as printing and parsing them. Note: as with other userland components, this is a WIP. However, when used in combination with the soon-to-be-committed ugidfw, it can actually be quite useful in multi-user environments to allow the administrator to limit inter-user file operations without resorting to heavier weight labeled security policies. Obtained form: TrustedBSD Project Sponsored by: DARPA, NAI Labs
Diffstat (limited to 'lib/libugidfw/ugidfw.c')
-rw-r--r--lib/libugidfw/ugidfw.c712
1 files changed, 712 insertions, 0 deletions
diff --git a/lib/libugidfw/ugidfw.c b/lib/libugidfw/ugidfw.c
new file mode 100644
index 0000000..91c6fe5
--- /dev/null
+++ b/lib/libugidfw/ugidfw.c
@@ -0,0 +1,712 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by NAI Labs, the
+ * Security Research Division of Network Associates, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+
+#include <security/mac_bsdextended/mac_bsdextended.h>
+
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ugidfw.h>
+
+/*
+ * Text format for rules: rules contain subjectand object elements, mode.
+ * Each element takes the form "[not] [uid number] [gid number]".
+ * The total form is "subject [element] object [element] mode [mode]".
+ * At least * one of a uid or gid entry must be present; both may also be
+ * present.
+ */
+
+#define MIB "security.mac.bsdextended"
+
+int
+bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
+{
+ struct group *grp;
+ struct passwd *pwd;
+ char *cur;
+ size_t left, len;
+ int anymode, unknownmode, truncated;
+
+ cur = buf;
+ left = buflen;
+ truncated = 0;
+
+ if (rule->mbr_subject.mbi_flags & (MBI_UID_DEFINED |
+ MBI_GID_DEFINED)) {
+ len = snprintf(cur, left, "subject ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+
+ if (rule->mbr_subject.mbi_flags & MBI_NEGATED) {
+ len = snprintf(cur, left, "not ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
+ pwd = getpwuid(rule->mbr_subject.mbi_uid);
+ if (pwd != NULL) {
+ len = snprintf(cur, left, "uid %s ",
+ pwd->pw_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, "uid %u ",
+ rule->mbr_subject.mbi_uid);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+ if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
+ grp = getgrgid(rule->mbr_subject.mbi_gid);
+ if (grp != NULL) {
+ len = snprintf(cur, left, "gid %s ",
+ grp->gr_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, "gid %u ",
+ rule->mbr_subject.mbi_gid);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+ }
+ if (rule->mbr_object.mbi_flags & (MBI_UID_DEFINED |
+ MBI_GID_DEFINED)) {
+ len = snprintf(cur, left, "object ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+
+ if (rule->mbr_object.mbi_flags & MBI_NEGATED) {
+ len = snprintf(cur, left, "not ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
+ pwd = getpwuid(rule->mbr_object.mbi_uid);
+ if (pwd != NULL) {
+ len = snprintf(cur, left, "uid %s ",
+ pwd->pw_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, "uid %u ",
+ rule->mbr_object.mbi_uid);
+ left -= len;
+ cur += len;
+ }
+ }
+ if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
+ grp = getgrgid(rule->mbr_object.mbi_gid);
+ if (grp != NULL) {
+ len = snprintf(cur, left, "gid %s ",
+ grp->gr_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, "gid %u ",
+ rule->mbr_object.mbi_gid);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+ }
+
+ len = snprintf(cur, left, "mode ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+
+ anymode = (rule->mbr_mode & VALLPERM);
+ unknownmode = (rule->mbr_mode & ~VALLPERM);
+
+ if (rule->mbr_mode & VADMIN) {
+ len = snprintf(cur, left, "a");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_mode & VREAD) {
+ len = snprintf(cur, left, "r");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_mode & VSTAT) {
+ len = snprintf(cur, left, "s");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_mode & VWRITE) {
+ len = snprintf(cur, left, "w");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_mode & VEXEC) {
+ len = snprintf(cur, left, "x");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (!anymode) {
+ len = snprintf(cur, left, "n");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (unknownmode) {
+ len = snprintf(cur, left, "?");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+
+ return (0);
+
+truncated:
+ return (-1);
+}
+
+int
+bsde_parse_identity(int argc, char *argv[],
+ struct mac_bsdextended_identity *identity, size_t buflen, char *errstr)
+{
+ struct group *grp;
+ struct passwd *pwd;
+ int uid_seen, gid_seen, not_seen;
+ int current;
+ char *endp;
+ long value;
+ uid_t uid;
+ gid_t gid;
+ size_t len;
+
+ if (argc == 0) {
+ len = snprintf(errstr, buflen, "Identity must not be empty");
+ return (-1);
+ }
+
+ current = 0;
+
+ /* First element might be "not". */
+ if (strcmp("not", argv[0]) == 0) {
+ not_seen = 1;
+ current++;
+ } else
+ not_seen = 0;
+
+ if (current >= argc) {
+ len = snprintf(errstr, buflen, "Identity short");
+ return (-1);
+ }
+
+ uid_seen = 0;
+ uid = 0;
+ gid_seen = 0;
+ gid = 0;
+
+ /* First phrase: uid [uid] or gid[gid]. */
+ if (strcmp("uid", argv[current]) == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "uid short");
+ return (-1);
+ }
+ pwd = getpwnam(argv[current+1]);
+ if (pwd != NULL)
+ uid = pwd->pw_uid;
+ else {
+ value = strtol(argv[current+1], &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen,
+ "invalid uid: '%s'",
+ argv[current+1]);
+ return (-1);
+ }
+ uid = value;
+ }
+ uid_seen = 1;
+ current += 2;
+ } else if (strcmp("gid", argv[current]) == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "gid short");
+ return (-1);
+ }
+ grp = getgrnam(argv[current+1]);
+ if (grp != NULL)
+ gid = grp->gr_gid;
+ else {
+ value = strtol(argv[current+1], &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen,
+ "invalid gid: '%s'",
+ argv[current+1]);
+ return (-1);
+ }
+ gid = value;
+ }
+ gid_seen = 1;
+ current += 2;
+ } else {
+ len = snprintf(errstr, buflen, "'%s' not expected",
+ argv[current]);
+ return (-1);
+ }
+
+ /* Onto optional second phrase. */
+ if (current + 1 < argc) {
+ /* Second phrase: uid [uid] or gid [gid], but not a repeat. */
+ if (strcmp("uid", argv[current]) == 0) {
+ if (uid_seen) {
+ len = snprintf(errstr, buflen,
+ "Only one uid permitted per identity clause");
+ return (-1);
+ }
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "uid short");
+ return (-1);
+ }
+ value = strtol(argv[current+1], &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen, "invalid uid: '%s'",
+ argv[current+1]);
+ return (-1);
+ }
+ uid = value;
+ uid_seen = 1;
+ current += 2;
+ } else if (strcmp("gid", argv[current]) == 0) {
+ if (gid_seen) {
+ len = snprintf(errstr, buflen,
+ "Only one gid permitted per identity clause");
+ return (-1);
+ }
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "gid short");
+ return (-1);
+ }
+ value = strtol(argv[current+1], &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen, "invalid gid: '%s'",
+ argv[current+1]);
+ return (-1);
+ }
+ gid = value;
+ gid_seen = 1;
+ current += 2;
+ } else {
+ len = snprintf(errstr, buflen, "'%s' not expected",
+ argv[current]);
+ return (-1);
+ }
+ }
+
+ if (current +1 < argc) {
+ len = snprintf(errstr, buflen, "'%s' not expected",
+ argv[current]);
+ return (-1);
+ }
+
+ /* Fill out the identity. */
+ identity->mbi_flags = 0;
+
+ if (not_seen)
+ identity->mbi_flags |= MBI_NEGATED;
+
+ if (uid_seen) {
+ identity->mbi_flags |= MBI_UID_DEFINED;
+ identity->mbi_uid = uid;
+ } else
+ identity->mbi_uid = 0;
+
+ if (gid_seen) {
+ identity->mbi_flags |= MBI_GID_DEFINED;
+ identity->mbi_gid = gid;
+ } else
+ identity->mbi_gid = 0;
+
+ return (0);
+}
+
+int
+bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
+ char *errstr)
+{
+ size_t len;
+ int i;
+
+ if (argc == 0) {
+ len = snprintf(errstr, buflen, "mode expects mode value");
+ return (-1);
+ }
+
+ if (argc != 1) {
+ len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
+ return (-1);
+ }
+
+ *mode = 0;
+ for (i = 0; i < strlen(argv[0]); i++) {
+ switch (argv[0][i]) {
+ case 'a':
+ *mode |= VADMIN;
+ break;
+ case 'r':
+ *mode |= VREAD;
+ break;
+ case 's':
+ *mode |= VSTAT;
+ break;
+ case 'w':
+ *mode |= VWRITE;
+ break;
+ case 'x':
+ *mode |= VEXEC;
+ break;
+ case 'n':
+ /* ignore */
+ break;
+ default:
+ len = snprintf(errstr, buflen, "Unknown mode letter: %c",
+ argv[0][i]);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int
+bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
+ size_t buflen, char *errstr)
+{
+ int subject, subject_elements, subject_elements_length;
+ int object, object_elements, object_elements_length;
+ int mode, mode_elements, mode_elements_length;
+ int error, i;
+ size_t len;
+
+ bzero(rule, sizeof(*rule));
+
+ if (argc < 1) {
+ len = snprintf(errstr, buflen, "Rule must begin with subject");
+ return (-1);
+ }
+
+ if (strcmp(argv[0], "subject") != 0) {
+ len = snprintf(errstr, buflen, "Rule must begin with subject");
+ return (-1);
+ }
+ subject = 0;
+ subject_elements = 1;
+
+ /* Search forward for object. */
+
+ object = -1;
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "object") == 0)
+ object = i;
+
+ if (object == -1) {
+ len = snprintf(errstr, buflen, "Rule must contain an object");
+ return (-1);
+ }
+
+ /* Search forward for mode. */
+ mode = -1;
+ for (i = object; i < argc; i++)
+ if (strcmp(argv[i], "mode") == 0)
+ mode = i;
+
+ if (mode == -1) {
+ len = snprintf(errstr, buflen, "Rule must contain mode");
+ return (-1);
+ }
+
+ subject_elements_length = object - subject - 1;
+ object_elements = object + 1;
+ object_elements_length = mode - object_elements;
+ mode_elements = mode + 1;
+ mode_elements_length = argc - mode_elements;
+
+ error = bsde_parse_identity(subject_elements_length,
+ argv + subject_elements, &rule->mbr_subject, buflen, errstr);
+ if (error)
+ return (-1);
+
+ error = bsde_parse_identity(object_elements_length,
+ argv + object_elements, &rule->mbr_object, buflen, errstr);
+ if (error)
+ return (-1);
+
+ error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
+ &rule->mbr_mode, buflen, errstr);
+ if (error)
+ return (-1);
+
+ return (0);
+}
+
+int
+bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
+ size_t buflen, char *errstr)
+{
+ char *stringdup, *stringp, *argv[20], **ap;
+ int argc, error;
+
+ stringp = stringdup = strdup(string);
+ while (*stringp == ' ' || *stringp == '\t')
+ stringp++;
+
+ argc = 0;
+ for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
+ argc++;
+ if (**ap != '\0')
+ if (++ap >= &argv[20])
+ break;
+ }
+
+ error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
+
+ free(stringdup);
+
+ return (error);
+}
+
+int
+bsde_get_mib(const char *string, int *name, int *namelen)
+{
+ int error, len;
+
+ len = *namelen;
+ error = sysctlnametomib(string, name, &len);
+ if (error)
+ return (error);
+
+ *namelen = len;
+ return (0);
+}
+
+int
+bsde_get_rule_count(size_t buflen, char *errstr)
+{
+ size_t len;
+ int error;
+ int rule_count;
+
+ len = sizeof(rule_count);
+ error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, NULL);
+ if (error) {
+ len = snprintf(errstr, buflen, strerror(errno));
+ return (-1);
+ }
+ if (len != sizeof(rule_count)) {
+ len = snprintf(errstr, buflen, "Data error in %s.rule_count",
+ MIB);
+ return (-1);
+ }
+
+ return (rule_count);
+}
+
+int
+bsde_get_rule_slots(size_t buflen, char *errstr)
+{
+ size_t len;
+ int error;
+ int rule_slots;
+
+ len = sizeof(rule_slots);
+ error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL,
+ NULL);
+ if (error) {
+ len = snprintf(errstr, buflen, strerror(errno));
+ return (-1);
+ }
+ if (len != sizeof(rule_slots)) {
+ len = snprintf(errstr, buflen, "Data error in %s.rule_slots",
+ MIB);
+ return (-1);
+ }
+
+ return (rule_slots);
+}
+
+/*
+ * Returns 0 for success;
+ * Returns -1 for failure;
+ * Returns -2 for not present
+ */
+int
+bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
+ char *errstr)
+{
+ int name[10];
+ size_t len, size;
+ int error;
+
+ len = 10;
+ error = bsde_get_mib(MIB ".rules", name, &len);
+ if (error) {
+ len = snprintf(errstr, errlen, "%s: %s", MIB ".rules",
+ strerror(errno));
+ return (-1);
+ }
+
+ size = sizeof(*rule);
+ name[len] = rulenum;
+ len++;
+ error = sysctl(name, len, rule, &size, NULL, 0);
+ if (error == -1 && errno == ENOENT)
+ return (-2);
+ if (error) {
+ len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
+ rulenum, strerror(errno));
+ return (-1);
+ } else if (size != sizeof(*rule)) {
+ len = snprintf(errstr, errlen, "Data error in %s.%d: %s",
+ MIB ".rules", rulenum, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
+{
+ struct mac_bsdextended_rule rule;
+ int name[10];
+ size_t len, size;
+ int error;
+
+ len = 10;
+ error = bsde_get_mib(MIB ".rules", name, &len);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
+ strerror(errno));
+ return (-1);
+ }
+
+ name[len] = rulenum;
+ len++;
+
+ size = sizeof(rule);
+ error = sysctl(name, len, NULL, NULL, &rule, 0);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
+ rulenum, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
+ char *errstr)
+{
+ int name[10];
+ size_t len, size;
+ int error;
+
+ len = 10;
+ error = bsde_get_mib(MIB ".rules", name, &len);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
+ strerror(errno));
+ return (-1);
+ }
+
+ name[len] = rulenum;
+ len++;
+
+ size = sizeof(*rule);
+ error = sysctl(name, len, NULL, NULL, rule, size);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
+ rulenum, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
OpenPOWER on IntegriCloud