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 <assert.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #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
filename_select(const struct dirent * d)30 static 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
security_get_boolean_names(char *** names,int * len)39 int 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
46 if (!len || names == NULL) {
47 errno = EINVAL;
48 return -1;
49 }
50 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) {
58 errno = ENOENT;
59 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++) {
69 n[i] = strdup(namelist[i]->d_name);
70 if (!n[i]) {
71 rc = -1;
72 goto bad_freen;
73 }
74 }
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:
84 if (i > 0) {
85 while (i >= 1)
86 free(n[--i]);
87 }
88 free(n);
89 bad:
90 goto out;
91 }
92
selinux_boolean_sub(const char * name)93 char *selinux_boolean_sub(const char *name)
94 {
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
103 cfg = fopen(selinux_booleans_subs_path(), "re");
104 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;
111 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;
130 ptr = dst;
131 while (*ptr && !isspace(*ptr))
132 ptr++;
133 *ptr = '\0';
134
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 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
175 alt_name = selinux_boolean_sub(name);
176 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);
192 out:
193 free(fname);
194 free(alt_name);
195
196 return fd;
197 }
198
199 #define STRBUF_SIZE 3
get_bool_value(const char * name,char ** buf)200 static int get_bool_value(const char *name, char **buf)
201 {
202 int fd, len;
203 int errno_tmp;
204
205 if (!selinux_mnt) {
206 errno = ENOENT;
207 return -1;
208 }
209
210 *buf = malloc(sizeof(char) * (STRBUF_SIZE + 1));
211 if (!*buf)
212 return -1;
213
214 (*buf)[STRBUF_SIZE] = 0;
215
216 fd = bool_open(name, O_RDONLY | O_CLOEXEC);
217 if (fd < 0)
218 goto out_err;
219
220 len = read(fd, *buf, STRBUF_SIZE);
221 errno_tmp = errno;
222 close(fd);
223 errno = errno_tmp;
224 if (len != STRBUF_SIZE)
225 goto out_err;
226
227 return 0;
228 out_err:
229 free(*buf);
230 return -1;
231 }
232
security_get_boolean_pending(const char * name)233 int 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
security_get_boolean_active(const char * name)249 int 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
security_set_boolean(const char * name,int value)266 int security_set_boolean(const char *name, int value)
267 {
268 int fd, ret;
269 char buf[2];
270
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
280 fd = bool_open(name, O_WRONLY | O_CLOEXEC);
281 if (fd < 0)
282 return -1;
283
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);
292
293 if (ret > 0)
294 return 0;
295 else
296 return -1;
297 }
298
security_commit_booleans(void)299 int 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);
311 fd = open(path, O_WRONLY | O_CLOEXEC);
312 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
rollback(SELboolean * boollist,int end)327 static 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
security_set_boolean_list(size_t boolcnt,SELboolean * boollist,int permanent)337 int 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++) {
343 boollist[i].value = !!boollist[i].value;
344 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
355 /* Return error as flag no longer used */
356 if (permanent)
357 return -1;
358
359 return 0;
360 }
361
362 /* This function is deprecated */
security_load_booleans(char * path)363 int security_load_booleans(char *path __attribute__((unused)))
364 {
365 return -1;
366 }
367 #else
368
369 #include <stdlib.h>
370 #include "selinux_internal.h"
371
security_set_boolean_list(size_t boolcnt,SELboolean * boollist,int permanent)372 int 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
security_load_booleans(char * path)379 int security_load_booleans(char *path __attribute__((unused)))
380 {
381 return -1;
382 }
383
security_get_boolean_names(char *** names,int * len)384 int security_get_boolean_names(char ***names __attribute__((unused)),
385 int *len __attribute__((unused)))
386 {
387 return -1;
388 }
389
security_get_boolean_pending(const char * name)390 int security_get_boolean_pending(const char *name __attribute__((unused)))
391 {
392 return -1;
393 }
394
security_get_boolean_active(const char * name)395 int security_get_boolean_active(const char *name __attribute__((unused)))
396 {
397 return -1;
398 }
399
security_set_boolean(const char * name,int value)400 int security_set_boolean(const char *name __attribute__((unused)),
401 int value __attribute__((unused)))
402 {
403 return -1;
404 }
405
security_commit_booleans(void)406 int security_commit_booleans(void)
407 {
408 return -1;
409 }
410
selinux_boolean_sub(const char * name)411 char *selinux_boolean_sub(const char *name __attribute__((unused)))
412 {
413 return NULL;
414 }
415 #endif
416
417 hidden_def(security_get_boolean_names)
418 hidden_def(selinux_boolean_sub)
419 hidden_def(security_get_boolean_active)
420 hidden_def(security_set_boolean)
421 hidden_def(security_commit_booleans)
422