#include <stdio.h>
#include <stdio_ext.h>
#include <string.h>
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include "policy.h"
#include "selinux_internal.h"
#include "get_default_type_internal.h"
#define SELINUXDIR "/etc/selinux/"
#define SELINUXCONFIG SELINUXDIR "config"
#define SELINUXDEFAULT "targeted"
#define SELINUXTYPETAG "SELINUXTYPE="
#define SELINUXTAG "SELINUX="
#define SETLOCALDEFS "SETLOCALDEFS="
#define REQUIRESEUSERS "REQUIRESEUSERS="
/* Indices for file paths arrays. */
#define BINPOLICY 0
#define CONTEXTS_DIR 1
#define FILE_CONTEXTS 2
#define HOMEDIR_CONTEXTS 3
#define DEFAULT_CONTEXTS 4
#define USER_CONTEXTS 5
#define FAILSAFE_CONTEXT 6
#define DEFAULT_TYPE 7
#define BOOLEANS 8
#define MEDIA_CONTEXTS 9
#define REMOVABLE_CONTEXT 10
#define CUSTOMIZABLE_TYPES 11
#define USERS_DIR 12
#define SEUSERS 13
#define TRANSLATIONS 14
#define NETFILTER_CONTEXTS 15
#define FILE_CONTEXTS_HOMEDIR 16
#define FILE_CONTEXTS_LOCAL 17
#define SECURETTY_TYPES 18
#define X_CONTEXTS 19
#define COLORS 20
#define VIRTUAL_DOMAIN 21
#define VIRTUAL_IMAGE 22
#define FILE_CONTEXT_SUBS 23
#define SEPGSQL_CONTEXTS 24
#define FILE_CONTEXT_SUBS_DIST 25
#define LXC_CONTEXTS 26
#define BOOLEAN_SUBS 27
#define SYSTEMD_CONTEXTS 28
#define NEL 29
/* Part of one-time lazy init */
static pthread_once_t once = PTHREAD_ONCE_INIT;
static void init_selinux_config(void);
/* New layout is relative to SELINUXDIR/policytype. */
static char *file_paths[NEL];
#define L1(l) L2(l)
#define L2(l)str##l
static const union file_path_suffixes_data {
struct {
#define S_(n, s) char L1(__LINE__)[sizeof(s)];
#include "file_path_suffixes.h"
#undef S_
};
char str[0];
} file_path_suffixes_data = {
{
#define S_(n, s) s,
#include "file_path_suffixes.h"
#undef S_
}
};
static const uint16_t file_path_suffixes_idx[NEL] = {
#define S_(n, s) [n] = offsetof(union file_path_suffixes_data, L1(__LINE__)),
#include "file_path_suffixes.h"
#undef S_
};
#undef L1
#undef L2
int selinux_getenforcemode(int *enforce)
{
int ret = -1;
FILE *cfg = fopen(SELINUXCONFIG, "r");
if (cfg) {
char *buf;
int len = sizeof(SELINUXTAG) - 1;
buf = malloc(selinux_page_size);
if (!buf) {
fclose(cfg);
return -1;
}
while (fgets_unlocked(buf, selinux_page_size, cfg)) {
if (strncmp(buf, SELINUXTAG, len))
continue;
if (!strncasecmp
(buf + len, "enforcing", sizeof("enforcing") - 1)) {
*enforce = 1;
ret = 0;
break;
} else
if (!strncasecmp
(buf + len, "permissive",
sizeof("permissive") - 1)) {
*enforce = 0;
ret = 0;
break;
} else
if (!strncasecmp
(buf + len, "disabled",
sizeof("disabled") - 1)) {
*enforce = -1;
ret = 0;
break;
}
}
fclose(cfg);
free(buf);
}
return ret;
}
hidden_def(selinux_getenforcemode)
static char *selinux_policytype;
int selinux_getpolicytype(char **type)
{
__selinux_once(once, init_selinux_config);
if (!selinux_policytype)
return -1;
*type = strdup(selinux_policytype);
return *type ? 0 : -1;
}
hidden_def(selinux_getpolicytype)
static int setpolicytype(const char *type)
{
free(selinux_policytype);
selinux_policytype = strdup(type);
return selinux_policytype ? 0 : -1;
}
static char *selinux_policyroot = NULL;
static const char *selinux_rootpath = SELINUXDIR;
static void init_selinux_config(void)
{
int i, *intptr;
size_t line_len;
ssize_t len;
char *line_buf = NULL, *buf_p, *value, *type = NULL, *end;
FILE *fp;
if (selinux_policyroot)
return;
fp = fopen(SELINUXCONFIG, "r");
if (fp) {
__fsetlocking(fp, FSETLOCKING_BYCALLER);
while ((len = getline(&line_buf, &line_len, fp)) > 0) {
if (line_buf[len - 1] == '\n')
line_buf[len - 1] = 0;
buf_p = line_buf;
while (isspace(*buf_p))
buf_p++;
if (*buf_p == '#' || *buf_p == 0)
continue;
if (!strncasecmp(buf_p, SELINUXTYPETAG,
sizeof(SELINUXTYPETAG) - 1)) {
selinux_policytype = type =
strdup(buf_p + sizeof(SELINUXTYPETAG) - 1);
if (!type)
return;
end = type + strlen(type) - 1;
while ((end > type) &&
(isspace(*end) || iscntrl(*end))) {
*end = 0;
end--;
}
continue;
} else if (!strncmp(buf_p, SETLOCALDEFS,
sizeof(SETLOCALDEFS) - 1)) {
value = buf_p + sizeof(SETLOCALDEFS) - 1;
intptr = &load_setlocaldefs;
} else if (!strncmp(buf_p, REQUIRESEUSERS,
sizeof(REQUIRESEUSERS) - 1)) {
value = buf_p + sizeof(REQUIRESEUSERS) - 1;
intptr = &require_seusers;
} else {
continue;
}
if (isdigit(*value))
*intptr = atoi(value);
else if (strncasecmp(value, "true", sizeof("true") - 1))
*intptr = 1;
else if (strncasecmp
(value, "false", sizeof("false") - 1))
*intptr = 0;
}
free(line_buf);
fclose(fp);
}
if (!type) {
selinux_policytype = type = strdup(SELINUXDEFAULT);
if (!type)
return;
}
if (asprintf(&selinux_policyroot, "%s%s", SELINUXDIR, type) == -1)
return;
for (i = 0; i < NEL; i++)
if (asprintf(&file_paths[i], "%s%s",
selinux_policyroot,
file_path_suffixes_data.str +
file_path_suffixes_idx[i])
== -1)
return;
}
static void fini_selinux_policyroot(void) __attribute__ ((destructor));
static void fini_selinux_policyroot(void)
{
int i;
free(selinux_policyroot);
selinux_policyroot = NULL;
for (i = 0; i < NEL; i++) {
free(file_paths[i]);
file_paths[i] = NULL;
}
free(selinux_policytype);
selinux_policytype = NULL;
}
void selinux_reset_config(void)
{
fini_selinux_policyroot();
init_selinux_config();
}
hidden_def(selinux_reset_config)
static const char *get_path(int idx)
{
__selinux_once(once, init_selinux_config);
return file_paths[idx];
}
const char *selinux_default_type_path(void)
{
return get_path(DEFAULT_TYPE);
}
hidden_def(selinux_default_type_path)
const char *selinux_policy_root(void)
{
__selinux_once(once, init_selinux_config);
return selinux_policyroot;
}
int selinux_set_policy_root(const char *path)
{
int i;
char *policy_type = strrchr(path, '/');
if (!policy_type) {
errno = EINVAL;
return -1;
}
policy_type++;
fini_selinuxmnt();
fini_selinux_policyroot();
selinux_policyroot = strdup(path);
if (! selinux_policyroot)
return -1;
if (setpolicytype(policy_type) != 0)
return -1;
for (i = 0; i < NEL; i++)
if (asprintf(&file_paths[i], "%s%s",
selinux_policyroot,
file_path_suffixes_data.str +
file_path_suffixes_idx[i])
== -1)
return -1;
return 0;
}
const char *selinux_path(void)
{
return selinux_rootpath;
}
hidden_def(selinux_path)
const char *selinux_default_context_path(void)
{
return get_path(DEFAULT_CONTEXTS);
}
hidden_def(selinux_default_context_path)
const char *selinux_securetty_types_path(void)
{
return get_path(SECURETTY_TYPES);
}
hidden_def(selinux_securetty_types_path)
const char *selinux_failsafe_context_path(void)
{
return get_path(FAILSAFE_CONTEXT);
}
hidden_def(selinux_failsafe_context_path)
const char *selinux_removable_context_path(void)
{
return get_path(REMOVABLE_CONTEXT);
}
hidden_def(selinux_removable_context_path)
const char *selinux_binary_policy_path(void)
{
return get_path(BINPOLICY);
}
hidden_def(selinux_binary_policy_path)
const char *selinux_current_policy_path(void)
{
int rc = 0;
int vers = 0;
static char policy_path[PATH_MAX];
if (selinux_mnt) {
snprintf(policy_path, sizeof(policy_path), "%s/policy", selinux_mnt);
if (access(policy_path, F_OK) == 0 ) {
return policy_path;
}
}
vers = security_policyvers();
do {
/* Check prior versions to see if old policy is available */
snprintf(policy_path, sizeof(policy_path), "%s.%d",
selinux_binary_policy_path(), vers);
} while ((rc = access(policy_path, F_OK)) && --vers > 0);
if (rc) return NULL;
return policy_path;
}
hidden_def(selinux_current_policy_path)
const char *selinux_file_context_path(void)
{
return get_path(FILE_CONTEXTS);
}
hidden_def(selinux_file_context_path)
const char *selinux_homedir_context_path(void)
{
return get_path(HOMEDIR_CONTEXTS);
}
hidden_def(selinux_homedir_context_path)
const char *selinux_media_context_path(void)
{
return get_path(MEDIA_CONTEXTS);
}
hidden_def(selinux_media_context_path)
const char *selinux_customizable_types_path(void)
{
return get_path(CUSTOMIZABLE_TYPES);
}
hidden_def(selinux_customizable_types_path)
const char *selinux_contexts_path(void)
{
return get_path(CONTEXTS_DIR);
}
const char *selinux_user_contexts_path(void)
{
return get_path(USER_CONTEXTS);
}
hidden_def(selinux_user_contexts_path)
const char *selinux_booleans_path(void)
{
return get_path(BOOLEANS);
}
hidden_def(selinux_booleans_path)
const char *selinux_users_path(void)
{
return get_path(USERS_DIR);
}
hidden_def(selinux_users_path)
const char *selinux_usersconf_path(void)
{
return get_path(SEUSERS);
}
hidden_def(selinux_usersconf_path)
const char *selinux_translations_path(void)
{
return get_path(TRANSLATIONS);
}
hidden_def(selinux_translations_path)
const char *selinux_colors_path(void)
{
return get_path(COLORS);
}
hidden_def(selinux_colors_path)
const char *selinux_netfilter_context_path(void)
{
return get_path(NETFILTER_CONTEXTS);
}
hidden_def(selinux_netfilter_context_path)
const char *selinux_file_context_homedir_path(void)
{
return get_path(FILE_CONTEXTS_HOMEDIR);
}
hidden_def(selinux_file_context_homedir_path)
const char *selinux_file_context_local_path(void)
{
return get_path(FILE_CONTEXTS_LOCAL);
}
hidden_def(selinux_file_context_local_path)
const char *selinux_x_context_path(void)
{
return get_path(X_CONTEXTS);
}
hidden_def(selinux_x_context_path)
const char *selinux_virtual_domain_context_path(void)
{
return get_path(VIRTUAL_DOMAIN);
}
hidden_def(selinux_virtual_domain_context_path)
const char *selinux_virtual_image_context_path(void)
{
return get_path(VIRTUAL_IMAGE);
}
hidden_def(selinux_virtual_image_context_path)
const char *selinux_lxc_contexts_path(void)
{
return get_path(LXC_CONTEXTS);
}
hidden_def(selinux_lxc_contexts_path)
const char *selinux_systemd_contexts_path(void)
{
return get_path(SYSTEMD_CONTEXTS);
}
hidden_def(selinux_systemd_contexts_path)
const char * selinux_booleans_subs_path(void) {
return get_path(BOOLEAN_SUBS);
}
hidden_def(selinux_booleans_subs_path)
const char * selinux_file_context_subs_path(void) {
return get_path(FILE_CONTEXT_SUBS);
}
hidden_def(selinux_file_context_subs_path)
const char * selinux_file_context_subs_dist_path(void) {
return get_path(FILE_CONTEXT_SUBS_DIST);
}
hidden_def(selinux_file_context_subs_dist_path)
const char *selinux_sepgsql_context_path(void)
{
return get_path(SEPGSQL_CONTEXTS);
}
hidden_def(selinux_sepgsql_context_path)