1 /*
2  * version_policy.c - Takes the given public platform policy, a private policy
3  * and a version number to produced a combined "versioned" policy file.
4  */
5 #include <errno.h>
6 #include <getopt.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <sys/stat.h>
10 #include <cil/android.h>
11 #include <cil/cil.h>
12 
usage(char * prog)13 void __attribute__ ((noreturn)) static usage(char *prog) {
14 	printf("Usage: %s [OPTION]...\n", prog);
15 	printf("\n");
16 	printf("Options:\n");
17 	printf("  -b, --base=<file>          (req'd) base policy for versioning.\n");
18 	printf("  -m, --mapping              generate cil version  mapping from base policy\n");
19 	printf("  -n, --number               (req'd) version number to use.\n");
20 	printf("  -o, --output=<file>        write cil policy to <file>\n");
21 	printf("  -t, --tgt_policy           policy to be versioned according to base policy\n");
22 	printf("  -h, --help                 display usage information\n");
23 	exit(1);
24 }
25 
26 /*
27  * read_cil_file - Initialize db and parse CIL input file.
28  */
read_cil_file(struct cil_db ** db,char * path)29 static int read_cil_file(struct cil_db **db, char *path) {
30 	int rc = SEPOL_ERR;
31 	FILE *file;
32 	struct stat filedata;
33 	uint32_t file_size;
34 	char *buff = NULL;
35 
36 	cil_db_init(db);
37 	file = fopen(path, "re");
38 	if (!file) {
39 		fprintf(stderr, "Could not open file: %s\n", path);
40 		goto file_err;
41 	}
42 	rc = stat(path, &filedata);
43 	if (rc == -1) {
44 		fprintf(stderr, "Could not stat file: %s - %s\n", path, strerror(errno));
45 		goto err;
46 	}
47 	file_size = filedata.st_size;
48 	buff = malloc(file_size);
49 	if (buff == NULL) {
50 		fprintf(stderr, "OOM!\n");
51 		rc = SEPOL_ERR;
52 		goto err;
53 	}
54 	rc = fread(buff, file_size, 1, file);
55 	if (rc != 1) {
56 		fprintf(stderr, "Failure reading file: %s\n", path);
57 		rc = SEPOL_ERR;
58 		goto err;
59 	}
60 	fclose(file);
61 	file = NULL;
62 
63 	/* creates parse_tree */
64 	rc = cil_add_file(*db, path, buff, file_size);
65 	if (rc != SEPOL_OK) {
66 		fprintf(stderr, "Failure adding %s to parse tree\n", path);
67 		goto parse_err;
68 	}
69 	free(buff);
70 
71 	return SEPOL_OK;
72 err:
73 	fclose(file);
74 parse_err:
75 	free(buff);
76 file_err:
77 	cil_db_destroy(db);
78 	return rc;
79 }
80 
main(int argc,char * argv[])81 int main(int argc, char *argv[])
82 {
83 	int opt_char;
84 	int opt_index = 0;
85 	int rc = SEPOL_ERR;
86 	bool mapping = false;
87 	char *base = NULL;
88 	char *tgt_policy = NULL;
89 	char *num = NULL;
90 	char *dot;
91 	char *output = NULL;
92 	FILE *output_file = NULL;
93 	struct cil_db *base_db = NULL;
94 	struct cil_db *out_db = NULL;
95 
96 	static struct option long_opts[] = {
97 		{"help", no_argument, 0, 'h'},
98 		{"base", required_argument, 0, 'b'},
99 		{"mapping", no_argument, 0, 'm'},
100 		{"number", required_argument, 0, 'n'},
101 		{"output", required_argument, 0, 'o'},
102 		{"tgt_policy", required_argument, 0, 't'},
103 		{0, 0, 0, 0}
104 	};
105 
106 	while (1) {
107 		opt_char = getopt_long(argc, argv, "b:mn:o:t:h", long_opts, &opt_index);
108 		if (opt_char == -1) {
109 			break;
110 		}
111 		switch (opt_char) {
112 		case 'b':
113 			base = strdup(optarg);
114 			break;
115 		case 'm':
116 			mapping = true;
117 			break;
118 		case 'n':
119 			num = strdup(optarg);
120 			break;
121 		case 'o':
122 			output = strdup(optarg);
123 			break;
124 		case 't':
125 			tgt_policy = strdup(optarg);
126 			break;
127 		case 'h':
128 			usage(argv[0]);
129 		default:
130 			fprintf(stderr, "Unsupported option: %s\n", optarg);
131 			usage(argv[0]);
132 		}
133 	}
134 	if (optind < argc) {
135 		fprintf(stderr, "Unknown arguments supplied\n");
136 		usage(argv[0]);
137 	}
138 	if (num == NULL || base == NULL || (mapping == false && tgt_policy == NULL)) {
139 		fprintf(stderr, "Please specify required arguments\n");
140 		usage(argv[0]);
141 	}
142 
143 	/* policy language doesn't like '.', so replace them with '_' in mapping version */
144 	dot = num;
145 	while ((dot = strchr(dot, '.')) != NULL) {
146 		*dot = '_';
147 		++dot;
148 	}
149 
150 	if (mapping && tgt_policy) {
151 		fprintf(stderr, "Please select only one mode between --mapping and --tgt_policy\n");
152 		usage(argv[0]);
153 	}
154 
155 	/* gimme only the important details */
156 	cil_set_log_level(CIL_WARN);
157 
158 	/* read platform policy */
159 	rc = read_cil_file(&base_db, base);
160 	if (rc != SEPOL_OK) {
161 		goto exit;
162 	}
163 
164 	if (mapping) {
165 		rc = cil_android_attrib_mapping(&out_db, base_db, num);
166 		if (rc != SEPOL_OK)
167 			goto exit;
168 	} else {
169 		/* read target policy, ready for manipulation */
170 		rc = read_cil_file(&out_db, tgt_policy);
171 		if (rc != SEPOL_OK) {
172 			goto exit;
173 		}
174 		/* attributize the target policy */
175 		rc = cil_android_attributize(out_db, base_db, num);
176 		if (rc != SEPOL_OK) {
177 			goto exit;
178 		}
179 	}
180 
181 	output_file = fopen(output, "we");
182 	if (!output_file) {
183 		fprintf(stderr, "Could not open file: %s\n", output);
184 		goto exit;
185 	}
186 
187 	rc = cil_write_build_ast(output_file, out_db);
188 	if (rc != SEPOL_OK) {
189 		fprintf(stderr, "Failed to write AST\n");
190 		goto build_err;
191 	}
192 
193 build_err:
194 	fclose(output_file);
195 exit:
196 	free(base);
197 	free(tgt_policy);
198 	free(num);
199 	free(output);
200 	cil_db_destroy(&base_db);
201 	cil_db_destroy(&out_db);
202 	return rc;
203 }
204