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