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 void rollback(SELboolean * boollist, int end)
236{
237	int i;
238
239	for (i = 0; i < end; i++)
240		security_set_boolean(boollist[i].name,
241				     security_get_boolean_active(boollist[i].
242								 name));
243}
244
245int security_set_boolean_list(size_t boolcnt, SELboolean * const boollist,
246			      int permanent __attribute__((unused)))
247{
248
249	size_t i;
250	for (i = 0; i < boolcnt; i++) {
251		if (security_set_boolean(boollist[i].name, boollist[i].value)) {
252			rollback(boollist, i);
253			return -1;
254		}
255	}
256
257	/* OK, let's do the commit */
258	if (security_commit_booleans()) {
259		return -1;
260	}
261
262	return 0;
263}
264