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