conf-parse.y revision 9cd587f5533456e7b26601e27e65744272e2e783
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#include "handle.h" 25 26#include <sepol/policydb.h> 27#include <selinux/selinux.h> 28#include <semanage/handle.h> 29 30#include <unistd.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34 35extern int semanage_lex(); /* defined in conf-scan.c */ 36int semanage_error(char *msg); 37 38extern FILE *semanage_in; 39extern char *semanage_text; 40 41static int parse_module_store(char *arg); 42static void semanage_conf_external_prog_destroy(external_prog_t *ep); 43static int new_external_prog(external_prog_t **chain); 44 45static semanage_conf_t *current_conf; 46static external_prog_t *new_external; 47static int parse_errors; 48 49#define PASSIGN(p1,p2) { free(p1); p1 = p2; } 50 51%} 52 53%name-prefix="semanage_" 54 55%union { 56 int d; 57 char *s; 58} 59 60%token MODULE_STORE VERSION EXPAND_CHECK FILE_MODE SAVE_PREVIOUS SAVE_LINKED 61%token LOAD_POLICY_START SETFILES_START DISABLE_GENHOMEDIRCON HANDLE_UNKNOWN USEPASSWD 62%token BZIP_BLOCKSIZE BZIP_SMALL 63%token VERIFY_MOD_START VERIFY_LINKED_START VERIFY_KERNEL_START BLOCK_END 64%token PROG_PATH PROG_ARGS 65%token <s> ARG 66%type <d> verify_start_tok 67 68%% 69 70config_file: config_line config_file 71 | /* empty */ 72 ; 73 74config_line: single_opt 75 | command_block 76 | verify_block 77 ; 78 79single_opt: module_store 80 | version 81 | expand_check 82 | file_mode 83 | save_previous 84 | save_linked 85 | disable_genhomedircon 86 | usepasswd 87 | handle_unknown 88 | bzip_blocksize 89 | bzip_small 90 ; 91 92module_store: MODULE_STORE '=' ARG { 93 if (parse_module_store($3) != 0) { 94 parse_errors++; 95 YYABORT; 96 } 97 } 98 99 ; 100 101version: VERSION '=' ARG { 102 current_conf->policyvers = atoi($3); 103 free($3); 104 if (current_conf->policyvers < sepol_policy_kern_vers_min() || 105 current_conf->policyvers > sepol_policy_kern_vers_max()) { 106 parse_errors++; 107 YYABORT; 108 } 109 } 110 ; 111 112expand_check: EXPAND_CHECK '=' ARG { 113 current_conf->expand_check = atoi($3); 114 free($3); 115 } 116 ; 117 118file_mode: FILE_MODE '=' ARG { 119 current_conf->file_mode = strtoul($3, NULL, 8); 120 free($3); 121 } 122 ; 123 124save_previous: SAVE_PREVIOUS '=' ARG { 125 if (strcasecmp($3, "true") == 0) 126 current_conf->save_previous = 1; 127 else if (strcasecmp($3, "false") == 0) 128 current_conf->save_previous = 0; 129 else { 130 yyerror("save-previous can only be 'true' or 'false'"); 131 } 132 } 133 ; 134 135 136save_linked: SAVE_LINKED '=' ARG { 137 if (strcasecmp($3, "true") == 0) 138 current_conf->save_linked = 1; 139 else if (strcasecmp($3, "false") == 0) 140 current_conf->save_linked = 0; 141 else { 142 yyerror("save-linked can only be 'true' or 'false'"); 143 } 144 } 145 ; 146 147disable_genhomedircon: DISABLE_GENHOMEDIRCON '=' ARG { 148 if (strcasecmp($3, "false") == 0) { 149 current_conf->disable_genhomedircon = 0; 150 } else if (strcasecmp($3, "true") == 0) { 151 current_conf->disable_genhomedircon = 1; 152 } else { 153 yyerror("disable-genhomedircon can only be 'true' or 'false'"); 154 } 155 free($3); 156 } 157 158usepasswd: USEPASSWD '=' ARG { 159 if (strcasecmp($3, "false") == 0) { 160 current_conf->usepasswd = 0; 161 } else if (strcasecmp($3, "true") == 0) { 162 current_conf->usepasswd = 1; 163 } else { 164 yyerror("usepasswd can only be 'true' or 'false'"); 165 } 166 free($3); 167 } 168 169handle_unknown: HANDLE_UNKNOWN '=' ARG { 170 if (strcasecmp($3, "deny") == 0) { 171 current_conf->handle_unknown = SEPOL_DENY_UNKNOWN; 172 } else if (strcasecmp($3, "reject") == 0) { 173 current_conf->handle_unknown = SEPOL_REJECT_UNKNOWN; 174 } else if (strcasecmp($3, "allow") == 0) { 175 current_conf->handle_unknown = SEPOL_ALLOW_UNKNOWN; 176 } else { 177 yyerror("handle-unknown can only be 'deny', 'reject' or 'allow'"); 178 } 179 free($3); 180 } 181 182bzip_blocksize: BZIP_BLOCKSIZE '=' ARG { 183 int blocksize = atoi($3); 184 free($3); 185 if (blocksize > 9) 186 yyerror("bzip-blocksize can only be in the range 0-9"); 187 else 188 current_conf->bzip_blocksize = blocksize; 189} 190 191bzip_small: BZIP_SMALL '=' ARG { 192 if (strcasecmp($3, "false") == 0) { 193 current_conf->bzip_small = 0; 194 } else if (strcasecmp($3, "true") == 0) { 195 current_conf->bzip_small = 1; 196 } else { 197 yyerror("bzip-small can only be 'true' or 'false'"); 198 } 199 free($3); 200} 201 202command_block: 203 command_start external_opts BLOCK_END { 204 if (new_external->path == NULL) { 205 parse_errors++; 206 YYABORT; 207 } 208 } 209 ; 210 211command_start: 212 LOAD_POLICY_START { 213 semanage_conf_external_prog_destroy(current_conf->load_policy); 214 current_conf->load_policy = NULL; 215 if (new_external_prog(¤t_conf->load_policy) == -1) { 216 parse_errors++; 217 YYABORT; 218 } 219 } 220 | SETFILES_START { 221 semanage_conf_external_prog_destroy(current_conf->setfiles); 222 current_conf->setfiles = NULL; 223 if (new_external_prog(¤t_conf->setfiles) == -1) { 224 parse_errors++; 225 YYABORT; 226 } 227 } 228 ; 229 230verify_block: verify_start external_opts BLOCK_END { 231 if (new_external->path == NULL) { 232 parse_errors++; 233 YYABORT; 234 } 235 } 236 ; 237 238verify_start: verify_start_tok { 239 if ($1 == -1) { 240 parse_errors++; 241 YYABORT; 242 } 243 } 244 ; 245 246verify_start_tok: VERIFY_MOD_START {$$ = new_external_prog(¤t_conf->mod_prog);} 247 | VERIFY_LINKED_START {$$ = new_external_prog(¤t_conf->linked_prog);} 248 | VERIFY_KERNEL_START {$$ = new_external_prog(¤t_conf->kernel_prog);} 249 ; 250 251external_opts: external_opt external_opts 252 | /* empty */ 253 ; 254 255external_opt: PROG_PATH '=' ARG { PASSIGN(new_external->path, $3); } 256 | PROG_ARGS '=' ARG { PASSIGN(new_external->args, $3); } 257 ; 258 259%% 260 261static int semanage_conf_init(semanage_conf_t * conf) 262{ 263 conf->store_type = SEMANAGE_CON_DIRECT; 264 conf->store_path = strdup(basename(semanage_policy_root())); 265 conf->policyvers = sepol_policy_kern_vers_max(); 266 conf->expand_check = 1; 267 conf->handle_unknown = -1; 268 conf->usepasswd = 1; 269 conf->file_mode = 0644; 270 conf->bzip_blocksize = 9; 271 conf->bzip_small = 0; 272 273 conf->save_previous = 0; 274 conf->save_linked = 0; 275 276 if ((conf->load_policy = 277 calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) { 278 return -1; 279 } 280 281 if (access("/sbin/load_policy", X_OK) == 0) { 282 conf->load_policy->path = strdup("/sbin/load_policy"); 283 } else { 284 conf->load_policy->path = strdup("/usr/sbin/load_policy"); 285 } 286 if (conf->load_policy->path == NULL) { 287 return -1; 288 } 289 conf->load_policy->args = NULL; 290 291 if ((conf->setfiles = 292 calloc(1, sizeof(*(current_conf->setfiles)))) == NULL) { 293 return -1; 294 } 295 if (access("/sbin/setfiles", X_OK) == 0) { 296 conf->setfiles->path = strdup("/sbin/setfiles"); 297 } else { 298 conf->setfiles->path = strdup("/usr/sbin/setfiles"); 299 } 300 if ((conf->setfiles->path == NULL) || 301 (conf->setfiles->args = strdup("-q -c $@ $<")) == NULL) { 302 return -1; 303 } 304 305 return 0; 306} 307 308/* Parse a libsemanage configuration file. THIS FUNCTION IS NOT 309 * THREAD-SAFE! Return a newly allocated semanage_conf_t *. If the 310 * configuration file could be read, parse it; otherwise rely upon 311 * default values. If the file could not be parsed correctly or if 312 * out of memory return NULL. 313 */ 314semanage_conf_t *semanage_conf_parse(const char *config_filename) 315{ 316 if ((current_conf = calloc(1, sizeof(*current_conf))) == NULL) { 317 return NULL; 318 } 319 if (semanage_conf_init(current_conf) == -1) { 320 goto cleanup; 321 } 322 if ((semanage_in = fopen(config_filename, "r")) == NULL) { 323 /* configuration file does not exist or could not be 324 * read. THIS IS NOT AN ERROR. just rely on the 325 * defaults. */ 326 return current_conf; 327 } 328 parse_errors = 0; 329 semanage_parse(); 330 fclose(semanage_in); 331 if (parse_errors != 0) { 332 goto cleanup; 333 } 334 return current_conf; 335 cleanup: 336 semanage_conf_destroy(current_conf); 337 return NULL; 338} 339 340static void semanage_conf_external_prog_destroy(external_prog_t * ep) 341{ 342 while (ep != NULL) { 343 external_prog_t *next = ep->next; 344 free(ep->path); 345 free(ep->args); 346 free(ep); 347 ep = next; 348 } 349} 350 351/* Deallocates all space associated with a configuration struct, 352 * including the pointer itself. */ 353void semanage_conf_destroy(semanage_conf_t * conf) 354{ 355 if (conf != NULL) { 356 free(conf->store_path); 357 semanage_conf_external_prog_destroy(conf->load_policy); 358 semanage_conf_external_prog_destroy(conf->setfiles); 359 semanage_conf_external_prog_destroy(conf->mod_prog); 360 semanage_conf_external_prog_destroy(conf->linked_prog); 361 semanage_conf_external_prog_destroy(conf->kernel_prog); 362 free(conf); 363 } 364} 365 366int semanage_error(char *msg) 367{ 368 fprintf(stderr, "error parsing semanage configuration file: %s\n", msg); 369 parse_errors++; 370 return 0; 371} 372 373/* Take the string argument for a module store. If it is exactly the 374 * word "direct" then have libsemanage directly manipulate the module 375 * store. The policy path will default to the active policy directory. 376 * Otherwise if it begins with a forward slash interpret it as 377 * an absolute path to a named socket, to which a policy server is 378 * listening on the other end. Otherwise treat it as the host name to 379 * an external server; if there is a colon in the name then everything 380 * after gives a port number. The default port number is 4242. 381 * Returns 0 on success, -1 if out of memory, -2 if a port number is 382 * illegal. 383 */ 384static int parse_module_store(char *arg) 385{ 386 /* arg is already a strdup()ed copy of yytext */ 387 if (arg == NULL) { 388 return -1; 389 } 390 free(current_conf->store_path); 391 if (strcmp(arg, "direct") == 0) { 392 current_conf->store_type = SEMANAGE_CON_DIRECT; 393 current_conf->store_path = 394 strdup(basename(semanage_policy_root())); 395 current_conf->server_port = -1; 396 free(arg); 397 } else if (*arg == '/') { 398 current_conf->store_type = SEMANAGE_CON_POLSERV_LOCAL; 399 current_conf->store_path = arg; 400 current_conf->server_port = -1; 401 } else { 402 char *s; 403 current_conf->store_type = SEMANAGE_CON_POLSERV_REMOTE; 404 if ((s = strchr(arg, ':')) == NULL) { 405 current_conf->store_path = arg; 406 current_conf->server_port = 4242; 407 } else { 408 char *endptr; 409 *s = '\0'; 410 current_conf->store_path = arg; 411 current_conf->server_port = strtol(s + 1, &endptr, 10); 412 if (*(s + 1) == '\0' || *endptr != '\0') { 413 return -2; 414 } 415 } 416 } 417 return 0; 418} 419 420/* Helper function; called whenever configuration file specifies 421 * another external program. Returns 0 on success, -1 if out of 422 * memory. 423 */ 424static int new_external_prog(external_prog_t ** chain) 425{ 426 if ((new_external = calloc(1, sizeof(*new_external))) == NULL) { 427 return -1; 428 } 429 /* hook this new external program to the end of the chain */ 430 if (*chain == NULL) { 431 *chain = new_external; 432 } else { 433 external_prog_t *prog = *chain; 434 while (prog->next != NULL) { 435 prog = prog->next; 436 } 437 prog->next = new_external; 438 } 439 return 0; 440} 441