1391b1d75SRobert Watson /* 2391b1d75SRobert Watson * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 3391b1d75SRobert Watson * Copyright (c) 2002 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 * 8391b1d75SRobert Watson * This software was developed for the FreeBSD Project in part by NAI Labs, 9391b1d75SRobert Watson * the Security Research Division of Network Associates, Inc. under 10391b1d75SRobert Watson * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA 11391b1d75SRobert Watson * 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 * 3. The names of the authors may not be used to endorse or promote 22391b1d75SRobert Watson * products derived from this software without specific prior written 23391b1d75SRobert Watson * permission. 24391b1d75SRobert Watson * 25391b1d75SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 26391b1d75SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27391b1d75SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28391b1d75SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 29391b1d75SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30391b1d75SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31391b1d75SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32391b1d75SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33391b1d75SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34391b1d75SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35391b1d75SRobert Watson * SUCH DAMAGE. 36391b1d75SRobert Watson * 37391b1d75SRobert Watson * $FreeBSD$ 38391b1d75SRobert Watson */ 39391b1d75SRobert Watson 40391b1d75SRobert Watson #include <sys/types.h> 41391b1d75SRobert Watson #include <sys/queue.h> 42391b1d75SRobert Watson #include <sys/sysctl.h> 43391b1d75SRobert Watson #include <sys/syslimits.h> 44391b1d75SRobert Watson 45391b1d75SRobert Watson #include <dlfcn.h> 46391b1d75SRobert Watson #include <errno.h> 47391b1d75SRobert Watson #include <stdio.h> 48391b1d75SRobert Watson #include <stdlib.h> 49391b1d75SRobert Watson #include <string.h> 50391b1d75SRobert Watson 51391b1d75SRobert Watson #include <sys/mac.h> 52391b1d75SRobert Watson 53391b1d75SRobert Watson static int internal_initialized; 54391b1d75SRobert Watson 55391b1d75SRobert Watson /* Default sets of labels for various query operations. */ 56391b1d75SRobert Watson static char *default_file_labels; 57391b1d75SRobert Watson static char *default_ifnet_labels; 58391b1d75SRobert Watson static char *default_process_labels; 59391b1d75SRobert Watson 60391b1d75SRobert Watson static void 61391b1d75SRobert Watson mac_destroy_labels(void) 62391b1d75SRobert Watson { 63391b1d75SRobert Watson 64391b1d75SRobert Watson if (default_file_labels != NULL) { 65391b1d75SRobert Watson free(default_file_labels); 66391b1d75SRobert Watson default_file_labels = NULL; 67391b1d75SRobert Watson } 68391b1d75SRobert Watson 69391b1d75SRobert Watson if (default_ifnet_labels != NULL) { 70391b1d75SRobert Watson free(default_ifnet_labels); 71391b1d75SRobert Watson default_ifnet_labels = NULL; 72391b1d75SRobert Watson } 73391b1d75SRobert Watson 74391b1d75SRobert Watson if (default_process_labels != NULL) { 75391b1d75SRobert Watson free(default_process_labels); 76391b1d75SRobert Watson default_process_labels = NULL; 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 90391b1d75SRobert Watson mac_init_internal(void) 91391b1d75SRobert Watson { 92391b1d75SRobert Watson FILE *file; 93391b1d75SRobert Watson char line[LINE_MAX]; 94391b1d75SRobert Watson int error; 95391b1d75SRobert Watson 96391b1d75SRobert Watson error = 0; 97391b1d75SRobert Watson 98391b1d75SRobert Watson file = fopen(MAC_CONFFILE, "r"); 99391b1d75SRobert Watson if (file == NULL) 100391b1d75SRobert Watson return (0); 101391b1d75SRobert Watson 102391b1d75SRobert Watson while (fgets(line, LINE_MAX, file)) { 103391b1d75SRobert Watson char *argv[ARG_MAX]; 104391b1d75SRobert Watson char *arg, *parse, *statement, *policyname, *modulename; 105391b1d75SRobert Watson int argc; 106391b1d75SRobert Watson 107391b1d75SRobert Watson if (line[strlen(line)-1] == '\n') 108391b1d75SRobert Watson line[strlen(line)-1] = '\0'; 109391b1d75SRobert Watson else { 110391b1d75SRobert Watson fclose(file); 111391b1d75SRobert Watson error = EINVAL; 112391b1d75SRobert Watson goto just_return; 113391b1d75SRobert Watson } 114391b1d75SRobert Watson 115391b1d75SRobert Watson parse = line; 116391b1d75SRobert Watson statement = ""; 117391b1d75SRobert Watson while (parse && statement[0] == '\0') 118391b1d75SRobert Watson statement = strsep(&parse, " \t"); 119391b1d75SRobert Watson 120391b1d75SRobert Watson /* Blank lines ok. */ 121391b1d75SRobert Watson if (strlen(statement) == 0) 122391b1d75SRobert Watson continue; 123391b1d75SRobert Watson 124391b1d75SRobert Watson /* Lines that consist only of comments ok. */ 125391b1d75SRobert Watson if (statement[0] == '#') 126391b1d75SRobert Watson continue; 127391b1d75SRobert Watson 128391b1d75SRobert Watson if (strcmp(statement, "default_file_labels") == 0) { 129391b1d75SRobert Watson if (default_file_labels != NULL) { 130391b1d75SRobert Watson free(default_file_labels); 131391b1d75SRobert Watson default_file_labels = NULL; 132391b1d75SRobert Watson } 133391b1d75SRobert Watson 134391b1d75SRobert Watson arg = strsep(&parse, "# \t"); 135391b1d75SRobert Watson if (arg != NULL && arg[0] != '\0') { 136391b1d75SRobert Watson default_file_labels = strdup(arg); 137391b1d75SRobert Watson if (default_file_labels == NULL) { 138391b1d75SRobert Watson error = ENOMEM; 139391b1d75SRobert Watson fclose(file); 140391b1d75SRobert Watson goto just_return; 141391b1d75SRobert Watson } 142391b1d75SRobert Watson } 143391b1d75SRobert Watson } else if (strcmp(statement, "default_ifnet_labels") == 0) { 144391b1d75SRobert Watson if (default_ifnet_labels != NULL) { 145391b1d75SRobert Watson free(default_ifnet_labels); 146391b1d75SRobert Watson default_ifnet_labels = NULL; 147391b1d75SRobert Watson } 148391b1d75SRobert Watson 149391b1d75SRobert Watson arg = strsep(&parse, "# \t"); 150391b1d75SRobert Watson if (arg != NULL && arg[0] != '\0') { 151391b1d75SRobert Watson default_ifnet_labels = strdup(arg); 152391b1d75SRobert Watson if (default_ifnet_labels == NULL) { 153391b1d75SRobert Watson error = ENOMEM; 154391b1d75SRobert Watson fclose(file); 155391b1d75SRobert Watson goto just_return; 156391b1d75SRobert Watson } 157391b1d75SRobert Watson } 158391b1d75SRobert Watson } else if (strcmp(statement, "default_process_labels") == 0) { 159391b1d75SRobert Watson if (default_process_labels != NULL) { 160391b1d75SRobert Watson free(default_process_labels); 161391b1d75SRobert Watson default_process_labels = NULL; 162391b1d75SRobert Watson } 163391b1d75SRobert Watson 164391b1d75SRobert Watson arg = strsep(&parse, "# \t"); 165391b1d75SRobert Watson if (arg != NULL && arg[0] != '\0') { 166391b1d75SRobert Watson default_process_labels = strdup(arg); 167391b1d75SRobert Watson if (default_process_labels == NULL) { 168391b1d75SRobert Watson error = ENOMEM; 169391b1d75SRobert Watson fclose(file); 170391b1d75SRobert Watson goto just_return; 171391b1d75SRobert Watson } 172391b1d75SRobert Watson } 173391b1d75SRobert Watson } else { 174391b1d75SRobert Watson fclose(file); 175391b1d75SRobert Watson error = EINVAL; 176391b1d75SRobert Watson goto just_return; 177391b1d75SRobert Watson } 178391b1d75SRobert Watson } 179391b1d75SRobert Watson 180391b1d75SRobert Watson fclose(file); 181391b1d75SRobert Watson 182391b1d75SRobert Watson internal_initialized = 1; 183391b1d75SRobert Watson 184391b1d75SRobert Watson just_return: 185391b1d75SRobert Watson if (error != 0) 186391b1d75SRobert Watson mac_destroy_internal(); 187391b1d75SRobert Watson return (error); 188391b1d75SRobert Watson } 189391b1d75SRobert Watson 190391b1d75SRobert Watson static int 191391b1d75SRobert Watson mac_maybe_init_internal(void) 192391b1d75SRobert Watson { 193391b1d75SRobert Watson 194391b1d75SRobert Watson if (!internal_initialized) 195391b1d75SRobert Watson return (mac_init_internal()); 196391b1d75SRobert Watson else 197391b1d75SRobert Watson return (0); 198391b1d75SRobert Watson } 199391b1d75SRobert Watson 200391b1d75SRobert Watson int 201391b1d75SRobert Watson mac_reload(void) 202391b1d75SRobert Watson { 203391b1d75SRobert Watson 204391b1d75SRobert Watson if (internal_initialized) 205391b1d75SRobert Watson mac_destroy_internal(); 206391b1d75SRobert Watson return (mac_init_internal()); 207391b1d75SRobert Watson } 208391b1d75SRobert Watson 209391b1d75SRobert Watson int 210391b1d75SRobert Watson mac_free(struct mac *mac) 211391b1d75SRobert Watson { 212391b1d75SRobert Watson int error; 213391b1d75SRobert Watson 214391b1d75SRobert Watson if (mac->m_string != NULL) 215391b1d75SRobert Watson free(mac->m_string); 216391b1d75SRobert Watson free(mac); 217391b1d75SRobert Watson 218391b1d75SRobert Watson return (0); 219391b1d75SRobert Watson } 220391b1d75SRobert Watson 221391b1d75SRobert Watson int 222391b1d75SRobert Watson mac_from_text(struct mac **mac, const char *text) 223391b1d75SRobert Watson { 224391b1d75SRobert Watson struct mac *temp; 225391b1d75SRobert Watson char *dup, *element, *search; 226391b1d75SRobert Watson int count, error; 227391b1d75SRobert Watson 228391b1d75SRobert Watson *mac = (struct mac *) malloc(sizeof(**mac)); 229391b1d75SRobert Watson if (*mac == NULL) 230391b1d75SRobert Watson return (ENOMEM); 231391b1d75SRobert Watson 232391b1d75SRobert Watson (*mac)->m_string = strdup(text); 233391b1d75SRobert Watson if ((*mac)->m_string == NULL) { 234391b1d75SRobert Watson free(*mac); 235391b1d75SRobert Watson *mac = NULL; 236391b1d75SRobert Watson return (ENOMEM); 237391b1d75SRobert Watson } 238391b1d75SRobert Watson 239391b1d75SRobert Watson (*mac)->m_buflen = strlen((*mac)->m_string)+1; 240391b1d75SRobert Watson 241391b1d75SRobert Watson return (0); 242391b1d75SRobert Watson } 243391b1d75SRobert Watson 244391b1d75SRobert Watson int 2454bae1674SChris Costello mac_to_text(struct mac *mac, char **text) 2464bae1674SChris Costello { 2474bae1674SChris Costello 2484bae1674SChris Costello *text = strdup(mac->m_string); 2494bae1674SChris Costello if (*text == NULL) 2504bae1674SChris Costello return (ENOMEM); 2514bae1674SChris Costello return (0); 2524bae1674SChris Costello } 2534bae1674SChris Costello 2544bae1674SChris Costello int 255391b1d75SRobert Watson mac_prepare(struct mac **mac, char *elements) 256391b1d75SRobert Watson { 257391b1d75SRobert Watson struct mac *temp; 258391b1d75SRobert Watson 259391b1d75SRobert Watson if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN) 260391b1d75SRobert Watson return (EINVAL); 261391b1d75SRobert Watson 262391b1d75SRobert Watson *mac = (struct mac *) malloc(sizeof(**mac)); 263391b1d75SRobert Watson if (*mac == NULL) 264391b1d75SRobert Watson return (ENOMEM); 265391b1d75SRobert Watson 266391b1d75SRobert Watson (*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN); 267391b1d75SRobert Watson if ((*mac)->m_string == NULL) { 268391b1d75SRobert Watson free(*mac); 269391b1d75SRobert Watson *mac = NULL; 270391b1d75SRobert Watson return (ENOMEM); 271391b1d75SRobert Watson } 272391b1d75SRobert Watson 273391b1d75SRobert Watson strcpy((*mac)->m_string, elements); 274391b1d75SRobert Watson (*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN; 275391b1d75SRobert Watson 276391b1d75SRobert Watson return (0); 277391b1d75SRobert Watson } 278391b1d75SRobert Watson 279391b1d75SRobert Watson int 280391b1d75SRobert Watson mac_prepare_file_label(struct mac **mac) 281391b1d75SRobert Watson { 282391b1d75SRobert Watson int error; 283391b1d75SRobert Watson 284391b1d75SRobert Watson error = mac_maybe_init_internal(); 285391b1d75SRobert Watson if (error != 0) 286391b1d75SRobert Watson return (error); 287391b1d75SRobert Watson 288391b1d75SRobert Watson if (default_file_labels == NULL) 289391b1d75SRobert Watson return (mac_prepare(mac, "")); 290391b1d75SRobert Watson 291391b1d75SRobert Watson return (mac_prepare(mac, default_file_labels)); 292391b1d75SRobert Watson } 293391b1d75SRobert Watson 294391b1d75SRobert Watson int 295391b1d75SRobert Watson mac_prepare_ifnet_label(struct mac **mac) 296391b1d75SRobert Watson { 297391b1d75SRobert Watson int error; 298391b1d75SRobert Watson 299391b1d75SRobert Watson error = mac_maybe_init_internal(); 300391b1d75SRobert Watson if (error != 0) 301391b1d75SRobert Watson return (error); 302391b1d75SRobert Watson 303391b1d75SRobert Watson if (default_ifnet_labels == NULL) 304391b1d75SRobert Watson return (mac_prepare(mac, "")); 305391b1d75SRobert Watson 306391b1d75SRobert Watson return (mac_prepare(mac, default_ifnet_labels)); 307391b1d75SRobert Watson } 308391b1d75SRobert Watson int 309391b1d75SRobert Watson mac_prepare_process_label(struct mac **mac) 310391b1d75SRobert Watson { 311391b1d75SRobert Watson int error; 312391b1d75SRobert Watson 313391b1d75SRobert Watson error = mac_maybe_init_internal(); 314391b1d75SRobert Watson if (error != 0) 315391b1d75SRobert Watson return (error); 316391b1d75SRobert Watson 317391b1d75SRobert Watson if (default_process_labels == NULL) 318391b1d75SRobert Watson return (mac_prepare(mac, "")); 319391b1d75SRobert Watson 320391b1d75SRobert Watson return (mac_prepare(mac, default_process_labels)); 321391b1d75SRobert Watson } 322391b1d75SRobert Watson 323391b1d75SRobert Watson /* 324391b1d75SRobert Watson * Simply test whether the TrustedBSD/MAC MIB tree is present; if so, 325391b1d75SRobert Watson * return 1 to indicate that the system has MAC enabled overall or for 326391b1d75SRobert Watson * a given policy. 327391b1d75SRobert Watson */ 328391b1d75SRobert Watson int 329391b1d75SRobert Watson mac_is_present(const char *policyname) 330391b1d75SRobert Watson { 331391b1d75SRobert Watson int mib[5]; 332391b1d75SRobert Watson size_t siz; 333391b1d75SRobert Watson char *mibname; 334391b1d75SRobert Watson int error; 335391b1d75SRobert Watson 336391b1d75SRobert Watson if (policyname != NULL) { 337391b1d75SRobert Watson if (policyname[strcspn(policyname, ".=")] != '\0') { 338391b1d75SRobert Watson errno = EINVAL; 339391b1d75SRobert Watson return (-1); 340391b1d75SRobert Watson } 341391b1d75SRobert Watson mibname = malloc(sizeof("security.mac.") - 1 + 342391b1d75SRobert Watson strlen(policyname) + sizeof(".enabled")); 343391b1d75SRobert Watson if (mibname == NULL) 344391b1d75SRobert Watson return (-1); 345391b1d75SRobert Watson strcpy(mibname, "security.mac."); 346391b1d75SRobert Watson strcat(mibname, policyname); 347391b1d75SRobert Watson strcat(mibname, ".enabled"); 348391b1d75SRobert Watson siz = 5; 349391b1d75SRobert Watson error = sysctlnametomib(mibname, mib, &siz); 350391b1d75SRobert Watson free(mibname); 351391b1d75SRobert Watson } else { 352391b1d75SRobert Watson siz = 3; 353391b1d75SRobert Watson error = sysctlnametomib("security.mac", mib, &siz); 354391b1d75SRobert Watson } 355391b1d75SRobert Watson if (error == -1) { 356391b1d75SRobert Watson switch (errno) { 357391b1d75SRobert Watson case ENOTDIR: 358391b1d75SRobert Watson case ENOENT: 359391b1d75SRobert Watson return (0); 360391b1d75SRobert Watson default: 361391b1d75SRobert Watson return (error); 362391b1d75SRobert Watson } 363391b1d75SRobert Watson } 364391b1d75SRobert Watson return (1); 365391b1d75SRobert Watson } 366