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 */
17typedef struct secolor {
18	uint32_t fg;
19	uint32_t bg;
20} secolor_t;
21
22typedef struct semnemonic {
23	char *name;
24	uint32_t color;
25	struct semnemonic *next;
26} semnemonic_t;
27
28typedef 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"
41static const char *rules[] = { "user", "role", "type", "range" };
42
43static setab_t *clist[N_COLOR];
44static setab_t *cend[N_COLOR];
45static semnemonic_t *mnemonics;
46
47static security_context_t my_context;
48
49void 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
78static 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;
117out:
118	free(ctx);
119	context_free(my_tmp);
120	context_free(con);
121	return rc;
122}
123
124static 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
150static 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
175static 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
194static 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 */
215static 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 */
244int 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
265static 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
272static const secolor_t default_color = { 0x000000, 0xffffff };
273
274static 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 */
285int 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;
340out:
341	context_free(con);
342
343	return rc;
344}
345