#include #include #include #include #include #include #include #include #include #include #include #include "policy.h" #include "selinux_internal.h" #include "get_default_type_internal.h" #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 OPENSSH_CONTEXTS 28 #define SYSTEMD_CONTEXTS 29 #define NEL 30 /* 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_openssh_contexts_path(void) { return get_path(OPENSSH_CONTEXTS); } hidden_def(selinux_openssh_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)