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