1 #include <stdio.h>
2 #include <stdio_ext.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <stddef.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <limits.h>
9 #include <unistd.h>
10 #include <pthread.h>
11 #include <errno.h>
12 #include "policy.h"
13 #include "selinux_internal.h"
14 #include "get_default_type_internal.h"
15
16 #define SELINUXDEFAULT "targeted"
17 #define SELINUXTYPETAG "SELINUXTYPE="
18 #define SELINUXTAG "SELINUX="
19 #define SETLOCALDEFS "SETLOCALDEFS="
20 #define REQUIRESEUSERS "REQUIRESEUSERS="
21
22 /* Indices for file paths arrays. */
23 #define BINPOLICY 0
24 #define CONTEXTS_DIR 1
25 #define FILE_CONTEXTS 2
26 #define HOMEDIR_CONTEXTS 3
27 #define DEFAULT_CONTEXTS 4
28 #define USER_CONTEXTS 5
29 #define FAILSAFE_CONTEXT 6
30 #define DEFAULT_TYPE 7
31 #define BOOLEANS 8
32 #define MEDIA_CONTEXTS 9
33 #define REMOVABLE_CONTEXT 10
34 #define CUSTOMIZABLE_TYPES 11
35 #define USERS_DIR 12
36 #define SEUSERS 13
37 #define TRANSLATIONS 14
38 #define NETFILTER_CONTEXTS 15
39 #define FILE_CONTEXTS_HOMEDIR 16
40 #define FILE_CONTEXTS_LOCAL 17
41 #define SECURETTY_TYPES 18
42 #define X_CONTEXTS 19
43 #define COLORS 20
44 #define VIRTUAL_DOMAIN 21
45 #define VIRTUAL_IMAGE 22
46 #define FILE_CONTEXT_SUBS 23
47 #define SEPGSQL_CONTEXTS 24
48 #define FILE_CONTEXT_SUBS_DIST 25
49 #define LXC_CONTEXTS 26
50 #define BOOLEAN_SUBS 27
51 #define OPENSSH_CONTEXTS 28
52 #define SYSTEMD_CONTEXTS 29
53 #define SNAPPERD_CONTEXTS 30
54 #define OPENRC_CONTEXTS 31
55 #define NEL 32
56
57 /* Part of one-time lazy init */
58 static pthread_once_t once = PTHREAD_ONCE_INIT;
59 static void init_selinux_config(void);
60
61 /* New layout is relative to SELINUXDIR/policytype. */
62 static char *file_paths[NEL];
63 #define L1(l) L2(l)
64 #define L2(l)str##l
65 static const union file_path_suffixes_data {
66 struct {
67 #define S_(n, s) char L1(__LINE__)[sizeof(s)];
68 #include "file_path_suffixes.h"
69 #undef S_
70 };
71 char str[0];
72 } file_path_suffixes_data = {
73 {
74 #define S_(n, s) s,
75 #include "file_path_suffixes.h"
76 #undef S_
77 }
78 };
79 static const uint16_t file_path_suffixes_idx[NEL] = {
80 #define S_(n, s) [n] = offsetof(union file_path_suffixes_data, L1(__LINE__)),
81 #include "file_path_suffixes.h"
82 #undef S_
83 };
84
85 #undef L1
86 #undef L2
87
selinux_getenforcemode(int * enforce)88 int selinux_getenforcemode(int *enforce)
89 {
90 int ret = -1;
91 FILE *cfg = fopen(SELINUXCONFIG, "re");
92 if (cfg) {
93 char *buf;
94 int len = sizeof(SELINUXTAG) - 1;
95 buf = malloc(selinux_page_size);
96 if (!buf) {
97 fclose(cfg);
98 return -1;
99 }
100 while (fgets_unlocked(buf, selinux_page_size, cfg)) {
101 if (strncmp(buf, SELINUXTAG, len))
102 continue;
103 if (!strncasecmp
104 (buf + len, "enforcing", sizeof("enforcing") - 1)) {
105 *enforce = 1;
106 ret = 0;
107 break;
108 } else
109 if (!strncasecmp
110 (buf + len, "permissive",
111 sizeof("permissive") - 1)) {
112 *enforce = 0;
113 ret = 0;
114 break;
115 } else
116 if (!strncasecmp
117 (buf + len, "disabled",
118 sizeof("disabled") - 1)) {
119 *enforce = -1;
120 ret = 0;
121 break;
122 }
123 }
124 fclose(cfg);
125 free(buf);
126 }
127 return ret;
128 }
129
hidden_def(selinux_getenforcemode)130 hidden_def(selinux_getenforcemode)
131
132 static char *selinux_policytype;
133
134 int selinux_getpolicytype(char **type)
135 {
136 __selinux_once(once, init_selinux_config);
137 if (!selinux_policytype)
138 return -1;
139 *type = strdup(selinux_policytype);
140 return *type ? 0 : -1;
141 }
142
hidden_def(selinux_getpolicytype)143 hidden_def(selinux_getpolicytype)
144
145 static int setpolicytype(const char *type)
146 {
147 free(selinux_policytype);
148 selinux_policytype = strdup(type);
149 return selinux_policytype ? 0 : -1;
150 }
151
152 static char *selinux_policyroot = NULL;
153 static const char *selinux_rootpath = SELINUXDIR;
154
init_selinux_config(void)155 static void init_selinux_config(void)
156 {
157 int i, *intptr;
158 size_t line_len;
159 ssize_t len;
160 char *line_buf = NULL, *buf_p, *value, *type = NULL, *end;
161 FILE *fp;
162
163 if (selinux_policyroot)
164 return;
165
166 fp = fopen(SELINUXCONFIG, "re");
167 if (fp) {
168 __fsetlocking(fp, FSETLOCKING_BYCALLER);
169 while ((len = getline(&line_buf, &line_len, fp)) > 0) {
170 if (line_buf[len - 1] == '\n')
171 line_buf[len - 1] = 0;
172 buf_p = line_buf;
173 while (isspace(*buf_p))
174 buf_p++;
175 if (*buf_p == '#' || *buf_p == 0)
176 continue;
177
178 if (!strncasecmp(buf_p, SELINUXTYPETAG,
179 sizeof(SELINUXTYPETAG) - 1)) {
180 type = strdup(buf_p + sizeof(SELINUXTYPETAG) - 1);
181 if (!type)
182 return;
183 end = type + strlen(type) - 1;
184 while ((end > type) &&
185 (isspace(*end) || iscntrl(*end))) {
186 *end = 0;
187 end--;
188 }
189 if (setpolicytype(type) != 0) {
190 free(type);
191 return;
192 }
193 free(type);
194 continue;
195 } else if (!strncmp(buf_p, SETLOCALDEFS,
196 sizeof(SETLOCALDEFS) - 1)) {
197 value = buf_p + sizeof(SETLOCALDEFS) - 1;
198 intptr = &load_setlocaldefs;
199 } else if (!strncmp(buf_p, REQUIRESEUSERS,
200 sizeof(REQUIRESEUSERS) - 1)) {
201 value = buf_p + sizeof(REQUIRESEUSERS) - 1;
202 intptr = &require_seusers;
203 } else {
204 continue;
205 }
206
207 if (isdigit(*value))
208 *intptr = atoi(value);
209 else if (strncasecmp(value, "true", sizeof("true") - 1))
210 *intptr = 1;
211 else if (strncasecmp
212 (value, "false", sizeof("false") - 1))
213 *intptr = 0;
214 }
215 free(line_buf);
216 fclose(fp);
217 }
218
219 if (!selinux_policytype && setpolicytype(SELINUXDEFAULT) != 0)
220 return;
221
222 if (asprintf(&selinux_policyroot, "%s%s", SELINUXDIR, selinux_policytype) == -1)
223 return;
224
225 for (i = 0; i < NEL; i++)
226 if (asprintf(&file_paths[i], "%s%s",
227 selinux_policyroot,
228 file_path_suffixes_data.str +
229 file_path_suffixes_idx[i])
230 == -1)
231 return;
232 }
233
234 static void fini_selinux_policyroot(void) __attribute__ ((destructor));
235
fini_selinux_policyroot(void)236 static void fini_selinux_policyroot(void)
237 {
238 int i;
239 free(selinux_policyroot);
240 selinux_policyroot = NULL;
241 for (i = 0; i < NEL; i++) {
242 free(file_paths[i]);
243 file_paths[i] = NULL;
244 }
245 free(selinux_policytype);
246 selinux_policytype = NULL;
247 }
248
selinux_reset_config(void)249 void selinux_reset_config(void)
250 {
251 fini_selinux_policyroot();
252 init_selinux_config();
253 }
254
hidden_def(selinux_reset_config)255 hidden_def(selinux_reset_config)
256
257 static const char *get_path(int idx)
258 {
259 __selinux_once(once, init_selinux_config);
260 return file_paths[idx];
261 }
262
selinux_default_type_path(void)263 const char *selinux_default_type_path(void)
264 {
265 return get_path(DEFAULT_TYPE);
266 }
267
hidden_def(selinux_default_type_path)268 hidden_def(selinux_default_type_path)
269
270 const char *selinux_policy_root(void)
271 {
272 __selinux_once(once, init_selinux_config);
273 return selinux_policyroot;
274 }
275
selinux_set_policy_root(const char * path)276 int selinux_set_policy_root(const char *path)
277 {
278 int i;
279 char *policy_type = strrchr(path, '/');
280 if (!policy_type) {
281 errno = EINVAL;
282 return -1;
283 }
284 policy_type++;
285
286 fini_selinux_policyroot();
287
288 selinux_policyroot = strdup(path);
289 if (! selinux_policyroot)
290 return -1;
291
292 if (setpolicytype(policy_type) != 0)
293 return -1;
294
295 for (i = 0; i < NEL; i++)
296 if (asprintf(&file_paths[i], "%s%s",
297 selinux_policyroot,
298 file_path_suffixes_data.str +
299 file_path_suffixes_idx[i])
300 == -1)
301 return -1;
302
303 return 0;
304 }
305
selinux_path(void)306 const char *selinux_path(void)
307 {
308 return selinux_rootpath;
309 }
310
hidden_def(selinux_path)311 hidden_def(selinux_path)
312
313 const char *selinux_default_context_path(void)
314 {
315 return get_path(DEFAULT_CONTEXTS);
316 }
317
hidden_def(selinux_default_context_path)318 hidden_def(selinux_default_context_path)
319
320 const char *selinux_securetty_types_path(void)
321 {
322 return get_path(SECURETTY_TYPES);
323 }
324
hidden_def(selinux_securetty_types_path)325 hidden_def(selinux_securetty_types_path)
326
327 const char *selinux_failsafe_context_path(void)
328 {
329 return get_path(FAILSAFE_CONTEXT);
330 }
331
hidden_def(selinux_failsafe_context_path)332 hidden_def(selinux_failsafe_context_path)
333
334 const char *selinux_removable_context_path(void)
335 {
336 return get_path(REMOVABLE_CONTEXT);
337 }
338
hidden_def(selinux_removable_context_path)339 hidden_def(selinux_removable_context_path)
340
341 const char *selinux_binary_policy_path(void)
342 {
343 return get_path(BINPOLICY);
344 }
345
hidden_def(selinux_binary_policy_path)346 hidden_def(selinux_binary_policy_path)
347
348 const char *selinux_current_policy_path(void)
349 {
350 int rc = 0;
351 int vers = 0;
352 static char policy_path[PATH_MAX];
353
354 if (selinux_mnt) {
355 snprintf(policy_path, sizeof(policy_path), "%s/policy", selinux_mnt);
356 if (access(policy_path, F_OK) == 0 ) {
357 return policy_path;
358 }
359 }
360 vers = security_policyvers();
361 do {
362 /* Check prior versions to see if old policy is available */
363 snprintf(policy_path, sizeof(policy_path), "%s.%d",
364 selinux_binary_policy_path(), vers);
365 } while ((rc = access(policy_path, F_OK)) && --vers > 0);
366
367 if (rc) return NULL;
368 return policy_path;
369 }
370
hidden_def(selinux_current_policy_path)371 hidden_def(selinux_current_policy_path)
372
373 const char *selinux_file_context_path(void)
374 {
375 return get_path(FILE_CONTEXTS);
376 }
377
hidden_def(selinux_file_context_path)378 hidden_def(selinux_file_context_path)
379
380 const char *selinux_homedir_context_path(void)
381 {
382 return get_path(HOMEDIR_CONTEXTS);
383 }
384
hidden_def(selinux_homedir_context_path)385 hidden_def(selinux_homedir_context_path)
386
387 const char *selinux_media_context_path(void)
388 {
389 return get_path(MEDIA_CONTEXTS);
390 }
391
hidden_def(selinux_media_context_path)392 hidden_def(selinux_media_context_path)
393
394 const char *selinux_customizable_types_path(void)
395 {
396 return get_path(CUSTOMIZABLE_TYPES);
397 }
398
hidden_def(selinux_customizable_types_path)399 hidden_def(selinux_customizable_types_path)
400
401 const char *selinux_contexts_path(void)
402 {
403 return get_path(CONTEXTS_DIR);
404 }
405
selinux_user_contexts_path(void)406 const char *selinux_user_contexts_path(void)
407 {
408 return get_path(USER_CONTEXTS);
409 }
410
hidden_def(selinux_user_contexts_path)411 hidden_def(selinux_user_contexts_path)
412
413 const char *selinux_booleans_path(void)
414 {
415 return get_path(BOOLEANS);
416 }
417
hidden_def(selinux_booleans_path)418 hidden_def(selinux_booleans_path)
419
420 const char *selinux_users_path(void)
421 {
422 return get_path(USERS_DIR);
423 }
424
hidden_def(selinux_users_path)425 hidden_def(selinux_users_path)
426
427 const char *selinux_usersconf_path(void)
428 {
429 return get_path(SEUSERS);
430 }
431
hidden_def(selinux_usersconf_path)432 hidden_def(selinux_usersconf_path)
433
434 const char *selinux_translations_path(void)
435 {
436 return get_path(TRANSLATIONS);
437 }
438
hidden_def(selinux_translations_path)439 hidden_def(selinux_translations_path)
440
441 const char *selinux_colors_path(void)
442 {
443 return get_path(COLORS);
444 }
445
hidden_def(selinux_colors_path)446 hidden_def(selinux_colors_path)
447
448 const char *selinux_netfilter_context_path(void)
449 {
450 return get_path(NETFILTER_CONTEXTS);
451 }
452
hidden_def(selinux_netfilter_context_path)453 hidden_def(selinux_netfilter_context_path)
454
455 const char *selinux_file_context_homedir_path(void)
456 {
457 return get_path(FILE_CONTEXTS_HOMEDIR);
458 }
459
hidden_def(selinux_file_context_homedir_path)460 hidden_def(selinux_file_context_homedir_path)
461
462 const char *selinux_file_context_local_path(void)
463 {
464 return get_path(FILE_CONTEXTS_LOCAL);
465 }
466
hidden_def(selinux_file_context_local_path)467 hidden_def(selinux_file_context_local_path)
468
469 const char *selinux_x_context_path(void)
470 {
471 return get_path(X_CONTEXTS);
472 }
473
hidden_def(selinux_x_context_path)474 hidden_def(selinux_x_context_path)
475
476 const char *selinux_virtual_domain_context_path(void)
477 {
478 return get_path(VIRTUAL_DOMAIN);
479 }
480
hidden_def(selinux_virtual_domain_context_path)481 hidden_def(selinux_virtual_domain_context_path)
482
483 const char *selinux_virtual_image_context_path(void)
484 {
485 return get_path(VIRTUAL_IMAGE);
486 }
487
hidden_def(selinux_virtual_image_context_path)488 hidden_def(selinux_virtual_image_context_path)
489
490 const char *selinux_lxc_contexts_path(void)
491 {
492 return get_path(LXC_CONTEXTS);
493 }
494
hidden_def(selinux_lxc_contexts_path)495 hidden_def(selinux_lxc_contexts_path)
496
497 const char *selinux_openrc_contexts_path(void)
498 {
499 return get_path(OPENRC_CONTEXTS);
500 }
501
hidden_def(selinux_openrc_contexts_path)502 hidden_def(selinux_openrc_contexts_path)
503
504 const char *selinux_openssh_contexts_path(void)
505 {
506 return get_path(OPENSSH_CONTEXTS);
507 }
508
hidden_def(selinux_openssh_contexts_path)509 hidden_def(selinux_openssh_contexts_path)
510
511 const char *selinux_snapperd_contexts_path(void)
512 {
513 return get_path(SNAPPERD_CONTEXTS);
514 }
515
hidden_def(selinux_snapperd_contexts_path)516 hidden_def(selinux_snapperd_contexts_path)
517
518 const char *selinux_systemd_contexts_path(void)
519 {
520 return get_path(SYSTEMD_CONTEXTS);
521 }
522
hidden_def(selinux_systemd_contexts_path)523 hidden_def(selinux_systemd_contexts_path)
524
525 const char * selinux_booleans_subs_path(void) {
526 return get_path(BOOLEAN_SUBS);
527 }
528
hidden_def(selinux_booleans_subs_path)529 hidden_def(selinux_booleans_subs_path)
530
531 const char * selinux_file_context_subs_path(void) {
532 return get_path(FILE_CONTEXT_SUBS);
533 }
534
hidden_def(selinux_file_context_subs_path)535 hidden_def(selinux_file_context_subs_path)
536
537 const char * selinux_file_context_subs_dist_path(void) {
538 return get_path(FILE_CONTEXT_SUBS_DIST);
539 }
540
hidden_def(selinux_file_context_subs_dist_path)541 hidden_def(selinux_file_context_subs_dist_path)
542
543 const char *selinux_sepgsql_context_path(void)
544 {
545 return get_path(SEPGSQL_CONTEXTS);
546 }
547
548 hidden_def(selinux_sepgsql_context_path)
549