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