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