Blob Blame History Raw
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.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 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)