1#include <stdio.h>
2#include <stdlib.h>
3#include <ctype.h>
4#include <errno.h>
5
6#include <sepol/policydb/policydb.h>
7#include <sepol/policydb/conditional.h>
8
9#include "debug.h"
10#include "private.h"
11#include "dso.h"
12
13/* -- Deprecated -- */
14
15static char *strtrim(char *dest, char *source, int size)
16{
17	int i = 0;
18	char *ptr = source;
19	i = 0;
20	while (isspace(*ptr) && i < size) {
21		ptr++;
22		i++;
23	}
24	strncpy(dest, ptr, size);
25	for (i = strlen(dest) - 1; i > 0; i--) {
26		if (!isspace(dest[i]))
27			break;
28	}
29	dest[i + 1] = '\0';
30	return dest;
31}
32
33static int process_boolean(char *buffer, char *name, int namesize, int *val)
34{
35	char name1[BUFSIZ];
36	char *ptr = NULL;
37	char *tok;
38
39	/* Skip spaces */
40	while (isspace(buffer[0]))
41		buffer++;
42	/* Ignore comments */
43	if (buffer[0] == '#')
44		return 0;
45
46	tok = strtok_r(buffer, "=", &ptr);
47	if (!tok) {
48		ERR(NULL, "illegal boolean definition %s", buffer);
49		return -1;
50	}
51	strncpy(name1, tok, BUFSIZ - 1);
52	strtrim(name, name1, namesize - 1);
53
54	tok = strtok_r(NULL, "\0", &ptr);
55	if (!tok) {
56		ERR(NULL, "illegal boolean definition %s=%s", name, buffer);
57		return -1;
58	}
59
60	while (isspace(*tok))
61		tok++;
62
63	*val = -1;
64	if (isdigit(tok[0]))
65		*val = atoi(tok);
66	else if (!strncasecmp(tok, "true", sizeof("true") - 1))
67		*val = 1;
68	else if (!strncasecmp(tok, "false", sizeof("false") - 1))
69		*val = 0;
70	if (*val != 0 && *val != 1) {
71		ERR(NULL, "illegal value for boolean %s=%s", name, tok);
72		return -1;
73	}
74	return 1;
75}
76
77static int load_booleans(struct policydb *policydb, const char *path,
78			 int *changesp)
79{
80	FILE *boolf;
81	char *buffer = NULL;
82	char localbools[BUFSIZ];
83	char name[BUFSIZ];
84	int val;
85	int errors = 0, changes = 0;
86	struct cond_bool_datum *datum;
87
88	boolf = fopen(path, "r");
89	if (boolf == NULL)
90		goto localbool;
91
92#ifdef __APPLE__
93        if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) {
94          ERR(NULL, "out of memory");
95	  return -1;
96	}
97
98        while(fgets(buffer, 255, boolf) != NULL) {
99#else
100	size_t size = 0;
101	while (getline(&buffer, &size, boolf) > 0) {
102#endif
103		int ret = process_boolean(buffer, name, sizeof(name), &val);
104		if (ret == -1)
105			errors++;
106		if (ret == 1) {
107			datum = hashtab_search(policydb->p_bools.table, name);
108			if (!datum) {
109				ERR(NULL, "unknown boolean %s", name);
110				errors++;
111				continue;
112			}
113			if (datum->state != val) {
114				datum->state = val;
115				changes++;
116			}
117		}
118	}
119	fclose(boolf);
120      localbool:
121	snprintf(localbools, sizeof(localbools), "%s.local", path);
122	boolf = fopen(localbools, "r");
123	if (boolf != NULL) {
124
125#ifdef __APPLE__
126
127	  while(fgets(buffer, 255, boolf) != NULL) {
128#else
129
130	    while (getline(&buffer, &size, boolf) > 0) {
131#endif
132			int ret =
133			    process_boolean(buffer, name, sizeof(name), &val);
134			if (ret == -1)
135				errors++;
136			if (ret == 1) {
137				datum =
138				    hashtab_search(policydb->p_bools.table,
139						   name);
140				if (!datum) {
141					ERR(NULL, "unknown boolean %s", name);
142					errors++;
143					continue;
144				}
145				if (datum->state != val) {
146					datum->state = val;
147					changes++;
148				}
149			}
150		}
151		fclose(boolf);
152	}
153	free(buffer);
154	if (errors)
155		errno = EINVAL;
156	*changesp = changes;
157	return errors ? -1 : 0;
158}
159
160int sepol_genbools(void *data, size_t len, const char *booleans)
161{
162	struct policydb policydb;
163	struct policy_file pf;
164	int rc, changes = 0;
165
166	if (policydb_init(&policydb))
167		goto err;
168	if (policydb_from_image(NULL, data, len, &policydb) < 0)
169		goto err;
170
171	if (load_booleans(&policydb, booleans, &changes) < 0) {
172		WARN(NULL, "error while reading %s", booleans);
173	}
174
175	if (!changes)
176		goto out;
177
178	if (evaluate_conds(&policydb) < 0) {
179		ERR(NULL, "error while re-evaluating conditionals");
180		errno = EINVAL;
181		goto err_destroy;
182	}
183
184	policy_file_init(&pf);
185	pf.type = PF_USE_MEMORY;
186	pf.data = data;
187	pf.len = len;
188	rc = policydb_write(&policydb, &pf);
189	if (rc) {
190		ERR(NULL, "unable to write new binary policy image");
191		errno = EINVAL;
192		goto err_destroy;
193	}
194
195      out:
196	policydb_destroy(&policydb);
197	return 0;
198
199      err_destroy:
200	policydb_destroy(&policydb);
201
202      err:
203	return -1;
204}
205
206int hidden sepol_genbools_policydb(policydb_t * policydb, const char *booleans)
207{
208	int rc, changes = 0;
209
210	rc = load_booleans(policydb, booleans, &changes);
211	if (!rc && changes)
212		rc = evaluate_conds(policydb);
213	if (rc)
214		errno = EINVAL;
215	return rc;
216}
217
218/* -- End Deprecated -- */
219
220int sepol_genbools_array(void *data, size_t len, char **names, int *values,
221			 int nel)
222{
223	struct policydb policydb;
224	struct policy_file pf;
225	int rc, i, errors = 0;
226	struct cond_bool_datum *datum;
227
228	/* Create policy database from image */
229	if (policydb_init(&policydb))
230		goto err;
231	if (policydb_from_image(NULL, data, len, &policydb) < 0)
232		goto err;
233
234	for (i = 0; i < nel; i++) {
235		datum = hashtab_search(policydb.p_bools.table, names[i]);
236		if (!datum) {
237			ERR(NULL, "boolean %s no longer in policy", names[i]);
238			errors++;
239			continue;
240		}
241		if (values[i] != 0 && values[i] != 1) {
242			ERR(NULL, "illegal value %d for boolean %s",
243			    values[i], names[i]);
244			errors++;
245			continue;
246		}
247		datum->state = values[i];
248	}
249
250	if (evaluate_conds(&policydb) < 0) {
251		ERR(NULL, "error while re-evaluating conditionals");
252		errno = EINVAL;
253		goto err_destroy;
254	}
255
256	policy_file_init(&pf);
257	pf.type = PF_USE_MEMORY;
258	pf.data = data;
259	pf.len = len;
260	rc = policydb_write(&policydb, &pf);
261	if (rc) {
262		ERR(NULL, "unable to write binary policy");
263		errno = EINVAL;
264		goto err_destroy;
265	}
266	if (errors) {
267		errno = EINVAL;
268		goto err_destroy;
269	}
270
271	policydb_destroy(&policydb);
272	return 0;
273
274      err_destroy:
275	policydb_destroy(&policydb);
276
277      err:
278	return -1;
279}
280