blob: 84e28536a82a828c49a5275b6823021dd765d0bb [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
83/**
William Robertsf0e0a942012-08-27 15:41:15 -070084 * The expected "type" of data the value in the key
85 * value pair should be.
86 */
87enum data_type {
88 dt_bool, dt_string
89};
90
William Roberts81e1f902015-06-03 21:57:47 -070091struct list_element {
92 list_element *next;
93};
94
95struct list {
96 list_element *head;
97 list_element *tail;
98 void (*freefn)(list_element *e);
99};
100
101struct key_map_regex {
102 pcre *compiled;
103 pcre_extra *extra;
William Robertsf0e0a942012-08-27 15:41:15 -0700104};
105
106/**
107 * The workhorse of the logic. This struct maps key value pairs to
108 * an associated set of meta data maintained in rule_map_new()
109 */
110struct key_map {
111 char *name;
112 key_dir dir;
113 data_type type;
114 char *data;
William Roberts81e1f902015-06-03 21:57:47 -0700115 key_map_regex regex;
William Robertsf0e0a942012-08-27 15:41:15 -0700116};
117
118/**
119 * Key value pair struct, this represents the raw kvp values coming
120 * from the rules files.
121 */
122struct kvp {
123 char *key;
124 char *value;
125};
126
127/**
128 * Rules are made up of meta data and an associated set of kvp stored in a
129 * key_map array.
130 */
131struct rule_map {
William Roberts81e1f902015-06-03 21:57:47 -0700132 bool is_never_allow;
133 list violations;
134 list_element listify;
William Robertsf0e0a942012-08-27 15:41:15 -0700135 char *key; /** key value before hashing */
William Roberts610a4b12013-10-15 18:26:00 -0700136 size_t length; /** length of the key map */
William Robertsf0e0a942012-08-27 15:41:15 -0700137 int lineno; /** Line number rule was encounter on */
William Roberts81e1f902015-06-03 21:57:47 -0700138 char *filename; /** File it was found in */
William Robertsf0e0a942012-08-27 15:41:15 -0700139 key_map m[]; /** key value mapping */
140};
141
142struct hash_entry {
William Roberts81e1f902015-06-03 21:57:47 -0700143 list_element listify;
William Robertsf0e0a942012-08-27 15:41:15 -0700144 rule_map *r; /** The rule map to store at that location */
145};
146
147/**
148 * Data associated for a policy file
149 */
150struct policy_info {
151
152 char *policy_file_name; /** policy file path name */
153 FILE *policy_file; /** file handle to the policy file */
154 sepol_policydb_t *db;
155 sepol_policy_file_t *pf;
156 sepol_handle_t *handle;
157 sepol_context_t *con;
158};
159
William Roberts81e1f902015-06-03 21:57:47 -0700160struct file_info {
161 FILE *file; /** file itself */
162 const char *name; /** name of file. do not free, these are not alloc'd */
163 list_element listify;
164};
165
166static void input_file_list_freefn(list_element *e);
167static void line_order_list_freefn(list_element *e);
168static void rule_map_free(rule_map *rm, bool is_in_htable);
169
William Robertsf0e0a942012-08-27 15:41:15 -0700170/** Set to !0 to enable verbose logging */
171static int logging_verbose = 0;
172
173/** file handle to the output file */
William Roberts81e1f902015-06-03 21:57:47 -0700174static file_info out_file;
William Robertsf0e0a942012-08-27 15:41:15 -0700175
William Roberts81e1f902015-06-03 21:57:47 -0700176static list input_file_list = list_init(input_file_list_freefn);
William Robertsf0e0a942012-08-27 15:41:15 -0700177
178static policy_info pol = {
179 .policy_file_name = NULL,
180 .policy_file = NULL,
181 .db = NULL,
182 .pf = NULL,
183 .handle = NULL,
184 .con = NULL
185};
186
187/**
William Roberts81e1f902015-06-03 21:57:47 -0700188 * Head pointer to a linked list of
189 * rule map table entries (hash_entry), used for
190 * preserving the order of entries
191 * based on "first encounter"
192 */
193static list line_order_list = list_init(line_order_list_freefn);
194
195/*
196 * List of hash_entrys for never allow rules.
197 */
198static list nallow_list = list_init(line_order_list_freefn);
199
200/**
William Robertsf0e0a942012-08-27 15:41:15 -0700201 * The heart of the mapping process, this must be updated if a new key value pair is added
202 * to a rule.
203 */
204key_map rules[] = {
205 /*Inputs*/
206 { .name = "isSystemServer", .type = dt_bool, .dir = dir_in, .data = NULL },
Stephen Smalleyff4db912014-09-15 15:16:06 -0400207 { .name = "isOwner", .type = dt_bool, .dir = dir_in, .data = NULL },
William Robertsf0e0a942012-08-27 15:41:15 -0700208 { .name = "user", .type = dt_string, .dir = dir_in, .data = NULL },
209 { .name = "seinfo", .type = dt_string, .dir = dir_in, .data = NULL },
210 { .name = "name", .type = dt_string, .dir = dir_in, .data = NULL },
Stephen Smalley6139de52014-02-19 10:54:41 -0500211 { .name = "path", .type = dt_string, .dir = dir_in, .data = NULL },
Jeff Vander Stoepee9c0b52015-10-05 09:15:04 -0700212 { .name = "isPrivApp", .type = dt_bool, .dir = dir_in, .data = NULL },
William Robertsf0e0a942012-08-27 15:41:15 -0700213 /*Outputs*/
214 { .name = "domain", .type = dt_string, .dir = dir_out, .data = NULL },
215 { .name = "type", .type = dt_string, .dir = dir_out, .data = NULL },
216 { .name = "levelFromUid", .type = dt_bool, .dir = dir_out, .data = NULL },
Stephen Smalley38084142012-11-28 10:46:18 -0500217 { .name = "levelFrom", .type = dt_string, .dir = dir_out, .data = NULL },
William Robertsf0e0a942012-08-27 15:41:15 -0700218 { .name = "level", .type = dt_string, .dir = dir_out, .data = NULL },
William Robertsfff29802012-11-27 14:20:34 -0800219};
William Robertsf0e0a942012-08-27 15:41:15 -0700220
221/**
William Roberts81e1f902015-06-03 21:57:47 -0700222 * Appends to the end of the list.
223 * @list The list to append to
224 * @e the element to append
William Robertsf0e0a942012-08-27 15:41:15 -0700225 */
William Roberts81e1f902015-06-03 21:57:47 -0700226void list_append(list *list, list_element *e) {
227
228 memset(e, 0, sizeof(*e));
229
230 if (list->head == NULL ) {
231 list->head = list->tail = e;
232 return;
233 }
234
235 list->tail->next = e;
236 list->tail = e;
237 return;
238}
William Robertsf0e0a942012-08-27 15:41:15 -0700239
240/**
William Roberts81e1f902015-06-03 21:57:47 -0700241 * Free's all the elements in the specified list.
242 * @list The list to free
William Robertsf0e0a942012-08-27 15:41:15 -0700243 */
William Roberts81e1f902015-06-03 21:57:47 -0700244static void list_free(list *list) {
245
246 list_element *tmp;
247 list_element *cursor = list->head;
248
249 while (cursor) {
250 tmp = cursor;
251 cursor = cursor->next;
252 if (list->freefn) {
253 list->freefn(tmp);
254 }
255 }
256}
257
258/*
259 * called when the lists are freed
260 */
261static void line_order_list_freefn(list_element *e) {
262 hash_entry *h = list_entry(e, typeof(*h), listify);
263 rule_map_free(h->r, true);
264 free(h);
265}
266
267static void input_file_list_freefn(list_element *e) {
268 file_info *f = list_entry(e, typeof(*f), listify);
269
270 if (f->file) {
271 fclose(f->file);
272 }
273 free(f);
274}
William Robertsf0e0a942012-08-27 15:41:15 -0700275
276/**
277 * Send a logging message to a file
278 * @param out
279 * Output file to send message too
280 * @param prefix
281 * A special prefix to write to the file, such as "Error:"
282 * @param fmt
283 * The printf style formatter to use, such as "%d"
284 */
William Roberts1e8c0612013-04-19 19:06:02 -0700285static void __attribute__ ((format(printf, 3, 4)))
286log_msg(FILE *out, const char *prefix, const char *fmt, ...) {
287
William Robertsf0e0a942012-08-27 15:41:15 -0700288 fprintf(out, "%s", prefix);
289 va_list args;
290 va_start(args, fmt);
291 vfprintf(out, fmt, args);
292 va_end(args);
293}
294
295/**
296 * Checks for a type in the policy.
297 * @param db
298 * The policy db to search
299 * @param type
300 * The type to search for
301 * @return
302 * 1 if the type is found, 0 otherwise.
303 * @warning
304 * This function always returns 1 if libsepol is not linked
305 * statically to this executable and LINK_SEPOL_STATIC is not
306 * defined.
307 */
William Roberts25528cf2016-01-29 10:32:34 -0800308static int check_type(sepol_policydb_t *db, char *type) {
William Robertsf0e0a942012-08-27 15:41:15 -0700309
310 int rc = 1;
311#if defined(LINK_SEPOL_STATIC)
312 policydb_t *d = (policydb_t *)db;
313 hashtab_datum_t dat;
314 dat = hashtab_search(d->p_types.table, type);
315 rc = (dat == NULL) ? 0 : 1;
316#endif
317 return rc;
318}
319
William Roberts81e1f902015-06-03 21:57:47 -0700320static bool match_regex(key_map *assert, const key_map *check) {
321
322 char *tomatch = check->data;
323
324 int ret = pcre_exec(assert->regex.compiled, assert->regex.extra, tomatch,
325 strlen(tomatch), 0, 0, NULL, 0);
326
327 /* 0 from pcre_exec means matched */
328 return !ret;
329}
330
331static bool compile_regex(key_map *km, const char **errbuf, int *erroff) {
332
333 size_t size;
334 char *anchored;
335
336 /*
337 * Explicitly anchor all regex's
338 * The size is the length of the string to anchor (km->data), the anchor
339 * characters ^ and $ and the null byte. Hence strlen(km->data) + 3
340 */
341 size = strlen(km->data) + 3;
342 anchored = alloca(size);
343 sprintf(anchored, "^%s$", km->data);
344
345 km->regex.compiled = pcre_compile(anchored, PCRE_DOTALL, errbuf, erroff,
346 NULL );
347 if (!km->regex.compiled) {
348 return false;
349 }
350
351 km->regex.extra = pcre_study(km->regex.compiled, 0, errbuf);
352 return true;
353}
354
William Robertsf0e0a942012-08-27 15:41:15 -0700355/**
356 * Validates a key_map against a set of enforcement rules, this
357 * function exits the application on a type that cannot be properly
358 * checked
359 *
360 * @param m
361 * The key map to check
362 * @param lineno
363 * The line number in the source file for the corresponding key map
William Robertsfff29802012-11-27 14:20:34 -0800364 * @return
William Roberts81e1f902015-06-03 21:57:47 -0700365 * true if valid, false if invalid
William Robertsf0e0a942012-08-27 15:41:15 -0700366 */
William Roberts81e1f902015-06-03 21:57:47 -0700367static bool key_map_validate(key_map *m, const char *filename, int lineno,
368 bool is_neverallow) {
William Robertsf0e0a942012-08-27 15:41:15 -0700369
William Roberts81e1f902015-06-03 21:57:47 -0700370 int erroff;
371 const char *errbuf;
372 bool rc = true;
William Robertsf0e0a942012-08-27 15:41:15 -0700373 int ret = 1;
William Robertsf0e0a942012-08-27 15:41:15 -0700374 char *key = m->name;
375 char *value = m->data;
376 data_type type = m->type;
William Robertsf0e0a942012-08-27 15:41:15 -0700377
William Roberts0ae3a8a2012-09-04 11:51:04 -0700378 log_info("Validating %s=%s\n", key, value);
379
William Roberts81e1f902015-06-03 21:57:47 -0700380 /*
381 * Neverallows are completely skipped from sanity checking so you can match
382 * un-unspecified inputs.
383 */
384 if (is_neverallow) {
385 if (!m->regex.compiled) {
386 rc = compile_regex(m, &errbuf, &erroff);
387 if (!rc) {
388 log_error("Invalid regex on line %d : %s PCRE error: %s at offset %d",
389 lineno, value, errbuf, erroff);
390 }
391 }
392 goto out;
393 }
394
395 /* Booleans can always be checked for sanity */
William Robertsf0e0a942012-08-27 15:41:15 -0700396 if (type == dt_bool && (!strcmp("true", value) || !strcmp("false", value))) {
397 goto out;
398 }
399 else if (type == dt_bool) {
William Robertsae23a1f2012-09-05 12:53:52 -0700400 log_error("Expected boolean value got: %s=%s on line: %d in file: %s\n",
William Roberts81e1f902015-06-03 21:57:47 -0700401 key, value, lineno, filename);
402 rc = false;
William Robertsf0e0a942012-08-27 15:41:15 -0700403 goto out;
404 }
405
Stephen Smalley38084142012-11-28 10:46:18 -0500406 if (!strcasecmp(key, "levelFrom") &&
407 (strcasecmp(value, "none") && strcasecmp(value, "all") &&
408 strcasecmp(value, "app") && strcasecmp(value, "user"))) {
409 log_error("Unknown levelFrom=%s on line: %d in file: %s\n",
William Roberts81e1f902015-06-03 21:57:47 -0700410 value, lineno, filename);
411 rc = false;
Stephen Smalley38084142012-11-28 10:46:18 -0500412 goto out;
413 }
414
William Robertsf0e0a942012-08-27 15:41:15 -0700415 /*
William Roberts63297212013-04-19 19:06:23 -0700416 * If there is no policy file present,
417 * then it is not going to enforce the types against the policy so just return.
William Robertsf0e0a942012-08-27 15:41:15 -0700418 * User and name cannot really be checked.
419 */
420 if (!pol.policy_file) {
421 goto out;
422 }
William Robertsf0e0a942012-08-27 15:41:15 -0700423 else if (!strcasecmp(key, "type") || !strcasecmp(key, "domain")) {
424
425 if(!check_type(pol.db, value)) {
426 log_error("Could not find selinux type \"%s\" on line: %d in file: %s\n", value,
William Roberts81e1f902015-06-03 21:57:47 -0700427 lineno, filename);
428 rc = false;
William Robertsf0e0a942012-08-27 15:41:15 -0700429 }
430 goto out;
431 }
William Robertsf0e0a942012-08-27 15:41:15 -0700432 else if (!strcasecmp(key, "level")) {
433
William Roberts0ae3a8a2012-09-04 11:51:04 -0700434 ret = sepol_mls_check(pol.handle, pol.db, value);
435 if (ret < 0) {
William Robertsae23a1f2012-09-05 12:53:52 -0700436 log_error("Could not find selinux level \"%s\", on line: %d in file: %s\n", value,
William Roberts81e1f902015-06-03 21:57:47 -0700437 lineno, filename);
438 rc = false;
William Roberts0ae3a8a2012-09-04 11:51:04 -0700439 goto out;
William Robertsf0e0a942012-08-27 15:41:15 -0700440 }
441 }
442
William Roberts0ae3a8a2012-09-04 11:51:04 -0700443out:
444 log_info("Key map validate returning: %d\n", rc);
445 return rc;
William Robertsf0e0a942012-08-27 15:41:15 -0700446}
447
448/**
449 * Prints a rule map back to a file
450 * @param fp
451 * The file handle to print too
452 * @param r
453 * The rule map to print
454 */
455static void rule_map_print(FILE *fp, rule_map *r) {
456
William Roberts610a4b12013-10-15 18:26:00 -0700457 size_t i;
William Robertsf0e0a942012-08-27 15:41:15 -0700458 key_map *m;
459
460 for (i = 0; i < r->length; i++) {
461 m = &(r->m[i]);
462 if (i < r->length - 1)
463 fprintf(fp, "%s=%s ", m->name, m->data);
464 else
465 fprintf(fp, "%s=%s", m->name, m->data);
466 }
467}
468
469/**
470 * Compare two rule maps for equality
471 * @param rmA
472 * a rule map to check
473 * @param rmB
474 * a rule map to check
475 * @return
William Robertsae23a1f2012-09-05 12:53:52 -0700476 * a map_match enum indicating the result
William Robertsf0e0a942012-08-27 15:41:15 -0700477 */
William Roberts0ae3a8a2012-09-04 11:51:04 -0700478static map_match rule_map_cmp(rule_map *rmA, rule_map *rmB) {
William Robertsf0e0a942012-08-27 15:41:15 -0700479
William Roberts610a4b12013-10-15 18:26:00 -0700480 size_t i;
481 size_t j;
William Robertsf0e0a942012-08-27 15:41:15 -0700482 int inputs_found = 0;
483 int num_of_matched_inputs = 0;
484 int input_mode = 0;
William Roberts610a4b12013-10-15 18:26:00 -0700485 size_t matches = 0;
William Robertsf0e0a942012-08-27 15:41:15 -0700486 key_map *mA;
487 key_map *mB;
488
William Robertsf0e0a942012-08-27 15:41:15 -0700489 for (i = 0; i < rmA->length; i++) {
490 mA = &(rmA->m[i]);
491
492 for (j = 0; j < rmB->length; j++) {
493 mB = &(rmB->m[j]);
494 input_mode = 0;
495
496 if (mA->type != mB->type)
497 continue;
498
499 if (strcmp(mA->name, mB->name))
500 continue;
501
502 if (strcmp(mA->data, mB->data))
503 continue;
504
505 if (mB->dir != mA->dir)
506 continue;
507 else if (mB->dir == dir_in) {
508 input_mode = 1;
509 inputs_found++;
510 }
511
William Roberts0ae3a8a2012-09-04 11:51:04 -0700512 if (input_mode) {
William Roberts1e8c0612013-04-19 19:06:02 -0700513 log_info("Matched input lines: name=%s data=%s\n", mA->name, mA->data);
William Robertsf0e0a942012-08-27 15:41:15 -0700514 num_of_matched_inputs++;
William Roberts0ae3a8a2012-09-04 11:51:04 -0700515 }
William Robertsf0e0a942012-08-27 15:41:15 -0700516
517 /* Match found, move on */
William Roberts1e8c0612013-04-19 19:06:02 -0700518 log_info("Matched lines: name=%s data=%s", mA->name, mA->data);
William Robertsf0e0a942012-08-27 15:41:15 -0700519 matches++;
520 break;
521 }
522 }
523
524 /* If they all matched*/
William Roberts0ae3a8a2012-09-04 11:51:04 -0700525 if (matches == rmA->length) {
526 log_info("Rule map cmp MATCH\n");
527 return map_matched;
528 }
William Robertsf0e0a942012-08-27 15:41:15 -0700529
530 /* They didn't all match but the input's did */
William Roberts0ae3a8a2012-09-04 11:51:04 -0700531 else if (num_of_matched_inputs == inputs_found) {
532 log_info("Rule map cmp INPUT MATCH\n");
533 return map_input_matched;
534 }
William Robertsf0e0a942012-08-27 15:41:15 -0700535
536 /* They didn't all match, and the inputs didn't match, ie it didn't
537 * match */
William Roberts0ae3a8a2012-09-04 11:51:04 -0700538 else {
539 log_info("Rule map cmp NO MATCH\n");
540 return map_no_matches;
541 }
William Robertsf0e0a942012-08-27 15:41:15 -0700542}
543
544/**
545 * Frees a rule map
546 * @param rm
547 * rule map to be freed.
William Roberts7d65b542015-06-19 09:43:28 -0700548 * @is_in_htable
549 * True if the rule map has been added to the hash table, false
550 * otherwise.
551 */
552static void rule_map_free(rule_map *rm, bool is_in_htable) {
William Robertsf0e0a942012-08-27 15:41:15 -0700553
William Roberts610a4b12013-10-15 18:26:00 -0700554 size_t i;
555 size_t len = rm->length;
William Robertsf0e0a942012-08-27 15:41:15 -0700556 for (i = 0; i < len; i++) {
557 key_map *m = &(rm->m[i]);
558 free(m->data);
William Roberts81e1f902015-06-03 21:57:47 -0700559
560 if (m->regex.compiled) {
561 pcre_free(m->regex.compiled);
562 }
563
564 if (m->regex.extra) {
565 pcre_free_study(m->regex.extra);
566 }
William Robertsf0e0a942012-08-27 15:41:15 -0700567 }
568
William Roberts7d65b542015-06-19 09:43:28 -0700569 /*
570 * hdestroy() frees comparsion keys for non glibc
571 * on GLIBC we always free on NON-GLIBC we free if
572 * it is not in the htable.
573 */
574 if (rm->key) {
rpcraig5dbfdc02012-10-23 11:03:47 -0400575#ifdef __GLIBC__
William Roberts7d65b542015-06-19 09:43:28 -0700576 /* silence unused warning */
577 (void)is_in_htable;
William Robertsf0e0a942012-08-27 15:41:15 -0700578 free(rm->key);
William Roberts7d65b542015-06-19 09:43:28 -0700579#else
580 if (!is_in_htable) {
581 free(rm->key);
582 }
rpcraig5dbfdc02012-10-23 11:03:47 -0400583#endif
William Roberts7d65b542015-06-19 09:43:28 -0700584 }
William Robertsf0e0a942012-08-27 15:41:15 -0700585
William Roberts81e1f902015-06-03 21:57:47 -0700586 free(rm->filename);
William Robertsf0e0a942012-08-27 15:41:15 -0700587 free(rm);
588}
589
590static void free_kvp(kvp *k) {
591 free(k->key);
592 free(k->value);
593}
594
595/**
William Roberts61846292013-10-15 09:38:24 -0700596 * Checks a rule_map for any variation of KVP's that shouldn't be allowed.
William Roberts81e1f902015-06-03 21:57:47 -0700597 * It builds an assertion failure list for each rule map.
William Roberts61846292013-10-15 09:38:24 -0700598 * Note that this function logs all errors.
599 *
600 * Current Checks:
601 * 1. That a specified name entry should have a specified seinfo entry as well.
William Roberts81e1f902015-06-03 21:57:47 -0700602 * 2. That no rule violates a neverallow
William Roberts61846292013-10-15 09:38:24 -0700603 * @param rm
604 * The rule map to check for validity.
William Roberts61846292013-10-15 09:38:24 -0700605 */
William Roberts81e1f902015-06-03 21:57:47 -0700606static void rule_map_validate(rule_map *rm) {
William Roberts61846292013-10-15 09:38:24 -0700607
William Roberts81e1f902015-06-03 21:57:47 -0700608 size_t i, j;
609 const key_map *rule;
610 key_map *nrule;
611 hash_entry *e;
612 rule_map *assert;
613 list_element *cursor;
William Roberts61846292013-10-15 09:38:24 -0700614
William Roberts81e1f902015-06-03 21:57:47 -0700615 list_for_each(&nallow_list, cursor) {
616 e = list_entry(cursor, typeof(*e), listify);
617 assert = e->r;
William Roberts61846292013-10-15 09:38:24 -0700618
William Roberts81e1f902015-06-03 21:57:47 -0700619 size_t cnt = 0;
620
621 for (j = 0; j < assert->length; j++) {
622 nrule = &(assert->m[j]);
623
624 // mark that nrule->name is for a null check
625 bool is_null_check = !strcmp(nrule->data, "\"\"");
626
627 for (i = 0; i < rm->length; i++) {
628 rule = &(rm->m[i]);
629
630 if (!strcmp(rule->name, nrule->name)) {
631
632 /* the name was found, (data cannot be false) then it was specified */
633 is_null_check = false;
634
635 if (match_regex(nrule, rule)) {
636 cnt++;
637 }
638 }
639 }
640
641 /*
642 * the nrule was marked in a null check and we never found a match on nrule, thus
643 * it matched and we update the cnt
644 */
645 if (is_null_check) {
646 cnt++;
647 }
William Roberts61846292013-10-15 09:38:24 -0700648 }
William Roberts81e1f902015-06-03 21:57:47 -0700649 if (cnt == assert->length) {
650 list_append(&rm->violations, &assert->listify);
William Roberts61846292013-10-15 09:38:24 -0700651 }
652 }
William Roberts61846292013-10-15 09:38:24 -0700653}
654
655/**
William Robertsf0e0a942012-08-27 15:41:15 -0700656 * Given a set of key value pairs, this will construct a new rule map.
657 * On error this function calls exit.
658 * @param keys
659 * Keys from a rule line to map
660 * @param num_of_keys
661 * The length of the keys array
662 * @param lineno
663 * The line number the keys were extracted from
664 * @return
665 * A rule map pointer.
666 */
William Roberts81e1f902015-06-03 21:57:47 -0700667static rule_map *rule_map_new(kvp keys[], size_t num_of_keys, int lineno,
668 const char *filename, bool is_never_allow) {
William Robertsf0e0a942012-08-27 15:41:15 -0700669
William Roberts610a4b12013-10-15 18:26:00 -0700670 size_t i = 0, j = 0;
William Robertsf0e0a942012-08-27 15:41:15 -0700671 rule_map *new_map = NULL;
672 kvp *k = NULL;
673 key_map *r = NULL, *x = NULL;
Stephen Smalley534fb072015-02-13 14:06:08 -0500674 bool seen[KVP_NUM_OF_RULES];
675
676 for (i = 0; i < KVP_NUM_OF_RULES; i++)
677 seen[i] = false;
William Robertsf0e0a942012-08-27 15:41:15 -0700678
679 new_map = calloc(1, (num_of_keys * sizeof(key_map)) + sizeof(rule_map));
680 if (!new_map)
681 goto oom;
682
William Roberts81e1f902015-06-03 21:57:47 -0700683 new_map->is_never_allow = is_never_allow;
William Robertsf0e0a942012-08-27 15:41:15 -0700684 new_map->length = num_of_keys;
685 new_map->lineno = lineno;
William Roberts81e1f902015-06-03 21:57:47 -0700686 new_map->filename = strdup(filename);
687 if (!new_map->filename) {
688 goto oom;
689 }
William Robertsf0e0a942012-08-27 15:41:15 -0700690
691 /* For all the keys in a rule line*/
692 for (i = 0; i < num_of_keys; i++) {
693 k = &(keys[i]);
694 r = &(new_map->m[i]);
695
696 for (j = 0; j < KVP_NUM_OF_RULES; j++) {
697 x = &(rules[j]);
698
699 /* Only assign key name to map name */
700 if (strcasecmp(k->key, x->name)) {
701 if (i == KVP_NUM_OF_RULES) {
702 log_error("No match for key: %s\n", k->key);
703 goto err;
704 }
705 continue;
706 }
707
Stephen Smalley534fb072015-02-13 14:06:08 -0500708 if (seen[j]) {
709 log_error("Duplicated key: %s\n", k->key);
710 goto err;
711 }
712 seen[j] = true;
713
William Robertsf0e0a942012-08-27 15:41:15 -0700714 memcpy(r, x, sizeof(key_map));
715
716 /* Assign rule map value to one from file */
717 r->data = strdup(k->value);
718 if (!r->data)
719 goto oom;
720
721 /* Enforce type check*/
William Roberts0ae3a8a2012-09-04 11:51:04 -0700722 log_info("Validating keys!\n");
William Roberts81e1f902015-06-03 21:57:47 -0700723 if (!key_map_validate(r, filename, lineno, new_map->is_never_allow)) {
William Robertsf0e0a942012-08-27 15:41:15 -0700724 log_error("Could not validate\n");
725 goto err;
726 }
727
William Roberts81e1f902015-06-03 21:57:47 -0700728 /*
729 * Only build key off of inputs with the exception of neverallows.
730 * Neverallows are keyed off of all key value pairs,
731 */
732 if (r->dir == dir_in || new_map->is_never_allow) {
William Robertsf0e0a942012-08-27 15:41:15 -0700733 char *tmp;
William Robertsb3ab56c2012-09-17 14:35:02 -0700734 int key_len = strlen(k->key);
735 int val_len = strlen(k->value);
736 int l = (new_map->key) ? strlen(new_map->key) : 0;
737 l = l + key_len + val_len;
William Robertsf0e0a942012-08-27 15:41:15 -0700738 l += 1;
739
740 tmp = realloc(new_map->key, l);
741 if (!tmp)
742 goto oom;
743
William Robertsb3ab56c2012-09-17 14:35:02 -0700744 if (!new_map->key)
745 memset(tmp, 0, l);
746
William Robertsf0e0a942012-08-27 15:41:15 -0700747 new_map->key = tmp;
748
William Robertsb3ab56c2012-09-17 14:35:02 -0700749 strncat(new_map->key, k->key, key_len);
750 strncat(new_map->key, k->value, val_len);
William Robertsf0e0a942012-08-27 15:41:15 -0700751 }
752 break;
753 }
754 free_kvp(k);
755 }
756
757 if (new_map->key == NULL) {
758 log_error("Strange, no keys found, input file corrupt perhaps?\n");
759 goto err;
760 }
761
762 return new_map;
763
764oom:
765 log_error("Out of memory!\n");
766err:
767 if(new_map) {
William Roberts7d65b542015-06-19 09:43:28 -0700768 rule_map_free(new_map, false);
William Robertsf0e0a942012-08-27 15:41:15 -0700769 for (; i < num_of_keys; i++) {
770 k = &(keys[i]);
771 free_kvp(k);
772 }
773 }
Stephen Smalley534fb072015-02-13 14:06:08 -0500774 return NULL;
William Robertsf0e0a942012-08-27 15:41:15 -0700775}
776
777/**
778 * Print the usage of the program
779 */
780static void usage() {
781 printf(
782 "checkseapp [options] <input file>\n"
783 "Processes an seapp_contexts file specified by argument <input file> (default stdin) "
William Robertsae23a1f2012-09-05 12:53:52 -0700784 "and allows later declarations to override previous ones on a match.\n"
William Robertsf0e0a942012-08-27 15:41:15 -0700785 "Options:\n"
786 "-h - print this help message\n"
787 "-v - enable verbose debugging informations\n"
William Roberts63297212013-04-19 19:06:23 -0700788 "-p policy file - specify policy file for strict checking of output selectors against the policy\n"
William Roberts81e1f902015-06-03 21:57:47 -0700789 "-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 -0700790}
791
792static void init() {
793
William Roberts81e1f902015-06-03 21:57:47 -0700794 bool has_out_file;
795 list_element *cursor;
796 file_info *tmp;
797
798 /* input files if the list is empty, use stdin */
799 if (!input_file_list.head) {
800 log_info("Using stdin for input\n");
801 tmp = malloc(sizeof(*tmp));
802 if (!tmp) {
803 log_error("oom");
William Robertsf0e0a942012-08-27 15:41:15 -0700804 exit(EXIT_FAILURE);
805 }
William Roberts81e1f902015-06-03 21:57:47 -0700806 tmp->name = "stdin";
807 tmp->file = stdin;
808 list_append(&input_file_list, &(tmp->listify));
809 }
810 else {
811 list_for_each(&input_file_list, cursor) {
812 tmp = list_entry(cursor, typeof(*tmp), listify);
813
814 log_info("Opening input file: \"%s\"\n", tmp->name);
815 tmp->file = fopen(tmp->name, "r");
816 if (!tmp->file) {
817 log_error("Could not open file: %s error: %s\n", tmp->name,
818 strerror(errno));
819 exit(EXIT_FAILURE);
820 }
821 }
William Robertsf0e0a942012-08-27 15:41:15 -0700822 }
823
William Roberts81e1f902015-06-03 21:57:47 -0700824 has_out_file = out_file.name != NULL;
825
826 /* If output file is -, then use stdout, else open the path */
827 if (has_out_file && !strcmp(out_file.name, "-")) {
828 out_file.file = stdout;
829 out_file.name = "stdout";
830 }
831 else if (has_out_file) {
832 out_file.file = fopen(out_file.name, "w+");
833 }
834
835 if (has_out_file && !out_file.file) {
836 log_error("Could not open file: \"%s\" error: \"%s\"\n", out_file.name,
837 strerror(errno));
838 exit(EXIT_FAILURE);
William Robertsf0e0a942012-08-27 15:41:15 -0700839 }
840
841 if (pol.policy_file_name) {
William Robertsf0e0a942012-08-27 15:41:15 -0700842 log_info("Opening policy file: %s\n", pol.policy_file_name);
843 pol.policy_file = fopen(pol.policy_file_name, "rb");
844 if (!pol.policy_file) {
845 log_error("Could not open file: %s error: %s\n",
846 pol.policy_file_name, strerror(errno));
847 exit(EXIT_FAILURE);
848 }
849
850 pol.handle = sepol_handle_create();
851 if (!pol.handle) {
852 log_error("Could not create sepolicy handle: %s\n",
853 strerror(errno));
854 exit(EXIT_FAILURE);
855 }
856
857 if (sepol_policy_file_create(&pol.pf) < 0) {
858 log_error("Could not create sepolicy file: %s!\n",
859 strerror(errno));
860 exit(EXIT_FAILURE);
861 }
862
863 sepol_policy_file_set_fp(pol.pf, pol.policy_file);
864 sepol_policy_file_set_handle(pol.pf, pol.handle);
865
866 if (sepol_policydb_create(&pol.db) < 0) {
867 log_error("Could not create sepolicy db: %s!\n",
868 strerror(errno));
869 exit(EXIT_FAILURE);
870 }
871
872 if (sepol_policydb_read(pol.db, pol.pf) < 0) {
873 log_error("Could not lod policy file to db: %s!\n",
874 strerror(errno));
875 exit(EXIT_FAILURE);
876 }
877 }
878
William Roberts81e1f902015-06-03 21:57:47 -0700879 list_for_each(&input_file_list, cursor) {
880 tmp = list_entry(cursor, typeof(*tmp), listify);
881 log_info("Input file set to: \"%s\"\n", tmp->name);
882 }
883
884 log_info("Policy file set to: \"%s\"\n",
885 (pol.policy_file_name == NULL) ? "None" : pol.policy_file_name);
886 log_info("Output file set to: \"%s\"\n", out_file.name);
William Robertsf0e0a942012-08-27 15:41:15 -0700887
William Roberts0ae3a8a2012-09-04 11:51:04 -0700888#if !defined(LINK_SEPOL_STATIC)
William Robertsa53ccf32012-09-17 12:53:44 -0700889 log_warn("LINK_SEPOL_STATIC is not defined\n""Not checking types!");
William Roberts0ae3a8a2012-09-04 11:51:04 -0700890#endif
891
William Robertsf0e0a942012-08-27 15:41:15 -0700892}
893
894/**
895 * Handle parsing and setting the global flags for the command line
896 * options. This function calls exit on failure.
897 * @param argc
898 * argument count
899 * @param argv
900 * argument list
901 */
902static void handle_options(int argc, char *argv[]) {
903
904 int c;
William Roberts81e1f902015-06-03 21:57:47 -0700905 file_info *input_file;
William Robertsf0e0a942012-08-27 15:41:15 -0700906
William Robertsf26b6d42015-06-23 10:22:45 -0700907 while ((c = getopt(argc, argv, "ho:p:v")) != -1) {
William Robertsf0e0a942012-08-27 15:41:15 -0700908 switch (c) {
909 case 'h':
910 usage();
911 exit(EXIT_SUCCESS);
912 case 'o':
William Roberts81e1f902015-06-03 21:57:47 -0700913 out_file.name = optarg;
William Robertsf0e0a942012-08-27 15:41:15 -0700914 break;
915 case 'p':
916 pol.policy_file_name = optarg;
917 break;
918 case 'v':
919 log_set_verbose();
920 break;
921 case '?':
922 if (optopt == 'o' || optopt == 'p')
923 log_error("Option -%c requires an argument.\n", optopt);
924 else if (isprint (optopt))
925 log_error("Unknown option `-%c'.\n", optopt);
926 else {
927 log_error(
928 "Unknown option character `\\x%x'.\n",
929 optopt);
William Robertsf0e0a942012-08-27 15:41:15 -0700930 }
William Robertsf0e0a942012-08-27 15:41:15 -0700931 default:
932 exit(EXIT_FAILURE);
933 }
934 }
935
William Roberts81e1f902015-06-03 21:57:47 -0700936 for (c = optind; c < argc; c++) {
William Robertsf0e0a942012-08-27 15:41:15 -0700937
William Roberts81e1f902015-06-03 21:57:47 -0700938 input_file = calloc(1, sizeof(*input_file));
939 if (!input_file) {
940 log_error("oom");
941 exit(EXIT_FAILURE);
942 }
943 input_file->name = argv[c];
944 list_append(&input_file_list, &input_file->listify);
William Robertsf0e0a942012-08-27 15:41:15 -0700945 }
946}
947
948/**
949 * Adds a rule to the hash table and to the ordered list if needed.
950 * @param rm
951 * The rule map to add.
952 */
953static void rule_add(rule_map *rm) {
954
William Roberts0ae3a8a2012-09-04 11:51:04 -0700955 map_match cmp;
William Robertsf0e0a942012-08-27 15:41:15 -0700956 ENTRY e;
957 ENTRY *f;
958 hash_entry *entry;
959 hash_entry *tmp;
William Roberts81e1f902015-06-03 21:57:47 -0700960 list *list_to_addto;
William Robertsf0e0a942012-08-27 15:41:15 -0700961
962 e.key = rm->key;
963
William Roberts0ae3a8a2012-09-04 11:51:04 -0700964 log_info("Searching for key: %s\n", e.key);
William Robertsf0e0a942012-08-27 15:41:15 -0700965 /* Check to see if it has already been added*/
966 f = hsearch(e, FIND);
967
968 /*
969 * Since your only hashing on a partial key, the inputs we need to handle
970 * when you want to override the outputs for a given input set, as well as
971 * checking for duplicate entries.
972 */
973 if(f) {
William Roberts0ae3a8a2012-09-04 11:51:04 -0700974 log_info("Existing entry found!\n");
William Robertsf0e0a942012-08-27 15:41:15 -0700975 tmp = (hash_entry *)f->data;
976 cmp = rule_map_cmp(rm, tmp->r);
Stephen Smalley0b820042015-02-13 14:58:31 -0500977 log_error("Duplicate line detected in file: %s\n"
978 "Lines %d and %d %s!\n",
William Roberts81e1f902015-06-03 21:57:47 -0700979 rm->filename, tmp->r->lineno, rm->lineno,
Stephen Smalley0b820042015-02-13 14:58:31 -0500980 map_match_str[cmp]);
William Roberts7d65b542015-06-19 09:43:28 -0700981 rule_map_free(rm, false);
Stephen Smalley0b820042015-02-13 14:58:31 -0500982 goto err;
William Robertsf0e0a942012-08-27 15:41:15 -0700983 }
984 /* It wasn't found, just add the rule map to the table */
985 else {
986
987 entry = malloc(sizeof(hash_entry));
988 if (!entry)
989 goto oom;
990
991 entry->r = rm;
992 e.data = entry;
993
994 f = hsearch(e, ENTER);
995 if(f == NULL) {
996 goto oom;
997 }
998
999 /* new entries must be added to the ordered list */
1000 entry->r = rm;
William Roberts81e1f902015-06-03 21:57:47 -07001001 list_to_addto = rm->is_never_allow ? &nallow_list : &line_order_list;
1002 list_append(list_to_addto, &entry->listify);
William Robertsf0e0a942012-08-27 15:41:15 -07001003 }
1004
1005 return;
1006oom:
1007 if (e.key)
1008 free(e.key);
1009 if (entry)
1010 free(entry);
1011 if (rm)
1012 free(rm);
1013 log_error("Out of memory in function: %s\n", __FUNCTION__);
1014err:
1015 exit(EXIT_FAILURE);
1016}
1017
William Roberts81e1f902015-06-03 21:57:47 -07001018static void parse_file(file_info *in_file) {
William Robertsf0e0a942012-08-27 15:41:15 -07001019
William Roberts81e1f902015-06-03 21:57:47 -07001020 char *p;
William Robertsf0e0a942012-08-27 15:41:15 -07001021 size_t len;
William Roberts81e1f902015-06-03 21:57:47 -07001022 char *token;
1023 char *saveptr;
1024 bool is_never_allow;
1025 bool found_whitespace;
1026
1027 size_t lineno = 0;
1028 char *name = NULL;
1029 char *value = NULL;
William Roberts610a4b12013-10-15 18:26:00 -07001030 size_t token_cnt = 0;
William Robertsf0e0a942012-08-27 15:41:15 -07001031
William Roberts81e1f902015-06-03 21:57:47 -07001032 char line_buf[BUFSIZ];
1033 kvp keys[KVP_NUM_OF_RULES];
William Robertsf0e0a942012-08-27 15:41:15 -07001034
William Roberts81e1f902015-06-03 21:57:47 -07001035 while (fgets(line_buf, sizeof(line_buf) - 1, in_file->file)) {
William Robertsf0e0a942012-08-27 15:41:15 -07001036 lineno++;
William Roberts81e1f902015-06-03 21:57:47 -07001037 is_never_allow = false;
1038 found_whitespace = false;
1039 log_info("Got line %zu\n", lineno);
William Robertsf0e0a942012-08-27 15:41:15 -07001040 len = strlen(line_buf);
1041 if (line_buf[len - 1] == '\n')
Alice Chuf6647eb2012-10-30 16:27:00 -07001042 line_buf[len - 1] = '\0';
William Robertsf0e0a942012-08-27 15:41:15 -07001043 p = line_buf;
William Roberts81e1f902015-06-03 21:57:47 -07001044
1045 /* neverallow lines must start with neverallow (ie ^neverallow) */
1046 if (!strncasecmp(p, "neverallow", strlen("neverallow"))) {
1047 p += strlen("neverallow");
1048 is_never_allow = true;
1049 }
1050
1051 /* strip trailing whitespace skip comments */
1052 while (isspace(*p)) {
William Robertsf0e0a942012-08-27 15:41:15 -07001053 p++;
William Roberts81e1f902015-06-03 21:57:47 -07001054 found_whitespace = true;
1055 }
Alice Chuf6647eb2012-10-30 16:27:00 -07001056 if (*p == '#' || *p == '\0')
William Robertsf0e0a942012-08-27 15:41:15 -07001057 continue;
1058
1059 token = strtok_r(p, " \t", &saveptr);
1060 if (!token)
1061 goto err;
1062
1063 token_cnt = 0;
1064 memset(keys, 0, sizeof(kvp) * KVP_NUM_OF_RULES);
1065 while (1) {
William Roberts0ae3a8a2012-09-04 11:51:04 -07001066
William Robertsf0e0a942012-08-27 15:41:15 -07001067 name = token;
1068 value = strchr(name, '=');
1069 if (!value)
1070 goto err;
1071 *value++ = 0;
1072
1073 keys[token_cnt].key = strdup(name);
1074 if (!keys[token_cnt].key)
1075 goto oom;
1076
1077 keys[token_cnt].value = strdup(value);
1078 if (!keys[token_cnt].value)
1079 goto oom;
1080
1081 token_cnt++;
1082
1083 token = strtok_r(NULL, " \t", &saveptr);
1084 if (!token)
1085 break;
1086
1087 } /*End token parsing */
1088
William Roberts81e1f902015-06-03 21:57:47 -07001089 rule_map *r = rule_map_new(keys, token_cnt, lineno, in_file->name, is_never_allow);
Stephen Smalley534fb072015-02-13 14:06:08 -05001090 if (!r)
1091 goto err;
William Robertsf0e0a942012-08-27 15:41:15 -07001092 rule_add(r);
1093
1094 } /* End file parsing */
1095 return;
1096
1097err:
William Roberts81e1f902015-06-03 21:57:47 -07001098 log_error("reading %s, line %zu, name %s, value %s\n",
1099 in_file->name, lineno, name, value);
1100 if(found_whitespace && name && !strcasecmp(name, "neverallow")) {
1101 log_error("perhaps whitespace before neverallow\n");
1102 }
William Robertsf0e0a942012-08-27 15:41:15 -07001103 exit(EXIT_FAILURE);
1104oom:
1105 log_error("In function %s: Out of memory\n", __FUNCTION__);
1106 exit(EXIT_FAILURE);
1107}
1108
1109/**
William Roberts81e1f902015-06-03 21:57:47 -07001110 * Parses the seapp_contexts file and neverallow file
1111 * and adds them to the hash table and ordered list entries
1112 * when it encounters them.
1113 * Calls exit on failure.
1114 */
1115static void parse() {
1116
1117 file_info *current;
1118 list_element *cursor;
1119 list_for_each(&input_file_list, cursor) {
1120 current = list_entry(cursor, typeof(*current), listify);
1121 parse_file(current);
1122 }
1123}
1124
1125static void validate() {
1126
1127 list_element *cursor, *v;
1128 bool found_issues = false;
1129 hash_entry *e;
1130 rule_map *r;
1131 list_for_each(&line_order_list, cursor) {
1132 e = list_entry(cursor, typeof(*e), listify);
1133 rule_map_validate(e->r);
1134 }
1135
1136 list_for_each(&line_order_list, cursor) {
1137 e = list_entry(cursor, typeof(*e), listify);
1138 r = e->r;
1139 list_for_each(&r->violations, v) {
1140 found_issues = true;
1141 log_error("Rule in File \"%s\" on line %d: \"", e->r->filename, e->r->lineno);
1142 rule_map_print(stderr, e->r);
1143 r = list_entry(v, rule_map, listify);
1144 fprintf(stderr, "\" violates neverallow in File \"%s\" on line %d: \"", r->filename, r->lineno);
1145 rule_map_print(stderr, r);
1146 fprintf(stderr, "\"\n");
1147 }
1148 }
1149
1150 if (found_issues) {
1151 exit(EXIT_FAILURE);
1152 }
1153}
1154
1155/**
William Robertsf0e0a942012-08-27 15:41:15 -07001156 * Should be called after parsing to cause the printing of the rule_maps
1157 * stored in the ordered list, head first, which preserves the "first encountered"
1158 * ordering.
1159 */
1160static void output() {
1161
William Roberts81e1f902015-06-03 21:57:47 -07001162 hash_entry *e;
1163 list_element *cursor;
William Robertsf0e0a942012-08-27 15:41:15 -07001164
William Roberts81e1f902015-06-03 21:57:47 -07001165 if (!out_file.file) {
1166 log_info("No output file, not outputting.\n");
1167 return;
1168 }
1169
1170 list_for_each(&line_order_list, cursor) {
1171 e = list_entry(cursor, hash_entry, listify);
1172 rule_map_print(out_file.file, e->r);
1173 fprintf(out_file.file, "\n");
William Robertsf0e0a942012-08-27 15:41:15 -07001174 }
1175}
1176
1177/**
1178 * This function is registered to the at exit handler and should clean up
1179 * the programs dynamic resources, such as memory and fd's.
1180 */
1181static void cleanup() {
1182
1183 /* Only close this when it was opened by me and not the crt */
William Roberts81e1f902015-06-03 21:57:47 -07001184 if (out_file.name && strcmp(out_file.name, "stdout") && out_file.file) {
1185 log_info("Closing file: %s\n", out_file.name);
1186 fclose(out_file.file);
William Robertsf0e0a942012-08-27 15:41:15 -07001187 }
1188
1189 if (pol.policy_file) {
1190
1191 log_info("Closing file: %s\n", pol.policy_file_name);
1192 fclose(pol.policy_file);
1193
1194 if (pol.db)
1195 sepol_policydb_free(pol.db);
1196
1197 if (pol.pf)
1198 sepol_policy_file_free(pol.pf);
1199
1200 if (pol.handle)
1201 sepol_handle_destroy(pol.handle);
1202 }
1203
William Roberts81e1f902015-06-03 21:57:47 -07001204 log_info("Freeing lists\n");
1205 list_free(&input_file_list);
1206 list_free(&line_order_list);
1207 list_free(&nallow_list);
William Robertsf0e0a942012-08-27 15:41:15 -07001208 hdestroy();
1209}
1210
1211int main(int argc, char *argv[]) {
1212 if (!hcreate(TABLE_SIZE)) {
1213 log_error("Could not create hash table: %s\n", strerror(errno));
1214 exit(EXIT_FAILURE);
1215 }
1216 atexit(cleanup);
1217 handle_options(argc, argv);
1218 init();
1219 log_info("Starting to parse\n");
1220 parse();
1221 log_info("Parsing completed, generating output\n");
William Roberts81e1f902015-06-03 21:57:47 -07001222 validate();
William Robertsf0e0a942012-08-27 15:41:15 -07001223 output();
1224 log_info("Success, generated output\n");
1225 exit(EXIT_SUCCESS);
1226}