1 2 /* Copyright (c) 2008-2009 Nall Design Works 3 Copyright 2006 Trusted Computer Solutions, Inc. */ 4 5 /* 6 Exported Interface 7 8 int init_translations(void); 9 void finish_context_translations(void); 10 int trans_context(const security_context_t, security_context_t *); 11 int untrans_context(const security_context_t, security_context_t *); 12 13 */ 14 15 #include <math.h> 16 #include <glob.h> 17 #include <values.h> 18 #include <unistd.h> 19 #include <fcntl.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <stdio.h> 23 #include <stdio_ext.h> 24 #include <ctype.h> 25 #include <selinux/selinux.h> 26 #include <selinux/context.h> 27 #include <syslog.h> 28 #include <errno.h> 29 #include <pcre.h> 30 #include <ctype.h> 31 #include <time.h> 32 #include <sys/time.h> 33 34 35 #include "mls_level.h" 36 #include "mcstrans.h" 37 38 #define N_BUCKETS 1453 39 #define OVECCOUNT (512*3) 40 41 #define log_error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) 42 43 #ifdef DEBUG 44 #define log_debug(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) 45 #else 46 #define log_debug(fmt, ...) ; 47 #endif 48 49 static unsigned int maxbit=0; 50 51 /* Define data structures */ 52 typedef struct context_map { 53 char *raw; 54 char *trans; 55 } context_map_t; 56 57 typedef struct context_map_node { 58 char *key; 59 context_map_t *map; 60 struct context_map_node *next; 61 } context_map_node_t; 62 63 typedef struct affix { 64 char *text; 65 struct affix *next; 66 } affix_t; 67 68 typedef struct word { 69 char *text; 70 ebitmap_t cat; 71 ebitmap_t normal; 72 ebitmap_t inverse; 73 struct word *next; 74 } word_t; 75 76 typedef struct word_group { 77 char *name; 78 char *whitespace; 79 char *join; 80 81 affix_t *prefixes; 82 affix_t *suffixes; 83 word_t *words; 84 85 pcre *prefix_regexp; 86 pcre *word_regexp; 87 pcre *suffix_regexp; 88 89 ebitmap_t def; 90 91 word_t **sword; 92 unsigned int sword_len; 93 94 struct word_group *next; 95 } word_group_t; 96 97 typedef struct base_classification { 98 char *trans; 99 mls_level_t *level; 100 struct base_classification *next; 101 } base_classification_t; 102 103 typedef struct domain { 104 char *name; 105 106 context_map_node_t *raw_to_trans[N_BUCKETS]; 107 context_map_node_t *trans_to_raw[N_BUCKETS]; 108 109 base_classification_t *base_classifications; 110 word_group_t *groups; 111 112 pcre *base_classification_regexp; 113 struct domain *next; 114 } domain_t; 115 116 static domain_t *domains; 117 118 typedef struct sens_constraint { 119 char op; 120 char *text; 121 unsigned int sens; 122 ebitmap_t cat; 123 struct sens_constraint *next; 124 } sens_constraint_t; 125 126 static sens_constraint_t *sens_constraints; 127 128 typedef struct cat_constraint { 129 char op; 130 char *text; 131 int nbits; 132 ebitmap_t mask; 133 ebitmap_t cat; 134 struct cat_constraint *next; 135 } cat_constraint_t; 136 137 static cat_constraint_t *cat_constraints; 138 139 unsigned int 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 ebitmap_t common; 529 for (s=sens_constraints; s; s=s->next) { 530 if (s->sens == l->sens) { 531 if (ebitmap_and(&common, &s->cat, &l->cat) < 0) 532 return 1; 533 nbits = ebitmap_cardinality(&common); 534 ebitmap_destroy(&common); 535 if (nbits) { 536 char *text = mls_level_to_string(l); 537 syslog(LOG_WARNING, "%s violates %s", text, s->text); 538 free(text); 539 return 1; 540 } 541 } 542 } 543 cat_constraint_t *c; 544 for (c=cat_constraints; c; c=c->next) { 545 if (ebitmap_and(&common, &c->mask, &l->cat) < 0) 546 return 1; 547 nbits = ebitmap_cardinality(&common); 548 ebitmap_destroy(&common); 549 if (nbits > 0) { 550 if (ebitmap_and(&common, &c->cat, &l->cat) < 0) 551 return 1; 552 nbits = ebitmap_cardinality(&common); 553 ebitmap_destroy(&common); 554 if ((c->op == '!' && nbits) || 555 (c->op == '>' && nbits != c->nbits)) { 556 char *text = mls_level_to_string(l); 557 syslog(LOG_WARNING, "%s violates %s (%d,%d)", text, c->text, nbits, c->nbits); 558 free(text); 559 return 1; 560 } 561 } 562 } 563 return 0; 564 } 565 566 void 567 destroy_sens_constraint(sens_constraint_t **list, sens_constraint_t *constraint) { 568 if (!constraint) { 569 return; 570 } 571 for (; list && *list; list = &(*list)->next) { 572 if (*list == constraint) { 573 *list = constraint->next; 574 break; 575 } 576 } 577 ebitmap_destroy(&constraint->cat); 578 free(constraint->text); 579 memset(constraint, 0, sizeof(sens_constraint_t)); 580 free(constraint); 581 } 582 583 void 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 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 630 add_cache(domain_t *domain, char *raw, char *trans) { 631 context_map_t *map = calloc(1, sizeof(context_map_t)); 632 if (!map) goto err; 633 634 map->raw = strdup(raw); 635 if (!map->raw) { 636 goto err; 637 } 638 map->trans = strdup(trans); 639 if (!map->trans) { 640 goto err; 641 } 642 643 log_debug(" add_cache (%s,%s)\n", raw, trans); 644 if (add_to_hashtable(domain->raw_to_trans, map->raw, map) < 0) 645 goto err; 646 647 if (add_to_hashtable(domain->trans_to_raw, map->trans, map) < 0) 648 goto err; 649 650 return 0; 651 err: 652 log_error("%s: allocation error", "add_cache"); 653 return -1; 654 } 655 656 static context_map_t * 657 find_in_table(context_map_node_t **table, const char *key) { 658 unsigned int bucket = hash(key) % N_BUCKETS; 659 context_map_node_t **n; 660 for (n = &table[bucket]; *n; n = &(*n)->next) 661 if (!strcmp((*n)->key, key)) 662 return (*n)->map; 663 return NULL; 664 } 665 666 char * 667 trim(char *str, const char *whitespace) { 668 char *p = str + strlen(str); 669 670 while (p > str && strchr(whitespace, *(p-1)) != NULL) 671 *--p = 0; 672 return str; 673 } 674 675 char * 676 triml(char *str, const char *whitespace) { 677 char *p = str; 678 679 while (*p && (strchr(whitespace, *p) != NULL)) 680 p++; 681 return p; 682 } 683 684 int 685 update(char **p, char *const val) { 686 free (*p); 687 *p = strdup(val); 688 if (!*p) { 689 log_error("allocation error %s", strerror(errno)); 690 return -1; 691 } 692 return 0; 693 } 694 695 int 696 append(affix_t **affixes, const char *val) { 697 affix_t *affix = calloc(1, sizeof(affix_t)); 698 if (!affix) { 699 goto err; 700 } 701 affix->text = strdup(val); 702 if (!affix->text) 703 goto err; 704 for (;*affixes; affixes = &(*affixes)->next) 705 ; 706 *affixes = affix; 707 return 0; 708 709 err: 710 log_error("allocation error %s", strerror(errno)); 711 return -1; 712 } 713 714 static int read_translations(const char *filename); 715 716 /* Process line from translation file. 717 Remove white space and set raw do data before the "=" and tok to data after it 718 Modifies the data pointed to by the buffer parameter 719 */ 720 static int 721 process_trans(char *buffer) { 722 static domain_t *domain; 723 static word_group_t *group; 724 static int base_classification; 725 static int lineno = 0; 726 char op='\0'; 727 728 lineno++; 729 log_debug("%d: %s", lineno, buffer); 730 731 /* zap leading whitespace */ 732 buffer = triml(buffer, "\t "); 733 734 /* Ignore comments */ 735 if (*buffer == '#') return 0; 736 char *comment = strpbrk (buffer, "#"); 737 if (comment) { 738 *comment = '\0'; 739 } 740 741 /* zap trailing whitespace */ 742 buffer = trim(buffer, "\t \r\n"); 743 744 if (*buffer == 0) return 0; 745 746 char *delim = strpbrk (buffer, "=!>"); 747 if (! delim) { 748 syslog(LOG_ERR, "invalid line (no !, = or >) %d", lineno); 749 return -1; 750 } 751 752 op = *delim; 753 *delim = '\0'; 754 char *raw = buffer; 755 char *tok = delim+1; 756 757 /* remove trailing/leading whitespace from the split tokens */ 758 trim(raw, "\t "); 759 tok = triml(tok, "\t "); 760 761 if (! *raw) { 762 syslog(LOG_ERR, "invalid line %d", lineno); 763 return -1; 764 } 765 766 if (! *tok) { 767 syslog(LOG_ERR, "invalid line %d", lineno); 768 return -1; 769 } 770 771 /* constraints have different syntax */ 772 if (op == '!' || op == '>') { 773 return add_constraint(op, raw, tok); 774 } 775 776 if (!strcmp(raw, "Domain")) { 777 domain = create_domain(tok); 778 group = NULL; 779 return 0; 780 } 781 782 if (!domain) { 783 domain = create_domain("Default"); 784 if (!domain) 785 return -1; 786 group = NULL; 787 } 788 789 if (!group && 790 (!strcmp(raw, "Whitespace") || !strcmp(raw, "Join") || 791 !strcmp(raw, "Prefix") || !strcmp(raw, "Suffix") || 792 !strcmp(raw, "Default"))) { 793 syslog(LOG_ERR, "expected ModifierGroup declaration on line %d", lineno); 794 return -1; 795 } 796 797 if (!strcmp(raw, "Include")) { 798 unsigned int n; 799 glob_t g; 800 g.gl_offs = 0; 801 if (glob(tok, GLOB_ERR, NULL, &g) < 0) { 802 globfree(&g); 803 return -1; 804 } 805 for (n=0; n < g.gl_pathc; n++) { 806 if (read_translations(g.gl_pathv[n]) < 0) { 807 globfree(&g); 808 return -1; 809 } 810 } 811 globfree(&g); 812 } else if (!strcmp(raw, "Base")) { 813 base_classification = 1; 814 } else if (!strcmp(raw, "ModifierGroup")) { 815 group = create_group(&domain->groups, tok); 816 if (!group) 817 return -1; 818 base_classification = 0; 819 } else if (!strcmp(raw, "Whitespace")) { 820 if (update (&group->whitespace, tok) < 0) 821 return -1; 822 } else if (!strcmp(raw, "Join")) { 823 if (update (&group->join, tok) < 0) 824 return -1; 825 } else if (!strcmp(raw, "Prefix")) { 826 if (append (&group->prefixes, tok) < 0) 827 return -1; 828 } else if (!strcmp(raw, "Suffix")) { 829 if (append (&group->suffixes, tok) < 0) 830 return -1; 831 } else if (!strcmp(raw, "Default")) { 832 ebitmap_t empty; 833 ebitmap_init(&empty); 834 if (parse_ebitmap(&group->def, &empty, tok) < 0) { 835 syslog(LOG_ERR, "unable to parse Default %d", lineno); 836 return -1; 837 } 838 } else if (group) { 839 if (add_word(group, raw, tok) < 0) { 840 syslog(LOG_ERR, "unable to add base_classification on line %d", lineno); 841 return -1; 842 } 843 } else { 844 if (base_classification) { 845 if (add_base_classification(domain, raw, tok) < 0) { 846 syslog(LOG_ERR, "unable to add base_classification on line %d", lineno); 847 return -1; 848 } 849 } 850 if (add_cache(domain, raw, tok) < 0) 851 return -1; 852 } 853 return 0; 854 } 855 856 int 857 read_translations(const char *filename) { 858 size_t size = 0; 859 char *buffer = NULL; 860 int rval = 0; 861 862 FILE *cfg = fopen(filename,"r"); 863 if (!cfg) { 864 syslog(LOG_ERR, "%s file open failed", filename); 865 return -1; 866 } 867 868 __fsetlocking(cfg, FSETLOCKING_BYCALLER); 869 while (getline(&buffer, &size, cfg) > 0) { 870 if( process_trans(buffer) < 0 ) { 871 syslog(LOG_ERR, "%s file read failed", filename); 872 rval = -1; 873 break; 874 } 875 } 876 free(buffer); 877 fclose(cfg); 878 return rval; 879 } 880 881 int 882 init_translations(void) { 883 if (is_selinux_mls_enabled() <= 0) 884 return -1; 885 886 return(read_translations(selinux_translations_path())); 887 } 888 889 char * 890 extract_range(const security_context_t incon) { 891 context_t con = context_new(incon); 892 if (!con) { 893 syslog(LOG_ERR, "extract_range context_new(%s) failed: %s", incon, strerror(errno)); 894 return NULL; 895 } 896 897 const char *range = context_range_get(con); 898 if (!range) { 899 syslog(LOG_ERR, "extract_range: context_range_get(%s) failed: %m", incon); 900 context_free(con); 901 return NULL; 902 } 903 char *r = strdup(range); 904 if (!r) { 905 log_error("extract_range: allocation error %s", strerror(errno)); 906 return NULL; 907 } 908 context_free(con); 909 return r; 910 } 911 912 char * 913 new_context_str(const security_context_t incon, const char *range) { 914 char *rcon = NULL; 915 context_t con = context_new(incon); 916 if (!con) { 917 goto exit; 918 } 919 context_range_set(con, range); 920 rcon = strdup(context_str(con)); 921 if (!rcon) { 922 goto exit; 923 } 924 925 return rcon; 926 927 exit: 928 log_error("new_context_str: %s %s", incon, strerror(errno)); 929 return NULL; 930 } 931 932 char * 933 find_in_hashtable(const char *range, domain_t *domain, context_map_node_t **table) { 934 char *trans = NULL; 935 context_map_t *map = find_in_table(table, range); 936 if (map) { 937 trans = strdup((table == domain->raw_to_trans) ? map->trans: map->raw); 938 if (!trans) { 939 log_error("find_in_hashtable: allocation error %s", strerror(errno)); 940 return NULL; 941 } 942 log_debug(" found %s in hashtable returning %s\n", range, trans); 943 } 944 return trans; 945 } 946 947 void 948 emit_whitespace(char*buffer, char *whitespace) { 949 strcat(buffer, "["); 950 strcat(buffer, whitespace); 951 strcat(buffer, "]"); 952 } 953 954 static int 955 string_size(const void *p1, const void *p2) { 956 return strlen(*(char **)p2) - strlen(*(char **)p1); 957 } 958 959 static int 960 word_size(const void *p1, const void *p2) { 961 word_t *w1 = *(word_t **)p1; 962 word_t *w2 = *(word_t **)p2; 963 int w1_len=strlen(w1->text); 964 int w2_len=strlen(w2->text); 965 if (w1_len == w2_len) 966 return strcmp(w1->text, w2->text); 967 return (w2_len - w1_len); 968 } 969 970 void 971 build_regexp(pcre **r, char *buffer) { 972 const char *error; 973 int error_offset; 974 if (*r) 975 pcre_free(*r); 976 *r = pcre_compile(buffer, PCRE_CASELESS, &error, &error_offset, NULL); 977 if (error) { 978 log_error("pcre=%s, error=%s\n", buffer, error ? error: "none"); 979 } 980 buffer[0] = '\0'; 981 } 982 983 int 984 build_regexps(domain_t *domain) { 985 char buffer[1024 * 128]; 986 buffer[0] = '\0'; 987 base_classification_t *bc; 988 word_group_t *g; 989 affix_t *a; 990 word_t *w; 991 size_t n_el, i; 992 993 for (n_el = 0, bc = domain->base_classifications; bc; bc = bc->next) { 994 n_el++; 995 } 996 997 char **sortable = calloc(n_el, sizeof(char *)); 998 if (!sortable) { 999 log_error("allocation error %s", strerror(errno)); 1000 return -1; 1001 } 1002 1003 for (i=0, bc = domain->base_classifications; bc; bc = bc->next) { 1004 sortable[i++] = bc->trans; 1005 } 1006 1007 qsort(sortable, n_el, sizeof(char *), string_size); 1008 1009 for (i = 0; i < n_el; i++) { 1010 strcat(buffer, sortable[i]); 1011 if (i < n_el) strcat(buffer,"|"); 1012 } 1013 1014 free(sortable); 1015 1016 log_debug(">>> %s classification regexp=%s\n", domain->name, buffer); 1017 build_regexp(&domain->base_classification_regexp, buffer); 1018 1019 for (g = domain->groups; g; g = g->next) { 1020 if (g->prefixes) { 1021 strcat(buffer,"(?:"); 1022 for (a = g->prefixes; a; a = a->next) { 1023 strcat(buffer, a->text); 1024 if (a->next) strcat(buffer,"|"); 1025 } 1026 strcat(buffer,")"); 1027 strcat(buffer,"[ ]+"); 1028 log_debug(">>> %s %s prefix regexp=%s\n", domain->name, g->name, buffer); 1029 build_regexp(&g->prefix_regexp, buffer); 1030 } 1031 1032 if (g->prefixes) 1033 strcat(buffer, "^"); 1034 strcat(buffer, "(?:"); 1035 1036 g->sword_len=0; 1037 for (w = g->words; w; w = w->next) 1038 g->sword_len++; 1039 1040 g->sword = calloc(g->sword_len, sizeof(word_t *)); 1041 if (!g->sword) { 1042 log_error("allocation error %s", strerror(errno)); 1043 return -1; 1044 } 1045 1046 i=0; 1047 for (w = g->words; w; w = w->next) 1048 g->sword[i++]=w; 1049 1050 qsort(g->sword, g->sword_len, sizeof(word_t *), word_size); 1051 1052 for (i=0; i < g->sword_len; i++) { 1053 if (i) strcat(buffer,"|"); 1054 strcat(buffer,"\\b"); 1055 strcat(buffer, g->sword[i]->text); 1056 strcat(buffer,"\\b"); 1057 } 1058 1059 if (g->whitespace) { 1060 strcat(buffer,"|["); 1061 strcat(buffer, g->whitespace); 1062 strcat(buffer, "]+"); 1063 } 1064 1065 strcat(buffer, ")+"); 1066 if (g->suffixes) 1067 strcat(buffer, "$"); 1068 1069 log_debug(">>> %s %s modifier regexp=%s\n", domain->name, g->name, buffer); 1070 build_regexp(&g->word_regexp, buffer); 1071 if (g->suffixes) { 1072 strcat(buffer,"[ ]+"); 1073 strcat(buffer,"(?:"); 1074 for (a = g->suffixes; a; a = a->next) { 1075 strcat(buffer, a->text); 1076 if (a->next) strcat(buffer,"|"); 1077 } 1078 strcat(buffer,")"); 1079 log_debug(">>> %s %s suffix regexp=%s\n", domain->name, g->name, buffer); 1080 build_regexp(&g->suffix_regexp, buffer); 1081 } 1082 } 1083 1084 return 0; 1085 } 1086 1087 char * 1088 compute_raw_from_trans(const char *level, domain_t *domain) { 1089 1090 #ifdef DEBUG 1091 struct timeval startTime; 1092 gettimeofday(&startTime, 0); 1093 #endif 1094 1095 int rc = 0; 1096 int ovector[OVECCOUNT]; 1097 word_group_t *g = NULL; 1098 char *work = NULL; 1099 char *r = NULL; 1100 const char * match = NULL; 1101 int work_len; 1102 mls_level_t *mraw = NULL; 1103 ebitmap_t set, clear, tmp; 1104 1105 ebitmap_init(&set); 1106 ebitmap_init(&clear); 1107 ebitmap_init(&tmp); 1108 1109 work = strdup(level); 1110 if (!work) { 1111 log_error("compute_raw_from_trans: allocation error %s", strerror(errno)); 1112 goto err; 1113 } 1114 work_len = strlen(work); 1115 1116 if (!domain->base_classification_regexp) 1117 if (build_regexps(domain) < 0) 1118 goto err; 1119 if (!domain->base_classification_regexp) 1120 goto err; 1121 log_debug(" compute_raw_from_trans work = %s\n", work); 1122 rc = pcre_exec(domain->base_classification_regexp, 0, work, work_len, 0, PCRE_ANCHORED, ovector, OVECCOUNT); 1123 if (rc > 0) { 1124 match = NULL; 1125 pcre_get_substring(work, ovector, rc, 0, &match); 1126 log_debug(" compute_raw_from_trans match = %s len = %u\n", match, strlen(match)); 1127 base_classification_t *bc; 1128 for (bc = domain->base_classifications; bc; bc = bc->next) { 1129 if (!strcmp(bc->trans, match)) { 1130 log_debug(" compute_raw_from_trans base classification %s matched %s\n", level, bc->trans); 1131 mraw = malloc(sizeof(mls_level_t)); 1132 if (!mraw) { 1133 log_error("allocation error %s", strerror(errno)); 1134 goto err; 1135 } 1136 if (mls_level_cpy(mraw, bc->level) < 0) 1137 goto err; 1138 break; 1139 } 1140 } 1141 1142 memset(work + ovector[0], '#', ovector[1] - ovector[0]); 1143 char *p=work + ovector[0] + ovector[1]; 1144 while (*p && (strchr(" ", *p) != NULL)) 1145 *p++ = '#'; 1146 pcre_free((char *)match); 1147 match = NULL; 1148 } else { 1149 log_debug(" compute_raw_from_trans no base classification matched %s\n", level); 1150 } 1151 1152 if (mraw == NULL) { 1153 goto err; 1154 } 1155 1156 int complete = 0; 1157 int change = 1; 1158 while(change && !complete) { 1159 change = 0; 1160 for (g = domain->groups; g && !change && !complete; g = g->next) { 1161 int prefix = 0, suffix = 0; 1162 int prefix_offset = 0, prefix_len = 0; 1163 int suffix_offset = 0, suffix_len = 0; 1164 if (g->prefix_regexp) { 1165 rc = pcre_exec(g->prefix_regexp, 0, work, work_len, 0, 0, ovector, OVECCOUNT); 1166 if (rc > 0) { 1167 prefix = 1; 1168 prefix_offset = ovector[0]; 1169 prefix_len = ovector[1] - ovector[0]; 1170 } 1171 } 1172 if (g->suffix_regexp) { 1173 rc = pcre_exec(g->suffix_regexp, 0, work, work_len, 0, 0, ovector, OVECCOUNT); 1174 if (rc > 0) { 1175 suffix = 1; 1176 suffix_offset = ovector[0]; 1177 suffix_len = ovector[1] - ovector[0]; 1178 } 1179 } 1180 1181 /* anchors prefix ^, suffix $ */ 1182 if (((!g->prefixes && !g->suffixes) || 1183 (g->prefixes && prefix) || 1184 (g->suffixes && suffix)) && 1185 g->word_regexp) { 1186 char *s = work + prefix_offset + prefix_len; 1187 int l = (suffix_len ? suffix_offset : work_len) - prefix_len - prefix_offset; 1188 rc = pcre_exec(g->word_regexp, 0, s, l, 0, 0, ovector, OVECCOUNT); 1189 if (rc > 0) { 1190 match = NULL; 1191 pcre_get_substring(s, ovector, rc, 0, &match); 1192 trim((char *)match, g->whitespace); 1193 if (*match) { 1194 char *p = triml((char *)match, g->whitespace); 1195 while (p && *p) { 1196 int plen = strlen(p); 1197 unsigned int i; 1198 for (i = 0; i < g->sword_len; i++) { 1199 word_t *w = g->sword[i]; 1200 int wlen = strlen(w->text); 1201 if (plen >= wlen && !strncmp(w->text, p, strlen(w->text))){ 1202 if (ebitmap_andnot(&set, &w->cat, &g->def, maxbit) < 0) goto err; 1203 1204 if (ebitmap_xor(&tmp, &w->cat, &g->def) < 0) goto err; 1205 if (ebitmap_and(&clear, &tmp, &g->def) < 0) goto err; 1206 if (ebitmap_union(&mraw->cat, &set) < 0) goto err; 1207 1208 ebitmap_destroy(&tmp); 1209 if (ebitmap_cpy(&tmp, &mraw->cat) < 0) goto err; 1210 ebitmap_destroy(&mraw->cat); 1211 if (ebitmap_andnot(&mraw->cat, &tmp, &clear, maxbit) < 0) goto err; 1212 1213 ebitmap_destroy(&tmp); 1214 ebitmap_destroy(&set); 1215 ebitmap_destroy(&clear); 1216 p += strlen(w->text); 1217 change++; 1218 break; 1219 } 1220 } 1221 if (i == g->sword_len) { 1222 syslog(LOG_ERR, "conversion error"); 1223 break; 1224 } 1225 p = triml(p, g->whitespace); 1226 } 1227 memset(work + prefix_offset, '#', prefix_len); 1228 memset(work + suffix_offset, '#', suffix_len); 1229 memset(s + ovector[0], '#', ovector[1] - ovector[0]); 1230 } 1231 pcre_free((void *)match); 1232 match = NULL; 1233 } 1234 } 1235 /* YYY */ 1236 complete=1; 1237 char *p = work; 1238 while(*p) { 1239 if (isalnum(*p++)) { 1240 complete=0; 1241 break; 1242 } 1243 } 1244 } 1245 } 1246 free(work); 1247 if (violates_constraints(mraw)) { 1248 complete = 0; 1249 } 1250 if (complete) 1251 r = mls_level_to_string(mraw); 1252 mls_level_destroy(mraw); 1253 free(mraw); 1254 1255 #ifdef DEBUG 1256 struct timeval stopTime; 1257 gettimeofday(&stopTime, 0); 1258 long int ms; 1259 if (startTime.tv_usec > stopTime.tv_usec) 1260 ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000); 1261 else 1262 ms = (stopTime.tv_sec - startTime.tv_sec ) * 1000 + (stopTime.tv_usec/1000 - startTime.tv_usec/1000); 1263 log_debug(" compute_raw_from_trans in %ld ms'\n", ms); 1264 #endif 1265 1266 return r; 1267 1268 err: 1269 mls_level_destroy(mraw); 1270 free(mraw); 1271 free(work); 1272 pcre_free((void *)match); 1273 ebitmap_destroy(&tmp); 1274 ebitmap_destroy(&set); 1275 ebitmap_destroy(&clear); 1276 return NULL; 1277 } 1278 1279 char * 1280 compute_trans_from_raw(const char *level, domain_t *domain) { 1281 1282 #ifdef DEBUG 1283 struct timeval startTime; 1284 gettimeofday(&startTime, 0); 1285 #endif 1286 1287 word_group_t *g; 1288 mls_level_t *l = NULL; 1289 char *rval = NULL; 1290 word_group_t *groups = NULL; 1291 ebitmap_t bit_diff, temp, handled, nothandled, unhandled, orig_unhandled; 1292 1293 ebitmap_init(&bit_diff); 1294 ebitmap_init(&temp); 1295 ebitmap_init(&handled); 1296 ebitmap_init(¬handled); 1297 ebitmap_init(&unhandled); 1298 ebitmap_init(&orig_unhandled); 1299 1300 if (!level) 1301 goto err; 1302 1303 l = parse_raw(level); 1304 if (!l) 1305 goto err; 1306 log_debug(" compute_trans_from_raw raw = %s\n", level); 1307 1308 /* YYY */ 1309 /* check constraints */ 1310 if (violates_constraints(l)) { 1311 syslog(LOG_ERR, "%s violates constraints", level); 1312 goto err; 1313 } 1314 1315 int doInverse = l->sens > 0; 1316 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 if (ebitmap_xor(&unhandled, &l->cat, &bc->level->cat) < 0) 1329 goto err; 1330 if (ebitmap_cpy(&orig_unhandled, &unhandled) < 0) 1331 goto err; 1332 1333 /* prebuild groups */ 1334 for (g = domain->groups; g; g = g->next) { 1335 word_group_t **t; 1336 for (t = &groups; *t; t = &(*t)->next) 1337 if (!strcmp(g->name, (*t)->name)) 1338 break; 1339 1340 if (! *t) { 1341 word_group_t *wg = create_group(&groups, g->name); 1342 if (g->prefixes) 1343 if (append(&wg->prefixes, g->prefixes->text) < 0) 1344 goto err; 1345 if (g->suffixes) 1346 if (append(&wg->suffixes, g->suffixes->text) < 0) 1347 goto err; 1348 if (g->join) 1349 if (update(&wg->join, g->join) < 0) 1350 goto err; 1351 } 1352 } 1353 1354 int loops, hamming, change=1; 1355 for (loops = 50; ebitmap_cardinality(&unhandled) && loops > 0 && change; loops--) { 1356 change = 0; 1357 hamming = 10000; 1358 if (ebitmap_xor(&handled, &unhandled, &orig_unhandled) < 0) 1359 goto err; 1360 if (ebitmap_not(¬handled, &handled, maxbit) < 0) 1361 goto err; 1362 word_group_t *currentGroup = NULL; 1363 word_t *currentWord = NULL; 1364 for (g = domain->groups; g && hamming; g = g->next) { 1365 word_t *w; 1366 for (w = g->words; w && hamming; w = w->next) { 1367 int cardinality = ebitmap_cardinality(&w->normal); 1368 /* If the word is all inverse bits and the level does not have inverse bits - skip */ 1369 if (cardinality && !doInverse) { 1370 continue; 1371 } 1372 1373 /* if only unhandled bits are different */ 1374 if (ebitmap_or(&temp, &w->normal, &w->inverse) < 0) 1375 goto err; 1376 if (ebitmap_and(&bit_diff, &temp, ¬handled) < 0) 1377 goto err; 1378 ebitmap_destroy(&temp); 1379 // xor bit_diff handled? 1380 if (ebitmap_and(&temp, &bit_diff, &unhandled) < 0) 1381 goto err; 1382 if (ebitmap_cmp(&bit_diff, &temp)) { 1383 int h = ebitmap_hamming_distance(&bit_diff, &unhandled); 1384 if (h < hamming) { 1385 hamming = h; 1386 currentGroup = g; 1387 currentWord = w; 1388 } 1389 } 1390 ebitmap_destroy(&bit_diff); 1391 ebitmap_destroy(&temp); 1392 } 1393 } 1394 ebitmap_destroy(&handled); 1395 ebitmap_destroy(¬handled); 1396 1397 if (currentWord) { 1398 if (ebitmap_xor(&bit_diff, ¤tWord->cat, &bc->level->cat) < 0) 1399 goto err; 1400 1401 if (ebitmap_cpy(&temp, &unhandled) < 0) 1402 goto err; 1403 ebitmap_destroy(&unhandled); 1404 if (ebitmap_andnot(&unhandled, &temp, &bit_diff, maxbit) < 0) 1405 goto err; 1406 1407 ebitmap_destroy(&bit_diff); 1408 ebitmap_destroy(&temp); 1409 1410 word_group_t **t; 1411 for (t = &groups; *t; t = &(*t)->next) 1412 if (!strcmp(currentGroup->name, (*t)->name)) 1413 break; 1414 create_word(&(*t)->words, currentWord->text); 1415 change++; 1416 } 1417 } 1418 1419 done = (ebitmap_cardinality(&unhandled) == 0); 1420 ebitmap_destroy(&unhandled); 1421 ebitmap_destroy(&orig_unhandled); 1422 if (done) { 1423 char buffer[9999]; 1424 buffer[0] = 0; 1425 strcat(buffer, bc->trans); 1426 strcat(buffer, " "); 1427 for (g=groups; g; g = g->next) { 1428 if (g->words && g->prefixes) { 1429 strcat(buffer, g->prefixes->text); 1430 strcat(buffer, " "); 1431 } 1432 word_t *w; 1433 for (w=g->words; w; w = w->next) { 1434 strcat(buffer, w->text); 1435 if (w->next) 1436 strcat(buffer, g->join); 1437 } 1438 if (g->words && g->suffixes) { 1439 strcat(buffer, " "); 1440 strcat(buffer, g->suffixes->text); 1441 } 1442 word_group_t *n = g->next; 1443 while(g->words && n) { 1444 if (n->words) { 1445 strcat(buffer, " "); 1446 break; 1447 } 1448 n = n->next; 1449 } 1450 } 1451 rval = strdup(buffer); 1452 if (!rval) { 1453 log_error("compute_trans_from_raw: allocation error %s", strerror(errno)); 1454 goto err; 1455 } 1456 } 1457 /* clean up */ 1458 while (groups) 1459 destroy_group(&groups, groups); 1460 } 1461 last = bc; 1462 } 1463 if (l) { 1464 mls_level_destroy(l); 1465 free(l); 1466 } 1467 1468 #ifdef DEBUG 1469 struct timeval stopTime; 1470 gettimeofday(&stopTime, 0); 1471 long int ms; 1472 if (startTime.tv_usec > stopTime.tv_usec) 1473 ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000); 1474 else 1475 ms = (stopTime.tv_sec - startTime.tv_sec ) * 1000 + (stopTime.tv_usec/1000 - startTime.tv_usec/1000); 1476 1477 log_debug(" compute_trans_from_raw in %ld ms'\n", ms); 1478 #endif 1479 1480 return rval; 1481 1482 err: 1483 while (groups) 1484 destroy_group(&groups, groups); 1485 mls_level_destroy(l); 1486 free(l); 1487 return NULL; 1488 } 1489 1490 int 1491 trans_context(const security_context_t incon, security_context_t *rcon) { 1492 char *trans = NULL; 1493 *rcon = NULL; 1494 1495 #ifdef DEBUG 1496 struct timeval startTime; 1497 gettimeofday(&startTime, 0); 1498 #endif 1499 1500 log_debug(" trans_context input = %s\n", incon); 1501 char *range = extract_range(incon); 1502 if (!range) return -1; 1503 1504 domain_t *domain = domains; 1505 for (;domain; domain = domain->next) { 1506 trans = find_in_hashtable(range, domain, domain->raw_to_trans); 1507 if (trans) break; 1508 1509 /* try split and translate */ 1510 char *lrange = NULL, *urange = NULL; 1511 char *ltrans = NULL, *utrans = NULL; 1512 char *dashp = strchr(range,'-'); 1513 if (dashp) { 1514 *dashp = 0; 1515 lrange = range; 1516 urange = dashp+1; 1517 } else { 1518 trans = compute_trans_from_raw(range, domain); 1519 if (trans) 1520 if (add_cache(domain, range, trans) < 0) 1521 return -1; 1522 } 1523 1524 if (lrange && urange) { 1525 ltrans = find_in_hashtable(lrange, domain, domain->raw_to_trans); 1526 if (! ltrans) { 1527 ltrans = compute_trans_from_raw(lrange, domain); 1528 if (ltrans) { 1529 if (add_cache(domain, lrange, ltrans) < 0) 1530 return -1; 1531 } else { 1532 ltrans = strdup(lrange); 1533 if (! ltrans) { 1534 log_error("strdup failed %s", strerror(errno)); 1535 return -1; 1536 } 1537 } 1538 } 1539 1540 utrans = find_in_hashtable(urange, domain, domain->raw_to_trans); 1541 if (! utrans) { 1542 utrans = compute_trans_from_raw(urange, domain); 1543 if (utrans) { 1544 if (add_cache(domain, urange, utrans) < 0) 1545 return -1; 1546 } else { 1547 utrans = strdup(urange); 1548 if (! utrans) { 1549 log_error("strdup failed %s", strerror(errno)); 1550 return -1; 1551 } 1552 } 1553 } 1554 1555 if (strcmp(ltrans, utrans) == 0) { 1556 if (asprintf(&trans, "%s", ltrans) < 0) { 1557 log_error("asprintf failed %s", strerror(errno)); 1558 return -1; 1559 } 1560 } else { 1561 if (asprintf(&trans, "%s-%s", ltrans, utrans) < 0) { 1562 log_error("asprintf failed %s", strerror(errno)); 1563 return -1; 1564 } 1565 } 1566 free(ltrans); 1567 free(utrans); 1568 *dashp = '-'; 1569 break; 1570 } 1571 if (dashp) 1572 *dashp = '-'; 1573 } 1574 1575 if (trans) { 1576 *rcon = new_context_str(incon, trans); 1577 free(trans); 1578 } else { 1579 *rcon = new_context_str(incon, range); 1580 } 1581 free(range); 1582 1583 #ifdef DEBUG 1584 struct timeval stopTime; 1585 gettimeofday(&stopTime, 0); 1586 long int ms; 1587 if (startTime.tv_usec > stopTime.tv_usec) 1588 ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000); 1589 else 1590 ms = (stopTime.tv_sec - startTime.tv_sec ) * 1000 + (stopTime.tv_usec/1000 - startTime.tv_usec/1000); 1591 1592 log_debug(" trans_context input='%s' output='%s in %ld ms'\n", incon, *rcon, ms); 1593 #endif 1594 return 0; 1595 } 1596 1597 int 1598 untrans_context(const security_context_t incon, security_context_t *rcon) { 1599 char *raw = NULL; 1600 *rcon = NULL; 1601 1602 #ifdef DEBUG 1603 struct timeval startTime; 1604 gettimeofday(&startTime, 0); 1605 #endif 1606 1607 log_debug(" untrans_context incon = %s\n", incon); 1608 char *range = extract_range(incon); 1609 if (!range) return -1; 1610 log_debug(" untrans_context range = %s\n", range); 1611 1612 domain_t *domain = domains; 1613 for (;domain; domain = domain->next) { 1614 raw = find_in_hashtable(range, domain, domain->trans_to_raw); 1615 if (raw) break; 1616 1617 /* try split and translate */ 1618 char *lrange = NULL, *urange = NULL; 1619 char *lraw = NULL, *uraw = NULL; 1620 char *dashp = strchr(range,'-'); 1621 if (dashp) { 1622 *dashp = 0; 1623 lrange = range; 1624 urange = dashp+1; 1625 } else { 1626 raw = compute_raw_from_trans(range, domain); 1627 if (raw) { 1628 char *canonical = find_in_hashtable(raw, domain, domain->raw_to_trans); 1629 if (!canonical) { 1630 canonical = compute_trans_from_raw(raw, domain); 1631 if (canonical && strcmp(canonical, range)) 1632 if (add_cache(domain, raw, canonical) < 0) 1633 return -1; 1634 } 1635 if (canonical) 1636 free(canonical); 1637 if (add_cache(domain, raw, range) < 0) 1638 return -1; 1639 } else { 1640 log_debug("untrans_context unable to compute raw context %s\n", range); 1641 } 1642 } 1643 1644 if (lrange && urange) { 1645 lraw = find_in_hashtable(lrange, domain, domain->trans_to_raw); 1646 if (! lraw) { 1647 lraw = compute_raw_from_trans(lrange, domain); 1648 if (lraw) { 1649 char *canonical = find_in_hashtable(lraw, domain, domain->raw_to_trans); 1650 if (!canonical) { 1651 canonical = compute_trans_from_raw(lraw, domain); 1652 if (canonical) 1653 if (add_cache(domain, lraw, canonical) < 0) 1654 return -1; 1655 } 1656 if (canonical) 1657 free(canonical); 1658 if (add_cache(domain, lraw, lrange) < 0) 1659 return -1; 1660 } else { 1661 lraw = strdup(lrange); 1662 if (! lraw) { 1663 log_error("strdup failed %s", strerror(errno)); 1664 return -1; 1665 } 1666 } 1667 } 1668 1669 uraw = find_in_hashtable(urange, domain, domain->trans_to_raw); 1670 if (! uraw) { 1671 uraw = compute_raw_from_trans(urange, domain); 1672 if (uraw) { 1673 char *canonical = find_in_hashtable(uraw, domain, domain->raw_to_trans); 1674 if (!canonical) { 1675 canonical = compute_trans_from_raw(uraw, domain); 1676 if (canonical) 1677 if (add_cache(domain, uraw, canonical) < 0) 1678 return -1; 1679 } 1680 if (canonical) 1681 free(canonical); 1682 if (add_cache(domain, uraw, urange) < 0) 1683 return -1; 1684 } else { 1685 uraw = strdup(urange); 1686 if (! uraw) { 1687 log_error("strdup failed %s", strerror(errno)); 1688 return -1; 1689 } 1690 } 1691 } 1692 1693 1694 if (strcmp(lraw, uraw) == 0) { 1695 if (asprintf(&raw, "%s", lraw) < 0) { 1696 log_error("asprintf failed %s", strerror(errno)); 1697 return -1; 1698 } 1699 } else { 1700 if (asprintf(&raw, "%s-%s", lraw, uraw) < 0) { 1701 log_error("asprintf failed %s", strerror(errno)); 1702 return -1; 1703 } 1704 } 1705 free(lraw); 1706 free(uraw); 1707 *dashp = '-'; 1708 break; 1709 } 1710 if (dashp) 1711 *dashp = '-'; 1712 } 1713 1714 if (raw) { 1715 *rcon = new_context_str(incon, raw); 1716 free(raw); 1717 } else { 1718 *rcon = new_context_str(incon, range); 1719 } 1720 free(range); 1721 1722 #ifdef DEBUG 1723 struct timeval stopTime; 1724 gettimeofday(&stopTime, 0); 1725 long int ms; 1726 if (startTime.tv_usec > stopTime.tv_usec) 1727 ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000); 1728 else 1729 ms = (stopTime.tv_sec - startTime.tv_sec ) * 1000 + (stopTime.tv_usec/1000 - startTime.tv_usec/1000); 1730 1731 log_debug(" untrans_context input='%s' output='%s' n %ld ms\n", incon, *rcon, ms); 1732 #endif 1733 return 0; 1734 } 1735 1736 void 1737 finish_context_translations(void) { 1738 while(domains) { 1739 domain_t *next = domains->next; 1740 destroy_domain(domains); 1741 domains = next; 1742 } 1743 while(sens_constraints) { 1744 sens_constraint_t *next = sens_constraints->next; 1745 destroy_sens_constraint(&sens_constraints, sens_constraints); 1746 sens_constraints = next; 1747 } 1748 while(cat_constraints) { 1749 cat_constraint_t *next = cat_constraints->next; 1750 destroy_cat_constraint(&cat_constraints, cat_constraints); 1751 cat_constraints = next; 1752 } 1753 } 1754 1755