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/expand.h>
89#include <sepol/policydb/link.h>
90
91#include "queue.h"
92#include "checkpolicy.h"
93#include "parse_util.h"
94
95static policydb_t policydb;
96static sidtab_t sidtab;
97
98extern policydb_t *policydbp;
99extern int mlspol;
100extern int werror;
101
102static int handle_unknown = SEPOL_DENY_UNKNOWN;
103static const char *txtfile = "policy.conf";
104static const char *binfile = "policy";
105
106unsigned int policyvers = 0;
107
108static __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|-] [-S] [-O] "
113	     "[-t target_platform (selinux,xen)] [-E] [-V] [input_file]\n",
114	     progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
115	exit(1);
116}
117
118#define FGETS(out, size, in) \
119do { \
120	if (fgets(out,size,in)==NULL) {	\
121		fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, \
122			strerror(errno)); \
123		exit(1);\
124	} \
125} while (0)
126
127static 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
146struct val_to_name {
147	unsigned int val;
148	char *name;
149};
150
151static 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
167static 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
203static 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
221static 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
232static 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
297static int display_bools(void)
298{
299	uint32_t i;
300
301	for (i = 0; i < policydbp->p_bools.nprim; i++) {
302		printf("%s : %d\n", policydbp->p_bool_val_to_name[i],
303		       policydbp->bool_val_to_struct[i]->state);
304	}
305	return 0;
306}
307
308static void display_expr(const cond_expr_t * exp)
309{
310
311	const cond_expr_t *cur;
312	for (cur = exp; cur != NULL; cur = cur->next) {
313		switch (cur->expr_type) {
314		case COND_BOOL:
315			printf("%s ",
316			       policydbp->p_bool_val_to_name[cur->bool - 1]);
317			break;
318		case COND_NOT:
319			printf("! ");
320			break;
321		case COND_OR:
322			printf("|| ");
323			break;
324		case COND_AND:
325			printf("&& ");
326			break;
327		case COND_XOR:
328			printf("^ ");
329			break;
330		case COND_EQ:
331			printf("== ");
332			break;
333		case COND_NEQ:
334			printf("!= ");
335			break;
336		default:
337			printf("error!");
338			break;
339		}
340	}
341}
342
343static int display_cond_expressions(void)
344{
345	const cond_node_t *cur;
346
347	for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) {
348		printf("expression: ");
349		display_expr(cur->expr);
350		printf("current state: %d\n", cur->cur_state);
351	}
352	return 0;
353}
354
355static int change_bool(const char *name, int state)
356{
357	cond_bool_datum_t *bool;
358
359	bool = hashtab_search(policydbp->p_bools.table, name);
360	if (bool == NULL) {
361		printf("Could not find bool %s\n", name);
362		return -1;
363	}
364	bool->state = state;
365	evaluate_conds(policydbp);
366	return 0;
367}
368
369static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused)))
370{
371	level_datum_t *levdatum = (level_datum_t *) datum;
372
373	if (!levdatum->isalias && !levdatum->defined) {
374		fprintf(stderr,
375			"Error:  sensitivity %s was not used in a level definition!\n",
376			key);
377		return -1;
378	}
379	return 0;
380}
381
382int main(int argc, char **argv)
383{
384	policydb_t parse_policy;
385	sepol_security_class_t tclass;
386	sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid;
387	sepol_security_context_t scontext;
388	struct sepol_av_decision avd;
389	class_datum_t *cladatum;
390	const char *file = txtfile;
391	char ans[80 + 1], *path, *fstype;
392	const char *outfile = NULL;
393	size_t scontext_len, pathlen;
394	unsigned int i;
395	unsigned int protocol, port;
396	unsigned int binary = 0, debug = 0, sort = 0, cil = 0, conf = 0, optimize = 0;
397	struct val_to_name v;
398	int ret, ch, fd, target = SEPOL_TARGET_SELINUX;
399	unsigned int nel, uret;
400	struct stat sb;
401	void *map;
402	FILE *outfp = NULL;
403	char *name;
404	int state;
405	int show_version = 0;
406	char *reason_buf = NULL;
407	unsigned int reason;
408	int flags;
409	struct policy_file pf;
410	const struct option long_options[] = {
411		{"output", required_argument, NULL, 'o'},
412		{"target", required_argument, NULL, 't'},
413		{"binary", no_argument, NULL, 'b'},
414		{"debug", no_argument, NULL, 'd'},
415		{"version", no_argument, NULL, 'V'},
416		{"handle-unknown", required_argument, NULL, 'U'},
417		{"mls", no_argument, NULL, 'M'},
418		{"cil", no_argument, NULL, 'C'},
419		{"conf",no_argument, NULL, 'F'},
420		{"sort", no_argument, NULL, 'S'},
421		{"optimize", no_argument, NULL, 'O'},
422		{"werror", no_argument, NULL, 'E'},
423		{"help", no_argument, NULL, 'h'},
424		{NULL, 0, NULL, 0}
425	};
426
427	while ((ch = getopt_long(argc, argv, "o:t:dbU:MCFSVc:OEh", long_options, NULL)) != -1) {
428		switch (ch) {
429		case 'o':
430			outfile = optarg;
431			break;
432		case 't':
433			if (!strcasecmp(optarg, "Xen"))
434				target = SEPOL_TARGET_XEN;
435			else if (!strcasecmp(optarg, "SELinux"))
436				target = SEPOL_TARGET_SELINUX;
437			else{
438				fprintf(stderr, "%s:  Unknown target platform:"
439					"%s\n", argv[0], optarg);
440				exit(1);
441			}
442			break;
443		case 'b':
444			binary = 1;
445			file = binfile;
446			break;
447		case 'd':
448			debug = 1;
449			break;
450		case 'V':
451			show_version = 1;
452			break;
453		case 'U':
454			if (!strcasecmp(optarg, "deny")) {
455				handle_unknown = DENY_UNKNOWN;
456				break;
457			}
458			if (!strcasecmp(optarg, "allow")) {
459				handle_unknown = ALLOW_UNKNOWN;
460				break;
461			}
462			if (!strcasecmp(optarg, "reject")) {
463				handle_unknown = REJECT_UNKNOWN;
464				break;
465			}
466			usage(argv[0]);
467		case 'S':
468			sort = 1;
469			break;
470		case 'O':
471			optimize = 1;
472			break;
473		case 'M':
474			mlspol = 1;
475			break;
476		case 'C':
477			cil = 1;
478			break;
479		case 'F':
480			conf = 1;
481			break;
482		case 'c':{
483				long int n;
484				errno = 0;
485				n = strtol(optarg, NULL, 10);
486				if (errno) {
487					fprintf(stderr,
488						"Invalid policyvers specified: %s\n",
489						optarg);
490					usage(argv[0]);
491					exit(1);
492				}
493				if (n < POLICYDB_VERSION_MIN
494				    || n > POLICYDB_VERSION_MAX) {
495					fprintf(stderr,
496						"policyvers value %ld not in range %d-%d\n",
497						n, POLICYDB_VERSION_MIN,
498						POLICYDB_VERSION_MAX);
499					usage(argv[0]);
500					exit(1);
501				}
502				policyvers = n;
503				break;
504			}
505		case 'E':
506			 werror = 1;
507			 break;
508		case 'h':
509		default:
510			usage(argv[0]);
511		}
512	}
513
514	if (show_version) {
515		printf("%d (compatibility range %d-%d)\n",
516			   policyvers ? policyvers : POLICYDB_VERSION_MAX ,
517		       POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
518		exit(0);
519	}
520
521	if (optind != argc) {
522		file = argv[optind++];
523		if (optind != argc)
524			usage(argv[0]);
525	}
526	/* Set policydb and sidtab used by libsepol service functions
527	   to my structures, so that I can directly populate and
528	   manipulate them. */
529	sepol_set_policydb(&policydb);
530	sepol_set_sidtab(&sidtab);
531
532	if (cil && conf) {
533		fprintf(stderr, "Can't convert to CIL and policy.conf at the same time\n");
534		exit(1);
535	}
536
537	if (binary) {
538		fd = open(file, O_RDONLY);
539		if (fd < 0) {
540			fprintf(stderr, "Can't open '%s':  %s\n",
541				file, strerror(errno));
542			exit(1);
543		}
544		if (fstat(fd, &sb) < 0) {
545			fprintf(stderr, "Can't stat '%s':  %s\n",
546				file, strerror(errno));
547			exit(1);
548		}
549		map =
550		    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
551			 fd, 0);
552		if (map == MAP_FAILED) {
553			fprintf(stderr, "Can't map '%s':  %s\n",
554				file, strerror(errno));
555			exit(1);
556		}
557		policy_file_init(&pf);
558		pf.type = PF_USE_MEMORY;
559		pf.data = map;
560		pf.len = sb.st_size;
561		if (policydb_init(&policydb)) {
562			fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
563				argv[0]);
564			exit(1);
565		}
566		ret = policydb_read(&policydb, &pf, 1);
567		if (ret) {
568			fprintf(stderr,
569				"%s:  error(s) encountered while parsing configuration\n",
570				argv[0]);
571			exit(1);
572		}
573		policydbp = &policydb;
574
575		/* Check Policy Consistency */
576		if (policydbp->mls) {
577			if (!mlspol) {
578				fprintf(stderr, "%s:  MLS policy, but non-MLS"
579					" is specified\n", argv[0]);
580				exit(1);
581			}
582		} else {
583			if (mlspol) {
584				fprintf(stderr, "%s:  non-MLS policy, but MLS"
585					" is specified\n", argv[0]);
586				exit(1);
587			}
588		}
589
590		if (policydbp->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
591			if (policyvers > policydbp->policyvers) {
592				fprintf(stderr, "Binary policies with version <= %u cannot be upgraded\n", POLICYDB_VERSION_PERMISSIVE);
593			} else if (policyvers) {
594				policydbp->policyvers = policyvers;
595			}
596		} else {
597			policydbp->policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
598		}
599	} else {
600		if (conf) {
601			fprintf(stderr, "Can only generate policy.conf from binary policy\n");
602			exit(1);
603		}
604		if (policydb_init(&parse_policy))
605			exit(1);
606		/* We build this as a base policy first since that is all the parser understands */
607		parse_policy.policy_type = POLICY_BASE;
608		policydb_set_target_platform(&parse_policy, target);
609
610		/* Let sepol know if we are dealing with MLS support */
611		parse_policy.mls = mlspol;
612		parse_policy.handle_unknown = handle_unknown;
613
614		policydbp = &parse_policy;
615
616		if (read_source_policy(policydbp, file, "checkpolicy") < 0)
617			exit(1);
618
619		if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
620			exit(1);
621
622		/* Linking takes care of optional avrule blocks */
623		if (link_modules(NULL, policydbp, NULL, 0, 0)) {
624			fprintf(stderr, "Error while resolving optionals\n");
625			exit(1);
626		}
627
628		if (!cil) {
629			if (policydb_init(&policydb)) {
630				fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
631				exit(1);
632			}
633			if (expand_module(NULL, policydbp, &policydb, 0, 1)) {
634				fprintf(stderr, "Error while expanding policy\n");
635				exit(1);
636			}
637			policydb_destroy(policydbp);
638			policydbp = &policydb;
639		}
640
641		policydbp->policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
642	}
643
644	if (policydb_load_isids(&policydb, &sidtab))
645		exit(1);
646
647	if (optimize && policydbp->policy_type == POLICY_KERN) {
648		ret = policydb_optimize(policydbp);
649		if (ret) {
650			fprintf(stderr, "%s:  error optimizing policy\n", argv[0]);
651			exit(1);
652		}
653	}
654
655	if (outfile) {
656		if (!strcmp(outfile, "-")) {
657			outfp = stdout;
658			outfile = "<STDOUT>";
659		} else {
660			outfp = fopen(outfile, "w");
661			if (!outfp) {
662				perror(outfile);
663				exit(1);
664			}
665		}
666
667		if (!cil) {
668			if (!conf) {
669				policydb.policy_type = POLICY_KERN;
670
671				policy_file_init(&pf);
672				pf.type = PF_USE_STDIO;
673				pf.fp = outfp;
674				if (sort) {
675					ret = policydb_sort_ocontexts(&policydb);
676					if (ret) {
677						fprintf(stderr, "%s:  error sorting ocontexts\n",
678						argv[0]);
679						exit(1);
680					}
681				}
682				ret = policydb_write(&policydb, &pf);
683			} else {
684				ret = sepol_kernel_policydb_to_conf(outfp, policydbp);
685			}
686			if (ret) {
687				fprintf(stderr, "%s:  error writing %s\n",
688						argv[0], outfile);
689				exit(1);
690			}
691		} else {
692			if (binary) {
693				ret = sepol_kernel_policydb_to_cil(outfp, policydbp);
694			} else {
695				ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
696			}
697			if (ret) {
698				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
699				exit(1);
700			}
701		}
702
703		if (outfp != stdout) {
704			if(fclose(outfp)) {
705				fprintf(stderr, "%s:  error closing %s:  %s\n", argv[0], outfile, strerror(errno));
706				exit(1);
707			}
708		}
709	} else if (cil) {
710		fprintf(stderr, "%s:  No file to write CIL was specified\n", argv[0]);
711		exit(1);
712	}
713
714	if (!debug) {
715		policydb_destroy(&policydb);
716		sepol_sidtab_destroy(&sidtab);
717		exit(0);
718	}
719
720      menu:
721	printf("\nSelect an option:\n");
722	printf("0)  Call compute_access_vector\n");
723	printf("1)  Call sid_to_context\n");
724	printf("2)  Call context_to_sid\n");
725	printf("3)  Call transition_sid\n");
726	printf("4)  Call member_sid\n");
727	printf("5)  Call change_sid\n");
728	printf("6)  Call list_sids\n");
729	printf("7)  Call load_policy\n");
730	printf("8)  Call fs_sid\n");
731	printf("9)  Call port_sid\n");
732	printf("a)  Call netif_sid\n");
733	printf("b)  Call node_sid\n");
734	printf("c)  Call fs_use\n");
735	printf("d)  Call genfs_sid\n");
736	printf("e)  Call get_user_sids\n");
737	printf("f)  display conditional bools\n");
738	printf("g)  display conditional expressions\n");
739	printf("h)  change a boolean value\n");
740	printf("i)  display constraint expressions\n");
741	printf("j)  display validatetrans expressions\n");
742	printf("k)  Call ibpkey_sid\n");
743	printf("l)  Call ibendport_sid\n");
744#ifdef EQUIVTYPES
745	printf("z)  Show equivalent types\n");
746#endif
747	printf("m)  Show menu again\n");
748	printf("q)  Exit\n");
749	while (1) {
750		printf("\nChoose:  ");
751		FGETS(ans, sizeof(ans), stdin);
752		switch (ans[0]) {
753		case '0':
754			printf("source sid?  ");
755			FGETS(ans, sizeof(ans), stdin);
756			ssid = atoi(ans);
757
758			printf("target sid?  ");
759			FGETS(ans, sizeof(ans), stdin);
760			tsid = atoi(ans);
761
762			printf("target class?  ");
763			FGETS(ans, sizeof(ans), stdin);
764			if (isdigit(ans[0])) {
765				tclass = atoi(ans);
766				if (!tclass
767				    || tclass > policydb.p_classes.nprim) {
768					printf("\nNo such class.\n");
769					break;
770				}
771				cladatum =
772				    policydb.class_val_to_struct[tclass - 1];
773			} else {
774				ans[strlen(ans) - 1] = 0;
775				cladatum =
776				    (class_datum_t *) hashtab_search(policydb.
777								     p_classes.
778								     table,
779								     ans);
780				if (!cladatum) {
781					printf("\nNo such class\n");
782					break;
783				}
784				tclass = cladatum->s.value;
785			}
786
787			if (!cladatum->comdatum && !cladatum->permissions.nprim) {
788				printf
789				    ("\nNo access vector definition for that class\n");
790				break;
791			}
792			ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
793			switch (ret) {
794			case 0:
795				printf("\nallowed {");
796				for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
797					if (avd.allowed & (UINT32_C(1) << (i - 1))) {
798						v.val = i;
799						ret =
800						    hashtab_map(cladatum->
801								permissions.
802								table,
803								find_perm, &v);
804						if (!ret && cladatum->comdatum) {
805							ret =
806							    hashtab_map
807							    (cladatum->
808							     comdatum->
809							     permissions.table,
810							     find_perm, &v);
811						}
812						if (ret)
813							printf(" %s", v.name);
814					}
815				}
816				printf(" }\n");
817				break;
818			case -EINVAL:
819				printf("\ninvalid sid\n");
820				break;
821			default:
822				printf("return code 0x%x\n", ret);
823			}
824			break;
825		case '1':
826			printf("sid?  ");
827			FGETS(ans, sizeof(ans), stdin);
828			ssid = atoi(ans);
829			ret = sepol_sid_to_context(ssid,
830						   &scontext, &scontext_len);
831			switch (ret) {
832			case 0:
833				printf("\nscontext %s\n", scontext);
834				free(scontext);
835				break;
836			case -EINVAL:
837				printf("\ninvalid sid\n");
838				break;
839			case -ENOMEM:
840				printf("\nout of memory\n");
841				break;
842			default:
843				printf("return code 0x%x\n", ret);
844			}
845			break;
846		case '2':
847			printf("scontext?  ");
848			FGETS(ans, sizeof(ans), stdin);
849			scontext_len = strlen(ans);
850			ans[scontext_len - 1] = 0;
851			ret = sepol_context_to_sid(ans, scontext_len, &ssid);
852			switch (ret) {
853			case 0:
854				printf("\nsid %d\n", ssid);
855				break;
856			case -EINVAL:
857				printf("\ninvalid context\n");
858				break;
859			case -ENOMEM:
860				printf("\nout of memory\n");
861				break;
862			default:
863				printf("return code 0x%x\n", ret);
864			}
865			break;
866		case '3':
867		case '4':
868		case '5':
869			ch = ans[0];
870
871			printf("source sid?  ");
872			FGETS(ans, sizeof(ans), stdin);
873			ssid = atoi(ans);
874			printf("target sid?  ");
875			FGETS(ans, sizeof(ans), stdin);
876			tsid = atoi(ans);
877
878			printf("object class?  ");
879			FGETS(ans, sizeof(ans), stdin);
880			if (isdigit(ans[0])) {
881				tclass = atoi(ans);
882				if (!tclass
883				    || tclass > policydb.p_classes.nprim) {
884					printf("\nNo such class.\n");
885					break;
886				}
887			} else {
888				ans[strlen(ans) - 1] = 0;
889				cladatum =
890				    (class_datum_t *) hashtab_search(policydb.
891								     p_classes.
892								     table,
893								     ans);
894				if (!cladatum) {
895					printf("\nNo such class\n");
896					break;
897				}
898				tclass = cladatum->s.value;
899			}
900
901			if (ch == '3')
902				ret =
903				    sepol_transition_sid(ssid, tsid, tclass,
904							 &ssid);
905			else if (ch == '4')
906				ret =
907				    sepol_member_sid(ssid, tsid, tclass, &ssid);
908			else
909				ret =
910				    sepol_change_sid(ssid, tsid, tclass, &ssid);
911			switch (ret) {
912			case 0:
913				printf("\nsid %d\n", ssid);
914				break;
915			case -EINVAL:
916				printf("\ninvalid sid\n");
917				break;
918			case -ENOMEM:
919				printf("\nout of memory\n");
920				break;
921			default:
922				printf("return code 0x%x\n", ret);
923			}
924			break;
925		case '6':
926			sepol_sidtab_map(&sidtab, print_sid, 0);
927			break;
928		case '7':
929			printf("pathname?  ");
930			FGETS(ans, sizeof(ans), stdin);
931			pathlen = strlen(ans);
932			ans[pathlen - 1] = 0;
933			fd = open(ans, O_RDONLY);
934			if (fd < 0) {
935				fprintf(stderr, "Can't open '%s':  %s\n",
936					ans, strerror(errno));
937				break;
938			}
939			if (fstat(fd, &sb) < 0) {
940				fprintf(stderr, "Can't stat '%s':  %s\n",
941					ans, strerror(errno));
942				break;
943			}
944			map =
945			    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
946				 MAP_PRIVATE, fd, 0);
947			if (map == MAP_FAILED) {
948				fprintf(stderr, "Can't map '%s':  %s\n",
949					ans, strerror(errno));
950				break;
951			}
952			ret = sepol_load_policy(map, sb.st_size);
953			switch (ret) {
954			case 0:
955				printf("\nsuccess\n");
956				break;
957			case -EINVAL:
958				printf("\ninvalid policy\n");
959				break;
960			case -ENOMEM:
961				printf("\nout of memory\n");
962				break;
963			default:
964				printf("return code 0x%x\n", ret);
965			}
966			break;
967		case '8':
968			printf("fs kdevname?  ");
969			FGETS(ans, sizeof(ans), stdin);
970			ans[strlen(ans) - 1] = 0;
971			ret = sepol_fs_sid(ans, &ssid, &tsid);
972			if (ret) {
973				printf("unknown fs kdevname\n");
974			} else {
975				printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
976			}
977			break;
978		case '9':
979			printf("protocol?  ");
980			FGETS(ans, sizeof(ans), stdin);
981			ans[strlen(ans) - 1] = 0;
982			if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
983				protocol = IPPROTO_TCP;
984			else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
985				protocol = IPPROTO_UDP;
986			else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
987				protocol = IPPROTO_DCCP;
988			else if (!strcmp(ans, "sctp") || !strcmp(ans, "SCTP"))
989				protocol = IPPROTO_SCTP;
990			else {
991				printf("unknown protocol\n");
992				break;
993			}
994			printf("port? ");
995			FGETS(ans, sizeof(ans), stdin);
996			port = atoi(ans);
997			sepol_port_sid(0, 0, protocol, port, &ssid);
998			printf("sid %d\n", ssid);
999			break;
1000		case 'a':
1001			printf("netif name?  ");
1002			FGETS(ans, sizeof(ans), stdin);
1003			ans[strlen(ans) - 1] = 0;
1004			ret = sepol_netif_sid(ans, &ssid, &tsid);
1005			if (ret) {
1006				printf("unknown name\n");
1007			} else {
1008				printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
1009			}
1010			break;
1011		case 'b':{
1012				char *p;
1013				int family, len;
1014				struct in_addr addr4;
1015				struct in6_addr addr6;
1016
1017				printf("protocol family? ");
1018				FGETS(ans, sizeof(ans), stdin);
1019				ans[strlen(ans) - 1] = 0;
1020				if (!strcasecmp(ans, "ipv4"))
1021					family = AF_INET;
1022				else if (!strcasecmp(ans, "ipv6"))
1023					family = AF_INET6;
1024				else {
1025					printf("unknown protocol family\n");
1026					break;
1027				}
1028
1029				printf("node address?  ");
1030				FGETS(ans, sizeof(ans), stdin);
1031				ans[strlen(ans) - 1] = 0;
1032
1033				if (family == AF_INET) {
1034					p = (char *)&addr4;
1035					len = sizeof(addr4);
1036				} else {
1037					p = (char *)&addr6;
1038					len = sizeof(addr6);
1039				}
1040
1041				if (inet_pton(family, ans, p) < 1) {
1042					printf("error parsing address\n");
1043					break;
1044				}
1045
1046				sepol_node_sid(family, p, len, &ssid);
1047				printf("sid %d\n", ssid);
1048				break;
1049			}
1050		case 'c':
1051			printf("fstype?  ");
1052			FGETS(ans, sizeof(ans), stdin);
1053			ans[strlen(ans) - 1] = 0;
1054			sepol_fs_use(ans, &uret, &ssid);
1055			switch (uret) {
1056			case SECURITY_FS_USE_XATTR:
1057				printf("use xattr\n");
1058				break;
1059			case SECURITY_FS_USE_TRANS:
1060				printf("use transition SIDs\n");
1061				break;
1062			case SECURITY_FS_USE_TASK:
1063				printf("use task SIDs\n");
1064				break;
1065			case SECURITY_FS_USE_GENFS:
1066				printf("use genfs\n");
1067				break;
1068			case SECURITY_FS_USE_NONE:
1069				printf("no labeling support\n");
1070				break;
1071			}
1072			printf("sid %d\n", ssid);
1073			break;
1074		case 'd':
1075			printf("fstype?  ");
1076			FGETS(ans, sizeof(ans), stdin);
1077			ans[strlen(ans) - 1] = 0;
1078			fstype = strdup(ans);
1079			printf("path?  ");
1080			FGETS(ans, sizeof(ans), stdin);
1081			ans[strlen(ans) - 1] = 0;
1082			path = strdup(ans);
1083			printf("object class?  ");
1084			FGETS(ans, sizeof(ans), stdin);
1085			if (isdigit(ans[0])) {
1086				tclass = atoi(ans);
1087				if (!tclass
1088				    || tclass > policydb.p_classes.nprim) {
1089					printf("\nNo such class.\n");
1090					break;
1091				}
1092			} else {
1093				ans[strlen(ans) - 1] = 0;
1094				cladatum =
1095				    (class_datum_t *) hashtab_search(policydb.
1096								     p_classes.
1097								     table,
1098								     ans);
1099				if (!cladatum) {
1100					printf("\nNo such class\n");
1101					break;
1102				}
1103				tclass = cladatum->s.value;
1104			}
1105			sepol_genfs_sid(fstype, path, tclass, &ssid);
1106			printf("sid %d\n", ssid);
1107			free(fstype);
1108			free(path);
1109			break;
1110		case 'e':
1111			printf("from SID?  ");
1112			FGETS(ans, sizeof(ans), stdin);
1113			ans[strlen(ans) - 1] = 0;
1114			ssid = atoi(ans);
1115
1116			printf("username?  ");
1117			FGETS(ans, sizeof(ans), stdin);
1118			ans[strlen(ans) - 1] = 0;
1119
1120			ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1121			switch (ret) {
1122			case 0:
1123				if (!nel)
1124					printf("\nnone\n");
1125				for (i = 0; i < nel; i++)
1126					print_sid(sids[i], NULL, NULL);
1127				free(sids);
1128				break;
1129			case -ENOMEM:
1130				printf("\nout of memory\n");
1131				break;
1132			case -EINVAL:
1133				printf("\ninvalid argument\n");
1134				break;
1135			default:
1136				printf("\nerror\n");
1137				break;
1138			}
1139			break;
1140		case 'f':
1141			display_bools();
1142			break;
1143		case 'g':
1144			display_cond_expressions();
1145			break;
1146		case 'h':
1147			printf("name? ");
1148			FGETS(ans, sizeof(ans), stdin);
1149			ans[strlen(ans) - 1] = 0;
1150
1151			name = strdup(ans);
1152			if (name == NULL) {
1153				fprintf(stderr, "couldn't strdup string.\n");
1154				break;
1155			}
1156
1157			printf("state? ");
1158			FGETS(ans, sizeof(ans), stdin);
1159			ans[strlen(ans) - 1] = 0;
1160
1161			if (atoi(ans))
1162				state = 1;
1163			else
1164				state = 0;
1165
1166			change_bool(name, state);
1167			free(name);
1168			break;
1169		case 'i':
1170			printf("source sid?  ");
1171			FGETS(ans, sizeof(ans), stdin);
1172			ssid = atoi(ans);
1173
1174			printf("target sid?  ");
1175			FGETS(ans, sizeof(ans), stdin);
1176			tsid = atoi(ans);
1177
1178			printf("target class?  ");
1179			FGETS(ans, sizeof(ans), stdin);
1180			if (isdigit(ans[0])) {
1181				tclass = atoi(ans);
1182				if (!tclass
1183				    || tclass > policydb.p_classes.nprim) {
1184					printf("\nNo such class.\n");
1185					break;
1186				}
1187			} else {
1188				ans[strlen(ans) - 1] = 0;
1189				cladatum =
1190				    (class_datum_t *) hashtab_search(policydb.
1191								     p_classes.
1192								     table,
1193								     ans);
1194				if (!cladatum) {
1195					printf("\nNo such class\n");
1196					break;
1197				}
1198				tclass = cladatum->s.value;
1199			}
1200
1201			flags = SHOW_GRANTED;
1202			if (sepol_compute_av_reason_buffer(ssid, tsid,
1203					tclass, 0, &avd, &reason,
1204					&reason_buf, flags)) {
1205				printf("\nconstraint error\n");
1206				break;
1207			}
1208			if (reason_buf) {
1209				printf("\nConstraint expressions:\n%s",
1210						reason_buf);
1211				free(reason_buf);
1212			} else {
1213				printf("\nNo constraints found.\n");
1214			}
1215			break;
1216		case 'j':
1217			printf("old sid?  ");
1218			FGETS(ans, sizeof(ans), stdin);
1219			oldsid = atoi(ans);
1220
1221			printf("new sid?  ");
1222			FGETS(ans, sizeof(ans), stdin);
1223			newsid = atoi(ans);
1224
1225			printf("task sid?  ");
1226			FGETS(ans, sizeof(ans), stdin);
1227			tasksid = atoi(ans);
1228
1229			printf("target class?  ");
1230			FGETS(ans, sizeof(ans), stdin);
1231			if (isdigit(ans[0])) {
1232				tclass = atoi(ans);
1233				if (!tclass
1234				    || tclass > policydb.p_classes.nprim) {
1235					printf("\nNo such class.\n");
1236					break;
1237				}
1238			} else {
1239				ans[strlen(ans) - 1] = 0;
1240				cladatum =
1241				    (class_datum_t *) hashtab_search(policydb.
1242								     p_classes.
1243								     table,
1244								     ans);
1245				if (!cladatum) {
1246					printf("\nNo such class\n");
1247					break;
1248				}
1249				tclass = cladatum->s.value;
1250			}
1251
1252			flags = SHOW_GRANTED;
1253			if (sepol_validate_transition_reason_buffer(oldsid,
1254						newsid, tasksid, tclass,
1255						&reason_buf, flags)) {
1256				printf("\nvalidatetrans error\n");
1257				break;
1258			}
1259			if (reason_buf) {
1260				printf("\nValidatetrans expressions:\n%s",
1261						reason_buf);
1262				free(reason_buf);
1263			} else {
1264				printf(
1265				    "\nNo validatetrans expressions found.\n");
1266			}
1267			break;
1268		case 'k':
1269			{
1270				char *p;
1271				struct in6_addr addr6;
1272				uint64_t subnet_prefix;
1273				unsigned int pkey;
1274
1275				printf("subnet prefix?  ");
1276				FGETS(ans, sizeof(ans), stdin);
1277				ans[strlen(ans) - 1] = 0;
1278				p = (char *)&addr6;
1279
1280				if (inet_pton(AF_INET6, ans, p) < 1) {
1281					printf("error parsing subnet prefix\n");
1282					break;
1283				}
1284
1285				memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
1286				printf("pkey? ");
1287				FGETS(ans, sizeof(ans), stdin);
1288				pkey = atoi(ans);
1289				sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
1290				printf("sid %d\n", ssid);
1291			}
1292			break;
1293		case 'l':
1294			printf("device name (eg. mlx4_0)?  ");
1295			FGETS(ans, sizeof(ans), stdin);
1296			ans[strlen(ans) - 1] = 0;
1297
1298			name = strdup(ans);
1299			if (!name) {
1300				fprintf(stderr, "couldn't strdup string.\n");
1301				break;
1302			}
1303
1304			printf("port? ");
1305			FGETS(ans, sizeof(ans), stdin);
1306			port = atoi(ans);
1307			sepol_ibendport_sid(name, port, &ssid);
1308			printf("sid %d\n", ssid);
1309			free(name);
1310			break;
1311#ifdef EQUIVTYPES
1312		case 'z':
1313			identify_equiv_types();
1314			break;
1315#endif
1316		case 'm':
1317			goto menu;
1318		case 'q':
1319			exit(0);
1320			break;
1321		default:
1322			printf("\nUnknown option %s.\n", ans);
1323		}
1324	}
1325
1326	return 0;
1327}
1328
1329/* FLASK */
1330