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