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 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 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 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 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 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 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 */ 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 */ 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 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 */ 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