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