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