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