Home | History | Annotate | Download | only in tools
      1 #include <stdio.h>
      2 #include <stdarg.h>
      3 #include <ctype.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <unistd.h>
      7 #include <string.h>
      8 #include <errno.h>
      9 #include <stdint.h>
     10 #include <search.h>
     11 #include <stdbool.h>
     12 #include <sepol/sepol.h>
     13 #include <sepol/policydb/policydb.h>
     14 
     15 #define TABLE_SIZE 1024
     16 #define KVP_NUM_OF_RULES (sizeof(rules) / sizeof(key_map))
     17 #define log_set_verbose() do { logging_verbose = 1; log_info("Enabling verbose\n"); } while(0)
     18 #define log_error(fmt, ...) log_msg(stderr, "Error: ", fmt, ##__VA_ARGS__)
     19 #define log_warn(fmt, ...) log_msg(stderr, "Warning: ", fmt, ##__VA_ARGS__)
     20 #define log_info(fmt, ...) if (logging_verbose ) { log_msg(stdout, "Info: ", fmt, ##__VA_ARGS__); }
     21 
     22 typedef struct line_order_list line_order_list;
     23 typedef struct hash_entry hash_entry;
     24 typedef enum key_dir key_dir;
     25 typedef enum data_type data_type;
     26 typedef enum rule_map_switch rule_map_switch;
     27 typedef enum map_match map_match;
     28 typedef struct key_map key_map;
     29 typedef struct kvp kvp;
     30 typedef struct rule_map rule_map;
     31 typedef struct policy_info policy_info;
     32 
     33 enum map_match {
     34 	map_no_matches,
     35 	map_input_matched,
     36 	map_matched
     37 };
     38 
     39 /**
     40  * Whether or not the "key" from a key vaue pair is considered an
     41  * input or an output.
     42  */
     43 enum key_dir {
     44 	dir_in, dir_out
     45 };
     46 
     47 /**
     48  * Used as options to rule_map_free()
     49  *
     50  * This is needed to get around the fact that GNU C's hash_map doesn't copy the key, so
     51  * we cannot free a key when overrding rule_map's in the table.
     52  */
     53 enum rule_map_switch {
     54 	rule_map_preserve_key, /** Used to preserve the key in the rule_map, ie don't free it*/
     55 	rule_map_destroy_key   /** Used when you need a full free of the rule_map structure*/
     56 };
     57 
     58 /**
     59  * The expected "type" of data the value in the key
     60  * value pair should be.
     61  */
     62 enum data_type {
     63 	dt_bool, dt_string
     64 };
     65 
     66 /**
     67  * This list is used to store a double pointer to each
     68  * hash table / line rule combination. This way a replacement
     69  * in the hash table automatically updates the list. The list
     70  * is also used to keep "first encountered" ordering amongst
     71  * the encountered key value pairs in the rules file.
     72  */
     73 struct line_order_list {
     74 	hash_entry *e;
     75 	line_order_list *next;
     76 };
     77 
     78 /**
     79  * The workhorse of the logic. This struct maps key value pairs to
     80  * an associated set of meta data maintained in rule_map_new()
     81  */
     82 struct key_map {
     83 	char *name;
     84 	key_dir dir;
     85 	data_type type;
     86 	char *data;
     87 };
     88 
     89 /**
     90  * Key value pair struct, this represents the raw kvp values coming
     91  * from the rules files.
     92  */
     93 struct kvp {
     94 	char *key;
     95 	char *value;
     96 };
     97 
     98 /**
     99  * Rules are made up of meta data and an associated set of kvp stored in a
    100  * key_map array.
    101  */
    102 struct rule_map {
    103 	char *key; /** key value before hashing */
    104 	size_t length; /** length of the key map */
    105 	int lineno; /** Line number rule was encounter on */
    106 	key_map m[]; /** key value mapping */
    107 };
    108 
    109 struct hash_entry {
    110 	rule_map *r; /** The rule map to store at that location */
    111 };
    112 
    113 /**
    114  * Data associated for a policy file
    115  */
    116 struct policy_info {
    117 
    118 	char *policy_file_name; /** policy file path name */
    119 	FILE *policy_file;      /** file handle to the policy file */
    120 	sepol_policydb_t *db;
    121 	sepol_policy_file_t *pf;
    122 	sepol_handle_t *handle;
    123 	sepol_context_t *con;
    124 };
    125 
    126 /** Set to !0 to enable verbose logging */
    127 static int logging_verbose = 0;
    128 
    129 /** set to !0 to enable strict checking of duplicate entries */
    130 static int is_strict = 0;
    131 
    132 /** file handle to the output file */
    133 static FILE *output_file = NULL;
    134 
    135 /** file handle to the input file */
    136 static FILE *input_file = NULL;
    137 
    138 /** output file path name */
    139 static char *out_file_name = NULL;
    140 
    141 /** input file path name */
    142 static char *in_file_name = NULL;
    143 
    144 static policy_info pol = {
    145 	.policy_file_name = NULL,
    146 	.policy_file = NULL,
    147 	.db = NULL,
    148 	.pf = NULL,
    149 	.handle = NULL,
    150 	.con = NULL
    151 };
    152 
    153 /**
    154  * The heart of the mapping process, this must be updated if a new key value pair is added
    155  * to a rule.
    156  */
    157 key_map rules[] = {
    158                 /*Inputs*/
    159                 { .name = "isSystemServer", .type = dt_bool,   .dir = dir_in,  .data = NULL },
    160                 { .name = "user",           .type = dt_string, .dir = dir_in,  .data = NULL },
    161                 { .name = "seinfo",         .type = dt_string, .dir = dir_in,  .data = NULL },
    162                 { .name = "name",           .type = dt_string, .dir = dir_in,  .data = NULL },
    163                 { .name = "path",           .type = dt_string, .dir = dir_in,  .data = NULL },
    164                 { .name = "sebool",         .type = dt_string, .dir = dir_in,  .data = NULL },
    165                 /*Outputs*/
    166                 { .name = "domain",         .type = dt_string, .dir = dir_out, .data = NULL },
    167                 { .name = "type",           .type = dt_string, .dir = dir_out, .data = NULL },
    168                 { .name = "levelFromUid",   .type = dt_bool,   .dir = dir_out, .data = NULL },
    169                 { .name = "levelFrom",      .type = dt_string,   .dir = dir_out, .data = NULL },
    170                 { .name = "level",          .type = dt_string, .dir = dir_out, .data = NULL },
    171 };
    172 
    173 /**
    174  * Head pointer to a linked list of
    175  * rule map table entries, used for
    176  * preserving the order of entries
    177  * based on "first encounter"
    178  */
    179 static line_order_list *list_head = NULL;
    180 
    181 /**
    182  * Pointer to the tail of the list for
    183  * quick appends to the end of the list
    184  */
    185 static line_order_list *list_tail = NULL;
    186 
    187 /**
    188  * Send a logging message to a file
    189  * @param out
    190  * 	Output file to send message too
    191  * @param prefix
    192  * 	A special prefix to write to the file, such as "Error:"
    193  * @param fmt
    194  * 	The printf style formatter to use, such as "%d"
    195  */
    196 static void __attribute__ ((format(printf, 3, 4)))
    197 log_msg(FILE *out, const char *prefix, const char *fmt, ...) {
    198 
    199 	fprintf(out, "%s", prefix);
    200 	va_list args;
    201 	va_start(args, fmt);
    202 	vfprintf(out, fmt, args);
    203 	va_end(args);
    204 }
    205 
    206 /**
    207  * Checks for a type in the policy.
    208  * @param db
    209  * 	The policy db to search
    210  * @param type
    211  * 	The type to search for
    212  * @return
    213  * 	1 if the type is found, 0 otherwise.
    214  * @warning
    215  * 	This function always returns 1 if libsepol is not linked
    216  * 	statically to this executable and LINK_SEPOL_STATIC is not
    217  * 	defined.
    218  */
    219 int check_type(sepol_policydb_t *db, char *type) {
    220 
    221 	int rc = 1;
    222 #if defined(LINK_SEPOL_STATIC)
    223 	policydb_t *d = (policydb_t *)db;
    224 	hashtab_datum_t dat;
    225 	dat = hashtab_search(d->p_types.table, type);
    226 	rc = (dat == NULL) ? 0 : 1;
    227 #endif
    228 	return rc;
    229 }
    230 
    231 /**
    232  * Validates a key_map against a set of enforcement rules, this
    233  * function exits the application on a type that cannot be properly
    234  * checked
    235  *
    236  * @param m
    237  * 	The key map to check
    238  * @param lineno
    239  * 	The line number in the source file for the corresponding key map
    240  * @return
    241  * 	1 if valid, 0 if invalid
    242  */
    243 static int key_map_validate(key_map *m, int lineno) {
    244 
    245 	int rc = 1;
    246 	int ret = 1;
    247 	int resp;
    248 	char *key = m->name;
    249 	char *value = m->data;
    250 	data_type type = m->type;
    251 	sepol_bool_key_t *se_key;
    252 
    253 	log_info("Validating %s=%s\n", key, value);
    254 
    255 	 /* Booleans can always be checked for sanity */
    256 	if (type == dt_bool && (!strcmp("true", value) || !strcmp("false", value))) {
    257 		goto out;
    258 	}
    259 	else if (type == dt_bool) {
    260 		log_error("Expected boolean value got: %s=%s on line: %d in file: %s\n",
    261 				key, value, lineno, out_file_name);
    262 		rc = 0;
    263 		goto out;
    264 	}
    265 
    266 	if (!strcasecmp(key, "levelFrom") &&
    267 	    (strcasecmp(value, "none") && strcasecmp(value, "all") &&
    268 	     strcasecmp(value, "app") && strcasecmp(value, "user"))) {
    269 		log_error("Unknown levelFrom=%s on line: %d in file: %s\n",
    270 			  value, lineno, out_file_name);
    271 		rc = 0;
    272 		goto out;
    273 	}
    274 
    275 	/*
    276 	 * If there is no policy file present,
    277 	 * then it is not going to enforce the types against the policy so just return.
    278 	 * User and name cannot really be checked.
    279 	 */
    280 	if (!pol.policy_file) {
    281 		goto out;
    282 	}
    283 	else if (!strcasecmp(key, "sebool")) {
    284 
    285 		ret = sepol_bool_key_create(pol.handle, value, &se_key);
    286 		if (ret < 0) {
    287 			log_error("Could not create selinux boolean key, error: %s\n",
    288 					strerror(errno));
    289 			rc = 0;
    290 			goto out;
    291 		}
    292 
    293 		ret = sepol_bool_exists(pol.handle, pol.db, se_key, &resp);
    294 		if (ret < 0) {
    295 			log_error("Could not check selinux boolean, error: %s\n",
    296 					strerror(errno));
    297 			rc = 0;
    298 			sepol_bool_key_free(se_key);
    299 			goto out;
    300 		}
    301 
    302 		if(!resp) {
    303 			log_error("Could not find selinux boolean \"%s\" on line: %d in file: %s\n",
    304 					value, lineno, out_file_name);
    305 			rc = 0;
    306 			sepol_bool_key_free(se_key);
    307 			goto out;
    308 		}
    309 		sepol_bool_key_free(se_key);
    310 	}
    311 	else if (!strcasecmp(key, "type") || !strcasecmp(key, "domain")) {
    312 
    313 		if(!check_type(pol.db, value)) {
    314 			log_error("Could not find selinux type \"%s\" on line: %d in file: %s\n", value,
    315 					lineno, out_file_name);
    316 			rc = 0;
    317 		}
    318 		goto out;
    319 	}
    320 	else if (!strcasecmp(key, "level")) {
    321 
    322 		ret = sepol_mls_check(pol.handle, pol.db, value);
    323 		if (ret < 0) {
    324 			log_error("Could not find selinux level \"%s\", on line: %d in file: %s\n", value,
    325 					lineno, out_file_name);
    326 			rc = 0;
    327 			goto out;
    328 		}
    329 	}
    330 
    331 out:
    332 	log_info("Key map validate returning: %d\n", rc);
    333 	return rc;
    334 }
    335 
    336 /**
    337  * Prints a rule map back to a file
    338  * @param fp
    339  * 	The file handle to print too
    340  * @param r
    341  * 	The rule map to print
    342  */
    343 static void rule_map_print(FILE *fp, rule_map *r) {
    344 
    345 	size_t i;
    346 	key_map *m;
    347 
    348 	for (i = 0; i < r->length; i++) {
    349 		m = &(r->m[i]);
    350 		if (i < r->length - 1)
    351 			fprintf(fp, "%s=%s ", m->name, m->data);
    352 		else
    353 			fprintf(fp, "%s=%s", m->name, m->data);
    354 	}
    355 }
    356 
    357 /**
    358  * Compare two rule maps for equality
    359  * @param rmA
    360  * 	a rule map to check
    361  * @param rmB
    362  * 	a rule map to check
    363  * @return
    364  *  a map_match enum indicating the result
    365  */
    366 static map_match rule_map_cmp(rule_map *rmA, rule_map *rmB) {
    367 
    368 	size_t i;
    369 	size_t j;
    370 	int inputs_found = 0;
    371 	int num_of_matched_inputs = 0;
    372 	int input_mode = 0;
    373 	size_t matches = 0;
    374 	key_map *mA;
    375 	key_map *mB;
    376 
    377 	if (rmA->length != rmB->length)
    378 		return map_no_matches;
    379 
    380 	for (i = 0; i < rmA->length; i++) {
    381 		mA = &(rmA->m[i]);
    382 
    383 		for (j = 0; j < rmB->length; j++) {
    384 			mB = &(rmB->m[j]);
    385 			input_mode = 0;
    386 
    387 			if (mA->type != mB->type)
    388 				continue;
    389 
    390 			if (strcmp(mA->name, mB->name))
    391 				continue;
    392 
    393 			if (strcmp(mA->data, mB->data))
    394 				continue;
    395 
    396 			if (mB->dir != mA->dir)
    397 				continue;
    398 			else if (mB->dir == dir_in) {
    399 				input_mode = 1;
    400 				inputs_found++;
    401 			}
    402 
    403 			if (input_mode) {
    404 				log_info("Matched input lines: name=%s data=%s\n", mA->name, mA->data);
    405 				num_of_matched_inputs++;
    406 			}
    407 
    408 			/* Match found, move on */
    409 			log_info("Matched lines: name=%s data=%s", mA->name, mA->data);
    410 			matches++;
    411 			break;
    412 		}
    413 	}
    414 
    415 	/* If they all matched*/
    416 	if (matches == rmA->length) {
    417 		log_info("Rule map cmp MATCH\n");
    418 		return map_matched;
    419 	}
    420 
    421 	/* They didn't all match but the input's did */
    422 	else if (num_of_matched_inputs == inputs_found) {
    423 		log_info("Rule map cmp INPUT MATCH\n");
    424 		return map_input_matched;
    425 	}
    426 
    427 	/* They didn't all match, and the inputs didn't match, ie it didn't
    428 	 * match */
    429 	else {
    430 		log_info("Rule map cmp NO MATCH\n");
    431 		return map_no_matches;
    432 	}
    433 }
    434 
    435 /**
    436  * Frees a rule map
    437  * @param rm
    438  * 	rule map to be freed.
    439  */
    440 static void rule_map_free(rule_map *rm,
    441 		rule_map_switch s __attribute__((unused)) /* only glibc builds, ignored otherwise */) {
    442 
    443 	size_t i;
    444 	size_t len = rm->length;
    445 	for (i = 0; i < len; i++) {
    446 		key_map *m = &(rm->m[i]);
    447 		free(m->data);
    448 	}
    449 
    450 /* hdestroy() frees comparsion keys for non glibc */
    451 #ifdef __GLIBC__
    452 	if(s == rule_map_destroy_key && rm->key)
    453 		free(rm->key);
    454 #endif
    455 
    456 	free(rm);
    457 }
    458 
    459 static void free_kvp(kvp *k) {
    460 	free(k->key);
    461 	free(k->value);
    462 }
    463 
    464 /**
    465  * Checks a rule_map for any variation of KVP's that shouldn't be allowed.
    466  * Note that this function logs all errors.
    467  *
    468  * Current Checks:
    469  * 1. That a specified name entry should have a specified seinfo entry as well.
    470  * @param rm
    471  *  The rule map to check for validity.
    472  * @return
    473  *  true if the rule is valid, false otherwise.
    474  */
    475 static bool rule_map_validate(const rule_map *rm) {
    476 
    477 	size_t i;
    478 	bool found_name = false;
    479 	bool found_seinfo = false;
    480 	char *name = NULL;
    481 	const key_map *tmp;
    482 
    483 	for(i=0; i < rm->length; i++) {
    484 		tmp = &(rm->m[i]);
    485 
    486 		if(!strcmp(tmp->name, "name") && tmp->data) {
    487 			name = tmp->data;
    488 			found_name = true;
    489 		}
    490 		if(!strcmp(tmp->name, "seinfo") && tmp->data && strcmp(tmp->data, "default")) {
    491 			found_seinfo = true;
    492 		}
    493 	}
    494 
    495 	if(found_name && !found_seinfo) {
    496 		log_error("No specific seinfo value specified with name=\"%s\", on line: %d:  insecure configuration!\n",
    497 				name, rm->lineno);
    498 		return false;
    499 	}
    500 
    501 	return true;
    502 }
    503 
    504 /**
    505  * Given a set of key value pairs, this will construct a new rule map.
    506  * On error this function calls exit.
    507  * @param keys
    508  * 	Keys from a rule line to map
    509  * @param num_of_keys
    510  * 	The length of the keys array
    511  * @param lineno
    512  * 	The line number the keys were extracted from
    513  * @return
    514  * 	A rule map pointer.
    515  */
    516 static rule_map *rule_map_new(kvp keys[], size_t num_of_keys, int lineno) {
    517 
    518 	size_t i = 0, j = 0;
    519 	bool valid_rule;
    520 	rule_map *new_map = NULL;
    521 	kvp *k = NULL;
    522 	key_map *r = NULL, *x = NULL;
    523 
    524 	new_map = calloc(1, (num_of_keys * sizeof(key_map)) + sizeof(rule_map));
    525 	if (!new_map)
    526 		goto oom;
    527 
    528 	new_map->length = num_of_keys;
    529 	new_map->lineno = lineno;
    530 
    531 	/* For all the keys in a rule line*/
    532 	for (i = 0; i < num_of_keys; i++) {
    533 		k = &(keys[i]);
    534 		r = &(new_map->m[i]);
    535 
    536 		for (j = 0; j < KVP_NUM_OF_RULES; j++) {
    537 			x = &(rules[j]);
    538 
    539 			/* Only assign key name to map name */
    540 			if (strcasecmp(k->key, x->name)) {
    541 				if (i == KVP_NUM_OF_RULES) {
    542 					log_error("No match for key: %s\n", k->key);
    543 					goto err;
    544 				}
    545 				continue;
    546 			}
    547 
    548 			memcpy(r, x, sizeof(key_map));
    549 
    550 			/* Assign rule map value to one from file */
    551 			r->data = strdup(k->value);
    552 			if (!r->data)
    553 				goto oom;
    554 
    555 			/* Enforce type check*/
    556 			log_info("Validating keys!\n");
    557 			if (!key_map_validate(r, lineno)) {
    558 				log_error("Could not validate\n");
    559 				goto err;
    560 			}
    561 
    562 			/* Only build key off of inputs*/
    563 			if (r->dir == dir_in) {
    564 				char *tmp;
    565 				int key_len = strlen(k->key);
    566 				int val_len = strlen(k->value);
    567 				int l = (new_map->key) ? strlen(new_map->key) : 0;
    568 				l = l + key_len + val_len;
    569 				l += 1;
    570 
    571 				tmp = realloc(new_map->key, l);
    572 				if (!tmp)
    573 					goto oom;
    574 
    575 				if (!new_map->key)
    576 					memset(tmp, 0, l);
    577 
    578 				new_map->key = tmp;
    579 
    580 				strncat(new_map->key, k->key, key_len);
    581 				strncat(new_map->key, k->value, val_len);
    582 			}
    583 			break;
    584 		}
    585 		free_kvp(k);
    586 	}
    587 
    588 	if (new_map->key == NULL) {
    589 		log_error("Strange, no keys found, input file corrupt perhaps?\n");
    590 		goto err;
    591 	}
    592 
    593 	valid_rule = rule_map_validate(new_map);
    594 	if(!valid_rule) {
    595 		/* Error message logged from rule_map_validate() */
    596 		goto err;
    597 	}
    598 
    599 	return new_map;
    600 
    601 oom:
    602 	log_error("Out of memory!\n");
    603 err:
    604 	if(new_map) {
    605 		rule_map_free(new_map, rule_map_destroy_key);
    606 		for (; i < num_of_keys; i++) {
    607 			k = &(keys[i]);
    608 			free_kvp(k);
    609 		}
    610 	}
    611 	exit(EXIT_FAILURE);
    612 }
    613 
    614 /**
    615  * Print the usage of the program
    616  */
    617 static void usage() {
    618 	printf(
    619 	        "checkseapp [options] <input file>\n"
    620 		        "Processes an seapp_contexts file specified by argument <input file> (default stdin) "
    621 		        "and allows later declarations to override previous ones on a match.\n"
    622 		        "Options:\n"
    623 		        "-h - print this help message\n"
    624 			"-s - enable strict checking of duplicates. This causes the program to exit on a duplicate entry with a non-zero exit status\n"
    625 		        "-v - enable verbose debugging informations\n"
    626 		        "-p policy file - specify policy file for strict checking of output selectors against the policy\n"
    627 		        "-o output file - specify output file, default is stdout\n");
    628 }
    629 
    630 static void init() {
    631 
    632 	/* If not set on stdin already */
    633 	if(!input_file) {
    634 		log_info("Opening input file: %s\n", in_file_name);
    635 		input_file = fopen(in_file_name, "r");
    636 		if (!input_file) {
    637 			log_error("Could not open file: %s error: %s\n", in_file_name, strerror(errno));
    638 			exit(EXIT_FAILURE);
    639 		}
    640 	}
    641 
    642 	/* If not set on std out already */
    643 	if(!output_file) {
    644 		output_file = fopen(out_file_name, "w+");
    645 		if (!output_file) {
    646 			log_error("Could not open file: %s error: %s\n", out_file_name, strerror(errno));
    647 			exit(EXIT_FAILURE);
    648 		}
    649 	}
    650 
    651 	if (pol.policy_file_name) {
    652 
    653 		log_info("Opening policy file: %s\n", pol.policy_file_name);
    654 		pol.policy_file = fopen(pol.policy_file_name, "rb");
    655 		if (!pol.policy_file) {
    656 			log_error("Could not open file: %s error: %s\n",
    657 					pol.policy_file_name, strerror(errno));
    658 			exit(EXIT_FAILURE);
    659 		}
    660 
    661 		pol.handle = sepol_handle_create();
    662 		if (!pol.handle) {
    663 			log_error("Could not create sepolicy handle: %s\n",
    664 					strerror(errno));
    665 			exit(EXIT_FAILURE);
    666 		}
    667 
    668 		if (sepol_policy_file_create(&pol.pf) < 0) {
    669 			log_error("Could not create sepolicy file: %s!\n",
    670 					strerror(errno));
    671 			exit(EXIT_FAILURE);
    672 		}
    673 
    674 		sepol_policy_file_set_fp(pol.pf, pol.policy_file);
    675 		sepol_policy_file_set_handle(pol.pf, pol.handle);
    676 
    677 		if (sepol_policydb_create(&pol.db) < 0) {
    678 			log_error("Could not create sepolicy db: %s!\n",
    679 					strerror(errno));
    680 			exit(EXIT_FAILURE);
    681 		}
    682 
    683 		if (sepol_policydb_read(pol.db, pol.pf) < 0) {
    684 			log_error("Could not lod policy file to db: %s!\n",
    685 					strerror(errno));
    686 			exit(EXIT_FAILURE);
    687 		}
    688 	}
    689 
    690 	log_info("Policy file set to: %s\n", (pol.policy_file_name == NULL) ? "None" : pol.policy_file_name);
    691 	log_info("Input file set to: %s\n", (in_file_name == NULL) ? "stdin" : in_file_name);
    692 	log_info("Output file set to: %s\n", (out_file_name == NULL) ? "stdout" : out_file_name);
    693 
    694 #if !defined(LINK_SEPOL_STATIC)
    695 	log_warn("LINK_SEPOL_STATIC is not defined\n""Not checking types!");
    696 #endif
    697 
    698 }
    699 
    700 /**
    701  * Handle parsing and setting the global flags for the command line
    702  * options. This function calls exit on failure.
    703  * @param argc
    704  * 	argument count
    705  * @param argv
    706  * 	argument list
    707  */
    708 static void handle_options(int argc, char *argv[]) {
    709 
    710 	int c;
    711 	int num_of_args;
    712 
    713 	while ((c = getopt(argc, argv, "ho:p:sv")) != -1) {
    714 		switch (c) {
    715 		case 'h':
    716 			usage();
    717 			exit(EXIT_SUCCESS);
    718 		case 'o':
    719 			out_file_name = optarg;
    720 			break;
    721 		case 'p':
    722 			pol.policy_file_name = optarg;
    723 			break;
    724 		case 's':
    725 			is_strict = 1;
    726 			break;
    727 		case 'v':
    728 			log_set_verbose();
    729 			break;
    730 		case '?':
    731 			if (optopt == 'o' || optopt == 'p')
    732 				log_error("Option -%c requires an argument.\n", optopt);
    733 			else if (isprint (optopt))
    734 				log_error("Unknown option `-%c'.\n", optopt);
    735 			else {
    736 				log_error(
    737 						"Unknown option character `\\x%x'.\n",
    738 						optopt);
    739 			}
    740 		default:
    741 			exit(EXIT_FAILURE);
    742 		}
    743 	}
    744 
    745 	num_of_args = argc - optind;
    746 
    747 	if (num_of_args > 1) {
    748 		log_error("Too many arguments, expected 0 or 1, argument, got %d\n", num_of_args);
    749 		usage();
    750 		exit(EXIT_FAILURE);
    751 	} else if (num_of_args == 1) {
    752 		in_file_name = argv[argc - 1];
    753 	} else {
    754 		input_file = stdin;
    755 		in_file_name = "stdin";
    756 	}
    757 
    758 	if (!out_file_name) {
    759 		output_file = stdout;
    760 		out_file_name = "stdout";
    761 	}
    762 }
    763 
    764 /**
    765  * Adds a rule_map double pointer, ie the hash table pointer to the list.
    766  * By using a double pointer, the hash table can have a line be overridden
    767  * and the value is updated in the list. This function calls exit on failure.
    768  * @param rm
    769  * 	the rule_map to add.
    770  */
    771 static void list_add(hash_entry *e) {
    772 
    773 	line_order_list *node = malloc(sizeof(line_order_list));
    774 	if (node == NULL)
    775 		goto oom;
    776 
    777 	node->next = NULL;
    778 	node->e = e;
    779 
    780 	if (list_head == NULL)
    781 		list_head = list_tail = node;
    782 	else {
    783 		list_tail->next = node;
    784 		list_tail = list_tail->next;
    785 	}
    786 	return;
    787 
    788 oom:
    789 	log_error("Out of memory!\n");
    790 	exit(EXIT_FAILURE);
    791 }
    792 
    793 /**
    794  * Free's the rule map list, which ultimatley contains
    795  * all the malloc'd rule_maps.
    796  */
    797 static void list_free() {
    798 	line_order_list *cursor, *tmp;
    799 	hash_entry *e;
    800 
    801 	cursor = list_head;
    802 	while (cursor) {
    803 		e = cursor->e;
    804 		rule_map_free(e->r, rule_map_destroy_key);
    805 		tmp = cursor;
    806 		cursor = cursor->next;
    807 		free(e);
    808 		free(tmp);
    809 	}
    810 }
    811 
    812 /**
    813  * Adds a rule to the hash table and to the ordered list if needed.
    814  * @param rm
    815  * 	The rule map to add.
    816  */
    817 static void rule_add(rule_map *rm) {
    818 
    819 	map_match cmp;
    820 	ENTRY e;
    821 	ENTRY *f;
    822 	hash_entry *entry;
    823 	hash_entry *tmp;
    824 	char *preserved_key;
    825 
    826 	e.key = rm->key;
    827 
    828 	log_info("Searching for key: %s\n", e.key);
    829 	/* Check to see if it has already been added*/
    830 	f = hsearch(e, FIND);
    831 
    832 	/*
    833 	 * Since your only hashing on a partial key, the inputs we need to handle
    834 	 * when you want to override the outputs for a given input set, as well as
    835 	 * checking for duplicate entries.
    836 	 */
    837 	if(f) {
    838 		log_info("Existing entry found!\n");
    839 		tmp = (hash_entry *)f->data;
    840 		cmp = rule_map_cmp(rm, tmp->r);
    841 		log_info("Comparing on rule map ret: %d\n", cmp);
    842 		/* Override be freeing the old rule map and updating
    843 		   the pointer */
    844 		if(cmp != map_matched) {
    845 
    846 			/*
    847 			 * DO NOT free key pointers given to the hash map, instead
    848 			 * free the new key. The ordering here is critical!
    849 			 */
    850 			preserved_key = tmp->r->key;
    851 			rule_map_free(tmp->r, rule_map_preserve_key);
    852 /*  hdestroy() frees comparsion keys for non glibc */
    853 #ifdef __GLIBC__
    854 			free(rm->key);
    855 #endif
    856 			rm->key = preserved_key;
    857 			tmp->r = rm;
    858 		}
    859 		/* Duplicate */
    860 		else {
    861 			/* if is_strict is set, then don't allow duplicates */
    862 			if(is_strict) {
    863 				log_error("Duplicate line detected in file: %s\n"
    864 					"Lines %d and %d match!\n",
    865 					out_file_name, tmp->r->lineno, rm->lineno);
    866 				rule_map_free(rm, rule_map_destroy_key);
    867 				goto err;
    868 			}
    869 
    870 			/* Allow duplicates, just drop the entry*/
    871 			log_info("Duplicate line detected in file: %s\n"
    872 					"Lines %d and %d match!\n",
    873 					out_file_name, tmp->r->lineno, rm->lineno);
    874 			rule_map_free(rm, rule_map_destroy_key);
    875 		}
    876 	}
    877 	/* It wasn't found, just add the rule map to the table */
    878 	else {
    879 
    880 		entry = malloc(sizeof(hash_entry));
    881 		if (!entry)
    882 			goto oom;
    883 
    884 		entry->r = rm;
    885 		e.data = entry;
    886 
    887 		f = hsearch(e, ENTER);
    888 		if(f == NULL) {
    889 			goto oom;
    890 		}
    891 
    892 		/* new entries must be added to the ordered list */
    893 		entry->r = rm;
    894 		list_add(entry);
    895 	}
    896 
    897 	return;
    898 oom:
    899 	if (e.key)
    900 		free(e.key);
    901 	if (entry)
    902 		free(entry);
    903 	if (rm)
    904 		free(rm);
    905 	log_error("Out of memory in function: %s\n", __FUNCTION__);
    906 err:
    907 	exit(EXIT_FAILURE);
    908 }
    909 
    910 /**
    911  * Parses the seapp_contexts file and adds them to the
    912  * hash table and ordered list entries when it encounters them.
    913  * Calls exit on failure.
    914  */
    915 static void parse() {
    916 
    917 	char line_buf[BUFSIZ];
    918 	char *token;
    919 	unsigned lineno = 0;
    920 	char *p, *name = NULL, *value = NULL, *saveptr;
    921 	size_t len;
    922 	kvp keys[KVP_NUM_OF_RULES];
    923 	size_t token_cnt = 0;
    924 
    925 	while (fgets(line_buf, sizeof line_buf - 1, input_file)) {
    926 
    927 		lineno++;
    928 		log_info("Got line %d\n", lineno);
    929 		len = strlen(line_buf);
    930 		if (line_buf[len - 1] == '\n')
    931 			line_buf[len - 1] = '\0';
    932 		p = line_buf;
    933 		while (isspace(*p))
    934 			p++;
    935 		if (*p == '#' || *p == '\0')
    936 			continue;
    937 
    938 		token = strtok_r(p, " \t", &saveptr);
    939 		if (!token)
    940 			goto err;
    941 
    942 		token_cnt = 0;
    943 		memset(keys, 0, sizeof(kvp) * KVP_NUM_OF_RULES);
    944 		while (1) {
    945 
    946 			name = token;
    947 			value = strchr(name, '=');
    948 			if (!value)
    949 				goto err;
    950 			*value++ = 0;
    951 
    952 			keys[token_cnt].key = strdup(name);
    953 			if (!keys[token_cnt].key)
    954 				goto oom;
    955 
    956 			keys[token_cnt].value = strdup(value);
    957 			if (!keys[token_cnt].value)
    958 				goto oom;
    959 
    960 			token_cnt++;
    961 
    962 			token = strtok_r(NULL, " \t", &saveptr);
    963 			if (!token)
    964 				break;
    965 
    966 		} /*End token parsing */
    967 
    968 		rule_map *r = rule_map_new(keys, token_cnt, lineno);
    969 		rule_add(r);
    970 
    971 	} /* End file parsing */
    972 	return;
    973 
    974 err:
    975 	log_error("reading %s, line %u, name %s, value %s\n",
    976 			in_file_name, lineno, name, value);
    977 	exit(EXIT_FAILURE);
    978 oom:
    979 	log_error("In function %s:  Out of memory\n", __FUNCTION__);
    980 	exit(EXIT_FAILURE);
    981 }
    982 
    983 /**
    984  * Should be called after parsing to cause the printing of the rule_maps
    985  * stored in the ordered list, head first, which preserves the "first encountered"
    986  * ordering.
    987  */
    988 static void output() {
    989 
    990 	rule_map *r;
    991 	line_order_list *cursor;
    992 	cursor = list_head;
    993 
    994 	while (cursor) {
    995 		r = cursor->e->r;
    996 		rule_map_print(output_file, r);
    997 		cursor = cursor->next;
    998 		fprintf(output_file, "\n");
    999 	}
   1000 }
   1001 
   1002 /**
   1003  * This function is registered to the at exit handler and should clean up
   1004  * the programs dynamic resources, such as memory and fd's.
   1005  */
   1006 static void cleanup() {
   1007 
   1008 	/* Only close this when it was opened by me and not the crt */
   1009 	if (out_file_name && output_file) {
   1010 		log_info("Closing file: %s\n", out_file_name);
   1011 		fclose(output_file);
   1012 	}
   1013 
   1014 	/* Only close this when it was opened by me  and not the crt */
   1015 	if (in_file_name && input_file) {
   1016 		log_info("Closing file: %s\n", in_file_name);
   1017 		fclose(input_file);
   1018 	}
   1019 
   1020 	if (pol.policy_file) {
   1021 
   1022 		log_info("Closing file: %s\n", pol.policy_file_name);
   1023 		fclose(pol.policy_file);
   1024 
   1025 		if (pol.db)
   1026 			sepol_policydb_free(pol.db);
   1027 
   1028 		if (pol.pf)
   1029 			sepol_policy_file_free(pol.pf);
   1030 
   1031 		if (pol.handle)
   1032 			sepol_handle_destroy(pol.handle);
   1033 	}
   1034 
   1035 	log_info("Freeing list\n");
   1036 	list_free();
   1037 	hdestroy();
   1038 }
   1039 
   1040 int main(int argc, char *argv[]) {
   1041 	if (!hcreate(TABLE_SIZE)) {
   1042 		log_error("Could not create hash table: %s\n", strerror(errno));
   1043 		exit(EXIT_FAILURE);
   1044 	}
   1045 	atexit(cleanup);
   1046 	handle_options(argc, argv);
   1047 	init();
   1048 	log_info("Starting to parse\n");
   1049 	parse();
   1050 	log_info("Parsing completed, generating output\n");
   1051 	output();
   1052 	log_info("Success, generated output\n");
   1053 	exit(EXIT_SUCCESS);
   1054 }
   1055