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;
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	struct policy_file pf;
399	struct option long_options[] = {
400		{"output", required_argument, NULL, 'o'},
401		{"target", required_argument, NULL, 't'},
402		{"binary", no_argument, NULL, 'b'},
403		{"debug", no_argument, NULL, 'd'},
404		{"version", no_argument, NULL, 'V'},
405		{"handle-unknown", optional_argument, NULL, 'U'},
406		{"mls", no_argument, NULL, 'M'},
407		{"help", no_argument, NULL, 'h'},
408		{NULL, 0, NULL, 0}
409	};
410
411	while ((ch = getopt_long(argc, argv, "o:t:dbU:MVc:h", long_options, NULL)) != -1) {
412		switch (ch) {
413		case 'o':
414			outfile = optarg;
415			break;
416		case 't':
417			if (!strcasecmp(optarg, "Xen"))
418				target = SEPOL_TARGET_XEN;
419			else if (!strcasecmp(optarg, "SELinux"))
420				target = SEPOL_TARGET_SELINUX;
421			else{
422				fprintf(stderr, "%s:  Unknown target platform:"
423					"%s\n", argv[0], optarg);
424				exit(1);
425			}
426			break;
427		case 'b':
428			binary = 1;
429			file = binfile;
430			break;
431		case 'd':
432			debug = 1;
433			break;
434		case 'V':
435			show_version = 1;
436			break;
437		case 'U':
438			if (!strcasecmp(optarg, "deny")) {
439				handle_unknown = DENY_UNKNOWN;
440				break;
441			}
442			if (!strcasecmp(optarg, "allow")) {
443				handle_unknown = ALLOW_UNKNOWN;
444				break;
445			}
446			if (!strcasecmp(optarg, "reject")) {
447				handle_unknown = REJECT_UNKNOWN;
448				break;
449			}
450			usage(argv[0]);
451		case 'M':
452			mlspol = 1;
453			break;
454		case 'c':{
455				long int n = strtol(optarg, NULL, 10);
456				if (errno) {
457					fprintf(stderr,
458						"Invalid policyvers specified: %s\n",
459						optarg);
460					usage(argv[0]);
461					exit(1);
462				}
463				if (n < POLICYDB_VERSION_MIN
464				    || n > POLICYDB_VERSION_MAX) {
465					fprintf(stderr,
466						"policyvers value %ld not in range %d-%d\n",
467						n, POLICYDB_VERSION_MIN,
468						POLICYDB_VERSION_MAX);
469					usage(argv[0]);
470					exit(1);
471				}
472				if (policyvers != n)
473					policyvers = n;
474				break;
475			}
476		case 'h':
477		default:
478			usage(argv[0]);
479		}
480	}
481
482	if (show_version) {
483		printf("%d (compatibility range %d-%d)\n", policyvers,
484		       POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
485		exit(0);
486	}
487
488	if (optind != argc) {
489		file = argv[optind++];
490		if (optind != argc)
491			usage(argv[0]);
492	}
493	printf("%s:  loading policy configuration from %s\n", argv[0], file);
494
495	/* Set policydb and sidtab used by libsepol service functions
496	   to my structures, so that I can directly populate and
497	   manipulate them. */
498	sepol_set_policydb(&policydb);
499	sepol_set_sidtab(&sidtab);
500
501	if (binary) {
502		fd = open(file, O_RDONLY);
503		if (fd < 0) {
504			fprintf(stderr, "Can't open '%s':  %s\n",
505				file, strerror(errno));
506			exit(1);
507		}
508		if (fstat(fd, &sb) < 0) {
509			fprintf(stderr, "Can't stat '%s':  %s\n",
510				file, strerror(errno));
511			exit(1);
512		}
513		map =
514		    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
515			 fd, 0);
516		if (map == MAP_FAILED) {
517			fprintf(stderr, "Can't map '%s':  %s\n",
518				file, strerror(errno));
519			exit(1);
520		}
521		policy_file_init(&pf);
522		pf.type = PF_USE_MEMORY;
523		pf.data = map;
524		pf.len = sb.st_size;
525		if (policydb_init(&policydb)) {
526			fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
527				argv[0]);
528			exit(1);
529		}
530		ret = policydb_read(&policydb, &pf, 1);
531		if (ret) {
532			fprintf(stderr,
533				"%s:  error(s) encountered while parsing configuration\n",
534				argv[0]);
535			exit(1);
536		}
537		policydbp = &policydb;
538
539		/* Check Policy Consistency */
540		if (policydbp->mls) {
541			if (!mlspol) {
542				fprintf(stderr, "%s:  MLS policy, but non-MLS"
543					" is specified\n", argv[0]);
544				exit(1);
545			}
546		} else {
547			if (mlspol) {
548				fprintf(stderr, "%s:  non-MLS policy, but MLS"
549					" is specified\n", argv[0]);
550				exit(1);
551			}
552		}
553	} else {
554		policydb_t parse_policy;
555
556		if (policydb_init(&parse_policy))
557			exit(1);
558		/* We build this as a base policy first since that is all the parser understands */
559		parse_policy.policy_type = POLICY_BASE;
560		policydb_set_target_platform(&parse_policy, target);
561
562		/* Let sepol know if we are dealing with MLS support */
563		parse_policy.mls = mlspol;
564		parse_policy.handle_unknown = handle_unknown;
565
566		policydbp = &parse_policy;
567
568		if (read_source_policy(policydbp, file, "checkpolicy") < 0)
569			exit(1);
570
571		if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
572			exit(1);
573
574		if (policydb_init(&policydb)) {
575			fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
576			exit(1);
577		}
578
579		/* Linking takes care of optional avrule blocks */
580		if (link_modules(NULL, &parse_policy, NULL, 0, 0)) {
581			fprintf(stderr, "Error while resolving optionals\n");
582			exit(1);
583		}
584
585		if (expand_module(NULL, &parse_policy, &policydb, 0, 1)) {
586			fprintf(stderr, "Error while expanding policy\n");
587			exit(1);
588		}
589		policydb_destroy(&parse_policy);
590		policydbp = &policydb;
591	}
592
593	if (policydb_load_isids(&policydb, &sidtab))
594		exit(1);
595
596	printf("%s:  policy configuration loaded\n", argv[0]);
597
598	if (outfile) {
599		printf
600		    ("%s:  writing binary representation (version %d) to %s\n",
601		     argv[0], policyvers, outfile);
602		outfp = fopen(outfile, "w");
603		if (!outfp) {
604			perror(outfile);
605			exit(1);
606		}
607
608		policydb.policy_type = POLICY_KERN;
609		policydb.policyvers = policyvers;
610
611		policy_file_init(&pf);
612		pf.type = PF_USE_STDIO;
613		pf.fp = outfp;
614		ret = policydb_write(&policydb, &pf);
615		if (ret) {
616			fprintf(stderr, "%s:  error writing %s\n",
617				argv[0], outfile);
618			exit(1);
619		}
620		fclose(outfp);
621	}
622	if (!debug) {
623		policydb_destroy(&policydb);
624		exit(0);
625	}
626
627      menu:
628	printf("\nSelect an option:\n");
629	printf("0)  Call compute_access_vector\n");
630	printf("1)  Call sid_to_context\n");
631	printf("2)  Call context_to_sid\n");
632	printf("3)  Call transition_sid\n");
633	printf("4)  Call member_sid\n");
634	printf("5)  Call change_sid\n");
635	printf("6)  Call list_sids\n");
636	printf("7)  Call load_policy\n");
637	printf("8)  Call fs_sid\n");
638	printf("9)  Call port_sid\n");
639	printf("a)  Call netif_sid\n");
640	printf("b)  Call node_sid\n");
641	printf("c)  Call fs_use\n");
642	printf("d)  Call genfs_sid\n");
643	printf("e)  Call get_user_sids\n");
644	printf("f)  display conditional bools\n");
645	printf("g)  display conditional expressions\n");
646	printf("h)  change a boolean value\n");
647#ifdef EQUIVTYPES
648	printf("z)  Show equivalent types\n");
649#endif
650	printf("m)  Show menu again\n");
651	printf("q)  Exit\n");
652	while (1) {
653		printf("\nChoose:  ");
654		FGETS(ans, sizeof(ans), stdin);
655		switch (ans[0]) {
656		case '0':
657			printf("source sid?  ");
658			FGETS(ans, sizeof(ans), stdin);
659			ssid = atoi(ans);
660
661			printf("target sid?  ");
662			FGETS(ans, sizeof(ans), stdin);
663			tsid = atoi(ans);
664
665			printf("target class?  ");
666			FGETS(ans, sizeof(ans), stdin);
667			if (isdigit(ans[0])) {
668				tclass = atoi(ans);
669				if (!tclass
670				    || tclass > policydb.p_classes.nprim) {
671					printf("\nNo such class.\n");
672					break;
673				}
674				cladatum =
675				    policydb.class_val_to_struct[tclass - 1];
676			} else {
677				ans[strlen(ans) - 1] = 0;
678				cladatum =
679				    (class_datum_t *) hashtab_search(policydb.
680								     p_classes.
681								     table,
682								     ans);
683				if (!cladatum) {
684					printf("\nNo such class\n");
685					break;
686				}
687				tclass = cladatum->s.value;
688			}
689
690			if (!cladatum->comdatum && !cladatum->permissions.nprim) {
691				printf
692				    ("\nNo access vector definition for that class\n");
693				break;
694			}
695			ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
696			switch (ret) {
697			case 0:
698				printf("\nallowed {");
699				for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
700					if (avd.allowed & (1 << (i - 1))) {
701						v.val = i;
702						ret =
703						    hashtab_map(cladatum->
704								permissions.
705								table,
706								find_perm, &v);
707						if (!ret && cladatum->comdatum) {
708							ret =
709							    hashtab_map
710							    (cladatum->
711							     comdatum->
712							     permissions.table,
713							     find_perm, &v);
714						}
715						if (ret)
716							printf(" %s", v.name);
717					}
718				}
719				printf(" }\n");
720				break;
721			case -EINVAL:
722				printf("\ninvalid sid\n");
723				break;
724			default:
725				printf("return code 0x%x\n", ret);
726			}
727			break;
728		case '1':
729			printf("sid?  ");
730			FGETS(ans, sizeof(ans), stdin);
731			ssid = atoi(ans);
732			ret = sepol_sid_to_context(ssid,
733						   &scontext, &scontext_len);
734			switch (ret) {
735			case 0:
736				printf("\nscontext %s\n", scontext);
737				free(scontext);
738				break;
739			case -EINVAL:
740				printf("\ninvalid sid\n");
741				break;
742			case -ENOMEM:
743				printf("\nout of memory\n");
744				break;
745			default:
746				printf("return code 0x%x\n", ret);
747			}
748			break;
749		case '2':
750			printf("scontext?  ");
751			FGETS(ans, sizeof(ans), stdin);
752			scontext_len = strlen(ans);
753			ans[scontext_len - 1] = 0;
754			ret = sepol_context_to_sid(ans, scontext_len, &ssid);
755			switch (ret) {
756			case 0:
757				printf("\nsid %d\n", ssid);
758				break;
759			case -EINVAL:
760				printf("\ninvalid context\n");
761				break;
762			case -ENOMEM:
763				printf("\nout of memory\n");
764				break;
765			default:
766				printf("return code 0x%x\n", ret);
767			}
768			break;
769		case '3':
770		case '4':
771		case '5':
772			ch = ans[0];
773
774			printf("source sid?  ");
775			FGETS(ans, sizeof(ans), stdin);
776			ssid = atoi(ans);
777			printf("target sid?  ");
778			FGETS(ans, sizeof(ans), stdin);
779			tsid = atoi(ans);
780
781			printf("object class?  ");
782			FGETS(ans, sizeof(ans), stdin);
783			if (isdigit(ans[0])) {
784				tclass = atoi(ans);
785				if (!tclass
786				    || tclass > policydb.p_classes.nprim) {
787					printf("\nNo such class.\n");
788					break;
789				}
790			} else {
791				ans[strlen(ans) - 1] = 0;
792				cladatum =
793				    (class_datum_t *) hashtab_search(policydb.
794								     p_classes.
795								     table,
796								     ans);
797				if (!cladatum) {
798					printf("\nNo such class\n");
799					break;
800				}
801				tclass = cladatum->s.value;
802			}
803
804			if (ch == '3')
805				ret =
806				    sepol_transition_sid(ssid, tsid, tclass,
807							 &ssid);
808			else if (ch == '4')
809				ret =
810				    sepol_member_sid(ssid, tsid, tclass, &ssid);
811			else
812				ret =
813				    sepol_change_sid(ssid, tsid, tclass, &ssid);
814			switch (ret) {
815			case 0:
816				printf("\nsid %d\n", ssid);
817				break;
818			case -EINVAL:
819				printf("\ninvalid sid\n");
820				break;
821			case -ENOMEM:
822				printf("\nout of memory\n");
823				break;
824			default:
825				printf("return code 0x%x\n", ret);
826			}
827			break;
828		case '6':
829			sepol_sidtab_map(&sidtab, print_sid, 0);
830			break;
831		case '7':
832			printf("pathname?  ");
833			FGETS(ans, sizeof(ans), stdin);
834			pathlen = strlen(ans);
835			ans[pathlen - 1] = 0;
836			printf("%s:  loading policy configuration from %s\n",
837			       argv[0], ans);
838			fd = open(ans, O_RDONLY);
839			if (fd < 0) {
840				fprintf(stderr, "Can't open '%s':  %s\n",
841					ans, strerror(errno));
842				break;
843			}
844			if (fstat(fd, &sb) < 0) {
845				fprintf(stderr, "Can't stat '%s':  %s\n",
846					ans, strerror(errno));
847				break;
848			}
849			map =
850			    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
851				 MAP_PRIVATE, fd, 0);
852			if (map == MAP_FAILED) {
853				fprintf(stderr, "Can't map '%s':  %s\n",
854					ans, strerror(errno));
855				break;
856			}
857			ret = sepol_load_policy(map, sb.st_size);
858			switch (ret) {
859			case 0:
860				printf("\nsuccess\n");
861				break;
862			case -EINVAL:
863				printf("\ninvalid policy\n");
864				break;
865			case -ENOMEM:
866				printf("\nout of memory\n");
867				break;
868			default:
869				printf("return code 0x%x\n", ret);
870			}
871			break;
872		case '8':
873			printf("fs kdevname?  ");
874			FGETS(ans, sizeof(ans), stdin);
875			ans[strlen(ans) - 1] = 0;
876			sepol_fs_sid(ans, &ssid, &tsid);
877			printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
878			break;
879		case '9':
880			printf("protocol?  ");
881			FGETS(ans, sizeof(ans), stdin);
882			ans[strlen(ans) - 1] = 0;
883			if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
884				protocol = IPPROTO_TCP;
885			else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
886				protocol = IPPROTO_UDP;
887			else {
888				printf("unknown protocol\n");
889				break;
890			}
891			printf("port? ");
892			FGETS(ans, sizeof(ans), stdin);
893			port = atoi(ans);
894			sepol_port_sid(0, 0, protocol, port, &ssid);
895			printf("sid %d\n", ssid);
896			break;
897		case 'a':
898			printf("netif name?  ");
899			FGETS(ans, sizeof(ans), stdin);
900			ans[strlen(ans) - 1] = 0;
901			sepol_netif_sid(ans, &ssid, &tsid);
902			printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
903			break;
904		case 'b':{
905				char *p;
906				int family, len;
907				struct in_addr addr4;
908				struct in6_addr addr6;
909
910				printf("protocol family? ");
911				FGETS(ans, sizeof(ans), stdin);
912				ans[strlen(ans) - 1] = 0;
913				if (!strcasecmp(ans, "ipv4"))
914					family = AF_INET;
915				else if (!strcasecmp(ans, "ipv6"))
916					family = AF_INET6;
917				else {
918					printf("unknown protocol family\n");
919					break;
920				}
921
922				printf("node address?  ");
923				FGETS(ans, sizeof(ans), stdin);
924				ans[strlen(ans) - 1] = 0;
925
926				if (family == AF_INET) {
927					p = (char *)&addr4;
928					len = sizeof(addr4);
929				} else {
930					p = (char *)&addr6;
931					len = sizeof(addr6);
932				}
933
934				if (inet_pton(family, ans, p) < 1) {
935					printf("error parsing address\n");
936					break;
937				}
938
939				sepol_node_sid(family, p, len, &ssid);
940				printf("sid %d\n", ssid);
941				break;
942			}
943		case 'c':
944			printf("fstype?  ");
945			FGETS(ans, sizeof(ans), stdin);
946			ans[strlen(ans) - 1] = 0;
947			sepol_fs_use(ans, &uret, &ssid);
948			switch (uret) {
949			case SECURITY_FS_USE_XATTR:
950				printf("use xattr\n");
951				break;
952			case SECURITY_FS_USE_TRANS:
953				printf("use transition SIDs\n");
954				break;
955			case SECURITY_FS_USE_TASK:
956				printf("use task SIDs\n");
957				break;
958			case SECURITY_FS_USE_GENFS:
959				printf("use genfs\n");
960				break;
961			case SECURITY_FS_USE_NONE:
962				printf("no labeling support\n");
963				break;
964			}
965			printf("sid %d\n", ssid);
966			break;
967		case 'd':
968			printf("fstype?  ");
969			FGETS(ans, sizeof(ans), stdin);
970			ans[strlen(ans) - 1] = 0;
971			fstype = strdup(ans);
972			printf("path?  ");
973			FGETS(ans, sizeof(ans), stdin);
974			ans[strlen(ans) - 1] = 0;
975			path = strdup(ans);
976			printf("object class?  ");
977			FGETS(ans, sizeof(ans), stdin);
978			if (isdigit(ans[0])) {
979				tclass = atoi(ans);
980				if (!tclass
981				    || tclass > policydb.p_classes.nprim) {
982					printf("\nNo such class.\n");
983					break;
984				}
985			} else {
986				ans[strlen(ans) - 1] = 0;
987				cladatum =
988				    (class_datum_t *) hashtab_search(policydb.
989								     p_classes.
990								     table,
991								     ans);
992				if (!cladatum) {
993					printf("\nNo such class\n");
994					break;
995				}
996				tclass = cladatum->s.value;
997			}
998			sepol_genfs_sid(fstype, path, tclass, &ssid);
999			printf("sid %d\n", ssid);
1000			free(fstype);
1001			free(path);
1002			break;
1003		case 'e':
1004			printf("from SID?  ");
1005			FGETS(ans, sizeof(ans), stdin);
1006			ans[strlen(ans) - 1] = 0;
1007			ssid = atoi(ans);
1008
1009			printf("username?  ");
1010			FGETS(ans, sizeof(ans), stdin);
1011			ans[strlen(ans) - 1] = 0;
1012
1013			ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1014			switch (ret) {
1015			case 0:
1016				if (!nel)
1017					printf("\nnone\n");
1018				for (i = 0; i < nel; i++)
1019					print_sid(sids[i], NULL, NULL);
1020				free(sids);
1021				break;
1022			case -ENOMEM:
1023				printf("\nout of memory\n");
1024				break;
1025			case -EINVAL:
1026				printf("\ninvalid argument\n");
1027				break;
1028			default:
1029				printf("\nerror\n");
1030				break;
1031			}
1032			break;
1033		case 'f':
1034			display_bools();
1035			break;
1036		case 'g':
1037			display_cond_expressions();
1038			break;
1039		case 'h':
1040			printf("name? ");
1041			FGETS(ans, sizeof(ans), stdin);
1042			ans[strlen(ans) - 1] = 0;
1043
1044			name = malloc((strlen(ans) + 1) * sizeof(char));
1045			if (name == NULL) {
1046				fprintf(stderr, "couldn't malloc string.\n");
1047				break;
1048			}
1049			strcpy(name, ans);
1050
1051			printf("state? ");
1052			FGETS(ans, sizeof(ans), stdin);
1053			ans[strlen(ans) - 1] = 0;
1054
1055			if (atoi(ans))
1056				state = 1;
1057			else
1058				state = 0;
1059
1060			change_bool(name, state);
1061			free(name);
1062			break;
1063#ifdef EQUIVTYPES
1064		case 'z':
1065			identify_equiv_types();
1066			break;
1067#endif
1068		case 'm':
1069			goto menu;
1070		case 'q':
1071			exit(0);
1072			break;
1073		default:
1074			printf("\nUnknown option %s.\n", ans);
1075		}
1076	}
1077
1078	return 0;
1079}
1080
1081/* FLASK */
1082