conf-parse.y revision b8b0d7fa8ad38104ec017fd2b4d41bc5e4845f3c
1/* Authors: Jason Tang <jtang@tresys.com> 2 * James Athey <jathey@tresys.com> 3 * 4 * Copyright (C) 2004-2006 Tresys Technology, LLC 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21%{ 22 23#include "semanage_conf.h" 24 25#include <sepol/policydb.h> 26#include <selinux/selinux.h> 27#include <semanage/handle.h> 28 29#include <unistd.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33 34extern int semanage_lex(); /* defined in conf-scan.c */ 35int semanage_error(const char *msg); 36 37extern FILE *semanage_in; 38extern char *semanage_text; 39 40static int parse_module_store(char *arg); 41static int parse_store_root_path(char *arg); 42static int parse_compiler_path(char *arg); 43static void semanage_conf_external_prog_destroy(external_prog_t *ep); 44static int new_external_prog(external_prog_t **chain); 45 46static semanage_conf_t *current_conf; 47static external_prog_t *new_external; 48static int parse_errors; 49 50#define PASSIGN(p1,p2) { free(p1); p1 = p2; } 51 52%} 53 54%name-prefix "semanage_" 55 56%union { 57 int d; 58 char *s; 59} 60 61%token MODULE_STORE VERSION EXPAND_CHECK FILE_MODE SAVE_PREVIOUS SAVE_LINKED TARGET_PLATFORM COMPILER_DIR IGNORE_MODULE_CACHE STORE_ROOT 62%token LOAD_POLICY_START SETFILES_START SEFCONTEXT_COMPILE_START DISABLE_GENHOMEDIRCON HANDLE_UNKNOWN USEPASSWD IGNOREDIRS 63%token BZIP_BLOCKSIZE BZIP_SMALL 64%token VERIFY_MOD_START VERIFY_LINKED_START VERIFY_KERNEL_START BLOCK_END 65%token PROG_PATH PROG_ARGS 66%token <s> ARG 67%type <d> verify_start_tok 68 69%% 70 71config_file: config_line config_file 72 | /* empty */ 73 ; 74 75config_line: single_opt 76 | command_block 77 | verify_block 78 ; 79 80single_opt: module_store 81 | version 82 | target_platform 83 | store_root 84 | compiler_dir 85 | ignore_module_cache 86 | expand_check 87 | file_mode 88 | save_previous 89 | save_linked 90 | disable_genhomedircon 91 | usepasswd 92 | ignoredirs 93 | handle_unknown 94 | bzip_blocksize 95 | bzip_small 96 ; 97 98module_store: MODULE_STORE '=' ARG { 99 if (parse_module_store($3) != 0) { 100 parse_errors++; 101 YYABORT; 102 } 103 } 104 105 ; 106 107store_root: STORE_ROOT '=' ARG { 108 if (parse_store_root_path($3) != 0) { 109 parse_errors++; 110 YYABORT; 111 } 112 } 113 ; 114 115compiler_dir: COMPILER_DIR '=' ARG { 116 if (parse_compiler_path($3) != 0) { 117 parse_errors++; 118 YYABORT; 119 } 120 } 121 ; 122 123ignore_module_cache: IGNORE_MODULE_CACHE '=' ARG { 124 if (strcasecmp($3, "true") == 0) 125 current_conf->ignore_module_cache = 1; 126 else if (strcasecmp($3, "false") == 0) 127 current_conf->ignore_module_cache = 0; 128 else { 129 yyerror("disable-caching can only be 'true' or 'false'"); 130 } 131 } 132 ; 133 134version: VERSION '=' ARG { 135 current_conf->policyvers = atoi($3); 136 free($3); 137 if (current_conf->policyvers < sepol_policy_kern_vers_min() || 138 current_conf->policyvers > sepol_policy_kern_vers_max()) { 139 parse_errors++; 140 YYABORT; 141 } 142 } 143 ; 144 145target_platform: TARGET_PLATFORM '=' ARG { 146 if (strcasecmp($3, "selinux") == 0) 147 current_conf->target_platform = SEPOL_TARGET_SELINUX; 148 else if (strcasecmp($3, "xen") == 0) 149 current_conf->target_platform = SEPOL_TARGET_XEN; 150 else { 151 yyerror("target_platform can only be 'selinux' or 'xen'"); 152 } 153 } 154 ; 155 156expand_check: EXPAND_CHECK '=' ARG { 157 current_conf->expand_check = atoi($3); 158 free($3); 159 } 160 ; 161 162file_mode: FILE_MODE '=' ARG { 163 current_conf->file_mode = strtoul($3, NULL, 8); 164 free($3); 165 } 166 ; 167 168save_previous: SAVE_PREVIOUS '=' ARG { 169 if (strcasecmp($3, "true") == 0) 170 current_conf->save_previous = 1; 171 else if (strcasecmp($3, "false") == 0) 172 current_conf->save_previous = 0; 173 else { 174 yyerror("save-previous can only be 'true' or 'false'"); 175 } 176 } 177 ; 178 179 180save_linked: SAVE_LINKED '=' ARG { 181 if (strcasecmp($3, "true") == 0) 182 current_conf->save_linked = 1; 183 else if (strcasecmp($3, "false") == 0) 184 current_conf->save_linked = 0; 185 else { 186 yyerror("save-linked can only be 'true' or 'false'"); 187 } 188 } 189 ; 190 191disable_genhomedircon: DISABLE_GENHOMEDIRCON '=' ARG { 192 if (strcasecmp($3, "false") == 0) { 193 current_conf->disable_genhomedircon = 0; 194 } else if (strcasecmp($3, "true") == 0) { 195 current_conf->disable_genhomedircon = 1; 196 } else { 197 yyerror("disable-genhomedircon can only be 'true' or 'false'"); 198 } 199 free($3); 200 } 201 202usepasswd: USEPASSWD '=' ARG { 203 if (strcasecmp($3, "false") == 0) { 204 current_conf->usepasswd = 0; 205 } else if (strcasecmp($3, "true") == 0) { 206 current_conf->usepasswd = 1; 207 } else { 208 yyerror("usepasswd can only be 'true' or 'false'"); 209 } 210 free($3); 211 } 212 213ignoredirs: IGNOREDIRS '=' ARG { 214 current_conf->ignoredirs = strdup($3); 215 } 216 217handle_unknown: HANDLE_UNKNOWN '=' ARG { 218 if (strcasecmp($3, "deny") == 0) { 219 current_conf->handle_unknown = SEPOL_DENY_UNKNOWN; 220 } else if (strcasecmp($3, "reject") == 0) { 221 current_conf->handle_unknown = SEPOL_REJECT_UNKNOWN; 222 } else if (strcasecmp($3, "allow") == 0) { 223 current_conf->handle_unknown = SEPOL_ALLOW_UNKNOWN; 224 } else { 225 yyerror("handle-unknown can only be 'deny', 'reject' or 'allow'"); 226 } 227 free($3); 228 } 229 230bzip_blocksize: BZIP_BLOCKSIZE '=' ARG { 231 int blocksize = atoi($3); 232 free($3); 233 if (blocksize > 9) 234 yyerror("bzip-blocksize can only be in the range 0-9"); 235 else 236 current_conf->bzip_blocksize = blocksize; 237} 238 239bzip_small: BZIP_SMALL '=' ARG { 240 if (strcasecmp($3, "false") == 0) { 241 current_conf->bzip_small = 0; 242 } else if (strcasecmp($3, "true") == 0) { 243 current_conf->bzip_small = 1; 244 } else { 245 yyerror("bzip-small can only be 'true' or 'false'"); 246 } 247 free($3); 248} 249 250command_block: 251 command_start external_opts BLOCK_END { 252 if (new_external->path == NULL) { 253 parse_errors++; 254 YYABORT; 255 } 256 } 257 ; 258 259command_start: 260 LOAD_POLICY_START { 261 semanage_conf_external_prog_destroy(current_conf->load_policy); 262 current_conf->load_policy = NULL; 263 if (new_external_prog(¤t_conf->load_policy) == -1) { 264 parse_errors++; 265 YYABORT; 266 } 267 } 268 | SETFILES_START { 269 semanage_conf_external_prog_destroy(current_conf->setfiles); 270 current_conf->setfiles = NULL; 271 if (new_external_prog(¤t_conf->setfiles) == -1) { 272 parse_errors++; 273 YYABORT; 274 } 275 } 276 | SEFCONTEXT_COMPILE_START { 277 semanage_conf_external_prog_destroy(current_conf->sefcontext_compile); 278 current_conf->sefcontext_compile = NULL; 279 if (new_external_prog(¤t_conf->sefcontext_compile) == -1) { 280 parse_errors++; 281 YYABORT; 282 } 283 } 284 ; 285 286verify_block: verify_start external_opts BLOCK_END { 287 if (new_external->path == NULL) { 288 parse_errors++; 289 YYABORT; 290 } 291 } 292 ; 293 294verify_start: verify_start_tok { 295 if ($1 == -1) { 296 parse_errors++; 297 YYABORT; 298 } 299 } 300 ; 301 302verify_start_tok: VERIFY_MOD_START {$$ = new_external_prog(¤t_conf->mod_prog);} 303 | VERIFY_LINKED_START {$$ = new_external_prog(¤t_conf->linked_prog);} 304 | VERIFY_KERNEL_START {$$ = new_external_prog(¤t_conf->kernel_prog);} 305 ; 306 307external_opts: external_opt external_opts 308 | /* empty */ 309 ; 310 311external_opt: PROG_PATH '=' ARG { PASSIGN(new_external->path, $3); } 312 | PROG_ARGS '=' ARG { PASSIGN(new_external->args, $3); } 313 ; 314 315%% 316 317static int semanage_conf_init(semanage_conf_t * conf) 318{ 319 conf->store_type = SEMANAGE_CON_DIRECT; 320 conf->store_path = strdup(basename(selinux_policy_root())); 321 conf->ignoredirs = NULL; 322 conf->store_root_path = strdup("/var/lib/selinux"); 323 conf->compiler_directory_path = strdup("/usr/libexec/selinux/hll"); 324 conf->policyvers = sepol_policy_kern_vers_max(); 325 conf->target_platform = SEPOL_TARGET_SELINUX; 326 conf->expand_check = 1; 327 conf->handle_unknown = -1; 328 conf->usepasswd = 1; 329 conf->file_mode = 0644; 330 conf->bzip_blocksize = 9; 331 conf->bzip_small = 0; 332 conf->ignore_module_cache = 0; 333 334 conf->save_previous = 0; 335 conf->save_linked = 0; 336 337 if ((conf->load_policy = 338 calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) { 339 return -1; 340 } 341 342 if (access("/sbin/load_policy", X_OK) == 0) { 343 conf->load_policy->path = strdup("/sbin/load_policy"); 344 } else { 345 conf->load_policy->path = strdup("/usr/sbin/load_policy"); 346 } 347 if (conf->load_policy->path == NULL) { 348 return -1; 349 } 350 conf->load_policy->args = NULL; 351 352 if ((conf->setfiles = 353 calloc(1, sizeof(*(current_conf->setfiles)))) == NULL) { 354 return -1; 355 } 356 if (access("/sbin/setfiles", X_OK) == 0) { 357 conf->setfiles->path = strdup("/sbin/setfiles"); 358 } else { 359 conf->setfiles->path = strdup("/usr/sbin/setfiles"); 360 } 361 if ((conf->setfiles->path == NULL) || 362 (conf->setfiles->args = strdup("-q -c $@ $<")) == NULL) { 363 return -1; 364 } 365 366 if ((conf->sefcontext_compile = 367 calloc(1, sizeof(*(current_conf->sefcontext_compile)))) == NULL) { 368 return -1; 369 } 370 if (access("/sbin/sefcontext_compile", X_OK) == 0) { 371 conf->sefcontext_compile->path = strdup("/sbin/sefcontext_compile"); 372 } else { 373 conf->sefcontext_compile->path = strdup("/usr/sbin/sefcontext_compile"); 374 } 375 if ((conf->sefcontext_compile->path == NULL) || 376 (conf->sefcontext_compile->args = strdup("$@")) == NULL) { 377 return -1; 378 } 379 380 return 0; 381} 382 383/* Parse a libsemanage configuration file. THIS FUNCTION IS NOT 384 * THREAD-SAFE! Return a newly allocated semanage_conf_t *. If the 385 * configuration file could be read, parse it; otherwise rely upon 386 * default values. If the file could not be parsed correctly or if 387 * out of memory return NULL. 388 */ 389semanage_conf_t *semanage_conf_parse(const char *config_filename) 390{ 391 if ((current_conf = calloc(1, sizeof(*current_conf))) == NULL) { 392 return NULL; 393 } 394 if (semanage_conf_init(current_conf) == -1) { 395 goto cleanup; 396 } 397 if ((semanage_in = fopen(config_filename, "r")) == NULL) { 398 /* configuration file does not exist or could not be 399 * read. THIS IS NOT AN ERROR. just rely on the 400 * defaults. */ 401 return current_conf; 402 } 403 parse_errors = 0; 404 semanage_parse(); 405 fclose(semanage_in); 406 if (parse_errors != 0) { 407 goto cleanup; 408 } 409 return current_conf; 410 cleanup: 411 semanage_conf_destroy(current_conf); 412 return NULL; 413} 414 415static void semanage_conf_external_prog_destroy(external_prog_t * ep) 416{ 417 while (ep != NULL) { 418 external_prog_t *next = ep->next; 419 free(ep->path); 420 free(ep->args); 421 free(ep); 422 ep = next; 423 } 424} 425 426/* Deallocates all space associated with a configuration struct, 427 * including the pointer itself. */ 428void semanage_conf_destroy(semanage_conf_t * conf) 429{ 430 if (conf != NULL) { 431 free(conf->store_path); 432 free(conf->ignoredirs); 433 free(conf->store_root_path); 434 free(conf->compiler_directory_path); 435 semanage_conf_external_prog_destroy(conf->load_policy); 436 semanage_conf_external_prog_destroy(conf->setfiles); 437 semanage_conf_external_prog_destroy(conf->sefcontext_compile); 438 semanage_conf_external_prog_destroy(conf->mod_prog); 439 semanage_conf_external_prog_destroy(conf->linked_prog); 440 semanage_conf_external_prog_destroy(conf->kernel_prog); 441 free(conf); 442 } 443} 444 445int semanage_error(const char *msg) 446{ 447 fprintf(stderr, "error parsing semanage configuration file: %s\n", msg); 448 parse_errors++; 449 return 0; 450} 451 452/* Take the string argument for a module store. If it is exactly the 453 * word "direct" then have libsemanage directly manipulate the module 454 * store. The policy path will default to the active policy directory. 455 * Otherwise if it begins with a forward slash interpret it as 456 * an absolute path to a named socket, to which a policy server is 457 * listening on the other end. Otherwise treat it as the host name to 458 * an external server; if there is a colon in the name then everything 459 * after gives a port number. The default port number is 4242. 460 * Returns 0 on success, -1 if out of memory, -2 if a port number is 461 * illegal. 462 */ 463static int parse_module_store(char *arg) 464{ 465 /* arg is already a strdup()ed copy of yytext */ 466 if (arg == NULL) { 467 return -1; 468 } 469 free(current_conf->store_path); 470 if (strcmp(arg, "direct") == 0) { 471 current_conf->store_type = SEMANAGE_CON_DIRECT; 472 current_conf->store_path = 473 strdup(basename(selinux_policy_root())); 474 current_conf->server_port = -1; 475 free(arg); 476 } else if (*arg == '/') { 477 current_conf->store_type = SEMANAGE_CON_POLSERV_LOCAL; 478 current_conf->store_path = arg; 479 current_conf->server_port = -1; 480 } else { 481 char *s; 482 current_conf->store_type = SEMANAGE_CON_POLSERV_REMOTE; 483 if ((s = strchr(arg, ':')) == NULL) { 484 current_conf->store_path = arg; 485 current_conf->server_port = 4242; 486 } else { 487 char *endptr; 488 *s = '\0'; 489 current_conf->store_path = arg; 490 current_conf->server_port = strtol(s + 1, &endptr, 10); 491 if (*(s + 1) == '\0' || *endptr != '\0') { 492 return -2; 493 } 494 } 495 } 496 return 0; 497} 498 499static int parse_store_root_path(char *arg) 500{ 501 if (arg == NULL) { 502 return -1; 503 } 504 505 free(current_conf->store_root_path); 506 current_conf->store_root_path = strdup(arg); 507 return 0; 508} 509 510static int parse_compiler_path(char *arg) 511{ 512 if (arg == NULL) { 513 return -1; 514 } 515 free(current_conf->compiler_directory_path); 516 current_conf->compiler_directory_path = strdup(arg); 517 return 0; 518} 519 520/* Helper function; called whenever configuration file specifies 521 * another external program. Returns 0 on success, -1 if out of 522 * memory. 523 */ 524static int new_external_prog(external_prog_t ** chain) 525{ 526 if ((new_external = calloc(1, sizeof(*new_external))) == NULL) { 527 return -1; 528 } 529 /* hook this new external program to the end of the chain */ 530 if (*chain == NULL) { 531 *chain = new_external; 532 } else { 533 external_prog_t *prog = *chain; 534 while (prog->next != NULL) { 535 prog = prog->next; 536 } 537 prog->next = new_external; 538 } 539 return 0; 540} 541