xref: /aosp_15_r20/external/selinux/checkpolicy/checkpolicy.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 
2 /*
3  * Author : Stephen Smalley, <[email protected]>
4  */
5 
6 /*
7  * Updated: Trusted Computer Solutions, Inc. <[email protected]>
8  *
9  *	Support for enhanced MLS infrastructure.
10  *
11  * Updated: Karl MacMillan <[email protected]>
12  *
13  * 	Added conditional policy language extensions
14  *
15  * Updated: James Morris <[email protected]>
16  *
17  *	Added IPv6 support.
18  *
19  * Updated: Joshua Brindle <[email protected]>
20  *	    Karl MacMillan <[email protected]>
21  *          Jason Tang     <[email protected]>
22  *
23  *	Policy Module support.
24  *
25  * Copyright (C) 2017 Mellanox Technologies Inc.
26  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
27  * Copyright (C) 2003 - 2005 Tresys Technology, LLC
28  * Copyright (C) 2003 Red Hat, Inc., James Morris <[email protected]>
29  *	This program is free software; you can redistribute it and/or modify
30  *  	it under the terms of the GNU General Public License as published by
31  *	the Free Software Foundation, version 2.
32  */
33 
34 /* FLASK */
35 
36 /*
37  * checkpolicy
38  *
39  * Load and check a policy configuration.
40  *
41  * A policy configuration is created in a text format,
42  * and then compiled into a binary format for use by
43  * the security server.  By default, checkpolicy reads
44  * the text format.   If '-b' is specified, then checkpolicy
45  * reads the binary format instead.
46  *
47  * If '-o output_file' is specified, then checkpolicy
48  * writes the binary format version of the configuration
49  * to the specified output file.
50  *
51  * If '-d' is specified, then checkpolicy permits the user
52  * to interactively test the security server functions with
53  * the loaded policy configuration.
54  *
55  * If '-c' is specified, then the supplied parameter is used to
56  * determine which policy version to use for generating binary
57  * policy.  This is for compatibility with older kernels. If any
58  * booleans or conditional rules are thrown away a warning is printed.
59  */
60 
61 #include <ctype.h>
62 #include <getopt.h>
63 #include <unistd.h>
64 #include <stdlib.h>
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <sys/socket.h>
68 #include <netinet/in.h>
69 #ifndef IPPROTO_DCCP
70 #define IPPROTO_DCCP 33
71 #endif
72 #ifndef IPPROTO_SCTP
73 #define IPPROTO_SCTP 132
74 #endif
75 #include <arpa/inet.h>
76 #include <fcntl.h>
77 #include <stdio.h>
78 #include <errno.h>
79 #include <sys/mman.h>
80 
81 #include <sepol/module_to_cil.h>
82 #include <sepol/kernel_to_cil.h>
83 #include <sepol/kernel_to_conf.h>
84 #include <sepol/policydb/policydb.h>
85 #include <sepol/policydb/services.h>
86 #include <sepol/policydb/conditional.h>
87 #include <sepol/policydb/hierarchy.h>
88 #include <sepol/policydb/expand.h>
89 #include <sepol/policydb/link.h>
90 
91 #include "queue.h"
92 #include "parse_util.h"
93 
94 // ANDROID: this code does not call policydb_destroy, perhaps others
__asan_default_options()95 const char *__asan_default_options() {
96     return "detect_leaks=0";
97 }
98 
99 static policydb_t policydb;
100 static sidtab_t sidtab;
101 
102 extern policydb_t *policydbp;
103 extern int mlspol;
104 extern int werror;
105 
106 static int handle_unknown = SEPOL_DENY_UNKNOWN;
107 static const char *txtfile = "policy.conf";
108 static const char *binfile = "policy";
109 
usage(const char * progname)110 static __attribute__((__noreturn__)) void usage(const char *progname)
111 {
112 	printf
113 	    ("usage:  %s [-b[F]] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M] "
114 	     "[-N] [-c policyvers (%d-%d)] [-o output_file|-] [-S] [-O] "
115 	     "[-t target_platform (selinux,xen)] [-E] [-V] [input_file]\n",
116 	     progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
117 	exit(1);
118 }
119 
120 #define FGETS(out, size, in) \
121 do { \
122 	if (fgets(out,size,in)==NULL) {	\
123 		fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, \
124 			strerror(errno)); \
125 		exit(1);\
126 	} \
127 } while (0)
128 
print_sid(sepol_security_id_t sid,context_struct_t * context,void * data)129 static int print_sid(sepol_security_id_t sid,
130 		     context_struct_t * context
131 		     __attribute__ ((unused)), void *data
132 		     __attribute__ ((unused)))
133 {
134 	sepol_security_context_t scontext;
135 	size_t scontext_len;
136 	int rc;
137 
138 	rc = sepol_sid_to_context(sid, &scontext, &scontext_len);
139 	if (rc)
140 		printf("sid %d -> error %d\n", sid, rc);
141 	else {
142 		printf("sid %d -> scontext %s\n", sid, scontext);
143 		free(scontext);
144 	}
145 	return 0;
146 }
147 
148 struct val_to_name {
149 	unsigned int val;
150 	char *name;
151 };
152 
find_perm(hashtab_key_t key,hashtab_datum_t datum,void * p)153 static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
154 {
155 	struct val_to_name *v = p;
156 	perm_datum_t *perdatum;
157 
158 	perdatum = (perm_datum_t *) datum;
159 
160 	if (v->val == perdatum->s.value) {
161 		v->name = key;
162 		return 1;
163 	}
164 
165 	return 0;
166 }
167 
168 #ifdef EQUIVTYPES
insert_type_rule(avtab_key_t * k,avtab_datum_t * d,struct avtab_node * type_rules)169 static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
170 			    struct avtab_node *type_rules)
171 {
172 	struct avtab_node *p, *c, *n;
173 
174 	for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
175 		/*
176 		 * Find the insertion point, keeping the list
177 		 * ordered by source type, then target type, then
178 		 * target class.
179 		 */
180 		if (k->source_type < c->key.source_type)
181 			break;
182 		if (k->source_type == c->key.source_type &&
183 		    k->target_type < c->key.target_type)
184 			break;
185 		if (k->source_type == c->key.source_type &&
186 		    k->target_type == c->key.target_type &&
187 		    k->target_class < c->key.target_class)
188 			break;
189 	}
190 
191 	/* Insert the rule */
192 	n = malloc(sizeof(struct avtab_node));
193 	if (!n) {
194 		fprintf(stderr, "out of memory\n");
195 		exit(1);
196 	}
197 
198 	n->key = *k;
199 	n->datum = *d;
200 	n->next = p->next;
201 	p->next = n;
202 	return 0;
203 }
204 
create_type_rules(avtab_key_t * k,avtab_datum_t * d,void * args)205 static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
206 {
207 	struct avtab_node *type_rules = args;
208 
209 	if (d->specified & AVTAB_ALLOWED) {
210 		/*
211 		 * Insert the rule into the lists for both
212 		 * the source type and the target type.
213 		 */
214 		if (insert_type_rule(k, d, &type_rules[k->source_type - 1]))
215 			return -1;
216 		if (insert_type_rule(k, d, &type_rules[k->target_type - 1]))
217 			return -1;
218 	}
219 
220 	return 0;
221 }
222 
free_type_rules(struct avtab_node * l)223 static void free_type_rules(struct avtab_node *l)
224 {
225 	struct avtab_node *tmp;
226 
227 	while (l) {
228 		tmp = l;
229 		l = l->next;
230 		free(tmp);
231 	}
232 }
233 
identify_equiv_types(void)234 static int identify_equiv_types(void)
235 {
236 	struct avtab_node *type_rules, *l1, *l2;
237 	int i, j;
238 
239 	/*
240 	 * Create a list of access vector rules for each type
241 	 * from the access vector table.
242 	 */
243 	type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim);
244 	if (!type_rules) {
245 		fprintf(stderr, "out of memory\n");
246 		exit(1);
247 	}
248 	memset(type_rules, 0,
249 	       sizeof(struct avtab_node) * policydb.p_types.nprim);
250 	if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules))
251 		exit(1);
252 
253 	/*
254 	 * Compare the type lists and identify equivalent types.
255 	 */
256 	for (i = 0; i < policydb.p_types.nprim - 1; i++) {
257 		if (!type_rules[i].next)
258 			continue;
259 		for (j = i + 1; j < policydb.p_types.nprim; j++) {
260 			for (l1 = type_rules[i].next, l2 = type_rules[j].next;
261 			     l1 && l2; l1 = l1->next, l2 = l2->next) {
262 				if (l2->key.source_type == (j + 1)) {
263 					if (l1->key.source_type != (i + 1))
264 						break;
265 				} else {
266 					if (l1->key.source_type !=
267 					    l2->key.source_type)
268 						break;
269 				}
270 				if (l2->key.target_type == (j + 1)) {
271 					if (l1->key.target_type != (i + 1))
272 						break;
273 				} else {
274 					if (l1->key.target_type !=
275 					    l2->key.target_type)
276 						break;
277 				}
278 				if (l1->key.target_class != l2->key.target_class
279 				    || l1->datum.allowed != l2->datum.allowed)
280 					break;
281 			}
282 			if (l1 || l2)
283 				continue;
284 			free_type_rules(type_rules[j].next);
285 			type_rules[j].next = NULL;
286 			printf("Types %s and %s are equivalent.\n",
287 			       policydb.p_type_val_to_name[i],
288 			       policydb.p_type_val_to_name[j]);
289 		}
290 		free_type_rules(type_rules[i].next);
291 		type_rules[i].next = NULL;
292 	}
293 
294 	free(type_rules);
295 	return 0;
296 }
297 #endif
298 
display_bools(void)299 static int display_bools(void)
300 {
301 	uint32_t i;
302 
303 	for (i = 0; i < policydbp->p_bools.nprim; i++) {
304 		printf("%s : %d\n", policydbp->p_bool_val_to_name[i],
305 		       policydbp->bool_val_to_struct[i]->state);
306 	}
307 	return 0;
308 }
309 
display_expr(const cond_expr_t * exp)310 static void display_expr(const cond_expr_t * exp)
311 {
312 
313 	const cond_expr_t *cur;
314 	for (cur = exp; cur != NULL; cur = cur->next) {
315 		switch (cur->expr_type) {
316 		case COND_BOOL:
317 			printf("%s ",
318 			       policydbp->p_bool_val_to_name[cur->boolean - 1]);
319 			break;
320 		case COND_NOT:
321 			printf("! ");
322 			break;
323 		case COND_OR:
324 			printf("|| ");
325 			break;
326 		case COND_AND:
327 			printf("&& ");
328 			break;
329 		case COND_XOR:
330 			printf("^ ");
331 			break;
332 		case COND_EQ:
333 			printf("== ");
334 			break;
335 		case COND_NEQ:
336 			printf("!= ");
337 			break;
338 		default:
339 			printf("error!");
340 			break;
341 		}
342 	}
343 }
344 
display_cond_expressions(void)345 static int display_cond_expressions(void)
346 {
347 	const cond_node_t *cur;
348 
349 	for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) {
350 		printf("expression: ");
351 		display_expr(cur->expr);
352 		printf("current state: %d\n", cur->cur_state);
353 	}
354 	return 0;
355 }
356 
change_bool(const char * name,int state)357 static int change_bool(const char *name, int state)
358 {
359 	cond_bool_datum_t *boolean;
360 
361 	boolean = hashtab_search(policydbp->p_bools.table, name);
362 	if (boolean == NULL) {
363 		printf("Could not find bool %s\n", name);
364 		return -1;
365 	}
366 	boolean->state = state;
367 	evaluate_conds(policydbp);
368 	return 0;
369 }
370 
check_level(hashtab_key_t key,hashtab_datum_t datum,void * arg)371 static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused)))
372 {
373 	level_datum_t *levdatum = (level_datum_t *) datum;
374 
375 	if (!levdatum->isalias && levdatum->notdefined) {
376 		fprintf(stderr, "Error:  sensitivity %s was not used in a level definition!\n",
377 				key);
378 		return -1;
379 	}
380 	return 0;
381 }
382 
main(int argc,char ** argv)383 int main(int argc, char **argv)
384 {
385 	policydb_t parse_policy;
386 	sepol_security_class_t tclass;
387 	sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid;
388 	sepol_security_context_t scontext;
389 	struct sepol_av_decision avd;
390 	class_datum_t *cladatum;
391 	const char *file = txtfile;
392 	char ans[80 + 1], *path, *fstype;
393 	const char *outfile = NULL;
394 	size_t scontext_len, pathlen;
395 	unsigned int i;
396 	unsigned int protocol, port;
397 	unsigned int binary = 0, debug = 0, sort = 0, cil = 0, conf = 0, optimize = 0, disable_neverallow = 0;
398 	struct val_to_name v;
399 	int ret, ch, fd, target = SEPOL_TARGET_SELINUX;
400 	unsigned int policyvers = 0;
401 	unsigned int nel, uret;
402 	struct stat sb;
403 	void *map;
404 	FILE *outfp = NULL;
405 	char *name;
406 	int state;
407 	int show_version = 0;
408 	char *reason_buf = NULL;
409 	unsigned int reason;
410 	int flags;
411 	struct policy_file pf;
412 	const struct option long_options[] = {
413 		{"output", required_argument, NULL, 'o'},
414 		{"target", required_argument, NULL, 't'},
415 		{"binary", no_argument, NULL, 'b'},
416 		{"debug", no_argument, NULL, 'd'},
417 		{"version", no_argument, NULL, 'V'},
418 		{"handle-unknown", required_argument, NULL, 'U'},
419 		{"mls", no_argument, NULL, 'M'},
420 		{"disable-neverallow", no_argument, NULL, 'N'},
421 		{"cil", no_argument, NULL, 'C'},
422 		{"conf",no_argument, NULL, 'F'},
423 		{"sort", no_argument, NULL, 'S'},
424 		{"optimize", no_argument, NULL, 'O'},
425 		{"werror", no_argument, NULL, 'E'},
426 		{"help", no_argument, NULL, 'h'},
427 		{NULL, 0, NULL, 0}
428 	};
429 
430 	while ((ch = getopt_long(argc, argv, "o:t:dbU:MNCFSVc:OEh", long_options, NULL)) != -1) {
431 		switch (ch) {
432 		case 'o':
433 			outfile = optarg;
434 			break;
435 		case 't':
436 			if (!strcasecmp(optarg, "Xen"))
437 				target = SEPOL_TARGET_XEN;
438 			else if (!strcasecmp(optarg, "SELinux"))
439 				target = SEPOL_TARGET_SELINUX;
440 			else{
441 				fprintf(stderr, "%s:  Unknown target platform:"
442 					"%s\n", argv[0], optarg);
443 				exit(1);
444 			}
445 			break;
446 		case 'b':
447 			binary = 1;
448 			file = binfile;
449 			break;
450 		case 'd':
451 			debug = 1;
452 			break;
453 		case 'V':
454 			show_version = 1;
455 			break;
456 		case 'U':
457 			if (!strcasecmp(optarg, "deny")) {
458 				handle_unknown = DENY_UNKNOWN;
459 				break;
460 			}
461 			if (!strcasecmp(optarg, "allow")) {
462 				handle_unknown = ALLOW_UNKNOWN;
463 				break;
464 			}
465 			if (!strcasecmp(optarg, "reject")) {
466 				handle_unknown = REJECT_UNKNOWN;
467 				break;
468 			}
469 			usage(argv[0]);
470 		case 'S':
471 			sort = 1;
472 			break;
473 		case 'O':
474 			optimize = 1;
475 			break;
476 		case 'M':
477 			mlspol = 1;
478 			break;
479 		case 'N':
480 			disable_neverallow = 1;
481 			break;
482 		case 'C':
483 			cil = 1;
484 			break;
485 		case 'F':
486 			conf = 1;
487 			break;
488 		case 'c':{
489 				long int n;
490 				errno = 0;
491 				n = strtol(optarg, NULL, 10);
492 				if (errno) {
493 					fprintf(stderr,
494 						"Invalid policyvers specified: %s\n",
495 						optarg);
496 					usage(argv[0]);
497 					exit(1);
498 				}
499 				if (n < POLICYDB_VERSION_MIN
500 				    || n > POLICYDB_VERSION_MAX) {
501 					fprintf(stderr,
502 						"policyvers value %ld not in range %d-%d\n",
503 						n, POLICYDB_VERSION_MIN,
504 						POLICYDB_VERSION_MAX);
505 					usage(argv[0]);
506 					exit(1);
507 				}
508 				policyvers = n;
509 				break;
510 			}
511 		case 'E':
512 			 werror = 1;
513 			 break;
514 		case 'h':
515 		default:
516 			usage(argv[0]);
517 		}
518 	}
519 
520 	if (show_version) {
521 		printf("%d (compatibility range %d-%d)\n",
522 			   policyvers ? policyvers : POLICYDB_VERSION_MAX ,
523 		       POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
524 		exit(0);
525 	}
526 
527 	if (optind != argc) {
528 		file = argv[optind++];
529 		if (optind != argc)
530 			usage(argv[0]);
531 	}
532 	/* Set policydb and sidtab used by libsepol service functions
533 	   to my structures, so that I can directly populate and
534 	   manipulate them. */
535 	sepol_set_policydb(&policydb);
536 	sepol_set_sidtab(&sidtab);
537 
538 	if (cil && conf) {
539 		fprintf(stderr, "Can't convert to CIL and policy.conf at the same time\n");
540 		exit(1);
541 	}
542 
543 	if (binary) {
544 		fd = open(file, O_RDONLY);
545 		if (fd < 0) {
546 			fprintf(stderr, "Can't open '%s':  %s\n",
547 				file, strerror(errno));
548 			exit(1);
549 		}
550 		if (fstat(fd, &sb) < 0) {
551 			fprintf(stderr, "Can't stat '%s':  %s\n",
552 				file, strerror(errno));
553 			exit(1);
554 		}
555 		map =
556 		    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
557 			 fd, 0);
558 		if (map == MAP_FAILED) {
559 			fprintf(stderr, "Can't map '%s':  %s\n",
560 				file, strerror(errno));
561 			exit(1);
562 		}
563 		policy_file_init(&pf);
564 		pf.type = PF_USE_MEMORY;
565 		pf.data = map;
566 		pf.len = sb.st_size;
567 		if (policydb_init(&policydb)) {
568 			fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
569 				argv[0]);
570 			exit(1);
571 		}
572 		ret = policydb_read(&policydb, &pf, 1);
573 		if (ret) {
574 			fprintf(stderr,
575 				"%s:  error(s) encountered while parsing configuration\n",
576 				argv[0]);
577 			exit(1);
578 		}
579 		policydbp = &policydb;
580 
581 		/* Check Policy Consistency */
582 		if (policydbp->mls) {
583 			if (!mlspol) {
584 				fprintf(stderr, "%s:  MLS policy, but non-MLS"
585 					" is specified\n", argv[0]);
586 				exit(1);
587 			}
588 		} else {
589 			if (mlspol) {
590 				fprintf(stderr, "%s:  non-MLS policy, but MLS"
591 					" is specified\n", argv[0]);
592 				exit(1);
593 			}
594 		}
595 
596 		if (policydbp->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
597 			if (policyvers > policydbp->policyvers) {
598 				fprintf(stderr, "Binary policies with version <= %u cannot be upgraded\n", POLICYDB_VERSION_PERMISSIVE);
599 			} else if (policyvers) {
600 				policydbp->policyvers = policyvers;
601 			}
602 		} else {
603 			policydbp->policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
604 		}
605 	} else {
606 		if (conf) {
607 			fprintf(stderr, "Can only generate policy.conf from binary policy\n");
608 			exit(1);
609 		}
610 		if (policydb_init(&parse_policy))
611 			exit(1);
612 		/* We build this as a base policy first since that is all the parser understands */
613 		parse_policy.policy_type = POLICY_BASE;
614 		policydb_set_target_platform(&parse_policy, target);
615 
616 		/* Let sepol know if we are dealing with MLS support */
617 		parse_policy.mls = mlspol;
618 		parse_policy.handle_unknown = handle_unknown;
619 		parse_policy.policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
620 
621 		policydbp = &parse_policy;
622 
623 		if (read_source_policy(policydbp, file, "checkpolicy") < 0)
624 			exit(1);
625 
626 		if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
627 			exit(1);
628 
629 		/* Linking takes care of optional avrule blocks */
630 		if (link_modules(NULL, policydbp, NULL, 0, 0)) {
631 			fprintf(stderr, "Error while resolving optionals\n");
632 			exit(1);
633 		}
634 
635 		if (!cil) {
636 			if (policydb_init(&policydb)) {
637 				fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
638 				exit(1);
639 			}
640 			if (expand_module(NULL, policydbp, &policydb, /*verbose=*/0, !disable_neverallow)) {
641 				fprintf(stderr, "Error while expanding policy\n");
642 				exit(1);
643 			}
644 			policydb.policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
645 			policydb_destroy(policydbp);
646 			policydbp = &policydb;
647 		}
648 	}
649 
650 	if (policydb_load_isids(&policydb, &sidtab))
651 		exit(1);
652 
653 	if (optimize && policydbp->policy_type == POLICY_KERN) {
654 		ret = policydb_optimize(policydbp);
655 		if (ret) {
656 			fprintf(stderr, "%s:  error optimizing policy\n", argv[0]);
657 			exit(1);
658 		}
659 	}
660 
661 	if (outfile) {
662 		if (!strcmp(outfile, "-")) {
663 			outfp = stdout;
664 			outfile = "<STDOUT>";
665 		} else {
666 			outfp = fopen(outfile, "w");
667 			if (!outfp) {
668 				perror(outfile);
669 				exit(1);
670 			}
671 		}
672 
673 		if (!cil) {
674 			if (!conf) {
675 				policydb.policy_type = POLICY_KERN;
676 
677 				policy_file_init(&pf);
678 				pf.type = PF_USE_STDIO;
679 				pf.fp = outfp;
680 				if (sort) {
681 					ret = policydb_sort_ocontexts(&policydb);
682 					if (ret) {
683 						fprintf(stderr, "%s:  error sorting ocontexts\n",
684 						argv[0]);
685 						exit(1);
686 					}
687 				}
688 				ret = policydb_write(&policydb, &pf);
689 			} else {
690 				ret = sepol_kernel_policydb_to_conf(outfp, policydbp);
691 			}
692 			if (ret) {
693 				fprintf(stderr, "%s:  error writing %s\n",
694 						argv[0], outfile);
695 				exit(1);
696 			}
697 		} else {
698 			if (binary) {
699 				ret = sepol_kernel_policydb_to_cil(outfp, policydbp);
700 			} else {
701 				ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
702 			}
703 			if (ret) {
704 				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
705 				exit(1);
706 			}
707 		}
708 
709 		if (outfp != stdout) {
710 			if(fclose(outfp)) {
711 				fprintf(stderr, "%s:  error closing %s:  %s\n", argv[0], outfile, strerror(errno));
712 				exit(1);
713 			}
714 		}
715 	} else if (cil) {
716 		fprintf(stderr, "%s:  No file to write CIL was specified\n", argv[0]);
717 		exit(1);
718 	}
719 
720 	if (!debug) {
721 		policydb_destroy(&policydb);
722 		sepol_sidtab_destroy(&sidtab);
723 		exit(0);
724 	}
725 
726       menu:
727 	printf("\nSelect an option:\n");
728 	printf("0)  Call compute_access_vector\n");
729 	printf("1)  Call sid_to_context\n");
730 	printf("2)  Call context_to_sid\n");
731 	printf("3)  Call transition_sid\n");
732 	printf("4)  Call member_sid\n");
733 	printf("5)  Call change_sid\n");
734 	printf("6)  Call list_sids\n");
735 	printf("7)  Call load_policy\n");
736 	printf("8)  Call fs_sid\n");
737 	printf("9)  Call port_sid\n");
738 	printf("a)  Call netif_sid\n");
739 	printf("b)  Call node_sid\n");
740 	printf("c)  Call fs_use\n");
741 	printf("d)  Call genfs_sid\n");
742 	printf("e)  Call get_user_sids\n");
743 	printf("f)  display conditional bools\n");
744 	printf("g)  display conditional expressions\n");
745 	printf("h)  change a boolean value\n");
746 	printf("i)  display constraint expressions\n");
747 	printf("j)  display validatetrans expressions\n");
748 	printf("k)  Call ibpkey_sid\n");
749 	printf("l)  Call ibendport_sid\n");
750 #ifdef EQUIVTYPES
751 	printf("z)  Show equivalent types\n");
752 #endif
753 	printf("m)  Show menu again\n");
754 	printf("q)  Exit\n");
755 	while (1) {
756 		printf("\nChoose:  ");
757 		FGETS(ans, sizeof(ans), stdin);
758 		switch (ans[0]) {
759 		case '0':
760 			printf("source sid?  ");
761 			FGETS(ans, sizeof(ans), stdin);
762 			ssid = atoi(ans);
763 
764 			printf("target sid?  ");
765 			FGETS(ans, sizeof(ans), stdin);
766 			tsid = atoi(ans);
767 
768 			printf("target class?  ");
769 			FGETS(ans, sizeof(ans), stdin);
770 			if (isdigit(ans[0])) {
771 				tclass = atoi(ans);
772 				if (!tclass
773 				    || tclass > policydb.p_classes.nprim) {
774 					printf("\nNo such class.\n");
775 					break;
776 				}
777 				cladatum =
778 				    policydb.class_val_to_struct[tclass - 1];
779 			} else {
780 				ans[strlen(ans) - 1] = 0;
781 				cladatum =
782 				    (class_datum_t *) hashtab_search(policydb.
783 								     p_classes.
784 								     table,
785 								     ans);
786 				if (!cladatum) {
787 					printf("\nNo such class\n");
788 					break;
789 				}
790 				tclass = cladatum->s.value;
791 			}
792 
793 			if (!cladatum->comdatum && !cladatum->permissions.nprim) {
794 				printf
795 				    ("\nNo access vector definition for that class\n");
796 				break;
797 			}
798 			ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
799 			switch (ret) {
800 			case 0:
801 				printf("\nallowed {");
802 				for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
803 					if (avd.allowed & (UINT32_C(1) << (i - 1))) {
804 						v.val = i;
805 						ret =
806 						    hashtab_map(cladatum->
807 								permissions.
808 								table,
809 								find_perm, &v);
810 						if (!ret && cladatum->comdatum) {
811 							ret =
812 							    hashtab_map
813 							    (cladatum->
814 							     comdatum->
815 							     permissions.table,
816 							     find_perm, &v);
817 						}
818 						if (ret)
819 							printf(" %s", v.name);
820 					}
821 				}
822 				printf(" }\n");
823 				break;
824 			case -EINVAL:
825 				printf("\ninvalid sid\n");
826 				break;
827 			default:
828 				printf("return code 0x%x\n", ret);
829 			}
830 			break;
831 		case '1':
832 			printf("sid?  ");
833 			FGETS(ans, sizeof(ans), stdin);
834 			ssid = atoi(ans);
835 			ret = sepol_sid_to_context(ssid,
836 						   &scontext, &scontext_len);
837 			switch (ret) {
838 			case 0:
839 				printf("\nscontext %s\n", scontext);
840 				free(scontext);
841 				break;
842 			case -EINVAL:
843 				printf("\ninvalid sid\n");
844 				break;
845 			case -ENOMEM:
846 				printf("\nout of memory\n");
847 				break;
848 			default:
849 				printf("return code 0x%x\n", ret);
850 			}
851 			break;
852 		case '2':
853 			printf("scontext?  ");
854 			FGETS(ans, sizeof(ans), stdin);
855 			scontext_len = strlen(ans);
856 			ans[scontext_len - 1] = 0;
857 			ret = sepol_context_to_sid(ans, scontext_len, &ssid);
858 			switch (ret) {
859 			case 0:
860 				printf("\nsid %d\n", ssid);
861 				break;
862 			case -EINVAL:
863 				printf("\ninvalid context\n");
864 				break;
865 			case -ENOMEM:
866 				printf("\nout of memory\n");
867 				break;
868 			default:
869 				printf("return code 0x%x\n", ret);
870 			}
871 			break;
872 		case '3':
873 		case '4':
874 		case '5':
875 			ch = ans[0];
876 
877 			printf("source sid?  ");
878 			FGETS(ans, sizeof(ans), stdin);
879 			ssid = atoi(ans);
880 			printf("target sid?  ");
881 			FGETS(ans, sizeof(ans), stdin);
882 			tsid = atoi(ans);
883 
884 			printf("object class?  ");
885 			FGETS(ans, sizeof(ans), stdin);
886 			if (isdigit(ans[0])) {
887 				tclass = atoi(ans);
888 				if (!tclass
889 				    || tclass > policydb.p_classes.nprim) {
890 					printf("\nNo such class.\n");
891 					break;
892 				}
893 			} else {
894 				ans[strlen(ans) - 1] = 0;
895 				cladatum =
896 				    (class_datum_t *) hashtab_search(policydb.
897 								     p_classes.
898 								     table,
899 								     ans);
900 				if (!cladatum) {
901 					printf("\nNo such class\n");
902 					break;
903 				}
904 				tclass = cladatum->s.value;
905 			}
906 
907 			if (ch == '3')
908 				ret =
909 				    sepol_transition_sid(ssid, tsid, tclass,
910 							 &ssid);
911 			else if (ch == '4')
912 				ret =
913 				    sepol_member_sid(ssid, tsid, tclass, &ssid);
914 			else
915 				ret =
916 				    sepol_change_sid(ssid, tsid, tclass, &ssid);
917 			switch (ret) {
918 			case 0:
919 				printf("\nsid %d\n", ssid);
920 				break;
921 			case -EINVAL:
922 				printf("\ninvalid sid\n");
923 				break;
924 			case -ENOMEM:
925 				printf("\nout of memory\n");
926 				break;
927 			default:
928 				printf("return code 0x%x\n", ret);
929 			}
930 			break;
931 		case '6':
932 			sepol_sidtab_map(&sidtab, print_sid, 0);
933 			break;
934 		case '7':
935 			printf("pathname?  ");
936 			FGETS(ans, sizeof(ans), stdin);
937 			pathlen = strlen(ans);
938 			ans[pathlen - 1] = 0;
939 			fd = open(ans, O_RDONLY);
940 			if (fd < 0) {
941 				fprintf(stderr, "Can't open '%s':  %s\n",
942 					ans, strerror(errno));
943 				break;
944 			}
945 			if (fstat(fd, &sb) < 0) {
946 				fprintf(stderr, "Can't stat '%s':  %s\n",
947 					ans, strerror(errno));
948 				break;
949 			}
950 			map =
951 			    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
952 				 MAP_PRIVATE, fd, 0);
953 			if (map == MAP_FAILED) {
954 				fprintf(stderr, "Can't map '%s':  %s\n",
955 					ans, strerror(errno));
956 				break;
957 			}
958 			ret = sepol_load_policy(map, sb.st_size);
959 			switch (ret) {
960 			case 0:
961 				printf("\nsuccess\n");
962 				break;
963 			case -EINVAL:
964 				printf("\ninvalid policy\n");
965 				break;
966 			case -ENOMEM:
967 				printf("\nout of memory\n");
968 				break;
969 			default:
970 				printf("return code 0x%x\n", ret);
971 			}
972 			break;
973 		case '8':
974 			printf("fs kdevname?  ");
975 			FGETS(ans, sizeof(ans), stdin);
976 			ans[strlen(ans) - 1] = 0;
977 			ret = sepol_fs_sid(ans, &ssid, &tsid);
978 			if (ret) {
979 				printf("unknown fs kdevname\n");
980 			} else {
981 				printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
982 			}
983 			break;
984 		case '9':
985 			printf("protocol?  ");
986 			FGETS(ans, sizeof(ans), stdin);
987 			ans[strlen(ans) - 1] = 0;
988 			if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
989 				protocol = IPPROTO_TCP;
990 			else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
991 				protocol = IPPROTO_UDP;
992 			else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
993 				protocol = IPPROTO_DCCP;
994 			else if (!strcmp(ans, "sctp") || !strcmp(ans, "SCTP"))
995 				protocol = IPPROTO_SCTP;
996 			else {
997 				printf("unknown protocol\n");
998 				break;
999 			}
1000 			printf("port? ");
1001 			FGETS(ans, sizeof(ans), stdin);
1002 			port = atoi(ans);
1003 			sepol_port_sid(0, 0, protocol, port, &ssid);
1004 			printf("sid %d\n", ssid);
1005 			break;
1006 		case 'a':
1007 			printf("netif name?  ");
1008 			FGETS(ans, sizeof(ans), stdin);
1009 			ans[strlen(ans) - 1] = 0;
1010 			ret = sepol_netif_sid(ans, &ssid, &tsid);
1011 			if (ret) {
1012 				printf("unknown name\n");
1013 			} else {
1014 				printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
1015 			}
1016 			break;
1017 		case 'b':{
1018 				char *p;
1019 				int family, len;
1020 				struct in_addr addr4;
1021 				struct in6_addr addr6;
1022 
1023 				printf("protocol family? ");
1024 				FGETS(ans, sizeof(ans), stdin);
1025 				ans[strlen(ans) - 1] = 0;
1026 				if (!strcasecmp(ans, "ipv4"))
1027 					family = AF_INET;
1028 				else if (!strcasecmp(ans, "ipv6"))
1029 					family = AF_INET6;
1030 				else {
1031 					printf("unknown protocol family\n");
1032 					break;
1033 				}
1034 
1035 				printf("node address?  ");
1036 				FGETS(ans, sizeof(ans), stdin);
1037 				ans[strlen(ans) - 1] = 0;
1038 
1039 				if (family == AF_INET) {
1040 					p = (char *)&addr4;
1041 					len = sizeof(addr4);
1042 				} else {
1043 					p = (char *)&addr6;
1044 					len = sizeof(addr6);
1045 				}
1046 
1047 				if (inet_pton(family, ans, p) < 1) {
1048 					printf("error parsing address\n");
1049 					break;
1050 				}
1051 
1052 				sepol_node_sid(family, p, len, &ssid);
1053 				printf("sid %d\n", ssid);
1054 				break;
1055 			}
1056 		case 'c':
1057 			printf("fstype?  ");
1058 			FGETS(ans, sizeof(ans), stdin);
1059 			ans[strlen(ans) - 1] = 0;
1060 			sepol_fs_use(ans, &uret, &ssid);
1061 			switch (uret) {
1062 			case SECURITY_FS_USE_XATTR:
1063 				printf("use xattr\n");
1064 				break;
1065 			case SECURITY_FS_USE_TRANS:
1066 				printf("use transition SIDs\n");
1067 				break;
1068 			case SECURITY_FS_USE_TASK:
1069 				printf("use task SIDs\n");
1070 				break;
1071 			case SECURITY_FS_USE_GENFS:
1072 				printf("use genfs\n");
1073 				break;
1074 			case SECURITY_FS_USE_NONE:
1075 				printf("no labeling support\n");
1076 				break;
1077 			}
1078 			printf("sid %d\n", ssid);
1079 			break;
1080 		case 'd':
1081 			printf("fstype?  ");
1082 			FGETS(ans, sizeof(ans), stdin);
1083 			ans[strlen(ans) - 1] = 0;
1084 			fstype = strdup(ans);
1085 			printf("path?  ");
1086 			FGETS(ans, sizeof(ans), stdin);
1087 			ans[strlen(ans) - 1] = 0;
1088 			path = strdup(ans);
1089 			printf("object class?  ");
1090 			FGETS(ans, sizeof(ans), stdin);
1091 			if (isdigit(ans[0])) {
1092 				tclass = atoi(ans);
1093 				if (!tclass
1094 				    || tclass > policydb.p_classes.nprim) {
1095 					printf("\nNo such class.\n");
1096 					break;
1097 				}
1098 			} else {
1099 				ans[strlen(ans) - 1] = 0;
1100 				cladatum =
1101 				    (class_datum_t *) hashtab_search(policydb.
1102 								     p_classes.
1103 								     table,
1104 								     ans);
1105 				if (!cladatum) {
1106 					printf("\nNo such class\n");
1107 					break;
1108 				}
1109 				tclass = cladatum->s.value;
1110 			}
1111 			sepol_genfs_sid(fstype, path, tclass, &ssid);
1112 			printf("sid %d\n", ssid);
1113 			free(fstype);
1114 			free(path);
1115 			break;
1116 		case 'e':
1117 			printf("from SID?  ");
1118 			FGETS(ans, sizeof(ans), stdin);
1119 			ans[strlen(ans) - 1] = 0;
1120 			ssid = atoi(ans);
1121 
1122 			printf("username?  ");
1123 			FGETS(ans, sizeof(ans), stdin);
1124 			ans[strlen(ans) - 1] = 0;
1125 
1126 			ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1127 			switch (ret) {
1128 			case 0:
1129 				if (!nel)
1130 					printf("\nnone\n");
1131 				for (i = 0; i < nel; i++)
1132 					print_sid(sids[i], NULL, NULL);
1133 				free(sids);
1134 				break;
1135 			case -ENOMEM:
1136 				printf("\nout of memory\n");
1137 				break;
1138 			case -EINVAL:
1139 				printf("\ninvalid argument\n");
1140 				break;
1141 			default:
1142 				printf("\nerror\n");
1143 				break;
1144 			}
1145 			break;
1146 		case 'f':
1147 			display_bools();
1148 			break;
1149 		case 'g':
1150 			display_cond_expressions();
1151 			break;
1152 		case 'h':
1153 			printf("name? ");
1154 			FGETS(ans, sizeof(ans), stdin);
1155 			ans[strlen(ans) - 1] = 0;
1156 
1157 			name = strdup(ans);
1158 			if (name == NULL) {
1159 				fprintf(stderr, "couldn't strdup string.\n");
1160 				break;
1161 			}
1162 
1163 			printf("state? ");
1164 			FGETS(ans, sizeof(ans), stdin);
1165 			ans[strlen(ans) - 1] = 0;
1166 
1167 			if (atoi(ans))
1168 				state = 1;
1169 			else
1170 				state = 0;
1171 
1172 			change_bool(name, state);
1173 			free(name);
1174 			break;
1175 		case 'i':
1176 			printf("source sid?  ");
1177 			FGETS(ans, sizeof(ans), stdin);
1178 			ssid = atoi(ans);
1179 
1180 			printf("target sid?  ");
1181 			FGETS(ans, sizeof(ans), stdin);
1182 			tsid = atoi(ans);
1183 
1184 			printf("target class?  ");
1185 			FGETS(ans, sizeof(ans), stdin);
1186 			if (isdigit(ans[0])) {
1187 				tclass = atoi(ans);
1188 				if (!tclass
1189 				    || tclass > policydb.p_classes.nprim) {
1190 					printf("\nNo such class.\n");
1191 					break;
1192 				}
1193 			} else {
1194 				ans[strlen(ans) - 1] = 0;
1195 				cladatum =
1196 				    (class_datum_t *) hashtab_search(policydb.
1197 								     p_classes.
1198 								     table,
1199 								     ans);
1200 				if (!cladatum) {
1201 					printf("\nNo such class\n");
1202 					break;
1203 				}
1204 				tclass = cladatum->s.value;
1205 			}
1206 
1207 			flags = SHOW_GRANTED;
1208 			if (sepol_compute_av_reason_buffer(ssid, tsid,
1209 					tclass, 0, &avd, &reason,
1210 					&reason_buf, flags)) {
1211 				printf("\nconstraint error\n");
1212 				break;
1213 			}
1214 			if (reason_buf) {
1215 				printf("\nConstraint expressions:\n%s",
1216 						reason_buf);
1217 				free(reason_buf);
1218 			} else {
1219 				printf("\nNo constraints found.\n");
1220 			}
1221 			break;
1222 		case 'j':
1223 			printf("old sid?  ");
1224 			FGETS(ans, sizeof(ans), stdin);
1225 			oldsid = atoi(ans);
1226 
1227 			printf("new sid?  ");
1228 			FGETS(ans, sizeof(ans), stdin);
1229 			newsid = atoi(ans);
1230 
1231 			printf("task sid?  ");
1232 			FGETS(ans, sizeof(ans), stdin);
1233 			tasksid = atoi(ans);
1234 
1235 			printf("target class?  ");
1236 			FGETS(ans, sizeof(ans), stdin);
1237 			if (isdigit(ans[0])) {
1238 				tclass = atoi(ans);
1239 				if (!tclass
1240 				    || tclass > policydb.p_classes.nprim) {
1241 					printf("\nNo such class.\n");
1242 					break;
1243 				}
1244 			} else {
1245 				ans[strlen(ans) - 1] = 0;
1246 				cladatum =
1247 				    (class_datum_t *) hashtab_search(policydb.
1248 								     p_classes.
1249 								     table,
1250 								     ans);
1251 				if (!cladatum) {
1252 					printf("\nNo such class\n");
1253 					break;
1254 				}
1255 				tclass = cladatum->s.value;
1256 			}
1257 
1258 			flags = SHOW_GRANTED;
1259 			if (sepol_validate_transition_reason_buffer(oldsid,
1260 						newsid, tasksid, tclass,
1261 						&reason_buf, flags)) {
1262 				printf("\nvalidatetrans error\n");
1263 				break;
1264 			}
1265 			if (reason_buf) {
1266 				printf("\nValidatetrans expressions:\n%s",
1267 						reason_buf);
1268 				free(reason_buf);
1269 			} else {
1270 				printf(
1271 				    "\nNo validatetrans expressions found.\n");
1272 			}
1273 			break;
1274 		case 'k':
1275 			{
1276 				char *p;
1277 				struct in6_addr addr6;
1278 				uint64_t subnet_prefix;
1279 				unsigned int pkey;
1280 
1281 				printf("subnet prefix?  ");
1282 				FGETS(ans, sizeof(ans), stdin);
1283 				ans[strlen(ans) - 1] = 0;
1284 				p = (char *)&addr6;
1285 
1286 				if (inet_pton(AF_INET6, ans, p) < 1) {
1287 					printf("error parsing subnet prefix\n");
1288 					break;
1289 				}
1290 
1291 				memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
1292 				printf("pkey? ");
1293 				FGETS(ans, sizeof(ans), stdin);
1294 				pkey = atoi(ans);
1295 				sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
1296 				printf("sid %d\n", ssid);
1297 			}
1298 			break;
1299 		case 'l':
1300 			printf("device name (eg. mlx4_0)?  ");
1301 			FGETS(ans, sizeof(ans), stdin);
1302 			ans[strlen(ans) - 1] = 0;
1303 
1304 			name = strdup(ans);
1305 			if (!name) {
1306 				fprintf(stderr, "couldn't strdup string.\n");
1307 				break;
1308 			}
1309 
1310 			printf("port? ");
1311 			FGETS(ans, sizeof(ans), stdin);
1312 			port = atoi(ans);
1313 			sepol_ibendport_sid(name, port, &ssid);
1314 			printf("sid %d\n", ssid);
1315 			free(name);
1316 			break;
1317 #ifdef EQUIVTYPES
1318 		case 'z':
1319 			identify_equiv_types();
1320 			break;
1321 #endif
1322 		case 'm':
1323 			goto menu;
1324 		case 'q':
1325 			exit(0);
1326 			break;
1327 		default:
1328 			printf("\nUnknown option %s.\n", ans);
1329 		}
1330 	}
1331 
1332 	return 0;
1333 }
1334 
1335 /* FLASK */
1336