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