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