1105698Srwatson/* 2105698Srwatson * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 3119314Srwatson * Copyright (c) 2002, 2003 Networks Associates Technology, Inc. 4105698Srwatson * All rights reserved. 5105698Srwatson * 6105698Srwatson * This software was developed by Robert Watson for the TrustedBSD Project. 7105698Srwatson * 8106436Srwatson * This software was developed for the FreeBSD Project in part by Network 9106436Srwatson * Associates Laboratories, the Security Research Division of Network 10106436Srwatson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 11106436Srwatson * as part of the DARPA CHATS research program. 12105698Srwatson * 13105698Srwatson * Redistribution and use in source and binary forms, with or without 14105698Srwatson * modification, are permitted provided that the following conditions 15105698Srwatson * are met: 16105698Srwatson * 1. Redistributions of source code must retain the above copyright 17105698Srwatson * notice, this list of conditions and the following disclaimer. 18105698Srwatson * 2. Redistributions in binary form must reproduce the above copyright 19105698Srwatson * notice, this list of conditions and the following disclaimer in the 20105698Srwatson * documentation and/or other materials provided with the distribution. 21105698Srwatson * 22105698Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23105698Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24105698Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25105698Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26105698Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27105698Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28105698Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29105698Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30105698Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31105698Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32105698Srwatson * SUCH DAMAGE. 33105698Srwatson */ 34105698Srwatson 35176901Srwatson#include <sys/cdefs.h> 36176901Srwatson__FBSDID("$FreeBSD$"); 37176901Srwatson 38105698Srwatson#include <sys/types.h> 39105698Srwatson#include <sys/queue.h> 40105698Srwatson#include <sys/sysctl.h> 41105698Srwatson 42105698Srwatson#include <dlfcn.h> 43105698Srwatson#include <errno.h> 44106053Swollman#include <limits.h> 45105698Srwatson#include <stdio.h> 46105698Srwatson#include <stdlib.h> 47105698Srwatson#include <string.h> 48124174Snectar#include <unistd.h> 49105698Srwatson 50105698Srwatson#include <sys/mac.h> 51105698Srwatson 52105698Srwatsonstatic int internal_initialized; 53105698Srwatson 54119314Srwatson/* 55119314Srwatson * Maintain a list of default label preparations for various object 56119314Srwatson * types. Each name will appear only once in the list. 57119314Srwatson * 58119314Srwatson * XXXMAC: Not thread-safe. 59119314Srwatson */ 60122868Srwatsonstatic LIST_HEAD(, label_default) label_default_head; 61119314Srwatsonstruct label_default { 62119314Srwatson char *ld_name; 63119314Srwatson char *ld_labels; 64119314Srwatson LIST_ENTRY(label_default) ld_entries; 65119314Srwatson}; 66105698Srwatson 67105698Srwatsonstatic void 68105698Srwatsonmac_destroy_labels(void) 69105698Srwatson{ 70119314Srwatson struct label_default *ld; 71105698Srwatson 72119314Srwatson while ((ld = LIST_FIRST(&label_default_head))) { 73119314Srwatson free(ld->ld_name); 74119314Srwatson free(ld->ld_labels); 75119314Srwatson LIST_REMOVE(ld, ld_entries); 76119314Srwatson free(ld); 77105698Srwatson } 78105698Srwatson} 79105698Srwatson 80105698Srwatsonstatic void 81105698Srwatsonmac_destroy_internal(void) 82105698Srwatson{ 83105698Srwatson 84105698Srwatson mac_destroy_labels(); 85105698Srwatson 86105698Srwatson internal_initialized = 0; 87105698Srwatson} 88105698Srwatson 89105698Srwatsonstatic int 90119314Srwatsonmac_add_type(const char *name, const char *labels) 91105698Srwatson{ 92119314Srwatson struct label_default *ld, *ld_new; 93119314Srwatson char *name_dup, *labels_dup; 94119314Srwatson 95119314Srwatson /* 96119314Srwatson * Speculatively allocate all the memory now to avoid allocating 97119314Srwatson * later when we will someday hold a mutex. 98119314Srwatson */ 99119314Srwatson name_dup = strdup(name); 100119314Srwatson if (name_dup == NULL) { 101119314Srwatson errno = ENOMEM; 102119314Srwatson return (-1); 103119314Srwatson } 104119314Srwatson labels_dup = strdup(labels); 105119314Srwatson if (labels_dup == NULL) { 106119314Srwatson free(name_dup); 107119314Srwatson errno = ENOMEM; 108119314Srwatson return (-1); 109119314Srwatson } 110119314Srwatson ld_new = malloc(sizeof(*ld)); 111119314Srwatson if (ld_new == NULL) { 112119314Srwatson free(name_dup); 113119314Srwatson free(labels_dup); 114119314Srwatson errno = ENOMEM; 115119314Srwatson return (-1); 116119314Srwatson } 117119314Srwatson 118119314Srwatson /* 119119314Srwatson * If the type is already present, replace the current entry 120119314Srwatson * rather than add a new instance. 121119314Srwatson */ 122119314Srwatson for (ld = LIST_FIRST(&label_default_head); ld != NULL; 123119314Srwatson ld = LIST_NEXT(ld, ld_entries)) { 124119314Srwatson if (strcmp(name, ld->ld_name) == 0) 125119314Srwatson break; 126119314Srwatson } 127119314Srwatson 128119314Srwatson if (ld != NULL) { 129119314Srwatson free(ld->ld_labels); 130119314Srwatson ld->ld_labels = labels_dup; 131119314Srwatson labels_dup = NULL; 132119314Srwatson } else { 133119314Srwatson ld = ld_new; 134119314Srwatson ld->ld_name = name_dup; 135119314Srwatson ld->ld_labels = labels_dup; 136119314Srwatson 137119314Srwatson ld_new = NULL; 138119314Srwatson name_dup = NULL; 139119314Srwatson labels_dup = NULL; 140119314Srwatson 141119314Srwatson LIST_INSERT_HEAD(&label_default_head, ld, ld_entries); 142119314Srwatson } 143119314Srwatson 144119314Srwatson if (name_dup != NULL) 145119314Srwatson free(name_dup); 146119314Srwatson if (labels_dup != NULL) 147119314Srwatson free(labels_dup); 148119314Srwatson if (ld_new != NULL) 149119314Srwatson free(ld_new); 150119314Srwatson 151119314Srwatson return (0); 152119314Srwatson} 153119314Srwatson 154119314Srwatsonstatic char * 155119314Srwatsonnext_token(char **string) 156119314Srwatson{ 157119314Srwatson char *token; 158119314Srwatson 159119314Srwatson token = strsep(string, " \t"); 160119314Srwatson while (token != NULL && *token == '\0') 161119314Srwatson token = strsep(string, " \t"); 162119314Srwatson 163119314Srwatson return (token); 164119314Srwatson} 165119314Srwatson 166119314Srwatsonstatic int 167119314Srwatsonmac_init_internal(int ignore_errors) 168119314Srwatson{ 169119314Srwatson const char *filename; 170119314Srwatson char line[LINE_MAX]; 171105698Srwatson FILE *file; 172105698Srwatson int error; 173105698Srwatson 174105698Srwatson error = 0; 175105698Srwatson 176119314Srwatson LIST_INIT(&label_default_head); 177119314Srwatson 178119314Srwatson if (!issetugid() && getenv("MAC_CONFFILE") != NULL) 179119314Srwatson filename = getenv("MAC_CONFFILE"); 180119314Srwatson else 181119314Srwatson filename = MAC_CONFFILE; 182119314Srwatson file = fopen(filename, "r"); 183105698Srwatson if (file == NULL) 184105698Srwatson return (0); 185105698Srwatson 186105698Srwatson while (fgets(line, LINE_MAX, file)) { 187124174Snectar char *comment, *parse, *statement; 188105698Srwatson 189105698Srwatson if (line[strlen(line)-1] == '\n') 190105698Srwatson line[strlen(line)-1] = '\0'; 191105698Srwatson else { 192119314Srwatson if (ignore_errors) 193119314Srwatson continue; 194105698Srwatson fclose(file); 195105698Srwatson error = EINVAL; 196105698Srwatson goto just_return; 197105698Srwatson } 198105698Srwatson 199119314Srwatson /* Remove any comment. */ 200119314Srwatson comment = line; 201119314Srwatson parse = strsep(&comment, "#"); 202105698Srwatson 203119314Srwatson /* Blank lines OK. */ 204119314Srwatson statement = next_token(&parse); 205119314Srwatson if (statement == NULL) 206105698Srwatson continue; 207105698Srwatson 208119314Srwatson if (strcmp(statement, "default_labels") == 0) { 209119314Srwatson char *name, *labels; 210105698Srwatson 211119314Srwatson name = next_token(&parse); 212119314Srwatson labels = next_token(&parse); 213119314Srwatson if (name == NULL || labels == NULL || 214119314Srwatson next_token(&parse) != NULL) { 215119314Srwatson if (ignore_errors) 216119314Srwatson continue; 217119314Srwatson error = EINVAL; 218119314Srwatson fclose(file); 219119314Srwatson goto just_return; 220105698Srwatson } 221105698Srwatson 222119314Srwatson if (mac_add_type(name, labels) == -1) { 223119314Srwatson if (ignore_errors) 224119314Srwatson continue; 225119314Srwatson fclose(file); 226119314Srwatson goto just_return; 227105698Srwatson } 228119314Srwatson } else if (strcmp(statement, "default_ifnet_labels") == 0 || 229119314Srwatson strcmp(statement, "default_file_labels") == 0 || 230119314Srwatson strcmp(statement, "default_process_labels") == 0) { 231119314Srwatson char *labels, *type; 232105698Srwatson 233119314Srwatson if (strcmp(statement, "default_ifnet_labels") == 0) 234119314Srwatson type = "ifnet"; 235119314Srwatson else if (strcmp(statement, "default_file_labels") == 0) 236119314Srwatson type = "file"; 237119314Srwatson else if (strcmp(statement, "default_process_labels") == 238119314Srwatson 0) 239119314Srwatson type = "process"; 240119314Srwatson 241119314Srwatson labels = next_token(&parse); 242119314Srwatson if (labels == NULL || next_token(&parse) != NULL) { 243119314Srwatson if (ignore_errors) 244119314Srwatson continue; 245119314Srwatson error = EINVAL; 246119314Srwatson fclose(file); 247119314Srwatson goto just_return; 248105698Srwatson } 249105698Srwatson 250119314Srwatson if (mac_add_type(type, labels) == -1) { 251119314Srwatson if (ignore_errors) 252119314Srwatson continue; 253119314Srwatson fclose(file); 254119314Srwatson goto just_return; 255105698Srwatson } 256105698Srwatson } else { 257119314Srwatson if (ignore_errors) 258119314Srwatson continue; 259105698Srwatson fclose(file); 260105698Srwatson error = EINVAL; 261105698Srwatson goto just_return; 262105698Srwatson } 263105698Srwatson } 264105698Srwatson 265105698Srwatson fclose(file); 266105698Srwatson 267105698Srwatson internal_initialized = 1; 268105698Srwatson 269105698Srwatsonjust_return: 270105698Srwatson if (error != 0) 271105698Srwatson mac_destroy_internal(); 272105698Srwatson return (error); 273105698Srwatson} 274105698Srwatson 275105698Srwatsonstatic int 276105698Srwatsonmac_maybe_init_internal(void) 277105698Srwatson{ 278105698Srwatson 279105698Srwatson if (!internal_initialized) 280119314Srwatson return (mac_init_internal(1)); 281105698Srwatson else 282105698Srwatson return (0); 283105698Srwatson} 284105698Srwatson 285105698Srwatsonint 286105698Srwatsonmac_reload(void) 287105698Srwatson{ 288105698Srwatson 289105698Srwatson if (internal_initialized) 290105698Srwatson mac_destroy_internal(); 291119314Srwatson return (mac_init_internal(0)); 292105698Srwatson} 293105698Srwatson 294105698Srwatsonint 295105698Srwatsonmac_free(struct mac *mac) 296105698Srwatson{ 297105698Srwatson 298105698Srwatson if (mac->m_string != NULL) 299105698Srwatson free(mac->m_string); 300105698Srwatson free(mac); 301105698Srwatson 302105698Srwatson return (0); 303105698Srwatson} 304105698Srwatson 305105698Srwatsonint 306105698Srwatsonmac_from_text(struct mac **mac, const char *text) 307105698Srwatson{ 308105698Srwatson 309105698Srwatson *mac = (struct mac *) malloc(sizeof(**mac)); 310105698Srwatson if (*mac == NULL) 311105698Srwatson return (ENOMEM); 312105698Srwatson 313105698Srwatson (*mac)->m_string = strdup(text); 314105698Srwatson if ((*mac)->m_string == NULL) { 315105698Srwatson free(*mac); 316105698Srwatson *mac = NULL; 317105698Srwatson return (ENOMEM); 318105698Srwatson } 319105698Srwatson 320105698Srwatson (*mac)->m_buflen = strlen((*mac)->m_string)+1; 321105698Srwatson 322105698Srwatson return (0); 323105698Srwatson} 324105698Srwatson 325105698Srwatsonint 326105837Schrismac_to_text(struct mac *mac, char **text) 327105837Schris{ 328105837Schris 329105837Schris *text = strdup(mac->m_string); 330105837Schris if (*text == NULL) 331105837Schris return (ENOMEM); 332105837Schris return (0); 333105837Schris} 334105837Schris 335105837Schrisint 336119317Srwatsonmac_prepare(struct mac **mac, const char *elements) 337105698Srwatson{ 338105698Srwatson 339105698Srwatson if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN) 340105698Srwatson return (EINVAL); 341105698Srwatson 342105698Srwatson *mac = (struct mac *) malloc(sizeof(**mac)); 343105698Srwatson if (*mac == NULL) 344105698Srwatson return (ENOMEM); 345105698Srwatson 346105698Srwatson (*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN); 347105698Srwatson if ((*mac)->m_string == NULL) { 348105698Srwatson free(*mac); 349105698Srwatson *mac = NULL; 350105698Srwatson return (ENOMEM); 351105698Srwatson } 352105698Srwatson 353105698Srwatson strcpy((*mac)->m_string, elements); 354105698Srwatson (*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN; 355105698Srwatson 356105698Srwatson return (0); 357105698Srwatson} 358105698Srwatson 359105698Srwatsonint 360119314Srwatsonmac_prepare_type(struct mac **mac, const char *name) 361119314Srwatson{ 362119314Srwatson struct label_default *ld; 363122732Srwatson int error; 364119314Srwatson 365122732Srwatson error = mac_maybe_init_internal(); 366122732Srwatson if (error != 0) 367122732Srwatson return (error); 368122732Srwatson 369119314Srwatson for (ld = LIST_FIRST(&label_default_head); ld != NULL; 370119314Srwatson ld = LIST_NEXT(ld, ld_entries)) { 371119314Srwatson if (strcmp(name, ld->ld_name) == 0) 372119314Srwatson return (mac_prepare(mac, ld->ld_labels)); 373119314Srwatson } 374119314Srwatson 375119588Srwatson errno = ENOENT; 376119588Srwatson return (-1); /* XXXMAC: ENOLABEL */ 377119314Srwatson} 378119314Srwatson 379119314Srwatsonint 380119314Srwatsonmac_prepare_ifnet_label(struct mac **mac) 381119314Srwatson{ 382119314Srwatson 383119314Srwatson return (mac_prepare_type(mac, "ifnet")); 384119314Srwatson} 385119314Srwatson 386119314Srwatsonint 387105698Srwatsonmac_prepare_file_label(struct mac **mac) 388105698Srwatson{ 389105698Srwatson 390119314Srwatson return (mac_prepare_type(mac, "file")); 391105698Srwatson} 392105698Srwatson 393105698Srwatsonint 394119314Srwatsonmac_prepare_packet_label(struct mac **mac) 395105698Srwatson{ 396105698Srwatson 397119314Srwatson return (mac_prepare_type(mac, "packet")); 398119314Srwatson} 399105698Srwatson 400105698Srwatsonint 401105698Srwatsonmac_prepare_process_label(struct mac **mac) 402105698Srwatson{ 403105698Srwatson 404119314Srwatson return (mac_prepare_type(mac, "process")); 405105698Srwatson} 406105698Srwatson 407105698Srwatson/* 408105698Srwatson * Simply test whether the TrustedBSD/MAC MIB tree is present; if so, 409105698Srwatson * return 1 to indicate that the system has MAC enabled overall or for 410105698Srwatson * a given policy. 411105698Srwatson */ 412105698Srwatsonint 413105698Srwatsonmac_is_present(const char *policyname) 414105698Srwatson{ 415105698Srwatson int mib[5]; 416105698Srwatson size_t siz; 417105698Srwatson char *mibname; 418105698Srwatson int error; 419105698Srwatson 420105698Srwatson if (policyname != NULL) { 421105698Srwatson if (policyname[strcspn(policyname, ".=")] != '\0') { 422105698Srwatson errno = EINVAL; 423105698Srwatson return (-1); 424105698Srwatson } 425105698Srwatson mibname = malloc(sizeof("security.mac.") - 1 + 426105698Srwatson strlen(policyname) + sizeof(".enabled")); 427105698Srwatson if (mibname == NULL) 428105698Srwatson return (-1); 429105698Srwatson strcpy(mibname, "security.mac."); 430105698Srwatson strcat(mibname, policyname); 431105698Srwatson strcat(mibname, ".enabled"); 432105698Srwatson siz = 5; 433105698Srwatson error = sysctlnametomib(mibname, mib, &siz); 434105698Srwatson free(mibname); 435105698Srwatson } else { 436105698Srwatson siz = 3; 437105698Srwatson error = sysctlnametomib("security.mac", mib, &siz); 438105698Srwatson } 439105698Srwatson if (error == -1) { 440105698Srwatson switch (errno) { 441105698Srwatson case ENOTDIR: 442105698Srwatson case ENOENT: 443105698Srwatson return (0); 444105698Srwatson default: 445105698Srwatson return (error); 446105698Srwatson } 447105698Srwatson } 448105698Srwatson return (1); 449105698Srwatson} 450