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