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