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