mac.c revision 122868
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 * $FreeBSD: head/lib/libc/posix1e/mac.c 122868 2003-11-17 19:48:35Z rwatson $ 35105698Srwatson */ 36105698Srwatson 37105698Srwatson#include <sys/types.h> 38105698Srwatson#include <sys/queue.h> 39105698Srwatson#include <sys/sysctl.h> 40105698Srwatson 41105698Srwatson#include <dlfcn.h> 42105698Srwatson#include <errno.h> 43106053Swollman#include <limits.h> 44105698Srwatson#include <stdio.h> 45105698Srwatson#include <stdlib.h> 46105698Srwatson#include <string.h> 47105698Srwatson 48105698Srwatson#include <sys/mac.h> 49105698Srwatson 50105698Srwatsonstatic int internal_initialized; 51105698Srwatson 52119314Srwatson/* 53119314Srwatson * Maintain a list of default label preparations for various object 54119314Srwatson * types. Each name will appear only once in the list. 55119314Srwatson * 56119314Srwatson * XXXMAC: Not thread-safe. 57119314Srwatson */ 58122868Srwatsonstatic LIST_HEAD(, label_default) label_default_head; 59119314Srwatsonstruct label_default { 60119314Srwatson char *ld_name; 61119314Srwatson char *ld_labels; 62119314Srwatson LIST_ENTRY(label_default) ld_entries; 63119314Srwatson}; 64105698Srwatson 65105698Srwatsonstatic void 66105698Srwatsonmac_destroy_labels(void) 67105698Srwatson{ 68119314Srwatson struct label_default *ld; 69105698Srwatson 70119314Srwatson while ((ld = LIST_FIRST(&label_default_head))) { 71119314Srwatson free(ld->ld_name); 72119314Srwatson free(ld->ld_labels); 73119314Srwatson LIST_REMOVE(ld, ld_entries); 74119314Srwatson free(ld); 75105698Srwatson } 76105698Srwatson} 77105698Srwatson 78105698Srwatsonstatic void 79105698Srwatsonmac_destroy_internal(void) 80105698Srwatson{ 81105698Srwatson 82105698Srwatson mac_destroy_labels(); 83105698Srwatson 84105698Srwatson internal_initialized = 0; 85105698Srwatson} 86105698Srwatson 87105698Srwatsonstatic int 88119314Srwatsonmac_add_type(const char *name, const char *labels) 89105698Srwatson{ 90119314Srwatson struct label_default *ld, *ld_new; 91119314Srwatson char *name_dup, *labels_dup; 92119314Srwatson 93119314Srwatson /* 94119314Srwatson * Speculatively allocate all the memory now to avoid allocating 95119314Srwatson * later when we will someday hold a mutex. 96119314Srwatson */ 97119314Srwatson name_dup = strdup(name); 98119314Srwatson if (name_dup == NULL) { 99119314Srwatson errno = ENOMEM; 100119314Srwatson return (-1); 101119314Srwatson } 102119314Srwatson labels_dup = strdup(labels); 103119314Srwatson if (labels_dup == NULL) { 104119314Srwatson free(name_dup); 105119314Srwatson errno = ENOMEM; 106119314Srwatson return (-1); 107119314Srwatson } 108119314Srwatson ld_new = malloc(sizeof(*ld)); 109119314Srwatson if (ld_new == NULL) { 110119314Srwatson free(name_dup); 111119314Srwatson free(labels_dup); 112119314Srwatson errno = ENOMEM; 113119314Srwatson return (-1); 114119314Srwatson } 115119314Srwatson 116119314Srwatson /* 117119314Srwatson * If the type is already present, replace the current entry 118119314Srwatson * rather than add a new instance. 119119314Srwatson */ 120119314Srwatson for (ld = LIST_FIRST(&label_default_head); ld != NULL; 121119314Srwatson ld = LIST_NEXT(ld, ld_entries)) { 122119314Srwatson if (strcmp(name, ld->ld_name) == 0) 123119314Srwatson break; 124119314Srwatson } 125119314Srwatson 126119314Srwatson if (ld != NULL) { 127119314Srwatson free(ld->ld_labels); 128119314Srwatson ld->ld_labels = labels_dup; 129119314Srwatson labels_dup = NULL; 130119314Srwatson } else { 131119314Srwatson ld = ld_new; 132119314Srwatson ld->ld_name = name_dup; 133119314Srwatson ld->ld_labels = labels_dup; 134119314Srwatson 135119314Srwatson ld_new = NULL; 136119314Srwatson name_dup = NULL; 137119314Srwatson labels_dup = NULL; 138119314Srwatson 139119314Srwatson LIST_INSERT_HEAD(&label_default_head, ld, ld_entries); 140119314Srwatson } 141119314Srwatson 142119314Srwatson if (name_dup != NULL) 143119314Srwatson free(name_dup); 144119314Srwatson if (labels_dup != NULL) 145119314Srwatson free(labels_dup); 146119314Srwatson if (ld_new != NULL) 147119314Srwatson free(ld_new); 148119314Srwatson 149119314Srwatson return (0); 150119314Srwatson} 151119314Srwatson 152119314Srwatsonstatic char * 153119314Srwatsonnext_token(char **string) 154119314Srwatson{ 155119314Srwatson char *token; 156119314Srwatson 157119314Srwatson token = strsep(string, " \t"); 158119314Srwatson while (token != NULL && *token == '\0') 159119314Srwatson token = strsep(string, " \t"); 160119314Srwatson 161119314Srwatson return (token); 162119314Srwatson} 163119314Srwatson 164119314Srwatsonstatic int 165119314Srwatsonmac_init_internal(int ignore_errors) 166119314Srwatson{ 167119314Srwatson const char *filename; 168119314Srwatson char line[LINE_MAX]; 169105698Srwatson FILE *file; 170105698Srwatson int error; 171105698Srwatson 172105698Srwatson error = 0; 173105698Srwatson 174119314Srwatson LIST_INIT(&label_default_head); 175119314Srwatson 176119314Srwatson if (!issetugid() && getenv("MAC_CONFFILE") != NULL) 177119314Srwatson filename = getenv("MAC_CONFFILE"); 178119314Srwatson else 179119314Srwatson filename = MAC_CONFFILE; 180119314Srwatson file = fopen(filename, "r"); 181105698Srwatson if (file == NULL) 182105698Srwatson return (0); 183105698Srwatson 184105698Srwatson while (fgets(line, LINE_MAX, file)) { 185119314Srwatson char *arg, *comment, *parse, *statement; 186105698Srwatson 187105698Srwatson if (line[strlen(line)-1] == '\n') 188105698Srwatson line[strlen(line)-1] = '\0'; 189105698Srwatson else { 190119314Srwatson if (ignore_errors) 191119314Srwatson continue; 192105698Srwatson fclose(file); 193105698Srwatson error = EINVAL; 194105698Srwatson goto just_return; 195105698Srwatson } 196105698Srwatson 197119314Srwatson /* Remove any comment. */ 198119314Srwatson comment = line; 199119314Srwatson parse = strsep(&comment, "#"); 200105698Srwatson 201119314Srwatson /* Blank lines OK. */ 202119314Srwatson statement = next_token(&parse); 203119314Srwatson if (statement == NULL) 204105698Srwatson continue; 205105698Srwatson 206119314Srwatson if (strcmp(statement, "default_labels") == 0) { 207119314Srwatson char *name, *labels; 208105698Srwatson 209119314Srwatson name = next_token(&parse); 210119314Srwatson labels = next_token(&parse); 211119314Srwatson if (name == NULL || labels == NULL || 212119314Srwatson next_token(&parse) != NULL) { 213119314Srwatson if (ignore_errors) 214119314Srwatson continue; 215119314Srwatson error = EINVAL; 216119314Srwatson fclose(file); 217119314Srwatson goto just_return; 218105698Srwatson } 219105698Srwatson 220119314Srwatson if (mac_add_type(name, labels) == -1) { 221119314Srwatson if (ignore_errors) 222119314Srwatson continue; 223119314Srwatson fclose(file); 224119314Srwatson goto just_return; 225105698Srwatson } 226119314Srwatson } else if (strcmp(statement, "default_ifnet_labels") == 0 || 227119314Srwatson strcmp(statement, "default_file_labels") == 0 || 228119314Srwatson strcmp(statement, "default_process_labels") == 0) { 229119314Srwatson char *labels, *type; 230105698Srwatson 231119314Srwatson if (strcmp(statement, "default_ifnet_labels") == 0) 232119314Srwatson type = "ifnet"; 233119314Srwatson else if (strcmp(statement, "default_file_labels") == 0) 234119314Srwatson type = "file"; 235119314Srwatson else if (strcmp(statement, "default_process_labels") == 236119314Srwatson 0) 237119314Srwatson type = "process"; 238119314Srwatson 239119314Srwatson labels = next_token(&parse); 240119314Srwatson if (labels == NULL || next_token(&parse) != NULL) { 241119314Srwatson if (ignore_errors) 242119314Srwatson continue; 243119314Srwatson error = EINVAL; 244119314Srwatson fclose(file); 245119314Srwatson goto just_return; 246105698Srwatson } 247105698Srwatson 248119314Srwatson if (mac_add_type(type, labels) == -1) { 249119314Srwatson if (ignore_errors) 250119314Srwatson continue; 251119314Srwatson fclose(file); 252119314Srwatson goto just_return; 253105698Srwatson } 254105698Srwatson } else { 255119314Srwatson if (ignore_errors) 256119314Srwatson continue; 257105698Srwatson fclose(file); 258105698Srwatson error = EINVAL; 259105698Srwatson goto just_return; 260105698Srwatson } 261105698Srwatson } 262105698Srwatson 263105698Srwatson fclose(file); 264105698Srwatson 265105698Srwatson internal_initialized = 1; 266105698Srwatson 267105698Srwatsonjust_return: 268105698Srwatson if (error != 0) 269105698Srwatson mac_destroy_internal(); 270105698Srwatson return (error); 271105698Srwatson} 272105698Srwatson 273105698Srwatsonstatic int 274105698Srwatsonmac_maybe_init_internal(void) 275105698Srwatson{ 276105698Srwatson 277105698Srwatson if (!internal_initialized) 278119314Srwatson return (mac_init_internal(1)); 279105698Srwatson else 280105698Srwatson return (0); 281105698Srwatson} 282105698Srwatson 283105698Srwatsonint 284105698Srwatsonmac_reload(void) 285105698Srwatson{ 286105698Srwatson 287105698Srwatson if (internal_initialized) 288105698Srwatson mac_destroy_internal(); 289119314Srwatson return (mac_init_internal(0)); 290105698Srwatson} 291105698Srwatson 292105698Srwatsonint 293105698Srwatsonmac_free(struct mac *mac) 294105698Srwatson{ 295105698Srwatson 296105698Srwatson if (mac->m_string != NULL) 297105698Srwatson free(mac->m_string); 298105698Srwatson free(mac); 299105698Srwatson 300105698Srwatson return (0); 301105698Srwatson} 302105698Srwatson 303105698Srwatsonint 304105698Srwatsonmac_from_text(struct mac **mac, const char *text) 305105698Srwatson{ 306105698Srwatson 307105698Srwatson *mac = (struct mac *) malloc(sizeof(**mac)); 308105698Srwatson if (*mac == NULL) 309105698Srwatson return (ENOMEM); 310105698Srwatson 311105698Srwatson (*mac)->m_string = strdup(text); 312105698Srwatson if ((*mac)->m_string == NULL) { 313105698Srwatson free(*mac); 314105698Srwatson *mac = NULL; 315105698Srwatson return (ENOMEM); 316105698Srwatson } 317105698Srwatson 318105698Srwatson (*mac)->m_buflen = strlen((*mac)->m_string)+1; 319105698Srwatson 320105698Srwatson return (0); 321105698Srwatson} 322105698Srwatson 323105698Srwatsonint 324105837Schrismac_to_text(struct mac *mac, char **text) 325105837Schris{ 326105837Schris 327105837Schris *text = strdup(mac->m_string); 328105837Schris if (*text == NULL) 329105837Schris return (ENOMEM); 330105837Schris return (0); 331105837Schris} 332105837Schris 333105837Schrisint 334119317Srwatsonmac_prepare(struct mac **mac, const char *elements) 335105698Srwatson{ 336105698Srwatson 337105698Srwatson if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN) 338105698Srwatson return (EINVAL); 339105698Srwatson 340105698Srwatson *mac = (struct mac *) malloc(sizeof(**mac)); 341105698Srwatson if (*mac == NULL) 342105698Srwatson return (ENOMEM); 343105698Srwatson 344105698Srwatson (*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN); 345105698Srwatson if ((*mac)->m_string == NULL) { 346105698Srwatson free(*mac); 347105698Srwatson *mac = NULL; 348105698Srwatson return (ENOMEM); 349105698Srwatson } 350105698Srwatson 351105698Srwatson strcpy((*mac)->m_string, elements); 352105698Srwatson (*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN; 353105698Srwatson 354105698Srwatson return (0); 355105698Srwatson} 356105698Srwatson 357105698Srwatsonint 358119314Srwatsonmac_prepare_type(struct mac **mac, const char *name) 359119314Srwatson{ 360119314Srwatson struct label_default *ld; 361122732Srwatson int error; 362119314Srwatson 363122732Srwatson error = mac_maybe_init_internal(); 364122732Srwatson if (error != 0) 365122732Srwatson return (error); 366122732Srwatson 367119314Srwatson for (ld = LIST_FIRST(&label_default_head); ld != NULL; 368119314Srwatson ld = LIST_NEXT(ld, ld_entries)) { 369119314Srwatson if (strcmp(name, ld->ld_name) == 0) 370119314Srwatson return (mac_prepare(mac, ld->ld_labels)); 371119314Srwatson } 372119314Srwatson 373119588Srwatson errno = ENOENT; 374119588Srwatson return (-1); /* XXXMAC: ENOLABEL */ 375119314Srwatson} 376119314Srwatson 377119314Srwatsonint 378119314Srwatsonmac_prepare_ifnet_label(struct mac **mac) 379119314Srwatson{ 380119314Srwatson 381119314Srwatson return (mac_prepare_type(mac, "ifnet")); 382119314Srwatson} 383119314Srwatson 384119314Srwatsonint 385105698Srwatsonmac_prepare_file_label(struct mac **mac) 386105698Srwatson{ 387105698Srwatson 388119314Srwatson return (mac_prepare_type(mac, "file")); 389105698Srwatson} 390105698Srwatson 391105698Srwatsonint 392119314Srwatsonmac_prepare_packet_label(struct mac **mac) 393105698Srwatson{ 394105698Srwatson 395119314Srwatson return (mac_prepare_type(mac, "packet")); 396119314Srwatson} 397105698Srwatson 398105698Srwatsonint 399105698Srwatsonmac_prepare_process_label(struct mac **mac) 400105698Srwatson{ 401105698Srwatson 402119314Srwatson return (mac_prepare_type(mac, "process")); 403105698Srwatson} 404105698Srwatson 405105698Srwatson/* 406105698Srwatson * Simply test whether the TrustedBSD/MAC MIB tree is present; if so, 407105698Srwatson * return 1 to indicate that the system has MAC enabled overall or for 408105698Srwatson * a given policy. 409105698Srwatson */ 410105698Srwatsonint 411105698Srwatsonmac_is_present(const char *policyname) 412105698Srwatson{ 413105698Srwatson int mib[5]; 414105698Srwatson size_t siz; 415105698Srwatson char *mibname; 416105698Srwatson int error; 417105698Srwatson 418105698Srwatson if (policyname != NULL) { 419105698Srwatson if (policyname[strcspn(policyname, ".=")] != '\0') { 420105698Srwatson errno = EINVAL; 421105698Srwatson return (-1); 422105698Srwatson } 423105698Srwatson mibname = malloc(sizeof("security.mac.") - 1 + 424105698Srwatson strlen(policyname) + sizeof(".enabled")); 425105698Srwatson if (mibname == NULL) 426105698Srwatson return (-1); 427105698Srwatson strcpy(mibname, "security.mac."); 428105698Srwatson strcat(mibname, policyname); 429105698Srwatson strcat(mibname, ".enabled"); 430105698Srwatson siz = 5; 431105698Srwatson error = sysctlnametomib(mibname, mib, &siz); 432105698Srwatson free(mibname); 433105698Srwatson } else { 434105698Srwatson siz = 3; 435105698Srwatson error = sysctlnametomib("security.mac", mib, &siz); 436105698Srwatson } 437105698Srwatson if (error == -1) { 438105698Srwatson switch (errno) { 439105698Srwatson case ENOTDIR: 440105698Srwatson case ENOENT: 441105698Srwatson return (0); 442105698Srwatson default: 443105698Srwatson return (error); 444105698Srwatson } 445105698Srwatson } 446105698Srwatson return (1); 447105698Srwatson} 448