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