1
2/* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
3 *
4 * Copyright (C) 2003,2004,2005 Tresys Technology, LLC
5 *	This program is free software; you can redistribute it and/or modify
6 *  	it under the terms of the GNU General Public License as published by
7 *	the Free Software Foundation, version 2.
8 */
9
10/*
11 * dismod.c
12 *
13 * Test program to the contents of a binary policy in text
14 * form.
15 *
16 * 	dismod binary_mod_file
17 */
18
19#include <getopt.h>
20#include <assert.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <sys/mman.h>
24#include <errno.h>
25#include <stdio.h>
26#include <fcntl.h>
27#include <stdlib.h>
28#include <unistd.h>
29
30#include <sepol/policydb/policydb.h>
31#include <sepol/policydb/services.h>
32#include <sepol/policydb/conditional.h>
33#include <sepol/policydb/flask.h>
34#include <sepol/policydb/link.h>
35#include <sepol/policydb/module.h>
36#include <sepol/policydb/util.h>
37#include <sepol/policydb/polcaps.h>
38
39#include <byteswap.h>
40#include <endian.h>
41
42#if __BYTE_ORDER == __LITTLE_ENDIAN
43#define le32_to_cpu(x) (x)
44#else
45#define le32_to_cpu(x) bswap_32(x)
46#endif
47
48#define DISPLAY_AVBLOCK_COND_AVTAB	0
49#define DISPLAY_AVBLOCK_UNCOND_AVTAB	1
50#define DISPLAY_AVBLOCK_ROLE_TYPE_NODE	2 /* unused? */
51#define DISPLAY_AVBLOCK_ROLE_TRANS	3
52#define DISPLAY_AVBLOCK_ROLE_ALLOW	4
53#define DISPLAY_AVBLOCK_REQUIRES	5
54#define DISPLAY_AVBLOCK_DECLARES	6
55#define DISPLAY_AVBLOCK_FILENAME_TRANS	7
56
57static policydb_t policydb;
58extern unsigned int ss_initialized;
59
60int policyvers = MOD_POLICYDB_VERSION_BASE;
61
62static const char *symbol_labels[9] = {
63	"commons",
64	"classes", "roles  ", "types  ", "users  ", "bools  ",
65	"levels ", "cats   ", "attribs"
66};
67
68void usage(const char *progname)
69{
70	printf("usage:  %s binary_pol_file\n\n", progname);
71	exit(1);
72}
73
74static void render_access_mask(uint32_t mask, uint32_t class, policydb_t * p,
75			       FILE * fp)
76{
77	char *perm;
78	fprintf(fp, "{");
79	perm = sepol_av_to_string(p, class, mask);
80	if (perm)
81		fprintf(fp, "%s ", perm);
82	fprintf(fp, "}");
83}
84
85static void render_access_bitmap(ebitmap_t * map, uint32_t class,
86				 policydb_t * p, FILE * fp)
87{
88	unsigned int i;
89	char *perm;
90	fprintf(fp, "{");
91	for (i = ebitmap_startbit(map); i < ebitmap_length(map); i++) {
92		if (ebitmap_get_bit(map, i)) {
93			perm = sepol_av_to_string(p, class, 1 << i);
94			if (perm)
95				fprintf(fp, " %s", perm);
96		}
97	}
98	fprintf(fp, " }");
99}
100
101static void display_id(policydb_t * p, FILE * fp, uint32_t symbol_type,
102		       uint32_t symbol_value, const char *prefix)
103{
104	char *id = p->sym_val_to_name[symbol_type][symbol_value];
105	scope_datum_t *scope =
106	    (scope_datum_t *) hashtab_search(p->scope[symbol_type].table, id);
107	assert(scope != NULL);
108	if (scope->scope == SCOPE_REQ) {
109		fprintf(fp, " [%s%s]", prefix, id);
110	} else {
111		fprintf(fp, " %s%s", prefix, id);
112	}
113}
114
115int display_type_set(type_set_t * set, uint32_t flags, policydb_t * policy,
116		     FILE * fp)
117{
118	unsigned int i, num_types;
119
120	if (set->flags & TYPE_STAR) {
121		fprintf(fp, " * ");
122		return 0;
123	} else if (set->flags & TYPE_COMP) {
124		fprintf(fp, " ~");
125	}
126
127	num_types = 0;
128	if (flags & RULE_SELF) {
129		num_types++;
130	}
131
132	for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types);
133	     i++) {
134		if (!ebitmap_get_bit(&set->types, i))
135			continue;
136		num_types++;
137		if (num_types > 1)
138			break;
139	}
140
141	if (num_types <= 1) {
142		for (i = ebitmap_startbit(&set->negset);
143		     i < ebitmap_length(&set->negset); i++) {
144			if (!ebitmap_get_bit(&set->negset, i))
145				continue;
146			num_types++;
147			if (num_types > 1)
148				break;
149		}
150	}
151
152	if (num_types > 1)
153		fprintf(fp, "{");
154
155	for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types);
156	     i++) {
157		if (!ebitmap_get_bit(&set->types, i))
158			continue;
159		display_id(policy, fp, SYM_TYPES, i, "");
160	}
161
162	for (i = ebitmap_startbit(&set->negset);
163	     i < ebitmap_length(&set->negset); i++) {
164		if (!ebitmap_get_bit(&set->negset, i))
165			continue;
166		display_id(policy, fp, SYM_TYPES, i, "-");
167	}
168
169	if (flags & RULE_SELF) {
170		fprintf(fp, " self");
171	}
172
173	if (num_types > 1)
174		fprintf(fp, " }");
175
176	return 0;
177}
178
179int display_mod_role_set(role_set_t * roles, policydb_t * p, FILE * fp)
180{
181	unsigned int i, num = 0;
182
183	if (roles->flags & ROLE_STAR) {
184		fprintf(fp, " * ");
185		return 0;
186	} else if (roles->flags & ROLE_COMP) {
187		fprintf(fp, " ~");
188	}
189
190	for (i = ebitmap_startbit(&roles->roles);
191	     i < ebitmap_length(&roles->roles); i++) {
192		if (!ebitmap_get_bit(&roles->roles, i))
193			continue;
194		num++;
195		if (num > 1) {
196			fprintf(fp, "{");
197			break;
198		}
199	}
200
201	for (i = ebitmap_startbit(&roles->roles);
202	     i < ebitmap_length(&roles->roles); i++) {
203		if (ebitmap_get_bit(&roles->roles, i))
204			display_id(p, fp, SYM_ROLES, i, "");
205	}
206
207	if (num > 1)
208		fprintf(fp, " }");
209
210	return 0;
211
212}
213
214int display_avrule(avrule_t * avrule, policydb_t * policy,
215		   FILE * fp)
216{
217	class_perm_node_t *cur;
218	int num_classes;
219
220	if (avrule == NULL) {
221		fprintf(fp, "  <empty>\n");
222		return 0;
223	}
224	if (avrule->specified & AVRULE_AV) {
225		if (avrule->specified & AVRULE_ALLOWED) {
226			fprintf(fp, "  allow");
227		}
228		if (avrule->specified & AVRULE_AUDITALLOW) {
229			fprintf(fp, "  auditallow ");
230		}
231		if (avrule->specified & AVRULE_DONTAUDIT) {
232			fprintf(fp, "  dontaudit");
233		}
234	} else if (avrule->specified & AVRULE_TYPE) {
235		if (avrule->specified & AVRULE_TRANSITION) {
236			fprintf(fp, "  type_transition");
237		}
238		if (avrule->specified & AVRULE_MEMBER) {
239			fprintf(fp, "  type_member");
240		}
241		if (avrule->specified & AVRULE_CHANGE) {
242			fprintf(fp, "  type_change");
243		}
244	} else if (avrule->specified & AVRULE_NEVERALLOW) {
245		fprintf(fp, "  neverallow");
246	} else {
247		fprintf(fp, "     ERROR: no valid rule type specified\n");
248		return -1;
249	}
250
251	if (display_type_set(&avrule->stypes, 0, policy, fp))
252		return -1;
253
254	if (display_type_set(&avrule->ttypes, avrule->flags, policy, fp))
255		return -1;
256
257	fprintf(fp, " :");
258	cur = avrule->perms;
259	num_classes = 0;
260	while (cur) {
261		num_classes++;
262		if (num_classes > 1)
263			break;
264		cur = cur->next;
265	}
266
267	if (num_classes > 1)
268		fprintf(fp, " {");
269
270	cur = avrule->perms;
271	while (cur) {
272		display_id(policy, fp, SYM_CLASSES, cur->tclass - 1, "");
273		cur = cur->next;
274	}
275
276	if (num_classes > 1)
277		fprintf(fp, " }");
278	fprintf(fp, " ");
279
280	if (avrule->specified & (AVRULE_AV | AVRULE_NEVERALLOW)) {
281		render_access_mask(avrule->perms->data, avrule->perms->tclass,
282				   policy, fp);
283	} else if (avrule->specified & AVRULE_TYPE) {
284		display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, "");
285	}
286
287	fprintf(fp, ";\n");
288
289	return 0;
290}
291
292int display_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
293{
294	type_datum_t *type;
295	FILE *fp;
296	unsigned int i, first_attrib = 1;
297
298	type = (type_datum_t *) datum;
299	fp = (FILE *) data;
300
301	if (type->primary) {
302		display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, "");
303		fprintf(fp, " [%d]: ", type->s.value);
304	} else {
305		/* as that aliases have no value of their own and that
306		 * they can never be required by a module, use this
307		 * alternative way of displaying a name */
308		fprintf(fp, " %s [%d]: ", (char *)key, type->s.value);
309	}
310	if (type->flavor == TYPE_ATTRIB) {
311		fprintf(fp, "attribute for types");
312		for (i = ebitmap_startbit(&type->types);
313		     i < ebitmap_length(&type->types); i++) {
314			if (!ebitmap_get_bit(&type->types, i))
315				continue;
316			if (first_attrib) {
317				first_attrib = 0;
318			} else {
319				fprintf(fp, ",");
320			}
321			display_id(&policydb, fp, SYM_TYPES, i, "");
322		}
323	} else if (type->primary) {
324		fprintf(fp, "type");
325	} else {
326		fprintf(fp, "alias for type");
327		display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, "");
328	}
329	fprintf(fp, " flags:%x\n", type->flags);
330
331	return 0;
332}
333
334int display_types(policydb_t * p, FILE * fp)
335{
336	if (hashtab_map(p->p_types.table, display_type_callback, fp))
337		return -1;
338	return 0;
339}
340
341int display_users(policydb_t * p, FILE * fp)
342{
343	unsigned int i, j;
344	ebitmap_t *bitmap;
345	for (i = 0; i < p->p_users.nprim; i++) {
346		display_id(p, fp, SYM_USERS, i, "");
347		fprintf(fp, ":");
348		bitmap = &(p->user_val_to_struct[i]->roles.roles);
349		for (j = ebitmap_startbit(bitmap); j < ebitmap_length(bitmap);
350		     j++) {
351			if (ebitmap_get_bit(bitmap, j)) {
352				display_id(p, fp, SYM_ROLES, j, "");
353			}
354		}
355		fprintf(fp, "\n");
356	}
357	return 0;
358}
359
360int display_bools(policydb_t * p, FILE * fp)
361{
362	unsigned int i;
363
364	for (i = 0; i < p->p_bools.nprim; i++) {
365		display_id(p, fp, SYM_BOOLS, i, "");
366		fprintf(fp, " : %d\n", p->bool_val_to_struct[i]->state);
367	}
368	return 0;
369}
370
371void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp)
372{
373
374	cond_expr_t *cur;
375	for (cur = exp; cur != NULL; cur = cur->next) {
376		switch (cur->expr_type) {
377		case COND_BOOL:
378			fprintf(fp, "%s ",
379				p->p_bool_val_to_name[cur->bool - 1]);
380			break;
381		case COND_NOT:
382			fprintf(fp, "! ");
383			break;
384		case COND_OR:
385			fprintf(fp, "|| ");
386			break;
387		case COND_AND:
388			fprintf(fp, "&& ");
389			break;
390		case COND_XOR:
391			fprintf(fp, "^ ");
392			break;
393		case COND_EQ:
394			fprintf(fp, "== ");
395			break;
396		case COND_NEQ:
397			fprintf(fp, "!= ");
398			break;
399		default:
400			fprintf(fp, "error!");
401			break;
402		}
403	}
404}
405
406void display_policycon(FILE * fp)
407{
408	/* There was an attempt to implement this at one time.  Look through
409	 * git history to find it. */
410	fprintf(fp, "Sorry, not implemented\n");
411}
412
413void display_initial_sids(policydb_t * p, FILE * fp)
414{
415	ocontext_t *cur;
416	char *user, *role, *type;
417
418	fprintf(fp, "Initial SIDs:\n");
419	for (cur = p->ocontexts[OCON_ISID]; cur != NULL; cur = cur->next) {
420		user = p->p_user_val_to_name[cur->context[0].user - 1];
421		role = p->p_role_val_to_name[cur->context[0].role - 1];
422		type = p->p_type_val_to_name[cur->context[0].type - 1];
423		fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n",
424			cur->u.name, cur->sid[0], user, role, type);
425	}
426#if 0
427	fprintf(fp, "Policy Initial SIDs:\n");
428	for (cur = p->ocontexts[OCON_POLICYISID]; cur != NULL; cur = cur->next) {
429		user = p->p_user_val_to_name[cur->context[0].user - 1];
430		role = p->p_role_val_to_name[cur->context[0].role - 1];
431		type = p->p_type_val_to_name[cur->context[0].type - 1];
432		fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n",
433			cur->u.name, cur->sid[0], user, role, type);
434	}
435#endif
436}
437
438void display_class_set(ebitmap_t *classes, policydb_t *p, FILE *fp)
439{
440	unsigned int i, num = 0;
441
442	for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) {
443		if (!ebitmap_get_bit(classes, i))
444			continue;
445		num++;
446		if (num > 1) {
447			fprintf(fp, "{");
448			break;
449		}
450	}
451
452	for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) {
453		if (ebitmap_get_bit(classes, i))
454			display_id(p, fp, SYM_CLASSES, i, "");
455	}
456
457	if (num > 1)
458		fprintf(fp, " }");
459}
460
461void display_role_trans(role_trans_rule_t * tr, policydb_t * p, FILE * fp)
462{
463	for (; tr; tr = tr->next) {
464		fprintf(fp, "role transition ");
465		display_mod_role_set(&tr->roles, p, fp);
466		display_type_set(&tr->types, 0, p, fp);
467		fprintf(fp, " :");
468		display_class_set(&tr->classes, p, fp);
469		display_id(p, fp, SYM_ROLES, tr->new_role - 1, "");
470		fprintf(fp, "\n");
471	}
472}
473
474void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp)
475{
476	for (; ra; ra = ra->next) {
477		fprintf(fp, "role allow ");
478		display_mod_role_set(&ra->roles, p, fp);
479		display_mod_role_set(&ra->new_roles, p, fp);
480		fprintf(fp, "\n");
481	}
482}
483
484static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp)
485{
486	fprintf(fp, "filename transition");
487	for (; tr; tr = tr->next) {
488		display_type_set(&tr->stypes, 0, p, fp);
489		display_type_set(&tr->ttypes, 0, p, fp);
490		display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":");
491		display_id(p, fp, SYM_TYPES, tr->otype - 1, "");
492		fprintf(fp, " %s\n", tr->name);
493	}
494}
495
496int role_display_callback(hashtab_key_t key __attribute__((unused)),
497			  hashtab_datum_t datum, void *data)
498{
499	role_datum_t *role;
500	FILE *fp;
501
502	role = (role_datum_t *) datum;
503	fp = (FILE *) data;
504
505	fprintf(fp, "role:");
506	display_id(&policydb, fp, SYM_ROLES, role->s.value - 1, "");
507	fprintf(fp, " types: ");
508	display_type_set(&role->types, 0, &policydb, fp);
509	fprintf(fp, "\n");
510
511	return 0;
512}
513
514static int display_scope_index(scope_index_t * indices, policydb_t * p,
515			       FILE * out_fp)
516{
517	unsigned int i;
518	for (i = 0; i < SYM_NUM; i++) {
519		unsigned int any_found = 0, j;
520		fprintf(out_fp, "%s:", symbol_labels[i]);
521		for (j = ebitmap_startbit(&indices->scope[i]);
522		     j < ebitmap_length(&indices->scope[i]); j++) {
523			if (ebitmap_get_bit(&indices->scope[i], j)) {
524				any_found = 1;
525				fprintf(out_fp, " %s",
526					p->sym_val_to_name[i][j]);
527				if (i == SYM_CLASSES) {
528					if (j < indices->class_perms_len) {
529						render_access_bitmap(indices->
530								     class_perms_map
531								     + j, j + 1,
532								     p, out_fp);
533					} else {
534						fprintf(out_fp,
535							"<no perms known>");
536					}
537				}
538			}
539		}
540		if (!any_found) {
541			fprintf(out_fp, " <empty>");
542		}
543		fprintf(out_fp, "\n");
544	}
545	return 0;
546}
547
548#if 0
549int display_cond_expressions(policydb_t * p, FILE * fp)
550{
551	cond_node_t *cur;
552	cond_av_list_t *av_cur;
553	for (cur = p->cond_list; cur != NULL; cur = cur->next) {
554		fprintf(fp, "expression: ");
555		display_expr(p, cur->expr, fp);
556		fprintf(fp, "current state: %d\n", cur->cur_state);
557		fprintf(fp, "True list:\n");
558		for (av_cur = cur->true_list; av_cur != NULL;
559		     av_cur = av_cur->next) {
560			fprintf(fp, "\t");
561			render_av_rule(&av_cur->node->key, &av_cur->node->datum,
562				       RENDER_CONDITIONAL, p, fp);
563		}
564		fprintf(fp, "False list:\n");
565		for (av_cur = cur->false_list; av_cur != NULL;
566		     av_cur = av_cur->next) {
567			fprintf(fp, "\t");
568			render_av_rule(&av_cur->node->key, &av_cur->node->datum,
569				       RENDER_CONDITIONAL, p, fp);
570		}
571	}
572	return 0;
573}
574
575int change_bool(char *name, int state, policydb_t * p, FILE * fp)
576{
577	cond_bool_datum_t *bool;
578
579	bool = hashtab_search(p->p_bools.table, name);
580	if (bool == NULL) {
581		fprintf(fp, "Could not find bool %s\n", name);
582		return -1;
583	}
584	bool->state = state;
585	evaluate_conds(p);
586	return 0;
587}
588#endif
589
590int display_avdecl(avrule_decl_t * decl, int field,
591		   policydb_t * policy, FILE * out_fp)
592{
593	fprintf(out_fp, "decl %u:%s\n", decl->decl_id,
594		(decl->enabled ? " [enabled]" : ""));
595	switch (field) {
596	case DISPLAY_AVBLOCK_COND_AVTAB:{
597			cond_list_t *cond = decl->cond_list;
598			avrule_t *avrule;
599			while (cond) {
600				fprintf(out_fp, "expression: ");
601				display_expr(&policydb, cond->expr, out_fp);
602				fprintf(out_fp, "current state: %d\n",
603					cond->cur_state);
604				fprintf(out_fp, "True list:\n");
605				avrule = cond->avtrue_list;
606				while (avrule) {
607					display_avrule(avrule,
608						       &policydb, out_fp);
609					avrule = avrule->next;
610				}
611				fprintf(out_fp, "False list:\n");
612				avrule = cond->avfalse_list;
613				while (avrule) {
614					display_avrule(avrule,
615						       &policydb, out_fp);
616					avrule = avrule->next;
617				}
618				cond = cond->next;
619			}
620			break;
621		}
622	case DISPLAY_AVBLOCK_UNCOND_AVTAB:{
623			avrule_t *avrule = decl->avrules;
624			if (avrule == NULL) {
625				fprintf(out_fp, "  <empty>\n");
626			}
627			while (avrule != NULL) {
628				if (display_avrule(avrule, policy, out_fp))
629					return -1;
630				avrule = avrule->next;
631			}
632			break;
633		}
634	case DISPLAY_AVBLOCK_ROLE_TYPE_NODE:{	/* role_type_node */
635			break;
636		}
637	case DISPLAY_AVBLOCK_ROLE_TRANS:{
638			display_role_trans(decl->role_tr_rules, policy, out_fp);
639			break;
640		}
641	case DISPLAY_AVBLOCK_ROLE_ALLOW:{
642			display_role_allow(decl->role_allow_rules, policy,
643					   out_fp);
644			break;
645		}
646	case DISPLAY_AVBLOCK_REQUIRES:{
647			if (display_scope_index
648			    (&decl->required, policy, out_fp)) {
649				return -1;
650			}
651			break;
652		}
653	case DISPLAY_AVBLOCK_DECLARES:{
654			if (display_scope_index
655			    (&decl->declared, policy, out_fp)) {
656				return -1;
657			}
658			break;
659		}
660	case DISPLAY_AVBLOCK_FILENAME_TRANS:
661		display_filename_trans(decl->filename_trans_rules, policy,
662				       out_fp);
663		break;
664	default:{
665			assert(0);
666		}
667	}
668	return 0;		/* should never get here */
669}
670
671int display_avblock(int field, policydb_t * policy,
672		    FILE * out_fp)
673{
674	avrule_block_t *block = policydb.global;
675	while (block != NULL) {
676		fprintf(out_fp, "--- begin avrule block ---\n");
677		avrule_decl_t *decl = block->branch_list;
678		while (decl != NULL) {
679			if (display_avdecl(decl, field, policy, out_fp)) {
680				return -1;
681			}
682			decl = decl->next;
683		}
684		block = block->next;
685	}
686	return 0;
687}
688
689int display_handle_unknown(policydb_t * p, FILE * out_fp)
690{
691	if (p->handle_unknown == ALLOW_UNKNOWN)
692		fprintf(out_fp, "Allow unknown classes and perms\n");
693	else if (p->handle_unknown == DENY_UNKNOWN)
694		fprintf(out_fp, "Deny unknown classes and perms\n");
695	else if (p->handle_unknown == REJECT_UNKNOWN)
696		fprintf(out_fp, "Reject unknown classes and perms\n");
697	return 0;
698}
699
700static int read_policy(char *filename, policydb_t * policy)
701{
702	FILE *in_fp;
703	struct policy_file f;
704	int retval;
705	uint32_t buf[1];
706
707	if ((in_fp = fopen(filename, "rb")) == NULL) {
708		fprintf(stderr, "Can't open '%s':  %s\n",
709			filename, strerror(errno));
710		exit(1);
711	}
712	policy_file_init(&f);
713	f.type = PF_USE_STDIO;
714	f.fp = in_fp;
715
716	/* peek at the first byte.  if they are indicative of a
717	   package use the package reader, otherwise use the normal
718	   policy reader */
719	if (fread(buf, sizeof(uint32_t), 1, in_fp) != 1) {
720		fprintf(stderr, "Could not read from policy.\n");
721		exit(1);
722	}
723	rewind(in_fp);
724	if (le32_to_cpu(buf[0]) == SEPOL_MODULE_PACKAGE_MAGIC) {
725		sepol_module_package_t *package;
726		if (sepol_module_package_create(&package)) {
727			fprintf(stderr, "%s:  Out of memory!\n", __FUNCTION__);
728			exit(1);
729		}
730		package->policy = (sepol_policydb_t *) policy;
731		package->file_contexts = NULL;
732		retval =
733		    sepol_module_package_read(package,
734					      (sepol_policy_file_t *) & f, 1);
735		free(package->file_contexts);
736	} else {
737		if (policydb_init(policy)) {
738			fprintf(stderr, "%s:  Out of memory!\n", __FUNCTION__);
739			exit(1);
740		}
741		retval = policydb_read(policy, &f, 1);
742	}
743	fclose(in_fp);
744	return retval;
745}
746
747static void link_module(policydb_t * base, FILE * out_fp)
748{
749	char module_name[80] = { 0 };
750	int ret;
751	policydb_t module, *mods = &module;
752
753	if (base->policy_type != POLICY_BASE) {
754		printf("Can only link if initial file was a base policy.\n");
755		return;
756	}
757	printf("\nModule filename: ");
758	if (fgets(module_name, sizeof(module_name), stdin) == NULL) {
759		fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
760				strerror(errno));
761		exit(1);
762	}
763
764	module_name[strlen(module_name) - 1] = '\0';	/* remove LF */
765	if (module_name[0] == '\0') {
766		return;
767	}
768
769	/* read the binary policy */
770	fprintf(out_fp, "Reading module...\n");
771	if (read_policy(module_name, mods)) {
772		fprintf(stderr,
773			"%s:  error(s) encountered while loading policy\n",
774			module_name);
775		exit(1);
776	}
777	if (module.policy_type != POLICY_MOD) {
778		fprintf(stderr, "This file is not a loadable policy module.\n");
779		exit(1);
780	}
781	if (policydb_index_classes(&module) ||
782	    policydb_index_others(NULL, &module, 0)) {
783		fprintf(stderr, "Could not index module.\n");
784		exit(1);
785	}
786	ret = link_modules(NULL, base, &mods, 1, 0);
787	if (ret != 0) {
788		printf("Link failed (error %d)\n", ret);
789		printf("(You will probably need to restart dismod.)\n");
790	}
791	policydb_destroy(&module);
792	return;
793}
794
795static void display_policycaps(policydb_t * p, FILE * fp)
796{
797	ebitmap_node_t *node;
798	const char *capname;
799	char buf[64];
800	unsigned int i;
801
802	fprintf(fp, "policy capabilities:\n");
803	ebitmap_for_each_bit(&p->policycaps, node, i) {
804		if (ebitmap_node_get_bit(node, i)) {
805			capname = sepol_polcap_getname(i);
806			if (capname == NULL) {
807				snprintf(buf, sizeof(buf), "unknown (%d)", i);
808				capname = buf;
809			}
810			fprintf(fp, "\t%s\n", capname);
811		}
812	}
813}
814
815int menu(void)
816{
817	printf("\nSelect a command:\n");
818	printf("1)  display unconditional AVTAB\n");
819	printf("2)  display conditional AVTAB\n");
820	printf("3)  display users\n");
821	printf("4)  display bools\n");
822	printf("5)  display roles\n");
823	printf("6)  display types, attributes, and aliases\n");
824	printf("7)  display role transitions\n");
825	printf("8)  display role allows\n");
826	printf("9)  Display policycon\n");
827	printf("0)  Display initial SIDs\n");
828	printf("\n");
829	printf("a)  Display avrule requirements\n");
830	printf("b)  Display avrule declarations\n");
831	printf("c)  Display policy capabilities\n");
832	printf("l)  Link in a module\n");
833	printf("u)  Display the unknown handling setting\n");
834	printf("F)  Display filename_trans rules\n");
835	printf("\n");
836	printf("f)  set output file\n");
837	printf("m)  display menu\n");
838	printf("q)  quit\n");
839	return 0;
840}
841
842int main(int argc, char **argv)
843{
844	FILE *out_fp = stdout;
845	char ans[81], OutfileName[121];
846
847	if (argc != 2)
848		usage(argv[0]);
849
850	/* read the binary policy */
851	fprintf(out_fp, "Reading policy...\n");
852	if (policydb_init(&policydb)) {
853		fprintf(stderr, "%s:  Out of memory!\n", __FUNCTION__);
854		exit(1);
855	}
856	if (read_policy(argv[1], &policydb)) {
857		fprintf(stderr,
858			"%s:  error(s) encountered while loading policy\n",
859			argv[0]);
860		exit(1);
861	}
862
863	if (policydb.policy_type != POLICY_BASE &&
864	    policydb.policy_type != POLICY_MOD) {
865		fprintf(stderr,
866			"This file is neither a base nor loadable policy module.\n");
867		exit(1);
868	}
869
870	if (policydb_index_classes(&policydb)) {
871		fprintf(stderr, "Error indexing classes\n");
872		exit(1);
873	}
874
875	if (policydb_index_others(NULL, &policydb, 1)) {
876		fprintf(stderr, "Error indexing others\n");
877		exit(1);
878	}
879
880	if (policydb.policy_type == POLICY_BASE) {
881		printf("Binary base policy file loaded.\n\n");
882	} else {
883		printf("Binary policy module file loaded.\n");
884		printf("Module name: %s\n", policydb.name);
885		printf("Module version: %s\n", policydb.version);
886		printf("\n");
887	}
888
889	menu();
890	for (;;) {
891		printf("\nCommand (\'m\' for menu):  ");
892		if (fgets(ans, sizeof(ans), stdin) == NULL) {
893			fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
894					strerror(errno));
895			continue;
896		}
897
898		switch (ans[0]) {
899
900		case '1':
901			fprintf(out_fp, "unconditional avtab:\n");
902			display_avblock(DISPLAY_AVBLOCK_UNCOND_AVTAB,
903					&policydb, out_fp);
904			break;
905		case '2':
906			fprintf(out_fp, "conditional avtab:\n");
907			display_avblock(DISPLAY_AVBLOCK_COND_AVTAB,
908					&policydb, out_fp);
909			break;
910		case '3':
911			display_users(&policydb, out_fp);
912			break;
913		case '4':
914			display_bools(&policydb, out_fp);
915			break;
916		case '5':
917			if (hashtab_map
918			    (policydb.p_roles.table, role_display_callback,
919			     out_fp))
920				exit(1);
921			break;
922		case '6':
923			if (display_types(&policydb, out_fp)) {
924				fprintf(stderr, "Error displaying types\n");
925				exit(1);
926			}
927			break;
928		case '7':
929			fprintf(out_fp, "role transitions:\n");
930			display_avblock(DISPLAY_AVBLOCK_ROLE_TRANS,
931					&policydb, out_fp);
932			break;
933		case '8':
934			fprintf(out_fp, "role allows:\n");
935			display_avblock(DISPLAY_AVBLOCK_ROLE_ALLOW,
936					&policydb, out_fp);
937			break;
938		case '9':
939			display_policycon(out_fp);
940			break;
941		case '0':
942			display_initial_sids(&policydb, out_fp);
943			break;
944		case 'a':
945			fprintf(out_fp, "avrule block requirements:\n");
946			display_avblock(DISPLAY_AVBLOCK_REQUIRES,
947					&policydb, out_fp);
948			break;
949		case 'b':
950			fprintf(out_fp, "avrule block declarations:\n");
951			display_avblock(DISPLAY_AVBLOCK_DECLARES,
952					&policydb, out_fp);
953			break;
954		case 'c':
955			display_policycaps(&policydb, out_fp);
956			break;
957		case 'u':
958		case 'U':
959			display_handle_unknown(&policydb, out_fp);
960			break;
961		case 'f':
962			printf
963			    ("\nFilename for output (<CR> for screen output): ");
964			if (fgets(OutfileName, sizeof(OutfileName), stdin) == NULL) {
965				fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
966						strerror(errno));
967				break;
968			}
969			OutfileName[strlen(OutfileName) - 1] = '\0';	/* fix_string (remove LF) */
970			if (strlen(OutfileName) == 0)
971				out_fp = stdout;
972			else if ((out_fp = fopen(OutfileName, "w")) == NULL) {
973				fprintf(stderr, "Cannot open output file %s\n",
974					OutfileName);
975				out_fp = stdout;
976			}
977			if (out_fp != stdout)
978				printf("\nOutput to file: %s\n", OutfileName);
979			break;
980		case 'F':
981			fprintf(out_fp, "filename_trans rules:\n");
982			display_avblock(DISPLAY_AVBLOCK_FILENAME_TRANS,
983					&policydb, out_fp);
984			break;
985		case 'l':
986			link_module(&policydb, out_fp);
987			break;
988		case 'q':
989			policydb_destroy(&policydb);
990			exit(0);
991			break;
992		case 'm':
993			menu();
994			break;
995		default:
996			printf("\nInvalid choice\n");
997			menu();
998			break;
999
1000		}
1001	}
1002	exit(EXIT_SUCCESS);
1003}
1004