1/*
2 * Authors: Joshua Brindle <jbrindle@tresys.com>
3 *	    Karl MacMillan <kmacmillan@tresys.com>
4 *          Jason Tang     <jtang@tresys.com>
5 *
6 *
7 * Copyright (C) 2004-5 Tresys Technology, LLC
8 *	This program is free software; you can redistribute it and/or modify
9 *  	it under the terms of the GNU General Public License as published by
10 *	the Free Software Foundation, version 2.
11 */
12
13#include <getopt.h>
14#include <unistd.h>
15#include <stdlib.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <fcntl.h>
19#include <stdio.h>
20#include <errno.h>
21#include <sys/mman.h>
22
23#include <sepol/module_to_cil.h>
24#include <sepol/policydb/policydb.h>
25#include <sepol/policydb/services.h>
26#include <sepol/policydb/conditional.h>
27#include <sepol/policydb/flask.h>
28#include <sepol/policydb/hierarchy.h>
29#include <sepol/policydb/expand.h>
30#include <sepol/policydb/link.h>
31#include <sepol/policydb/sidtab.h>
32
33#include "queue.h"
34#include "checkpolicy.h"
35#include "parse_util.h"
36
37extern char *optarg;
38extern int optind;
39
40static sidtab_t sidtab;
41
42extern int mlspol;
43
44static int handle_unknown = SEPOL_DENY_UNKNOWN;
45static const char *txtfile = "policy.conf";
46static const char *binfile = "policy";
47
48unsigned int policy_type = POLICY_BASE;
49unsigned int policyvers = MOD_POLICYDB_VERSION_MAX;
50
51static int read_binary_policy(policydb_t * p, const char *file, const char *progname)
52{
53	int fd;
54	struct stat sb;
55	void *map;
56	struct policy_file f, *fp;
57
58	fd = open(file, O_RDONLY);
59	if (fd < 0) {
60		fprintf(stderr, "Can't open '%s':  %s\n",
61			file, strerror(errno));
62		return -1;
63	}
64	if (fstat(fd, &sb) < 0) {
65		fprintf(stderr, "Can't stat '%s':  %s\n",
66			file, strerror(errno));
67		close(fd);
68		return -1;
69	}
70	map =
71	    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
72	close(fd);
73	if (map == MAP_FAILED) {
74		fprintf(stderr, "Can't map '%s':  %s\n", file, strerror(errno));
75		return -1;
76	}
77	policy_file_init(&f);
78	f.type = PF_USE_MEMORY;
79	f.data = map;
80	f.len = sb.st_size;
81	fp = &f;
82
83	if (policydb_init(p)) {
84		fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
85			progname);
86		return -1;
87	}
88	if (policydb_read(p, fp, 1)) {
89		fprintf(stderr,
90			"%s:  error(s) encountered while parsing configuration\n",
91			progname);
92		return -1;
93	}
94
95	/* Check Policy Consistency */
96	if (p->mls) {
97		if (!mlspol) {
98			fprintf(stderr, "%s:  MLS policy, but non-MLS"
99				" is specified\n", progname);
100			return -1;
101		}
102	} else {
103		if (mlspol) {
104			fprintf(stderr, "%s:  non-MLS policy, but MLS"
105				" is specified\n", progname);
106			return -1;
107		}
108	}
109	return 0;
110}
111
112static int write_binary_policy(policydb_t * p, FILE *outfp)
113{
114	struct policy_file pf;
115
116	p->policy_type = policy_type;
117	p->policyvers = policyvers;
118	p->handle_unknown = handle_unknown;
119
120	policy_file_init(&pf);
121	pf.type = PF_USE_STDIO;
122	pf.fp = outfp;
123	return policydb_write(p, &pf);
124}
125
126static void usage(char *progname)
127{
128	printf("usage:  %s [-h] [-V] [-b] [-C] [-U handle_unknown] [-m] [-M] [-o FILE] [INPUT]\n", progname);
129	printf("Build base and policy modules.\n");
130	printf("Options:\n");
131	printf("  INPUT      build module from INPUT (else read from \"%s\")\n",
132	       txtfile);
133	printf("  -V         show policy versions created by this program\n");
134	printf("  -b         treat input as a binary policy file\n");
135	printf("  -C         output CIL policy instead of binary policy\n");
136	printf("  -h         print usage\n");
137	printf("  -U OPTION  How to handle unknown classes and permissions\n");
138	printf("               deny: Deny unknown kernel checks\n");
139	printf("               reject: Reject loading of policy with unknowns\n");
140	printf("               allow: Allow unknown kernel checks\n");
141	printf("  -m         build a policy module instead of a base module\n");
142	printf("  -M         enable MLS policy\n");
143	printf("  -o FILE    write module to FILE (else just check syntax)\n");
144	exit(1);
145}
146
147int main(int argc, char **argv)
148{
149	const char *file = txtfile, *outfile = NULL;
150	unsigned int binary = 0, cil = 0;
151	int ch;
152	int show_version = 0;
153	policydb_t modpolicydb;
154	struct option long_options[] = {
155		{"help", no_argument, NULL, 'h'},
156		{"output", required_argument, NULL, 'o'},
157		{"binary", no_argument, NULL, 'b'},
158		{"version", no_argument, NULL, 'V'},
159		{"handle-unknown", required_argument, NULL, 'U'},
160		{"mls", no_argument, NULL, 'M'},
161		{"cil", no_argument, NULL, 'C'},
162		{NULL, 0, NULL, 0}
163	};
164
165	while ((ch = getopt_long(argc, argv, "ho:bVU:mMC", long_options, NULL)) != -1) {
166		switch (ch) {
167		case 'h':
168			usage(argv[0]);
169			break;
170		case 'o':
171			outfile = optarg;
172			break;
173		case 'b':
174			binary = 1;
175			file = binfile;
176			break;
177		case 'V':
178			show_version = 1;
179			break;
180		case 'U':
181			if (!strcasecmp(optarg, "deny")) {
182				handle_unknown = DENY_UNKNOWN;
183				break;
184			}
185			if (!strcasecmp(optarg, "reject")) {
186				handle_unknown = REJECT_UNKNOWN;
187				break;
188			}
189			if (!strcasecmp(optarg, "allow")) {
190				handle_unknown = ALLOW_UNKNOWN;
191				break;
192			}
193			usage(argv[0]);
194		case 'm':
195			policy_type = POLICY_MOD;
196			policyvers = MOD_POLICYDB_VERSION_MAX;
197			break;
198		case 'M':
199			mlspol = 1;
200			break;
201		case 'C':
202			cil = 1;
203			break;
204		default:
205			usage(argv[0]);
206		}
207	}
208
209	if (show_version) {
210		printf("Module versions %d-%d\n",
211		       MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX);
212		exit(0);
213	}
214
215	if (handle_unknown && (policy_type != POLICY_BASE)) {
216		fprintf(stderr, "%s:  Handling of unknown classes and permissions is only valid in the base module.\n", argv[0]);
217		exit(1);
218	}
219
220	if (binary && (policy_type != POLICY_BASE)) {
221		fprintf(stderr, "%s:  -b and -m are incompatible with each other.\n", argv[0]);
222		exit(1);
223	}
224
225	if (optind != argc) {
226		file = argv[optind++];
227		if (optind != argc)
228			usage(argv[0]);
229	}
230	printf("%s:  loading policy configuration from %s\n", argv[0], file);
231
232	/* Set policydb and sidtab used by libsepol service functions
233	   to my structures, so that I can directly populate and
234	   manipulate them. */
235	sepol_set_policydb(&modpolicydb);
236	sepol_set_sidtab(&sidtab);
237
238	if (binary) {
239		if (read_binary_policy(&modpolicydb, file, argv[0]) == -1) {
240			exit(1);
241		}
242	} else {
243		if (policydb_init(&modpolicydb)) {
244			fprintf(stderr, "%s: out of memory!\n", argv[0]);
245			return -1;
246		}
247
248		modpolicydb.policy_type = policy_type;
249		modpolicydb.mls = mlspol;
250		modpolicydb.handle_unknown = handle_unknown;
251
252		if (read_source_policy(&modpolicydb, file, argv[0]) == -1) {
253			exit(1);
254		}
255
256		if (hierarchy_check_constraints(NULL, &modpolicydb)) {
257			return -1;
258		}
259	}
260
261	if (modpolicydb.policy_type == POLICY_BASE && !cil) {
262		/* Verify that we can successfully expand the base module. */
263		policydb_t kernpolicydb;
264
265		if (policydb_init(&kernpolicydb)) {
266			fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
267			exit(1);
268		}
269		if (link_modules(NULL, &modpolicydb, NULL, 0, 0)) {
270			fprintf(stderr, "%s:  link modules failed\n", argv[0]);
271			exit(1);
272		}
273		if (expand_module(NULL, &modpolicydb, &kernpolicydb, 0, 1)) {
274			fprintf(stderr, "%s:  expand module failed\n", argv[0]);
275			exit(1);
276		}
277		policydb_destroy(&kernpolicydb);
278	}
279
280	if (policydb_load_isids(&modpolicydb, &sidtab))
281		exit(1);
282
283	sepol_sidtab_destroy(&sidtab);
284
285	printf("%s:  policy configuration loaded\n", argv[0]);
286
287	if (outfile) {
288		FILE *outfp = fopen(outfile, "w");
289
290		if (!outfp) {
291			perror(outfile);
292			exit(1);
293		}
294
295		if (!cil) {
296			printf("%s:  writing binary representation (version %d) to %s\n",
297				   argv[0], policyvers, file);
298
299			if (write_binary_policy(&modpolicydb, outfp) != 0) {
300				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
301				exit(1);
302			}
303		} else {
304			printf("%s:  writing CIL to %s\n",argv[0], outfile);
305
306			if (sepol_module_policydb_to_cil(outfp, &modpolicydb, 0) != 0) {
307				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
308				exit(1);
309			}
310		}
311
312		fclose(outfp);
313	} else if (cil) {
314		fprintf(stderr, "%s:  No file to write CIL was specified\n", argv[0]);
315		exit(1);
316	}
317
318	policydb_destroy(&modpolicydb);
319
320	return 0;
321}
322
323/* FLASK */
324