146d1a925SRobert Watson /*- 2a6c2bc8bSRobert Watson * Copyright (c) 2002-2005 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 } 344a6c2bc8bSRobert Watson pwd = getpwnam(argv[current+1]); 345a6c2bc8bSRobert Watson if (pwd != NULL) 346a6c2bc8bSRobert Watson uid = pwd->pw_uid; 347a6c2bc8bSRobert Watson else { 34846d1a925SRobert Watson value = strtol(argv[current+1], &endp, 10); 34946d1a925SRobert Watson if (*endp != '\0') { 350a6c2bc8bSRobert Watson len = snprintf(errstr, buflen, 351a6c2bc8bSRobert Watson "invalid uid: '%s'", 35246d1a925SRobert Watson argv[current+1]); 35346d1a925SRobert Watson return (-1); 35446d1a925SRobert Watson } 35546d1a925SRobert Watson uid = value; 356a6c2bc8bSRobert Watson } 35746d1a925SRobert Watson uid_seen = 1; 35846d1a925SRobert Watson current += 2; 35946d1a925SRobert Watson } else if (strcmp("gid", argv[current]) == 0) { 36046d1a925SRobert Watson if (gid_seen) { 36146d1a925SRobert Watson len = snprintf(errstr, buflen, 36246d1a925SRobert Watson "Only one gid permitted per identity clause"); 36346d1a925SRobert Watson return (-1); 36446d1a925SRobert Watson } 36546d1a925SRobert Watson if (current + 2 > argc) { 36646d1a925SRobert Watson len = snprintf(errstr, buflen, "gid short"); 36746d1a925SRobert Watson return (-1); 36846d1a925SRobert Watson } 369a6c2bc8bSRobert Watson grp = getgrnam(argv[current+1]); 370a6c2bc8bSRobert Watson if (grp != NULL) 371a6c2bc8bSRobert Watson gid = grp->gr_gid; 372a6c2bc8bSRobert Watson else { 37346d1a925SRobert Watson value = strtol(argv[current+1], &endp, 10); 37446d1a925SRobert Watson if (*endp != '\0') { 375a6c2bc8bSRobert Watson len = snprintf(errstr, buflen, 376a6c2bc8bSRobert Watson "invalid gid: '%s'", 37746d1a925SRobert Watson argv[current+1]); 37846d1a925SRobert Watson return (-1); 37946d1a925SRobert Watson } 38046d1a925SRobert Watson gid = value; 381a6c2bc8bSRobert Watson } 38246d1a925SRobert Watson gid_seen = 1; 38346d1a925SRobert Watson current += 2; 38446d1a925SRobert Watson } else { 38546d1a925SRobert Watson len = snprintf(errstr, buflen, "'%s' not expected", 38646d1a925SRobert Watson argv[current]); 38746d1a925SRobert Watson return (-1); 38846d1a925SRobert Watson } 38946d1a925SRobert Watson } 39046d1a925SRobert Watson 39146d1a925SRobert Watson if (current +1 < argc) { 39246d1a925SRobert Watson len = snprintf(errstr, buflen, "'%s' not expected", 39346d1a925SRobert Watson argv[current]); 39446d1a925SRobert Watson return (-1); 39546d1a925SRobert Watson } 39646d1a925SRobert Watson 39746d1a925SRobert Watson /* Fill out the identity. */ 39846d1a925SRobert Watson identity->mbi_flags = 0; 39946d1a925SRobert Watson 40046d1a925SRobert Watson if (not_seen) 40146d1a925SRobert Watson identity->mbi_flags |= MBI_NEGATED; 40246d1a925SRobert Watson 40346d1a925SRobert Watson if (uid_seen) { 40446d1a925SRobert Watson identity->mbi_flags |= MBI_UID_DEFINED; 40546d1a925SRobert Watson identity->mbi_uid = uid; 40646d1a925SRobert Watson } else 40746d1a925SRobert Watson identity->mbi_uid = 0; 40846d1a925SRobert Watson 40946d1a925SRobert Watson if (gid_seen) { 41046d1a925SRobert Watson identity->mbi_flags |= MBI_GID_DEFINED; 41146d1a925SRobert Watson identity->mbi_gid = gid; 41246d1a925SRobert Watson } else 41346d1a925SRobert Watson identity->mbi_gid = 0; 41446d1a925SRobert Watson 41546d1a925SRobert Watson return (0); 41646d1a925SRobert Watson } 41746d1a925SRobert Watson 41846d1a925SRobert Watson int 41946d1a925SRobert Watson bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen, 42046d1a925SRobert Watson char *errstr) 42146d1a925SRobert Watson { 42246d1a925SRobert Watson size_t len; 42346d1a925SRobert Watson int i; 42446d1a925SRobert Watson 42546d1a925SRobert Watson if (argc == 0) { 42646d1a925SRobert Watson len = snprintf(errstr, buflen, "mode expects mode value"); 42746d1a925SRobert Watson return (-1); 42846d1a925SRobert Watson } 42946d1a925SRobert Watson 43046d1a925SRobert Watson if (argc != 1) { 43146d1a925SRobert Watson len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]); 43246d1a925SRobert Watson return (-1); 43346d1a925SRobert Watson } 43446d1a925SRobert Watson 43546d1a925SRobert Watson *mode = 0; 43646d1a925SRobert Watson for (i = 0; i < strlen(argv[0]); i++) { 43746d1a925SRobert Watson switch (argv[0][i]) { 43846d1a925SRobert Watson case 'a': 439f4194603SRobert Watson *mode |= MBI_ADMIN; 44046d1a925SRobert Watson break; 44146d1a925SRobert Watson case 'r': 442f4194603SRobert Watson *mode |= MBI_READ; 44346d1a925SRobert Watson break; 44446d1a925SRobert Watson case 's': 445f4194603SRobert Watson *mode |= MBI_STAT; 44646d1a925SRobert Watson break; 44746d1a925SRobert Watson case 'w': 448f4194603SRobert Watson *mode |= MBI_WRITE; 44946d1a925SRobert Watson break; 45046d1a925SRobert Watson case 'x': 451f4194603SRobert Watson *mode |= MBI_EXEC; 45246d1a925SRobert Watson break; 45346d1a925SRobert Watson case 'n': 45446d1a925SRobert Watson /* ignore */ 45546d1a925SRobert Watson break; 45646d1a925SRobert Watson default: 45746d1a925SRobert Watson len = snprintf(errstr, buflen, "Unknown mode letter: %c", 45846d1a925SRobert Watson argv[0][i]); 45946d1a925SRobert Watson return (-1); 46046d1a925SRobert Watson } 46146d1a925SRobert Watson } 46246d1a925SRobert Watson 46346d1a925SRobert Watson return (0); 46446d1a925SRobert Watson } 46546d1a925SRobert Watson 46646d1a925SRobert Watson int 46746d1a925SRobert Watson bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule, 46846d1a925SRobert Watson size_t buflen, char *errstr) 46946d1a925SRobert Watson { 47046d1a925SRobert Watson int subject, subject_elements, subject_elements_length; 47146d1a925SRobert Watson int object, object_elements, object_elements_length; 47246d1a925SRobert Watson int mode, mode_elements, mode_elements_length; 47346d1a925SRobert Watson int error, i; 47446d1a925SRobert Watson size_t len; 47546d1a925SRobert Watson 47646d1a925SRobert Watson bzero(rule, sizeof(*rule)); 47746d1a925SRobert Watson 47846d1a925SRobert Watson if (argc < 1) { 47946d1a925SRobert Watson len = snprintf(errstr, buflen, "Rule must begin with subject"); 48046d1a925SRobert Watson return (-1); 48146d1a925SRobert Watson } 48246d1a925SRobert Watson 48346d1a925SRobert Watson if (strcmp(argv[0], "subject") != 0) { 48446d1a925SRobert Watson len = snprintf(errstr, buflen, "Rule must begin with subject"); 48546d1a925SRobert Watson return (-1); 48646d1a925SRobert Watson } 48746d1a925SRobert Watson subject = 0; 48846d1a925SRobert Watson subject_elements = 1; 48946d1a925SRobert Watson 49046d1a925SRobert Watson /* Search forward for object. */ 49146d1a925SRobert Watson 49246d1a925SRobert Watson object = -1; 49346d1a925SRobert Watson for (i = 1; i < argc; i++) 49446d1a925SRobert Watson if (strcmp(argv[i], "object") == 0) 49546d1a925SRobert Watson object = i; 49646d1a925SRobert Watson 49746d1a925SRobert Watson if (object == -1) { 49846d1a925SRobert Watson len = snprintf(errstr, buflen, "Rule must contain an object"); 49946d1a925SRobert Watson return (-1); 50046d1a925SRobert Watson } 50146d1a925SRobert Watson 50246d1a925SRobert Watson /* Search forward for mode. */ 50346d1a925SRobert Watson mode = -1; 50446d1a925SRobert Watson for (i = object; i < argc; i++) 50546d1a925SRobert Watson if (strcmp(argv[i], "mode") == 0) 50646d1a925SRobert Watson mode = i; 50746d1a925SRobert Watson 50846d1a925SRobert Watson if (mode == -1) { 50946d1a925SRobert Watson len = snprintf(errstr, buflen, "Rule must contain mode"); 51046d1a925SRobert Watson return (-1); 51146d1a925SRobert Watson } 51246d1a925SRobert Watson 51346d1a925SRobert Watson subject_elements_length = object - subject - 1; 51446d1a925SRobert Watson object_elements = object + 1; 51546d1a925SRobert Watson object_elements_length = mode - object_elements; 51646d1a925SRobert Watson mode_elements = mode + 1; 51746d1a925SRobert Watson mode_elements_length = argc - mode_elements; 51846d1a925SRobert Watson 51946d1a925SRobert Watson error = bsde_parse_identity(subject_elements_length, 52046d1a925SRobert Watson argv + subject_elements, &rule->mbr_subject, buflen, errstr); 52146d1a925SRobert Watson if (error) 52246d1a925SRobert Watson return (-1); 52346d1a925SRobert Watson 52446d1a925SRobert Watson error = bsde_parse_identity(object_elements_length, 52546d1a925SRobert Watson argv + object_elements, &rule->mbr_object, buflen, errstr); 52646d1a925SRobert Watson if (error) 52746d1a925SRobert Watson return (-1); 52846d1a925SRobert Watson 52946d1a925SRobert Watson error = bsde_parse_mode(mode_elements_length, argv + mode_elements, 53046d1a925SRobert Watson &rule->mbr_mode, buflen, errstr); 53146d1a925SRobert Watson if (error) 53246d1a925SRobert Watson return (-1); 53346d1a925SRobert Watson 53446d1a925SRobert Watson return (0); 53546d1a925SRobert Watson } 53646d1a925SRobert Watson 53746d1a925SRobert Watson int 53846d1a925SRobert Watson bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule, 53946d1a925SRobert Watson size_t buflen, char *errstr) 54046d1a925SRobert Watson { 54146d1a925SRobert Watson char *stringdup, *stringp, *argv[20], **ap; 54246d1a925SRobert Watson int argc, error; 54346d1a925SRobert Watson 54446d1a925SRobert Watson stringp = stringdup = strdup(string); 54546d1a925SRobert Watson while (*stringp == ' ' || *stringp == '\t') 54646d1a925SRobert Watson stringp++; 54746d1a925SRobert Watson 54846d1a925SRobert Watson argc = 0; 54946d1a925SRobert Watson for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) { 55046d1a925SRobert Watson argc++; 55146d1a925SRobert Watson if (**ap != '\0') 55246d1a925SRobert Watson if (++ap >= &argv[20]) 55346d1a925SRobert Watson break; 55446d1a925SRobert Watson } 55546d1a925SRobert Watson 55646d1a925SRobert Watson error = bsde_parse_rule(argc, argv, rule, buflen, errstr); 55746d1a925SRobert Watson 55846d1a925SRobert Watson free(stringdup); 55946d1a925SRobert Watson 56046d1a925SRobert Watson return (error); 56146d1a925SRobert Watson } 56246d1a925SRobert Watson 56346d1a925SRobert Watson int 564da30581eSRobert Watson bsde_get_mib(const char *string, int *name, size_t *namelen) 56546d1a925SRobert Watson { 566da30581eSRobert Watson size_t len; 567da30581eSRobert Watson int error; 56846d1a925SRobert Watson 56946d1a925SRobert Watson len = *namelen; 57046d1a925SRobert Watson error = sysctlnametomib(string, name, &len); 57146d1a925SRobert Watson if (error) 57246d1a925SRobert Watson return (error); 57346d1a925SRobert Watson 57446d1a925SRobert Watson *namelen = len; 57546d1a925SRobert Watson return (0); 57646d1a925SRobert Watson } 57746d1a925SRobert Watson 57846d1a925SRobert Watson int 57946d1a925SRobert Watson bsde_get_rule_count(size_t buflen, char *errstr) 58046d1a925SRobert Watson { 58146d1a925SRobert Watson size_t len; 58246d1a925SRobert Watson int error; 58346d1a925SRobert Watson int rule_count; 58446d1a925SRobert Watson 58546d1a925SRobert Watson len = sizeof(rule_count); 5860f9a2306SBruce Evans error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0); 58746d1a925SRobert Watson if (error) { 58846d1a925SRobert Watson len = snprintf(errstr, buflen, strerror(errno)); 58946d1a925SRobert Watson return (-1); 59046d1a925SRobert Watson } 59146d1a925SRobert Watson if (len != sizeof(rule_count)) { 59246d1a925SRobert Watson len = snprintf(errstr, buflen, "Data error in %s.rule_count", 59346d1a925SRobert Watson MIB); 59446d1a925SRobert Watson return (-1); 59546d1a925SRobert Watson } 59646d1a925SRobert Watson 59746d1a925SRobert Watson return (rule_count); 59846d1a925SRobert Watson } 59946d1a925SRobert Watson 60046d1a925SRobert Watson int 60146d1a925SRobert Watson bsde_get_rule_slots(size_t buflen, char *errstr) 60246d1a925SRobert Watson { 60346d1a925SRobert Watson size_t len; 60446d1a925SRobert Watson int error; 60546d1a925SRobert Watson int rule_slots; 60646d1a925SRobert Watson 60746d1a925SRobert Watson len = sizeof(rule_slots); 6080f9a2306SBruce Evans error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0); 60946d1a925SRobert Watson if (error) { 61046d1a925SRobert Watson len = snprintf(errstr, buflen, strerror(errno)); 61146d1a925SRobert Watson return (-1); 61246d1a925SRobert Watson } 61346d1a925SRobert Watson if (len != sizeof(rule_slots)) { 61446d1a925SRobert Watson len = snprintf(errstr, buflen, "Data error in %s.rule_slots", 61546d1a925SRobert Watson MIB); 61646d1a925SRobert Watson return (-1); 61746d1a925SRobert Watson } 61846d1a925SRobert Watson 61946d1a925SRobert Watson return (rule_slots); 62046d1a925SRobert Watson } 62146d1a925SRobert Watson 62246d1a925SRobert Watson /* 62346d1a925SRobert Watson * Returns 0 for success; 62446d1a925SRobert Watson * Returns -1 for failure; 62546d1a925SRobert Watson * Returns -2 for not present 62646d1a925SRobert Watson */ 62746d1a925SRobert Watson int 62846d1a925SRobert Watson bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen, 62946d1a925SRobert Watson char *errstr) 63046d1a925SRobert Watson { 63146d1a925SRobert Watson int name[10]; 63246d1a925SRobert Watson size_t len, size; 63346d1a925SRobert Watson int error; 63446d1a925SRobert Watson 63546d1a925SRobert Watson len = 10; 63646d1a925SRobert Watson error = bsde_get_mib(MIB ".rules", name, &len); 63746d1a925SRobert Watson if (error) { 63846d1a925SRobert Watson len = snprintf(errstr, errlen, "%s: %s", MIB ".rules", 63946d1a925SRobert Watson strerror(errno)); 64046d1a925SRobert Watson return (-1); 64146d1a925SRobert Watson } 64246d1a925SRobert Watson 64346d1a925SRobert Watson size = sizeof(*rule); 64446d1a925SRobert Watson name[len] = rulenum; 64546d1a925SRobert Watson len++; 64646d1a925SRobert Watson error = sysctl(name, len, rule, &size, NULL, 0); 64746d1a925SRobert Watson if (error == -1 && errno == ENOENT) 64846d1a925SRobert Watson return (-2); 64946d1a925SRobert Watson if (error) { 65046d1a925SRobert Watson len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules", 65146d1a925SRobert Watson rulenum, strerror(errno)); 65246d1a925SRobert Watson return (-1); 65346d1a925SRobert Watson } else if (size != sizeof(*rule)) { 65446d1a925SRobert Watson len = snprintf(errstr, errlen, "Data error in %s.%d: %s", 65546d1a925SRobert Watson MIB ".rules", rulenum, strerror(errno)); 65646d1a925SRobert Watson return (-1); 65746d1a925SRobert Watson } 65846d1a925SRobert Watson 65946d1a925SRobert Watson return (0); 66046d1a925SRobert Watson } 66146d1a925SRobert Watson 66246d1a925SRobert Watson int 66346d1a925SRobert Watson bsde_delete_rule(int rulenum, size_t buflen, char *errstr) 66446d1a925SRobert Watson { 66546d1a925SRobert Watson struct mac_bsdextended_rule rule; 66646d1a925SRobert Watson int name[10]; 66746d1a925SRobert Watson size_t len, size; 66846d1a925SRobert Watson int error; 66946d1a925SRobert Watson 67046d1a925SRobert Watson len = 10; 67146d1a925SRobert Watson error = bsde_get_mib(MIB ".rules", name, &len); 67246d1a925SRobert Watson if (error) { 67346d1a925SRobert Watson len = snprintf(errstr, buflen, "%s: %s", MIB ".rules", 67446d1a925SRobert Watson strerror(errno)); 67546d1a925SRobert Watson return (-1); 67646d1a925SRobert Watson } 67746d1a925SRobert Watson 67846d1a925SRobert Watson name[len] = rulenum; 67946d1a925SRobert Watson len++; 68046d1a925SRobert Watson 68146d1a925SRobert Watson size = sizeof(rule); 68246d1a925SRobert Watson error = sysctl(name, len, NULL, NULL, &rule, 0); 68346d1a925SRobert Watson if (error) { 68446d1a925SRobert Watson len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules", 68546d1a925SRobert Watson rulenum, strerror(errno)); 68646d1a925SRobert Watson return (-1); 68746d1a925SRobert Watson } 68846d1a925SRobert Watson 68946d1a925SRobert Watson return (0); 69046d1a925SRobert Watson } 69146d1a925SRobert Watson 69246d1a925SRobert Watson int 69346d1a925SRobert Watson bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen, 69446d1a925SRobert Watson char *errstr) 69546d1a925SRobert Watson { 69646d1a925SRobert Watson int name[10]; 69746d1a925SRobert Watson size_t len, size; 69846d1a925SRobert Watson int error; 69946d1a925SRobert Watson 70046d1a925SRobert Watson len = 10; 70146d1a925SRobert Watson error = bsde_get_mib(MIB ".rules", name, &len); 70246d1a925SRobert Watson if (error) { 70346d1a925SRobert Watson len = snprintf(errstr, buflen, "%s: %s", MIB ".rules", 70446d1a925SRobert Watson strerror(errno)); 70546d1a925SRobert Watson return (-1); 70646d1a925SRobert Watson } 70746d1a925SRobert Watson 70846d1a925SRobert Watson name[len] = rulenum; 70946d1a925SRobert Watson len++; 71046d1a925SRobert Watson 71146d1a925SRobert Watson size = sizeof(*rule); 71246d1a925SRobert Watson error = sysctl(name, len, NULL, NULL, rule, size); 71346d1a925SRobert Watson if (error) { 71446d1a925SRobert Watson len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules", 71546d1a925SRobert Watson rulenum, strerror(errno)); 71646d1a925SRobert Watson return (-1); 71746d1a925SRobert Watson } 71846d1a925SRobert Watson 71946d1a925SRobert Watson return (0); 72046d1a925SRobert Watson } 72147ab23aaSRobert Watson 72247ab23aaSRobert Watson int 72347ab23aaSRobert Watson bsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen, 72447ab23aaSRobert Watson char *errstr) 72547ab23aaSRobert Watson { 72647ab23aaSRobert Watson char charstr[BUFSIZ]; 72747ab23aaSRobert Watson int name[10]; 72847ab23aaSRobert Watson size_t len, size; 72947ab23aaSRobert Watson int error, rule_slots; 73047ab23aaSRobert Watson 73147ab23aaSRobert Watson len = 10; 73247ab23aaSRobert Watson error = bsde_get_mib(MIB ".rules", name, &len); 73347ab23aaSRobert Watson if (error) { 73447ab23aaSRobert Watson len = snprintf(errstr, buflen, "%s: %s", MIB ".rules", 73547ab23aaSRobert Watson strerror(errno)); 73647ab23aaSRobert Watson return (-1); 73747ab23aaSRobert Watson } 73847ab23aaSRobert Watson 73947ab23aaSRobert Watson rule_slots = bsde_get_rule_slots(BUFSIZ, charstr); 74047ab23aaSRobert Watson if (rule_slots == -1) { 74147ab23aaSRobert Watson len = snprintf(errstr, buflen, "unable to get rule slots: %s", 74247ab23aaSRobert Watson strerror(errno)); 74347ab23aaSRobert Watson return (-1); 74447ab23aaSRobert Watson } 74547ab23aaSRobert Watson 74647ab23aaSRobert Watson name[len] = rule_slots; 74747ab23aaSRobert Watson len++; 74847ab23aaSRobert Watson 74947ab23aaSRobert Watson size = sizeof(*rule); 75047ab23aaSRobert Watson error = sysctl(name, len, NULL, NULL, rule, size); 75147ab23aaSRobert Watson if (error) { 75247ab23aaSRobert Watson len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules", 75347ab23aaSRobert Watson rule_slots, strerror(errno)); 75447ab23aaSRobert Watson return (-1); 75547ab23aaSRobert Watson } 75647ab23aaSRobert Watson 75747ab23aaSRobert Watson if (rulenum != NULL) 758fbc822aeSPawel Jakub Dawidek *rulenum = rule_slots; 75947ab23aaSRobert Watson 76047ab23aaSRobert Watson return (0); 76147ab23aaSRobert Watson } 762