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