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/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 
    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 }
    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 
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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