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