Home | History | Annotate | Download | only in src
      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 	unsigned 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
    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
    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
    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
    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
    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 *
    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
    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 *
    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
    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 *
    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
    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 *
    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
    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
    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
    525 violates_constraints(mls_level_t *l) {
    526 	int nbits;
    527 	sens_constraint_t *s;
    528 	ebitmap_t common;
    529 	for (s=sens_constraints; s; s=s->next) {
    530 		if (s->sens == l->sens) {
    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 		if (ebitmap_and(&common, &c->mask, &l->cat) < 0)
    546 			return 1;
    547 		nbits = ebitmap_cardinality(&common);
    548 		ebitmap_destroy(&common);
    549 		if (nbits > 0) {
    550 			if (ebitmap_and(&common, &c->cat, &l->cat) < 0)
    551 				return 1;
    552 			nbits = ebitmap_cardinality(&common);
    553 			ebitmap_destroy(&common);
    554 			if ((c->op == '!' && nbits) ||
    555 			    (c->op == '>' && nbits != c->nbits)) {
    556 				char *text = mls_level_to_string(l);
    557 				syslog(LOG_WARNING, "%s violates %s (%d,%d)", text, c->text, nbits, c->nbits);
    558 				free(text);
    559 				return 1;
    560 			}
    561 		}
    562 	}
    563 	return 0;
    564 }
    565 
    566 void
    567 destroy_sens_constraint(sens_constraint_t **list, sens_constraint_t *constraint) {
    568 	if (!constraint) {
    569 		return;
    570 	}
    571 	for (; list && *list; list = &(*list)->next) {
    572 		if (*list == constraint) {
    573 			*list = constraint->next;
    574 			break;
    575 		}
    576 	}
    577 	ebitmap_destroy(&constraint->cat);
    578 	free(constraint->text);
    579 	memset(constraint, 0, sizeof(sens_constraint_t));
    580 	free(constraint);
    581 }
    582 
    583 void
    584 destroy_cat_constraint(cat_constraint_t **list, cat_constraint_t *constraint) {
    585 	if (!constraint) {
    586 		return;
    587 	}
    588 	for (; list && *list; list = &(*list)->next) {
    589 		if (*list == constraint) {
    590 			*list = constraint->next;
    591 			break;
    592 		}
    593 	}
    594 	ebitmap_destroy(&constraint->mask);
    595 	ebitmap_destroy(&constraint->cat);
    596 	free(constraint->text);
    597 	memset(constraint, 0, sizeof(cat_constraint_t));
    598 	free(constraint);
    599 }
    600 
    601 
    602 static int
    603 add_base_classification(domain_t *domain, char *raw, char *trans) {
    604 	mls_level_t *level = parse_raw(raw);
    605 	if (level) {
    606 		base_classification_t **i;
    607 		base_classification_t *base_classification = calloc(1, sizeof(base_classification_t));
    608 		if (!base_classification) {
    609 			log_error("allocation error %s", strerror(errno));
    610 			return -1;
    611 		}
    612 		base_classification->trans=strdup(trans);
    613 		if (!base_classification->trans) {
    614 			log_error("allocation error %s", strerror(errno));
    615 			free(base_classification);
    616 			return -1;
    617 		}
    618 		base_classification->level=level;
    619 
    620 		for (i=&domain->base_classifications; *i; i=&(*i)->next)
    621 		;
    622 		*i = base_classification;
    623 			return 0;
    624 		}
    625 	log_error(" add_base_classification error %s %s\n", raw, trans);
    626 	return -1;
    627 }
    628 
    629 static int
    630 add_cache(domain_t *domain, char *raw, char *trans) {
    631 	context_map_t *map = calloc(1, sizeof(context_map_t));
    632 	if (!map) goto err;
    633 
    634 	map->raw = strdup(raw);
    635 	if (!map->raw) {
    636 		goto err;
    637 	}
    638 	map->trans = strdup(trans);
    639 	if (!map->trans) {
    640 		goto err;
    641 	}
    642 
    643 	log_debug(" add_cache (%s,%s)\n", raw, trans);
    644 	if (add_to_hashtable(domain->raw_to_trans, map->raw, map) < 0)
    645 		goto err;
    646 
    647 	if (add_to_hashtable(domain->trans_to_raw, map->trans, map) < 0)
    648 		goto err;
    649 
    650 	return 0;
    651 err:
    652 	log_error("%s: allocation error", "add_cache");
    653 	return -1;
    654 }
    655 
    656 static context_map_t *
    657 find_in_table(context_map_node_t **table, const char *key) {
    658 	unsigned int bucket = hash(key) % N_BUCKETS;
    659 	context_map_node_t **n;
    660 	for (n = &table[bucket]; *n; n = &(*n)->next)
    661 		if (!strcmp((*n)->key, key))
    662 			return (*n)->map;
    663 	return NULL;
    664 }
    665 
    666 char *
    667 trim(char *str, const char *whitespace) {
    668 	char *p = str + strlen(str);
    669 
    670 	while (p > str && strchr(whitespace, *(p-1)) != NULL)
    671 		*--p = 0;
    672 	return str;
    673 }
    674 
    675 char *
    676 triml(char *str, const char *whitespace) {
    677 	char *p = str;
    678 
    679 	while (*p && (strchr(whitespace, *p) != NULL))
    680 		p++;
    681 	return p;
    682 }
    683 
    684 int
    685 update(char **p, char *const val) {
    686 	free (*p);
    687 	*p = strdup(val);
    688 	if (!*p) {
    689 		log_error("allocation error %s", strerror(errno));
    690 		return -1;
    691 	}
    692 	return 0;
    693 }
    694 
    695 int
    696 append(affix_t **affixes, const char *val) {
    697 	affix_t *affix = calloc(1, sizeof(affix_t));
    698 	if (!affix) {
    699 		goto err;
    700 	}
    701 	affix->text = strdup(val);
    702 	if (!affix->text)
    703 		goto err;
    704 	for (;*affixes; affixes = &(*affixes)->next)
    705 		;
    706 	*affixes = affix;
    707 	return 0;
    708 
    709 err:
    710 	log_error("allocation error %s", strerror(errno));
    711 	return -1;
    712 }
    713 
    714 static int read_translations(const char *filename);
    715 
    716 /* Process line from translation file.
    717    Remove white space and set raw do data before the "=" and tok to data after it
    718    Modifies the data pointed to by the buffer parameter
    719  */
    720 static int
    721 process_trans(char *buffer) {
    722 	static domain_t *domain;
    723 	static word_group_t *group;
    724 	static int base_classification;
    725 	static int lineno = 0;
    726 	char op='\0';
    727 
    728 	lineno++;
    729 	log_debug("%d: %s", lineno, buffer);
    730 
    731 	/* zap leading whitespace */
    732 	buffer = triml(buffer, "\t ");
    733 
    734 	/* Ignore comments */
    735 	if (*buffer == '#') return 0;
    736 	char *comment = strpbrk (buffer, "#");
    737 	if (comment) {
    738 		*comment = '\0';
    739 	}
    740 
    741 	/* zap trailing whitespace */
    742 	buffer = trim(buffer, "\t \r\n");
    743 
    744 	if (*buffer == 0) return 0;
    745 
    746 	char *delim = strpbrk (buffer, "=!>");
    747 	if (! delim) {
    748 		syslog(LOG_ERR, "invalid line (no !, = or >) %d", lineno);
    749 		return -1;
    750 	}
    751 
    752 	op = *delim;
    753 	*delim = '\0';
    754 	char *raw = buffer;
    755 	char *tok = delim+1;
    756 
    757 	/* remove trailing/leading whitespace from the split tokens */
    758 	trim(raw, "\t ");
    759 	tok = triml(tok, "\t ");
    760 
    761 	if (! *raw) {
    762 		syslog(LOG_ERR, "invalid line %d", lineno);
    763 		return -1;
    764 	}
    765 
    766 	if (! *tok) {
    767 		syslog(LOG_ERR, "invalid line %d", lineno);
    768 		return -1;
    769 	}
    770 
    771 	/* constraints have different syntax */
    772 	if (op == '!' || op == '>') {
    773 		return add_constraint(op, raw, tok);
    774 	}
    775 
    776 	if (!strcmp(raw, "Domain")) {
    777 		domain = create_domain(tok);
    778 		group = NULL;
    779 		return 0;
    780 	}
    781 
    782 	if (!domain) {
    783 		domain = create_domain("Default");
    784 		if (!domain)
    785 			return -1;
    786 		group = NULL;
    787 	}
    788 
    789 	if (!group &&
    790 	    (!strcmp(raw, "Whitespace") || !strcmp(raw, "Join") ||
    791 	     !strcmp(raw, "Prefix") || !strcmp(raw, "Suffix") ||
    792 		 !strcmp(raw, "Default"))) {
    793 		syslog(LOG_ERR, "expected  ModifierGroup declaration on line %d", lineno);
    794 		return -1;
    795 	}
    796 
    797 	if (!strcmp(raw, "Include")) {
    798 		unsigned int n;
    799 		glob_t g;
    800 		g.gl_offs = 0;
    801 		if (glob(tok, GLOB_ERR, NULL, &g) < 0) {
    802 			globfree(&g);
    803 			return -1;
    804 		}
    805 		for (n=0; n < g.gl_pathc; n++) {
    806 			if (read_translations(g.gl_pathv[n]) < 0) {
    807 				globfree(&g);
    808 				return -1;
    809 			}
    810 		}
    811 		globfree(&g);
    812 	} else if (!strcmp(raw, "Base")) {
    813 		base_classification = 1;
    814 	} else if (!strcmp(raw, "ModifierGroup")) {
    815 		group = create_group(&domain->groups, tok);
    816 		if (!group)
    817 			return -1;
    818 		base_classification = 0;
    819 	} else if (!strcmp(raw, "Whitespace")) {
    820 		if (update (&group->whitespace, tok) < 0)
    821 			return -1;
    822 	} else if (!strcmp(raw, "Join")) {
    823 		if (update (&group->join, tok) < 0)
    824 			return -1;
    825 	} else if (!strcmp(raw, "Prefix")) {
    826 		if (append (&group->prefixes, tok) < 0)
    827 			return -1;
    828 	} else if (!strcmp(raw, "Suffix")) {
    829 		if (append (&group->suffixes, tok) < 0)
    830 			return -1;
    831 	} else if (!strcmp(raw, "Default")) {
    832 		ebitmap_t empty;
    833 		ebitmap_init(&empty);
    834 		if (parse_ebitmap(&group->def, &empty, tok) < 0) {
    835 			syslog(LOG_ERR, "unable to parse Default %d", lineno);
    836 			return -1;
    837 		}
    838 	} else if (group) {
    839 		if (add_word(group, raw, tok) < 0) {
    840 			syslog(LOG_ERR, "unable to add base_classification on line %d", lineno);
    841 			return -1;
    842 		}
    843 	} else {
    844 		if (base_classification) {
    845 			if (add_base_classification(domain, raw, tok) < 0) {
    846 				syslog(LOG_ERR, "unable to add base_classification on line %d", lineno);
    847 				return -1;
    848 			}
    849 		}
    850 		if (add_cache(domain, raw, tok) < 0)
    851 			return -1;
    852 	}
    853 	return 0;
    854 }
    855 
    856 int
    857 read_translations(const char *filename) {
    858 	size_t size = 0;
    859 	char *buffer = NULL;
    860 	int rval = 0;
    861 
    862 	FILE *cfg = fopen(filename,"r");
    863 	if (!cfg) {
    864 		syslog(LOG_ERR, "%s file open failed", filename);
    865 		return -1;
    866 	}
    867 
    868 	__fsetlocking(cfg, FSETLOCKING_BYCALLER);
    869 	while (getline(&buffer, &size, cfg) > 0) {
    870 		if( process_trans(buffer) < 0 ) {
    871 			syslog(LOG_ERR, "%s file read failed", filename);
    872 			rval = -1;
    873 			break;
    874 		}
    875 	}
    876 	free(buffer);
    877 	fclose(cfg);
    878 	return rval;
    879 }
    880 
    881 int
    882 init_translations(void) {
    883 	if (is_selinux_mls_enabled() <= 0)
    884 		return -1;
    885 
    886 	return(read_translations(selinux_translations_path()));
    887 }
    888 
    889 char *
    890 extract_range(const security_context_t incon) {
    891 	context_t con = context_new(incon);
    892 	if (!con) {
    893 		syslog(LOG_ERR, "extract_range context_new(%s) failed: %s", incon, strerror(errno));
    894 		return NULL;
    895 	}
    896 
    897 	const char *range = context_range_get(con);
    898 	if (!range) {
    899 		syslog(LOG_ERR, "extract_range: context_range_get(%s) failed: %m", incon);
    900 		context_free(con);
    901 		return NULL;
    902 	}
    903 	char *r = strdup(range);
    904 	if (!r) {
    905 		log_error("extract_range: allocation error %s", strerror(errno));
    906 		return NULL;
    907 	}
    908 	context_free(con);
    909 	return r;
    910 }
    911 
    912 char *
    913 new_context_str(const security_context_t incon, const char *range) {
    914 	char *rcon = NULL;
    915 	context_t con = context_new(incon);
    916 	if (!con) {
    917 		goto exit;
    918 	}
    919 	context_range_set(con, range);
    920 	rcon = strdup(context_str(con));
    921 	if (!rcon) {
    922 		goto exit;
    923 	}
    924 
    925 	return rcon;
    926 
    927 exit:
    928 	log_error("new_context_str: %s %s", incon, strerror(errno));
    929 	return NULL;
    930 }
    931 
    932 char *
    933 find_in_hashtable(const char *range, domain_t *domain, context_map_node_t **table) {
    934 	char *trans = NULL;
    935 	context_map_t *map = find_in_table(table, range);
    936 	if (map) {
    937 		trans = strdup((table == domain->raw_to_trans) ? map->trans: map->raw);
    938 		if (!trans) {
    939 			log_error("find_in_hashtable: allocation error %s", strerror(errno));
    940 			return NULL;
    941 		}
    942 		log_debug(" found %s in hashtable returning %s\n", range, trans);
    943 	}
    944 	return trans;
    945 }
    946 
    947 void
    948 emit_whitespace(char*buffer, char *whitespace) {
    949 	strcat(buffer, "[");
    950 	strcat(buffer, whitespace);
    951 	strcat(buffer, "]");
    952 }
    953 
    954 static int
    955 string_size(const void *p1, const void *p2) {
    956 	return strlen(*(char **)p2) - strlen(*(char **)p1);
    957 }
    958 
    959 static int
    960 word_size(const void *p1, const void *p2) {
    961 	word_t *w1 = *(word_t **)p1;
    962 	word_t *w2 = *(word_t **)p2;
    963 	int w1_len=strlen(w1->text);
    964 	int w2_len=strlen(w2->text);
    965 	if (w1_len == w2_len)
    966 		return strcmp(w1->text, w2->text);
    967 	return (w2_len - w1_len);
    968 }
    969 
    970 void
    971 build_regexp(pcre **r, char *buffer) {
    972 	const char *error;
    973 	int error_offset;
    974 	if (*r)
    975 		pcre_free(*r);
    976 	*r = pcre_compile(buffer, PCRE_CASELESS, &error, &error_offset, NULL);
    977 	if (error) {
    978 		log_error("pcre=%s, error=%s\n", buffer, error ? error: "none");
    979 	}
    980 	buffer[0] = '\0';
    981 }
    982 
    983 int
    984 build_regexps(domain_t *domain) {
    985 	char buffer[1024 * 128];
    986 	buffer[0] = '\0';
    987 	base_classification_t *bc;
    988 	word_group_t *g;
    989 	affix_t *a;
    990 	word_t *w;
    991 	size_t n_el, i;
    992 
    993 	for (n_el = 0, bc = domain->base_classifications; bc; bc = bc->next) {
    994 		n_el++;
    995 	}
    996 
    997 	char **sortable = calloc(n_el, sizeof(char *));
    998 	if (!sortable) {
    999 		log_error("allocation error %s", strerror(errno));
   1000 		return -1;
   1001 	}
   1002 
   1003 	for (i=0, bc = domain->base_classifications; bc; bc = bc->next) {
   1004 		sortable[i++] = bc->trans;
   1005 	}
   1006 
   1007 	qsort(sortable, n_el, sizeof(char *), string_size);
   1008 
   1009 	for (i = 0; i < n_el; i++) {
   1010 		strcat(buffer, sortable[i]);
   1011 		if (i < n_el) strcat(buffer,"|");
   1012 	}
   1013 
   1014 	free(sortable);
   1015 
   1016 	log_debug(">>> %s classification regexp=%s\n", domain->name, buffer);
   1017 	build_regexp(&domain->base_classification_regexp, buffer);
   1018 
   1019 	for (g = domain->groups; g; g = g->next) {
   1020 		if (g->prefixes) {
   1021 			strcat(buffer,"(?:");
   1022 			for (a = g->prefixes; a; a = a->next) {
   1023 				strcat(buffer, a->text);
   1024 				if (a->next) strcat(buffer,"|");
   1025 			}
   1026 			strcat(buffer,")");
   1027 			strcat(buffer,"[ 	]+");
   1028 			log_debug(">>> %s %s prefix regexp=%s\n", domain->name, g->name, buffer);
   1029 			build_regexp(&g->prefix_regexp, buffer);
   1030 		}
   1031 
   1032 		if (g->prefixes)
   1033 			strcat(buffer, "^");
   1034 		strcat(buffer, "(?:");
   1035 
   1036 		g->sword_len=0;
   1037 		for (w = g->words; w; w = w->next)
   1038 			g->sword_len++;
   1039 
   1040 		g->sword = calloc(g->sword_len, sizeof(word_t *));
   1041 		if (!g->sword) {
   1042 			log_error("allocation error %s", strerror(errno));
   1043 			return -1;
   1044 		}
   1045 
   1046 		i=0;
   1047 		for (w = g->words; w; w = w->next)
   1048 			g->sword[i++]=w;
   1049 
   1050 		qsort(g->sword, g->sword_len, sizeof(word_t *), word_size);
   1051 
   1052 		for (i=0; i < g->sword_len; i++) {
   1053 			if (i) strcat(buffer,"|");
   1054 			strcat(buffer,"\\b");
   1055 			strcat(buffer, g->sword[i]->text);
   1056 			strcat(buffer,"\\b");
   1057 		}
   1058 
   1059 		if (g->whitespace) {
   1060 			strcat(buffer,"|[");
   1061 			strcat(buffer, g->whitespace);
   1062 			strcat(buffer, "]+");
   1063 		}
   1064 
   1065 		strcat(buffer, ")+");
   1066 		if (g->suffixes)
   1067 			strcat(buffer, "$");
   1068 
   1069 		log_debug(">>> %s %s modifier regexp=%s\n", domain->name, g->name, buffer);
   1070 		build_regexp(&g->word_regexp, buffer);
   1071 		if (g->suffixes) {
   1072 			strcat(buffer,"[ 	]+");
   1073 			strcat(buffer,"(?:");
   1074 			for (a = g->suffixes; a; a = a->next) {
   1075 				strcat(buffer, a->text);
   1076 				if (a->next) strcat(buffer,"|");
   1077 			}
   1078 			strcat(buffer,")");
   1079 			log_debug(">>> %s %s suffix regexp=%s\n", domain->name, g->name, buffer);
   1080 			build_regexp(&g->suffix_regexp, buffer);
   1081 		}
   1082 	}
   1083 
   1084 	return 0;
   1085 }
   1086 
   1087 char *
   1088 compute_raw_from_trans(const char *level, domain_t *domain) {
   1089 
   1090 #ifdef DEBUG
   1091 	struct timeval startTime;
   1092 	gettimeofday(&startTime, 0);
   1093 #endif
   1094 
   1095 	int rc = 0;
   1096 	int ovector[OVECCOUNT];
   1097 	word_group_t *g = NULL;
   1098 	char *work = NULL;
   1099 	char *r = NULL;
   1100 	const char * match = NULL;
   1101 	int work_len;
   1102 	mls_level_t *mraw = NULL;
   1103 	ebitmap_t set, clear, tmp;
   1104 
   1105 	ebitmap_init(&set);
   1106 	ebitmap_init(&clear);
   1107 	ebitmap_init(&tmp);
   1108 
   1109 	work = strdup(level);
   1110 	if (!work) {
   1111 		log_error("compute_raw_from_trans: allocation error %s", strerror(errno));
   1112 		goto err;
   1113 	}
   1114 	work_len = strlen(work);
   1115 
   1116 	if (!domain->base_classification_regexp)
   1117 		if (build_regexps(domain) < 0)
   1118 			goto err;
   1119 	if (!domain->base_classification_regexp)
   1120 		goto err;
   1121 	log_debug(" compute_raw_from_trans work = %s\n", work);
   1122 	rc = pcre_exec(domain->base_classification_regexp, 0, work, work_len, 0, PCRE_ANCHORED, ovector, OVECCOUNT);
   1123 	if (rc > 0) {
   1124 		match = NULL;
   1125 		pcre_get_substring(work, ovector, rc, 0, &match);
   1126 		log_debug(" compute_raw_from_trans match = %s len = %u\n", match, strlen(match));
   1127 		base_classification_t *bc;
   1128 		for (bc = domain->base_classifications; bc; bc = bc->next) {
   1129 			if (!strcmp(bc->trans, match)) {
   1130 				log_debug(" compute_raw_from_trans base classification %s matched %s\n", level, bc->trans);
   1131 				mraw = malloc(sizeof(mls_level_t));
   1132 				if (!mraw) {
   1133 					log_error("allocation error %s", strerror(errno));
   1134 					goto err;
   1135 				}
   1136 				if (mls_level_cpy(mraw, bc->level) < 0)
   1137 					goto err;
   1138 				break;
   1139 			}
   1140 		}
   1141 
   1142 		memset(work + ovector[0], '#', ovector[1] - ovector[0]);
   1143 		char *p=work + ovector[0] + ovector[1];
   1144 		while (*p && (strchr(" 	", *p) != NULL))
   1145 			*p++ = '#';
   1146 		pcre_free((char *)match);
   1147 		match = NULL;
   1148 	} else {
   1149 		log_debug(" compute_raw_from_trans no base classification matched %s\n", level);
   1150 	}
   1151 
   1152 	if (mraw == NULL) {
   1153 		goto err;
   1154 	}
   1155 
   1156 	int complete = 0;
   1157 	int change = 1;
   1158 	while(change && !complete) {
   1159 		change = 0;
   1160 		for (g = domain->groups; g && !change && !complete; g = g->next) {
   1161 			int prefix = 0, suffix = 0;
   1162 			int prefix_offset = 0, prefix_len = 0;
   1163 			int suffix_offset = 0, suffix_len = 0;
   1164 			if (g->prefix_regexp) {
   1165 				rc = pcre_exec(g->prefix_regexp, 0, work, work_len, 0, 0, ovector, OVECCOUNT);
   1166 				if (rc > 0) {
   1167 					prefix = 1;
   1168 					prefix_offset = ovector[0];
   1169 					prefix_len = ovector[1] - ovector[0];
   1170 				}
   1171 			}
   1172 			if (g->suffix_regexp) {
   1173 				rc = pcre_exec(g->suffix_regexp, 0, work, work_len, 0, 0, ovector, OVECCOUNT);
   1174 				if (rc > 0) {
   1175 					suffix = 1;
   1176 					suffix_offset = ovector[0];
   1177 					suffix_len = ovector[1] - ovector[0];
   1178 				}
   1179 			}
   1180 
   1181 /* anchors prefix ^, suffix $ */
   1182 			if (((!g->prefixes && !g->suffixes) ||
   1183 			     (g->prefixes && prefix) ||
   1184 			     (g->suffixes && suffix)) &&
   1185 			     g->word_regexp) {
   1186 				char *s = work + prefix_offset + prefix_len;
   1187 				int l = (suffix_len ? suffix_offset : work_len) - prefix_len - prefix_offset;
   1188 				rc = pcre_exec(g->word_regexp, 0, s, l, 0, 0, ovector, OVECCOUNT);
   1189 				if (rc > 0) {
   1190 					match = NULL;
   1191 					pcre_get_substring(s, ovector, rc, 0, &match);
   1192 					trim((char *)match, g->whitespace);
   1193 					if (*match) {
   1194 						char *p = triml((char *)match, g->whitespace);
   1195 						while (p && *p) {
   1196 							int plen = strlen(p);
   1197 							unsigned int i;
   1198 							for (i = 0; i < g->sword_len; i++) {
   1199 								word_t *w = g->sword[i];
   1200 								int wlen = strlen(w->text);
   1201 								if (plen >= wlen && !strncmp(w->text, p, strlen(w->text))){
   1202 									if (ebitmap_andnot(&set, &w->cat, &g->def, maxbit) < 0) goto err;
   1203 
   1204 									if (ebitmap_xor(&tmp, &w->cat, &g->def) < 0) goto err;
   1205 									if (ebitmap_and(&clear, &tmp, &g->def) < 0) goto err;
   1206 									if (ebitmap_union(&mraw->cat, &set) < 0) goto err;
   1207 
   1208 									ebitmap_destroy(&tmp);
   1209 									if (ebitmap_cpy(&tmp, &mraw->cat) < 0) goto err;
   1210 									ebitmap_destroy(&mraw->cat);
   1211 									if (ebitmap_andnot(&mraw->cat, &tmp, &clear, maxbit) < 0) goto err;
   1212 
   1213 									ebitmap_destroy(&tmp);
   1214 									ebitmap_destroy(&set);
   1215 									ebitmap_destroy(&clear);
   1216 									p += strlen(w->text);
   1217 									change++;
   1218 									break;
   1219 								}
   1220 							}
   1221 							if (i == g->sword_len) {
   1222 								syslog(LOG_ERR, "conversion error");
   1223 								break;
   1224 							}
   1225 							p = triml(p, g->whitespace);
   1226 						}
   1227 						memset(work + prefix_offset, '#', prefix_len);
   1228 						memset(work + suffix_offset, '#', suffix_len);
   1229 						memset(s + ovector[0], '#', ovector[1] - ovector[0]);
   1230 					}
   1231 					pcre_free((void *)match);
   1232 					match = NULL;
   1233 				}
   1234 			}
   1235 /* YYY */
   1236 			complete=1;
   1237 			char *p = work;
   1238 			while(*p) {
   1239 				if (isalnum(*p++)) {
   1240 					complete=0;
   1241 					break;
   1242 				}
   1243 			}
   1244 		}
   1245 	}
   1246 	free(work);
   1247 	if (violates_constraints(mraw)) {
   1248 		complete = 0;
   1249 	}
   1250 	if (complete)
   1251 		r = mls_level_to_string(mraw);
   1252 	mls_level_destroy(mraw);
   1253 	free(mraw);
   1254 
   1255 #ifdef DEBUG
   1256 	struct timeval stopTime;
   1257 	gettimeofday(&stopTime, 0);
   1258 	long int ms;
   1259 	if (startTime.tv_usec > stopTime.tv_usec)
   1260 		ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
   1261 	else
   1262 		ms = (stopTime.tv_sec - startTime.tv_sec    ) * 1000 + (stopTime.tv_usec/1000        - startTime.tv_usec/1000);
   1263 	log_debug(" compute_raw_from_trans in %ld ms'\n", ms);
   1264 #endif
   1265 
   1266 	return r;
   1267 
   1268 err:
   1269 	mls_level_destroy(mraw);
   1270 	free(mraw);
   1271 	free(work);
   1272 	pcre_free((void *)match);
   1273 	ebitmap_destroy(&tmp);
   1274 	ebitmap_destroy(&set);
   1275 	ebitmap_destroy(&clear);
   1276 	return NULL;
   1277 }
   1278 
   1279 char *
   1280 compute_trans_from_raw(const char *level, domain_t *domain) {
   1281 
   1282 #ifdef DEBUG
   1283 	struct timeval startTime;
   1284 	gettimeofday(&startTime, 0);
   1285 #endif
   1286 
   1287 	word_group_t *g;
   1288 	mls_level_t *l = NULL;
   1289 	char *rval = NULL;
   1290 	word_group_t *groups = NULL;
   1291 	ebitmap_t bit_diff, temp, handled, nothandled, unhandled, orig_unhandled;
   1292 
   1293 	ebitmap_init(&bit_diff);
   1294 	ebitmap_init(&temp);
   1295 	ebitmap_init(&handled);
   1296 	ebitmap_init(&nothandled);
   1297 	ebitmap_init(&unhandled);
   1298 	ebitmap_init(&orig_unhandled);
   1299 
   1300 	if (!level)
   1301 		goto err;
   1302 
   1303 	l = parse_raw(level);
   1304 	if (!l)
   1305 		goto err;
   1306 	log_debug(" compute_trans_from_raw raw = %s\n", level);
   1307 
   1308 /* YYY */
   1309 	/* check constraints */
   1310 	if (violates_constraints(l)) {
   1311 		syslog(LOG_ERR, "%s violates constraints", level);
   1312 		goto err;
   1313 	}
   1314 
   1315 	int doInverse = l->sens > 0;
   1316 
   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 			if (ebitmap_xor(&unhandled, &l->cat, &bc->level->cat) < 0)
   1329 				goto err;
   1330 			if (ebitmap_cpy(&orig_unhandled, &unhandled) < 0)
   1331 				goto err;
   1332 
   1333 			/* prebuild groups */
   1334 			for (g = domain->groups; g; g = g->next) {
   1335 				word_group_t **t;
   1336 				for (t = &groups; *t; t = &(*t)->next)
   1337 					if (!strcmp(g->name, (*t)->name))
   1338 						break;
   1339 
   1340 				if (! *t) {
   1341 					word_group_t *wg = create_group(&groups, g->name);
   1342 					if (g->prefixes)
   1343 						if (append(&wg->prefixes, g->prefixes->text) < 0)
   1344 							goto err;
   1345 					if (g->suffixes)
   1346 						if (append(&wg->suffixes, g->suffixes->text) < 0)
   1347 							goto err;
   1348 					if (g->join)
   1349 						if (update(&wg->join, g->join) < 0)
   1350 							goto err;
   1351 				}
   1352 			}
   1353 
   1354 			int loops, hamming, change=1;
   1355 			for (loops = 50; ebitmap_cardinality(&unhandled) && loops > 0 && change; loops--) {
   1356 				change = 0;
   1357 				hamming = 10000;
   1358 				if (ebitmap_xor(&handled, &unhandled, &orig_unhandled) < 0)
   1359 					goto err;
   1360 				if (ebitmap_not(&nothandled, &handled, maxbit) < 0)
   1361 					goto err;
   1362 				word_group_t *currentGroup = NULL;
   1363 				word_t *currentWord = NULL;
   1364 				for (g = domain->groups; g && hamming; g = g->next) {
   1365 					word_t *w;
   1366 					for (w = g->words; w && hamming; w = w->next) {
   1367 						int cardinality = ebitmap_cardinality(&w->normal);
   1368 						/* If the word is all inverse bits and the level does not have inverse bits - skip */
   1369 						if (cardinality && !doInverse) {
   1370 							continue;
   1371 						}
   1372 
   1373 						/* if only unhandled bits are different */
   1374 						if (ebitmap_or(&temp, &w->normal, &w->inverse) < 0)
   1375 							goto err;
   1376 						if (ebitmap_and(&bit_diff, &temp, &nothandled) < 0)
   1377 							goto err;
   1378 						ebitmap_destroy(&temp);
   1379 // xor bit_diff handled?
   1380 						if (ebitmap_and(&temp, &bit_diff, &unhandled) < 0)
   1381 							goto err;
   1382 						if (ebitmap_cmp(&bit_diff, &temp)) {
   1383 							int h = ebitmap_hamming_distance(&bit_diff, &unhandled);
   1384 							if (h < hamming) {
   1385 								hamming = h;
   1386 								currentGroup = g;
   1387 								currentWord = w;
   1388 							}
   1389 						}
   1390 						ebitmap_destroy(&bit_diff);
   1391 						ebitmap_destroy(&temp);
   1392 					}
   1393 				}
   1394 				ebitmap_destroy(&handled);
   1395 				ebitmap_destroy(&nothandled);
   1396 
   1397 				if (currentWord) {
   1398 					if (ebitmap_xor(&bit_diff, &currentWord->cat, &bc->level->cat) < 0)
   1399 						goto err;
   1400 
   1401 					if (ebitmap_cpy(&temp, &unhandled) < 0)
   1402 						goto err;
   1403 					ebitmap_destroy(&unhandled);
   1404 					if (ebitmap_andnot(&unhandled, &temp, &bit_diff, maxbit) < 0)
   1405 						goto err;
   1406 
   1407 					ebitmap_destroy(&bit_diff);
   1408 					ebitmap_destroy(&temp);
   1409 
   1410 					word_group_t **t;
   1411 					for (t = &groups; *t; t = &(*t)->next)
   1412 						if (!strcmp(currentGroup->name, (*t)->name))
   1413 							break;
   1414 					create_word(&(*t)->words, currentWord->text);
   1415 					change++;
   1416 				}
   1417 			}
   1418 
   1419 			done = (ebitmap_cardinality(&unhandled) == 0);
   1420 			ebitmap_destroy(&unhandled);
   1421 			ebitmap_destroy(&orig_unhandled);
   1422 			if (done) {
   1423 				char buffer[9999];
   1424 				buffer[0] = 0;
   1425 				strcat(buffer, bc->trans);
   1426 				strcat(buffer, " ");
   1427 				for (g=groups; g; g = g->next) {
   1428 					if (g->words && g->prefixes) {
   1429 						strcat(buffer, g->prefixes->text);
   1430 						strcat(buffer, " ");
   1431 					}
   1432 					word_t *w;
   1433 					for (w=g->words; w; w = w->next) {
   1434 						strcat(buffer, w->text);
   1435 						if (w->next)
   1436 							strcat(buffer, g->join);
   1437 					}
   1438 					if (g->words && g->suffixes) {
   1439 						strcat(buffer, " ");
   1440 						strcat(buffer, g->suffixes->text);
   1441 					}
   1442 					word_group_t *n = g->next;
   1443 					while(g->words && n) {
   1444 						if (n->words) {
   1445 							strcat(buffer, " ");
   1446 							break;
   1447 						}
   1448 						n = n->next;
   1449 					}
   1450 				}
   1451 				rval = strdup(buffer);
   1452 				if (!rval) {
   1453 					log_error("compute_trans_from_raw: allocation error %s", strerror(errno));
   1454 					goto err;
   1455 				}
   1456 			}
   1457 			/* clean up */
   1458 			while (groups)
   1459 				destroy_group(&groups, groups);
   1460 		}
   1461 		last = bc;
   1462 	}
   1463 	if (l) {
   1464 		mls_level_destroy(l);
   1465 		free(l);
   1466 	}
   1467 
   1468 #ifdef DEBUG
   1469 	struct timeval stopTime;
   1470 	gettimeofday(&stopTime, 0);
   1471 	long int ms;
   1472 	if (startTime.tv_usec > stopTime.tv_usec)
   1473 		ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
   1474 	else
   1475 		ms = (stopTime.tv_sec - startTime.tv_sec    ) * 1000 + (stopTime.tv_usec/1000        - startTime.tv_usec/1000);
   1476 
   1477 	log_debug(" compute_trans_from_raw in %ld ms'\n", ms);
   1478 #endif
   1479 
   1480 	return rval;
   1481 
   1482 err:
   1483 	while (groups)
   1484 		destroy_group(&groups, groups);
   1485 	mls_level_destroy(l);
   1486 	free(l);
   1487 	return NULL;
   1488 }
   1489 
   1490 int
   1491 trans_context(const security_context_t incon, security_context_t *rcon) {
   1492 	char *trans = NULL;
   1493 	*rcon = NULL;
   1494 
   1495 #ifdef DEBUG
   1496 	struct timeval startTime;
   1497 	gettimeofday(&startTime, 0);
   1498 #endif
   1499 
   1500 	log_debug(" trans_context input = %s\n", incon);
   1501 	char *range = extract_range(incon);
   1502 	if (!range) return -1;
   1503 
   1504 	domain_t *domain = domains;
   1505 	for (;domain; domain = domain->next) {
   1506 		trans = find_in_hashtable(range, domain, domain->raw_to_trans);
   1507 		if (trans) break;
   1508 
   1509 		/* try split and translate */
   1510 		char *lrange = NULL, *urange = NULL;
   1511 		char *ltrans = NULL, *utrans = NULL;
   1512 		char *dashp = strchr(range,'-');
   1513 		if (dashp) {
   1514 			*dashp = 0;
   1515 			lrange = range;
   1516 			urange = dashp+1;
   1517 		} else {
   1518 			trans = compute_trans_from_raw(range, domain);
   1519 			if (trans)
   1520 				if (add_cache(domain, range, trans) < 0)
   1521 					return -1;
   1522 		}
   1523 
   1524 		if (lrange && urange) {
   1525 			ltrans = find_in_hashtable(lrange, domain, domain->raw_to_trans);
   1526 			if (! ltrans) {
   1527 				ltrans = compute_trans_from_raw(lrange, domain);
   1528 				if (ltrans) {
   1529 					if (add_cache(domain, lrange, ltrans) < 0)
   1530 						return -1;
   1531 				} else {
   1532 					ltrans = strdup(lrange);
   1533 					if (! ltrans) {
   1534 						log_error("strdup failed %s", strerror(errno));
   1535 						return -1;
   1536 					}
   1537 				}
   1538 			}
   1539 
   1540 			utrans = find_in_hashtable(urange, domain, domain->raw_to_trans);
   1541 			if (! utrans) {
   1542 				utrans = compute_trans_from_raw(urange, domain);
   1543 				if (utrans) {
   1544 					if (add_cache(domain, urange, utrans) < 0)
   1545 						return -1;
   1546 				} else {
   1547 					utrans = strdup(urange);
   1548 					if (! utrans) {
   1549 						log_error("strdup failed %s", strerror(errno));
   1550  						return -1;
   1551  					}
   1552  				}
   1553 			}
   1554 
   1555 			if (strcmp(ltrans, utrans) == 0) {
   1556 				if (asprintf(&trans, "%s", ltrans) < 0) {
   1557 					log_error("asprintf failed %s", strerror(errno));
   1558 					return -1;
   1559 				}
   1560 			} else {
   1561 				if (asprintf(&trans, "%s-%s", ltrans, utrans) < 0) {
   1562 					log_error("asprintf failed %s", strerror(errno));
   1563 					return -1;
   1564 				}
   1565 			}
   1566 			free(ltrans);
   1567 			free(utrans);
   1568 			*dashp = '-';
   1569 			break;
   1570 		}
   1571 		if (dashp)
   1572 			*dashp = '-';
   1573 	}
   1574 
   1575 	if (trans) {
   1576 		*rcon = new_context_str(incon, trans);
   1577 		free(trans);
   1578 	} else {
   1579 		*rcon = new_context_str(incon, range);
   1580 	}
   1581 	free(range);
   1582 
   1583 #ifdef DEBUG
   1584 	struct timeval stopTime;
   1585 	gettimeofday(&stopTime, 0);
   1586 	long int ms;
   1587 	if (startTime.tv_usec > stopTime.tv_usec)
   1588 		ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
   1589 	else
   1590 		ms = (stopTime.tv_sec - startTime.tv_sec    ) * 1000 + (stopTime.tv_usec/1000        - startTime.tv_usec/1000);
   1591 
   1592 	log_debug(" trans_context input='%s' output='%s in %ld ms'\n", incon, *rcon, ms);
   1593 #endif
   1594 	return 0;
   1595 }
   1596 
   1597 int
   1598 untrans_context(const security_context_t incon, security_context_t *rcon) {
   1599 	char *raw = NULL;
   1600 	*rcon = NULL;
   1601 
   1602 #ifdef DEBUG
   1603 	struct timeval startTime;
   1604 	gettimeofday(&startTime, 0);
   1605 #endif
   1606 
   1607 	log_debug(" untrans_context incon = %s\n", incon);
   1608 	char *range = extract_range(incon);
   1609 	if (!range) return -1;
   1610 	log_debug(" untrans_context range = %s\n", range);
   1611 
   1612 	domain_t *domain = domains;
   1613 	for (;domain; domain = domain->next) {
   1614 		raw = find_in_hashtable(range, domain, domain->trans_to_raw);
   1615 		if (raw) break;
   1616 
   1617 		/* try split and translate */
   1618 		char *lrange = NULL, *urange = NULL;
   1619 		char *lraw = NULL, *uraw = NULL;
   1620 		char *dashp = strchr(range,'-');
   1621 		if (dashp) {
   1622 			*dashp = 0;
   1623 			lrange = range;
   1624 			urange = dashp+1;
   1625 		} else {
   1626 			raw = compute_raw_from_trans(range, domain);
   1627 			if (raw) {
   1628 				char *canonical = find_in_hashtable(raw, domain, domain->raw_to_trans);
   1629 				if (!canonical) {
   1630 					canonical = compute_trans_from_raw(raw, domain);
   1631 					if (canonical && strcmp(canonical, range))
   1632 						if (add_cache(domain, raw, canonical) < 0)
   1633 							return -1;
   1634 				}
   1635 				if (canonical)
   1636 					free(canonical);
   1637 				if (add_cache(domain, raw, range) < 0)
   1638 					return -1;
   1639 			} else {
   1640 				log_debug("untrans_context unable to compute raw context %s\n", range);
   1641 			}
   1642 		}
   1643 
   1644 		if (lrange && urange) {
   1645 			lraw = find_in_hashtable(lrange, domain, domain->trans_to_raw);
   1646 			if (! lraw) {
   1647 				lraw = compute_raw_from_trans(lrange, domain);
   1648 				if (lraw) {
   1649 					char *canonical = find_in_hashtable(lraw, domain, domain->raw_to_trans);
   1650 					if (!canonical) {
   1651 						canonical = compute_trans_from_raw(lraw, domain);
   1652 						if (canonical)
   1653 							if (add_cache(domain, lraw, canonical) < 0)
   1654 								return -1;
   1655 					}
   1656 					if (canonical)
   1657 						free(canonical);
   1658 					if (add_cache(domain, lraw, lrange) < 0)
   1659 						return -1;
   1660 				} else {
   1661 					lraw = strdup(lrange);
   1662 					if (! lraw) {
   1663 						log_error("strdup failed %s", strerror(errno));
   1664 						return -1;
   1665 					}
   1666 				}
   1667 			}
   1668 
   1669 			uraw = find_in_hashtable(urange, domain, domain->trans_to_raw);
   1670 			if (! uraw) {
   1671 				uraw = compute_raw_from_trans(urange, domain);
   1672 				if (uraw) {
   1673 					char *canonical = find_in_hashtable(uraw, domain, domain->raw_to_trans);
   1674 					if (!canonical) {
   1675 						canonical = compute_trans_from_raw(uraw, domain);
   1676 						if (canonical)
   1677 							if (add_cache(domain, uraw, canonical) < 0)
   1678 								return -1;
   1679 							}
   1680 					if (canonical)
   1681 						free(canonical);
   1682 					if (add_cache(domain, uraw, urange) < 0)
   1683 						return -1;
   1684 				} else {
   1685 					uraw = strdup(urange);
   1686 					if (! uraw) {
   1687 						log_error("strdup failed %s", strerror(errno));
   1688 						return -1;
   1689 					}
   1690 				}
   1691 			}
   1692 
   1693 
   1694 			if (strcmp(lraw, uraw) == 0) {
   1695 				if (asprintf(&raw, "%s", lraw) < 0) {
   1696 					log_error("asprintf failed %s", strerror(errno));
   1697 					return -1;
   1698 				}
   1699 			} else {
   1700 				if (asprintf(&raw, "%s-%s", lraw, uraw) < 0) {
   1701 					log_error("asprintf failed %s", strerror(errno));
   1702 					return -1;
   1703 				}
   1704 			}
   1705 			free(lraw);
   1706 			free(uraw);
   1707 			*dashp = '-';
   1708 			break;
   1709 		}
   1710 		if (dashp)
   1711 			*dashp = '-';
   1712 	}
   1713 
   1714 	if (raw) {
   1715 		*rcon = new_context_str(incon, raw);
   1716 		free(raw);
   1717 	} else {
   1718 		*rcon = new_context_str(incon, range);
   1719 	}
   1720 	free(range);
   1721 
   1722 #ifdef DEBUG
   1723 	struct timeval stopTime;
   1724 	gettimeofday(&stopTime, 0);
   1725 	long int ms;
   1726 	if (startTime.tv_usec > stopTime.tv_usec)
   1727 		ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
   1728 	else
   1729 		ms = (stopTime.tv_sec - startTime.tv_sec    ) * 1000 + (stopTime.tv_usec/1000        - startTime.tv_usec/1000);
   1730 
   1731 	log_debug(" untrans_context input='%s' output='%s' n %ld ms\n", incon, *rcon, ms);
   1732 #endif
   1733 	return 0;
   1734 }
   1735 
   1736 void
   1737 finish_context_translations(void) {
   1738 	while(domains) {
   1739 		domain_t *next = domains->next;
   1740 		destroy_domain(domains);
   1741 		domains = next;
   1742 	}
   1743 	while(sens_constraints) {
   1744 		sens_constraint_t *next = sens_constraints->next;
   1745 		destroy_sens_constraint(&sens_constraints, sens_constraints);
   1746 		sens_constraints = next;
   1747 	}
   1748 	while(cat_constraints) {
   1749 		cat_constraint_t *next = cat_constraints->next;
   1750 		destroy_cat_constraint(&cat_constraints, cat_constraints);
   1751 		cat_constraints = next;
   1752 	}
   1753 }
   1754 
   1755