blob: aca294fbed664180ee8230ca4206272b8ab9caf1 [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>
William Roberts61846292013-10-15 09:38:24 -070011#include <stdbool.h>
William Robertsf0e0a942012-08-27 15:41:15 -070012#include <sepol/sepol.h>
13#include <sepol/policydb/policydb.h>
William Roberts81e1f902015-06-03 21:57:47 -070014#include <pcre.h>
William Robertsf0e0a942012-08-27 15:41:15 -070015
16#define TABLE_SIZE 1024
17#define KVP_NUM_OF_RULES (sizeof(rules) / sizeof(key_map))
18#define log_set_verbose() do { logging_verbose = 1; log_info("Enabling verbose\n"); } while(0)
19#define log_error(fmt, ...) log_msg(stderr, "Error: ", fmt, ##__VA_ARGS__)
20#define log_warn(fmt, ...) log_msg(stderr, "Warning: ", fmt, ##__VA_ARGS__)
21#define log_info(fmt, ...) if (logging_verbose ) { log_msg(stdout, "Info: ", fmt, ##__VA_ARGS__); }
22
William Roberts81e1f902015-06-03 21:57:47 -070023/**
24 * Initializes an empty, static list.
25 */
26#define list_init(free_fn) { .head = NULL, .tail = NULL, .freefn = free_fn }
27
28/**
29 * given an item in the list, finds the offset for the container
30 * it was stored in.
31 *
32 * @element The element from the list
33 * @type The container type ie what you allocated that has the list_element structure in it.
34 * @name The name of the field that is the list_element
35 *
36 */
37#define list_entry(element, type, name) \
38 (type *)(((uint8_t *)element) - (uint8_t *)&(((type *)NULL)->name))
39
40/**
41 * Iterates over the list, do not free elements from the list when using this.
42 * @list The list head to walk
43 * @var The variable name for the cursor
44 */
45#define list_for_each(list, var) \
46 for(var = (list)->head; var != NULL; var = var->next)
47
48
William Robertsf0e0a942012-08-27 15:41:15 -070049typedef struct hash_entry hash_entry;
50typedef enum key_dir key_dir;
51typedef enum data_type data_type;
52typedef enum rule_map_switch rule_map_switch;
William Roberts0ae3a8a2012-09-04 11:51:04 -070053typedef enum map_match map_match;
William Robertsf0e0a942012-08-27 15:41:15 -070054typedef struct key_map key_map;
55typedef struct kvp kvp;
56typedef struct rule_map rule_map;
57typedef struct policy_info policy_info;
William Roberts81e1f902015-06-03 21:57:47 -070058typedef struct list_element list_element;
59typedef struct list list;
60typedef struct key_map_regex key_map_regex;
61typedef struct file_info file_info;
William Robertsf0e0a942012-08-27 15:41:15 -070062
William Roberts0ae3a8a2012-09-04 11:51:04 -070063enum map_match {
64 map_no_matches,
65 map_input_matched,
66 map_matched
67};
68
Stephen Smalley0b820042015-02-13 14:58:31 -050069const char *map_match_str[] = {
70 "do not match",
71 "match on all inputs",
72 "match on everything"
73};
74
William Robertsf0e0a942012-08-27 15:41:15 -070075/**
76 * Whether or not the "key" from a key vaue pair is considered an
77 * input or an output.
78 */
79enum key_dir {
80 dir_in, dir_out
81};
82
William Roberts81e1f902015-06-03 21:57:47 -070083struct list_element {
84 list_element *next;
85};
86
87struct list {
88 list_element *head;
89 list_element *tail;
90 void (*freefn)(list_element *e);
91};
92
93struct key_map_regex {
94 pcre *compiled;
95 pcre_extra *extra;
William Robertsf0e0a942012-08-27 15:41:15 -070096};
97
98/**
99 * The workhorse of the logic. This struct maps key value pairs to
100 * an associated set of meta data maintained in rule_map_new()
101 */
102struct key_map {
103 char *name;
104 key_dir dir;
William Robertsf0e0a942012-08-27 15:41:15 -0700105 char *data;
William Roberts81e1f902015-06-03 21:57:47 -0700106 key_map_regex regex;
William Roberts696a66b2016-01-29 10:41:50 -0800107 bool (*fn_validate)(char *value, char **errmsg);
William Robertsf0e0a942012-08-27 15:41:15 -0700108};
109
110/**
111 * Key value pair struct, this represents the raw kvp values coming
112 * from the rules files.
113 */
114struct kvp {
115 char *key;
116 char *value;
117};
118
119/**
120 * Rules are made up of meta data and an associated set of kvp stored in a
121 * key_map array.
122 */
123struct rule_map {
William Roberts81e1f902015-06-03 21:57:47 -0700124 bool is_never_allow;
125 list violations;
126 list_element listify;
William Robertsf0e0a942012-08-27 15:41:15 -0700127 char *key; /** key value before hashing */
William Roberts610a4b12013-10-15 18:26:00 -0700128 size_t length; /** length of the key map */
William Robertsf0e0a942012-08-27 15:41:15 -0700129 int lineno; /** Line number rule was encounter on */
William Roberts81e1f902015-06-03 21:57:47 -0700130 char *filename; /** File it was found in */
William Robertsf0e0a942012-08-27 15:41:15 -0700131 key_map m[]; /** key value mapping */
132};
133
134struct hash_entry {
William Roberts81e1f902015-06-03 21:57:47 -0700135 list_element listify;
William Robertsf0e0a942012-08-27 15:41:15 -0700136 rule_map *r; /** The rule map to store at that location */
137};
138
139/**
140 * Data associated for a policy file
141 */
142struct policy_info {
143
144 char *policy_file_name; /** policy file path name */
145 FILE *policy_file; /** file handle to the policy file */
146 sepol_policydb_t *db;
147 sepol_policy_file_t *pf;
148 sepol_handle_t *handle;
149 sepol_context_t *con;
150};
151
William Roberts81e1f902015-06-03 21:57:47 -0700152struct file_info {
153 FILE *file; /** file itself */
154 const char *name; /** name of file. do not free, these are not alloc'd */
155 list_element listify;
156};
157
158static void input_file_list_freefn(list_element *e);
159static void line_order_list_freefn(list_element *e);
160static void rule_map_free(rule_map *rm, bool is_in_htable);
161
William Robertsf0e0a942012-08-27 15:41:15 -0700162/** Set to !0 to enable verbose logging */
163static int logging_verbose = 0;
164
165/** file handle to the output file */
William Roberts81e1f902015-06-03 21:57:47 -0700166static file_info out_file;
William Robertsf0e0a942012-08-27 15:41:15 -0700167
William Roberts81e1f902015-06-03 21:57:47 -0700168static list input_file_list = list_init(input_file_list_freefn);
William Robertsf0e0a942012-08-27 15:41:15 -0700169
170static policy_info pol = {
171 .policy_file_name = NULL,
172 .policy_file = NULL,
173 .db = NULL,
174 .pf = NULL,
175 .handle = NULL,
176 .con = NULL
177};
178
179/**
William Roberts81e1f902015-06-03 21:57:47 -0700180 * Head pointer to a linked list of
181 * rule map table entries (hash_entry), used for
182 * preserving the order of entries
183 * based on "first encounter"
184 */
185static list line_order_list = list_init(line_order_list_freefn);
186
187/*
188 * List of hash_entrys for never allow rules.
189 */
190static list nallow_list = list_init(line_order_list_freefn);
191
William Roberts696a66b2016-01-29 10:41:50 -0800192/* validation call backs */
193static bool validate_bool(char *value, char **errmsg);
194static bool validate_levelFrom(char *value, char **errmsg);
195static bool validate_selinux_type(char *value, char **errmsg);
196static bool validate_selinux_level(char *value, char **errmsg);
197
William Roberts81e1f902015-06-03 21:57:47 -0700198/**
William Robertsf0e0a942012-08-27 15:41:15 -0700199 * The heart of the mapping process, this must be updated if a new key value pair is added
200 * to a rule.
201 */
202key_map rules[] = {
203 /*Inputs*/
William Robertsc92dae92016-01-29 11:03:40 -0800204 { .name = "isSystemServer", .dir = dir_in, .data = NULL, .fn_validate = validate_bool },
205 { .name = "isOwner", .dir = dir_in, .data = NULL, .fn_validate = validate_bool },
206 { .name = "user", .dir = dir_in, .data = NULL },
207 { .name = "seinfo", .dir = dir_in, .data = NULL },
208 { .name = "name", .dir = dir_in, .data = NULL },
209 { .name = "path", .dir = dir_in, .data = NULL },
210 { .name = "isPrivApp", .dir = dir_in, .data = NULL, .fn_validate = validate_bool },
William Robertsf0e0a942012-08-27 15:41:15 -0700211 /*Outputs*/
William Robertsc92dae92016-01-29 11:03:40 -0800212 { .name = "domain", .dir = dir_out, .data = NULL, .fn_validate = validate_selinux_type },
213 { .name = "type", .dir = dir_out, .data = NULL, .fn_validate = validate_selinux_type },
214 { .name = "levelFromUid", .dir = dir_out, .data = NULL, .fn_validate = validate_bool },
215 { .name = "levelFrom", .dir = dir_out, .data = NULL, .fn_validate = validate_levelFrom },
216 { .name = "level", .dir = dir_out, .data = NULL, .fn_validate = validate_selinux_level },
William Robertsfff29802012-11-27 14:20:34 -0800217};
William Robertsf0e0a942012-08-27 15:41:15 -0700218
219/**
William Roberts81e1f902015-06-03 21:57:47 -0700220 * Appends to the end of the list.
221 * @list The list to append to
222 * @e the element to append
William Robertsf0e0a942012-08-27 15:41:15 -0700223 */
William Roberts81e1f902015-06-03 21:57:47 -0700224void list_append(list *list, list_element *e) {
225
226 memset(e, 0, sizeof(*e));
227
228 if (list->head == NULL ) {
229 list->head = list->tail = e;
230 return;
231 }
232
233 list->tail->next = e;
234 list->tail = e;
235 return;
236}
William Robertsf0e0a942012-08-27 15:41:15 -0700237
238/**
William Roberts81e1f902015-06-03 21:57:47 -0700239 * Free's all the elements in the specified list.
240 * @list The list to free
William Robertsf0e0a942012-08-27 15:41:15 -0700241 */
William Roberts81e1f902015-06-03 21:57:47 -0700242static void list_free(list *list) {
243
244 list_element *tmp;
245 list_element *cursor = list->head;
246
247 while (cursor) {
248 tmp = cursor;
249 cursor = cursor->next;
250 if (list->freefn) {
251 list->freefn(tmp);
252 }
253 }
254}
255
256/*
257 * called when the lists are freed
258 */
259static void line_order_list_freefn(list_element *e) {
260 hash_entry *h = list_entry(e, typeof(*h), listify);
261 rule_map_free(h->r, true);
262 free(h);
263}
264
265static void input_file_list_freefn(list_element *e) {
266 file_info *f = list_entry(e, typeof(*f), listify);
267
268 if (f->file) {
269 fclose(f->file);
270 }
271 free(f);
272}
William Robertsf0e0a942012-08-27 15:41:15 -0700273
274/**
275 * Send a logging message to a file
276 * @param out
277 * Output file to send message too
278 * @param prefix
279 * A special prefix to write to the file, such as "Error:"
280 * @param fmt
281 * The printf style formatter to use, such as "%d"
282 */
William Roberts1e8c0612013-04-19 19:06:02 -0700283static void __attribute__ ((format(printf, 3, 4)))
284log_msg(FILE *out, const char *prefix, const char *fmt, ...) {
285
William Robertsf0e0a942012-08-27 15:41:15 -0700286 fprintf(out, "%s", prefix);
287 va_list args;
288 va_start(args, fmt);
289 vfprintf(out, fmt, args);
290 va_end(args);
291}
292
293/**
294 * Checks for a type in the policy.
295 * @param db
296 * The policy db to search
297 * @param type
298 * The type to search for
299 * @return
300 * 1 if the type is found, 0 otherwise.
301 * @warning
302 * This function always returns 1 if libsepol is not linked
303 * statically to this executable and LINK_SEPOL_STATIC is not
304 * defined.
305 */
William Roberts25528cf2016-01-29 10:32:34 -0800306static int check_type(sepol_policydb_t *db, char *type) {
William Robertsf0e0a942012-08-27 15:41:15 -0700307
308 int rc = 1;
309#if defined(LINK_SEPOL_STATIC)
310 policydb_t *d = (policydb_t *)db;
311 hashtab_datum_t dat;
312 dat = hashtab_search(d->p_types.table, type);
313 rc = (dat == NULL) ? 0 : 1;
314#endif
315 return rc;
316}
317
William Roberts81e1f902015-06-03 21:57:47 -0700318static bool match_regex(key_map *assert, const key_map *check) {
319
320 char *tomatch = check->data;
321
322 int ret = pcre_exec(assert->regex.compiled, assert->regex.extra, tomatch,
323 strlen(tomatch), 0, 0, NULL, 0);
324
325 /* 0 from pcre_exec means matched */
326 return !ret;
327}
328
329static bool compile_regex(key_map *km, const char **errbuf, int *erroff) {
330
331 size_t size;
332 char *anchored;
333
334 /*
335 * Explicitly anchor all regex's
336 * The size is the length of the string to anchor (km->data), the anchor
337 * characters ^ and $ and the null byte. Hence strlen(km->data) + 3
338 */
339 size = strlen(km->data) + 3;
340 anchored = alloca(size);
341 sprintf(anchored, "^%s$", km->data);
342
343 km->regex.compiled = pcre_compile(anchored, PCRE_DOTALL, errbuf, erroff,
344 NULL );
345 if (!km->regex.compiled) {
346 return false;
347 }
348
349 km->regex.extra = pcre_study(km->regex.compiled, 0, errbuf);
350 return true;
351}
352
William Roberts696a66b2016-01-29 10:41:50 -0800353static bool validate_bool(char *value, char **errmsg) {
354
355 if (!strcmp("true", value) || !strcmp("false", value)) {
356 return true;
357 }
358
359 *errmsg = "Expecting \"true\" or \"false\"";
360 return false;
361}
362
363static bool validate_levelFrom(char *value, char **errmsg) {
364
365 if(strcasecmp(value, "none") && strcasecmp(value, "all") &&
366 strcasecmp(value, "app") && strcasecmp(value, "user")) {
367 *errmsg = "Expecting one of: \"none\", \"all\", \"app\" or \"user\"";
368 return false;
369 }
370 return true;
371}
372
373static bool validate_selinux_type(char *value, char **errmsg) {
374
375 /*
376 * No policy file present means we cannot check
377 * SE Linux types
378 */
379 if (!pol.policy_file) {
380 return true;
381 }
382
383 if(!check_type(pol.db, value)) {
384 *errmsg = "Expecting a valid SELinux type";
385 return false;
386 }
387
388 return true;
389}
390
391static bool validate_selinux_level(char *value, char **errmsg) {
392
393 /*
394 * No policy file present means we cannot check
395 * SE Linux MLS
396 */
397 if (!pol.policy_file) {
398 return true;
399 }
400
401 int ret = sepol_mls_check(pol.handle, pol.db, value);
402 if (ret < 0) {
403 *errmsg = "Expecting a valid SELinux MLS value";
404 return false;
405 }
406
407 return true;
408}
409
William Robertsf0e0a942012-08-27 15:41:15 -0700410/**
411 * Validates a key_map against a set of enforcement rules, this
412 * function exits the application on a type that cannot be properly
413 * checked
414 *
415 * @param m
416 * The key map to check
417 * @param lineno
418 * The line number in the source file for the corresponding key map
William Robertsfff29802012-11-27 14:20:34 -0800419 * @return
William Roberts81e1f902015-06-03 21:57:47 -0700420 * true if valid, false if invalid
William Robertsf0e0a942012-08-27 15:41:15 -0700421 */
William Roberts81e1f902015-06-03 21:57:47 -0700422static bool key_map_validate(key_map *m, const char *filename, int lineno,
423 bool is_neverallow) {
William Robertsf0e0a942012-08-27 15:41:15 -0700424
William Roberts81e1f902015-06-03 21:57:47 -0700425 int erroff;
426 const char *errbuf;
427 bool rc = true;
William Robertsf0e0a942012-08-27 15:41:15 -0700428 char *key = m->name;
429 char *value = m->data;
William Roberts696a66b2016-01-29 10:41:50 -0800430 char *errmsg = NULL;
William Robertsf0e0a942012-08-27 15:41:15 -0700431
William Roberts0ae3a8a2012-09-04 11:51:04 -0700432 log_info("Validating %s=%s\n", key, value);
433
William Roberts81e1f902015-06-03 21:57:47 -0700434 /*
435 * Neverallows are completely skipped from sanity checking so you can match
436 * un-unspecified inputs.
437 */
438 if (is_neverallow) {
439 if (!m->regex.compiled) {
440 rc = compile_regex(m, &errbuf, &erroff);
441 if (!rc) {
442 log_error("Invalid regex on line %d : %s PCRE error: %s at offset %d",
443 lineno, value, errbuf, erroff);
444 }
445 }
446 goto out;
447 }
448
William Roberts696a66b2016-01-29 10:41:50 -0800449 /* If the key has a validation routine, call it */
450 if (m->fn_validate) {
451 rc = m->fn_validate(value, &errmsg);
William Robertsf0e0a942012-08-27 15:41:15 -0700452
William Roberts696a66b2016-01-29 10:41:50 -0800453 if (!rc) {
454 log_error("Could not validate key \"%s\" for value \"%s\" on line: %d in file: \"%s\": %s\n", key, value,
455 lineno, filename, errmsg);
William Robertsf0e0a942012-08-27 15:41:15 -0700456 }
457 }
458
William Roberts0ae3a8a2012-09-04 11:51:04 -0700459out:
460 log_info("Key map validate returning: %d\n", rc);
461 return rc;
William Robertsf0e0a942012-08-27 15:41:15 -0700462}
463
464/**
465 * Prints a rule map back to a file
466 * @param fp
467 * The file handle to print too
468 * @param r
469 * The rule map to print
470 */
471static void rule_map_print(FILE *fp, rule_map *r) {
472
William Roberts610a4b12013-10-15 18:26:00 -0700473 size_t i;
William Robertsf0e0a942012-08-27 15:41:15 -0700474 key_map *m;
475
476 for (i = 0; i < r->length; i++) {
477 m = &(r->m[i]);
478 if (i < r->length - 1)
479 fprintf(fp, "%s=%s ", m->name, m->data);
480 else
481 fprintf(fp, "%s=%s", m->name, m->data);
482 }
483}
484
485/**
486 * Compare two rule maps for equality
487 * @param rmA
488 * a rule map to check
489 * @param rmB
490 * a rule map to check
491 * @return
William Robertsae23a1f2012-09-05 12:53:52 -0700492 * a map_match enum indicating the result
William Robertsf0e0a942012-08-27 15:41:15 -0700493 */
William Roberts0ae3a8a2012-09-04 11:51:04 -0700494static map_match rule_map_cmp(rule_map *rmA, rule_map *rmB) {
William Robertsf0e0a942012-08-27 15:41:15 -0700495
William Roberts610a4b12013-10-15 18:26:00 -0700496 size_t i;
497 size_t j;
William Robertsf0e0a942012-08-27 15:41:15 -0700498 int inputs_found = 0;
499 int num_of_matched_inputs = 0;
500 int input_mode = 0;
William Roberts610a4b12013-10-15 18:26:00 -0700501 size_t matches = 0;
William Robertsf0e0a942012-08-27 15:41:15 -0700502 key_map *mA;
503 key_map *mB;
504
William Robertsf0e0a942012-08-27 15:41:15 -0700505 for (i = 0; i < rmA->length; i++) {
506 mA = &(rmA->m[i]);
507
508 for (j = 0; j < rmB->length; j++) {
509 mB = &(rmB->m[j]);
510 input_mode = 0;
511
William Robertsf0e0a942012-08-27 15:41:15 -0700512 if (strcmp(mA->name, mB->name))
513 continue;
514
515 if (strcmp(mA->data, mB->data))
516 continue;
517
518 if (mB->dir != mA->dir)
519 continue;
520 else if (mB->dir == dir_in) {
521 input_mode = 1;
522 inputs_found++;
523 }
524
William Roberts0ae3a8a2012-09-04 11:51:04 -0700525 if (input_mode) {
William Roberts1e8c0612013-04-19 19:06:02 -0700526 log_info("Matched input lines: name=%s data=%s\n", mA->name, mA->data);
William Robertsf0e0a942012-08-27 15:41:15 -0700527 num_of_matched_inputs++;
William Roberts0ae3a8a2012-09-04 11:51:04 -0700528 }
William Robertsf0e0a942012-08-27 15:41:15 -0700529
530 /* Match found, move on */
William Roberts1e8c0612013-04-19 19:06:02 -0700531 log_info("Matched lines: name=%s data=%s", mA->name, mA->data);
William Robertsf0e0a942012-08-27 15:41:15 -0700532 matches++;
533 break;
534 }
535 }
536
537 /* If they all matched*/
William Roberts0ae3a8a2012-09-04 11:51:04 -0700538 if (matches == rmA->length) {
539 log_info("Rule map cmp MATCH\n");
540 return map_matched;
541 }
William Robertsf0e0a942012-08-27 15:41:15 -0700542
543 /* They didn't all match but the input's did */
William Roberts0ae3a8a2012-09-04 11:51:04 -0700544 else if (num_of_matched_inputs == inputs_found) {
545 log_info("Rule map cmp INPUT MATCH\n");
546 return map_input_matched;
547 }
William Robertsf0e0a942012-08-27 15:41:15 -0700548
549 /* They didn't all match, and the inputs didn't match, ie it didn't
550 * match */
William Roberts0ae3a8a2012-09-04 11:51:04 -0700551 else {
552 log_info("Rule map cmp NO MATCH\n");
553 return map_no_matches;
554 }
William Robertsf0e0a942012-08-27 15:41:15 -0700555}
556
557/**
558 * Frees a rule map
559 * @param rm
560 * rule map to be freed.
William Roberts7d65b542015-06-19 09:43:28 -0700561 * @is_in_htable
562 * True if the rule map has been added to the hash table, false
563 * otherwise.
564 */
565static void rule_map_free(rule_map *rm, bool is_in_htable) {
William Robertsf0e0a942012-08-27 15:41:15 -0700566
William Roberts610a4b12013-10-15 18:26:00 -0700567 size_t i;
568 size_t len = rm->length;
William Robertsf0e0a942012-08-27 15:41:15 -0700569 for (i = 0; i < len; i++) {
570 key_map *m = &(rm->m[i]);
571 free(m->data);
William Roberts81e1f902015-06-03 21:57:47 -0700572
573 if (m->regex.compiled) {
574 pcre_free(m->regex.compiled);
575 }
576
577 if (m->regex.extra) {
578 pcre_free_study(m->regex.extra);
579 }
William Robertsf0e0a942012-08-27 15:41:15 -0700580 }
581
William Roberts7d65b542015-06-19 09:43:28 -0700582 /*
583 * hdestroy() frees comparsion keys for non glibc
584 * on GLIBC we always free on NON-GLIBC we free if
585 * it is not in the htable.
586 */
587 if (rm->key) {
rpcraig5dbfdc02012-10-23 11:03:47 -0400588#ifdef __GLIBC__
William Roberts7d65b542015-06-19 09:43:28 -0700589 /* silence unused warning */
590 (void)is_in_htable;
William Robertsf0e0a942012-08-27 15:41:15 -0700591 free(rm->key);
William Roberts7d65b542015-06-19 09:43:28 -0700592#else
593 if (!is_in_htable) {
594 free(rm->key);
595 }
rpcraig5dbfdc02012-10-23 11:03:47 -0400596#endif
William Roberts7d65b542015-06-19 09:43:28 -0700597 }
William Robertsf0e0a942012-08-27 15:41:15 -0700598
William Roberts81e1f902015-06-03 21:57:47 -0700599 free(rm->filename);
William Robertsf0e0a942012-08-27 15:41:15 -0700600 free(rm);
601}
602
603static void free_kvp(kvp *k) {
604 free(k->key);
605 free(k->value);
606}
607
608/**
William Roberts61846292013-10-15 09:38:24 -0700609 * Checks a rule_map for any variation of KVP's that shouldn't be allowed.
William Roberts81e1f902015-06-03 21:57:47 -0700610 * It builds an assertion failure list for each rule map.
William Roberts61846292013-10-15 09:38:24 -0700611 * Note that this function logs all errors.
612 *
613 * Current Checks:
614 * 1. That a specified name entry should have a specified seinfo entry as well.
William Roberts81e1f902015-06-03 21:57:47 -0700615 * 2. That no rule violates a neverallow
William Roberts61846292013-10-15 09:38:24 -0700616 * @param rm
617 * The rule map to check for validity.
William Roberts61846292013-10-15 09:38:24 -0700618 */
William Roberts81e1f902015-06-03 21:57:47 -0700619static void rule_map_validate(rule_map *rm) {
William Roberts61846292013-10-15 09:38:24 -0700620
William Roberts81e1f902015-06-03 21:57:47 -0700621 size_t i, j;
622 const key_map *rule;
623 key_map *nrule;
624 hash_entry *e;
625 rule_map *assert;
626 list_element *cursor;
William Roberts61846292013-10-15 09:38:24 -0700627
William Roberts81e1f902015-06-03 21:57:47 -0700628 list_for_each(&nallow_list, cursor) {
629 e = list_entry(cursor, typeof(*e), listify);
630 assert = e->r;
William Roberts61846292013-10-15 09:38:24 -0700631
William Roberts81e1f902015-06-03 21:57:47 -0700632 size_t cnt = 0;
633
634 for (j = 0; j < assert->length; j++) {
635 nrule = &(assert->m[j]);
636
637 // mark that nrule->name is for a null check
638 bool is_null_check = !strcmp(nrule->data, "\"\"");
639
640 for (i = 0; i < rm->length; i++) {
641 rule = &(rm->m[i]);
642
643 if (!strcmp(rule->name, nrule->name)) {
644
645 /* the name was found, (data cannot be false) then it was specified */
646 is_null_check = false;
647
648 if (match_regex(nrule, rule)) {
649 cnt++;
650 }
651 }
652 }
653
654 /*
655 * the nrule was marked in a null check and we never found a match on nrule, thus
656 * it matched and we update the cnt
657 */
658 if (is_null_check) {
659 cnt++;
660 }
William Roberts61846292013-10-15 09:38:24 -0700661 }
William Roberts81e1f902015-06-03 21:57:47 -0700662 if (cnt == assert->length) {
663 list_append(&rm->violations, &assert->listify);
William Roberts61846292013-10-15 09:38:24 -0700664 }
665 }
William Roberts61846292013-10-15 09:38:24 -0700666}
667
668/**
William Robertsf0e0a942012-08-27 15:41:15 -0700669 * Given a set of key value pairs, this will construct a new rule map.
670 * On error this function calls exit.
671 * @param keys
672 * Keys from a rule line to map
673 * @param num_of_keys
674 * The length of the keys array
675 * @param lineno
676 * The line number the keys were extracted from
677 * @return
678 * A rule map pointer.
679 */
William Roberts81e1f902015-06-03 21:57:47 -0700680static rule_map *rule_map_new(kvp keys[], size_t num_of_keys, int lineno,
681 const char *filename, bool is_never_allow) {
William Robertsf0e0a942012-08-27 15:41:15 -0700682
William Roberts610a4b12013-10-15 18:26:00 -0700683 size_t i = 0, j = 0;
William Robertsf0e0a942012-08-27 15:41:15 -0700684 rule_map *new_map = NULL;
685 kvp *k = NULL;
686 key_map *r = NULL, *x = NULL;
Stephen Smalley534fb072015-02-13 14:06:08 -0500687 bool seen[KVP_NUM_OF_RULES];
688
689 for (i = 0; i < KVP_NUM_OF_RULES; i++)
690 seen[i] = false;
William Robertsf0e0a942012-08-27 15:41:15 -0700691
692 new_map = calloc(1, (num_of_keys * sizeof(key_map)) + sizeof(rule_map));
693 if (!new_map)
694 goto oom;
695
William Roberts81e1f902015-06-03 21:57:47 -0700696 new_map->is_never_allow = is_never_allow;
William Robertsf0e0a942012-08-27 15:41:15 -0700697 new_map->length = num_of_keys;
698 new_map->lineno = lineno;
William Roberts81e1f902015-06-03 21:57:47 -0700699 new_map->filename = strdup(filename);
700 if (!new_map->filename) {
701 goto oom;
702 }
William Robertsf0e0a942012-08-27 15:41:15 -0700703
704 /* For all the keys in a rule line*/
705 for (i = 0; i < num_of_keys; i++) {
706 k = &(keys[i]);
707 r = &(new_map->m[i]);
708
709 for (j = 0; j < KVP_NUM_OF_RULES; j++) {
710 x = &(rules[j]);
711
712 /* Only assign key name to map name */
713 if (strcasecmp(k->key, x->name)) {
714 if (i == KVP_NUM_OF_RULES) {
715 log_error("No match for key: %s\n", k->key);
716 goto err;
717 }
718 continue;
719 }
720
Stephen Smalley534fb072015-02-13 14:06:08 -0500721 if (seen[j]) {
722 log_error("Duplicated key: %s\n", k->key);
723 goto err;
724 }
725 seen[j] = true;
726
William Robertsf0e0a942012-08-27 15:41:15 -0700727 memcpy(r, x, sizeof(key_map));
728
729 /* Assign rule map value to one from file */
730 r->data = strdup(k->value);
731 if (!r->data)
732 goto oom;
733
734 /* Enforce type check*/
William Roberts0ae3a8a2012-09-04 11:51:04 -0700735 log_info("Validating keys!\n");
William Roberts81e1f902015-06-03 21:57:47 -0700736 if (!key_map_validate(r, filename, lineno, new_map->is_never_allow)) {
William Robertsf0e0a942012-08-27 15:41:15 -0700737 log_error("Could not validate\n");
738 goto err;
739 }
740
William Roberts81e1f902015-06-03 21:57:47 -0700741 /*
742 * Only build key off of inputs with the exception of neverallows.
743 * Neverallows are keyed off of all key value pairs,
744 */
745 if (r->dir == dir_in || new_map->is_never_allow) {
William Robertsf0e0a942012-08-27 15:41:15 -0700746 char *tmp;
William Robertsb3ab56c2012-09-17 14:35:02 -0700747 int key_len = strlen(k->key);
748 int val_len = strlen(k->value);
749 int l = (new_map->key) ? strlen(new_map->key) : 0;
750 l = l + key_len + val_len;
William Robertsf0e0a942012-08-27 15:41:15 -0700751 l += 1;
752
753 tmp = realloc(new_map->key, l);
754 if (!tmp)
755 goto oom;
756
William Robertsb3ab56c2012-09-17 14:35:02 -0700757 if (!new_map->key)
758 memset(tmp, 0, l);
759
William Robertsf0e0a942012-08-27 15:41:15 -0700760 new_map->key = tmp;
761
William Robertsb3ab56c2012-09-17 14:35:02 -0700762 strncat(new_map->key, k->key, key_len);
763 strncat(new_map->key, k->value, val_len);
William Robertsf0e0a942012-08-27 15:41:15 -0700764 }
765 break;
766 }
767 free_kvp(k);
768 }
769
770 if (new_map->key == NULL) {
771 log_error("Strange, no keys found, input file corrupt perhaps?\n");
772 goto err;
773 }
774
775 return new_map;
776
777oom:
778 log_error("Out of memory!\n");
779err:
780 if(new_map) {
William Roberts7d65b542015-06-19 09:43:28 -0700781 rule_map_free(new_map, false);
William Robertsf0e0a942012-08-27 15:41:15 -0700782 for (; i < num_of_keys; i++) {
783 k = &(keys[i]);
784 free_kvp(k);
785 }
786 }
Stephen Smalley534fb072015-02-13 14:06:08 -0500787 return NULL;
William Robertsf0e0a942012-08-27 15:41:15 -0700788}
789
790/**
791 * Print the usage of the program
792 */
793static void usage() {
794 printf(
795 "checkseapp [options] <input file>\n"
796 "Processes an seapp_contexts file specified by argument <input file> (default stdin) "
William Robertsae23a1f2012-09-05 12:53:52 -0700797 "and allows later declarations to override previous ones on a match.\n"
William Robertsf0e0a942012-08-27 15:41:15 -0700798 "Options:\n"
799 "-h - print this help message\n"
800 "-v - enable verbose debugging informations\n"
William Roberts63297212013-04-19 19:06:23 -0700801 "-p policy file - specify policy file for strict checking of output selectors against the policy\n"
William Roberts81e1f902015-06-03 21:57:47 -0700802 "-o output file - specify output file or - for stdout. No argument runs in silent mode and outputs nothing\n");
William Robertsf0e0a942012-08-27 15:41:15 -0700803}
804
805static void init() {
806
William Roberts81e1f902015-06-03 21:57:47 -0700807 bool has_out_file;
808 list_element *cursor;
809 file_info *tmp;
810
811 /* input files if the list is empty, use stdin */
812 if (!input_file_list.head) {
813 log_info("Using stdin for input\n");
814 tmp = malloc(sizeof(*tmp));
815 if (!tmp) {
816 log_error("oom");
William Robertsf0e0a942012-08-27 15:41:15 -0700817 exit(EXIT_FAILURE);
818 }
William Roberts81e1f902015-06-03 21:57:47 -0700819 tmp->name = "stdin";
820 tmp->file = stdin;
821 list_append(&input_file_list, &(tmp->listify));
822 }
823 else {
824 list_for_each(&input_file_list, cursor) {
825 tmp = list_entry(cursor, typeof(*tmp), listify);
826
827 log_info("Opening input file: \"%s\"\n", tmp->name);
828 tmp->file = fopen(tmp->name, "r");
829 if (!tmp->file) {
830 log_error("Could not open file: %s error: %s\n", tmp->name,
831 strerror(errno));
832 exit(EXIT_FAILURE);
833 }
834 }
William Robertsf0e0a942012-08-27 15:41:15 -0700835 }
836
William Roberts81e1f902015-06-03 21:57:47 -0700837 has_out_file = out_file.name != NULL;
838
839 /* If output file is -, then use stdout, else open the path */
840 if (has_out_file && !strcmp(out_file.name, "-")) {
841 out_file.file = stdout;
842 out_file.name = "stdout";
843 }
844 else if (has_out_file) {
845 out_file.file = fopen(out_file.name, "w+");
846 }
847
848 if (has_out_file && !out_file.file) {
849 log_error("Could not open file: \"%s\" error: \"%s\"\n", out_file.name,
850 strerror(errno));
851 exit(EXIT_FAILURE);
William Robertsf0e0a942012-08-27 15:41:15 -0700852 }
853
854 if (pol.policy_file_name) {
William Robertsf0e0a942012-08-27 15:41:15 -0700855 log_info("Opening policy file: %s\n", pol.policy_file_name);
856 pol.policy_file = fopen(pol.policy_file_name, "rb");
857 if (!pol.policy_file) {
858 log_error("Could not open file: %s error: %s\n",
859 pol.policy_file_name, strerror(errno));
860 exit(EXIT_FAILURE);
861 }
862
863 pol.handle = sepol_handle_create();
864 if (!pol.handle) {
865 log_error("Could not create sepolicy handle: %s\n",
866 strerror(errno));
867 exit(EXIT_FAILURE);
868 }
869
870 if (sepol_policy_file_create(&pol.pf) < 0) {
871 log_error("Could not create sepolicy file: %s!\n",
872 strerror(errno));
873 exit(EXIT_FAILURE);
874 }
875
876 sepol_policy_file_set_fp(pol.pf, pol.policy_file);
877 sepol_policy_file_set_handle(pol.pf, pol.handle);
878
879 if (sepol_policydb_create(&pol.db) < 0) {
880 log_error("Could not create sepolicy db: %s!\n",
881 strerror(errno));
882 exit(EXIT_FAILURE);
883 }
884
885 if (sepol_policydb_read(pol.db, pol.pf) < 0) {
886 log_error("Could not lod policy file to db: %s!\n",
887 strerror(errno));
888 exit(EXIT_FAILURE);
889 }
890 }
891
William Roberts81e1f902015-06-03 21:57:47 -0700892 list_for_each(&input_file_list, cursor) {
893 tmp = list_entry(cursor, typeof(*tmp), listify);
894 log_info("Input file set to: \"%s\"\n", tmp->name);
895 }
896
897 log_info("Policy file set to: \"%s\"\n",
898 (pol.policy_file_name == NULL) ? "None" : pol.policy_file_name);
899 log_info("Output file set to: \"%s\"\n", out_file.name);
William Robertsf0e0a942012-08-27 15:41:15 -0700900
William Roberts0ae3a8a2012-09-04 11:51:04 -0700901#if !defined(LINK_SEPOL_STATIC)
William Robertsa53ccf32012-09-17 12:53:44 -0700902 log_warn("LINK_SEPOL_STATIC is not defined\n""Not checking types!");
William Roberts0ae3a8a2012-09-04 11:51:04 -0700903#endif
904
William Robertsf0e0a942012-08-27 15:41:15 -0700905}
906
907/**
908 * Handle parsing and setting the global flags for the command line
909 * options. This function calls exit on failure.
910 * @param argc
911 * argument count
912 * @param argv
913 * argument list
914 */
915static void handle_options(int argc, char *argv[]) {
916
917 int c;
William Roberts81e1f902015-06-03 21:57:47 -0700918 file_info *input_file;
William Robertsf0e0a942012-08-27 15:41:15 -0700919
William Robertsf26b6d42015-06-23 10:22:45 -0700920 while ((c = getopt(argc, argv, "ho:p:v")) != -1) {
William Robertsf0e0a942012-08-27 15:41:15 -0700921 switch (c) {
922 case 'h':
923 usage();
924 exit(EXIT_SUCCESS);
925 case 'o':
William Roberts81e1f902015-06-03 21:57:47 -0700926 out_file.name = optarg;
William Robertsf0e0a942012-08-27 15:41:15 -0700927 break;
928 case 'p':
929 pol.policy_file_name = optarg;
930 break;
931 case 'v':
932 log_set_verbose();
933 break;
934 case '?':
935 if (optopt == 'o' || optopt == 'p')
936 log_error("Option -%c requires an argument.\n", optopt);
937 else if (isprint (optopt))
938 log_error("Unknown option `-%c'.\n", optopt);
939 else {
940 log_error(
941 "Unknown option character `\\x%x'.\n",
942 optopt);
William Robertsf0e0a942012-08-27 15:41:15 -0700943 }
William Robertsf0e0a942012-08-27 15:41:15 -0700944 default:
945 exit(EXIT_FAILURE);
946 }
947 }
948
William Roberts81e1f902015-06-03 21:57:47 -0700949 for (c = optind; c < argc; c++) {
William Robertsf0e0a942012-08-27 15:41:15 -0700950
William Roberts81e1f902015-06-03 21:57:47 -0700951 input_file = calloc(1, sizeof(*input_file));
952 if (!input_file) {
953 log_error("oom");
954 exit(EXIT_FAILURE);
955 }
956 input_file->name = argv[c];
957 list_append(&input_file_list, &input_file->listify);
William Robertsf0e0a942012-08-27 15:41:15 -0700958 }
959}
960
961/**
962 * Adds a rule to the hash table and to the ordered list if needed.
963 * @param rm
964 * The rule map to add.
965 */
966static void rule_add(rule_map *rm) {
967
William Roberts0ae3a8a2012-09-04 11:51:04 -0700968 map_match cmp;
William Robertsf0e0a942012-08-27 15:41:15 -0700969 ENTRY e;
970 ENTRY *f;
971 hash_entry *entry;
972 hash_entry *tmp;
William Roberts81e1f902015-06-03 21:57:47 -0700973 list *list_to_addto;
William Robertsf0e0a942012-08-27 15:41:15 -0700974
975 e.key = rm->key;
976
William Roberts0ae3a8a2012-09-04 11:51:04 -0700977 log_info("Searching for key: %s\n", e.key);
William Robertsf0e0a942012-08-27 15:41:15 -0700978 /* Check to see if it has already been added*/
979 f = hsearch(e, FIND);
980
981 /*
982 * Since your only hashing on a partial key, the inputs we need to handle
983 * when you want to override the outputs for a given input set, as well as
984 * checking for duplicate entries.
985 */
986 if(f) {
William Roberts0ae3a8a2012-09-04 11:51:04 -0700987 log_info("Existing entry found!\n");
William Robertsf0e0a942012-08-27 15:41:15 -0700988 tmp = (hash_entry *)f->data;
989 cmp = rule_map_cmp(rm, tmp->r);
Stephen Smalley0b820042015-02-13 14:58:31 -0500990 log_error("Duplicate line detected in file: %s\n"
991 "Lines %d and %d %s!\n",
William Roberts81e1f902015-06-03 21:57:47 -0700992 rm->filename, tmp->r->lineno, rm->lineno,
Stephen Smalley0b820042015-02-13 14:58:31 -0500993 map_match_str[cmp]);
William Roberts7d65b542015-06-19 09:43:28 -0700994 rule_map_free(rm, false);
Stephen Smalley0b820042015-02-13 14:58:31 -0500995 goto err;
William Robertsf0e0a942012-08-27 15:41:15 -0700996 }
997 /* It wasn't found, just add the rule map to the table */
998 else {
999
1000 entry = malloc(sizeof(hash_entry));
1001 if (!entry)
1002 goto oom;
1003
1004 entry->r = rm;
1005 e.data = entry;
1006
1007 f = hsearch(e, ENTER);
1008 if(f == NULL) {
1009 goto oom;
1010 }
1011
1012 /* new entries must be added to the ordered list */
1013 entry->r = rm;
William Roberts81e1f902015-06-03 21:57:47 -07001014 list_to_addto = rm->is_never_allow ? &nallow_list : &line_order_list;
1015 list_append(list_to_addto, &entry->listify);
William Robertsf0e0a942012-08-27 15:41:15 -07001016 }
1017
1018 return;
1019oom:
1020 if (e.key)
1021 free(e.key);
1022 if (entry)
1023 free(entry);
1024 if (rm)
1025 free(rm);
1026 log_error("Out of memory in function: %s\n", __FUNCTION__);
1027err:
1028 exit(EXIT_FAILURE);
1029}
1030
William Roberts81e1f902015-06-03 21:57:47 -07001031static void parse_file(file_info *in_file) {
William Robertsf0e0a942012-08-27 15:41:15 -07001032
William Roberts81e1f902015-06-03 21:57:47 -07001033 char *p;
William Robertsf0e0a942012-08-27 15:41:15 -07001034 size_t len;
William Roberts81e1f902015-06-03 21:57:47 -07001035 char *token;
1036 char *saveptr;
1037 bool is_never_allow;
1038 bool found_whitespace;
1039
1040 size_t lineno = 0;
1041 char *name = NULL;
1042 char *value = NULL;
William Roberts610a4b12013-10-15 18:26:00 -07001043 size_t token_cnt = 0;
William Robertsf0e0a942012-08-27 15:41:15 -07001044
William Roberts81e1f902015-06-03 21:57:47 -07001045 char line_buf[BUFSIZ];
1046 kvp keys[KVP_NUM_OF_RULES];
William Robertsf0e0a942012-08-27 15:41:15 -07001047
William Roberts81e1f902015-06-03 21:57:47 -07001048 while (fgets(line_buf, sizeof(line_buf) - 1, in_file->file)) {
William Robertsf0e0a942012-08-27 15:41:15 -07001049 lineno++;
William Roberts81e1f902015-06-03 21:57:47 -07001050 is_never_allow = false;
1051 found_whitespace = false;
1052 log_info("Got line %zu\n", lineno);
William Robertsf0e0a942012-08-27 15:41:15 -07001053 len = strlen(line_buf);
1054 if (line_buf[len - 1] == '\n')
Alice Chuf6647eb2012-10-30 16:27:00 -07001055 line_buf[len - 1] = '\0';
William Robertsf0e0a942012-08-27 15:41:15 -07001056 p = line_buf;
William Roberts81e1f902015-06-03 21:57:47 -07001057
1058 /* neverallow lines must start with neverallow (ie ^neverallow) */
1059 if (!strncasecmp(p, "neverallow", strlen("neverallow"))) {
1060 p += strlen("neverallow");
1061 is_never_allow = true;
1062 }
1063
1064 /* strip trailing whitespace skip comments */
1065 while (isspace(*p)) {
William Robertsf0e0a942012-08-27 15:41:15 -07001066 p++;
William Roberts81e1f902015-06-03 21:57:47 -07001067 found_whitespace = true;
1068 }
Alice Chuf6647eb2012-10-30 16:27:00 -07001069 if (*p == '#' || *p == '\0')
William Robertsf0e0a942012-08-27 15:41:15 -07001070 continue;
1071
1072 token = strtok_r(p, " \t", &saveptr);
1073 if (!token)
1074 goto err;
1075
1076 token_cnt = 0;
1077 memset(keys, 0, sizeof(kvp) * KVP_NUM_OF_RULES);
1078 while (1) {
William Roberts0ae3a8a2012-09-04 11:51:04 -07001079
William Robertsf0e0a942012-08-27 15:41:15 -07001080 name = token;
1081 value = strchr(name, '=');
1082 if (!value)
1083 goto err;
1084 *value++ = 0;
1085
1086 keys[token_cnt].key = strdup(name);
1087 if (!keys[token_cnt].key)
1088 goto oom;
1089
1090 keys[token_cnt].value = strdup(value);
1091 if (!keys[token_cnt].value)
1092 goto oom;
1093
1094 token_cnt++;
1095
1096 token = strtok_r(NULL, " \t", &saveptr);
1097 if (!token)
1098 break;
1099
1100 } /*End token parsing */
1101
William Roberts81e1f902015-06-03 21:57:47 -07001102 rule_map *r = rule_map_new(keys, token_cnt, lineno, in_file->name, is_never_allow);
Stephen Smalley534fb072015-02-13 14:06:08 -05001103 if (!r)
1104 goto err;
William Robertsf0e0a942012-08-27 15:41:15 -07001105 rule_add(r);
1106
1107 } /* End file parsing */
1108 return;
1109
1110err:
William Robertsefebf972016-01-29 10:34:04 -08001111 log_error("Reading file: \"%s\" line: %zu name: \"%s\" value: \"%s\"\n",
William Roberts81e1f902015-06-03 21:57:47 -07001112 in_file->name, lineno, name, value);
1113 if(found_whitespace && name && !strcasecmp(name, "neverallow")) {
1114 log_error("perhaps whitespace before neverallow\n");
1115 }
William Robertsf0e0a942012-08-27 15:41:15 -07001116 exit(EXIT_FAILURE);
1117oom:
1118 log_error("In function %s: Out of memory\n", __FUNCTION__);
1119 exit(EXIT_FAILURE);
1120}
1121
1122/**
William Roberts81e1f902015-06-03 21:57:47 -07001123 * Parses the seapp_contexts file and neverallow file
1124 * and adds them to the hash table and ordered list entries
1125 * when it encounters them.
1126 * Calls exit on failure.
1127 */
1128static void parse() {
1129
1130 file_info *current;
1131 list_element *cursor;
1132 list_for_each(&input_file_list, cursor) {
1133 current = list_entry(cursor, typeof(*current), listify);
1134 parse_file(current);
1135 }
1136}
1137
1138static void validate() {
1139
1140 list_element *cursor, *v;
1141 bool found_issues = false;
1142 hash_entry *e;
1143 rule_map *r;
1144 list_for_each(&line_order_list, cursor) {
1145 e = list_entry(cursor, typeof(*e), listify);
1146 rule_map_validate(e->r);
1147 }
1148
1149 list_for_each(&line_order_list, cursor) {
1150 e = list_entry(cursor, typeof(*e), listify);
1151 r = e->r;
1152 list_for_each(&r->violations, v) {
1153 found_issues = true;
1154 log_error("Rule in File \"%s\" on line %d: \"", e->r->filename, e->r->lineno);
1155 rule_map_print(stderr, e->r);
1156 r = list_entry(v, rule_map, listify);
1157 fprintf(stderr, "\" violates neverallow in File \"%s\" on line %d: \"", r->filename, r->lineno);
1158 rule_map_print(stderr, r);
1159 fprintf(stderr, "\"\n");
1160 }
1161 }
1162
1163 if (found_issues) {
1164 exit(EXIT_FAILURE);
1165 }
1166}
1167
1168/**
William Robertsf0e0a942012-08-27 15:41:15 -07001169 * Should be called after parsing to cause the printing of the rule_maps
1170 * stored in the ordered list, head first, which preserves the "first encountered"
1171 * ordering.
1172 */
1173static void output() {
1174
William Roberts81e1f902015-06-03 21:57:47 -07001175 hash_entry *e;
1176 list_element *cursor;
William Robertsf0e0a942012-08-27 15:41:15 -07001177
William Roberts81e1f902015-06-03 21:57:47 -07001178 if (!out_file.file) {
1179 log_info("No output file, not outputting.\n");
1180 return;
1181 }
1182
1183 list_for_each(&line_order_list, cursor) {
1184 e = list_entry(cursor, hash_entry, listify);
1185 rule_map_print(out_file.file, e->r);
1186 fprintf(out_file.file, "\n");
William Robertsf0e0a942012-08-27 15:41:15 -07001187 }
1188}
1189
1190/**
1191 * This function is registered to the at exit handler and should clean up
1192 * the programs dynamic resources, such as memory and fd's.
1193 */
1194static void cleanup() {
1195
1196 /* Only close this when it was opened by me and not the crt */
William Roberts81e1f902015-06-03 21:57:47 -07001197 if (out_file.name && strcmp(out_file.name, "stdout") && out_file.file) {
1198 log_info("Closing file: %s\n", out_file.name);
1199 fclose(out_file.file);
William Robertsf0e0a942012-08-27 15:41:15 -07001200 }
1201
1202 if (pol.policy_file) {
1203
1204 log_info("Closing file: %s\n", pol.policy_file_name);
1205 fclose(pol.policy_file);
1206
1207 if (pol.db)
1208 sepol_policydb_free(pol.db);
1209
1210 if (pol.pf)
1211 sepol_policy_file_free(pol.pf);
1212
1213 if (pol.handle)
1214 sepol_handle_destroy(pol.handle);
1215 }
1216
William Roberts81e1f902015-06-03 21:57:47 -07001217 log_info("Freeing lists\n");
1218 list_free(&input_file_list);
1219 list_free(&line_order_list);
1220 list_free(&nallow_list);
William Robertsf0e0a942012-08-27 15:41:15 -07001221 hdestroy();
1222}
1223
1224int main(int argc, char *argv[]) {
1225 if (!hcreate(TABLE_SIZE)) {
1226 log_error("Could not create hash table: %s\n", strerror(errno));
1227 exit(EXIT_FAILURE);
1228 }
1229 atexit(cleanup);
1230 handle_options(argc, argv);
1231 init();
1232 log_info("Starting to parse\n");
1233 parse();
1234 log_info("Parsing completed, generating output\n");
William Roberts81e1f902015-06-03 21:57:47 -07001235 validate();
William Robertsf0e0a942012-08-27 15:41:15 -07001236 output();
1237 log_info("Success, generated output\n");
1238 exit(EXIT_SUCCESS);
1239}