146d1a925SRobert Watson /*- 247ab23aaSRobert Watson * Copyright (c) 2002, 2004 Networks Associates Technology, Inc. 346d1a925SRobert Watson * All rights reserved. 446d1a925SRobert Watson * 50285334bSRobert Watson * This software was developed for the FreeBSD Project by Network Associates 60285334bSRobert Watson * Laboratories, the Security Research Division of Network Associates, Inc. 70285334bSRobert Watson * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 80285334bSRobert Watson * DARPA CHATS research program. 946d1a925SRobert Watson * 1046d1a925SRobert Watson * Redistribution and use in source and binary forms, with or without 1146d1a925SRobert Watson * modification, are permitted provided that the following conditions 1246d1a925SRobert Watson * are met: 1346d1a925SRobert Watson * 1. Redistributions of source code must retain the above copyright 1446d1a925SRobert Watson * notice, this list of conditions and the following disclaimer. 1546d1a925SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 1646d1a925SRobert Watson * notice, this list of conditions and the following disclaimer in the 1746d1a925SRobert Watson * documentation and/or other materials provided with the distribution. 1846d1a925SRobert Watson * 1946d1a925SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2046d1a925SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2146d1a925SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2246d1a925SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2346d1a925SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2446d1a925SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2546d1a925SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2646d1a925SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2746d1a925SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2846d1a925SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2946d1a925SRobert Watson * SUCH DAMAGE. 3046d1a925SRobert Watson * 3146d1a925SRobert Watson * $FreeBSD$ 3246d1a925SRobert Watson */ 3346d1a925SRobert Watson #include <sys/param.h> 3446d1a925SRobert Watson #include <sys/errno.h> 3546d1a925SRobert Watson #include <sys/time.h> 3646d1a925SRobert Watson #include <sys/sysctl.h> 3746d1a925SRobert Watson 3846d1a925SRobert Watson #include <security/mac_bsdextended/mac_bsdextended.h> 3946d1a925SRobert Watson 4046d1a925SRobert Watson #include <grp.h> 4146d1a925SRobert Watson #include <pwd.h> 4246d1a925SRobert Watson #include <stdio.h> 4346d1a925SRobert Watson #include <stdlib.h> 4446d1a925SRobert Watson #include <string.h> 4546d1a925SRobert Watson 46912dd12aSRobert Watson #include "ugidfw.h" 4746d1a925SRobert Watson 4846d1a925SRobert Watson /* 4946d1a925SRobert Watson * Text format for rules: rules contain subjectand object elements, mode. 5046d1a925SRobert Watson * Each element takes the form "[not] [uid number] [gid number]". 5146d1a925SRobert Watson * The total form is "subject [element] object [element] mode [mode]". 5246d1a925SRobert Watson * At least * one of a uid or gid entry must be present; both may also be 5346d1a925SRobert Watson * present. 5446d1a925SRobert Watson */ 5546d1a925SRobert Watson 5646d1a925SRobert Watson #define MIB "security.mac.bsdextended" 5746d1a925SRobert Watson 5846d1a925SRobert Watson int 5946d1a925SRobert Watson bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen) 6046d1a925SRobert Watson { 6146d1a925SRobert Watson struct group *grp; 6246d1a925SRobert Watson struct passwd *pwd; 6346d1a925SRobert Watson char *cur; 6446d1a925SRobert Watson size_t left, len; 6546d1a925SRobert Watson int anymode, unknownmode, truncated; 6646d1a925SRobert Watson 6746d1a925SRobert Watson cur = buf; 6846d1a925SRobert Watson left = buflen; 6946d1a925SRobert Watson truncated = 0; 7046d1a925SRobert Watson 7146d1a925SRobert Watson if (rule->mbr_subject.mbi_flags & (MBI_UID_DEFINED | 7246d1a925SRobert Watson MBI_GID_DEFINED)) { 7346d1a925SRobert Watson len = snprintf(cur, left, "subject "); 7446d1a925SRobert Watson if (len < 0 || len > left) 7546d1a925SRobert Watson goto truncated; 7646d1a925SRobert Watson left -= len; 7746d1a925SRobert Watson cur += len; 7846d1a925SRobert Watson 7946d1a925SRobert Watson if (rule->mbr_subject.mbi_flags & MBI_NEGATED) { 8046d1a925SRobert Watson len = snprintf(cur, left, "not "); 8146d1a925SRobert Watson if (len < 0 || len > left) 8246d1a925SRobert Watson goto truncated; 8346d1a925SRobert Watson left -= len; 8446d1a925SRobert Watson cur += len; 8546d1a925SRobert Watson } 8646d1a925SRobert Watson if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) { 8746d1a925SRobert Watson pwd = getpwuid(rule->mbr_subject.mbi_uid); 8846d1a925SRobert Watson if (pwd != NULL) { 8946d1a925SRobert Watson len = snprintf(cur, left, "uid %s ", 9046d1a925SRobert Watson pwd->pw_name); 9146d1a925SRobert Watson if (len < 0 || len > left) 9246d1a925SRobert Watson goto truncated; 9346d1a925SRobert Watson left -= len; 9446d1a925SRobert Watson cur += len; 9546d1a925SRobert Watson } else { 9646d1a925SRobert Watson len = snprintf(cur, left, "uid %u ", 9746d1a925SRobert Watson rule->mbr_subject.mbi_uid); 9846d1a925SRobert Watson if (len < 0 || len > left) 9946d1a925SRobert Watson goto truncated; 10046d1a925SRobert Watson left -= len; 10146d1a925SRobert Watson cur += len; 10246d1a925SRobert Watson } 10346d1a925SRobert Watson } 10446d1a925SRobert Watson if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) { 10546d1a925SRobert Watson grp = getgrgid(rule->mbr_subject.mbi_gid); 10646d1a925SRobert Watson if (grp != NULL) { 10746d1a925SRobert Watson len = snprintf(cur, left, "gid %s ", 10846d1a925SRobert Watson grp->gr_name); 10946d1a925SRobert Watson if (len < 0 || len > left) 11046d1a925SRobert Watson goto truncated; 11146d1a925SRobert Watson left -= len; 11246d1a925SRobert Watson cur += len; 11346d1a925SRobert Watson } else { 11446d1a925SRobert Watson len = snprintf(cur, left, "gid %u ", 11546d1a925SRobert Watson rule->mbr_subject.mbi_gid); 11646d1a925SRobert Watson if (len < 0 || len > left) 11746d1a925SRobert Watson goto truncated; 11846d1a925SRobert Watson left -= len; 11946d1a925SRobert Watson cur += len; 12046d1a925SRobert Watson } 12146d1a925SRobert Watson } 12246d1a925SRobert Watson } 12346d1a925SRobert Watson if (rule->mbr_object.mbi_flags & (MBI_UID_DEFINED | 12446d1a925SRobert Watson MBI_GID_DEFINED)) { 12546d1a925SRobert Watson len = snprintf(cur, left, "object "); 12646d1a925SRobert Watson if (len < 0 || len > left) 12746d1a925SRobert Watson goto truncated; 12846d1a925SRobert Watson left -= len; 12946d1a925SRobert Watson cur += len; 13046d1a925SRobert Watson 13146d1a925SRobert Watson if (rule->mbr_object.mbi_flags & MBI_NEGATED) { 13246d1a925SRobert Watson len = snprintf(cur, left, "not "); 13346d1a925SRobert Watson if (len < 0 || len > left) 13446d1a925SRobert Watson goto truncated; 13546d1a925SRobert Watson left -= len; 13646d1a925SRobert Watson cur += len; 13746d1a925SRobert Watson } 13846d1a925SRobert Watson if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) { 13946d1a925SRobert Watson pwd = getpwuid(rule->mbr_object.mbi_uid); 14046d1a925SRobert Watson if (pwd != NULL) { 14146d1a925SRobert Watson len = snprintf(cur, left, "uid %s ", 14246d1a925SRobert Watson pwd->pw_name); 14346d1a925SRobert Watson if (len < 0 || len > left) 14446d1a925SRobert Watson goto truncated; 14546d1a925SRobert Watson left -= len; 14646d1a925SRobert Watson cur += len; 14746d1a925SRobert Watson } else { 14846d1a925SRobert Watson len = snprintf(cur, left, "uid %u ", 14946d1a925SRobert Watson rule->mbr_object.mbi_uid); 15046d1a925SRobert Watson left -= len; 15146d1a925SRobert Watson cur += len; 15246d1a925SRobert Watson } 15346d1a925SRobert Watson } 15446d1a925SRobert Watson if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) { 15546d1a925SRobert Watson grp = getgrgid(rule->mbr_object.mbi_gid); 15646d1a925SRobert Watson if (grp != NULL) { 15746d1a925SRobert Watson len = snprintf(cur, left, "gid %s ", 15846d1a925SRobert Watson grp->gr_name); 15946d1a925SRobert Watson if (len < 0 || len > left) 16046d1a925SRobert Watson goto truncated; 16146d1a925SRobert Watson left -= len; 16246d1a925SRobert Watson cur += len; 16346d1a925SRobert Watson } else { 16446d1a925SRobert Watson len = snprintf(cur, left, "gid %u ", 16546d1a925SRobert Watson rule->mbr_object.mbi_gid); 16646d1a925SRobert Watson if (len < 0 || len > left) 16746d1a925SRobert Watson goto truncated; 16846d1a925SRobert Watson left -= len; 16946d1a925SRobert Watson cur += len; 17046d1a925SRobert Watson } 17146d1a925SRobert Watson } 17246d1a925SRobert Watson } 17346d1a925SRobert Watson 17446d1a925SRobert Watson len = snprintf(cur, left, "mode "); 17546d1a925SRobert Watson if (len < 0 || len > left) 17646d1a925SRobert Watson goto truncated; 17746d1a925SRobert Watson left -= len; 17846d1a925SRobert Watson cur += len; 17946d1a925SRobert Watson 180f4194603SRobert Watson anymode = (rule->mbr_mode & MBI_ALLPERM); 181f4194603SRobert Watson unknownmode = (rule->mbr_mode & ~MBI_ALLPERM); 18246d1a925SRobert Watson 183f4194603SRobert Watson if (rule->mbr_mode & MBI_ADMIN) { 18446d1a925SRobert Watson len = snprintf(cur, left, "a"); 18546d1a925SRobert Watson if (len < 0 || len > left) 18646d1a925SRobert Watson goto truncated; 18746d1a925SRobert Watson 18846d1a925SRobert Watson left -= len; 18946d1a925SRobert Watson cur += len; 19046d1a925SRobert Watson } 191f4194603SRobert Watson if (rule->mbr_mode & MBI_READ) { 19246d1a925SRobert Watson len = snprintf(cur, left, "r"); 19346d1a925SRobert Watson if (len < 0 || len > left) 19446d1a925SRobert Watson goto truncated; 19546d1a925SRobert Watson 19646d1a925SRobert Watson left -= len; 19746d1a925SRobert Watson cur += len; 19846d1a925SRobert Watson } 199f4194603SRobert Watson if (rule->mbr_mode & MBI_STAT) { 20046d1a925SRobert Watson len = snprintf(cur, left, "s"); 20146d1a925SRobert Watson if (len < 0 || len > left) 20246d1a925SRobert Watson goto truncated; 20346d1a925SRobert Watson 20446d1a925SRobert Watson left -= len; 20546d1a925SRobert Watson cur += len; 20646d1a925SRobert Watson } 207f4194603SRobert Watson if (rule->mbr_mode & MBI_WRITE) { 20846d1a925SRobert Watson len = snprintf(cur, left, "w"); 20946d1a925SRobert Watson if (len < 0 || len > left) 21046d1a925SRobert Watson goto truncated; 21146d1a925SRobert Watson 21246d1a925SRobert Watson left -= len; 21346d1a925SRobert Watson cur += len; 21446d1a925SRobert Watson } 215f4194603SRobert Watson if (rule->mbr_mode & MBI_EXEC) { 21646d1a925SRobert Watson len = snprintf(cur, left, "x"); 21746d1a925SRobert Watson if (len < 0 || len > left) 21846d1a925SRobert Watson goto truncated; 21946d1a925SRobert Watson 22046d1a925SRobert Watson left -= len; 22146d1a925SRobert Watson cur += len; 22246d1a925SRobert Watson } 22346d1a925SRobert Watson if (!anymode) { 22446d1a925SRobert Watson len = snprintf(cur, left, "n"); 22546d1a925SRobert Watson if (len < 0 || len > left) 22646d1a925SRobert Watson goto truncated; 22746d1a925SRobert Watson 22846d1a925SRobert Watson left -= len; 22946d1a925SRobert Watson cur += len; 23046d1a925SRobert Watson } 23146d1a925SRobert Watson if (unknownmode) { 23246d1a925SRobert Watson len = snprintf(cur, left, "?"); 23346d1a925SRobert Watson if (len < 0 || len > left) 23446d1a925SRobert Watson goto truncated; 23546d1a925SRobert Watson 23646d1a925SRobert Watson left -= len; 23746d1a925SRobert Watson cur += len; 23846d1a925SRobert Watson } 23946d1a925SRobert Watson 24046d1a925SRobert Watson return (0); 24146d1a925SRobert Watson 24246d1a925SRobert Watson truncated: 24346d1a925SRobert Watson return (-1); 24446d1a925SRobert Watson } 24546d1a925SRobert Watson 24646d1a925SRobert Watson int 24746d1a925SRobert Watson bsde_parse_identity(int argc, char *argv[], 24846d1a925SRobert Watson struct mac_bsdextended_identity *identity, size_t buflen, char *errstr) 24946d1a925SRobert Watson { 25046d1a925SRobert Watson struct group *grp; 25146d1a925SRobert Watson struct passwd *pwd; 25246d1a925SRobert Watson int uid_seen, gid_seen, not_seen; 25346d1a925SRobert Watson int current; 25446d1a925SRobert Watson char *endp; 25546d1a925SRobert Watson long value; 25646d1a925SRobert Watson uid_t uid; 25746d1a925SRobert Watson gid_t gid; 25846d1a925SRobert Watson size_t len; 25946d1a925SRobert Watson 26046d1a925SRobert Watson if (argc == 0) { 26146d1a925SRobert Watson len = snprintf(errstr, buflen, "Identity must not be empty"); 26246d1a925SRobert Watson return (-1); 26346d1a925SRobert Watson } 26446d1a925SRobert Watson 26546d1a925SRobert Watson current = 0; 26646d1a925SRobert Watson 26746d1a925SRobert Watson /* First element might be "not". */ 26846d1a925SRobert Watson if (strcmp("not", argv[0]) == 0) { 26946d1a925SRobert Watson not_seen = 1; 27046d1a925SRobert Watson current++; 27146d1a925SRobert Watson } else 27246d1a925SRobert Watson not_seen = 0; 27346d1a925SRobert Watson 27446d1a925SRobert Watson if (current >= argc) { 27546d1a925SRobert Watson len = snprintf(errstr, buflen, "Identity short"); 27646d1a925SRobert Watson return (-1); 27746d1a925SRobert Watson } 27846d1a925SRobert Watson 27946d1a925SRobert Watson uid_seen = 0; 28046d1a925SRobert Watson uid = 0; 28146d1a925SRobert Watson gid_seen = 0; 28246d1a925SRobert Watson gid = 0; 28346d1a925SRobert Watson 28446d1a925SRobert Watson /* First phrase: uid [uid] or gid[gid]. */ 28546d1a925SRobert Watson if (strcmp("uid", argv[current]) == 0) { 28646d1a925SRobert Watson if (current + 2 > argc) { 28746d1a925SRobert Watson len = snprintf(errstr, buflen, "uid short"); 28846d1a925SRobert Watson return (-1); 28946d1a925SRobert Watson } 29046d1a925SRobert Watson pwd = getpwnam(argv[current+1]); 29146d1a925SRobert Watson if (pwd != NULL) 29246d1a925SRobert Watson uid = pwd->pw_uid; 29346d1a925SRobert Watson else { 29446d1a925SRobert Watson value = strtol(argv[current+1], &endp, 10); 29546d1a925SRobert Watson if (*endp != '\0') { 29646d1a925SRobert Watson len = snprintf(errstr, buflen, 29746d1a925SRobert Watson "invalid uid: '%s'", 29846d1a925SRobert Watson argv[current+1]); 29946d1a925SRobert Watson return (-1); 30046d1a925SRobert Watson } 30146d1a925SRobert Watson uid = value; 30246d1a925SRobert Watson } 30346d1a925SRobert Watson uid_seen = 1; 30446d1a925SRobert Watson current += 2; 30546d1a925SRobert Watson } else if (strcmp("gid", argv[current]) == 0) { 30646d1a925SRobert Watson if (current + 2 > argc) { 30746d1a925SRobert Watson len = snprintf(errstr, buflen, "gid short"); 30846d1a925SRobert Watson return (-1); 30946d1a925SRobert Watson } 31046d1a925SRobert Watson grp = getgrnam(argv[current+1]); 31146d1a925SRobert Watson if (grp != NULL) 31246d1a925SRobert Watson gid = grp->gr_gid; 31346d1a925SRobert Watson else { 31446d1a925SRobert Watson value = strtol(argv[current+1], &endp, 10); 31546d1a925SRobert Watson if (*endp != '\0') { 31646d1a925SRobert Watson len = snprintf(errstr, buflen, 31746d1a925SRobert Watson "invalid gid: '%s'", 31846d1a925SRobert Watson argv[current+1]); 31946d1a925SRobert Watson return (-1); 32046d1a925SRobert Watson } 32146d1a925SRobert Watson gid = value; 32246d1a925SRobert Watson } 32346d1a925SRobert Watson gid_seen = 1; 32446d1a925SRobert Watson current += 2; 32546d1a925SRobert Watson } else { 32646d1a925SRobert Watson len = snprintf(errstr, buflen, "'%s' not expected", 32746d1a925SRobert Watson argv[current]); 32846d1a925SRobert Watson return (-1); 32946d1a925SRobert Watson } 33046d1a925SRobert Watson 33146d1a925SRobert Watson /* Onto optional second phrase. */ 33246d1a925SRobert Watson if (current + 1 < argc) { 33346d1a925SRobert Watson /* Second phrase: uid [uid] or gid [gid], but not a repeat. */ 33446d1a925SRobert Watson if (strcmp("uid", argv[current]) == 0) { 33546d1a925SRobert Watson if (uid_seen) { 33646d1a925SRobert Watson len = snprintf(errstr, buflen, 33746d1a925SRobert Watson "Only one uid permitted per identity clause"); 33846d1a925SRobert Watson return (-1); 33946d1a925SRobert Watson } 34046d1a925SRobert Watson if (current + 2 > argc) { 34146d1a925SRobert Watson len = snprintf(errstr, buflen, "uid short"); 34246d1a925SRobert Watson return (-1); 34346d1a925SRobert Watson } 34446d1a925SRobert Watson value = strtol(argv[current+1], &endp, 10); 34546d1a925SRobert Watson if (*endp != '\0') { 34646d1a925SRobert Watson len = snprintf(errstr, buflen, "invalid uid: '%s'", 34746d1a925SRobert Watson argv[current+1]); 34846d1a925SRobert Watson return (-1); 34946d1a925SRobert Watson } 35046d1a925SRobert Watson uid = value; 35146d1a925SRobert Watson uid_seen = 1; 35246d1a925SRobert Watson current += 2; 35346d1a925SRobert Watson } else if (strcmp("gid", argv[current]) == 0) { 35446d1a925SRobert Watson if (gid_seen) { 35546d1a925SRobert Watson len = snprintf(errstr, buflen, 35646d1a925SRobert Watson "Only one gid permitted per identity clause"); 35746d1a925SRobert Watson return (-1); 35846d1a925SRobert Watson } 35946d1a925SRobert Watson if (current + 2 > argc) { 36046d1a925SRobert Watson len = snprintf(errstr, buflen, "gid short"); 36146d1a925SRobert Watson return (-1); 36246d1a925SRobert Watson } 36346d1a925SRobert Watson value = strtol(argv[current+1], &endp, 10); 36446d1a925SRobert Watson if (*endp != '\0') { 36546d1a925SRobert Watson len = snprintf(errstr, buflen, "invalid gid: '%s'", 36646d1a925SRobert Watson argv[current+1]); 36746d1a925SRobert Watson return (-1); 36846d1a925SRobert Watson } 36946d1a925SRobert Watson gid = value; 37046d1a925SRobert Watson gid_seen = 1; 37146d1a925SRobert Watson current += 2; 37246d1a925SRobert Watson } else { 37346d1a925SRobert Watson len = snprintf(errstr, buflen, "'%s' not expected", 37446d1a925SRobert Watson argv[current]); 37546d1a925SRobert Watson return (-1); 37646d1a925SRobert Watson } 37746d1a925SRobert Watson } 37846d1a925SRobert Watson 37946d1a925SRobert Watson if (current +1 < argc) { 38046d1a925SRobert Watson len = snprintf(errstr, buflen, "'%s' not expected", 38146d1a925SRobert Watson argv[current]); 38246d1a925SRobert Watson return (-1); 38346d1a925SRobert Watson } 38446d1a925SRobert Watson 38546d1a925SRobert Watson /* Fill out the identity. */ 38646d1a925SRobert Watson identity->mbi_flags = 0; 38746d1a925SRobert Watson 38846d1a925SRobert Watson if (not_seen) 38946d1a925SRobert Watson identity->mbi_flags |= MBI_NEGATED; 39046d1a925SRobert Watson 39146d1a925SRobert Watson if (uid_seen) { 39246d1a925SRobert Watson identity->mbi_flags |= MBI_UID_DEFINED; 39346d1a925SRobert Watson identity->mbi_uid = uid; 39446d1a925SRobert Watson } else 39546d1a925SRobert Watson identity->mbi_uid = 0; 39646d1a925SRobert Watson 39746d1a925SRobert Watson if (gid_seen) { 39846d1a925SRobert Watson identity->mbi_flags |= MBI_GID_DEFINED; 39946d1a925SRobert Watson identity->mbi_gid = gid; 40046d1a925SRobert Watson } else 40146d1a925SRobert Watson identity->mbi_gid = 0; 40246d1a925SRobert Watson 40346d1a925SRobert Watson return (0); 40446d1a925SRobert Watson } 40546d1a925SRobert Watson 40646d1a925SRobert Watson int 40746d1a925SRobert Watson bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen, 40846d1a925SRobert Watson char *errstr) 40946d1a925SRobert Watson { 41046d1a925SRobert Watson size_t len; 41146d1a925SRobert Watson int i; 41246d1a925SRobert Watson 41346d1a925SRobert Watson if (argc == 0) { 41446d1a925SRobert Watson len = snprintf(errstr, buflen, "mode expects mode value"); 41546d1a925SRobert Watson return (-1); 41646d1a925SRobert Watson } 41746d1a925SRobert Watson 41846d1a925SRobert Watson if (argc != 1) { 41946d1a925SRobert Watson len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]); 42046d1a925SRobert Watson return (-1); 42146d1a925SRobert Watson } 42246d1a925SRobert Watson 42346d1a925SRobert Watson *mode = 0; 42446d1a925SRobert Watson for (i = 0; i < strlen(argv[0]); i++) { 42546d1a925SRobert Watson switch (argv[0][i]) { 42646d1a925SRobert Watson case 'a': 427f4194603SRobert Watson *mode |= MBI_ADMIN; 42846d1a925SRobert Watson break; 42946d1a925SRobert Watson case 'r': 430f4194603SRobert Watson *mode |= MBI_READ; 43146d1a925SRobert Watson break; 43246d1a925SRobert Watson case 's': 433f4194603SRobert Watson *mode |= MBI_STAT; 43446d1a925SRobert Watson break; 43546d1a925SRobert Watson case 'w': 436f4194603SRobert Watson *mode |= MBI_WRITE; 43746d1a925SRobert Watson break; 43846d1a925SRobert Watson case 'x': 439f4194603SRobert Watson *mode |= MBI_EXEC; 44046d1a925SRobert Watson break; 44146d1a925SRobert Watson case 'n': 44246d1a925SRobert Watson /* ignore */ 44346d1a925SRobert Watson break; 44446d1a925SRobert Watson default: 44546d1a925SRobert Watson len = snprintf(errstr, buflen, "Unknown mode letter: %c", 44646d1a925SRobert Watson argv[0][i]); 44746d1a925SRobert Watson return (-1); 44846d1a925SRobert Watson } 44946d1a925SRobert Watson } 45046d1a925SRobert Watson 45146d1a925SRobert Watson return (0); 45246d1a925SRobert Watson } 45346d1a925SRobert Watson 45446d1a925SRobert Watson int 45546d1a925SRobert Watson bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule, 45646d1a925SRobert Watson size_t buflen, char *errstr) 45746d1a925SRobert Watson { 45846d1a925SRobert Watson int subject, subject_elements, subject_elements_length; 45946d1a925SRobert Watson int object, object_elements, object_elements_length; 46046d1a925SRobert Watson int mode, mode_elements, mode_elements_length; 46146d1a925SRobert Watson int error, i; 46246d1a925SRobert Watson size_t len; 46346d1a925SRobert Watson 46446d1a925SRobert Watson bzero(rule, sizeof(*rule)); 46546d1a925SRobert Watson 46646d1a925SRobert Watson if (argc < 1) { 46746d1a925SRobert Watson len = snprintf(errstr, buflen, "Rule must begin with subject"); 46846d1a925SRobert Watson return (-1); 46946d1a925SRobert Watson } 47046d1a925SRobert Watson 47146d1a925SRobert Watson if (strcmp(argv[0], "subject") != 0) { 47246d1a925SRobert Watson len = snprintf(errstr, buflen, "Rule must begin with subject"); 47346d1a925SRobert Watson return (-1); 47446d1a925SRobert Watson } 47546d1a925SRobert Watson subject = 0; 47646d1a925SRobert Watson subject_elements = 1; 47746d1a925SRobert Watson 47846d1a925SRobert Watson /* Search forward for object. */ 47946d1a925SRobert Watson 48046d1a925SRobert Watson object = -1; 48146d1a925SRobert Watson for (i = 1; i < argc; i++) 48246d1a925SRobert Watson if (strcmp(argv[i], "object") == 0) 48346d1a925SRobert Watson object = i; 48446d1a925SRobert Watson 48546d1a925SRobert Watson if (object == -1) { 48646d1a925SRobert Watson len = snprintf(errstr, buflen, "Rule must contain an object"); 48746d1a925SRobert Watson return (-1); 48846d1a925SRobert Watson } 48946d1a925SRobert Watson 49046d1a925SRobert Watson /* Search forward for mode. */ 49146d1a925SRobert Watson mode = -1; 49246d1a925SRobert Watson for (i = object; i < argc; i++) 49346d1a925SRobert Watson if (strcmp(argv[i], "mode") == 0) 49446d1a925SRobert Watson mode = i; 49546d1a925SRobert Watson 49646d1a925SRobert Watson if (mode == -1) { 49746d1a925SRobert Watson len = snprintf(errstr, buflen, "Rule must contain mode"); 49846d1a925SRobert Watson return (-1); 49946d1a925SRobert Watson } 50046d1a925SRobert Watson 50146d1a925SRobert Watson subject_elements_length = object - subject - 1; 50246d1a925SRobert Watson object_elements = object + 1; 50346d1a925SRobert Watson object_elements_length = mode - object_elements; 50446d1a925SRobert Watson mode_elements = mode + 1; 50546d1a925SRobert Watson mode_elements_length = argc - mode_elements; 50646d1a925SRobert Watson 50746d1a925SRobert Watson error = bsde_parse_identity(subject_elements_length, 50846d1a925SRobert Watson argv + subject_elements, &rule->mbr_subject, buflen, errstr); 50946d1a925SRobert Watson if (error) 51046d1a925SRobert Watson return (-1); 51146d1a925SRobert Watson 51246d1a925SRobert Watson error = bsde_parse_identity(object_elements_length, 51346d1a925SRobert Watson argv + object_elements, &rule->mbr_object, buflen, errstr); 51446d1a925SRobert Watson if (error) 51546d1a925SRobert Watson return (-1); 51646d1a925SRobert Watson 51746d1a925SRobert Watson error = bsde_parse_mode(mode_elements_length, argv + mode_elements, 51846d1a925SRobert Watson &rule->mbr_mode, buflen, errstr); 51946d1a925SRobert Watson if (error) 52046d1a925SRobert Watson return (-1); 52146d1a925SRobert Watson 52246d1a925SRobert Watson return (0); 52346d1a925SRobert Watson } 52446d1a925SRobert Watson 52546d1a925SRobert Watson int 52646d1a925SRobert Watson bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule, 52746d1a925SRobert Watson size_t buflen, char *errstr) 52846d1a925SRobert Watson { 52946d1a925SRobert Watson char *stringdup, *stringp, *argv[20], **ap; 53046d1a925SRobert Watson int argc, error; 53146d1a925SRobert Watson 53246d1a925SRobert Watson stringp = stringdup = strdup(string); 53346d1a925SRobert Watson while (*stringp == ' ' || *stringp == '\t') 53446d1a925SRobert Watson stringp++; 53546d1a925SRobert Watson 53646d1a925SRobert Watson argc = 0; 53746d1a925SRobert Watson for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) { 53846d1a925SRobert Watson argc++; 53946d1a925SRobert Watson if (**ap != '\0') 54046d1a925SRobert Watson if (++ap >= &argv[20]) 54146d1a925SRobert Watson break; 54246d1a925SRobert Watson } 54346d1a925SRobert Watson 54446d1a925SRobert Watson error = bsde_parse_rule(argc, argv, rule, buflen, errstr); 54546d1a925SRobert Watson 54646d1a925SRobert Watson free(stringdup); 54746d1a925SRobert Watson 54846d1a925SRobert Watson return (error); 54946d1a925SRobert Watson } 55046d1a925SRobert Watson 55146d1a925SRobert Watson int 552da30581eSRobert Watson bsde_get_mib(const char *string, int *name, size_t *namelen) 55346d1a925SRobert Watson { 554da30581eSRobert Watson size_t len; 555da30581eSRobert Watson int error; 55646d1a925SRobert Watson 55746d1a925SRobert Watson len = *namelen; 55846d1a925SRobert Watson error = sysctlnametomib(string, name, &len); 55946d1a925SRobert Watson if (error) 56046d1a925SRobert Watson return (error); 56146d1a925SRobert Watson 56246d1a925SRobert Watson *namelen = len; 56346d1a925SRobert Watson return (0); 56446d1a925SRobert Watson } 56546d1a925SRobert Watson 56646d1a925SRobert Watson int 56746d1a925SRobert Watson bsde_get_rule_count(size_t buflen, char *errstr) 56846d1a925SRobert Watson { 56946d1a925SRobert Watson size_t len; 57046d1a925SRobert Watson int error; 57146d1a925SRobert Watson int rule_count; 57246d1a925SRobert Watson 57346d1a925SRobert Watson len = sizeof(rule_count); 5740f9a2306SBruce Evans error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0); 57546d1a925SRobert Watson if (error) { 57646d1a925SRobert Watson len = snprintf(errstr, buflen, strerror(errno)); 57746d1a925SRobert Watson return (-1); 57846d1a925SRobert Watson } 57946d1a925SRobert Watson if (len != sizeof(rule_count)) { 58046d1a925SRobert Watson len = snprintf(errstr, buflen, "Data error in %s.rule_count", 58146d1a925SRobert Watson MIB); 58246d1a925SRobert Watson return (-1); 58346d1a925SRobert Watson } 58446d1a925SRobert Watson 58546d1a925SRobert Watson return (rule_count); 58646d1a925SRobert Watson } 58746d1a925SRobert Watson 58846d1a925SRobert Watson int 58946d1a925SRobert Watson bsde_get_rule_slots(size_t buflen, char *errstr) 59046d1a925SRobert Watson { 59146d1a925SRobert Watson size_t len; 59246d1a925SRobert Watson int error; 59346d1a925SRobert Watson int rule_slots; 59446d1a925SRobert Watson 59546d1a925SRobert Watson len = sizeof(rule_slots); 5960f9a2306SBruce Evans error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0); 59746d1a925SRobert Watson if (error) { 59846d1a925SRobert Watson len = snprintf(errstr, buflen, strerror(errno)); 59946d1a925SRobert Watson return (-1); 60046d1a925SRobert Watson } 60146d1a925SRobert Watson if (len != sizeof(rule_slots)) { 60246d1a925SRobert Watson len = snprintf(errstr, buflen, "Data error in %s.rule_slots", 60346d1a925SRobert Watson MIB); 60446d1a925SRobert Watson return (-1); 60546d1a925SRobert Watson } 60646d1a925SRobert Watson 60746d1a925SRobert Watson return (rule_slots); 60846d1a925SRobert Watson } 60946d1a925SRobert Watson 61046d1a925SRobert Watson /* 61146d1a925SRobert Watson * Returns 0 for success; 61246d1a925SRobert Watson * Returns -1 for failure; 61346d1a925SRobert Watson * Returns -2 for not present 61446d1a925SRobert Watson */ 61546d1a925SRobert Watson int 61646d1a925SRobert Watson bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen, 61746d1a925SRobert Watson char *errstr) 61846d1a925SRobert Watson { 61946d1a925SRobert Watson int name[10]; 62046d1a925SRobert Watson size_t len, size; 62146d1a925SRobert Watson int error; 62246d1a925SRobert Watson 62346d1a925SRobert Watson len = 10; 62446d1a925SRobert Watson error = bsde_get_mib(MIB ".rules", name, &len); 62546d1a925SRobert Watson if (error) { 62646d1a925SRobert Watson len = snprintf(errstr, errlen, "%s: %s", MIB ".rules", 62746d1a925SRobert Watson strerror(errno)); 62846d1a925SRobert Watson return (-1); 62946d1a925SRobert Watson } 63046d1a925SRobert Watson 63146d1a925SRobert Watson size = sizeof(*rule); 63246d1a925SRobert Watson name[len] = rulenum; 63346d1a925SRobert Watson len++; 63446d1a925SRobert Watson error = sysctl(name, len, rule, &size, NULL, 0); 63546d1a925SRobert Watson if (error == -1 && errno == ENOENT) 63646d1a925SRobert Watson return (-2); 63746d1a925SRobert Watson if (error) { 63846d1a925SRobert Watson len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules", 63946d1a925SRobert Watson rulenum, strerror(errno)); 64046d1a925SRobert Watson return (-1); 64146d1a925SRobert Watson } else if (size != sizeof(*rule)) { 64246d1a925SRobert Watson len = snprintf(errstr, errlen, "Data error in %s.%d: %s", 64346d1a925SRobert Watson MIB ".rules", rulenum, strerror(errno)); 64446d1a925SRobert Watson return (-1); 64546d1a925SRobert Watson } 64646d1a925SRobert Watson 64746d1a925SRobert Watson return (0); 64846d1a925SRobert Watson } 64946d1a925SRobert Watson 65046d1a925SRobert Watson int 65146d1a925SRobert Watson bsde_delete_rule(int rulenum, size_t buflen, char *errstr) 65246d1a925SRobert Watson { 65346d1a925SRobert Watson struct mac_bsdextended_rule rule; 65446d1a925SRobert Watson int name[10]; 65546d1a925SRobert Watson size_t len, size; 65646d1a925SRobert Watson int error; 65746d1a925SRobert Watson 65846d1a925SRobert Watson len = 10; 65946d1a925SRobert Watson error = bsde_get_mib(MIB ".rules", name, &len); 66046d1a925SRobert Watson if (error) { 66146d1a925SRobert Watson len = snprintf(errstr, buflen, "%s: %s", MIB ".rules", 66246d1a925SRobert Watson strerror(errno)); 66346d1a925SRobert Watson return (-1); 66446d1a925SRobert Watson } 66546d1a925SRobert Watson 66646d1a925SRobert Watson name[len] = rulenum; 66746d1a925SRobert Watson len++; 66846d1a925SRobert Watson 66946d1a925SRobert Watson size = sizeof(rule); 67046d1a925SRobert Watson error = sysctl(name, len, NULL, NULL, &rule, 0); 67146d1a925SRobert Watson if (error) { 67246d1a925SRobert Watson len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules", 67346d1a925SRobert Watson rulenum, strerror(errno)); 67446d1a925SRobert Watson return (-1); 67546d1a925SRobert Watson } 67646d1a925SRobert Watson 67746d1a925SRobert Watson return (0); 67846d1a925SRobert Watson } 67946d1a925SRobert Watson 68046d1a925SRobert Watson int 68146d1a925SRobert Watson bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen, 68246d1a925SRobert Watson char *errstr) 68346d1a925SRobert Watson { 68446d1a925SRobert Watson int name[10]; 68546d1a925SRobert Watson size_t len, size; 68646d1a925SRobert Watson int error; 68746d1a925SRobert Watson 68846d1a925SRobert Watson len = 10; 68946d1a925SRobert Watson error = bsde_get_mib(MIB ".rules", name, &len); 69046d1a925SRobert Watson if (error) { 69146d1a925SRobert Watson len = snprintf(errstr, buflen, "%s: %s", MIB ".rules", 69246d1a925SRobert Watson strerror(errno)); 69346d1a925SRobert Watson return (-1); 69446d1a925SRobert Watson } 69546d1a925SRobert Watson 69646d1a925SRobert Watson name[len] = rulenum; 69746d1a925SRobert Watson len++; 69846d1a925SRobert Watson 69946d1a925SRobert Watson size = sizeof(*rule); 70046d1a925SRobert Watson error = sysctl(name, len, NULL, NULL, rule, size); 70146d1a925SRobert Watson if (error) { 70246d1a925SRobert Watson len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules", 70346d1a925SRobert Watson rulenum, strerror(errno)); 70446d1a925SRobert Watson return (-1); 70546d1a925SRobert Watson } 70646d1a925SRobert Watson 70746d1a925SRobert Watson return (0); 70846d1a925SRobert Watson } 70947ab23aaSRobert Watson 71047ab23aaSRobert Watson int 71147ab23aaSRobert Watson bsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen, 71247ab23aaSRobert Watson char *errstr) 71347ab23aaSRobert Watson { 71447ab23aaSRobert Watson char charstr[BUFSIZ]; 71547ab23aaSRobert Watson int name[10]; 71647ab23aaSRobert Watson size_t len, size; 71747ab23aaSRobert Watson int error, rule_slots; 71847ab23aaSRobert Watson 71947ab23aaSRobert Watson len = 10; 72047ab23aaSRobert Watson error = bsde_get_mib(MIB ".rules", name, &len); 72147ab23aaSRobert Watson if (error) { 72247ab23aaSRobert Watson len = snprintf(errstr, buflen, "%s: %s", MIB ".rules", 72347ab23aaSRobert Watson strerror(errno)); 72447ab23aaSRobert Watson return (-1); 72547ab23aaSRobert Watson } 72647ab23aaSRobert Watson 72747ab23aaSRobert Watson rule_slots = bsde_get_rule_slots(BUFSIZ, charstr); 72847ab23aaSRobert Watson if (rule_slots == -1) { 72947ab23aaSRobert Watson len = snprintf(errstr, buflen, "unable to get rule slots: %s", 73047ab23aaSRobert Watson strerror(errno)); 73147ab23aaSRobert Watson return (-1); 73247ab23aaSRobert Watson } 73347ab23aaSRobert Watson 73447ab23aaSRobert Watson name[len] = rule_slots; 73547ab23aaSRobert Watson len++; 73647ab23aaSRobert Watson 73747ab23aaSRobert Watson size = sizeof(*rule); 73847ab23aaSRobert Watson error = sysctl(name, len, NULL, NULL, rule, size); 73947ab23aaSRobert Watson if (error) { 74047ab23aaSRobert Watson len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules", 74147ab23aaSRobert Watson rule_slots, strerror(errno)); 74247ab23aaSRobert Watson return (-1); 74347ab23aaSRobert Watson } 74447ab23aaSRobert Watson 74547ab23aaSRobert Watson if (rulenum != NULL) 746fbc822aeSPawel Jakub Dawidek *rulenum = rule_slots; 74747ab23aaSRobert Watson 74847ab23aaSRobert Watson return (0); 74947ab23aaSRobert Watson } 750