1391b1d75SRobert Watson /* 2391b1d75SRobert Watson * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 3738824adSRobert Watson * Copyright (c) 2002, 2003 Networks Associates Technology, Inc. 4391b1d75SRobert Watson * All rights reserved. 5391b1d75SRobert Watson * 6391b1d75SRobert Watson * This software was developed by Robert Watson for the TrustedBSD Project. 7391b1d75SRobert Watson * 8f8d08150SRobert Watson * This software was developed for the FreeBSD Project in part by Network 9f8d08150SRobert Watson * Associates Laboratories, the Security Research Division of Network 10f8d08150SRobert Watson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 11f8d08150SRobert Watson * as part of the DARPA CHATS research program. 12391b1d75SRobert Watson * 13391b1d75SRobert Watson * Redistribution and use in source and binary forms, with or without 14391b1d75SRobert Watson * modification, are permitted provided that the following conditions 15391b1d75SRobert Watson * are met: 16391b1d75SRobert Watson * 1. Redistributions of source code must retain the above copyright 17391b1d75SRobert Watson * notice, this list of conditions and the following disclaimer. 18391b1d75SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 19391b1d75SRobert Watson * notice, this list of conditions and the following disclaimer in the 20391b1d75SRobert Watson * documentation and/or other materials provided with the distribution. 21391b1d75SRobert Watson * 22391b1d75SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23391b1d75SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24391b1d75SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25391b1d75SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26391b1d75SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27391b1d75SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28391b1d75SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29391b1d75SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30391b1d75SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31391b1d75SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32391b1d75SRobert Watson * SUCH DAMAGE. 33391b1d75SRobert Watson * 34391b1d75SRobert Watson * $FreeBSD$ 35391b1d75SRobert Watson */ 36391b1d75SRobert Watson 37391b1d75SRobert Watson #include <sys/types.h> 38391b1d75SRobert Watson #include <sys/queue.h> 39391b1d75SRobert Watson #include <sys/sysctl.h> 40391b1d75SRobert Watson 41391b1d75SRobert Watson #include <dlfcn.h> 42391b1d75SRobert Watson #include <errno.h> 43688dfe45SGarrett Wollman #include <limits.h> 44391b1d75SRobert Watson #include <stdio.h> 45391b1d75SRobert Watson #include <stdlib.h> 46391b1d75SRobert Watson #include <string.h> 47391b1d75SRobert Watson 48391b1d75SRobert Watson #include <sys/mac.h> 49391b1d75SRobert Watson 50391b1d75SRobert Watson static int internal_initialized; 51391b1d75SRobert Watson 52738824adSRobert Watson /* 53738824adSRobert Watson * Maintain a list of default label preparations for various object 54738824adSRobert Watson * types. Each name will appear only once in the list. 55738824adSRobert Watson * 56738824adSRobert Watson * XXXMAC: Not thread-safe. 57738824adSRobert Watson */ 58738824adSRobert Watson LIST_HEAD(, label_default) label_default_head; 59738824adSRobert Watson struct label_default { 60738824adSRobert Watson char *ld_name; 61738824adSRobert Watson char *ld_labels; 62738824adSRobert Watson LIST_ENTRY(label_default) ld_entries; 63738824adSRobert Watson }; 64391b1d75SRobert Watson 65391b1d75SRobert Watson static void 66391b1d75SRobert Watson mac_destroy_labels(void) 67391b1d75SRobert Watson { 68738824adSRobert Watson struct label_default *ld; 69391b1d75SRobert Watson 70738824adSRobert Watson while ((ld = LIST_FIRST(&label_default_head))) { 71738824adSRobert Watson free(ld->ld_name); 72738824adSRobert Watson free(ld->ld_labels); 73738824adSRobert Watson LIST_REMOVE(ld, ld_entries); 74738824adSRobert Watson free(ld); 75391b1d75SRobert Watson } 76391b1d75SRobert Watson } 77391b1d75SRobert Watson 78391b1d75SRobert Watson static void 79391b1d75SRobert Watson mac_destroy_internal(void) 80391b1d75SRobert Watson { 81391b1d75SRobert Watson 82391b1d75SRobert Watson mac_destroy_labels(); 83391b1d75SRobert Watson 84391b1d75SRobert Watson internal_initialized = 0; 85391b1d75SRobert Watson } 86391b1d75SRobert Watson 87391b1d75SRobert Watson static int 88738824adSRobert Watson mac_add_type(const char *name, const char *labels) 89391b1d75SRobert Watson { 90738824adSRobert Watson struct label_default *ld, *ld_new; 91738824adSRobert Watson char *name_dup, *labels_dup; 92738824adSRobert Watson 93738824adSRobert Watson /* 94738824adSRobert Watson * Speculatively allocate all the memory now to avoid allocating 95738824adSRobert Watson * later when we will someday hold a mutex. 96738824adSRobert Watson */ 97738824adSRobert Watson name_dup = strdup(name); 98738824adSRobert Watson if (name_dup == NULL) { 99738824adSRobert Watson errno = ENOMEM; 100738824adSRobert Watson return (-1); 101738824adSRobert Watson } 102738824adSRobert Watson labels_dup = strdup(labels); 103738824adSRobert Watson if (labels_dup == NULL) { 104738824adSRobert Watson free(name_dup); 105738824adSRobert Watson errno = ENOMEM; 106738824adSRobert Watson return (-1); 107738824adSRobert Watson } 108738824adSRobert Watson ld_new = malloc(sizeof(*ld)); 109738824adSRobert Watson if (ld_new == NULL) { 110738824adSRobert Watson free(name_dup); 111738824adSRobert Watson free(labels_dup); 112738824adSRobert Watson errno = ENOMEM; 113738824adSRobert Watson return (-1); 114738824adSRobert Watson } 115738824adSRobert Watson 116738824adSRobert Watson /* 117738824adSRobert Watson * If the type is already present, replace the current entry 118738824adSRobert Watson * rather than add a new instance. 119738824adSRobert Watson */ 120738824adSRobert Watson for (ld = LIST_FIRST(&label_default_head); ld != NULL; 121738824adSRobert Watson ld = LIST_NEXT(ld, ld_entries)) { 122738824adSRobert Watson if (strcmp(name, ld->ld_name) == 0) 123738824adSRobert Watson break; 124738824adSRobert Watson } 125738824adSRobert Watson 126738824adSRobert Watson if (ld != NULL) { 127738824adSRobert Watson free(ld->ld_labels); 128738824adSRobert Watson ld->ld_labels = labels_dup; 129738824adSRobert Watson labels_dup = NULL; 130738824adSRobert Watson } else { 131738824adSRobert Watson ld = ld_new; 132738824adSRobert Watson ld->ld_name = name_dup; 133738824adSRobert Watson ld->ld_labels = labels_dup; 134738824adSRobert Watson 135738824adSRobert Watson ld_new = NULL; 136738824adSRobert Watson name_dup = NULL; 137738824adSRobert Watson labels_dup = NULL; 138738824adSRobert Watson 139738824adSRobert Watson LIST_INSERT_HEAD(&label_default_head, ld, ld_entries); 140738824adSRobert Watson } 141738824adSRobert Watson 142738824adSRobert Watson if (name_dup != NULL) 143738824adSRobert Watson free(name_dup); 144738824adSRobert Watson if (labels_dup != NULL) 145738824adSRobert Watson free(labels_dup); 146738824adSRobert Watson if (ld_new != NULL) 147738824adSRobert Watson free(ld_new); 148738824adSRobert Watson 149738824adSRobert Watson return (0); 150738824adSRobert Watson } 151738824adSRobert Watson 152738824adSRobert Watson static char * 153738824adSRobert Watson next_token(char **string) 154738824adSRobert Watson { 155738824adSRobert Watson char *token; 156738824adSRobert Watson 157738824adSRobert Watson token = strsep(string, " \t"); 158738824adSRobert Watson while (token != NULL && *token == '\0') 159738824adSRobert Watson token = strsep(string, " \t"); 160738824adSRobert Watson 161738824adSRobert Watson return (token); 162738824adSRobert Watson } 163738824adSRobert Watson 164738824adSRobert Watson static int 165738824adSRobert Watson mac_init_internal(int ignore_errors) 166738824adSRobert Watson { 167738824adSRobert Watson const char *filename; 168391b1d75SRobert Watson char line[LINE_MAX]; 169738824adSRobert Watson FILE *file; 170391b1d75SRobert Watson int error; 171391b1d75SRobert Watson 172391b1d75SRobert Watson error = 0; 173391b1d75SRobert Watson 174738824adSRobert Watson LIST_INIT(&label_default_head); 175738824adSRobert Watson 176738824adSRobert Watson if (!issetugid() && getenv("MAC_CONFFILE") != NULL) 177738824adSRobert Watson filename = getenv("MAC_CONFFILE"); 178738824adSRobert Watson else 179738824adSRobert Watson filename = MAC_CONFFILE; 180738824adSRobert Watson file = fopen(filename, "r"); 181391b1d75SRobert Watson if (file == NULL) 182391b1d75SRobert Watson return (0); 183391b1d75SRobert Watson 184391b1d75SRobert Watson while (fgets(line, LINE_MAX, file)) { 185738824adSRobert Watson char *arg, *comment, *parse, *statement; 186391b1d75SRobert Watson 187391b1d75SRobert Watson if (line[strlen(line)-1] == '\n') 188391b1d75SRobert Watson line[strlen(line)-1] = '\0'; 189391b1d75SRobert Watson else { 190738824adSRobert Watson if (ignore_errors) 191738824adSRobert Watson continue; 192391b1d75SRobert Watson fclose(file); 193391b1d75SRobert Watson error = EINVAL; 194391b1d75SRobert Watson goto just_return; 195391b1d75SRobert Watson } 196391b1d75SRobert Watson 197738824adSRobert Watson /* Remove any comment. */ 198738824adSRobert Watson comment = line; 199738824adSRobert Watson parse = strsep(&comment, "#"); 200391b1d75SRobert Watson 201738824adSRobert Watson /* Blank lines OK. */ 202738824adSRobert Watson statement = next_token(&parse); 203738824adSRobert Watson if (statement == NULL) 204391b1d75SRobert Watson continue; 205391b1d75SRobert Watson 206738824adSRobert Watson if (strcmp(statement, "default_labels") == 0) { 207738824adSRobert Watson char *name, *labels; 208738824adSRobert Watson 209738824adSRobert Watson name = next_token(&parse); 210738824adSRobert Watson labels = next_token(&parse); 211738824adSRobert Watson if (name == NULL || labels == NULL || 212738824adSRobert Watson next_token(&parse) != NULL) { 213738824adSRobert Watson if (ignore_errors) 214391b1d75SRobert Watson continue; 215738824adSRobert Watson error = EINVAL; 216391b1d75SRobert Watson fclose(file); 217391b1d75SRobert Watson goto just_return; 218391b1d75SRobert Watson } 219391b1d75SRobert Watson 220738824adSRobert Watson if (mac_add_type(name, labels) == -1) { 221738824adSRobert Watson if (ignore_errors) 222738824adSRobert Watson continue; 223391b1d75SRobert Watson fclose(file); 224391b1d75SRobert Watson goto just_return; 225391b1d75SRobert Watson } 226738824adSRobert Watson } else if (strcmp(statement, "default_ifnet_labels") == 0 || 227738824adSRobert Watson strcmp(statement, "default_file_labels") == 0 || 228738824adSRobert Watson strcmp(statement, "default_process_labels") == 0) { 229738824adSRobert Watson char *labels, *type; 230391b1d75SRobert Watson 231738824adSRobert Watson if (strcmp(statement, "default_ifnet_labels") == 0) 232738824adSRobert Watson type = "ifnet"; 233738824adSRobert Watson else if (strcmp(statement, "default_file_labels") == 0) 234738824adSRobert Watson type = "file"; 235738824adSRobert Watson else if (strcmp(statement, "default_process_labels") == 236738824adSRobert Watson 0) 237738824adSRobert Watson type = "process"; 238738824adSRobert Watson 239738824adSRobert Watson labels = next_token(&parse); 240738824adSRobert Watson if (labels == NULL || next_token(&parse) != NULL) { 241738824adSRobert Watson if (ignore_errors) 242738824adSRobert Watson continue; 243738824adSRobert Watson error = EINVAL; 244391b1d75SRobert Watson fclose(file); 245391b1d75SRobert Watson goto just_return; 246391b1d75SRobert Watson } 247738824adSRobert Watson 248738824adSRobert Watson if (mac_add_type(type, labels) == -1) { 249738824adSRobert Watson if (ignore_errors) 250738824adSRobert Watson continue; 251738824adSRobert Watson fclose(file); 252738824adSRobert Watson goto just_return; 253391b1d75SRobert Watson } 254391b1d75SRobert Watson } else { 255738824adSRobert Watson if (ignore_errors) 256738824adSRobert Watson continue; 257391b1d75SRobert Watson fclose(file); 258391b1d75SRobert Watson error = EINVAL; 259391b1d75SRobert Watson goto just_return; 260391b1d75SRobert Watson } 261391b1d75SRobert Watson } 262391b1d75SRobert Watson 263391b1d75SRobert Watson fclose(file); 264391b1d75SRobert Watson 265391b1d75SRobert Watson internal_initialized = 1; 266391b1d75SRobert Watson 267391b1d75SRobert Watson just_return: 268391b1d75SRobert Watson if (error != 0) 269391b1d75SRobert Watson mac_destroy_internal(); 270391b1d75SRobert Watson return (error); 271391b1d75SRobert Watson } 272391b1d75SRobert Watson 273391b1d75SRobert Watson static int 274391b1d75SRobert Watson mac_maybe_init_internal(void) 275391b1d75SRobert Watson { 276391b1d75SRobert Watson 277391b1d75SRobert Watson if (!internal_initialized) 278738824adSRobert Watson return (mac_init_internal(1)); 279391b1d75SRobert Watson else 280391b1d75SRobert Watson return (0); 281391b1d75SRobert Watson } 282391b1d75SRobert Watson 283391b1d75SRobert Watson int 284391b1d75SRobert Watson mac_reload(void) 285391b1d75SRobert Watson { 286391b1d75SRobert Watson 287391b1d75SRobert Watson if (internal_initialized) 288391b1d75SRobert Watson mac_destroy_internal(); 289738824adSRobert Watson return (mac_init_internal(0)); 290391b1d75SRobert Watson } 291391b1d75SRobert Watson 292391b1d75SRobert Watson int 293391b1d75SRobert Watson mac_free(struct mac *mac) 294391b1d75SRobert Watson { 295391b1d75SRobert Watson 296391b1d75SRobert Watson if (mac->m_string != NULL) 297391b1d75SRobert Watson free(mac->m_string); 298391b1d75SRobert Watson free(mac); 299391b1d75SRobert Watson 300391b1d75SRobert Watson return (0); 301391b1d75SRobert Watson } 302391b1d75SRobert Watson 303391b1d75SRobert Watson int 304391b1d75SRobert Watson mac_from_text(struct mac **mac, const char *text) 305391b1d75SRobert Watson { 306391b1d75SRobert Watson 307391b1d75SRobert Watson *mac = (struct mac *) malloc(sizeof(**mac)); 308391b1d75SRobert Watson if (*mac == NULL) 309391b1d75SRobert Watson return (ENOMEM); 310391b1d75SRobert Watson 311391b1d75SRobert Watson (*mac)->m_string = strdup(text); 312391b1d75SRobert Watson if ((*mac)->m_string == NULL) { 313391b1d75SRobert Watson free(*mac); 314391b1d75SRobert Watson *mac = NULL; 315391b1d75SRobert Watson return (ENOMEM); 316391b1d75SRobert Watson } 317391b1d75SRobert Watson 318391b1d75SRobert Watson (*mac)->m_buflen = strlen((*mac)->m_string)+1; 319391b1d75SRobert Watson 320391b1d75SRobert Watson return (0); 321391b1d75SRobert Watson } 322391b1d75SRobert Watson 323391b1d75SRobert Watson int 3244bae1674SChris Costello mac_to_text(struct mac *mac, char **text) 3254bae1674SChris Costello { 3264bae1674SChris Costello 3274bae1674SChris Costello *text = strdup(mac->m_string); 3284bae1674SChris Costello if (*text == NULL) 3294bae1674SChris Costello return (ENOMEM); 3304bae1674SChris Costello return (0); 3314bae1674SChris Costello } 3324bae1674SChris Costello 3334bae1674SChris Costello int 334391b1d75SRobert Watson mac_prepare(struct mac **mac, char *elements) 335391b1d75SRobert Watson { 336391b1d75SRobert Watson 337391b1d75SRobert Watson if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN) 338391b1d75SRobert Watson return (EINVAL); 339391b1d75SRobert Watson 340391b1d75SRobert Watson *mac = (struct mac *) malloc(sizeof(**mac)); 341391b1d75SRobert Watson if (*mac == NULL) 342391b1d75SRobert Watson return (ENOMEM); 343391b1d75SRobert Watson 344391b1d75SRobert Watson (*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN); 345391b1d75SRobert Watson if ((*mac)->m_string == NULL) { 346391b1d75SRobert Watson free(*mac); 347391b1d75SRobert Watson *mac = NULL; 348391b1d75SRobert Watson return (ENOMEM); 349391b1d75SRobert Watson } 350391b1d75SRobert Watson 351391b1d75SRobert Watson strcpy((*mac)->m_string, elements); 352391b1d75SRobert Watson (*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN; 353391b1d75SRobert Watson 354391b1d75SRobert Watson return (0); 355391b1d75SRobert Watson } 356391b1d75SRobert Watson 357391b1d75SRobert Watson int 358738824adSRobert Watson mac_prepare_type(struct mac **mac, const char *name) 359391b1d75SRobert Watson { 360738824adSRobert Watson struct label_default *ld; 361391b1d75SRobert Watson 362738824adSRobert Watson for (ld = LIST_FIRST(&label_default_head); ld != NULL; 363738824adSRobert Watson ld = LIST_NEXT(ld, ld_entries)) { 364738824adSRobert Watson if (strcmp(name, ld->ld_name) == 0) 365738824adSRobert Watson return (mac_prepare(mac, ld->ld_labels)); 366738824adSRobert Watson } 367391b1d75SRobert Watson 368738824adSRobert Watson return (ENOENT); /* XXXMAC: ENOLABEL */ 369391b1d75SRobert Watson } 370391b1d75SRobert Watson 371391b1d75SRobert Watson int 372391b1d75SRobert Watson mac_prepare_ifnet_label(struct mac **mac) 373391b1d75SRobert Watson { 374391b1d75SRobert Watson int error; 375391b1d75SRobert Watson 376391b1d75SRobert Watson error = mac_maybe_init_internal(); 377391b1d75SRobert Watson if (error != 0) 378391b1d75SRobert Watson return (error); 379391b1d75SRobert Watson 380738824adSRobert Watson return (mac_prepare_type(mac, "ifnet")); 381391b1d75SRobert Watson } 382738824adSRobert Watson 383738824adSRobert Watson int 384738824adSRobert Watson mac_prepare_file_label(struct mac **mac) 385738824adSRobert Watson { 386738824adSRobert Watson int error; 387738824adSRobert Watson 388738824adSRobert Watson error = mac_maybe_init_internal(); 389738824adSRobert Watson if (error != 0) 390738824adSRobert Watson return (error); 391738824adSRobert Watson 392738824adSRobert Watson return (mac_prepare_type(mac, "file")); 393738824adSRobert Watson } 394738824adSRobert Watson 395738824adSRobert Watson int 396738824adSRobert Watson mac_prepare_packet_label(struct mac **mac) 397738824adSRobert Watson { 398738824adSRobert Watson int error; 399738824adSRobert Watson 400738824adSRobert Watson error = mac_maybe_init_internal(); 401738824adSRobert Watson if (error != 0) 402738824adSRobert Watson return (error); 403738824adSRobert Watson 404738824adSRobert Watson return (mac_prepare_type(mac, "packet")); 405738824adSRobert Watson } 406738824adSRobert Watson 407391b1d75SRobert Watson int 408391b1d75SRobert Watson mac_prepare_process_label(struct mac **mac) 409391b1d75SRobert Watson { 410391b1d75SRobert Watson int error; 411391b1d75SRobert Watson 412391b1d75SRobert Watson error = mac_maybe_init_internal(); 413391b1d75SRobert Watson if (error != 0) 414391b1d75SRobert Watson return (error); 415391b1d75SRobert Watson 416738824adSRobert Watson return (mac_prepare_type(mac, "process")); 417391b1d75SRobert Watson } 418391b1d75SRobert Watson 419391b1d75SRobert Watson /* 420391b1d75SRobert Watson * Simply test whether the TrustedBSD/MAC MIB tree is present; if so, 421391b1d75SRobert Watson * return 1 to indicate that the system has MAC enabled overall or for 422391b1d75SRobert Watson * a given policy. 423391b1d75SRobert Watson */ 424391b1d75SRobert Watson int 425391b1d75SRobert Watson mac_is_present(const char *policyname) 426391b1d75SRobert Watson { 427391b1d75SRobert Watson int mib[5]; 428391b1d75SRobert Watson size_t siz; 429391b1d75SRobert Watson char *mibname; 430391b1d75SRobert Watson int error; 431391b1d75SRobert Watson 432391b1d75SRobert Watson if (policyname != NULL) { 433391b1d75SRobert Watson if (policyname[strcspn(policyname, ".=")] != '\0') { 434391b1d75SRobert Watson errno = EINVAL; 435391b1d75SRobert Watson return (-1); 436391b1d75SRobert Watson } 437391b1d75SRobert Watson mibname = malloc(sizeof("security.mac.") - 1 + 438391b1d75SRobert Watson strlen(policyname) + sizeof(".enabled")); 439391b1d75SRobert Watson if (mibname == NULL) 440391b1d75SRobert Watson return (-1); 441391b1d75SRobert Watson strcpy(mibname, "security.mac."); 442391b1d75SRobert Watson strcat(mibname, policyname); 443391b1d75SRobert Watson strcat(mibname, ".enabled"); 444391b1d75SRobert Watson siz = 5; 445391b1d75SRobert Watson error = sysctlnametomib(mibname, mib, &siz); 446391b1d75SRobert Watson free(mibname); 447391b1d75SRobert Watson } else { 448391b1d75SRobert Watson siz = 3; 449391b1d75SRobert Watson error = sysctlnametomib("security.mac", mib, &siz); 450391b1d75SRobert Watson } 451391b1d75SRobert Watson if (error == -1) { 452391b1d75SRobert Watson switch (errno) { 453391b1d75SRobert Watson case ENOTDIR: 454391b1d75SRobert Watson case ENOENT: 455391b1d75SRobert Watson return (0); 456391b1d75SRobert Watson default: 457391b1d75SRobert Watson return (error); 458391b1d75SRobert Watson } 459391b1d75SRobert Watson } 460391b1d75SRobert Watson return (1); 461391b1d75SRobert Watson } 462