xref: /aosp_15_r20/external/selinux/libselinux/src/booleans.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 /*
2  * Author: Karl MacMillan <[email protected]>
3  *
4  * Modified:
5  *   Dan Walsh <[email protected]> - Added security_load_booleans().
6  */
7 
8 #ifndef DISABLE_BOOL
9 
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
14 #include <dirent.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdio_ext.h>
18 #include <unistd.h>
19 #include <fnmatch.h>
20 #include <limits.h>
21 #include <ctype.h>
22 #include <errno.h>
23 
24 #include "selinux_internal.h"
25 #include "policy.h"
26 
27 #define SELINUX_BOOL_DIR "/booleans/"
28 
filename_select(const struct dirent * d)29 static int filename_select(const struct dirent *d)
30 {
31 	if (d->d_name[0] == '.'
32 	    && (d->d_name[1] == '\0'
33 		|| (d->d_name[1] == '.' && d->d_name[2] == '\0')))
34 		return 0;
35 	return 1;
36 }
37 
security_get_boolean_names(char *** names,int * len)38 int security_get_boolean_names(char ***names, int *len)
39 {
40 	char path[PATH_MAX];
41 	int i, rc;
42 	struct dirent **namelist;
43 	char **n;
44 
45 	if (!len || names == NULL) {
46 		errno = EINVAL;
47 		return -1;
48 	}
49 	if (!selinux_mnt) {
50 		errno = ENOENT;
51 		return -1;
52 	}
53 
54 	snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR);
55 	*len = scandir(path, &namelist, &filename_select, alphasort);
56 	if (*len < 0) {
57 		return -1;
58 	}
59 	if (*len == 0) {
60 		free(namelist);
61 		errno = ENOENT;
62 		return -1;
63 	}
64 
65 	n = (char **)malloc(sizeof(char *) * *len);
66 	if (!n) {
67 		rc = -1;
68 		goto bad;
69 	}
70 
71 	for (i = 0; i < *len; i++) {
72 		n[i] = strdup(namelist[i]->d_name);
73 		if (!n[i]) {
74 			rc = -1;
75 			goto bad_freen;
76 		}
77 	}
78 	rc = 0;
79 	*names = n;
80       out:
81 	for (i = 0; i < *len; i++) {
82 		free(namelist[i]);
83 	}
84 	free(namelist);
85 	return rc;
86       bad_freen:
87 	if (i > 0) {
88 		while (i >= 1)
89 			free(n[--i]);
90 	}
91 	free(n);
92       bad:
93 	goto out;
94 }
95 
selinux_boolean_sub(const char * name)96 char *selinux_boolean_sub(const char *name)
97 {
98 	char *sub = NULL;
99 	char *line_buf = NULL;
100 	size_t line_len;
101 	FILE *cfg;
102 
103 	if (!name)
104 		return NULL;
105 
106 	cfg = fopen(selinux_booleans_subs_path(), "re");
107 	if (!cfg)
108 		goto out;
109 
110 	while (getline(&line_buf, &line_len, cfg) != -1) {
111 		char *ptr;
112 		char *src = line_buf;
113 		char *dst;
114 		while (*src && isspace((unsigned char)*src))
115 			src++;
116 		if (!*src)
117 			continue;
118 		if (src[0] == '#')
119 			continue;
120 
121 		ptr = src;
122 		while (*ptr && !isspace((unsigned char)*ptr))
123 			ptr++;
124 		*ptr++ = '\0';
125 		if (strcmp(src, name) != 0)
126 			continue;
127 
128 		dst = ptr;
129 		while (*dst && isspace((unsigned char)*dst))
130 			dst++;
131 		if (!*dst)
132 			continue;
133 		ptr = dst;
134 		while (*ptr && !isspace((unsigned char)*ptr))
135 			ptr++;
136 		*ptr = '\0';
137 
138 		if (!strchr(dst, '/'))
139 			sub = strdup(dst);
140 
141 		break;
142 	}
143 	free(line_buf);
144 	fclose(cfg);
145 out:
146 	if (!sub)
147 		sub = strdup(name);
148 	return sub;
149 }
150 
bool_open(const char * name,int flag)151 static int bool_open(const char *name, int flag) {
152 	char *fname = NULL;
153 	char *alt_name = NULL;
154 	size_t len;
155 	int fd = -1;
156 	int ret;
157 	char *ptr;
158 
159 	if (!name || strchr(name, '/')) {
160 		errno = EINVAL;
161 		return -1;
162 	}
163 
164 	/* note the 'sizeof' gets us enough room for the '\0' */
165 	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
166 	fname = malloc(sizeof(char) * len);
167 	if (!fname)
168 		return -1;
169 
170 	ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
171 	if (ret < 0 || (size_t)ret >= len)
172 		goto out;
173 
174 	fd = open(fname, flag);
175 	if (fd >= 0 || errno != ENOENT)
176 		goto out;
177 
178 	alt_name = selinux_boolean_sub(name);
179 	if (!alt_name)
180 		goto out;
181 
182 	/* note the 'sizeof' gets us enough room for the '\0' */
183 	len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
184 	ptr = realloc(fname, len);
185 	if (!ptr)
186 		goto out;
187 	fname = ptr;
188 
189 	ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name);
190 	if (ret < 0 || (size_t)ret >= len)
191 		goto out;
192 
193 	fd = open(fname, flag);
194 out:
195 	free(fname);
196 	free(alt_name);
197 
198 	return fd;
199 }
200 
201 #define STRBUF_SIZE 3
get_bool_value(const char * name,char ** buf)202 static int get_bool_value(const char *name, char **buf)
203 {
204 	int fd, len;
205 	int errno_tmp;
206 
207 	if (!selinux_mnt) {
208 		errno = ENOENT;
209 		return -1;
210 	}
211 
212 	*buf = malloc(sizeof(char) * (STRBUF_SIZE + 1));
213 	if (!*buf)
214 		return -1;
215 
216 	(*buf)[STRBUF_SIZE] = 0;
217 
218 	fd = bool_open(name, O_RDONLY | O_CLOEXEC);
219 	if (fd < 0)
220 		goto out_err;
221 
222 	len = read(fd, *buf, STRBUF_SIZE);
223 	errno_tmp = errno;
224 	close(fd);
225 	errno = errno_tmp;
226 	if (len != STRBUF_SIZE)
227 		goto out_err;
228 
229 	return 0;
230 out_err:
231 	free(*buf);
232 	return -1;
233 }
234 
security_get_boolean_pending(const char * name)235 int security_get_boolean_pending(const char *name)
236 {
237 	char *buf;
238 	int val;
239 
240 	if (get_bool_value(name, &buf))
241 		return -1;
242 
243 	if (atoi(&buf[1]))
244 		val = 1;
245 	else
246 		val = 0;
247 	free(buf);
248 	return val;
249 }
250 
security_get_boolean_active(const char * name)251 int security_get_boolean_active(const char *name)
252 {
253 	char *buf;
254 	int val;
255 
256 	if (get_bool_value(name, &buf))
257 		return -1;
258 
259 	buf[1] = '\0';
260 	if (atoi(buf))
261 		val = 1;
262 	else
263 		val = 0;
264 	free(buf);
265 	return val;
266 }
267 
security_set_boolean(const char * name,int value)268 int security_set_boolean(const char *name, int value)
269 {
270 	int fd, ret;
271 	char buf[2];
272 
273 	if (!selinux_mnt) {
274 		errno = ENOENT;
275 		return -1;
276 	}
277 	if (value < 0 || value > 1) {
278 		errno = EINVAL;
279 		return -1;
280 	}
281 
282 	fd = bool_open(name, O_WRONLY | O_CLOEXEC);
283 	if (fd < 0)
284 		return -1;
285 
286 	if (value)
287 		buf[0] = '1';
288 	else
289 		buf[0] = '0';
290 	buf[1] = '\0';
291 
292 	ret = write(fd, buf, 2);
293 	close(fd);
294 
295 	if (ret > 0)
296 		return 0;
297 	else
298 		return -1;
299 }
300 
security_commit_booleans(void)301 int security_commit_booleans(void)
302 {
303 	int fd, ret;
304 	char buf[2];
305 	char path[PATH_MAX];
306 
307 	if (!selinux_mnt) {
308 		errno = ENOENT;
309 		return -1;
310 	}
311 
312 	snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt);
313 	fd = open(path, O_WRONLY | O_CLOEXEC);
314 	if (fd < 0)
315 		return -1;
316 
317 	buf[0] = '1';
318 	buf[1] = '\0';
319 
320 	ret = write(fd, buf, 2);
321 	close(fd);
322 
323 	if (ret > 0)
324 		return 0;
325 	else
326 		return -1;
327 }
328 
rollback(SELboolean * boollist,int end)329 static void rollback(SELboolean * boollist, int end)
330 {
331 	int i;
332 
333 	for (i = 0; i < end; i++)
334 		security_set_boolean(boollist[i].name,
335 				     security_get_boolean_active(boollist[i].
336 								 name));
337 }
338 
security_set_boolean_list(size_t boolcnt,SELboolean * boollist,int permanent)339 int security_set_boolean_list(size_t boolcnt, SELboolean * boollist,
340 			      int permanent)
341 {
342 
343 	size_t i;
344 	for (i = 0; i < boolcnt; i++) {
345 		boollist[i].value = !!boollist[i].value;
346 		if (security_set_boolean(boollist[i].name, boollist[i].value)) {
347 			rollback(boollist, i);
348 			return -1;
349 		}
350 	}
351 
352 	/* OK, let's do the commit */
353 	if (security_commit_booleans()) {
354 		return -1;
355 	}
356 
357 	/* Return error as flag no longer used */
358 	if (permanent)
359 		return -1;
360 
361 	return 0;
362 }
363 
364 /* This function is deprecated */
security_load_booleans(char * path)365 int security_load_booleans(char *path __attribute__((unused)))
366 {
367 	return -1;
368 }
369 #else
370 
371 #include <stdlib.h>
372 #include "selinux_internal.h"
373 
security_set_boolean_list(size_t boolcnt,SELboolean * boollist,int permanent)374 int security_set_boolean_list(size_t boolcnt __attribute__((unused)),
375 	SELboolean * boollist __attribute__((unused)),
376 	int permanent __attribute__((unused)))
377 {
378 	return -1;
379 }
380 
security_load_booleans(char * path)381 int security_load_booleans(char *path __attribute__((unused)))
382 {
383 	return -1;
384 }
385 
security_get_boolean_names(char *** names,int * len)386 int security_get_boolean_names(char ***names __attribute__((unused)),
387 	int *len __attribute__((unused)))
388 {
389 	return -1;
390 }
391 
security_get_boolean_pending(const char * name)392 int security_get_boolean_pending(const char *name __attribute__((unused)))
393 {
394 	return -1;
395 }
396 
security_get_boolean_active(const char * name)397 int security_get_boolean_active(const char *name __attribute__((unused)))
398 {
399 	return -1;
400 }
401 
security_set_boolean(const char * name,int value)402 int security_set_boolean(const char *name __attribute__((unused)),
403 	int value __attribute__((unused)))
404 {
405 	return -1;
406 }
407 
security_commit_booleans(void)408 int security_commit_booleans(void)
409 {
410 	return -1;
411 }
412 
selinux_boolean_sub(const char * name)413 char *selinux_boolean_sub(const char *name __attribute__((unused)))
414 {
415 	return NULL;
416 }
417 #endif
418 
419