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