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