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