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