Home | History | Annotate | Download | only in src
      1 #include <unistd.h>
      2 #include <fcntl.h>
      3 #include <stdlib.h>
      4 #include <stdint.h>
      5 #include <string.h>
      6 #include <stdio.h>
      7 #include <stdio_ext.h>
      8 #include <ctype.h>
      9 #include <alloca.h>
     10 #include <fnmatch.h>
     11 #include <syslog.h>
     12 #include <selinux/selinux.h>
     13 #include <selinux/context.h>
     14 #include "mcstrans.h"
     15 
     16 /* Define data structures */
     17 typedef struct secolor {
     18 	uint32_t fg;
     19 	uint32_t bg;
     20 } secolor_t;
     21 
     22 typedef struct semnemonic {
     23 	char *name;
     24 	uint32_t color;
     25 	struct semnemonic *next;
     26 } semnemonic_t;
     27 
     28 typedef struct setab {
     29 	char *pattern;
     30 	secolor_t color;
     31 	struct setab *next;
     32 } setab_t;
     33 
     34 #define COLOR_USER	0
     35 #define COLOR_ROLE	1
     36 #define COLOR_TYPE	2
     37 #define COLOR_RANGE	3
     38 #define N_COLOR		4
     39 
     40 #define AUX_RULE_COLOR "color"
     41 static const char *rules[] = { "user", "role", "type", "range" };
     42 
     43 static setab_t *clist[N_COLOR];
     44 static setab_t *cend[N_COLOR];
     45 static semnemonic_t *mnemonics;
     46 
     47 static security_context_t my_context;
     48 
     49 void finish_context_colors(void) {
     50 	setab_t *cur, *next;
     51 	semnemonic_t *ptr;
     52 	unsigned i;
     53 
     54 	for (i = 0; i < N_COLOR; i++) {
     55 		cur = clist[i];
     56 		while(cur) {
     57 			next = cur->next;
     58 			free(cur->pattern);
     59 			free(cur);
     60 			cur = next;
     61 		}
     62 		clist[i] = cend[i] = NULL;
     63 	}
     64 
     65 	ptr = mnemonics;
     66 	while (ptr) {
     67 		mnemonics = ptr->next;
     68 		free(ptr->name);
     69 		free(ptr);
     70 		ptr = mnemonics;
     71 	}
     72 	mnemonics = NULL;
     73 
     74 	freecon(my_context);
     75 	my_context = NULL;
     76 }
     77 
     78 static int check_dominance(const char *pattern, const char *raw) {
     79 	security_context_t ctx;
     80 	context_t con;
     81 	struct av_decision avd;
     82 	int rc = -1;
     83 	context_t my_tmp;
     84 	const char *raw_range;
     85 	security_class_t context_class = string_to_security_class("context");
     86 	access_vector_t context_contains_perm = string_to_av_perm(context_class, "contains");
     87 
     88 	con = context_new(raw);
     89 	if (!con)
     90 		return -1;
     91 	raw_range = context_range_get(con);
     92 
     93 	my_tmp = context_new(my_context);
     94 	if (!my_tmp) {
     95 		context_free(con);
     96 		return -1;
     97 	}
     98 
     99 	ctx = NULL;
    100 	if (context_range_set(my_tmp, pattern))
    101 		goto out;
    102 	ctx = strdup(context_str(my_tmp));
    103 	if (!ctx)
    104 		goto out;
    105 
    106 	if (context_range_set(my_tmp, raw_range))
    107 		goto out;
    108 	raw = context_str(my_tmp);
    109 	if (!raw)
    110 		goto out;
    111 
    112 	rc = security_compute_av_raw(ctx, (security_context_t)raw, context_class, context_contains_perm, &avd);
    113 	if (rc)
    114 		goto out;
    115 
    116 	rc = (context_contains_perm & avd.allowed) != context_contains_perm;
    117 out:
    118 	free(ctx);
    119 	context_free(my_tmp);
    120 	context_free(con);
    121 	return rc;
    122 }
    123 
    124 static const secolor_t *find_color(int idx, const char *component,
    125 				   const char *raw) {
    126 	setab_t *ptr = clist[idx];
    127 
    128 	if (idx == COLOR_RANGE) {
    129 		if (!raw) {
    130 			return NULL;
    131 		}
    132 	} else if (!component) {
    133 		return NULL;
    134 	}
    135 
    136 	while (ptr) {
    137 		if (fnmatch(ptr->pattern, component, 0) == 0) {
    138 			if (idx == COLOR_RANGE) {
    139 			    if (check_dominance(ptr->pattern, raw) == 0)
    140 					return &ptr->color;
    141 			} else
    142 				return &ptr->color;
    143 		}
    144 		ptr = ptr->next;
    145 	}
    146 
    147 	return NULL;
    148 }
    149 
    150 static int add_secolor(int idx, char *pattern, uint32_t fg, uint32_t bg) {
    151 	setab_t *cptr;
    152 
    153 	cptr = calloc(1, sizeof(setab_t));
    154 	if (!cptr) return -1;
    155 
    156 	cptr->pattern = strdup(pattern);
    157 	if (!cptr->pattern) {
    158 		free(cptr);
    159 		return -1;
    160 	}
    161 
    162 	cptr->color.fg = fg & 0xffffff;
    163 	cptr->color.bg = bg & 0xffffff;
    164 
    165 	if (cend[idx]) {
    166 		cend[idx]->next = cptr;
    167 		cend[idx] = cptr;
    168 	} else {
    169 		clist[idx] = cptr;
    170 		cend[idx] = cptr;
    171 	}
    172 	return 0;
    173 }
    174 
    175 static int find_mnemonic(const char *name, uint32_t *retval)
    176 {
    177 	semnemonic_t *ptr;
    178 
    179 	if (*name == '#')
    180 		return sscanf(name, "#%x", retval) == 1 ? 0 : -1;
    181 
    182 	ptr = mnemonics;
    183 	while (ptr) {
    184 		if (!strcmp(ptr->name, name)) {
    185 			*retval = ptr->color;
    186 			return 0;
    187 		}
    188 		ptr = ptr->next;
    189 	}
    190 
    191 	return -1;
    192 }
    193 
    194 static int add_mnemonic(const char *name, uint32_t color)
    195 {
    196 	semnemonic_t *ptr = malloc(sizeof(semnemonic_t));
    197 	if (!ptr)
    198 		return -1;
    199 
    200 	ptr->color = color;
    201 	ptr->name = strdup(name);
    202 	if (!ptr->name) {
    203 		free(ptr);
    204 		return -1;
    205 	}
    206 
    207 	ptr->next = mnemonics;
    208 	mnemonics = ptr;
    209 	return 0;
    210 }
    211 
    212 
    213 /* Process line from color file.
    214    May modify the data pointed to by the buffer paremeter */
    215 static int process_color(char *buffer, int line) {
    216 	char rule[10], pat[256], f[256], b[256];
    217 	uint32_t i, fg, bg;
    218 	int ret;
    219 
    220 	while(isspace(*buffer))
    221 		buffer++;
    222 	if(buffer[0] == '#' || buffer[0] == '\0') return 0;
    223 
    224 	ret = sscanf(buffer, "%8s %255s = %255s %255s", rule, pat, f, b);
    225 	if (ret == 4) {
    226 		if (find_mnemonic(f, &fg) == 0 && find_mnemonic(b, &bg) == 0)
    227 			for (i = 0; i < N_COLOR; i++)
    228 				if (!strcmp(rule, rules[i]))
    229 					return add_secolor(i, pat, fg, bg);
    230 	}
    231 	else if (ret == 3) {
    232 		if (!strcmp(rule, AUX_RULE_COLOR)) {
    233 			if (sscanf(f, "#%x", &fg) == 1)
    234 				return add_mnemonic(pat, fg);
    235 		}
    236 	}
    237 
    238 	syslog(LOG_WARNING, "Line %d of secolors file is invalid.", line);
    239 	return 0;
    240 }
    241 
    242 /* Read in color file.
    243  */
    244 int init_colors(void) {
    245 	FILE *cfg = NULL;
    246 	size_t size = 0;
    247 	char *buffer = NULL;
    248 	int line = 0;
    249 
    250 	getcon(&my_context);
    251 
    252 	cfg = fopen(selinux_colors_path(), "r");
    253 	if (!cfg) return 1;
    254 
    255 	__fsetlocking(cfg, FSETLOCKING_BYCALLER);
    256 	while (getline(&buffer, &size, cfg) > 0) {
    257 		if( process_color(buffer, ++line) < 0 ) break;
    258 	}
    259 	free(buffer);
    260 
    261 	fclose(cfg);
    262 	return 0;
    263 }
    264 
    265 static const unsigned precedence[N_COLOR][N_COLOR - 1] = {
    266 	{ COLOR_ROLE, COLOR_TYPE, COLOR_RANGE },
    267 	{ COLOR_USER, COLOR_TYPE, COLOR_RANGE },
    268 	{ COLOR_USER, COLOR_ROLE, COLOR_RANGE },
    269 	{ COLOR_USER, COLOR_ROLE, COLOR_TYPE },
    270 };
    271 
    272 static const secolor_t default_color = { 0x000000, 0xffffff };
    273 
    274 static int parse_components(context_t con, char **components) {
    275 	components[COLOR_USER] = (char *)context_user_get(con);
    276 	components[COLOR_ROLE] = (char *)context_role_get(con);
    277 	components[COLOR_TYPE] = (char *)context_type_get(con);
    278 	components[COLOR_RANGE] = (char *)context_range_get(con);
    279 
    280 	return 0;
    281 }
    282 
    283 /* Look up colors.
    284  */
    285 int raw_color(const security_context_t raw, char **color_str) {
    286 #define CHARS_PER_COLOR 16
    287 	context_t con;
    288 	uint32_t i, j, mask = 0;
    289 	const secolor_t *items[N_COLOR];
    290 	char *result, *components[N_COLOR];
    291 	char buf[CHARS_PER_COLOR + 1];
    292 	size_t result_size = (N_COLOR * CHARS_PER_COLOR) + 1;
    293 	int rc = -1;
    294 
    295 	if (!color_str || !*color_str) {
    296 		return -1;
    297 	}
    298 
    299 	/* parse context and allocate memory */
    300 	con = context_new(raw);
    301 	if (!con)
    302 		return -1;
    303 	if (parse_components(con, components) < 0)
    304 		goto out;
    305 
    306 	result = malloc(result_size);
    307 	if (!result)
    308 		goto out;
    309 	result[0] = '\0';
    310 
    311 	/* find colors for which we have a match */
    312 	for (i = 0; i < N_COLOR; i++) {
    313 		items[i] = find_color(i, components[i], raw);
    314 		if (items[i])
    315 			mask |= (1 << i);
    316 	}
    317 	if (mask == 0) {
    318 		items[0] = &default_color;
    319 		mask = 1;
    320 	}
    321 
    322 	/* propagate colors according to the precedence rules */
    323 	for (i = 0; i < N_COLOR; i++)
    324 		if (!(mask & (1 << i)))
    325 			for (j = 0; j < N_COLOR - 1; j++)
    326 				if (mask & (1 << precedence[i][j])) {
    327 					items[i] = items[precedence[i][j]];
    328 					break;
    329 				}
    330 
    331 	/* print results into a big long string */
    332 	for (i = 0; i < N_COLOR; i++) {
    333 		snprintf(buf, sizeof(buf), "#%06x #%06x ",
    334 			 items[i]->fg, items[i]->bg);
    335 		strncat(result, buf, result_size-1);
    336 	}
    337 
    338 	*color_str = result;
    339 	rc = 0;
    340 out:
    341 	context_free(con);
    342 
    343 	return rc;
    344 }
    345