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