1
2 /* Copyright (c) 2008-2009 Nall Design Works
3 Copyright 2006 Trusted Computer Solutions, Inc. */
4
5 /*
6 Exported Interface
7
8 int init_translations(void);
9 void finish_context_translations(void);
10 int trans_context(const security_context_t, security_context_t *);
11 int untrans_context(const security_context_t, security_context_t *);
12
13 */
14
15 #include <math.h>
16 #include <glob.h>
17 #include <values.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdio_ext.h>
24 #include <ctype.h>
25 #include <selinux/selinux.h>
26 #include <selinux/context.h>
27 #include <syslog.h>
28 #include <errno.h>
29 #include <pcre.h>
30 #include <ctype.h>
31 #include <time.h>
32 #include <sys/time.h>
33
34
35 #include "mls_level.h"
36 #include "mcstrans.h"
37
38 #define N_BUCKETS 1453
39 #define OVECCOUNT (512*3)
40
41 #define log_error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
42
43 #ifdef DEBUG
44 #define log_debug(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
45 #else
46 #define log_debug(fmt, ...) ;
47 #endif
48
49 static unsigned int maxbit=0;
50
51 /* Define data structures */
52 typedef struct context_map {
53 char *raw;
54 char *trans;
55 } context_map_t;
56
57 typedef struct context_map_node {
58 char *key;
59 context_map_t *map;
60 struct context_map_node *next;
61 } context_map_node_t;
62
63 typedef struct affix {
64 char *text;
65 struct affix *next;
66 } affix_t;
67
68 typedef struct word {
69 char *text;
70 ebitmap_t cat;
71 ebitmap_t normal;
72 ebitmap_t inverse;
73 struct word *next;
74 } word_t;
75
76 typedef struct word_group {
77 char *name;
78 char *whitespace;
79 char *join;
80
81 affix_t *prefixes;
82 affix_t *suffixes;
83 word_t *words;
84
85 pcre *prefix_regexp;
86 pcre *word_regexp;
87 pcre *suffix_regexp;
88
89 ebitmap_t def;
90
91 word_t **sword;
92 int sword_len;
93
94 struct word_group *next;
95 } word_group_t;
96
97 typedef struct base_classification {
98 char *trans;
99 mls_level_t *level;
100 struct base_classification *next;
101 } base_classification_t;
102
103 typedef struct domain {
104 char *name;
105
106 context_map_node_t *raw_to_trans[N_BUCKETS];
107 context_map_node_t *trans_to_raw[N_BUCKETS];
108
109 base_classification_t *base_classifications;
110 word_group_t *groups;
111
112 pcre *base_classification_regexp;
113 struct domain *next;
114 } domain_t;
115
116 static domain_t *domains;
117
118 typedef struct sens_constraint {
119 char op;
120 char *text;
121 unsigned int sens;
122 ebitmap_t cat;
123 struct sens_constraint *next;
124 } sens_constraint_t;
125
126 static sens_constraint_t *sens_constraints;
127
128 typedef struct cat_constraint {
129 char op;
130 char *text;
131 int nbits;
132 ebitmap_t mask;
133 ebitmap_t cat;
134 struct cat_constraint *next;
135 } cat_constraint_t;
136
137 static cat_constraint_t *cat_constraints;
138
139 unsigned int
hash(const char * str)140 hash(const char *str) {
141 unsigned int hash = 5381;
142 int c;
143
144 while ((c = *(unsigned const char *)str++))
145 hash = ((hash << 5) + hash) + c;
146
147 return hash;
148 }
149
150 static int
add_to_hashtable(context_map_node_t ** table,char * key,context_map_t * map)151 add_to_hashtable(context_map_node_t **table, char *key, context_map_t *map) {
152 unsigned int bucket = hash(key) % N_BUCKETS;
153 context_map_node_t **n;
154 for (n = &table[bucket]; *n; n = &(*n)->next)
155 ;
156 *n = malloc(sizeof(context_map_node_t));
157 if (! *n)
158 goto err;
159 (*n)->key = key;
160 (*n)->map = map;
161 (*n)->next = NULL;
162 return 0;
163 err:
164 syslog(LOG_ERR, "add_to_hashtable: allocation error");
165 return -1;
166 }
167
168 static int
numdigits(unsigned int n)169 numdigits(unsigned int n)
170 {
171 int count = 1;
172 while ((n = n / 10))
173 count++;
174 return count;
175 }
176
177 static int
parse_category(ebitmap_t * e,const char * raw,int allowinverse)178 parse_category(ebitmap_t *e, const char *raw, int allowinverse)
179 {
180 int inverse = 0;
181 unsigned int low, high;
182 while (*raw) {
183 if (allowinverse && *raw == '~') {
184 inverse = !inverse;
185 raw++;
186 continue;
187 }
188 if (sscanf(raw,"c%u", &low) != 1)
189 return -1;
190 raw += numdigits(low) + 1;
191 if (*raw == '.') {
192 raw++;
193 if (sscanf(raw,"c%u", &high) != 1)
194 return -1;
195 raw += numdigits(high) + 1;
196 } else {
197 high = low;
198 }
199 while (low <= high) {
200 if (low >= maxbit)
201 maxbit = low + 1;
202 if (ebitmap_set_bit(e, low, inverse ? 0 : 1) < 0)
203 return -1;
204 low++;
205 }
206 if (*raw == ',') {
207 raw++;
208 inverse = 0;
209 } else if (*raw != '\0') {
210 return -1;
211 }
212 }
213 return 0;
214 }
215
216 int
parse_ebitmap(ebitmap_t * e,ebitmap_t * def,const char * raw)217 parse_ebitmap(ebitmap_t *e, ebitmap_t *def, const char *raw) {
218 int rc = ebitmap_cpy(e, def);
219 if (rc < 0)
220 return rc;
221 rc = parse_category(e, raw, 1);
222 if (rc < 0)
223 return rc;
224 return 0;
225 }
226
227 mls_level_t *
parse_raw(const char * raw)228 parse_raw(const char *raw) {
229 mls_level_t *mls = calloc(1, sizeof(mls_level_t));
230 if (!mls)
231 goto err;
232 if (sscanf(raw,"s%u", &mls->sens) != 1)
233 goto err;
234 raw += numdigits(mls->sens) + 1;
235 if (*raw == ':') {
236 raw++;
237 if (parse_category(&mls->cat, raw, 0) < 0)
238 goto err;
239 } else if (*raw != '\0') {
240 goto err;
241 }
242
243 return mls;
244
245 err:
246 ebitmap_destroy(&mls->cat);
247 free(mls);
248 return NULL;
249 }
250
251 void
destroy_word(word_t ** list,word_t * word)252 destroy_word(word_t **list, word_t *word) {
253 if (!word) {
254 return;
255 }
256 for (; list && *list; list = &(*list)->next) {
257 if (*list == word) {
258 *list = word->next;
259 break;
260 }
261 }
262 free(word->text);
263 ebitmap_destroy(&word->cat);
264 ebitmap_destroy(&word->normal);
265 ebitmap_destroy(&word->inverse);
266 memset(word, 0, sizeof(word_t));
267 free(word);
268 }
269
270 word_t *
create_word(word_t ** list,const char * text)271 create_word(word_t **list, const char *text) {
272 word_t *w = calloc(1, sizeof(word_t));
273 if (!w) {
274 goto err;
275 }
276 w->text = strdup(text);
277 if (!w->text) {
278 goto err;
279 }
280 if (list) {
281 for (; *list; list = &(*list)->next)
282 ;
283 *list = w;
284 }
285
286 return w;
287
288 err:
289 log_error("create_word: allocation error %s", strerror(errno));
290 destroy_word(NULL, w);
291 return NULL;
292 }
293
294 void
destroy_group(word_group_t ** list,word_group_t * group)295 destroy_group(word_group_t **list, word_group_t *group) {
296 for (; list && *list; list = &(*list)->next) {
297 if (*list == group) {
298 *list = group->next;
299 break;
300 }
301 }
302 while(group->prefixes) {
303 affix_t *next = group->prefixes->next;
304 free(group->prefixes->text);
305 free(group->prefixes);
306 group->prefixes=next;
307 }
308 while(group->suffixes) {
309 affix_t *next = group->suffixes->next;
310 free(group->suffixes->text);
311 free(group->suffixes);
312 group->suffixes=next;
313 }
314 while(group->words)
315 destroy_word(&group->words, group->words);
316 free(group->whitespace);
317 free(group->name);
318 free(group->sword);
319 free(group->join);
320 pcre_free(group->prefix_regexp);
321 pcre_free(group->word_regexp);
322 pcre_free(group->suffix_regexp);
323 ebitmap_destroy(&group->def);
324 free(group);
325 }
326
327 word_group_t *
create_group(word_group_t ** list,const char * name)328 create_group(word_group_t **list, const char *name) {
329 word_group_t *group = calloc(1, sizeof(word_group_t));
330 if (!group)
331 return NULL;
332 group->name = strdup(name);
333 if (!group->name) {
334 goto err;
335 }
336 group->join = strdup(" ");
337 if (!group->join) {
338 goto err;
339 }
340 group->whitespace = strdup(" ");
341 if (!group->whitespace) {
342 goto err;
343 }
344 group->sword = NULL;
345
346 if (list) {
347 for (; *list; list = &(*list)->next)
348 ;
349 *list = group;
350 }
351
352 return group;
353
354 err:
355 log_error("allocation error %s", strerror(errno));
356 destroy_group(NULL, group);
357 return NULL;
358 }
359
360 void
destroy_domain(domain_t * domain)361 destroy_domain(domain_t *domain) {
362 int i;
363 unsigned int rt = 0, tr = 0;
364 for (i=0; i < N_BUCKETS; i++) {
365 context_map_node_t *ptr;
366 for (ptr = domain->trans_to_raw[i]; ptr;) {
367 context_map_node_t *t = ptr->next;
368 free(ptr);
369 ptr = t;
370 tr++;
371 }
372 domain->trans_to_raw[i] = NULL;
373 }
374 for (i=0; i < N_BUCKETS; i++) {
375 context_map_node_t *ptr;
376 for (ptr = domain->raw_to_trans[i]; ptr;) {
377 context_map_node_t *t = ptr->next;
378 free(ptr->map->raw);
379 free(ptr->map->trans);
380 free(ptr->map);
381 free(ptr);
382 ptr = t;
383 rt++;
384 }
385 domain->raw_to_trans[i] = NULL;
386 }
387 while (domain->base_classifications) {
388 base_classification_t *next = domain->base_classifications->next;
389 free(domain->base_classifications->trans);
390 ebitmap_destroy(&domain->base_classifications->level->cat);
391 free(domain->base_classifications->level);
392 free(domain->base_classifications);
393 domain->base_classifications = next;
394 }
395 pcre_free(domain->base_classification_regexp);
396 while (domain->groups)
397 destroy_group(&domain->groups, domain->groups);
398 free(domain->name);
399 free(domain);
400
401 syslog(LOG_INFO, "cache sizes: tr = %u, rt = %u", tr, rt);
402 }
403
404 domain_t *
create_domain(const char * name)405 create_domain(const char *name) {
406 domain_t *domain = calloc(1, sizeof(domain_t));
407 if (!domain) {
408 goto err;
409 }
410 domain->name = strdup(name);
411 if (!domain->name) {
412 goto err;
413 }
414
415 domain_t **d = &domains;
416 for (; *d; d = &(*d)->next)
417 ;
418 *d = domain;
419
420 return domain;
421
422 err:
423 log_error("allocation error %s", strerror(errno));
424 destroy_domain(domain);
425 return NULL;
426 }
427
428 int
add_word(word_group_t * group,char * raw,char * trans)429 add_word(word_group_t *group, char *raw, char *trans) {
430 if (strchr(trans,'-')) {
431 log_error("'%s'is invalid because '-' is illegal in modifiers.\n", trans);
432 return -1;
433 }
434 word_t *word = create_word(&group->words, trans);
435 int rc = parse_ebitmap(&word->cat, &group->def, raw);
436 if (rc < 0) {
437 log_error(" syntax error in %s\n", raw);
438 destroy_word(&group->words, word);
439 return -1;
440 }
441 if (ebitmap_andnot(&word->normal, &word->cat, &group->def, maxbit) < 0)
442 return -1;
443
444 ebitmap_t temp;
445 if (ebitmap_xor(&temp, &word->cat, &group->def) < 0)
446 return -1;
447 if (ebitmap_and(&word->inverse, &temp, &group->def) < 0)
448 return -1;
449 ebitmap_destroy(&temp);
450
451 return 0;
452 }
453
454 int
add_constraint(char op,char * raw,char * tok)455 add_constraint(char op, char *raw, char *tok) {
456 log_debug("%s\n", "add_constraint");
457 ebitmap_t empty;
458 ebitmap_init(&empty);
459 if (!raw || !*raw) {
460 syslog(LOG_ERR, "unable to parse line");
461 return -1;
462 }
463 if (*raw == 's') {
464 sens_constraint_t *constraint = calloc(1, sizeof(sens_constraint_t));
465 if (!constraint) {
466 log_error("allocation error %s", strerror(errno));
467 return -1;
468 }
469 if (sscanf(raw,"s%u", &constraint->sens) != 1) {
470 syslog(LOG_ERR, "unable to parse level");
471 free(constraint);
472 return -1;
473 }
474 if (parse_ebitmap(&constraint->cat, &empty, tok) < 0) {
475 syslog(LOG_ERR, "unable to parse cat");
476 free(constraint);
477 return -1;
478 }
479 if (asprintf(&constraint->text, "%s%c%s", raw, op, tok) < 0) {
480 log_error("asprintf failed %s", strerror(errno));
481 return -1;
482 }
483 constraint->op = op;
484 sens_constraint_t **p;
485 for (p= &sens_constraints; *p; p = &(*p)->next)
486 ;
487 *p = constraint;
488 return 0;
489 } else if (*raw == 'c' ) {
490 cat_constraint_t *constraint = calloc(1, sizeof(cat_constraint_t));
491 if (!constraint) {
492 log_error("allocation error %s", strerror(errno));
493 return -1;
494 }
495 if (parse_ebitmap(&constraint->mask, &empty, raw) < 0) {
496 syslog(LOG_ERR, "unable to parse mask");
497 free(constraint);
498 return -1;
499 }
500 if (parse_ebitmap(&constraint->cat, &empty, tok) < 0) {
501 syslog(LOG_ERR, "unable to parse cat");
502 ebitmap_destroy(&constraint->mask);
503 free(constraint);
504 return -1;
505 }
506 if (asprintf(&constraint->text, "%s%c%s", raw, op, tok) < 0) {
507 log_error("asprintf failed %s", strerror(errno));
508 return -1;
509 }
510 constraint->nbits = ebitmap_cardinality(&constraint->cat);
511 constraint->op = op;
512 cat_constraint_t **p;
513 for (p= &cat_constraints; *p; p = &(*p)->next)
514 ;
515 *p = constraint;
516 return 0;
517 } else {
518 return -1;
519 }
520
521 return 0;
522 }
523
524 int
violates_constraints(mls_level_t * l)525 violates_constraints(mls_level_t *l) {
526 int nbits;
527 sens_constraint_t *s;
528 for (s=sens_constraints; s; s=s->next) {
529 if (s->sens == l->sens) {
530 ebitmap_t common;
531 if (ebitmap_and(&common, &s->cat, &l->cat) < 0)
532 return 1;
533 nbits = ebitmap_cardinality(&common);
534 ebitmap_destroy(&common);
535 if (nbits) {
536 char *text = mls_level_to_string(l);
537 syslog(LOG_WARNING, "%s violates %s", text, s->text);
538 free(text);
539 return 1;
540 }
541 }
542 }
543 cat_constraint_t *c;
544 for (c=cat_constraints; c; c=c->next) {
545 ebitmap_t common;
546 if (ebitmap_and(&common, &c->mask, &l->cat) < 0)
547 return 1;
548 nbits = ebitmap_cardinality(&common);
549 ebitmap_destroy(&common);
550 if (nbits > 0) {
551 ebitmap_t common;
552 if (ebitmap_and(&common, &c->cat, &l->cat) < 0)
553 return 1;
554 nbits = ebitmap_cardinality(&common);
555 ebitmap_destroy(&common);
556 if ((c->op == '!' && nbits) ||
557 (c->op == '>' && nbits != c->nbits)) {
558 char *text = mls_level_to_string(l);
559 syslog(LOG_WARNING, "%s violates %s (%d,%d)", text, c->text, nbits, c->nbits);
560 free(text);
561 return 1;
562 }
563 }
564 }
565 return 0;
566 }
567
568 void
destroy_sens_constraint(sens_constraint_t ** list,sens_constraint_t * constraint)569 destroy_sens_constraint(sens_constraint_t **list, sens_constraint_t *constraint) {
570 if (!constraint) {
571 return;
572 }
573 for (; list && *list; list = &(*list)->next) {
574 if (*list == constraint) {
575 *list = constraint->next;
576 break;
577 }
578 }
579 ebitmap_destroy(&constraint->cat);
580 free(constraint->text);
581 memset(constraint, 0, sizeof(sens_constraint_t));
582 free(constraint);
583 }
584
585 void
destroy_cat_constraint(cat_constraint_t ** list,cat_constraint_t * constraint)586 destroy_cat_constraint(cat_constraint_t **list, cat_constraint_t *constraint) {
587 if (!constraint) {
588 return;
589 }
590 for (; list && *list; list = &(*list)->next) {
591 if (*list == constraint) {
592 *list = constraint->next;
593 break;
594 }
595 }
596 ebitmap_destroy(&constraint->mask);
597 ebitmap_destroy(&constraint->cat);
598 free(constraint->text);
599 memset(constraint, 0, sizeof(cat_constraint_t));
600 free(constraint);
601 }
602
603
604 static int
add_base_classification(domain_t * domain,char * raw,char * trans)605 add_base_classification(domain_t *domain, char *raw, char *trans) {
606 mls_level_t *level = parse_raw(raw);
607 if (level) {
608 base_classification_t **i;
609 base_classification_t *base_classification = calloc(1, sizeof(base_classification_t));
610 if (!base_classification) {
611 log_error("allocation error %s", strerror(errno));
612 return -1;
613 }
614 base_classification->trans=strdup(trans);
615 if (!base_classification->trans) {
616 log_error("allocation error %s", strerror(errno));
617 free(base_classification);
618 return -1;
619 }
620 base_classification->level=level;
621
622 for (i=&domain->base_classifications; *i; i=&(*i)->next)
623 ;
624 *i = base_classification;
625 return 0;
626 }
627 log_error(" add_base_classification error %s %s\n", raw, trans);
628 return -1;
629 }
630
631 static int
add_cache(domain_t * domain,char * raw,char * trans)632 add_cache(domain_t *domain, char *raw, char *trans) {
633 context_map_t *map = calloc(1, sizeof(context_map_t));
634 if (!map) goto err;
635
636 map->raw = strdup(raw);
637 if (!map->raw) {
638 goto err;
639 }
640 map->trans = strdup(trans);
641 if (!map->trans) {
642 goto err;
643 }
644
645 log_debug(" add_cache (%s,%s)\n", raw, trans);
646 if (add_to_hashtable(domain->raw_to_trans, map->raw, map) < 0)
647 goto err;
648
649 if (add_to_hashtable(domain->trans_to_raw, map->trans, map) < 0)
650 goto err;
651
652 return 0;
653 err:
654 log_error("%s: allocation error", "add_cache");
655 return -1;
656 }
657
658 static context_map_t *
find_in_table(context_map_node_t ** table,const char * key)659 find_in_table(context_map_node_t **table, const char *key) {
660 unsigned int bucket = hash(key) % N_BUCKETS;
661 context_map_node_t **n;
662 for (n = &table[bucket]; *n; n = &(*n)->next)
663 if (!strcmp((*n)->key, key))
664 return (*n)->map;
665 return NULL;
666 }
667
668 char *
trim(char * str,const char * whitespace)669 trim(char *str, const char *whitespace) {
670 char *p = str + strlen(str);
671
672 while (p > str && strchr(whitespace, *(p-1)) != NULL)
673 *--p = 0;
674 return str;
675 }
676
677 char *
triml(char * str,const char * whitespace)678 triml(char *str, const char *whitespace) {
679 char *p = str;
680
681 while (*p && (strchr(whitespace, *p) != NULL))
682 p++;
683 return p;
684 }
685
686 int
update(char ** p,char * const val)687 update(char **p, char *const val) {
688 free (*p);
689 *p = strdup(val);
690 if (!*p) {
691 log_error("allocation error %s", strerror(errno));
692 return -1;
693 }
694 return 0;
695 }
696
697 int
append(affix_t ** affixes,const char * val)698 append(affix_t **affixes, const char *val) {
699 affix_t *affix = calloc(1, sizeof(affix_t));
700 if (!affix) {
701 goto err;
702 }
703 affix->text = strdup(val);
704 if (!affix->text)
705 goto err;
706 for (;*affixes; affixes = &(*affixes)->next)
707 ;
708 *affixes = affix;
709 return 0;
710
711 err:
712 log_error("allocation error %s", strerror(errno));
713 return -1;
714 }
715
716 static int read_translations(const char *filename);
717
718 /* Process line from translation file.
719 Remove white space and set raw do data before the "=" and tok to data after it
720 Modifies the data pointed to by the buffer parameter
721 */
722 static int
process_trans(char * buffer)723 process_trans(char *buffer) {
724 static domain_t *domain;
725 static word_group_t *group;
726 static int base_classification;
727 static int lineno = 0;
728 char op='\0';
729
730 lineno++;
731 log_debug("%d: %s", lineno, buffer);
732
733 /* zap leading whitespace */
734 buffer = triml(buffer, "\t ");
735
736 /* Ignore comments */
737 if (*buffer == '#') return 0;
738 char *comment = strpbrk (buffer, "#");
739 if (comment) {
740 *comment = '\0';
741 }
742
743 /* zap trailing whitespace */
744 buffer = trim(buffer, "\t \r\n");
745
746 if (*buffer == 0) return 0;
747
748 char *delim = strpbrk (buffer, "=!>");
749 if (! delim) {
750 syslog(LOG_ERR, "invalid line (no !, = or >) %d", lineno);
751 return -1;
752 }
753
754 op = *delim;
755 *delim = '\0';
756 char *raw = buffer;
757 char *tok = delim+1;
758
759 /* remove trailing/leading whitespace from the split tokens */
760 trim(raw, "\t ");
761 tok = triml(tok, "\t ");
762
763 if (! *raw) {
764 syslog(LOG_ERR, "invalid line %d", lineno);
765 return -1;
766 }
767
768 if (! *tok) {
769 syslog(LOG_ERR, "invalid line %d", lineno);
770 return -1;
771 }
772
773 /* constraints have different syntax */
774 if (op == '!' || op == '>') {
775 return add_constraint(op, raw, tok);
776 }
777
778 if (!strcmp(raw, "Domain")) {
779 domain = create_domain(tok);
780 group = NULL;
781 return 0;
782 }
783
784 if (!domain) {
785 domain = create_domain("Default");
786 if (!domain)
787 return -1;
788 group = NULL;
789 }
790
791 if (!group &&
792 (!strcmp(raw, "Whitespace") || !strcmp(raw, "Join") ||
793 !strcmp(raw, "Prefix") || !strcmp(raw, "Suffix") ||
794 !strcmp(raw, "Default"))) {
795 syslog(LOG_ERR, "expected ModifierGroup declaration on line %d", lineno);
796 return -1;
797 }
798
799 if (!strcmp(raw, "Include")) {
800 unsigned int n;
801 glob_t g;
802 g.gl_offs = 0;
803 if (glob(tok, GLOB_ERR, NULL, &g) < 0) {
804 globfree(&g);
805 return -1;
806 }
807 for (n=0; n < g.gl_pathc; n++) {
808 if (read_translations(g.gl_pathv[n]) < 0) {
809 globfree(&g);
810 return -1;
811 }
812 }
813 globfree(&g);
814 } else if (!strcmp(raw, "Base")) {
815 base_classification = 1;
816 } else if (!strcmp(raw, "ModifierGroup")) {
817 group = create_group(&domain->groups, tok);
818 if (!group)
819 return -1;
820 base_classification = 0;
821 } else if (!strcmp(raw, "Whitespace")) {
822 if (update (&group->whitespace, tok) < 0)
823 return -1;
824 } else if (!strcmp(raw, "Join")) {
825 if (update (&group->join, tok) < 0)
826 return -1;
827 } else if (!strcmp(raw, "Prefix")) {
828 if (append (&group->prefixes, tok) < 0)
829 return -1;
830 } else if (!strcmp(raw, "Suffix")) {
831 if (append (&group->suffixes, tok) < 0)
832 return -1;
833 } else if (!strcmp(raw, "Default")) {
834 ebitmap_t empty;
835 ebitmap_init(&empty);
836 if (parse_ebitmap(&group->def, &empty, tok) < 0) {
837 syslog(LOG_ERR, "unable to parse Default %d", lineno);
838 return -1;
839 }
840 } else if (group) {
841 if (add_word(group, raw, tok) < 0) {
842 syslog(LOG_ERR, "unable to add base_classification on line %d", lineno);
843 return -1;
844 }
845 } else {
846 if (base_classification) {
847 if (add_base_classification(domain, raw, tok) < 0) {
848 syslog(LOG_ERR, "unable to add base_classification on line %d", lineno);
849 return -1;
850 }
851 }
852 if (add_cache(domain, raw, tok) < 0)
853 return -1;
854 }
855 return 0;
856 }
857
858 int
read_translations(const char * filename)859 read_translations(const char *filename) {
860 size_t size = 0;
861 char *buffer = NULL;
862 int rval = 0;
863
864 FILE *cfg = fopen(filename,"r");
865 if (!cfg) {
866 syslog(LOG_ERR, "%s file open failed", filename);
867 return -1;
868 }
869
870 __fsetlocking(cfg, FSETLOCKING_BYCALLER);
871 while (getline(&buffer, &size, cfg) > 0) {
872 if( process_trans(buffer) < 0 ) {
873 syslog(LOG_ERR, "%s file read failed", filename);
874 rval = -1;
875 break;
876 }
877 }
878 free(buffer);
879 fclose(cfg);
880 return rval;
881 }
882
883 int
init_translations(void)884 init_translations(void) {
885 if (is_selinux_mls_enabled() <= 0)
886 return -1;
887
888 return(read_translations(selinux_translations_path()));
889 }
890
891 char *
extract_range(const security_context_t incon)892 extract_range(const security_context_t incon) {
893 context_t con = context_new(incon);
894 if (!con) {
895 syslog(LOG_ERR, "extract_range context_new(%s) failed: %s", incon, strerror(errno));
896 return NULL;
897 }
898
899 const char *range = context_range_get(con);
900 if (!range) {
901 syslog(LOG_ERR, "extract_range: context_range_get(%s) failed: %m", incon);
902 context_free(con);
903 return NULL;
904 }
905 char *r = strdup(range);
906 if (!r) {
907 log_error("extract_range: allocation error %s", strerror(errno));
908 return NULL;
909 }
910 context_free(con);
911 return r;
912 }
913
914 char *
new_context_str(const security_context_t incon,const char * range)915 new_context_str(const security_context_t incon, const char *range) {
916 char *rcon = NULL;
917 context_t con = context_new(incon);
918 if (!con) {
919 goto exit;
920 }
921 context_range_set(con, range);
922 rcon = strdup(context_str(con));
923 if (!rcon) {
924 goto exit;
925 }
926
927 return rcon;
928
929 exit:
930 log_error("new_context_str: %s %s", incon, strerror(errno));
931 return NULL;
932 }
933
934 char *
find_in_hashtable(const char * range,domain_t * domain,context_map_node_t ** table)935 find_in_hashtable(const char *range, domain_t *domain, context_map_node_t **table) {
936 char *trans = NULL;
937 context_map_t *map = find_in_table(table, range);
938 if (map) {
939 trans = strdup((table == domain->raw_to_trans) ? map->trans: map->raw);
940 if (!trans) {
941 log_error("find_in_hashtable: allocation error %s", strerror(errno));
942 return NULL;
943 }
944 log_debug(" found %s in hashtable returning %s\n", range, trans);
945 }
946 return trans;
947 }
948
949 void
emit_whitespace(char * buffer,char * whitespace)950 emit_whitespace(char*buffer, char *whitespace) {
951 strcat(buffer, "[");
952 strcat(buffer, whitespace);
953 strcat(buffer, "]");
954 }
955
956 static int
string_size(const void * p1,const void * p2)957 string_size(const void *p1, const void *p2) {
958 return strlen(*(char **)p2) - strlen(*(char **)p1);
959 }
960
961 static int
word_size(const void * p1,const void * p2)962 word_size(const void *p1, const void *p2) {
963 word_t *w1 = *(word_t **)p1;
964 word_t *w2 = *(word_t **)p2;
965 int w1_len=strlen(w1->text);
966 int w2_len=strlen(w2->text);
967 if (w1_len == w2_len)
968 return strcmp(w1->text, w2->text);
969 return (w2_len - w1_len);
970 }
971
972 void
build_regexp(pcre ** r,char * buffer)973 build_regexp(pcre **r, char *buffer) {
974 const char *error;
975 int error_offset;
976 if (*r)
977 pcre_free(*r);
978 *r = pcre_compile(buffer, PCRE_CASELESS, &error, &error_offset, NULL);
979 if (error) {
980 log_error("pcre=%s, error=%s\n", buffer, error ? error: "none");
981 }
982 buffer[0] = '\0';
983 }
984
985 int
build_regexps(domain_t * domain)986 build_regexps(domain_t *domain) {
987 char buffer[1024 * 128];
988 buffer[0] = '\0';
989 base_classification_t *bc;
990 word_group_t *g;
991 affix_t *a;
992 word_t *w;
993 size_t n_el, i;
994
995 for (n_el = 0, bc = domain->base_classifications; bc; bc = bc->next) {
996 n_el++;
997 }
998
999 char **sortable = calloc(n_el, sizeof(char *));
1000 if (!sortable) {
1001 log_error("allocation error %s", strerror(errno));
1002 return -1;
1003 }
1004
1005 for (i=0, bc = domain->base_classifications; bc; bc = bc->next) {
1006 sortable[i++] = bc->trans;
1007 }
1008
1009 qsort(sortable, n_el, sizeof(char *), string_size);
1010
1011 for (i = 0; i < n_el; i++) {
1012 strcat(buffer, sortable[i]);
1013 if (i < n_el) strcat(buffer,"|");
1014 }
1015
1016 free(sortable);
1017
1018 log_debug(">>> %s classification regexp=%s\n", domain->name, buffer);
1019 build_regexp(&domain->base_classification_regexp, buffer);
1020
1021 for (g = domain->groups; g; g = g->next) {
1022 if (g->prefixes) {
1023 strcat(buffer,"(?:");
1024 for (a = g->prefixes; a; a = a->next) {
1025 strcat(buffer, a->text);
1026 if (a->next) strcat(buffer,"|");
1027 }
1028 strcat(buffer,")");
1029 strcat(buffer,"[ ]+");
1030 log_debug(">>> %s %s prefix regexp=%s\n", domain->name, g->name, buffer);
1031 build_regexp(&g->prefix_regexp, buffer);
1032 }
1033
1034 if (g->prefixes)
1035 strcat(buffer, "^");
1036 strcat(buffer, "(?:");
1037
1038 g->sword_len=0;
1039 for (w = g->words; w; w = w->next)
1040 g->sword_len++;
1041
1042 g->sword = calloc(g->sword_len, sizeof(word_t *));
1043 if (!g->sword) {
1044 log_error("allocation error %s", strerror(errno));
1045 return -1;
1046 }
1047
1048 int i=0;
1049 for (w = g->words; w; w = w->next)
1050 g->sword[i++]=w;
1051
1052 qsort(g->sword, g->sword_len, sizeof(word_t *), word_size);
1053
1054 for (i=0; i < g->sword_len; i++) {
1055 if (i) strcat(buffer,"|");
1056 strcat(buffer,"\\b");
1057 strcat(buffer, g->sword[i]->text);
1058 strcat(buffer,"\\b");
1059 }
1060
1061 if (g->whitespace) {
1062 strcat(buffer,"|[");
1063 strcat(buffer, g->whitespace);
1064 strcat(buffer, "]+");
1065 }
1066
1067 strcat(buffer, ")+");
1068 if (g->suffixes)
1069 strcat(buffer, "$");
1070
1071 log_debug(">>> %s %s modifier regexp=%s\n", domain->name, g->name, buffer);
1072 build_regexp(&g->word_regexp, buffer);
1073 if (g->suffixes) {
1074 strcat(buffer,"[ ]+");
1075 strcat(buffer,"(?:");
1076 for (a = g->suffixes; a; a = a->next) {
1077 strcat(buffer, a->text);
1078 if (a->next) strcat(buffer,"|");
1079 }
1080 strcat(buffer,")");
1081 log_debug(">>> %s %s suffix regexp=%s\n", domain->name, g->name, buffer);
1082 build_regexp(&g->suffix_regexp, buffer);
1083 }
1084 }
1085
1086 return 0;
1087 }
1088
1089 char *
compute_raw_from_trans(const char * level,domain_t * domain)1090 compute_raw_from_trans(const char *level, domain_t *domain) {
1091
1092 #ifdef DEBUG
1093 struct timeval startTime;
1094 gettimeofday(&startTime, 0);
1095 #endif
1096
1097 int ovector[OVECCOUNT];
1098 word_group_t *g = NULL;
1099 char *work = NULL;
1100 char *r = NULL;
1101 const char * match = NULL;
1102 int work_len;
1103 mls_level_t *mraw = NULL;
1104 ebitmap_t set, clear, tmp;
1105
1106 ebitmap_init(&set);
1107 ebitmap_init(&clear);
1108 ebitmap_init(&tmp);
1109
1110 work = strdup(level);
1111 if (!work) {
1112 log_error("compute_raw_from_trans: allocation error %s", strerror(errno));
1113 goto err;
1114 }
1115 work_len = strlen(work);
1116
1117 if (!domain->base_classification_regexp)
1118 if (build_regexps(domain) < 0)
1119 goto err;
1120 if (!domain->base_classification_regexp)
1121 goto err;
1122 log_debug(" compute_raw_from_trans work = %s\n", work);
1123 int rc = pcre_exec(domain->base_classification_regexp, 0, work, work_len, 0, PCRE_ANCHORED, ovector, OVECCOUNT);
1124 if (rc > 0) {
1125 match = NULL;
1126 pcre_get_substring(work, ovector, rc, 0, &match);
1127 log_debug(" compute_raw_from_trans match = %s len = %u\n", match, strlen(match));
1128 base_classification_t *bc;
1129 for (bc = domain->base_classifications; bc; bc = bc->next) {
1130 if (!strcmp(bc->trans, match)) {
1131 log_debug(" compute_raw_from_trans base classification %s matched %s\n", level, bc->trans);
1132 mraw = malloc(sizeof(mls_level_t));
1133 if (!mraw) {
1134 log_error("allocation error %s", strerror(errno));
1135 goto err;
1136 }
1137 if (mls_level_cpy(mraw, bc->level) < 0)
1138 goto err;
1139 break;
1140 }
1141 }
1142
1143 memset(work + ovector[0], '#', ovector[1] - ovector[0]);
1144 char *p=work + ovector[0] + ovector[1];
1145 while (*p && (strchr(" ", *p) != NULL))
1146 *p++ = '#';
1147 pcre_free((char *)match);
1148 match = NULL;
1149 } else {
1150 log_debug(" compute_raw_from_trans no base classification matched %s\n", level);
1151 }
1152
1153 if (mraw == NULL) {
1154 goto err;
1155 }
1156
1157 int complete = 0;
1158 int change = 1;
1159 while(change && !complete) {
1160 change = 0;
1161 for (g = domain->groups; g && !change && !complete; g = g->next) {
1162 int prefix = 0, suffix = 0;
1163 int prefix_offset = 0, prefix_len = 0;
1164 int suffix_offset = 0, suffix_len = 0;
1165 if (g->prefix_regexp) {
1166 int rc = pcre_exec(g->prefix_regexp, 0, work, work_len, 0, 0, ovector, OVECCOUNT);
1167 if (rc > 0) {
1168 prefix = 1;
1169 prefix_offset = ovector[0];
1170 prefix_len = ovector[1] - ovector[0];
1171 }
1172 }
1173 if (g->suffix_regexp) {
1174 int rc = pcre_exec(g->suffix_regexp, 0, work, work_len, 0, 0, ovector, OVECCOUNT);
1175 if (rc > 0) {
1176 suffix = 1;
1177 suffix_offset = ovector[0];
1178 suffix_len = ovector[1] - ovector[0];
1179 }
1180 }
1181
1182 /* anchors prefix ^, suffix $ */
1183 if (((!g->prefixes && !g->suffixes) ||
1184 (g->prefixes && prefix) ||
1185 (g->suffixes && suffix)) &&
1186 g->word_regexp) {
1187 char *s = work + prefix_offset + prefix_len;
1188 int l = (suffix_len ? suffix_offset : work_len) - prefix_len - prefix_offset;
1189 int rc = pcre_exec(g->word_regexp, 0, s, l, 0, 0, ovector, OVECCOUNT);
1190 if (rc > 0) {
1191 match = NULL;
1192 pcre_get_substring(s, ovector, rc, 0, &match);
1193 trim((char *)match, g->whitespace);
1194 if (*match) {
1195 char *p = triml((char *)match, g->whitespace);
1196 while (p && *p) {
1197 int plen = strlen(p);
1198 int i;
1199 for (i = 0; i < g->sword_len; i++) {
1200 word_t *w = g->sword[i];
1201 int wlen = strlen(w->text);
1202 if (plen >= wlen && !strncmp(w->text, p, strlen(w->text))){
1203 if (ebitmap_andnot(&set, &w->cat, &g->def, maxbit) < 0) goto err;
1204
1205 if (ebitmap_xor(&tmp, &w->cat, &g->def) < 0) goto err;
1206 if (ebitmap_and(&clear, &tmp, &g->def) < 0) goto err;
1207 if (ebitmap_union(&mraw->cat, &set) < 0) goto err;
1208
1209 ebitmap_destroy(&tmp);
1210 if (ebitmap_cpy(&tmp, &mraw->cat) < 0) goto err;
1211 ebitmap_destroy(&mraw->cat);
1212 if (ebitmap_andnot(&mraw->cat, &tmp, &clear, maxbit) < 0) goto err;
1213
1214 ebitmap_destroy(&tmp);
1215 ebitmap_destroy(&set);
1216 ebitmap_destroy(&clear);
1217 p += strlen(w->text);
1218 change++;
1219 break;
1220 }
1221 }
1222 if (i == g->sword_len) {
1223 syslog(LOG_ERR, "conversion error");
1224 break;
1225 }
1226 p = triml(p, g->whitespace);
1227 }
1228 memset(work + prefix_offset, '#', prefix_len);
1229 memset(work + suffix_offset, '#', suffix_len);
1230 memset(s + ovector[0], '#', ovector[1] - ovector[0]);
1231 }
1232 pcre_free((void *)match);
1233 match = NULL;
1234 }
1235 }
1236 /* YYY */
1237 complete=1;
1238 char *p = work;
1239 while(*p) {
1240 if (isalnum(*p++)) {
1241 complete=0;
1242 break;
1243 }
1244 }
1245 }
1246 }
1247 free(work);
1248 if (violates_constraints(mraw)) {
1249 complete = 0;
1250 }
1251 if (complete)
1252 r = mls_level_to_string(mraw);
1253 mls_level_destroy(mraw);
1254 free(mraw);
1255
1256 #ifdef DEBUG
1257 struct timeval stopTime;
1258 gettimeofday(&stopTime, 0);
1259 long int ms;
1260 if (startTime.tv_usec > stopTime.tv_usec)
1261 ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
1262 else
1263 ms = (stopTime.tv_sec - startTime.tv_sec ) * 1000 + (stopTime.tv_usec/1000 - startTime.tv_usec/1000);
1264 log_debug(" compute_raw_from_trans in %ld ms'\n", ms);
1265 #endif
1266
1267 return r;
1268
1269 err:
1270 mls_level_destroy(mraw);
1271 free(mraw);
1272 free(work);
1273 pcre_free((void *)match);
1274 ebitmap_destroy(&tmp);
1275 ebitmap_destroy(&set);
1276 ebitmap_destroy(&clear);
1277 return NULL;
1278 }
1279
1280 char *
compute_trans_from_raw(const char * level,domain_t * domain)1281 compute_trans_from_raw(const char *level, domain_t *domain) {
1282
1283 #ifdef DEBUG
1284 struct timeval startTime;
1285 gettimeofday(&startTime, 0);
1286 #endif
1287
1288 mls_level_t *l = NULL;
1289 char *rval = NULL;
1290 ebitmap_t bit_diff, temp, handled, nothandled, unhandled, orig_unhandled;
1291
1292 ebitmap_init(&bit_diff);
1293 ebitmap_init(&temp);
1294 ebitmap_init(&handled);
1295 ebitmap_init(¬handled);
1296 ebitmap_init(&unhandled);
1297 ebitmap_init(&orig_unhandled);
1298
1299 if (!level)
1300 goto err;
1301
1302 l = parse_raw(level);
1303 if (!l)
1304 goto err;
1305 log_debug(" compute_trans_from_raw raw = %s\n", level);
1306
1307 /* YYY */
1308 /* check constraints */
1309 if (violates_constraints(l)) {
1310 syslog(LOG_ERR, "%s violates constraints", level);
1311 goto err;
1312 }
1313
1314 int doInverse = l->sens > 0;
1315
1316 word_group_t *groups = NULL;
1317 base_classification_t *bc, *last = NULL;
1318 int done = 0;
1319 for (bc = domain->base_classifications; bc && !done; bc = bc->next) {
1320 if (l->sens == bc->level->sens) {
1321 /* skip if alias of last bc */
1322 if (last &&
1323 last->level->sens == bc->level->sens &&
1324 ebitmap_cmp(&last->level->cat, &bc->level->cat) == 0)
1325 continue;
1326
1327 /* compute bits not consumed by base classification */
1328 ebitmap_t unhandled, orig_unhandled;
1329 if (ebitmap_xor(&unhandled, &l->cat, &bc->level->cat) < 0)
1330 goto err;
1331 if (ebitmap_cpy(&orig_unhandled, &unhandled) < 0)
1332 goto err;
1333
1334 /* prebuild groups */
1335 word_group_t *g;
1336 for (g = domain->groups; g; g = g->next) {
1337 word_group_t **t;
1338 for (t = &groups; *t; t = &(*t)->next)
1339 if (!strcmp(g->name, (*t)->name))
1340 break;
1341
1342 if (! *t) {
1343 word_group_t *wg = create_group(&groups, g->name);
1344 if (g->prefixes)
1345 if (append(&wg->prefixes, g->prefixes->text) < 0)
1346 goto err;
1347 if (g->suffixes)
1348 if (append(&wg->suffixes, g->suffixes->text) < 0)
1349 goto err;
1350 if (g->join)
1351 if (update(&wg->join, g->join) < 0)
1352 goto err;
1353 }
1354 }
1355
1356 int loops, hamming, change=1;
1357 for (loops = 50; ebitmap_cardinality(&unhandled) && loops > 0 && change; loops--) {
1358 change = 0;
1359 hamming = 10000;
1360 ebitmap_t handled, nothandled;
1361 if (ebitmap_xor(&handled, &unhandled, &orig_unhandled) < 0)
1362 goto err;
1363 if (ebitmap_not(¬handled, &handled, maxbit) < 0)
1364 goto err;
1365 word_group_t *currentGroup = NULL;
1366 word_t *currentWord = NULL;
1367 for (g = domain->groups; g && hamming; g = g->next) {
1368 word_t *w;
1369 for (w = g->words; w && hamming; w = w->next) {
1370 int cardinality = ebitmap_cardinality(&w->normal);
1371 /* If the word is all inverse bits and the level does not have inverse bits - skip */
1372 if (cardinality && !doInverse) {
1373 continue;
1374 }
1375
1376 /* if only unhandled bits are different */
1377 ebitmap_t temp;
1378 ebitmap_t bit_diff;
1379 if (ebitmap_or(&temp, &w->normal, &w->inverse) < 0)
1380 goto err;
1381 if (ebitmap_and(&bit_diff, &temp, ¬handled) < 0)
1382 goto err;
1383 ebitmap_destroy(&temp);
1384 // xor bit_diff handled?
1385 if (ebitmap_and(&temp, &bit_diff, &unhandled) < 0)
1386 goto err;
1387 if (ebitmap_cmp(&bit_diff, &temp)) {
1388 int h = ebitmap_hamming_distance(&bit_diff, &unhandled);
1389 if (h < hamming) {
1390 hamming = h;
1391 currentGroup = g;
1392 currentWord = w;
1393 }
1394 }
1395 ebitmap_destroy(&bit_diff);
1396 ebitmap_destroy(&temp);
1397 }
1398 }
1399 ebitmap_destroy(&handled);
1400 ebitmap_destroy(¬handled);
1401
1402 if (currentWord) {
1403 ebitmap_t bit_diff;
1404 if (ebitmap_xor(&bit_diff, ¤tWord->cat, &bc->level->cat) < 0)
1405 goto err;
1406
1407 ebitmap_t temp;
1408 if (ebitmap_cpy(&temp, &unhandled) < 0)
1409 goto err;
1410 ebitmap_destroy(&unhandled);
1411 if (ebitmap_andnot(&unhandled, &temp, &bit_diff, maxbit) < 0)
1412 goto err;
1413
1414 ebitmap_destroy(&bit_diff);
1415 ebitmap_destroy(&temp);
1416
1417 word_group_t **t;
1418 for (t = &groups; *t; t = &(*t)->next)
1419 if (!strcmp(currentGroup->name, (*t)->name))
1420 break;
1421 create_word(&(*t)->words, currentWord->text);
1422 change++;
1423 }
1424 }
1425
1426 done = (ebitmap_cardinality(&unhandled) == 0);
1427 ebitmap_destroy(&unhandled);
1428 ebitmap_destroy(&orig_unhandled);
1429 if (done) {
1430 char buffer[9999];
1431 buffer[0] = 0;
1432 strcat(buffer, bc->trans);
1433 strcat(buffer, " ");
1434 word_group_t *g;
1435 for (g=groups; g; g = g->next) {
1436 if (g->words && g->prefixes) {
1437 strcat(buffer, g->prefixes->text);
1438 strcat(buffer, " ");
1439 }
1440 word_t *w;
1441 for (w=g->words; w; w = w->next) {
1442 strcat(buffer, w->text);
1443 if (w->next)
1444 strcat(buffer, g->join);
1445 }
1446 if (g->words && g->suffixes) {
1447 strcat(buffer, " ");
1448 strcat(buffer, g->suffixes->text);
1449 }
1450 word_group_t *n = g->next;
1451 while(g->words && n) {
1452 if (n->words) {
1453 strcat(buffer, " ");
1454 break;
1455 }
1456 n = n->next;
1457 }
1458 }
1459 rval = strdup(buffer);
1460 if (!rval) {
1461 log_error("compute_trans_from_raw: allocation error %s", strerror(errno));
1462 goto err;
1463 }
1464 }
1465 /* clean up */
1466 while (groups)
1467 destroy_group(&groups, groups);
1468 }
1469 last = bc;
1470 }
1471 if (l) {
1472 mls_level_destroy(l);
1473 free(l);
1474 }
1475
1476 #ifdef DEBUG
1477 struct timeval stopTime;
1478 gettimeofday(&stopTime, 0);
1479 long int ms;
1480 if (startTime.tv_usec > stopTime.tv_usec)
1481 ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
1482 else
1483 ms = (stopTime.tv_sec - startTime.tv_sec ) * 1000 + (stopTime.tv_usec/1000 - startTime.tv_usec/1000);
1484
1485 log_debug(" compute_trans_from_raw in %ld ms'\n", ms);
1486 #endif
1487
1488 return rval;
1489
1490 err:
1491 while (groups)
1492 destroy_group(&groups, groups);
1493 mls_level_destroy(l);
1494 free(l);
1495 return NULL;
1496 }
1497
1498 int
trans_context(const security_context_t incon,security_context_t * rcon)1499 trans_context(const security_context_t incon, security_context_t *rcon) {
1500 char *trans = NULL;
1501 *rcon = NULL;
1502
1503 #ifdef DEBUG
1504 struct timeval startTime;
1505 gettimeofday(&startTime, 0);
1506 #endif
1507
1508 log_debug(" trans_context input = %s\n", incon);
1509 char *range = extract_range(incon);
1510 if (!range) return -1;
1511
1512 domain_t *domain = domains;
1513 for (;domain; domain = domain->next) {
1514 trans = find_in_hashtable(range, domain, domain->raw_to_trans);
1515 if (trans) break;
1516
1517 /* try split and translate */
1518 char *lrange = NULL, *urange = NULL;
1519 char *ltrans = NULL, *utrans = NULL;
1520 char *dashp = strchr(range,'-');
1521 if (dashp) {
1522 *dashp = 0;
1523 lrange = range;
1524 urange = dashp+1;
1525 } else {
1526 trans = compute_trans_from_raw(range, domain);
1527 if (trans)
1528 if (add_cache(domain, range, trans) < 0)
1529 return -1;
1530 }
1531
1532 if (lrange && urange) {
1533 ltrans = find_in_hashtable(lrange, domain, domain->raw_to_trans);
1534 if (! ltrans) {
1535 ltrans = compute_trans_from_raw(lrange, domain);
1536 if (ltrans) {
1537 if (add_cache(domain, lrange, ltrans) < 0)
1538 return -1;
1539 } else {
1540 ltrans = strdup(lrange);
1541 if (! ltrans) {
1542 log_error("strdup failed %s", strerror(errno));
1543 return -1;
1544 }
1545 }
1546 }
1547
1548 utrans = find_in_hashtable(urange, domain, domain->raw_to_trans);
1549 if (! utrans) {
1550 utrans = compute_trans_from_raw(urange, domain);
1551 if (utrans) {
1552 if (add_cache(domain, urange, utrans) < 0)
1553 return -1;
1554 } else {
1555 utrans = strdup(urange);
1556 if (! utrans) {
1557 log_error("strdup failed %s", strerror(errno));
1558 return -1;
1559 }
1560 }
1561 }
1562
1563 if (strcmp(ltrans, utrans) == 0) {
1564 if (asprintf(&trans, "%s", ltrans) < 0) {
1565 log_error("asprintf failed %s", strerror(errno));
1566 return -1;
1567 }
1568 } else {
1569 if (asprintf(&trans, "%s-%s", ltrans, utrans) < 0) {
1570 log_error("asprintf failed %s", strerror(errno));
1571 return -1;
1572 }
1573 }
1574 free(ltrans);
1575 free(utrans);
1576 *dashp = '-';
1577 break;
1578 }
1579 if (dashp)
1580 *dashp = '-';
1581 }
1582
1583 if (trans) {
1584 *rcon = new_context_str(incon, trans);
1585 free(trans);
1586 } else {
1587 *rcon = new_context_str(incon, range);
1588 }
1589 free(range);
1590
1591 #ifdef DEBUG
1592 struct timeval stopTime;
1593 gettimeofday(&stopTime, 0);
1594 long int ms;
1595 if (startTime.tv_usec > stopTime.tv_usec)
1596 ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
1597 else
1598 ms = (stopTime.tv_sec - startTime.tv_sec ) * 1000 + (stopTime.tv_usec/1000 - startTime.tv_usec/1000);
1599
1600 log_debug(" trans_context input='%s' output='%s in %ld ms'\n", incon, *rcon, ms);
1601 #endif
1602 return 0;
1603 }
1604
1605 int
untrans_context(const security_context_t incon,security_context_t * rcon)1606 untrans_context(const security_context_t incon, security_context_t *rcon) {
1607 char *raw = NULL;
1608 *rcon = NULL;
1609
1610 #ifdef DEBUG
1611 struct timeval startTime;
1612 gettimeofday(&startTime, 0);
1613 #endif
1614
1615 log_debug(" untrans_context incon = %s\n", incon);
1616 char *range = extract_range(incon);
1617 if (!range) return -1;
1618 log_debug(" untrans_context range = %s\n", range);
1619
1620 domain_t *domain = domains;
1621 for (;domain; domain = domain->next) {
1622 raw = find_in_hashtable(range, domain, domain->trans_to_raw);
1623 if (raw) break;
1624
1625 /* try split and translate */
1626 char *lrange = NULL, *urange = NULL;
1627 char *lraw = NULL, *uraw = NULL;
1628 char *dashp = strchr(range,'-');
1629 if (dashp) {
1630 *dashp = 0;
1631 lrange = range;
1632 urange = dashp+1;
1633 } else {
1634 raw = compute_raw_from_trans(range, domain);
1635 if (raw) {
1636 char *canonical = find_in_hashtable(raw, domain, domain->raw_to_trans);
1637 if (!canonical) {
1638 canonical = compute_trans_from_raw(raw, domain);
1639 if (canonical && strcmp(canonical, range))
1640 if (add_cache(domain, raw, canonical) < 0)
1641 return -1;
1642 }
1643 if (canonical)
1644 free(canonical);
1645 if (add_cache(domain, raw, range) < 0)
1646 return -1;
1647 } else {
1648 log_debug("untrans_context unable to compute raw context %s\n", range);
1649 }
1650 }
1651
1652 if (lrange && urange) {
1653 lraw = find_in_hashtable(lrange, domain, domain->trans_to_raw);
1654 if (! lraw) {
1655 lraw = compute_raw_from_trans(lrange, domain);
1656 if (lraw) {
1657 char *canonical = find_in_hashtable(lraw, domain, domain->raw_to_trans);
1658 if (!canonical) {
1659 canonical = compute_trans_from_raw(lraw, domain);
1660 if (canonical)
1661 if (add_cache(domain, lraw, canonical) < 0)
1662 return -1;
1663 }
1664 if (canonical)
1665 free(canonical);
1666 if (add_cache(domain, lraw, lrange) < 0)
1667 return -1;
1668 } else {
1669 lraw = strdup(lrange);
1670 if (! lraw) {
1671 log_error("strdup failed %s", strerror(errno));
1672 return -1;
1673 }
1674 }
1675 }
1676
1677 uraw = find_in_hashtable(urange, domain, domain->trans_to_raw);
1678 if (! uraw) {
1679 uraw = compute_raw_from_trans(urange, domain);
1680 if (uraw) {
1681 char *canonical = find_in_hashtable(uraw, domain, domain->raw_to_trans);
1682 if (!canonical) {
1683 canonical = compute_trans_from_raw(uraw, domain);
1684 if (canonical)
1685 if (add_cache(domain, uraw, canonical) < 0)
1686 return -1;
1687 }
1688 if (canonical)
1689 free(canonical);
1690 if (add_cache(domain, uraw, urange) < 0)
1691 return -1;
1692 } else {
1693 uraw = strdup(urange);
1694 if (! uraw) {
1695 log_error("strdup failed %s", strerror(errno));
1696 return -1;
1697 }
1698 }
1699 }
1700
1701
1702 if (strcmp(lraw, uraw) == 0) {
1703 if (asprintf(&raw, "%s", lraw) < 0) {
1704 log_error("asprintf failed %s", strerror(errno));
1705 return -1;
1706 }
1707 } else {
1708 if (asprintf(&raw, "%s-%s", lraw, uraw) < 0) {
1709 log_error("asprintf failed %s", strerror(errno));
1710 return -1;
1711 }
1712 }
1713 free(lraw);
1714 free(uraw);
1715 *dashp = '-';
1716 break;
1717 }
1718 if (dashp)
1719 *dashp = '-';
1720 }
1721
1722 if (raw) {
1723 *rcon = new_context_str(incon, raw);
1724 free(raw);
1725 } else {
1726 *rcon = new_context_str(incon, range);
1727 }
1728 free(range);
1729
1730 #ifdef DEBUG
1731 struct timeval stopTime;
1732 gettimeofday(&stopTime, 0);
1733 long int ms;
1734 if (startTime.tv_usec > stopTime.tv_usec)
1735 ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
1736 else
1737 ms = (stopTime.tv_sec - startTime.tv_sec ) * 1000 + (stopTime.tv_usec/1000 - startTime.tv_usec/1000);
1738
1739 log_debug(" untrans_context input='%s' output='%s' n %ld ms\n", incon, *rcon, ms);
1740 #endif
1741 return 0;
1742 }
1743
1744 void
finish_context_translations(void)1745 finish_context_translations(void) {
1746 while(domains) {
1747 domain_t *next = domains->next;
1748 destroy_domain(domains);
1749 domains = next;
1750 }
1751 while(sens_constraints) {
1752 sens_constraint_t *next = sens_constraints->next;
1753 destroy_sens_constraint(&sens_constraints, sens_constraints);
1754 sens_constraints = next;
1755 }
1756 while(cat_constraints) {
1757 cat_constraint_t *next = cat_constraints->next;
1758 destroy_cat_constraint(&cat_constraints, cat_constraints);
1759 cat_constraints = next;
1760 }
1761 }
1762
1763