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