1255e72915d4cbddceb435e13d81601755714e9fSE Android#include <stdio.h>
2255e72915d4cbddceb435e13d81601755714e9fSE Android#include <stdlib.h>
3255e72915d4cbddceb435e13d81601755714e9fSE Android#include <ctype.h>
4255e72915d4cbddceb435e13d81601755714e9fSE Android#include <errno.h>
5255e72915d4cbddceb435e13d81601755714e9fSE Android
6255e72915d4cbddceb435e13d81601755714e9fSE Android#include <sepol/policydb/policydb.h>
7255e72915d4cbddceb435e13d81601755714e9fSE Android#include <sepol/policydb/conditional.h>
8255e72915d4cbddceb435e13d81601755714e9fSE Android
9255e72915d4cbddceb435e13d81601755714e9fSE Android#include "debug.h"
10255e72915d4cbddceb435e13d81601755714e9fSE Android#include "private.h"
11255e72915d4cbddceb435e13d81601755714e9fSE Android#include "dso.h"
12255e72915d4cbddceb435e13d81601755714e9fSE Android
13255e72915d4cbddceb435e13d81601755714e9fSE Android/* -- Deprecated -- */
14255e72915d4cbddceb435e13d81601755714e9fSE Android
15255e72915d4cbddceb435e13d81601755714e9fSE Androidstatic char *strtrim(char *dest, char *source, int size)
16255e72915d4cbddceb435e13d81601755714e9fSE Android{
17255e72915d4cbddceb435e13d81601755714e9fSE Android	int i = 0;
18255e72915d4cbddceb435e13d81601755714e9fSE Android	char *ptr = source;
19255e72915d4cbddceb435e13d81601755714e9fSE Android	i = 0;
20255e72915d4cbddceb435e13d81601755714e9fSE Android	while (isspace(*ptr) && i < size) {
21255e72915d4cbddceb435e13d81601755714e9fSE Android		ptr++;
22255e72915d4cbddceb435e13d81601755714e9fSE Android		i++;
23255e72915d4cbddceb435e13d81601755714e9fSE Android	}
24255e72915d4cbddceb435e13d81601755714e9fSE Android	strncpy(dest, ptr, size);
25255e72915d4cbddceb435e13d81601755714e9fSE Android	for (i = strlen(dest) - 1; i > 0; i--) {
26255e72915d4cbddceb435e13d81601755714e9fSE Android		if (!isspace(dest[i]))
27255e72915d4cbddceb435e13d81601755714e9fSE Android			break;
28255e72915d4cbddceb435e13d81601755714e9fSE Android	}
29255e72915d4cbddceb435e13d81601755714e9fSE Android	dest[i + 1] = '\0';
30255e72915d4cbddceb435e13d81601755714e9fSE Android	return dest;
31255e72915d4cbddceb435e13d81601755714e9fSE Android}
32255e72915d4cbddceb435e13d81601755714e9fSE Android
33255e72915d4cbddceb435e13d81601755714e9fSE Androidstatic int process_boolean(char *buffer, char *name, int namesize, int *val)
34255e72915d4cbddceb435e13d81601755714e9fSE Android{
35255e72915d4cbddceb435e13d81601755714e9fSE Android	char name1[BUFSIZ];
36dedcd596b31e0e4fc15d75b3a8b5e6b61e6c28b3Stephen Smalley	char *ptr = NULL;
37255e72915d4cbddceb435e13d81601755714e9fSE Android	char *tok = strtok_r(buffer, "=", &ptr);
38255e72915d4cbddceb435e13d81601755714e9fSE Android	if (tok) {
39255e72915d4cbddceb435e13d81601755714e9fSE Android		strncpy(name1, tok, BUFSIZ - 1);
40255e72915d4cbddceb435e13d81601755714e9fSE Android		strtrim(name, name1, namesize - 1);
41255e72915d4cbddceb435e13d81601755714e9fSE Android		if (name[0] == '#')
42255e72915d4cbddceb435e13d81601755714e9fSE Android			return 0;
43255e72915d4cbddceb435e13d81601755714e9fSE Android		tok = strtok_r(NULL, "\0", &ptr);
44255e72915d4cbddceb435e13d81601755714e9fSE Android		if (tok) {
45255e72915d4cbddceb435e13d81601755714e9fSE Android			while (isspace(*tok))
46255e72915d4cbddceb435e13d81601755714e9fSE Android				tok++;
47255e72915d4cbddceb435e13d81601755714e9fSE Android			*val = -1;
48255e72915d4cbddceb435e13d81601755714e9fSE Android			if (isdigit(tok[0]))
49255e72915d4cbddceb435e13d81601755714e9fSE Android				*val = atoi(tok);
50255e72915d4cbddceb435e13d81601755714e9fSE Android			else if (!strncasecmp(tok, "true", sizeof("true") - 1))
51255e72915d4cbddceb435e13d81601755714e9fSE Android				*val = 1;
52255e72915d4cbddceb435e13d81601755714e9fSE Android			else if (!strncasecmp
53255e72915d4cbddceb435e13d81601755714e9fSE Android				 (tok, "false", sizeof("false") - 1))
54255e72915d4cbddceb435e13d81601755714e9fSE Android				*val = 0;
55255e72915d4cbddceb435e13d81601755714e9fSE Android			if (*val != 0 && *val != 1) {
56255e72915d4cbddceb435e13d81601755714e9fSE Android				ERR(NULL, "illegal value for boolean "
57255e72915d4cbddceb435e13d81601755714e9fSE Android				    "%s=%s", name, tok);
58255e72915d4cbddceb435e13d81601755714e9fSE Android				return -1;
59255e72915d4cbddceb435e13d81601755714e9fSE Android			}
60255e72915d4cbddceb435e13d81601755714e9fSE Android
61255e72915d4cbddceb435e13d81601755714e9fSE Android		}
62255e72915d4cbddceb435e13d81601755714e9fSE Android	}
63255e72915d4cbddceb435e13d81601755714e9fSE Android	return 1;
64255e72915d4cbddceb435e13d81601755714e9fSE Android}
65255e72915d4cbddceb435e13d81601755714e9fSE Android
66255e72915d4cbddceb435e13d81601755714e9fSE Androidstatic int load_booleans(struct policydb *policydb, const char *path,
67255e72915d4cbddceb435e13d81601755714e9fSE Android			 int *changesp)
68255e72915d4cbddceb435e13d81601755714e9fSE Android{
69255e72915d4cbddceb435e13d81601755714e9fSE Android	FILE *boolf;
70255e72915d4cbddceb435e13d81601755714e9fSE Android	char *buffer = NULL;
71255e72915d4cbddceb435e13d81601755714e9fSE Android	size_t size = 0;
72255e72915d4cbddceb435e13d81601755714e9fSE Android	char localbools[BUFSIZ];
73255e72915d4cbddceb435e13d81601755714e9fSE Android	char name[BUFSIZ];
74255e72915d4cbddceb435e13d81601755714e9fSE Android	int val;
75255e72915d4cbddceb435e13d81601755714e9fSE Android	int errors = 0, changes = 0;
76255e72915d4cbddceb435e13d81601755714e9fSE Android	struct cond_bool_datum *datum;
77255e72915d4cbddceb435e13d81601755714e9fSE Android
78255e72915d4cbddceb435e13d81601755714e9fSE Android	boolf = fopen(path, "r");
79255e72915d4cbddceb435e13d81601755714e9fSE Android	if (boolf == NULL)
80255e72915d4cbddceb435e13d81601755714e9fSE Android		goto localbool;
81255e72915d4cbddceb435e13d81601755714e9fSE Android
82b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley#ifdef DARWIN
83b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley        if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) {
84b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley          ERR(NULL, "out of memory");
85b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley	  return -1;
86b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley	}
87b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley
88b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley        while(fgets(buffer, 255, boolf) != NULL) {
89b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley#else
90255e72915d4cbddceb435e13d81601755714e9fSE Android	while (getline(&buffer, &size, boolf) > 0) {
91b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley#endif
92255e72915d4cbddceb435e13d81601755714e9fSE Android		int ret = process_boolean(buffer, name, sizeof(name), &val);
93255e72915d4cbddceb435e13d81601755714e9fSE Android		if (ret == -1)
94255e72915d4cbddceb435e13d81601755714e9fSE Android			errors++;
95255e72915d4cbddceb435e13d81601755714e9fSE Android		if (ret == 1) {
96255e72915d4cbddceb435e13d81601755714e9fSE Android			datum = hashtab_search(policydb->p_bools.table, name);
97255e72915d4cbddceb435e13d81601755714e9fSE Android			if (!datum) {
98255e72915d4cbddceb435e13d81601755714e9fSE Android				ERR(NULL, "unknown boolean %s", name);
99255e72915d4cbddceb435e13d81601755714e9fSE Android				errors++;
100255e72915d4cbddceb435e13d81601755714e9fSE Android				continue;
101255e72915d4cbddceb435e13d81601755714e9fSE Android			}
102255e72915d4cbddceb435e13d81601755714e9fSE Android			if (datum->state != val) {
103255e72915d4cbddceb435e13d81601755714e9fSE Android				datum->state = val;
104255e72915d4cbddceb435e13d81601755714e9fSE Android				changes++;
105255e72915d4cbddceb435e13d81601755714e9fSE Android			}
106255e72915d4cbddceb435e13d81601755714e9fSE Android		}
107255e72915d4cbddceb435e13d81601755714e9fSE Android	}
108255e72915d4cbddceb435e13d81601755714e9fSE Android	fclose(boolf);
109255e72915d4cbddceb435e13d81601755714e9fSE Android      localbool:
110255e72915d4cbddceb435e13d81601755714e9fSE Android	snprintf(localbools, sizeof(localbools), "%s.local", path);
111255e72915d4cbddceb435e13d81601755714e9fSE Android	boolf = fopen(localbools, "r");
112255e72915d4cbddceb435e13d81601755714e9fSE Android	if (boolf != NULL) {
113b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley
114b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley#ifdef DARWIN
115b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley
116b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley	  while(fgets(buffer, 255, boolf) != NULL) {
117b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley#else
118b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley
119b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley	    while (getline(&buffer, &size, boolf) > 0) {
120b1db49d77789525ac1f4e73e978e35694f21ea1aStephen Smalley#endif
121255e72915d4cbddceb435e13d81601755714e9fSE Android			int ret =
122255e72915d4cbddceb435e13d81601755714e9fSE Android			    process_boolean(buffer, name, sizeof(name), &val);
123255e72915d4cbddceb435e13d81601755714e9fSE Android			if (ret == -1)
124255e72915d4cbddceb435e13d81601755714e9fSE Android				errors++;
125255e72915d4cbddceb435e13d81601755714e9fSE Android			if (ret == 1) {
126255e72915d4cbddceb435e13d81601755714e9fSE Android				datum =
127255e72915d4cbddceb435e13d81601755714e9fSE Android				    hashtab_search(policydb->p_bools.table,
128255e72915d4cbddceb435e13d81601755714e9fSE Android						   name);
129255e72915d4cbddceb435e13d81601755714e9fSE Android				if (!datum) {
130255e72915d4cbddceb435e13d81601755714e9fSE Android					ERR(NULL, "unknown boolean %s", name);
131255e72915d4cbddceb435e13d81601755714e9fSE Android					errors++;
132255e72915d4cbddceb435e13d81601755714e9fSE Android					continue;
133255e72915d4cbddceb435e13d81601755714e9fSE Android				}
134255e72915d4cbddceb435e13d81601755714e9fSE Android				if (datum->state != val) {
135255e72915d4cbddceb435e13d81601755714e9fSE Android					datum->state = val;
136255e72915d4cbddceb435e13d81601755714e9fSE Android					changes++;
137255e72915d4cbddceb435e13d81601755714e9fSE Android				}
138255e72915d4cbddceb435e13d81601755714e9fSE Android			}
139255e72915d4cbddceb435e13d81601755714e9fSE Android		}
140255e72915d4cbddceb435e13d81601755714e9fSE Android		fclose(boolf);
141255e72915d4cbddceb435e13d81601755714e9fSE Android	}
142255e72915d4cbddceb435e13d81601755714e9fSE Android	free(buffer);
143255e72915d4cbddceb435e13d81601755714e9fSE Android	if (errors)
144255e72915d4cbddceb435e13d81601755714e9fSE Android		errno = EINVAL;
145255e72915d4cbddceb435e13d81601755714e9fSE Android	*changesp = changes;
146255e72915d4cbddceb435e13d81601755714e9fSE Android	return errors ? -1 : 0;
147255e72915d4cbddceb435e13d81601755714e9fSE Android}
148255e72915d4cbddceb435e13d81601755714e9fSE Android
149255e72915d4cbddceb435e13d81601755714e9fSE Androidint sepol_genbools(void *data, size_t len, char *booleans)
150255e72915d4cbddceb435e13d81601755714e9fSE Android{
151255e72915d4cbddceb435e13d81601755714e9fSE Android	struct policydb policydb;
152255e72915d4cbddceb435e13d81601755714e9fSE Android	struct policy_file pf;
153255e72915d4cbddceb435e13d81601755714e9fSE Android	int rc, changes = 0;
154255e72915d4cbddceb435e13d81601755714e9fSE Android
155255e72915d4cbddceb435e13d81601755714e9fSE Android	if (policydb_init(&policydb))
156255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err;
157255e72915d4cbddceb435e13d81601755714e9fSE Android	if (policydb_from_image(NULL, data, len, &policydb) < 0)
158255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err;
159255e72915d4cbddceb435e13d81601755714e9fSE Android
160255e72915d4cbddceb435e13d81601755714e9fSE Android	if (load_booleans(&policydb, booleans, &changes) < 0) {
161255e72915d4cbddceb435e13d81601755714e9fSE Android		WARN(NULL, "error while reading %s", booleans);
162255e72915d4cbddceb435e13d81601755714e9fSE Android	}
163255e72915d4cbddceb435e13d81601755714e9fSE Android
164255e72915d4cbddceb435e13d81601755714e9fSE Android	if (!changes)
165255e72915d4cbddceb435e13d81601755714e9fSE Android		goto out;
166255e72915d4cbddceb435e13d81601755714e9fSE Android
167255e72915d4cbddceb435e13d81601755714e9fSE Android	if (evaluate_conds(&policydb) < 0) {
168255e72915d4cbddceb435e13d81601755714e9fSE Android		ERR(NULL, "error while re-evaluating conditionals");
169255e72915d4cbddceb435e13d81601755714e9fSE Android		errno = EINVAL;
170255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err_destroy;
171255e72915d4cbddceb435e13d81601755714e9fSE Android	}
172255e72915d4cbddceb435e13d81601755714e9fSE Android
173255e72915d4cbddceb435e13d81601755714e9fSE Android	policy_file_init(&pf);
174255e72915d4cbddceb435e13d81601755714e9fSE Android	pf.type = PF_USE_MEMORY;
175255e72915d4cbddceb435e13d81601755714e9fSE Android	pf.data = data;
176255e72915d4cbddceb435e13d81601755714e9fSE Android	pf.len = len;
177255e72915d4cbddceb435e13d81601755714e9fSE Android	rc = policydb_write(&policydb, &pf);
178255e72915d4cbddceb435e13d81601755714e9fSE Android	if (rc) {
179255e72915d4cbddceb435e13d81601755714e9fSE Android		ERR(NULL, "unable to write new binary policy image");
180255e72915d4cbddceb435e13d81601755714e9fSE Android		errno = EINVAL;
181255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err_destroy;
182255e72915d4cbddceb435e13d81601755714e9fSE Android	}
183255e72915d4cbddceb435e13d81601755714e9fSE Android
184255e72915d4cbddceb435e13d81601755714e9fSE Android      out:
185255e72915d4cbddceb435e13d81601755714e9fSE Android	policydb_destroy(&policydb);
186255e72915d4cbddceb435e13d81601755714e9fSE Android	return 0;
187255e72915d4cbddceb435e13d81601755714e9fSE Android
188255e72915d4cbddceb435e13d81601755714e9fSE Android      err_destroy:
189255e72915d4cbddceb435e13d81601755714e9fSE Android	policydb_destroy(&policydb);
190255e72915d4cbddceb435e13d81601755714e9fSE Android
191255e72915d4cbddceb435e13d81601755714e9fSE Android      err:
192255e72915d4cbddceb435e13d81601755714e9fSE Android	return -1;
193255e72915d4cbddceb435e13d81601755714e9fSE Android}
194255e72915d4cbddceb435e13d81601755714e9fSE Android
195255e72915d4cbddceb435e13d81601755714e9fSE Androidint hidden sepol_genbools_policydb(policydb_t * policydb, const char *booleans)
196255e72915d4cbddceb435e13d81601755714e9fSE Android{
197255e72915d4cbddceb435e13d81601755714e9fSE Android	int rc, changes = 0;
198255e72915d4cbddceb435e13d81601755714e9fSE Android
199255e72915d4cbddceb435e13d81601755714e9fSE Android	rc = load_booleans(policydb, booleans, &changes);
200255e72915d4cbddceb435e13d81601755714e9fSE Android	if (!rc && changes)
201255e72915d4cbddceb435e13d81601755714e9fSE Android		rc = evaluate_conds(policydb);
202255e72915d4cbddceb435e13d81601755714e9fSE Android	if (rc)
203255e72915d4cbddceb435e13d81601755714e9fSE Android		errno = EINVAL;
204255e72915d4cbddceb435e13d81601755714e9fSE Android	return rc;
205255e72915d4cbddceb435e13d81601755714e9fSE Android}
206255e72915d4cbddceb435e13d81601755714e9fSE Android
207255e72915d4cbddceb435e13d81601755714e9fSE Android/* -- End Deprecated -- */
208255e72915d4cbddceb435e13d81601755714e9fSE Android
209255e72915d4cbddceb435e13d81601755714e9fSE Androidint sepol_genbools_array(void *data, size_t len, char **names, int *values,
210255e72915d4cbddceb435e13d81601755714e9fSE Android			 int nel)
211255e72915d4cbddceb435e13d81601755714e9fSE Android{
212255e72915d4cbddceb435e13d81601755714e9fSE Android	struct policydb policydb;
213255e72915d4cbddceb435e13d81601755714e9fSE Android	struct policy_file pf;
214255e72915d4cbddceb435e13d81601755714e9fSE Android	int rc, i, errors = 0;
215255e72915d4cbddceb435e13d81601755714e9fSE Android	struct cond_bool_datum *datum;
216255e72915d4cbddceb435e13d81601755714e9fSE Android
217255e72915d4cbddceb435e13d81601755714e9fSE Android	/* Create policy database from image */
218255e72915d4cbddceb435e13d81601755714e9fSE Android	if (policydb_init(&policydb))
219255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err;
220255e72915d4cbddceb435e13d81601755714e9fSE Android	if (policydb_from_image(NULL, data, len, &policydb) < 0)
221255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err;
222255e72915d4cbddceb435e13d81601755714e9fSE Android
223255e72915d4cbddceb435e13d81601755714e9fSE Android	for (i = 0; i < nel; i++) {
224255e72915d4cbddceb435e13d81601755714e9fSE Android		datum = hashtab_search(policydb.p_bools.table, names[i]);
225255e72915d4cbddceb435e13d81601755714e9fSE Android		if (!datum) {
226255e72915d4cbddceb435e13d81601755714e9fSE Android			ERR(NULL, "boolean %s no longer in policy", names[i]);
227255e72915d4cbddceb435e13d81601755714e9fSE Android			errors++;
228255e72915d4cbddceb435e13d81601755714e9fSE Android			continue;
229255e72915d4cbddceb435e13d81601755714e9fSE Android		}
230255e72915d4cbddceb435e13d81601755714e9fSE Android		if (values[i] != 0 && values[i] != 1) {
231255e72915d4cbddceb435e13d81601755714e9fSE Android			ERR(NULL, "illegal value %d for boolean %s",
232255e72915d4cbddceb435e13d81601755714e9fSE Android			    values[i], names[i]);
233255e72915d4cbddceb435e13d81601755714e9fSE Android			errors++;
234255e72915d4cbddceb435e13d81601755714e9fSE Android			continue;
235255e72915d4cbddceb435e13d81601755714e9fSE Android		}
236255e72915d4cbddceb435e13d81601755714e9fSE Android		datum->state = values[i];
237255e72915d4cbddceb435e13d81601755714e9fSE Android	}
238255e72915d4cbddceb435e13d81601755714e9fSE Android
239255e72915d4cbddceb435e13d81601755714e9fSE Android	if (evaluate_conds(&policydb) < 0) {
240255e72915d4cbddceb435e13d81601755714e9fSE Android		ERR(NULL, "error while re-evaluating conditionals");
241255e72915d4cbddceb435e13d81601755714e9fSE Android		errno = EINVAL;
242255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err_destroy;
243255e72915d4cbddceb435e13d81601755714e9fSE Android	}
244255e72915d4cbddceb435e13d81601755714e9fSE Android
245255e72915d4cbddceb435e13d81601755714e9fSE Android	policy_file_init(&pf);
246255e72915d4cbddceb435e13d81601755714e9fSE Android	pf.type = PF_USE_MEMORY;
247255e72915d4cbddceb435e13d81601755714e9fSE Android	pf.data = data;
248255e72915d4cbddceb435e13d81601755714e9fSE Android	pf.len = len;
249255e72915d4cbddceb435e13d81601755714e9fSE Android	rc = policydb_write(&policydb, &pf);
250255e72915d4cbddceb435e13d81601755714e9fSE Android	if (rc) {
251255e72915d4cbddceb435e13d81601755714e9fSE Android		ERR(NULL, "unable to write binary policy");
252255e72915d4cbddceb435e13d81601755714e9fSE Android		errno = EINVAL;
253255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err_destroy;
254255e72915d4cbddceb435e13d81601755714e9fSE Android	}
255255e72915d4cbddceb435e13d81601755714e9fSE Android	if (errors) {
256255e72915d4cbddceb435e13d81601755714e9fSE Android		errno = EINVAL;
257255e72915d4cbddceb435e13d81601755714e9fSE Android		goto err_destroy;
258255e72915d4cbddceb435e13d81601755714e9fSE Android	}
259255e72915d4cbddceb435e13d81601755714e9fSE Android
260255e72915d4cbddceb435e13d81601755714e9fSE Android	policydb_destroy(&policydb);
261255e72915d4cbddceb435e13d81601755714e9fSE Android	return 0;
262255e72915d4cbddceb435e13d81601755714e9fSE Android
263255e72915d4cbddceb435e13d81601755714e9fSE Android      err_destroy:
264255e72915d4cbddceb435e13d81601755714e9fSE Android	policydb_destroy(&policydb);
265255e72915d4cbddceb435e13d81601755714e9fSE Android
266255e72915d4cbddceb435e13d81601755714e9fSE Android      err:
267255e72915d4cbddceb435e13d81601755714e9fSE Android	return -1;
268255e72915d4cbddceb435e13d81601755714e9fSE Android}
269