1/* Authors: Karl MacMillan <kmacmillan@tresys.com>
2 *
3 * Copyright (C) 2004 Tresys Technology, LLC
4 *	This program is free software; you can redistribute it and/or modify
5 *  	it under the terms of the GNU General Public License as published by
6 *	the Free Software Foundation, version 2.
7 */
8
9#include <sepol/module.h>
10#include <getopt.h>
11#include <fcntl.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <unistd.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <sys/mman.h>
19#include <fcntl.h>
20#include <errno.h>
21
22char *progname = NULL;
23extern char *optarg;
24
25static __attribute__((__noreturn__)) void usage(const char *prog)
26{
27	printf("usage: %s -o <output file> -m <module> [-f <file contexts>]\n",
28	       prog);
29	printf("Options:\n");
30	printf("  -o --outfile		Output file (required)\n");
31	printf("  -m --module		Module file (required)\n");
32	printf("  -f --fc		File contexts file\n");
33	printf("  -s --seuser		Seusers file (only valid in base)\n");
34	printf
35	    ("  -u --user_extra	user_extra file (only valid in base)\n");
36	printf("  -n --nc		Netfilter contexts file\n");
37	exit(1);
38}
39
40static int file_to_policy_file(const char *filename, struct sepol_policy_file **pf,
41			       const char *mode)
42{
43	FILE *f;
44
45	if (sepol_policy_file_create(pf)) {
46		fprintf(stderr, "%s:  Out of memory\n", progname);
47		return -1;
48	}
49
50	f = fopen(filename, mode);
51	if (!f) {
52		fprintf(stderr, "%s:  Could not open file %s:  %s\n", progname,
53			strerror(errno), filename);
54		return -1;
55	}
56	sepol_policy_file_set_fp(*pf, f);
57	return 0;
58}
59
60static int file_to_data(const char *path, char **data, size_t * len)
61{
62	int fd;
63	struct stat sb;
64	fd = open(path, O_RDONLY);
65	if (fd < 0) {
66		fprintf(stderr, "%s:  Failed to open %s:  %s\n", progname, path,
67			strerror(errno));
68		return -1;
69	}
70	if (fstat(fd, &sb) < 0) {
71		fprintf(stderr, "%s:  Failed to fstat %s:  %s\n", progname,
72			path, strerror(errno));
73		goto err;
74	}
75	if (!sb.st_size) {
76		*len = 0;
77		return 0;
78	}
79
80	*data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
81	if (*data == MAP_FAILED) {
82		fprintf(stderr, "%s:  Failed to mmap %s:  %s\n", progname, path,
83			strerror(errno));
84		goto err;
85	}
86	*len = sb.st_size;
87	close(fd);
88	return 0;
89      err:
90	close(fd);
91	return -1;
92}
93
94int main(int argc, char **argv)
95{
96	struct sepol_module_package *pkg;
97	struct sepol_policy_file *mod, *out;
98	char *module = NULL, *file_contexts = NULL, *seusers =
99	    NULL, *user_extra = NULL;
100	char *fcdata = NULL, *outfile = NULL, *seusersdata =
101	    NULL, *user_extradata = NULL;
102	char *netfilter_contexts = NULL, *ncdata = NULL;
103	size_t fclen = 0, seuserslen = 0, user_extralen = 0, nclen = 0;
104	int i;
105
106	static struct option opts[] = {
107		{"module", required_argument, NULL, 'm'},
108		{"fc", required_argument, NULL, 'f'},
109		{"seuser", required_argument, NULL, 's'},
110		{"user_extra", required_argument, NULL, 'u'},
111		{"nc", required_argument, NULL, 'n'},
112		{"outfile", required_argument, NULL, 'o'},
113		{"help", 0, NULL, 'h'},
114		{NULL, 0, NULL, 0}
115	};
116
117	while ((i = getopt_long(argc, argv, "m:f:s:u:o:n:h", opts, NULL)) != -1) {
118		switch (i) {
119		case 'h':
120			usage(argv[0]);
121			exit(0);
122		case 'm':
123			if (module) {
124				fprintf(stderr,
125					"May not specify more than one module\n");
126				exit(1);
127			}
128			module = strdup(optarg);
129			if (!module)
130				exit(1);
131			break;
132		case 'f':
133			if (file_contexts) {
134				fprintf(stderr,
135					"May not specify more than one file context file\n");
136				exit(1);
137			}
138			file_contexts = strdup(optarg);
139			if (!file_contexts)
140				exit(1);
141			break;
142		case 'o':
143			if (outfile) {
144				fprintf(stderr,
145					"May not specify more than one output file\n");
146				exit(1);
147			}
148			outfile = strdup(optarg);
149			if (!outfile)
150				exit(1);
151			break;
152		case 's':
153			if (seusers) {
154				fprintf(stderr,
155					"May not specify more than one seuser file\n");
156				exit(1);
157			}
158			seusers = strdup(optarg);
159			if (!seusers)
160				exit(1);
161			break;
162		case 'u':
163			if (user_extra) {
164				fprintf(stderr,
165					"May not specify more than one user_extra file\n");
166				exit(1);
167			}
168			user_extra = strdup(optarg);
169			if (!user_extra)
170				exit(1);
171			break;
172		case 'n':
173			if (netfilter_contexts) {
174				fprintf(stderr,
175					"May not specify more than one netfilter contexts file\n");
176				exit(1);
177			}
178			netfilter_contexts = strdup(optarg);
179			if (!netfilter_contexts)
180				exit(1);
181			break;
182		}
183	}
184
185	progname = argv[0];
186
187	if (!module || !outfile) {
188		usage(argv[0]);
189		exit(0);
190	}
191
192	if (file_contexts) {
193		if (file_to_data(file_contexts, &fcdata, &fclen))
194			exit(1);
195	}
196
197	if (seusers) {
198		if (file_to_data(seusers, &seusersdata, &seuserslen))
199			exit(1);
200	}
201
202	if (user_extra) {
203		if (file_to_data(user_extra, &user_extradata, &user_extralen))
204			exit(1);
205	}
206
207	if (netfilter_contexts) {
208		if (file_to_data(netfilter_contexts, &ncdata, &nclen))
209			exit(1);
210	}
211
212	if (file_to_policy_file(module, &mod, "r"))
213		exit(1);
214
215	if (sepol_module_package_create(&pkg)) {
216		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
217		exit(1);
218	}
219
220	if (sepol_policydb_read(sepol_module_package_get_policy(pkg), mod)) {
221		fprintf(stderr,
222			"%s:  Error while reading policy module from %s\n",
223			argv[0], module);
224		exit(1);
225	}
226
227	if (fclen)
228		sepol_module_package_set_file_contexts(pkg, fcdata, fclen);
229
230	if (seuserslen)
231		sepol_module_package_set_seusers(pkg, seusersdata, seuserslen);
232
233	if (user_extra)
234		sepol_module_package_set_user_extra(pkg, user_extradata,
235						    user_extralen);
236
237	if (nclen)
238		sepol_module_package_set_netfilter_contexts(pkg, ncdata, nclen);
239
240	if (file_to_policy_file(outfile, &out, "w"))
241		exit(1);
242
243	if (sepol_module_package_write(pkg, out)) {
244		fprintf(stderr,
245			"%s:  Error while writing module package to %s\n",
246			argv[0], argv[1]);
247		exit(1);
248	}
249
250	if (fclen)
251		munmap(fcdata, fclen);
252	if (nclen)
253		munmap(ncdata, nclen);
254	sepol_policy_file_free(mod);
255	sepol_policy_file_free(out);
256	sepol_module_package_free(pkg);
257	free(file_contexts);
258	free(outfile);
259	free(module);
260	free(seusers);
261	free(user_extra);
262	exit(0);
263}
264