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