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 
37 extern char *optarg;
38 extern int optind;
39 
40 static sidtab_t sidtab;
41 
42 extern int mlspol;
43 
44 static int handle_unknown = SEPOL_DENY_UNKNOWN;
45 static const char *txtfile = "policy.conf";
46 static const char *binfile = "policy";
47 
48 unsigned int policy_type = POLICY_BASE;
49 unsigned int policyvers = MOD_POLICYDB_VERSION_MAX;
50 
read_binary_policy(policydb_t * p,const char * file,const char * progname)51 static 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 
write_binary_policy(policydb_t * p,FILE * outfp)112 static 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 
usage(char * progname)126 static 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 
main(int argc,char ** argv)147 int 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