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