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
49static unsigned int maxbit=0;
50
51/* Define data structures */
52typedef struct context_map {
53	char *raw;
54	char *trans;
55} context_map_t;
56
57typedef struct context_map_node {
58	char *key;
59	context_map_t *map;
60	struct context_map_node *next;
61} context_map_node_t;
62
63typedef struct affix {
64	char *text;
65	struct affix *next;
66} affix_t;
67
68typedef 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
76typedef 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
97typedef struct base_classification {
98	char *trans;
99	mls_level_t *level;
100	struct base_classification *next;
101} base_classification_t;
102
103typedef 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
116static domain_t *domains;
117
118typedef 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
126static sens_constraint_t *sens_constraints;
127
128typedef 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
137static cat_constraint_t *cat_constraints;
138
139unsigned int
140hash(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
150static int
151add_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;
163err:
164	syslog(LOG_ERR, "add_to_hashtable: allocation error");
165	return -1;
166}
167
168static int
169numdigits(unsigned int n)
170{
171	int count = 1;
172	while ((n = n / 10))
173		count++;
174	return count;
175}
176
177static int
178parse_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
216int
217parse_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
227mls_level_t *
228parse_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
245err:
246	ebitmap_destroy(&mls->cat);
247	free(mls);
248	return NULL;
249}
250
251void
252destroy_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
270word_t *
271create_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
288err:
289	log_error("create_word: allocation error %s", strerror(errno));
290	destroy_word(NULL, w);
291	return NULL;
292}
293
294void
295destroy_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
327word_group_t *
328create_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
354err:
355	log_error("allocation error %s", strerror(errno));
356	destroy_group(NULL, group);
357	return NULL;
358}
359
360void
361destroy_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
404domain_t *
405create_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
422err:
423	log_error("allocation error %s", strerror(errno));
424	destroy_domain(domain);
425	return NULL;
426}
427
428int
429add_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
454int
455add_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
524int
525violates_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
568void
569destroy_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
585void
586destroy_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
604static int
605add_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
631static int
632add_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;
653err:
654	log_error("%s: allocation error", "add_cache");
655	return -1;
656}
657
658static context_map_t *
659find_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
668char *
669trim(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
677char *
678triml(char *str, const char *whitespace) {
679	char *p = str;
680
681	while (*p && (strchr(whitespace, *p) != NULL))
682		p++;
683	return p;
684}
685
686int
687update(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
697int
698append(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
711err:
712	log_error("allocation error %s", strerror(errno));
713	return -1;
714}
715
716static 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 */
722static int
723process_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
858int
859read_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
883int
884init_translations(void) {
885	if (is_selinux_mls_enabled() <= 0)
886		return -1;
887
888	return(read_translations(selinux_translations_path()));
889}
890
891char *
892extract_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
914char *
915new_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
929exit:
930	log_error("new_context_str: %s %s", incon, strerror(errno));
931	return NULL;
932}
933
934char *
935find_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
949void
950emit_whitespace(char*buffer, char *whitespace) {
951	strcat(buffer, "[");
952	strcat(buffer, whitespace);
953	strcat(buffer, "]");
954}
955
956static int
957string_size(const void *p1, const void *p2) {
958	return strlen(*(char **)p2) - strlen(*(char **)p1);
959}
960
961static int
962word_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
972void
973build_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
985int
986build_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
1089char *
1090compute_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
1269err:
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
1280char *
1281compute_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
1490err:
1491	while (groups)
1492		destroy_group(&groups, groups);
1493	mls_level_destroy(l);
1494	free(l);
1495	return NULL;
1496}
1497
1498int
1499trans_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
1605int
1606untrans_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
1744void
1745finish_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