conf-parse.y revision 057197c69aaa36cf28694517151479de8ebb3c4c
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(void); /* 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 REMOVE_HLL 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 | remove_hll 97 ; 98 99module_store: MODULE_STORE '=' ARG { 100 if (parse_module_store($3) != 0) { 101 parse_errors++; 102 YYABORT; 103 } 104 } 105 106 ; 107 108store_root: STORE_ROOT '=' ARG { 109 if (parse_store_root_path($3) != 0) { 110 parse_errors++; 111 YYABORT; 112 } 113 } 114 ; 115 116compiler_dir: COMPILER_DIR '=' ARG { 117 if (parse_compiler_path($3) != 0) { 118 parse_errors++; 119 YYABORT; 120 } 121 } 122 ; 123 124ignore_module_cache: IGNORE_MODULE_CACHE '=' ARG { 125 if (strcasecmp($3, "true") == 0) 126 current_conf->ignore_module_cache = 1; 127 else if (strcasecmp($3, "false") == 0) 128 current_conf->ignore_module_cache = 0; 129 else { 130 yyerror("disable-caching can only be 'true' or 'false'"); 131 } 132 } 133 ; 134 135version: VERSION '=' ARG { 136 current_conf->policyvers = atoi($3); 137 free($3); 138 if (current_conf->policyvers < sepol_policy_kern_vers_min() || 139 current_conf->policyvers > sepol_policy_kern_vers_max()) { 140 parse_errors++; 141 YYABORT; 142 } 143 } 144 ; 145 146target_platform: TARGET_PLATFORM '=' ARG { 147 if (strcasecmp($3, "selinux") == 0) 148 current_conf->target_platform = SEPOL_TARGET_SELINUX; 149 else if (strcasecmp($3, "xen") == 0) 150 current_conf->target_platform = SEPOL_TARGET_XEN; 151 else { 152 yyerror("target_platform can only be 'selinux' or 'xen'"); 153 } 154 } 155 ; 156 157expand_check: EXPAND_CHECK '=' ARG { 158 current_conf->expand_check = atoi($3); 159 free($3); 160 } 161 ; 162 163file_mode: FILE_MODE '=' ARG { 164 current_conf->file_mode = strtoul($3, NULL, 8); 165 free($3); 166 } 167 ; 168 169save_previous: SAVE_PREVIOUS '=' ARG { 170 if (strcasecmp($3, "true") == 0) 171 current_conf->save_previous = 1; 172 else if (strcasecmp($3, "false") == 0) 173 current_conf->save_previous = 0; 174 else { 175 yyerror("save-previous can only be 'true' or 'false'"); 176 } 177 } 178 ; 179 180 181save_linked: SAVE_LINKED '=' ARG { 182 if (strcasecmp($3, "true") == 0) 183 current_conf->save_linked = 1; 184 else if (strcasecmp($3, "false") == 0) 185 current_conf->save_linked = 0; 186 else { 187 yyerror("save-linked can only be 'true' or 'false'"); 188 } 189 } 190 ; 191 192disable_genhomedircon: DISABLE_GENHOMEDIRCON '=' ARG { 193 if (strcasecmp($3, "false") == 0) { 194 current_conf->disable_genhomedircon = 0; 195 } else if (strcasecmp($3, "true") == 0) { 196 current_conf->disable_genhomedircon = 1; 197 } else { 198 yyerror("disable-genhomedircon can only be 'true' or 'false'"); 199 } 200 free($3); 201 } 202 203usepasswd: USEPASSWD '=' ARG { 204 if (strcasecmp($3, "false") == 0) { 205 current_conf->usepasswd = 0; 206 } else if (strcasecmp($3, "true") == 0) { 207 current_conf->usepasswd = 1; 208 } else { 209 yyerror("usepasswd can only be 'true' or 'false'"); 210 } 211 free($3); 212 } 213 214ignoredirs: IGNOREDIRS '=' ARG { 215 current_conf->ignoredirs = strdup($3); 216 } 217 218handle_unknown: HANDLE_UNKNOWN '=' ARG { 219 if (strcasecmp($3, "deny") == 0) { 220 current_conf->handle_unknown = SEPOL_DENY_UNKNOWN; 221 } else if (strcasecmp($3, "reject") == 0) { 222 current_conf->handle_unknown = SEPOL_REJECT_UNKNOWN; 223 } else if (strcasecmp($3, "allow") == 0) { 224 current_conf->handle_unknown = SEPOL_ALLOW_UNKNOWN; 225 } else { 226 yyerror("handle-unknown can only be 'deny', 'reject' or 'allow'"); 227 } 228 free($3); 229 } 230 231bzip_blocksize: BZIP_BLOCKSIZE '=' ARG { 232 int blocksize = atoi($3); 233 free($3); 234 if (blocksize > 9) 235 yyerror("bzip-blocksize can only be in the range 0-9"); 236 else 237 current_conf->bzip_blocksize = blocksize; 238} 239 240bzip_small: BZIP_SMALL '=' ARG { 241 if (strcasecmp($3, "false") == 0) { 242 current_conf->bzip_small = 0; 243 } else if (strcasecmp($3, "true") == 0) { 244 current_conf->bzip_small = 1; 245 } else { 246 yyerror("bzip-small can only be 'true' or 'false'"); 247 } 248 free($3); 249} 250 251remove_hll: REMOVE_HLL'=' ARG { 252 if (strcasecmp($3, "false") == 0) { 253 current_conf->remove_hll = 0; 254 } else if (strcasecmp($3, "true") == 0) { 255 current_conf->remove_hll = 1; 256 } else { 257 yyerror("remove-hll can only be 'true' or 'false'"); 258 } 259 free($3); 260} 261 262command_block: 263 command_start external_opts BLOCK_END { 264 if (new_external->path == NULL) { 265 parse_errors++; 266 YYABORT; 267 } 268 } 269 ; 270 271command_start: 272 LOAD_POLICY_START { 273 semanage_conf_external_prog_destroy(current_conf->load_policy); 274 current_conf->load_policy = NULL; 275 if (new_external_prog(¤t_conf->load_policy) == -1) { 276 parse_errors++; 277 YYABORT; 278 } 279 } 280 | SETFILES_START { 281 semanage_conf_external_prog_destroy(current_conf->setfiles); 282 current_conf->setfiles = NULL; 283 if (new_external_prog(¤t_conf->setfiles) == -1) { 284 parse_errors++; 285 YYABORT; 286 } 287 } 288 | SEFCONTEXT_COMPILE_START { 289 semanage_conf_external_prog_destroy(current_conf->sefcontext_compile); 290 current_conf->sefcontext_compile = NULL; 291 if (new_external_prog(¤t_conf->sefcontext_compile) == -1) { 292 parse_errors++; 293 YYABORT; 294 } 295 } 296 ; 297 298verify_block: verify_start external_opts BLOCK_END { 299 if (new_external->path == NULL) { 300 parse_errors++; 301 YYABORT; 302 } 303 } 304 ; 305 306verify_start: verify_start_tok { 307 if ($1 == -1) { 308 parse_errors++; 309 YYABORT; 310 } 311 } 312 ; 313 314verify_start_tok: VERIFY_MOD_START {$$ = new_external_prog(¤t_conf->mod_prog);} 315 | VERIFY_LINKED_START {$$ = new_external_prog(¤t_conf->linked_prog);} 316 | VERIFY_KERNEL_START {$$ = new_external_prog(¤t_conf->kernel_prog);} 317 ; 318 319external_opts: external_opt external_opts 320 | /* empty */ 321 ; 322 323external_opt: PROG_PATH '=' ARG { PASSIGN(new_external->path, $3); } 324 | PROG_ARGS '=' ARG { PASSIGN(new_external->args, $3); } 325 ; 326 327%% 328 329static int semanage_conf_init(semanage_conf_t * conf) 330{ 331 conf->store_type = SEMANAGE_CON_DIRECT; 332 conf->store_path = strdup(basename(selinux_policy_root())); 333 conf->ignoredirs = NULL; 334 conf->store_root_path = strdup("/var/lib/selinux"); 335 conf->compiler_directory_path = strdup("/usr/libexec/selinux/hll"); 336 conf->policyvers = sepol_policy_kern_vers_max(); 337 conf->target_platform = SEPOL_TARGET_SELINUX; 338 conf->expand_check = 1; 339 conf->handle_unknown = -1; 340 conf->usepasswd = 1; 341 conf->file_mode = 0644; 342 conf->bzip_blocksize = 9; 343 conf->bzip_small = 0; 344 conf->ignore_module_cache = 0; 345 conf->remove_hll = 0; 346 347 conf->save_previous = 0; 348 conf->save_linked = 0; 349 350 if ((conf->load_policy = 351 calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) { 352 return -1; 353 } 354 355 if (access("/sbin/load_policy", X_OK) == 0) { 356 conf->load_policy->path = strdup("/sbin/load_policy"); 357 } else { 358 conf->load_policy->path = strdup("/usr/sbin/load_policy"); 359 } 360 if (conf->load_policy->path == NULL) { 361 return -1; 362 } 363 conf->load_policy->args = NULL; 364 365 if ((conf->setfiles = 366 calloc(1, sizeof(*(current_conf->setfiles)))) == NULL) { 367 return -1; 368 } 369 if (access("/sbin/setfiles", X_OK) == 0) { 370 conf->setfiles->path = strdup("/sbin/setfiles"); 371 } else { 372 conf->setfiles->path = strdup("/usr/sbin/setfiles"); 373 } 374 if ((conf->setfiles->path == NULL) || 375 (conf->setfiles->args = strdup("-q -c $@ $<")) == NULL) { 376 return -1; 377 } 378 379 if ((conf->sefcontext_compile = 380 calloc(1, sizeof(*(current_conf->sefcontext_compile)))) == NULL) { 381 return -1; 382 } 383 if (access("/sbin/sefcontext_compile", X_OK) == 0) { 384 conf->sefcontext_compile->path = strdup("/sbin/sefcontext_compile"); 385 } else { 386 conf->sefcontext_compile->path = strdup("/usr/sbin/sefcontext_compile"); 387 } 388 if ((conf->sefcontext_compile->path == NULL) || 389 (conf->sefcontext_compile->args = strdup("$@")) == NULL) { 390 return -1; 391 } 392 393 return 0; 394} 395 396/* Parse a libsemanage configuration file. THIS FUNCTION IS NOT 397 * THREAD-SAFE! Return a newly allocated semanage_conf_t *. If the 398 * configuration file could be read, parse it; otherwise rely upon 399 * default values. If the file could not be parsed correctly or if 400 * out of memory return NULL. 401 */ 402semanage_conf_t *semanage_conf_parse(const char *config_filename) 403{ 404 if ((current_conf = calloc(1, sizeof(*current_conf))) == NULL) { 405 return NULL; 406 } 407 if (semanage_conf_init(current_conf) == -1) { 408 goto cleanup; 409 } 410 if ((semanage_in = fopen(config_filename, "r")) == NULL) { 411 /* configuration file does not exist or could not be 412 * read. THIS IS NOT AN ERROR. just rely on the 413 * defaults. */ 414 return current_conf; 415 } 416 parse_errors = 0; 417 semanage_parse(); 418 fclose(semanage_in); 419 if (parse_errors != 0) { 420 goto cleanup; 421 } 422 return current_conf; 423 cleanup: 424 semanage_conf_destroy(current_conf); 425 return NULL; 426} 427 428static void semanage_conf_external_prog_destroy(external_prog_t * ep) 429{ 430 while (ep != NULL) { 431 external_prog_t *next = ep->next; 432 free(ep->path); 433 free(ep->args); 434 free(ep); 435 ep = next; 436 } 437} 438 439/* Deallocates all space associated with a configuration struct, 440 * including the pointer itself. */ 441void semanage_conf_destroy(semanage_conf_t * conf) 442{ 443 if (conf != NULL) { 444 free(conf->store_path); 445 free(conf->ignoredirs); 446 free(conf->store_root_path); 447 free(conf->compiler_directory_path); 448 semanage_conf_external_prog_destroy(conf->load_policy); 449 semanage_conf_external_prog_destroy(conf->setfiles); 450 semanage_conf_external_prog_destroy(conf->sefcontext_compile); 451 semanage_conf_external_prog_destroy(conf->mod_prog); 452 semanage_conf_external_prog_destroy(conf->linked_prog); 453 semanage_conf_external_prog_destroy(conf->kernel_prog); 454 free(conf); 455 } 456} 457 458int semanage_error(const char *msg) 459{ 460 fprintf(stderr, "error parsing semanage configuration file: %s\n", msg); 461 parse_errors++; 462 return 0; 463} 464 465/* Take the string argument for a module store. If it is exactly the 466 * word "direct" then have libsemanage directly manipulate the module 467 * store. The policy path will default to the active policy directory. 468 * Otherwise if it begins with a forward slash interpret it as 469 * an absolute path to a named socket, to which a policy server is 470 * listening on the other end. Otherwise treat it as the host name to 471 * an external server; if there is a colon in the name then everything 472 * after gives a port number. The default port number is 4242. 473 * Returns 0 on success, -1 if out of memory, -2 if a port number is 474 * illegal. 475 */ 476static int parse_module_store(char *arg) 477{ 478 /* arg is already a strdup()ed copy of yytext */ 479 if (arg == NULL) { 480 return -1; 481 } 482 free(current_conf->store_path); 483 if (strcmp(arg, "direct") == 0) { 484 current_conf->store_type = SEMANAGE_CON_DIRECT; 485 current_conf->store_path = 486 strdup(basename(selinux_policy_root())); 487 current_conf->server_port = -1; 488 free(arg); 489 } else if (*arg == '/') { 490 current_conf->store_type = SEMANAGE_CON_POLSERV_LOCAL; 491 current_conf->store_path = arg; 492 current_conf->server_port = -1; 493 } else { 494 char *s; 495 current_conf->store_type = SEMANAGE_CON_POLSERV_REMOTE; 496 if ((s = strchr(arg, ':')) == NULL) { 497 current_conf->store_path = arg; 498 current_conf->server_port = 4242; 499 } else { 500 char *endptr; 501 *s = '\0'; 502 current_conf->store_path = arg; 503 current_conf->server_port = strtol(s + 1, &endptr, 10); 504 if (*(s + 1) == '\0' || *endptr != '\0') { 505 return -2; 506 } 507 } 508 } 509 return 0; 510} 511 512static int parse_store_root_path(char *arg) 513{ 514 if (arg == NULL) { 515 return -1; 516 } 517 518 free(current_conf->store_root_path); 519 current_conf->store_root_path = strdup(arg); 520 return 0; 521} 522 523static int parse_compiler_path(char *arg) 524{ 525 if (arg == NULL) { 526 return -1; 527 } 528 free(current_conf->compiler_directory_path); 529 current_conf->compiler_directory_path = strdup(arg); 530 return 0; 531} 532 533/* Helper function; called whenever configuration file specifies 534 * another external program. Returns 0 on success, -1 if out of 535 * memory. 536 */ 537static int new_external_prog(external_prog_t ** chain) 538{ 539 if ((new_external = calloc(1, sizeof(*new_external))) == NULL) { 540 return -1; 541 } 542 /* hook this new external program to the end of the chain */ 543 if (*chain == NULL) { 544 *chain = new_external; 545 } else { 546 external_prog_t *prog = *chain; 547 while (prog->next != NULL) { 548 prog = prog->next; 549 } 550 prog->next = new_external; 551 } 552 return 0; 553} 554