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