blob: ffa8d26b0f3ab192e4dc05af2cc0193aae82ab34 [file] [log] [blame]
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001/*
2 * Author: Karl MacMillan <kmacmillan@tresys.com>
3 *
4 * Modified:
5 * Dan Walsh <dwalsh@redhat.com> - Added security_load_booleans().
6 */
7
William Robertsa7962182016-10-17 16:24:09 -04008#ifndef DISABLE_BOOL
9
Eric Paris88c35242012-04-18 11:00:24 -040010#include <assert.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040011#include <sys/types.h>
12#include <sys/stat.h>
13#include <fcntl.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040014#include <stdlib.h>
15#include <dirent.h>
16#include <string.h>
17#include <stdio.h>
18#include <stdio_ext.h>
19#include <unistd.h>
20#include <fnmatch.h>
21#include <limits.h>
22#include <ctype.h>
23#include <errno.h>
24
25#include "selinux_internal.h"
26#include "policy.h"
27
28#define SELINUX_BOOL_DIR "/booleans/"
29
30static int filename_select(const struct dirent *d)
31{
32 if (d->d_name[0] == '.'
33 && (d->d_name[1] == '\0'
34 || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
35 return 0;
36 return 1;
37}
38
39int security_get_boolean_names(char ***names, int *len)
40{
41 char path[PATH_MAX];
42 int i, rc;
43 struct dirent **namelist;
44 char **n;
45
Richard Haines98234cf2011-11-27 16:11:37 +000046 if (!len || names == NULL) {
47 errno = EINVAL;
48 return -1;
49 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -040050 if (!selinux_mnt) {
51 errno = ENOENT;
52 return -1;
53 }
54
55 snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR);
56 *len = scandir(path, &namelist, &filename_select, alphasort);
57 if (*len <= 0) {
Petr Lautrbach5689d822019-01-31 20:48:23 +010058 errno = ENOENT;
Joshua Brindle13cd4c82008-08-19 15:30:36 -040059 return -1;
60 }
61
62 n = (char **)malloc(sizeof(char *) * *len);
63 if (!n) {
64 rc = -1;
65 goto bad;
66 }
67
68 for (i = 0; i < *len; i++) {
William Robertsd8859772016-09-23 11:02:53 -070069 n[i] = strdup(namelist[i]->d_name);
Joshua Brindle13cd4c82008-08-19 15:30:36 -040070 if (!n[i]) {
71 rc = -1;
72 goto bad_freen;
73 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -040074 }
75 rc = 0;
76 *names = n;
77 out:
78 for (i = 0; i < *len; i++) {
79 free(namelist[i]);
80 }
81 free(namelist);
82 return rc;
83 bad_freen:
Richard Hainesee8f7a82019-07-08 14:37:01 +010084 if (i > 0) {
85 while (i >= 1)
86 free(n[--i]);
87 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -040088 free(n);
89 bad:
90 goto out;
91}
92
Dan Walshee690162012-06-11 13:25:29 -040093char *selinux_boolean_sub(const char *name)
Eric Paris88c35242012-04-18 11:00:24 -040094{
95 char *sub = NULL;
96 char *line_buf = NULL;
97 size_t line_len;
98 FILE *cfg;
99
100 if (!name)
101 return NULL;
102
Nick Kralevich64afa1a2016-12-11 09:30:16 -0800103 cfg = fopen(selinux_booleans_subs_path(), "re");
Eric Paris88c35242012-04-18 11:00:24 -0400104 if (!cfg)
105 goto out;
106
107 while (getline(&line_buf, &line_len, cfg) != -1) {
108 char *ptr;
109 char *src = line_buf;
110 char *dst;
Eric Paris88c35242012-04-18 11:00:24 -0400111 while (*src && isspace(*src))
112 src++;
113 if (!*src)
114 continue;
115 if (src[0] == '#')
116 continue;
117
118 ptr = src;
119 while (*ptr && !isspace(*ptr))
120 ptr++;
121 *ptr++ = '\0';
122 if (strcmp(src, name) != 0)
123 continue;
124
125 dst = ptr;
126 while (*dst && isspace(*dst))
127 dst++;
128 if (!*dst)
129 continue;
Unto Stene1a74392019-05-10 16:52:08 +0300130 ptr = dst;
Eric Paris88c35242012-04-18 11:00:24 -0400131 while (*ptr && !isspace(*ptr))
132 ptr++;
Unto Stene1a74392019-05-10 16:52:08 +0300133 *ptr = '\0';
Eric Paris88c35242012-04-18 11:00:24 -0400134
135 sub = strdup(dst);
136
137 break;
138 }
Eric Paris88c35242012-04-18 11:00:24 -0400139 free(line_buf);
140 fclose(cfg);
141out:
142 if (!sub)
143 sub = strdup(name);
144 return sub;
145}
146
147static int bool_open(const char *name, int flag) {
148 char *fname = NULL;
149 char *alt_name = NULL;
150 int len;
151 int fd = -1;
152 int ret;
153 char *ptr;
154
155 if (!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)
168 goto out;
169 assert(ret < len);
170
171 fd = open(fname, flag);
172 if (fd >= 0 || errno != ENOENT)
173 goto out;
174
Dan Walshee690162012-06-11 13:25:29 -0400175 alt_name = selinux_boolean_sub(name);
Eric Paris88c35242012-04-18 11:00:24 -0400176 if (!alt_name)
177 goto out;
178
179 /* note the 'sizeof' gets us enough room for the '\0' */
180 len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
181 ptr = realloc(fname, len);
182 if (!ptr)
183 goto out;
184 fname = ptr;
185
186 ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name);
187 if (ret < 0)
188 goto out;
189 assert(ret < len);
190
191 fd = open(fname, flag);
192out:
193 free(fname);
194 free(alt_name);
195
196 return fd;
197}
198
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400199#define STRBUF_SIZE 3
200static int get_bool_value(const char *name, char **buf)
201{
202 int fd, len;
Eric Paris88c35242012-04-18 11:00:24 -0400203 int errno_tmp;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400204
205 if (!selinux_mnt) {
206 errno = ENOENT;
207 return -1;
208 }
209
Eric Paris88c35242012-04-18 11:00:24 -0400210 *buf = malloc(sizeof(char) * (STRBUF_SIZE + 1));
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400211 if (!*buf)
Eric Paris88c35242012-04-18 11:00:24 -0400212 return -1;
213
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400214 (*buf)[STRBUF_SIZE] = 0;
215
Nick Kralevich64afa1a2016-12-11 09:30:16 -0800216 fd = bool_open(name, O_RDONLY | O_CLOEXEC);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400217 if (fd < 0)
Eric Paris88c35242012-04-18 11:00:24 -0400218 goto out_err;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400219
220 len = read(fd, *buf, STRBUF_SIZE);
Eric Paris88c35242012-04-18 11:00:24 -0400221 errno_tmp = errno;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400222 close(fd);
Eric Paris88c35242012-04-18 11:00:24 -0400223 errno = errno_tmp;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400224 if (len != STRBUF_SIZE)
Eric Paris88c35242012-04-18 11:00:24 -0400225 goto out_err;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400226
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400227 return 0;
Eric Paris88c35242012-04-18 11:00:24 -0400228out_err:
229 free(*buf);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400230 return -1;
231}
232
233int security_get_boolean_pending(const char *name)
234{
235 char *buf;
236 int val;
237
238 if (get_bool_value(name, &buf))
239 return -1;
240
241 if (atoi(&buf[1]))
242 val = 1;
243 else
244 val = 0;
245 free(buf);
246 return val;
247}
248
249int security_get_boolean_active(const char *name)
250{
251 char *buf;
252 int val;
253
254 if (get_bool_value(name, &buf))
255 return -1;
256
257 buf[1] = '\0';
258 if (atoi(buf))
259 val = 1;
260 else
261 val = 0;
262 free(buf);
263 return val;
264}
265
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400266int security_set_boolean(const char *name, int value)
267{
Eric Paris88c35242012-04-18 11:00:24 -0400268 int fd, ret;
269 char buf[2];
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400270
271 if (!selinux_mnt) {
272 errno = ENOENT;
273 return -1;
274 }
275 if (value < 0 || value > 1) {
276 errno = EINVAL;
277 return -1;
278 }
279
Nick Kralevich64afa1a2016-12-11 09:30:16 -0800280 fd = bool_open(name, O_WRONLY | O_CLOEXEC);
Eric Paris88c35242012-04-18 11:00:24 -0400281 if (fd < 0)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400282 return -1;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400283
284 if (value)
285 buf[0] = '1';
286 else
287 buf[0] = '0';
288 buf[1] = '\0';
289
290 ret = write(fd, buf, 2);
291 close(fd);
Eric Paris88c35242012-04-18 11:00:24 -0400292
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400293 if (ret > 0)
294 return 0;
295 else
296 return -1;
297}
298
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400299int security_commit_booleans(void)
300{
301 int fd, ret;
302 char buf[2];
303 char path[PATH_MAX];
304
305 if (!selinux_mnt) {
306 errno = ENOENT;
307 return -1;
308 }
309
310 snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt);
Nick Kralevich64afa1a2016-12-11 09:30:16 -0800311 fd = open(path, O_WRONLY | O_CLOEXEC);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400312 if (fd < 0)
313 return -1;
314
315 buf[0] = '1';
316 buf[1] = '\0';
317
318 ret = write(fd, buf, 2);
319 close(fd);
320
321 if (ret > 0)
322 return 0;
323 else
324 return -1;
325}
326
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400327static void rollback(SELboolean * boollist, int end)
328{
329 int i;
330
331 for (i = 0; i < end; i++)
332 security_set_boolean(boollist[i].name,
333 security_get_boolean_active(boollist[i].
334 name));
335}
336
337int security_set_boolean_list(size_t boolcnt, SELboolean * boollist,
338 int permanent)
339{
340
341 size_t i;
342 for (i = 0; i < boolcnt; i++) {
Stephen Smalley84679792018-05-03 14:48:43 -0400343 boollist[i].value = !!boollist[i].value;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400344 if (security_set_boolean(boollist[i].name, boollist[i].value)) {
345 rollback(boollist, i);
346 return -1;
347 }
348 }
349
350 /* OK, let's do the commit */
351 if (security_commit_booleans()) {
352 return -1;
353 }
354
Richard Hainesc3f94922019-06-24 19:02:28 +0100355 /* Return error as flag no longer used */
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400356 if (permanent)
Richard Hainesc3f94922019-06-24 19:02:28 +0100357 return -1;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400358
359 return 0;
360}
Richard Hainesc3f94922019-06-24 19:02:28 +0100361
362/* This function is deprecated */
363int security_load_booleans(char *path __attribute__((unused)))
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400364{
Richard Hainesc3f94922019-06-24 19:02:28 +0100365 return -1;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400366}
William Robertsadca1032016-09-29 14:02:25 -0400367#else
William Robertsa7962182016-10-17 16:24:09 -0400368
369#include <stdlib.h>
370#include "selinux_internal.h"
371
William Robertsadca1032016-09-29 14:02:25 -0400372int security_set_boolean_list(size_t boolcnt __attribute__((unused)),
373 SELboolean * boollist __attribute__((unused)),
374 int permanent __attribute__((unused)))
375{
376 return -1;
377}
378
379int security_load_booleans(char *path __attribute__((unused)))
380{
381 return -1;
382}
383
384int security_get_boolean_names(char ***names __attribute__((unused)),
385 int *len __attribute__((unused)))
386{
387 return -1;
388}
389
390int security_get_boolean_pending(const char *name __attribute__((unused)))
391{
392 return -1;
393}
394
395int security_get_boolean_active(const char *name __attribute__((unused)))
396{
397 return -1;
398}
399
400int security_set_boolean(const char *name __attribute__((unused)),
401 int value __attribute__((unused)))
402{
403 return -1;
404}
405
406int security_commit_booleans(void)
407{
408 return -1;
409}
410
411char *selinux_boolean_sub(const char *name __attribute__((unused)))
412{
413 return NULL;
414}
415#endif
416
417hidden_def(security_get_boolean_names)
418hidden_def(selinux_boolean_sub)
419hidden_def(security_get_boolean_active)
420hidden_def(security_set_boolean)
421hidden_def(security_commit_booleans)