booleans.c revision f074036424618c130dacb3464465a8b40bffef58
1/*
2 * Author: Karl MacMillan <kmacmillan@tresys.com>
3 *
4 * Modified:
5 *   Dan Walsh <dwalsh@redhat.com> - Added security_load_booleans().
6 */
7
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <assert.h>
12#include <stdlib.h>
13#include <dirent.h>
14#include <string.h>
15#include <stdio.h>
16#include <unistd.h>
17#include <fnmatch.h>
18#include <limits.h>
19#include <ctype.h>
20#include <errno.h>
21
22#include "selinux_internal.h"
23#include "policy.h"
24
25#define SELINUX_BOOL_DIR "/booleans/"
26
27static int filename_select(const struct dirent *d)
28{
29	if (d->d_name[0] == '.'
30	    && (d->d_name[1] == '\0'
31		|| (d->d_name[1] == '.' && d->d_name[2] == '\0')))
32		return 0;
33	return 1;
34}
35
36int security_get_boolean_names(char ***names, int *len)
37{
38	char path[PATH_MAX];
39	int i, rc;
40	struct dirent **namelist;
41	char **n;
42
43	assert(len);
44	if (!selinux_mnt) {
45		errno = ENOENT;
46		return -1;
47	}
48
49	snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR);
50	*len = scandir(path, &namelist, &filename_select, alphasort);
51	if (*len <= 0) {
52		return -1;
53	}
54
55	n = (char **)malloc(sizeof(char *) * *len);
56	if (!n) {
57		rc = -1;
58		goto bad;
59	}
60
61	for (i = 0; i < *len; i++) {
62	        n[i] = strdup(namelist[i]->d_name);
63		if (!n[i]) {
64			rc = -1;
65			goto bad_freen;
66		}
67	}
68	rc = 0;
69	*names = n;
70      out:
71	for (i = 0; i < *len; i++) {
72		free(namelist[i]);
73	}
74	free(namelist);
75	return rc;
76      bad_freen:
77	for (--i; i >= 0; --i)
78		free(n[i]);
79	free(n);
80      bad:
81	goto out;
82}
83
84hidden_def(security_get_boolean_names)
85#define STRBUF_SIZE 3
86static int get_bool_value(const char *name, char **buf)
87{
88	int fd, len;
89	char *fname = NULL;
90
91	if (!selinux_mnt) {
92		errno = ENOENT;
93		return -1;
94	}
95
96	*buf = (char *)malloc(sizeof(char) * (STRBUF_SIZE + 1));
97	if (!*buf)
98		goto out;
99	(*buf)[STRBUF_SIZE] = 0;
100
101	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
102	fname = (char *)malloc(sizeof(char) * len);
103	if (!fname)
104		goto out;
105	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
106
107	fd = open(fname, O_RDONLY);
108	if (fd < 0)
109		goto out;
110
111	len = read(fd, *buf, STRBUF_SIZE);
112	close(fd);
113	if (len != STRBUF_SIZE)
114		goto out;
115
116	free(fname);
117	return 0;
118      out:
119	if (*buf)
120		free(*buf);
121	if (fname)
122		free(fname);
123	return -1;
124}
125
126int security_get_boolean_pending(const char *name)
127{
128	char *buf;
129	int val;
130
131	if (get_bool_value(name, &buf))
132		return -1;
133
134	if (atoi(&buf[1]))
135		val = 1;
136	else
137		val = 0;
138	free(buf);
139	return val;
140}
141
142int security_get_boolean_active(const char *name)
143{
144	char *buf;
145	int val;
146
147	if (get_bool_value(name, &buf))
148		return -1;
149
150	buf[1] = '\0';
151	if (atoi(buf))
152		val = 1;
153	else
154		val = 0;
155	free(buf);
156	return val;
157}
158
159hidden_def(security_get_boolean_active)
160
161int security_set_boolean(const char *name, int value)
162{
163	int fd, ret, len;
164	char buf[2], *fname;
165
166	if (!selinux_mnt) {
167		errno = ENOENT;
168		return -1;
169	}
170	if (value < 0 || value > 1) {
171		errno = EINVAL;
172		return -1;
173	}
174
175	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
176	fname = (char *)malloc(sizeof(char) * len);
177	if (!fname)
178		return -1;
179	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
180
181	fd = open(fname, O_WRONLY);
182	if (fd < 0) {
183		ret = -1;
184		goto out;
185	}
186
187	if (value)
188		buf[0] = '1';
189	else
190		buf[0] = '0';
191	buf[1] = '\0';
192
193	ret = write(fd, buf, 2);
194	close(fd);
195      out:
196	free(fname);
197	if (ret > 0)
198		return 0;
199	else
200		return -1;
201}
202
203hidden_def(security_set_boolean)
204
205int security_commit_booleans(void)
206{
207	int fd, ret;
208	char buf[2];
209	char path[PATH_MAX];
210
211	if (!selinux_mnt) {
212		errno = ENOENT;
213		return -1;
214	}
215
216	snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt);
217	fd = open(path, O_WRONLY);
218	if (fd < 0)
219		return -1;
220
221	buf[0] = '1';
222	buf[1] = '\0';
223
224	ret = write(fd, buf, 2);
225	close(fd);
226
227	if (ret > 0)
228		return 0;
229	else
230		return -1;
231}
232
233hidden_def(security_commit_booleans)
234
235static char *strtrim(char *dest, char *source, int size)
236{
237	int i = 0;
238	char *ptr = source;
239	i = 0;
240	while (isspace(*ptr) && i < size) {
241		ptr++;
242		i++;
243	}
244	strncpy(dest, ptr, size);
245	for (i = strlen(dest) - 1; i > 0; i--) {
246		if (!isspace(dest[i]))
247			break;
248	}
249	dest[i + 1] = '\0';
250	return dest;
251}
252static int process_boolean(char *buffer, char *name, int namesize, int *val)
253{
254	char name1[BUFSIZ];
255	char *ptr;
256	char *tok = strtok_r(buffer, "=", &ptr);
257	if (tok) {
258		strncpy(name1, tok, BUFSIZ - 1);
259		strtrim(name, name1, namesize - 1);
260		if (name[0] == '#')
261			return 0;
262		tok = strtok_r(NULL, "\0", &ptr);
263		if (tok) {
264			while (isspace(*tok))
265				tok++;
266			*val = -1;
267			if (isdigit(tok[0]))
268				*val = atoi(tok);
269			else if (!strncasecmp(tok, "true", sizeof("true") - 1))
270				*val = 1;
271			else if (!strncasecmp
272				 (tok, "false", sizeof("false") - 1))
273				*val = 0;
274			if (*val != 0 && *val != 1) {
275				errno = EINVAL;
276				return -1;
277			}
278
279		}
280	}
281	return 1;
282}
283
284static void rollback(SELboolean * boollist, int end)
285{
286	int i;
287
288	for (i = 0; i < end; i++)
289		security_set_boolean(boollist[i].name,
290				     security_get_boolean_active(boollist[i].
291								 name));
292}
293
294int security_set_boolean_list(size_t boolcnt, SELboolean * boollist,
295			      int permanent __attribute__((unused)))
296{
297
298	size_t i;
299	for (i = 0; i < boolcnt; i++) {
300		if (security_set_boolean(boollist[i].name, boollist[i].value)) {
301			rollback(boollist, i);
302			return -1;
303		}
304	}
305
306	/* OK, let's do the commit */
307	if (security_commit_booleans()) {
308		return -1;
309	}
310
311	return 0;
312}
313