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#include <libgen.h>
23
24#include <sepol/module_to_cil.h>
25#include <sepol/policydb/policydb.h>
26#include <sepol/policydb/services.h>
27#include <sepol/policydb/conditional.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
37static sidtab_t sidtab;
38
39extern int mlspol;
40extern int werror;
41
42static int handle_unknown = SEPOL_DENY_UNKNOWN;
43static const char *txtfile = "policy.conf";
44static const char *binfile = "policy";
45
46unsigned int policy_type = POLICY_BASE;
47unsigned int policyvers = MOD_POLICYDB_VERSION_MAX;
48
49static int read_binary_policy(policydb_t * p, const char *file, const char *progname)
50{
51	int fd;
52	struct stat sb;
53	void *map;
54	struct policy_file f, *fp;
55
56	fd = open(file, O_RDONLY);
57	if (fd < 0) {
58		fprintf(stderr, "Can't open '%s':  %s\n",
59			file, strerror(errno));
60		return -1;
61	}
62	if (fstat(fd, &sb) < 0) {
63		fprintf(stderr, "Can't stat '%s':  %s\n",
64			file, strerror(errno));
65		close(fd);
66		return -1;
67	}
68	map =
69	    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
70	close(fd);
71	if (map == MAP_FAILED) {
72		fprintf(stderr, "Can't map '%s':  %s\n", file, strerror(errno));
73		return -1;
74	}
75	policy_file_init(&f);
76	f.type = PF_USE_MEMORY;
77	f.data = map;
78	f.len = sb.st_size;
79	fp = &f;
80
81	if (policydb_init(p)) {
82		fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
83			progname);
84		return -1;
85	}
86	if (policydb_read(p, fp, 1)) {
87		fprintf(stderr,
88			"%s:  error(s) encountered while parsing configuration\n",
89			progname);
90		return -1;
91	}
92
93	/* Check Policy Consistency */
94	if (p->mls) {
95		if (!mlspol) {
96			fprintf(stderr, "%s:  MLS policy, but non-MLS"
97				" is specified\n", progname);
98			return -1;
99		}
100	} else {
101		if (mlspol) {
102			fprintf(stderr, "%s:  non-MLS policy, but MLS"
103				" is specified\n", progname);
104			return -1;
105		}
106	}
107	return 0;
108}
109
110static int write_binary_policy(policydb_t * p, FILE *outfp)
111{
112	struct policy_file pf;
113
114	p->policy_type = policy_type;
115	p->policyvers = policyvers;
116	p->handle_unknown = handle_unknown;
117
118	policy_file_init(&pf);
119	pf.type = PF_USE_STDIO;
120	pf.fp = outfp;
121	return policydb_write(p, &pf);
122}
123
124static __attribute__((__noreturn__)) void usage(const char *progname)
125{
126	printf("usage:  %s [-h] [-V] [-b] [-C] [-E] [-U handle_unknown] [-m] [-M] [-o FILE] [-c VERSION] [INPUT]\n", progname);
127	printf("Build base and policy modules.\n");
128	printf("Options:\n");
129	printf("  INPUT      build module from INPUT (else read from \"%s\")\n",
130	       txtfile);
131	printf("  -V         show policy versions created by this program\n");
132	printf("  -b         treat input as a binary policy file\n");
133	printf("  -C         output CIL policy instead of binary policy\n");
134	printf("  -E         treat warnings as errors\n");
135	printf("  -h         print usage\n");
136	printf("  -U OPTION  How to handle unknown classes and permissions\n");
137	printf("               deny: Deny unknown kernel checks\n");
138	printf("               reject: Reject loading of policy with unknowns\n");
139	printf("               allow: Allow unknown kernel checks\n");
140	printf("  -m         build a policy module instead of a base module\n");
141	printf("  -M         enable MLS policy\n");
142	printf("  -o FILE    write module to FILE (else just check syntax)\n");
143	printf("  -c VERSION build a policy module targeting a modular policy version (%d-%d)\n",
144	       MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX);
145	exit(1);
146}
147
148int main(int argc, char **argv)
149{
150	const char *file = txtfile, *outfile = NULL;
151	unsigned int binary = 0, cil = 0;
152	int ch;
153	int show_version = 0;
154	policydb_t modpolicydb;
155	const struct option long_options[] = {
156		{"help", no_argument, NULL, 'h'},
157		{"output", required_argument, NULL, 'o'},
158		{"binary", no_argument, NULL, 'b'},
159		{"version", no_argument, NULL, 'V'},
160		{"handle-unknown", required_argument, NULL, 'U'},
161		{"mls", no_argument, NULL, 'M'},
162		{"cil", no_argument, NULL, 'C'},
163		{"werror", no_argument, NULL, 'E'},
164		{NULL, 0, NULL, 0}
165	};
166
167	while ((ch = getopt_long(argc, argv, "ho:bVEU:mMCc:", long_options, NULL)) != -1) {
168		switch (ch) {
169		case 'h':
170			usage(argv[0]);
171			break;
172		case 'o':
173			outfile = optarg;
174			break;
175		case 'b':
176			binary = 1;
177			file = binfile;
178			break;
179		case 'V':
180			show_version = 1;
181			break;
182		case 'E':
183			werror = 1;
184			break;
185		case 'U':
186			if (!strcasecmp(optarg, "deny")) {
187				handle_unknown = DENY_UNKNOWN;
188				break;
189			}
190			if (!strcasecmp(optarg, "reject")) {
191				handle_unknown = REJECT_UNKNOWN;
192				break;
193			}
194			if (!strcasecmp(optarg, "allow")) {
195				handle_unknown = ALLOW_UNKNOWN;
196				break;
197			}
198			usage(argv[0]);
199		case 'm':
200			policy_type = POLICY_MOD;
201			break;
202		case 'M':
203			mlspol = 1;
204			break;
205		case 'C':
206			cil = 1;
207			break;
208		case 'c': {
209			long int n;
210			errno = 0;
211			n = strtol(optarg, NULL, 10);
212			if (errno) {
213				fprintf(stderr,
214					"Invalid policyvers specified: %s\n",
215					optarg);
216				usage(argv[0]);
217			}
218
219			if (n < MOD_POLICYDB_VERSION_MIN
220			    || n > MOD_POLICYDB_VERSION_MAX) {
221				fprintf(stderr,
222					"policyvers value %ld not in range %d-%d\n",
223					n, MOD_POLICYDB_VERSION_MIN,
224					MOD_POLICYDB_VERSION_MAX);
225				usage(argv[0]);
226			}
227
228			policyvers = n;
229			break;
230		}
231		default:
232			usage(argv[0]);
233		}
234	}
235
236	if (show_version) {
237		printf("Module versions %d-%d\n",
238		       MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX);
239		exit(0);
240	}
241
242	if (handle_unknown && (policy_type != POLICY_BASE)) {
243		fprintf(stderr, "%s:  Handling of unknown classes and permissions is only valid in the base module.\n", argv[0]);
244		exit(1);
245	}
246
247	if (binary && (policy_type != POLICY_BASE)) {
248		fprintf(stderr, "%s:  -b and -m are incompatible with each other.\n", argv[0]);
249		exit(1);
250	}
251
252	if (optind != argc) {
253		file = argv[optind++];
254		if (optind != argc)
255			usage(argv[0]);
256	}
257
258	/* Set policydb and sidtab used by libsepol service functions
259	   to my structures, so that I can directly populate and
260	   manipulate them. */
261	sepol_set_policydb(&modpolicydb);
262	sepol_set_sidtab(&sidtab);
263
264	if (binary) {
265		if (read_binary_policy(&modpolicydb, file, argv[0]) == -1) {
266			exit(1);
267		}
268	} else {
269		if (policydb_init(&modpolicydb)) {
270			fprintf(stderr, "%s: out of memory!\n", argv[0]);
271			exit(1);
272		}
273
274		modpolicydb.policy_type = policy_type;
275		modpolicydb.mls = mlspol;
276		modpolicydb.handle_unknown = handle_unknown;
277
278		if (read_source_policy(&modpolicydb, file, argv[0]) == -1) {
279			exit(1);
280		}
281
282		if (hierarchy_check_constraints(NULL, &modpolicydb)) {
283			exit(1);
284		}
285	}
286
287	if (policy_type != POLICY_BASE && outfile) {
288		char *out_name;
289		char *separator;
290		char *mod_name = modpolicydb.name;
291		char *out_path = strdup(outfile);
292		if (out_path == NULL) {
293			fprintf(stderr, "%s:  out of memory\n", argv[0]);
294			exit(1);
295		}
296		out_name = basename(out_path);
297		separator = strrchr(out_name, '.');
298		if (separator) {
299			*separator = '\0';
300		}
301		if (strcmp(mod_name, out_name) != 0) {
302			fprintf(stderr,	"%s:  Module name %s is different than the output base filename %s\n", argv[0], mod_name, out_name);
303			exit(1);
304		}
305		free(out_path);
306	}
307
308	if (modpolicydb.policy_type == POLICY_BASE && !cil) {
309		/* Verify that we can successfully expand the base module. */
310		policydb_t kernpolicydb;
311
312		if (policydb_init(&kernpolicydb)) {
313			fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
314			exit(1);
315		}
316		if (link_modules(NULL, &modpolicydb, NULL, 0, 0)) {
317			fprintf(stderr, "%s:  link modules failed\n", argv[0]);
318			exit(1);
319		}
320		if (expand_module(NULL, &modpolicydb, &kernpolicydb, 0, 1)) {
321			fprintf(stderr, "%s:  expand module failed\n", argv[0]);
322			exit(1);
323		}
324		policydb_destroy(&kernpolicydb);
325	}
326
327	if (policydb_load_isids(&modpolicydb, &sidtab))
328		exit(1);
329
330	sepol_sidtab_destroy(&sidtab);
331
332	if (outfile) {
333		FILE *outfp = fopen(outfile, "w");
334
335		if (!outfp) {
336			fprintf(stderr, "%s:  error opening %s:  %s\n", argv[0], outfile, strerror(errno));
337			exit(1);
338		}
339
340		if (!cil) {
341			if (write_binary_policy(&modpolicydb, outfp) != 0) {
342				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
343				exit(1);
344			}
345		} else {
346			if (sepol_module_policydb_to_cil(outfp, &modpolicydb, 0) != 0) {
347				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
348				exit(1);
349			}
350		}
351
352		if (fclose(outfp)) {
353			fprintf(stderr, "%s:  error closing %s:  %s\n", argv[0], outfile, strerror(errno));
354			exit(1);
355		}
356	} else if (cil) {
357		fprintf(stderr, "%s:  No file to write CIL was specified\n", argv[0]);
358		exit(1);
359	}
360
361	policydb_destroy(&modpolicydb);
362
363	return 0;
364}
365
366/* FLASK */
367