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 	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 	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
    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
    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
    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
    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 *
    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 *
    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 *
    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
    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
    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
    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
    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
    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 *
    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 *
    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 *
    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
    950 emit_whitespace(char*buffer, char *whitespace) {
    951 	strcat(buffer, "[");
    952 	strcat(buffer, whitespace);
    953 	strcat(buffer, "]");
    954 }
    955 
    956 static int
    957 string_size(const void *p1, const void *p2) {
    958 	return strlen(*(char **)p2) - strlen(*(char **)p1);
    959 }
    960 
    961 static int
    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
    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
    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 *
   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 *
   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(&nothandled);
   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(&nothandled, &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, &nothandled) < 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(&nothandled);
   1401 
   1402 				if (currentWord) {
   1403 					ebitmap_t bit_diff;
   1404 					if (ebitmap_xor(&bit_diff, &currentWord->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
   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
   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
   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