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