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 35cee815cfSRobert Watson #include <sys/cdefs.h> 36cee815cfSRobert Watson __FBSDID("$FreeBSD$"); 37cee815cfSRobert Watson 38391b1d75SRobert Watson #include <sys/types.h> 39391b1d75SRobert Watson #include <sys/queue.h> 40391b1d75SRobert Watson #include <sys/sysctl.h> 41391b1d75SRobert Watson 42391b1d75SRobert Watson #include <dlfcn.h> 43391b1d75SRobert Watson #include <errno.h> 44688dfe45SGarrett Wollman #include <limits.h> 45391b1d75SRobert Watson #include <stdio.h> 46391b1d75SRobert Watson #include <stdlib.h> 47391b1d75SRobert Watson #include <string.h> 4884d9142fSJacques Vidrine #include <unistd.h> 49391b1d75SRobert Watson 50391b1d75SRobert Watson #include <sys/mac.h> 51391b1d75SRobert Watson 52391b1d75SRobert Watson static int internal_initialized; 53391b1d75SRobert Watson 54738824adSRobert Watson /* 55738824adSRobert Watson * Maintain a list of default label preparations for various object 56738824adSRobert Watson * types. Each name will appear only once in the list. 57738824adSRobert Watson * 58738824adSRobert Watson * XXXMAC: Not thread-safe. 59738824adSRobert Watson */ 60a2f046e8SRobert Watson static LIST_HEAD(, label_default) label_default_head; 61738824adSRobert Watson struct label_default { 62738824adSRobert Watson char *ld_name; 63738824adSRobert Watson char *ld_labels; 64738824adSRobert Watson LIST_ENTRY(label_default) ld_entries; 65738824adSRobert Watson }; 66391b1d75SRobert Watson 67391b1d75SRobert Watson static void 68391b1d75SRobert Watson mac_destroy_labels(void) 69391b1d75SRobert Watson { 70738824adSRobert Watson struct label_default *ld; 71391b1d75SRobert Watson 72738824adSRobert Watson while ((ld = LIST_FIRST(&label_default_head))) { 73738824adSRobert Watson free(ld->ld_name); 74738824adSRobert Watson free(ld->ld_labels); 75738824adSRobert Watson LIST_REMOVE(ld, ld_entries); 76738824adSRobert Watson free(ld); 77391b1d75SRobert Watson } 78391b1d75SRobert Watson } 79391b1d75SRobert Watson 80391b1d75SRobert Watson static void 81391b1d75SRobert Watson mac_destroy_internal(void) 82391b1d75SRobert Watson { 83391b1d75SRobert Watson 84391b1d75SRobert Watson mac_destroy_labels(); 85391b1d75SRobert Watson 86391b1d75SRobert Watson internal_initialized = 0; 87391b1d75SRobert Watson } 88391b1d75SRobert Watson 89391b1d75SRobert Watson static int 90738824adSRobert Watson mac_add_type(const char *name, const char *labels) 91391b1d75SRobert Watson { 92738824adSRobert Watson struct label_default *ld, *ld_new; 93738824adSRobert Watson char *name_dup, *labels_dup; 94738824adSRobert Watson 95738824adSRobert Watson /* 96738824adSRobert Watson * Speculatively allocate all the memory now to avoid allocating 97738824adSRobert Watson * later when we will someday hold a mutex. 98738824adSRobert Watson */ 99738824adSRobert Watson name_dup = strdup(name); 100738824adSRobert Watson if (name_dup == NULL) { 101738824adSRobert Watson errno = ENOMEM; 102738824adSRobert Watson return (-1); 103738824adSRobert Watson } 104738824adSRobert Watson labels_dup = strdup(labels); 105738824adSRobert Watson if (labels_dup == NULL) { 106738824adSRobert Watson free(name_dup); 107738824adSRobert Watson errno = ENOMEM; 108738824adSRobert Watson return (-1); 109738824adSRobert Watson } 110738824adSRobert Watson ld_new = malloc(sizeof(*ld)); 111738824adSRobert Watson if (ld_new == NULL) { 112738824adSRobert Watson free(name_dup); 113738824adSRobert Watson free(labels_dup); 114738824adSRobert Watson errno = ENOMEM; 115738824adSRobert Watson return (-1); 116738824adSRobert Watson } 117738824adSRobert Watson 118738824adSRobert Watson /* 119738824adSRobert Watson * If the type is already present, replace the current entry 120738824adSRobert Watson * rather than add a new instance. 121738824adSRobert Watson */ 122738824adSRobert Watson for (ld = LIST_FIRST(&label_default_head); ld != NULL; 123738824adSRobert Watson ld = LIST_NEXT(ld, ld_entries)) { 124738824adSRobert Watson if (strcmp(name, ld->ld_name) == 0) 125738824adSRobert Watson break; 126738824adSRobert Watson } 127738824adSRobert Watson 128738824adSRobert Watson if (ld != NULL) { 129738824adSRobert Watson free(ld->ld_labels); 130738824adSRobert Watson ld->ld_labels = labels_dup; 131738824adSRobert Watson labels_dup = NULL; 132738824adSRobert Watson } else { 133738824adSRobert Watson ld = ld_new; 134738824adSRobert Watson ld->ld_name = name_dup; 135738824adSRobert Watson ld->ld_labels = labels_dup; 136738824adSRobert Watson 137738824adSRobert Watson ld_new = NULL; 138738824adSRobert Watson name_dup = NULL; 139738824adSRobert Watson labels_dup = NULL; 140738824adSRobert Watson 141738824adSRobert Watson LIST_INSERT_HEAD(&label_default_head, ld, ld_entries); 142738824adSRobert Watson } 143738824adSRobert Watson 144738824adSRobert Watson if (name_dup != NULL) 145738824adSRobert Watson free(name_dup); 146738824adSRobert Watson if (labels_dup != NULL) 147738824adSRobert Watson free(labels_dup); 148738824adSRobert Watson if (ld_new != NULL) 149738824adSRobert Watson free(ld_new); 150738824adSRobert Watson 151738824adSRobert Watson return (0); 152738824adSRobert Watson } 153738824adSRobert Watson 154738824adSRobert Watson static char * 155738824adSRobert Watson next_token(char **string) 156738824adSRobert Watson { 157738824adSRobert Watson char *token; 158738824adSRobert Watson 159738824adSRobert Watson token = strsep(string, " \t"); 160738824adSRobert Watson while (token != NULL && *token == '\0') 161738824adSRobert Watson token = strsep(string, " \t"); 162738824adSRobert Watson 163738824adSRobert Watson return (token); 164738824adSRobert Watson } 165738824adSRobert Watson 166738824adSRobert Watson static int 167738824adSRobert Watson mac_init_internal(int ignore_errors) 168738824adSRobert Watson { 169738824adSRobert Watson const char *filename; 170391b1d75SRobert Watson char line[LINE_MAX]; 171738824adSRobert Watson FILE *file; 172391b1d75SRobert Watson int error; 173391b1d75SRobert Watson 174391b1d75SRobert Watson error = 0; 175391b1d75SRobert Watson 176738824adSRobert Watson LIST_INIT(&label_default_head); 177738824adSRobert Watson 178738824adSRobert Watson if (!issetugid() && getenv("MAC_CONFFILE") != NULL) 179738824adSRobert Watson filename = getenv("MAC_CONFFILE"); 180738824adSRobert Watson else 181738824adSRobert Watson filename = MAC_CONFFILE; 182*a93705b0SJilles Tjoelker file = fopen(filename, "re"); 183391b1d75SRobert Watson if (file == NULL) 184391b1d75SRobert Watson return (0); 185391b1d75SRobert Watson 186391b1d75SRobert Watson while (fgets(line, LINE_MAX, file)) { 18784d9142fSJacques Vidrine char *comment, *parse, *statement; 188391b1d75SRobert Watson 189391b1d75SRobert Watson if (line[strlen(line)-1] == '\n') 190391b1d75SRobert Watson line[strlen(line)-1] = '\0'; 191391b1d75SRobert Watson else { 192738824adSRobert Watson if (ignore_errors) 193738824adSRobert Watson continue; 194391b1d75SRobert Watson fclose(file); 195391b1d75SRobert Watson error = EINVAL; 196391b1d75SRobert Watson goto just_return; 197391b1d75SRobert Watson } 198391b1d75SRobert Watson 199738824adSRobert Watson /* Remove any comment. */ 200738824adSRobert Watson comment = line; 201738824adSRobert Watson parse = strsep(&comment, "#"); 202391b1d75SRobert Watson 203738824adSRobert Watson /* Blank lines OK. */ 204738824adSRobert Watson statement = next_token(&parse); 205738824adSRobert Watson if (statement == NULL) 206391b1d75SRobert Watson continue; 207391b1d75SRobert Watson 208738824adSRobert Watson if (strcmp(statement, "default_labels") == 0) { 209738824adSRobert Watson char *name, *labels; 210738824adSRobert Watson 211738824adSRobert Watson name = next_token(&parse); 212738824adSRobert Watson labels = next_token(&parse); 213738824adSRobert Watson if (name == NULL || labels == NULL || 214738824adSRobert Watson next_token(&parse) != NULL) { 215738824adSRobert Watson if (ignore_errors) 216391b1d75SRobert Watson continue; 217738824adSRobert Watson error = EINVAL; 218391b1d75SRobert Watson fclose(file); 219391b1d75SRobert Watson goto just_return; 220391b1d75SRobert Watson } 221391b1d75SRobert Watson 222738824adSRobert Watson if (mac_add_type(name, labels) == -1) { 223738824adSRobert Watson if (ignore_errors) 224738824adSRobert Watson continue; 225391b1d75SRobert Watson fclose(file); 226391b1d75SRobert Watson goto just_return; 227391b1d75SRobert Watson } 228738824adSRobert Watson } else if (strcmp(statement, "default_ifnet_labels") == 0 || 229738824adSRobert Watson strcmp(statement, "default_file_labels") == 0 || 230738824adSRobert Watson strcmp(statement, "default_process_labels") == 0) { 231738824adSRobert Watson char *labels, *type; 232391b1d75SRobert Watson 233738824adSRobert Watson if (strcmp(statement, "default_ifnet_labels") == 0) 234738824adSRobert Watson type = "ifnet"; 235738824adSRobert Watson else if (strcmp(statement, "default_file_labels") == 0) 236738824adSRobert Watson type = "file"; 237738824adSRobert Watson else if (strcmp(statement, "default_process_labels") == 238738824adSRobert Watson 0) 239738824adSRobert Watson type = "process"; 240738824adSRobert Watson 241738824adSRobert Watson labels = next_token(&parse); 242738824adSRobert Watson if (labels == NULL || next_token(&parse) != NULL) { 243738824adSRobert Watson if (ignore_errors) 244738824adSRobert Watson continue; 245738824adSRobert Watson error = EINVAL; 246391b1d75SRobert Watson fclose(file); 247391b1d75SRobert Watson goto just_return; 248391b1d75SRobert Watson } 249738824adSRobert Watson 250738824adSRobert Watson if (mac_add_type(type, labels) == -1) { 251738824adSRobert Watson if (ignore_errors) 252738824adSRobert Watson continue; 253738824adSRobert Watson fclose(file); 254738824adSRobert Watson goto just_return; 255391b1d75SRobert Watson } 256391b1d75SRobert Watson } else { 257738824adSRobert Watson if (ignore_errors) 258738824adSRobert Watson continue; 259391b1d75SRobert Watson fclose(file); 260391b1d75SRobert Watson error = EINVAL; 261391b1d75SRobert Watson goto just_return; 262391b1d75SRobert Watson } 263391b1d75SRobert Watson } 264391b1d75SRobert Watson 265391b1d75SRobert Watson fclose(file); 266391b1d75SRobert Watson 267391b1d75SRobert Watson internal_initialized = 1; 268391b1d75SRobert Watson 269391b1d75SRobert Watson just_return: 270391b1d75SRobert Watson if (error != 0) 271391b1d75SRobert Watson mac_destroy_internal(); 272391b1d75SRobert Watson return (error); 273391b1d75SRobert Watson } 274391b1d75SRobert Watson 275391b1d75SRobert Watson static int 276391b1d75SRobert Watson mac_maybe_init_internal(void) 277391b1d75SRobert Watson { 278391b1d75SRobert Watson 279391b1d75SRobert Watson if (!internal_initialized) 280738824adSRobert Watson return (mac_init_internal(1)); 281391b1d75SRobert Watson else 282391b1d75SRobert Watson return (0); 283391b1d75SRobert Watson } 284391b1d75SRobert Watson 285391b1d75SRobert Watson int 286391b1d75SRobert Watson mac_reload(void) 287391b1d75SRobert Watson { 288391b1d75SRobert Watson 289391b1d75SRobert Watson if (internal_initialized) 290391b1d75SRobert Watson mac_destroy_internal(); 291738824adSRobert Watson return (mac_init_internal(0)); 292391b1d75SRobert Watson } 293391b1d75SRobert Watson 294391b1d75SRobert Watson int 295391b1d75SRobert Watson mac_free(struct mac *mac) 296391b1d75SRobert Watson { 297391b1d75SRobert Watson 298391b1d75SRobert Watson if (mac->m_string != NULL) 299391b1d75SRobert Watson free(mac->m_string); 300391b1d75SRobert Watson free(mac); 301391b1d75SRobert Watson 302391b1d75SRobert Watson return (0); 303391b1d75SRobert Watson } 304391b1d75SRobert Watson 305391b1d75SRobert Watson int 306391b1d75SRobert Watson mac_from_text(struct mac **mac, const char *text) 307391b1d75SRobert Watson { 308391b1d75SRobert Watson 309391b1d75SRobert Watson *mac = (struct mac *) malloc(sizeof(**mac)); 310391b1d75SRobert Watson if (*mac == NULL) 311391b1d75SRobert Watson return (ENOMEM); 312391b1d75SRobert Watson 313391b1d75SRobert Watson (*mac)->m_string = strdup(text); 314391b1d75SRobert Watson if ((*mac)->m_string == NULL) { 315391b1d75SRobert Watson free(*mac); 316391b1d75SRobert Watson *mac = NULL; 317391b1d75SRobert Watson return (ENOMEM); 318391b1d75SRobert Watson } 319391b1d75SRobert Watson 320391b1d75SRobert Watson (*mac)->m_buflen = strlen((*mac)->m_string)+1; 321391b1d75SRobert Watson 322391b1d75SRobert Watson return (0); 323391b1d75SRobert Watson } 324391b1d75SRobert Watson 325391b1d75SRobert Watson int 3264bae1674SChris Costello mac_to_text(struct mac *mac, char **text) 3274bae1674SChris Costello { 3284bae1674SChris Costello 3294bae1674SChris Costello *text = strdup(mac->m_string); 3304bae1674SChris Costello if (*text == NULL) 3314bae1674SChris Costello return (ENOMEM); 3324bae1674SChris Costello return (0); 3334bae1674SChris Costello } 3344bae1674SChris Costello 3354bae1674SChris Costello int 336930d4ffaSRobert Watson mac_prepare(struct mac **mac, const char *elements) 337391b1d75SRobert Watson { 338391b1d75SRobert Watson 339391b1d75SRobert Watson if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN) 340391b1d75SRobert Watson return (EINVAL); 341391b1d75SRobert Watson 342391b1d75SRobert Watson *mac = (struct mac *) malloc(sizeof(**mac)); 343391b1d75SRobert Watson if (*mac == NULL) 344391b1d75SRobert Watson return (ENOMEM); 345391b1d75SRobert Watson 346391b1d75SRobert Watson (*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN); 347391b1d75SRobert Watson if ((*mac)->m_string == NULL) { 348391b1d75SRobert Watson free(*mac); 349391b1d75SRobert Watson *mac = NULL; 350391b1d75SRobert Watson return (ENOMEM); 351391b1d75SRobert Watson } 352391b1d75SRobert Watson 353391b1d75SRobert Watson strcpy((*mac)->m_string, elements); 354391b1d75SRobert Watson (*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN; 355391b1d75SRobert Watson 356391b1d75SRobert Watson return (0); 357391b1d75SRobert Watson } 358391b1d75SRobert Watson 359391b1d75SRobert Watson int 360738824adSRobert Watson mac_prepare_type(struct mac **mac, const char *name) 361391b1d75SRobert Watson { 362738824adSRobert Watson struct label_default *ld; 3636e07ce26SRobert Watson int error; 3646e07ce26SRobert Watson 3656e07ce26SRobert Watson error = mac_maybe_init_internal(); 3666e07ce26SRobert Watson if (error != 0) 3676e07ce26SRobert Watson return (error); 368391b1d75SRobert Watson 369738824adSRobert Watson for (ld = LIST_FIRST(&label_default_head); ld != NULL; 370738824adSRobert Watson ld = LIST_NEXT(ld, ld_entries)) { 371738824adSRobert Watson if (strcmp(name, ld->ld_name) == 0) 372738824adSRobert Watson return (mac_prepare(mac, ld->ld_labels)); 373738824adSRobert Watson } 374391b1d75SRobert Watson 3757ea02dcdSRobert Watson errno = ENOENT; 3767ea02dcdSRobert Watson return (-1); /* XXXMAC: ENOLABEL */ 377391b1d75SRobert Watson } 378391b1d75SRobert Watson 379391b1d75SRobert Watson int 380391b1d75SRobert Watson mac_prepare_ifnet_label(struct mac **mac) 381391b1d75SRobert Watson { 382391b1d75SRobert Watson 383738824adSRobert Watson return (mac_prepare_type(mac, "ifnet")); 384391b1d75SRobert Watson } 385738824adSRobert Watson 386738824adSRobert Watson int 387738824adSRobert Watson mac_prepare_file_label(struct mac **mac) 388738824adSRobert Watson { 389738824adSRobert Watson 390738824adSRobert Watson return (mac_prepare_type(mac, "file")); 391738824adSRobert Watson } 392738824adSRobert Watson 393738824adSRobert Watson int 394738824adSRobert Watson mac_prepare_packet_label(struct mac **mac) 395738824adSRobert Watson { 396738824adSRobert Watson 397738824adSRobert Watson return (mac_prepare_type(mac, "packet")); 398738824adSRobert Watson } 399738824adSRobert Watson 400391b1d75SRobert Watson int 401391b1d75SRobert Watson mac_prepare_process_label(struct mac **mac) 402391b1d75SRobert Watson { 403391b1d75SRobert Watson 404738824adSRobert Watson return (mac_prepare_type(mac, "process")); 405391b1d75SRobert Watson } 406391b1d75SRobert Watson 407391b1d75SRobert Watson /* 408391b1d75SRobert Watson * Simply test whether the TrustedBSD/MAC MIB tree is present; if so, 409391b1d75SRobert Watson * return 1 to indicate that the system has MAC enabled overall or for 410391b1d75SRobert Watson * a given policy. 411391b1d75SRobert Watson */ 412391b1d75SRobert Watson int 413391b1d75SRobert Watson mac_is_present(const char *policyname) 414391b1d75SRobert Watson { 415391b1d75SRobert Watson int mib[5]; 416391b1d75SRobert Watson size_t siz; 417391b1d75SRobert Watson char *mibname; 418391b1d75SRobert Watson int error; 419391b1d75SRobert Watson 420391b1d75SRobert Watson if (policyname != NULL) { 421391b1d75SRobert Watson if (policyname[strcspn(policyname, ".=")] != '\0') { 422391b1d75SRobert Watson errno = EINVAL; 423391b1d75SRobert Watson return (-1); 424391b1d75SRobert Watson } 425391b1d75SRobert Watson mibname = malloc(sizeof("security.mac.") - 1 + 426391b1d75SRobert Watson strlen(policyname) + sizeof(".enabled")); 427391b1d75SRobert Watson if (mibname == NULL) 428391b1d75SRobert Watson return (-1); 429391b1d75SRobert Watson strcpy(mibname, "security.mac."); 430391b1d75SRobert Watson strcat(mibname, policyname); 431391b1d75SRobert Watson strcat(mibname, ".enabled"); 432391b1d75SRobert Watson siz = 5; 433391b1d75SRobert Watson error = sysctlnametomib(mibname, mib, &siz); 434391b1d75SRobert Watson free(mibname); 435391b1d75SRobert Watson } else { 436391b1d75SRobert Watson siz = 3; 437391b1d75SRobert Watson error = sysctlnametomib("security.mac", mib, &siz); 438391b1d75SRobert Watson } 439391b1d75SRobert Watson if (error == -1) { 440391b1d75SRobert Watson switch (errno) { 441391b1d75SRobert Watson case ENOTDIR: 442391b1d75SRobert Watson case ENOENT: 443391b1d75SRobert Watson return (0); 444391b1d75SRobert Watson default: 445391b1d75SRobert Watson return (error); 446391b1d75SRobert Watson } 447391b1d75SRobert Watson } 448391b1d75SRobert Watson return (1); 449391b1d75SRobert Watson } 450