• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 
finish_context_colors(void)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 
check_dominance(const char * pattern,const char * raw)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 
find_color(int idx,const char * component,const char * raw)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 
add_secolor(int idx,char * pattern,uint32_t fg,uint32_t bg)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 
find_mnemonic(const char * name,uint32_t * retval)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 
add_mnemonic(const char * name,uint32_t color)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 */
process_color(char * buffer,int line)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  */
init_colors(void)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 
parse_components(context_t con,char ** components)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  */
raw_color(const security_context_t raw,char ** color_str)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 	int rc = -1;
293 
294 	if (!color_str && !*color_str) {
295 		return -1;
296 	}
297 
298 	/* parse context and allocate memory */
299 	con = context_new(raw);
300 	if (!con)
301 		return -1;
302 	if (parse_components(con, components) < 0)
303 		goto out;
304 
305 	result = malloc((N_COLOR * CHARS_PER_COLOR) + 1);
306 	if (!result)
307 		goto out;
308 	result[0] = '\0';
309 
310 	/* find colors for which we have a match */
311 	for (i = 0; i < N_COLOR; i++) {
312 		items[i] = find_color(i, components[i], raw);
313 		if (items[i])
314 			mask |= (1 << i);
315 	}
316 	if (mask == 0) {
317 		items[0] = &default_color;
318 		mask = 1;
319 	}
320 
321 	/* propagate colors according to the precedence rules */
322 	for (i = 0; i < N_COLOR; i++)
323 		if (!(mask & (1 << i)))
324 			for (j = 0; j < N_COLOR - 1; j++)
325 				if (mask & (1 << precedence[i][j])) {
326 					items[i] = items[precedence[i][j]];
327 					break;
328 				}
329 
330 	/* print results into a big long string */
331 	for (i = 0; i < N_COLOR; i++) {
332 		snprintf(buf, sizeof(buf), "#%06x #%06x ",
333 			 items[i]->fg, items[i]->bg);
334 		strncat(result, buf, sizeof(buf));
335 	}
336 
337 	*color_str = result;
338 	rc = 0;
339 out:
340 	context_free(con);
341 
342 	return rc;
343 }
344