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