#include #include #include #include #include #include #include #include #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 DEFAULT_CONTEXTS 3 #define USER_CONTEXTS 4 #define FAILSAFE_CONTEXT 5 #define DEFAULT_TYPE 6 #define BOOLEANS 7 #define MEDIA_CONTEXTS 8 #define REMOVABLE_CONTEXT 9 #define CUSTOMIZABLE_TYPES 10 #define USERS_DIR 11 #define SEUSERS 12 #define NEL 13 /* 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_ }; /* Old layout had fixed locations. */ #define SECURITYCONFIG "/etc/sysconfig/selinux" #define SECURITYDIR "/etc/security" static const union compat_file_path_data { struct { #define S_(n, s) char L1(__LINE__)[sizeof(s)]; #include "compat_file_path.h" #undef S_ }; char str[0]; } compat_file_path_data = { { #define S_(n, s) s, #include "compat_file_path.h" #undef S_ } }; static const uint16_t compat_file_path_idx[NEL] = { #define S_(n, s) [n] = offsetof(union compat_file_path_data, L1(__LINE__)), #include "compat_file_path.h" #undef S_ }; #undef L1 #undef L2 static int use_compat_file_path; int selinux_getenforcemode(int *enforce) { int ret=-1; FILE *cfg = fopen(SELINUXCONFIG,"r"); char buf[4097]; int len=sizeof(SELINUXTAG)-1; if (!cfg) { cfg = fopen(SECURITYCONFIG,"r"); } if (cfg) { while (fgets_unlocked(buf, 4096, 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); } return ret; } hidden_def(selinux_getenforcemode) static char *selinux_policyroot = NULL; static void init_selinux_config(void) __attribute__ ((constructor)); static void init_selinux_config(void) { int i, *intptr; size_t rootlen, len; char *line_buf = NULL, *buf_p, *value; FILE *fp; if (selinux_policyroot) return; if (access(SELINUXDIR, F_OK) != 0) { selinux_policyroot = SECURITYDIR; use_compat_file_path = 1; return; } fp = fopen(SELINUXCONFIG,"r"); if (fp) { while (getline(&line_buf, &len, fp) > 0) { len = strlen(line_buf); /* reset in case of embedded NUL */ 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)) { char *type, *end; type = buf_p+sizeof(SELINUXTYPETAG)-1; end = type + strlen(type)-1; while ((end > type) && (isspace(*end) || iscntrl(*end))) { *end = 0; end--; } rootlen = sizeof(SELINUXDIR) + strlen(type); selinux_policyroot = malloc(rootlen); if (!selinux_policyroot) return; snprintf(selinux_policyroot, rootlen, "%s%s", SELINUXDIR, type); 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); } for (i = 0; i < NEL; i++) { len = rootlen + strlen(file_path_suffixes_data.str + file_path_suffixes_idx[i])+1; file_paths[i] = malloc(len); if (!file_paths[i]) return; snprintf(file_paths[i], len, "%s%s", selinux_policyroot, file_path_suffixes_data.str + file_path_suffixes_idx[i]); } use_compat_file_path = 0; } static void fini_selinux_policyroot(void) __attribute__ ((destructor)); static void fini_selinux_policyroot(void) { int i; if (use_compat_file_path) { selinux_policyroot = NULL; return; } free(selinux_policyroot); selinux_policyroot = NULL; for (i = 0; i < NEL; i++) { free(file_paths[i]); file_paths[i] = NULL; } } static const char *get_path(int idx) { if (!use_compat_file_path) return file_paths[idx]; return compat_file_path_data.str + compat_file_path_idx[idx]; } const char *selinux_default_type_path() { return get_path(DEFAULT_TYPE); } hidden_def(selinux_default_type_path) const char *selinux_policy_root() { return selinux_policyroot; } const char *selinux_default_context_path() { return get_path(DEFAULT_CONTEXTS); } hidden_def(selinux_default_context_path) const char *selinux_failsafe_context_path() { return get_path(FAILSAFE_CONTEXT); } hidden_def(selinux_failsafe_context_path) const char *selinux_removable_context_path() { return get_path(REMOVABLE_CONTEXT); } hidden_def(selinux_removable_context_path) const char *selinux_binary_policy_path() { return get_path(BINPOLICY); } hidden_def(selinux_binary_policy_path) const char *selinux_file_context_path() { return get_path(FILE_CONTEXTS); } hidden_def(selinux_file_context_path) const char *selinux_media_context_path() { return get_path(MEDIA_CONTEXTS); } hidden_def(selinux_media_context_path) const char *selinux_customizable_types_path() { return get_path(CUSTOMIZABLE_TYPES); } hidden_def(selinux_customizable_types_path) const char *selinux_contexts_path() { return get_path(CONTEXTS_DIR); } const char *selinux_user_contexts_path() { return get_path(USER_CONTEXTS); } hidden_def(selinux_user_contexts_path) const char *selinux_booleans_path() { return get_path(BOOLEANS); } hidden_def(selinux_booleans_path) const char *selinux_users_path() { return get_path(USERS_DIR); } const char *selinux_usersconf_path() { return get_path(SEUSERS); } hidden_def(selinux_users_path) hidden_def(selinux_usersconf_path)