45 46#define princ_num_comp(P) ((P)->name.name_string.len) 47#define princ_type(P) ((P)->name.name_type) 48#define princ_comp(P) ((P)->name.name_string.val) 49#define princ_ncomp(P, N) ((P)->name.name_string.val[(N)]) 50#define princ_realm(P) ((P)->realm) 51 52void 53krb5_free_principal(krb5_context context, 54 krb5_principal p) 55{ 56 if(p){ 57 free_Principal(p); 58 free(p); 59 } 60} 61 62int 63krb5_principal_get_type(krb5_context context, 64 krb5_principal principal) 65{ 66 return princ_type(principal); 67} 68 69const char * 70krb5_principal_get_realm(krb5_context context, 71 krb5_principal principal) 72{ 73 return princ_realm(principal); 74} 75 76const char * 77krb5_principal_get_comp_string(krb5_context context, 78 krb5_principal principal, 79 unsigned int component) 80{ 81 if(component >= princ_num_comp(principal)) 82 return NULL; 83 return princ_ncomp(principal, component); 84} 85 86krb5_error_code 87krb5_parse_name(krb5_context context, 88 const char *name, 89 krb5_principal *principal) 90{ 91 krb5_error_code ret; 92 general_string *comp; 93 general_string realm; 94 int ncomp; 95 96 const char *p; 97 char *q; 98 char *s; 99 char *start; 100 101 int n; 102 char c; 103 int got_realm = 0; 104 105 /* count number of component */ 106 ncomp = 1; 107 for(p = name; *p; p++){ 108 if(*p=='\\'){ 109 if(!p[1]) { 110 krb5_set_error_string (context, 111 "trailing \\ in principal name"); 112 return KRB5_PARSE_MALFORMED; 113 } 114 p++; 115 } else if(*p == '/') 116 ncomp++; 117 } 118 comp = calloc(ncomp, sizeof(*comp)); 119 if (comp == NULL) { 120 krb5_set_error_string (context, "malloc: out of memory"); 121 return ENOMEM; 122 } 123 124 n = 0; 125 p = start = q = s = strdup(name); 126 if (start == NULL) { 127 free (comp); 128 krb5_set_error_string (context, "malloc: out of memory"); 129 return ENOMEM; 130 } 131 while(*p){ 132 c = *p++; 133 if(c == '\\'){ 134 c = *p++; 135 if(c == 'n') 136 c = '\n'; 137 else if(c == 't') 138 c = '\t'; 139 else if(c == 'b') 140 c = '\b'; 141 else if(c == '0') 142 c = '\0'; 143 else if(c == '\0') { 144 krb5_set_error_string (context, 145 "trailing \\ in principal name"); 146 ret = KRB5_PARSE_MALFORMED; 147 goto exit; 148 } 149 }else if(c == '/' || c == '@'){ 150 if(got_realm){ 151 krb5_set_error_string (context, 152 "part after realm in principal name"); 153 ret = KRB5_PARSE_MALFORMED; 154 goto exit; 155 }else{ 156 comp[n] = malloc(q - start + 1); 157 if (comp[n] == NULL) { 158 krb5_set_error_string (context, "malloc: out of memory"); 159 ret = ENOMEM; 160 goto exit; 161 } 162 memcpy(comp[n], start, q - start); 163 comp[n][q - start] = 0; 164 n++; 165 } 166 if(c == '@') 167 got_realm = 1; 168 start = q; 169 continue; 170 } 171 if(got_realm && (c == ':' || c == '/' || c == '\0')) { 172 krb5_set_error_string (context, 173 "part after realm in principal name"); 174 ret = KRB5_PARSE_MALFORMED; 175 goto exit; 176 } 177 *q++ = c; 178 } 179 if(got_realm){ 180 realm = malloc(q - start + 1); 181 if (realm == NULL) { 182 krb5_set_error_string (context, "malloc: out of memory"); 183 ret = ENOMEM; 184 goto exit; 185 } 186 memcpy(realm, start, q - start); 187 realm[q - start] = 0; 188 }else{ 189 ret = krb5_get_default_realm (context, &realm); 190 if (ret) 191 goto exit; 192 193 comp[n] = malloc(q - start + 1); 194 if (comp[n] == NULL) { 195 krb5_set_error_string (context, "malloc: out of memory"); 196 ret = ENOMEM; 197 goto exit; 198 } 199 memcpy(comp[n], start, q - start); 200 comp[n][q - start] = 0; 201 n++; 202 } 203 *principal = malloc(sizeof(**principal)); 204 if (*principal == NULL) { 205 krb5_set_error_string (context, "malloc: out of memory"); 206 ret = ENOMEM; 207 goto exit; 208 } 209 (*principal)->name.name_type = KRB5_NT_PRINCIPAL; 210 (*principal)->name.name_string.val = comp; 211 princ_num_comp(*principal) = n; 212 (*principal)->realm = realm; 213 free(s); 214 return 0; 215exit: 216 while(n>0){ 217 free(comp[--n]); 218 } 219 free(comp); 220 free(s); 221 return ret; 222} 223 224static const char quotable_chars[] = " \n\t\b\\/@"; 225static const char replace_chars[] = " ntb\\/@"; 226 227#define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0); 228 229static size_t 230quote_string(const char *s, char *out, size_t index, size_t len) 231{ 232 const char *p, *q; 233 for(p = s; *p && index < len; p++){ 234 if((q = strchr(quotable_chars, *p))){ 235 add_char(out, index, len, '\\'); 236 add_char(out, index, len, replace_chars[q - quotable_chars]); 237 }else 238 add_char(out, index, len, *p); 239 } 240 if(index < len) 241 out[index] = '\0'; 242 return index; 243} 244 245 246static krb5_error_code 247unparse_name_fixed(krb5_context context, 248 krb5_const_principal principal, 249 char *name, 250 size_t len, 251 krb5_boolean short_form) 252{ 253 size_t index = 0; 254 int i; 255 for(i = 0; i < princ_num_comp(principal); i++){ 256 if(i) 257 add_char(name, index, len, '/'); 258 index = quote_string(princ_ncomp(principal, i), name, index, len); 259 if(index == len) 260 return ERANGE; 261 } 262 /* add realm if different from default realm */ 263 if(short_form) { 264 krb5_realm r; 265 krb5_error_code ret; 266 ret = krb5_get_default_realm(context, &r); 267 if(ret) 268 return ret; 269 if(strcmp(princ_realm(principal), r) != 0) 270 short_form = 0; 271 free(r); 272 } 273 if(!short_form) { 274 add_char(name, index, len, '@'); 275 index = quote_string(princ_realm(principal), name, index, len); 276 if(index == len) 277 return ERANGE; 278 } 279 return 0; 280} 281 282krb5_error_code 283krb5_unparse_name_fixed(krb5_context context, 284 krb5_const_principal principal, 285 char *name, 286 size_t len) 287{ 288 return unparse_name_fixed(context, principal, name, len, FALSE); 289} 290 291krb5_error_code 292krb5_unparse_name_fixed_short(krb5_context context, 293 krb5_const_principal principal, 294 char *name, 295 size_t len) 296{ 297 return unparse_name_fixed(context, principal, name, len, TRUE); 298} 299 300static krb5_error_code 301unparse_name(krb5_context context, 302 krb5_const_principal principal, 303 char **name, 304 krb5_boolean short_flag) 305{ 306 size_t len = 0, plen; 307 int i; 308 krb5_error_code ret; 309 /* count length */ 310 plen = strlen(princ_realm(principal)); 311 if(strcspn(princ_realm(principal), quotable_chars) == plen) 312 len += plen; 313 else 314 len += 2*plen; 315 len++; 316 for(i = 0; i < princ_num_comp(principal); i++){ 317 plen = strlen(princ_ncomp(principal, i)); 318 if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen) 319 len += plen; 320 else 321 len += 2*plen; 322 len++; 323 } 324 *name = malloc(len); 325 if(len != 0 && *name == NULL) { 326 krb5_set_error_string (context, "malloc: out of memory"); 327 return ENOMEM; 328 } 329 ret = unparse_name_fixed(context, principal, *name, len, short_flag); 330 if(ret) 331 free(*name); 332 return ret; 333} 334 335krb5_error_code 336krb5_unparse_name(krb5_context context, 337 krb5_const_principal principal, 338 char **name) 339{ 340 return unparse_name(context, principal, name, FALSE); 341} 342 343krb5_error_code 344krb5_unparse_name_short(krb5_context context, 345 krb5_const_principal principal, 346 char **name) 347{ 348 return unparse_name(context, principal, name, TRUE); 349} 350 351#if 0 /* not implemented */ 352 353krb5_error_code 354krb5_unparse_name_ext(krb5_context context, 355 krb5_const_principal principal, 356 char **name, 357 size_t *size) 358{ 359 krb5_abortx(context, "unimplemented krb5_unparse_name_ext called"); 360} 361 362#endif 363 364krb5_realm* 365krb5_princ_realm(krb5_context context, 366 krb5_principal principal) 367{ 368 return &princ_realm(principal); 369} 370 371 372void 373krb5_princ_set_realm(krb5_context context, 374 krb5_principal principal, 375 krb5_realm *realm) 376{ 377 princ_realm(principal) = *realm; 378} 379 380 381krb5_error_code 382krb5_build_principal(krb5_context context, 383 krb5_principal *principal, 384 int rlen, 385 krb5_const_realm realm, 386 ...) 387{ 388 krb5_error_code ret; 389 va_list ap; 390 va_start(ap, realm); 391 ret = krb5_build_principal_va(context, principal, rlen, realm, ap); 392 va_end(ap); 393 return ret; 394} 395 396static krb5_error_code 397append_component(krb5_context context, krb5_principal p, 398 const char *comp, 399 size_t comp_len) 400{ 401 general_string *tmp; 402 size_t len = princ_num_comp(p); 403 404 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp)); 405 if(tmp == NULL) { 406 krb5_set_error_string (context, "malloc: out of memory"); 407 return ENOMEM; 408 } 409 princ_comp(p) = tmp; 410 princ_ncomp(p, len) = malloc(comp_len + 1); 411 if (princ_ncomp(p, len) == NULL) { 412 krb5_set_error_string (context, "malloc: out of memory"); 413 return ENOMEM; 414 } 415 memcpy (princ_ncomp(p, len), comp, comp_len); 416 princ_ncomp(p, len)[comp_len] = '\0'; 417 princ_num_comp(p)++; 418 return 0; 419} 420 421static void 422va_ext_princ(krb5_context context, krb5_principal p, va_list ap) 423{ 424 while(1){ 425 const char *s; 426 int len; 427 len = va_arg(ap, int); 428 if(len == 0) 429 break; 430 s = va_arg(ap, const char*); 431 append_component(context, p, s, len); 432 } 433} 434 435static void 436va_princ(krb5_context context, krb5_principal p, va_list ap) 437{ 438 while(1){ 439 const char *s; 440 s = va_arg(ap, const char*); 441 if(s == NULL) 442 break; 443 append_component(context, p, s, strlen(s)); 444 } 445} 446 447 448static krb5_error_code 449build_principal(krb5_context context, 450 krb5_principal *principal, 451 int rlen, 452 krb5_const_realm realm, 453 void (*func)(krb5_context, krb5_principal, va_list), 454 va_list ap) 455{ 456 krb5_principal p; 457 458 p = calloc(1, sizeof(*p)); 459 if (p == NULL) { 460 krb5_set_error_string (context, "malloc: out of memory"); 461 return ENOMEM; 462 } 463 princ_type(p) = KRB5_NT_PRINCIPAL; 464 465 princ_realm(p) = strdup(realm); 466 if(p->realm == NULL){ 467 free(p); 468 krb5_set_error_string (context, "malloc: out of memory"); 469 return ENOMEM; 470 } 471 472 (*func)(context, p, ap); 473 *principal = p; 474 return 0; 475} 476 477krb5_error_code 478krb5_make_principal(krb5_context context, 479 krb5_principal *principal, 480 krb5_const_realm realm, 481 ...) 482{ 483 krb5_error_code ret; 484 krb5_realm r = NULL; 485 va_list ap; 486 if(realm == NULL) { 487 ret = krb5_get_default_realm(context, &r); 488 if(ret) 489 return ret; 490 realm = r; 491 } 492 va_start(ap, realm); 493 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap); 494 va_end(ap); 495 if(r) 496 free(r); 497 return ret; 498} 499 500krb5_error_code 501krb5_build_principal_va(krb5_context context, 502 krb5_principal *principal, 503 int rlen, 504 krb5_const_realm realm, 505 va_list ap) 506{ 507 return build_principal(context, principal, rlen, realm, va_princ, ap); 508} 509 510krb5_error_code 511krb5_build_principal_va_ext(krb5_context context, 512 krb5_principal *principal, 513 int rlen, 514 krb5_const_realm realm, 515 va_list ap) 516{ 517 return build_principal(context, principal, rlen, realm, va_ext_princ, ap); 518} 519 520 521krb5_error_code 522krb5_build_principal_ext(krb5_context context, 523 krb5_principal *principal, 524 int rlen, 525 krb5_const_realm realm, 526 ...) 527{ 528 krb5_error_code ret; 529 va_list ap; 530 va_start(ap, realm); 531 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap); 532 va_end(ap); 533 return ret; 534} 535 536 537krb5_error_code 538krb5_copy_principal(krb5_context context, 539 krb5_const_principal inprinc, 540 krb5_principal *outprinc) 541{ 542 krb5_principal p = malloc(sizeof(*p)); 543 if (p == NULL) { 544 krb5_set_error_string (context, "malloc: out of memory"); 545 return ENOMEM; 546 } 547 if(copy_Principal(inprinc, p)) { 548 free(p); 549 krb5_set_error_string (context, "malloc: out of memory"); 550 return ENOMEM; 551 } 552 *outprinc = p; 553 return 0; 554} 555 556/* 557 * return TRUE iff princ1 == princ2 (without considering the realm) 558 */ 559 560krb5_boolean 561krb5_principal_compare_any_realm(krb5_context context, 562 krb5_const_principal princ1, 563 krb5_const_principal princ2) 564{ 565 int i; 566 if(princ_num_comp(princ1) != princ_num_comp(princ2)) 567 return FALSE; 568 for(i = 0; i < princ_num_comp(princ1); i++){ 569 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0) 570 return FALSE; 571 } 572 return TRUE; 573} 574 575/* 576 * return TRUE iff princ1 == princ2 577 */ 578 579krb5_boolean 580krb5_principal_compare(krb5_context context, 581 krb5_const_principal princ1, 582 krb5_const_principal princ2) 583{ 584 if(!krb5_realm_compare(context, princ1, princ2)) 585 return FALSE; 586 return krb5_principal_compare_any_realm(context, princ1, princ2); 587} 588 589/* 590 * return TRUE iff realm(princ1) == realm(princ2) 591 */ 592 593krb5_boolean 594krb5_realm_compare(krb5_context context, 595 krb5_const_principal princ1, 596 krb5_const_principal princ2) 597{ 598 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0; 599} 600 601/* 602 * return TRUE iff princ matches pattern 603 */ 604 605krb5_boolean 606krb5_principal_match(krb5_context context, 607 krb5_const_principal princ, 608 krb5_const_principal pattern) 609{ 610 int i; 611 if(princ_num_comp(princ) != princ_num_comp(pattern)) 612 return FALSE; 613 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0) 614 return FALSE; 615 for(i = 0; i < princ_num_comp(princ); i++){ 616 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0) 617 return FALSE; 618 } 619 return TRUE; 620} 621 622 623struct v4_name_convert { 624 const char *from; 625 const char *to; 626} default_v4_name_convert[] = { 627 { "ftp", "ftp" }, 628 { "hprop", "hprop" }, 629 { "pop", "pop" }, 630 { "imap", "imap" }, 631 { "rcmd", "host" }, 632 { "smtp", "smtp" }, 633 { NULL, NULL } 634}; 635 636/* 637 * return the converted instance name of `name' in `realm'. 638 * look in the configuration file and then in the default set above. 639 * return NULL if no conversion is appropriate. 640 */ 641 642static const char* 643get_name_conversion(krb5_context context, const char *realm, const char *name) 644{ 645 struct v4_name_convert *q; 646 const char *p; 647 648 p = krb5_config_get_string(context, NULL, "realms", realm, 649 "v4_name_convert", "host", name, NULL); 650 if(p == NULL) 651 p = krb5_config_get_string(context, NULL, "libdefaults", 652 "v4_name_convert", "host", name, NULL); 653 if(p) 654 return p; 655 656 /* XXX should be possible to override default list */ 657 p = krb5_config_get_string(context, NULL, 658 "realms", 659 realm, 660 "v4_name_convert", 661 "plain", 662 name, 663 NULL); 664 if(p) 665 return NULL; 666 p = krb5_config_get_string(context, NULL, 667 "libdefaults", 668 "v4_name_convert", 669 "plain", 670 name, 671 NULL); 672 if(p) 673 return NULL; 674 for(q = default_v4_name_convert; q->from; q++) 675 if(strcmp(q->from, name) == 0) 676 return q->to; 677 return NULL; 678} 679 680/* 681 * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'. 682 * if `resolve', use DNS. 683 * if `func', use that function for validating the conversion 684 */ 685 686krb5_error_code 687krb5_425_conv_principal_ext(krb5_context context, 688 const char *name, 689 const char *instance, 690 const char *realm, 691 krb5_boolean (*func)(krb5_context, krb5_principal), 692 krb5_boolean resolve, 693 krb5_principal *princ) 694{ 695 const char *p; 696 krb5_error_code ret; 697 krb5_principal pr; 698 char host[MAXHOSTNAMELEN]; 699 char local_hostname[MAXHOSTNAMELEN]; 700 701 /* do the following: if the name is found in the 702 `v4_name_convert:host' part, is is assumed to be a `host' type 703 principal, and the instance is looked up in the 704 `v4_instance_convert' part. if not found there the name is 705 (optionally) looked up as a hostname, and if that doesn't yield 706 anything, the `default_domain' is appended to the instance 707 */ 708 709 if(instance == NULL) 710 goto no_host; 711 if(instance[0] == 0){ 712 instance = NULL; 713 goto no_host; 714 } 715 p = get_name_conversion(context, realm, name); 716 if(p == NULL) 717 goto no_host; 718 name = p; 719 p = krb5_config_get_string(context, NULL, "realms", realm, 720 "v4_instance_convert", instance, NULL); 721 if(p){ 722 instance = p; 723 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 724 if(func == NULL || (*func)(context, pr)){ 725 *princ = pr; 726 return 0; 727 } 728 krb5_free_principal(context, pr); 729 *princ = NULL; 730 krb5_clear_error_string (context); 731 return HEIM_ERR_V4_PRINC_NO_CONV; 732 } 733 if(resolve){ 734 krb5_boolean passed = FALSE; 735 char *inst = NULL; 736#ifdef USE_RESOLVER 737 struct dns_reply *r; 738 739 r = dns_lookup(instance, "aaaa"); 740 if (r && r->head && r->head->type == T_AAAA) { 741 inst = strdup(r->head->domain); 742 dns_free_data(r); 743 passed = TRUE; 744 } else { 745 r = dns_lookup(instance, "a"); 746 if(r && r->head && r->head->type == T_A) { 747 inst = strdup(r->head->domain); 748 dns_free_data(r); 749 passed = TRUE; 750 } 751 } 752#else 753 struct addrinfo hints, *ai; 754 int ret; 755 756 memset (&hints, 0, sizeof(hints)); 757 hints.ai_flags = AI_CANONNAME; 758 ret = getaddrinfo(instance, NULL, &hints, &ai); 759 if (ret == 0) { 760 const struct addrinfo *a; 761 for (a = ai; a != NULL; a = a->ai_next) { 762 if (a->ai_canonname != NULL) { 763 inst = strdup (a->ai_canonname); 764 passed = TRUE; 765 break; 766 } 767 } 768 freeaddrinfo (ai); 769 } 770#endif 771 if (passed) { 772 if (inst == NULL) { 773 krb5_set_error_string (context, "malloc: out of memory"); 774 return ENOMEM; 775 } 776 strlwr(inst); 777 ret = krb5_make_principal(context, &pr, realm, name, inst, 778 NULL); 779 free (inst); 780 if(ret == 0) { 781 if(func == NULL || (*func)(context, pr)){ 782 *princ = pr; 783 return 0; 784 } 785 krb5_free_principal(context, pr); 786 } 787 } 788 } 789 if(func != NULL) { 790 snprintf(host, sizeof(host), "%s.%s", instance, realm); 791 strlwr(host); 792 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 793 if((*func)(context, pr)){ 794 *princ = pr; 795 return 0; 796 } 797 krb5_free_principal(context, pr); 798 } 799 800 /* 801 * if the instance is the first component of the local hostname, 802 * the converted host should be the long hostname. 803 */ 804 805 if (func == NULL && 806 gethostname (local_hostname, sizeof(local_hostname)) == 0 && 807 strncmp(instance, local_hostname, strlen(instance)) == 0 && 808 local_hostname[strlen(instance)] == '.') { 809 strlcpy(host, local_hostname, sizeof(host)); 810 goto local_host; 811 } 812 813 { 814 char **domains, **d; 815 domains = krb5_config_get_strings(context, NULL, "realms", realm, 816 "v4_domains", NULL); 817 for(d = domains; d && *d; d++){ 818 snprintf(host, sizeof(host), "%s.%s", instance, *d); 819 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 820 if(func == NULL || (*func)(context, pr)){ 821 *princ = pr; 822 krb5_config_free_strings(domains); 823 return 0; 824 } 825 krb5_free_principal(context, pr); 826 } 827 krb5_config_free_strings(domains); 828 } 829 830 831 p = krb5_config_get_string(context, NULL, "realms", realm, 832 "default_domain", NULL); 833 if(p == NULL){ 834 /* this should be an error, just faking a name is not good */ 835 krb5_clear_error_string (context); 836 return HEIM_ERR_V4_PRINC_NO_CONV; 837 } 838 839 if (*p == '.') 840 ++p; 841 snprintf(host, sizeof(host), "%s.%s", instance, p); 842local_host: 843 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 844 if(func == NULL || (*func)(context, pr)){ 845 *princ = pr; 846 return 0; 847 } 848 krb5_free_principal(context, pr); 849 krb5_clear_error_string (context); 850 return HEIM_ERR_V4_PRINC_NO_CONV; 851no_host: 852 p = krb5_config_get_string(context, NULL, 853 "realms", 854 realm, 855 "v4_name_convert", 856 "plain", 857 name, 858 NULL); 859 if(p == NULL) 860 p = krb5_config_get_string(context, NULL, 861 "libdefaults", 862 "v4_name_convert", 863 "plain", 864 name, 865 NULL); 866 if(p) 867 name = p; 868 869 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 870 if(func == NULL || (*func)(context, pr)){ 871 *princ = pr; 872 return 0; 873 } 874 krb5_free_principal(context, pr); 875 krb5_clear_error_string (context); 876 return HEIM_ERR_V4_PRINC_NO_CONV; 877} 878 879krb5_error_code 880krb5_425_conv_principal(krb5_context context, 881 const char *name, 882 const char *instance, 883 const char *realm, 884 krb5_principal *princ) 885{ 886 krb5_boolean resolve = krb5_config_get_bool(context, 887 NULL, 888 "libdefaults", 889 "v4_instance_resolve", 890 NULL); 891 892 return krb5_425_conv_principal_ext(context, name, instance, realm, 893 NULL, resolve, princ); 894} 895 896 897static int 898check_list(const krb5_config_binding *l, const char *name, const char **out) 899{ 900 while(l){ 901 if (l->type != krb5_config_string) 902 continue; 903 if(strcmp(name, l->u.string) == 0) { 904 *out = l->name; 905 return 1; 906 } 907 l = l->next; 908 } 909 return 0; 910} 911 912static int 913name_convert(krb5_context context, const char *name, const char *realm, 914 const char **out) 915{ 916 const krb5_config_binding *l; 917 l = krb5_config_get_list (context, 918 NULL, 919 "realms", 920 realm, 921 "v4_name_convert", 922 "host", 923 NULL); 924 if(l && check_list(l, name, out)) 925 return KRB5_NT_SRV_HST; 926 l = krb5_config_get_list (context, 927 NULL, 928 "libdefaults", 929 "v4_name_convert", 930 "host", 931 NULL); 932 if(l && check_list(l, name, out)) 933 return KRB5_NT_SRV_HST; 934 l = krb5_config_get_list (context, 935 NULL, 936 "realms", 937 realm, 938 "v4_name_convert", 939 "plain", 940 NULL); 941 if(l && check_list(l, name, out)) 942 return KRB5_NT_UNKNOWN; 943 l = krb5_config_get_list (context, 944 NULL, 945 "libdefaults", 946 "v4_name_convert", 947 "host", 948 NULL); 949 if(l && check_list(l, name, out)) 950 return KRB5_NT_UNKNOWN; 951 952 /* didn't find it in config file, try built-in list */ 953 { 954 struct v4_name_convert *q; 955 for(q = default_v4_name_convert; q->from; q++) { 956 if(strcmp(name, q->to) == 0) { 957 *out = q->from; 958 return KRB5_NT_SRV_HST; 959 } 960 } 961 } 962 return -1; 963} 964 965/* 966 * convert the v5 principal in `principal' into a v4 corresponding one 967 * in `name, instance, realm' 968 * this is limited interface since there's no length given for these 969 * three parameters. They have to be 40 bytes each (ANAME_SZ). 970 */ 971 972krb5_error_code 973krb5_524_conv_principal(krb5_context context, 974 const krb5_principal principal, 975 char *name, 976 char *instance, 977 char *realm) 978{ 979 const char *n, *i, *r; 980 char tmpinst[40]; 981 int type = princ_type(principal); 982 const int aname_sz = 40; 983 984 r = principal->realm; 985 986 switch(principal->name.name_string.len){ 987 case 1: 988 n = principal->name.name_string.val[0]; 989 i = ""; 990 break; 991 case 2: 992 n = principal->name.name_string.val[0]; 993 i = principal->name.name_string.val[1]; 994 break; 995 default: 996 krb5_set_error_string (context, 997 "cannot convert a %d component principal", 998 principal->name.name_string.len); 999 return KRB5_PARSE_MALFORMED; 1000 } 1001 1002 { 1003 const char *tmp; 1004 int t = name_convert(context, n, r, &tmp); 1005 if(t >= 0) { 1006 type = t; 1007 n = tmp; 1008 } 1009 } 1010 1011 if(type == KRB5_NT_SRV_HST){ 1012 char *p; 1013 1014 strlcpy (tmpinst, i, sizeof(tmpinst)); 1015 p = strchr(tmpinst, '.'); 1016 if(p) 1017 *p = 0; 1018 i = tmpinst; 1019 } 1020 1021 if (strlcpy (name, n, aname_sz) >= aname_sz) { 1022 krb5_set_error_string (context, 1023 "too long name component to convert"); 1024 return KRB5_PARSE_MALFORMED; 1025 } 1026 if (strlcpy (instance, i, aname_sz) >= aname_sz) { 1027 krb5_set_error_string (context, 1028 "too long instance component to convert"); 1029 return KRB5_PARSE_MALFORMED; 1030 } 1031 if (strlcpy (realm, r, aname_sz) >= aname_sz) { 1032 krb5_set_error_string (context, 1033 "too long realm component to convert"); 1034 return KRB5_PARSE_MALFORMED; 1035 } 1036 return 0; 1037} 1038 1039/* 1040 * Create a principal in `ret_princ' for the service `sname' running 1041 * on host `hostname'. */ 1042 1043krb5_error_code 1044krb5_sname_to_principal (krb5_context context, 1045 const char *hostname, 1046 const char *sname, 1047 int32_t type, 1048 krb5_principal *ret_princ) 1049{ 1050 krb5_error_code ret; 1051 char localhost[MAXHOSTNAMELEN]; 1052 char **realms, *host = NULL; 1053 1054 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) { 1055 krb5_set_error_string (context, "unsupported name type %d", 1056 type); 1057 return KRB5_SNAME_UNSUPP_NAMETYPE; 1058 } 1059 if(hostname == NULL) { 1060 gethostname(localhost, sizeof(localhost)); 1061 hostname = localhost; 1062 } 1063 if(sname == NULL) 1064 sname = "host"; 1065 if(type == KRB5_NT_SRV_HST) { 1066 ret = krb5_expand_hostname_realms (context, hostname, 1067 &host, &realms); 1068 if (ret) 1069 return ret; 1070 strlwr(host); 1071 hostname = host; 1072 } else { 1073 ret = krb5_get_host_realm(context, hostname, &realms); 1074 if(ret) 1075 return ret; 1076 } 1077 1078 ret = krb5_make_principal(context, ret_princ, realms[0], sname, 1079 hostname, NULL); 1080 if(host) 1081 free(host); 1082 krb5_free_host_realm(context, realms); 1083 return ret; 1084}
| 45 46#define princ_num_comp(P) ((P)->name.name_string.len) 47#define princ_type(P) ((P)->name.name_type) 48#define princ_comp(P) ((P)->name.name_string.val) 49#define princ_ncomp(P, N) ((P)->name.name_string.val[(N)]) 50#define princ_realm(P) ((P)->realm) 51 52void 53krb5_free_principal(krb5_context context, 54 krb5_principal p) 55{ 56 if(p){ 57 free_Principal(p); 58 free(p); 59 } 60} 61 62int 63krb5_principal_get_type(krb5_context context, 64 krb5_principal principal) 65{ 66 return princ_type(principal); 67} 68 69const char * 70krb5_principal_get_realm(krb5_context context, 71 krb5_principal principal) 72{ 73 return princ_realm(principal); 74} 75 76const char * 77krb5_principal_get_comp_string(krb5_context context, 78 krb5_principal principal, 79 unsigned int component) 80{ 81 if(component >= princ_num_comp(principal)) 82 return NULL; 83 return princ_ncomp(principal, component); 84} 85 86krb5_error_code 87krb5_parse_name(krb5_context context, 88 const char *name, 89 krb5_principal *principal) 90{ 91 krb5_error_code ret; 92 general_string *comp; 93 general_string realm; 94 int ncomp; 95 96 const char *p; 97 char *q; 98 char *s; 99 char *start; 100 101 int n; 102 char c; 103 int got_realm = 0; 104 105 /* count number of component */ 106 ncomp = 1; 107 for(p = name; *p; p++){ 108 if(*p=='\\'){ 109 if(!p[1]) { 110 krb5_set_error_string (context, 111 "trailing \\ in principal name"); 112 return KRB5_PARSE_MALFORMED; 113 } 114 p++; 115 } else if(*p == '/') 116 ncomp++; 117 } 118 comp = calloc(ncomp, sizeof(*comp)); 119 if (comp == NULL) { 120 krb5_set_error_string (context, "malloc: out of memory"); 121 return ENOMEM; 122 } 123 124 n = 0; 125 p = start = q = s = strdup(name); 126 if (start == NULL) { 127 free (comp); 128 krb5_set_error_string (context, "malloc: out of memory"); 129 return ENOMEM; 130 } 131 while(*p){ 132 c = *p++; 133 if(c == '\\'){ 134 c = *p++; 135 if(c == 'n') 136 c = '\n'; 137 else if(c == 't') 138 c = '\t'; 139 else if(c == 'b') 140 c = '\b'; 141 else if(c == '0') 142 c = '\0'; 143 else if(c == '\0') { 144 krb5_set_error_string (context, 145 "trailing \\ in principal name"); 146 ret = KRB5_PARSE_MALFORMED; 147 goto exit; 148 } 149 }else if(c == '/' || c == '@'){ 150 if(got_realm){ 151 krb5_set_error_string (context, 152 "part after realm in principal name"); 153 ret = KRB5_PARSE_MALFORMED; 154 goto exit; 155 }else{ 156 comp[n] = malloc(q - start + 1); 157 if (comp[n] == NULL) { 158 krb5_set_error_string (context, "malloc: out of memory"); 159 ret = ENOMEM; 160 goto exit; 161 } 162 memcpy(comp[n], start, q - start); 163 comp[n][q - start] = 0; 164 n++; 165 } 166 if(c == '@') 167 got_realm = 1; 168 start = q; 169 continue; 170 } 171 if(got_realm && (c == ':' || c == '/' || c == '\0')) { 172 krb5_set_error_string (context, 173 "part after realm in principal name"); 174 ret = KRB5_PARSE_MALFORMED; 175 goto exit; 176 } 177 *q++ = c; 178 } 179 if(got_realm){ 180 realm = malloc(q - start + 1); 181 if (realm == NULL) { 182 krb5_set_error_string (context, "malloc: out of memory"); 183 ret = ENOMEM; 184 goto exit; 185 } 186 memcpy(realm, start, q - start); 187 realm[q - start] = 0; 188 }else{ 189 ret = krb5_get_default_realm (context, &realm); 190 if (ret) 191 goto exit; 192 193 comp[n] = malloc(q - start + 1); 194 if (comp[n] == NULL) { 195 krb5_set_error_string (context, "malloc: out of memory"); 196 ret = ENOMEM; 197 goto exit; 198 } 199 memcpy(comp[n], start, q - start); 200 comp[n][q - start] = 0; 201 n++; 202 } 203 *principal = malloc(sizeof(**principal)); 204 if (*principal == NULL) { 205 krb5_set_error_string (context, "malloc: out of memory"); 206 ret = ENOMEM; 207 goto exit; 208 } 209 (*principal)->name.name_type = KRB5_NT_PRINCIPAL; 210 (*principal)->name.name_string.val = comp; 211 princ_num_comp(*principal) = n; 212 (*principal)->realm = realm; 213 free(s); 214 return 0; 215exit: 216 while(n>0){ 217 free(comp[--n]); 218 } 219 free(comp); 220 free(s); 221 return ret; 222} 223 224static const char quotable_chars[] = " \n\t\b\\/@"; 225static const char replace_chars[] = " ntb\\/@"; 226 227#define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0); 228 229static size_t 230quote_string(const char *s, char *out, size_t index, size_t len) 231{ 232 const char *p, *q; 233 for(p = s; *p && index < len; p++){ 234 if((q = strchr(quotable_chars, *p))){ 235 add_char(out, index, len, '\\'); 236 add_char(out, index, len, replace_chars[q - quotable_chars]); 237 }else 238 add_char(out, index, len, *p); 239 } 240 if(index < len) 241 out[index] = '\0'; 242 return index; 243} 244 245 246static krb5_error_code 247unparse_name_fixed(krb5_context context, 248 krb5_const_principal principal, 249 char *name, 250 size_t len, 251 krb5_boolean short_form) 252{ 253 size_t index = 0; 254 int i; 255 for(i = 0; i < princ_num_comp(principal); i++){ 256 if(i) 257 add_char(name, index, len, '/'); 258 index = quote_string(princ_ncomp(principal, i), name, index, len); 259 if(index == len) 260 return ERANGE; 261 } 262 /* add realm if different from default realm */ 263 if(short_form) { 264 krb5_realm r; 265 krb5_error_code ret; 266 ret = krb5_get_default_realm(context, &r); 267 if(ret) 268 return ret; 269 if(strcmp(princ_realm(principal), r) != 0) 270 short_form = 0; 271 free(r); 272 } 273 if(!short_form) { 274 add_char(name, index, len, '@'); 275 index = quote_string(princ_realm(principal), name, index, len); 276 if(index == len) 277 return ERANGE; 278 } 279 return 0; 280} 281 282krb5_error_code 283krb5_unparse_name_fixed(krb5_context context, 284 krb5_const_principal principal, 285 char *name, 286 size_t len) 287{ 288 return unparse_name_fixed(context, principal, name, len, FALSE); 289} 290 291krb5_error_code 292krb5_unparse_name_fixed_short(krb5_context context, 293 krb5_const_principal principal, 294 char *name, 295 size_t len) 296{ 297 return unparse_name_fixed(context, principal, name, len, TRUE); 298} 299 300static krb5_error_code 301unparse_name(krb5_context context, 302 krb5_const_principal principal, 303 char **name, 304 krb5_boolean short_flag) 305{ 306 size_t len = 0, plen; 307 int i; 308 krb5_error_code ret; 309 /* count length */ 310 plen = strlen(princ_realm(principal)); 311 if(strcspn(princ_realm(principal), quotable_chars) == plen) 312 len += plen; 313 else 314 len += 2*plen; 315 len++; 316 for(i = 0; i < princ_num_comp(principal); i++){ 317 plen = strlen(princ_ncomp(principal, i)); 318 if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen) 319 len += plen; 320 else 321 len += 2*plen; 322 len++; 323 } 324 *name = malloc(len); 325 if(len != 0 && *name == NULL) { 326 krb5_set_error_string (context, "malloc: out of memory"); 327 return ENOMEM; 328 } 329 ret = unparse_name_fixed(context, principal, *name, len, short_flag); 330 if(ret) 331 free(*name); 332 return ret; 333} 334 335krb5_error_code 336krb5_unparse_name(krb5_context context, 337 krb5_const_principal principal, 338 char **name) 339{ 340 return unparse_name(context, principal, name, FALSE); 341} 342 343krb5_error_code 344krb5_unparse_name_short(krb5_context context, 345 krb5_const_principal principal, 346 char **name) 347{ 348 return unparse_name(context, principal, name, TRUE); 349} 350 351#if 0 /* not implemented */ 352 353krb5_error_code 354krb5_unparse_name_ext(krb5_context context, 355 krb5_const_principal principal, 356 char **name, 357 size_t *size) 358{ 359 krb5_abortx(context, "unimplemented krb5_unparse_name_ext called"); 360} 361 362#endif 363 364krb5_realm* 365krb5_princ_realm(krb5_context context, 366 krb5_principal principal) 367{ 368 return &princ_realm(principal); 369} 370 371 372void 373krb5_princ_set_realm(krb5_context context, 374 krb5_principal principal, 375 krb5_realm *realm) 376{ 377 princ_realm(principal) = *realm; 378} 379 380 381krb5_error_code 382krb5_build_principal(krb5_context context, 383 krb5_principal *principal, 384 int rlen, 385 krb5_const_realm realm, 386 ...) 387{ 388 krb5_error_code ret; 389 va_list ap; 390 va_start(ap, realm); 391 ret = krb5_build_principal_va(context, principal, rlen, realm, ap); 392 va_end(ap); 393 return ret; 394} 395 396static krb5_error_code 397append_component(krb5_context context, krb5_principal p, 398 const char *comp, 399 size_t comp_len) 400{ 401 general_string *tmp; 402 size_t len = princ_num_comp(p); 403 404 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp)); 405 if(tmp == NULL) { 406 krb5_set_error_string (context, "malloc: out of memory"); 407 return ENOMEM; 408 } 409 princ_comp(p) = tmp; 410 princ_ncomp(p, len) = malloc(comp_len + 1); 411 if (princ_ncomp(p, len) == NULL) { 412 krb5_set_error_string (context, "malloc: out of memory"); 413 return ENOMEM; 414 } 415 memcpy (princ_ncomp(p, len), comp, comp_len); 416 princ_ncomp(p, len)[comp_len] = '\0'; 417 princ_num_comp(p)++; 418 return 0; 419} 420 421static void 422va_ext_princ(krb5_context context, krb5_principal p, va_list ap) 423{ 424 while(1){ 425 const char *s; 426 int len; 427 len = va_arg(ap, int); 428 if(len == 0) 429 break; 430 s = va_arg(ap, const char*); 431 append_component(context, p, s, len); 432 } 433} 434 435static void 436va_princ(krb5_context context, krb5_principal p, va_list ap) 437{ 438 while(1){ 439 const char *s; 440 s = va_arg(ap, const char*); 441 if(s == NULL) 442 break; 443 append_component(context, p, s, strlen(s)); 444 } 445} 446 447 448static krb5_error_code 449build_principal(krb5_context context, 450 krb5_principal *principal, 451 int rlen, 452 krb5_const_realm realm, 453 void (*func)(krb5_context, krb5_principal, va_list), 454 va_list ap) 455{ 456 krb5_principal p; 457 458 p = calloc(1, sizeof(*p)); 459 if (p == NULL) { 460 krb5_set_error_string (context, "malloc: out of memory"); 461 return ENOMEM; 462 } 463 princ_type(p) = KRB5_NT_PRINCIPAL; 464 465 princ_realm(p) = strdup(realm); 466 if(p->realm == NULL){ 467 free(p); 468 krb5_set_error_string (context, "malloc: out of memory"); 469 return ENOMEM; 470 } 471 472 (*func)(context, p, ap); 473 *principal = p; 474 return 0; 475} 476 477krb5_error_code 478krb5_make_principal(krb5_context context, 479 krb5_principal *principal, 480 krb5_const_realm realm, 481 ...) 482{ 483 krb5_error_code ret; 484 krb5_realm r = NULL; 485 va_list ap; 486 if(realm == NULL) { 487 ret = krb5_get_default_realm(context, &r); 488 if(ret) 489 return ret; 490 realm = r; 491 } 492 va_start(ap, realm); 493 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap); 494 va_end(ap); 495 if(r) 496 free(r); 497 return ret; 498} 499 500krb5_error_code 501krb5_build_principal_va(krb5_context context, 502 krb5_principal *principal, 503 int rlen, 504 krb5_const_realm realm, 505 va_list ap) 506{ 507 return build_principal(context, principal, rlen, realm, va_princ, ap); 508} 509 510krb5_error_code 511krb5_build_principal_va_ext(krb5_context context, 512 krb5_principal *principal, 513 int rlen, 514 krb5_const_realm realm, 515 va_list ap) 516{ 517 return build_principal(context, principal, rlen, realm, va_ext_princ, ap); 518} 519 520 521krb5_error_code 522krb5_build_principal_ext(krb5_context context, 523 krb5_principal *principal, 524 int rlen, 525 krb5_const_realm realm, 526 ...) 527{ 528 krb5_error_code ret; 529 va_list ap; 530 va_start(ap, realm); 531 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap); 532 va_end(ap); 533 return ret; 534} 535 536 537krb5_error_code 538krb5_copy_principal(krb5_context context, 539 krb5_const_principal inprinc, 540 krb5_principal *outprinc) 541{ 542 krb5_principal p = malloc(sizeof(*p)); 543 if (p == NULL) { 544 krb5_set_error_string (context, "malloc: out of memory"); 545 return ENOMEM; 546 } 547 if(copy_Principal(inprinc, p)) { 548 free(p); 549 krb5_set_error_string (context, "malloc: out of memory"); 550 return ENOMEM; 551 } 552 *outprinc = p; 553 return 0; 554} 555 556/* 557 * return TRUE iff princ1 == princ2 (without considering the realm) 558 */ 559 560krb5_boolean 561krb5_principal_compare_any_realm(krb5_context context, 562 krb5_const_principal princ1, 563 krb5_const_principal princ2) 564{ 565 int i; 566 if(princ_num_comp(princ1) != princ_num_comp(princ2)) 567 return FALSE; 568 for(i = 0; i < princ_num_comp(princ1); i++){ 569 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0) 570 return FALSE; 571 } 572 return TRUE; 573} 574 575/* 576 * return TRUE iff princ1 == princ2 577 */ 578 579krb5_boolean 580krb5_principal_compare(krb5_context context, 581 krb5_const_principal princ1, 582 krb5_const_principal princ2) 583{ 584 if(!krb5_realm_compare(context, princ1, princ2)) 585 return FALSE; 586 return krb5_principal_compare_any_realm(context, princ1, princ2); 587} 588 589/* 590 * return TRUE iff realm(princ1) == realm(princ2) 591 */ 592 593krb5_boolean 594krb5_realm_compare(krb5_context context, 595 krb5_const_principal princ1, 596 krb5_const_principal princ2) 597{ 598 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0; 599} 600 601/* 602 * return TRUE iff princ matches pattern 603 */ 604 605krb5_boolean 606krb5_principal_match(krb5_context context, 607 krb5_const_principal princ, 608 krb5_const_principal pattern) 609{ 610 int i; 611 if(princ_num_comp(princ) != princ_num_comp(pattern)) 612 return FALSE; 613 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0) 614 return FALSE; 615 for(i = 0; i < princ_num_comp(princ); i++){ 616 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0) 617 return FALSE; 618 } 619 return TRUE; 620} 621 622 623struct v4_name_convert { 624 const char *from; 625 const char *to; 626} default_v4_name_convert[] = { 627 { "ftp", "ftp" }, 628 { "hprop", "hprop" }, 629 { "pop", "pop" }, 630 { "imap", "imap" }, 631 { "rcmd", "host" }, 632 { "smtp", "smtp" }, 633 { NULL, NULL } 634}; 635 636/* 637 * return the converted instance name of `name' in `realm'. 638 * look in the configuration file and then in the default set above. 639 * return NULL if no conversion is appropriate. 640 */ 641 642static const char* 643get_name_conversion(krb5_context context, const char *realm, const char *name) 644{ 645 struct v4_name_convert *q; 646 const char *p; 647 648 p = krb5_config_get_string(context, NULL, "realms", realm, 649 "v4_name_convert", "host", name, NULL); 650 if(p == NULL) 651 p = krb5_config_get_string(context, NULL, "libdefaults", 652 "v4_name_convert", "host", name, NULL); 653 if(p) 654 return p; 655 656 /* XXX should be possible to override default list */ 657 p = krb5_config_get_string(context, NULL, 658 "realms", 659 realm, 660 "v4_name_convert", 661 "plain", 662 name, 663 NULL); 664 if(p) 665 return NULL; 666 p = krb5_config_get_string(context, NULL, 667 "libdefaults", 668 "v4_name_convert", 669 "plain", 670 name, 671 NULL); 672 if(p) 673 return NULL; 674 for(q = default_v4_name_convert; q->from; q++) 675 if(strcmp(q->from, name) == 0) 676 return q->to; 677 return NULL; 678} 679 680/* 681 * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'. 682 * if `resolve', use DNS. 683 * if `func', use that function for validating the conversion 684 */ 685 686krb5_error_code 687krb5_425_conv_principal_ext(krb5_context context, 688 const char *name, 689 const char *instance, 690 const char *realm, 691 krb5_boolean (*func)(krb5_context, krb5_principal), 692 krb5_boolean resolve, 693 krb5_principal *princ) 694{ 695 const char *p; 696 krb5_error_code ret; 697 krb5_principal pr; 698 char host[MAXHOSTNAMELEN]; 699 char local_hostname[MAXHOSTNAMELEN]; 700 701 /* do the following: if the name is found in the 702 `v4_name_convert:host' part, is is assumed to be a `host' type 703 principal, and the instance is looked up in the 704 `v4_instance_convert' part. if not found there the name is 705 (optionally) looked up as a hostname, and if that doesn't yield 706 anything, the `default_domain' is appended to the instance 707 */ 708 709 if(instance == NULL) 710 goto no_host; 711 if(instance[0] == 0){ 712 instance = NULL; 713 goto no_host; 714 } 715 p = get_name_conversion(context, realm, name); 716 if(p == NULL) 717 goto no_host; 718 name = p; 719 p = krb5_config_get_string(context, NULL, "realms", realm, 720 "v4_instance_convert", instance, NULL); 721 if(p){ 722 instance = p; 723 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 724 if(func == NULL || (*func)(context, pr)){ 725 *princ = pr; 726 return 0; 727 } 728 krb5_free_principal(context, pr); 729 *princ = NULL; 730 krb5_clear_error_string (context); 731 return HEIM_ERR_V4_PRINC_NO_CONV; 732 } 733 if(resolve){ 734 krb5_boolean passed = FALSE; 735 char *inst = NULL; 736#ifdef USE_RESOLVER 737 struct dns_reply *r; 738 739 r = dns_lookup(instance, "aaaa"); 740 if (r && r->head && r->head->type == T_AAAA) { 741 inst = strdup(r->head->domain); 742 dns_free_data(r); 743 passed = TRUE; 744 } else { 745 r = dns_lookup(instance, "a"); 746 if(r && r->head && r->head->type == T_A) { 747 inst = strdup(r->head->domain); 748 dns_free_data(r); 749 passed = TRUE; 750 } 751 } 752#else 753 struct addrinfo hints, *ai; 754 int ret; 755 756 memset (&hints, 0, sizeof(hints)); 757 hints.ai_flags = AI_CANONNAME; 758 ret = getaddrinfo(instance, NULL, &hints, &ai); 759 if (ret == 0) { 760 const struct addrinfo *a; 761 for (a = ai; a != NULL; a = a->ai_next) { 762 if (a->ai_canonname != NULL) { 763 inst = strdup (a->ai_canonname); 764 passed = TRUE; 765 break; 766 } 767 } 768 freeaddrinfo (ai); 769 } 770#endif 771 if (passed) { 772 if (inst == NULL) { 773 krb5_set_error_string (context, "malloc: out of memory"); 774 return ENOMEM; 775 } 776 strlwr(inst); 777 ret = krb5_make_principal(context, &pr, realm, name, inst, 778 NULL); 779 free (inst); 780 if(ret == 0) { 781 if(func == NULL || (*func)(context, pr)){ 782 *princ = pr; 783 return 0; 784 } 785 krb5_free_principal(context, pr); 786 } 787 } 788 } 789 if(func != NULL) { 790 snprintf(host, sizeof(host), "%s.%s", instance, realm); 791 strlwr(host); 792 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 793 if((*func)(context, pr)){ 794 *princ = pr; 795 return 0; 796 } 797 krb5_free_principal(context, pr); 798 } 799 800 /* 801 * if the instance is the first component of the local hostname, 802 * the converted host should be the long hostname. 803 */ 804 805 if (func == NULL && 806 gethostname (local_hostname, sizeof(local_hostname)) == 0 && 807 strncmp(instance, local_hostname, strlen(instance)) == 0 && 808 local_hostname[strlen(instance)] == '.') { 809 strlcpy(host, local_hostname, sizeof(host)); 810 goto local_host; 811 } 812 813 { 814 char **domains, **d; 815 domains = krb5_config_get_strings(context, NULL, "realms", realm, 816 "v4_domains", NULL); 817 for(d = domains; d && *d; d++){ 818 snprintf(host, sizeof(host), "%s.%s", instance, *d); 819 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 820 if(func == NULL || (*func)(context, pr)){ 821 *princ = pr; 822 krb5_config_free_strings(domains); 823 return 0; 824 } 825 krb5_free_principal(context, pr); 826 } 827 krb5_config_free_strings(domains); 828 } 829 830 831 p = krb5_config_get_string(context, NULL, "realms", realm, 832 "default_domain", NULL); 833 if(p == NULL){ 834 /* this should be an error, just faking a name is not good */ 835 krb5_clear_error_string (context); 836 return HEIM_ERR_V4_PRINC_NO_CONV; 837 } 838 839 if (*p == '.') 840 ++p; 841 snprintf(host, sizeof(host), "%s.%s", instance, p); 842local_host: 843 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 844 if(func == NULL || (*func)(context, pr)){ 845 *princ = pr; 846 return 0; 847 } 848 krb5_free_principal(context, pr); 849 krb5_clear_error_string (context); 850 return HEIM_ERR_V4_PRINC_NO_CONV; 851no_host: 852 p = krb5_config_get_string(context, NULL, 853 "realms", 854 realm, 855 "v4_name_convert", 856 "plain", 857 name, 858 NULL); 859 if(p == NULL) 860 p = krb5_config_get_string(context, NULL, 861 "libdefaults", 862 "v4_name_convert", 863 "plain", 864 name, 865 NULL); 866 if(p) 867 name = p; 868 869 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 870 if(func == NULL || (*func)(context, pr)){ 871 *princ = pr; 872 return 0; 873 } 874 krb5_free_principal(context, pr); 875 krb5_clear_error_string (context); 876 return HEIM_ERR_V4_PRINC_NO_CONV; 877} 878 879krb5_error_code 880krb5_425_conv_principal(krb5_context context, 881 const char *name, 882 const char *instance, 883 const char *realm, 884 krb5_principal *princ) 885{ 886 krb5_boolean resolve = krb5_config_get_bool(context, 887 NULL, 888 "libdefaults", 889 "v4_instance_resolve", 890 NULL); 891 892 return krb5_425_conv_principal_ext(context, name, instance, realm, 893 NULL, resolve, princ); 894} 895 896 897static int 898check_list(const krb5_config_binding *l, const char *name, const char **out) 899{ 900 while(l){ 901 if (l->type != krb5_config_string) 902 continue; 903 if(strcmp(name, l->u.string) == 0) { 904 *out = l->name; 905 return 1; 906 } 907 l = l->next; 908 } 909 return 0; 910} 911 912static int 913name_convert(krb5_context context, const char *name, const char *realm, 914 const char **out) 915{ 916 const krb5_config_binding *l; 917 l = krb5_config_get_list (context, 918 NULL, 919 "realms", 920 realm, 921 "v4_name_convert", 922 "host", 923 NULL); 924 if(l && check_list(l, name, out)) 925 return KRB5_NT_SRV_HST; 926 l = krb5_config_get_list (context, 927 NULL, 928 "libdefaults", 929 "v4_name_convert", 930 "host", 931 NULL); 932 if(l && check_list(l, name, out)) 933 return KRB5_NT_SRV_HST; 934 l = krb5_config_get_list (context, 935 NULL, 936 "realms", 937 realm, 938 "v4_name_convert", 939 "plain", 940 NULL); 941 if(l && check_list(l, name, out)) 942 return KRB5_NT_UNKNOWN; 943 l = krb5_config_get_list (context, 944 NULL, 945 "libdefaults", 946 "v4_name_convert", 947 "host", 948 NULL); 949 if(l && check_list(l, name, out)) 950 return KRB5_NT_UNKNOWN; 951 952 /* didn't find it in config file, try built-in list */ 953 { 954 struct v4_name_convert *q; 955 for(q = default_v4_name_convert; q->from; q++) { 956 if(strcmp(name, q->to) == 0) { 957 *out = q->from; 958 return KRB5_NT_SRV_HST; 959 } 960 } 961 } 962 return -1; 963} 964 965/* 966 * convert the v5 principal in `principal' into a v4 corresponding one 967 * in `name, instance, realm' 968 * this is limited interface since there's no length given for these 969 * three parameters. They have to be 40 bytes each (ANAME_SZ). 970 */ 971 972krb5_error_code 973krb5_524_conv_principal(krb5_context context, 974 const krb5_principal principal, 975 char *name, 976 char *instance, 977 char *realm) 978{ 979 const char *n, *i, *r; 980 char tmpinst[40]; 981 int type = princ_type(principal); 982 const int aname_sz = 40; 983 984 r = principal->realm; 985 986 switch(principal->name.name_string.len){ 987 case 1: 988 n = principal->name.name_string.val[0]; 989 i = ""; 990 break; 991 case 2: 992 n = principal->name.name_string.val[0]; 993 i = principal->name.name_string.val[1]; 994 break; 995 default: 996 krb5_set_error_string (context, 997 "cannot convert a %d component principal", 998 principal->name.name_string.len); 999 return KRB5_PARSE_MALFORMED; 1000 } 1001 1002 { 1003 const char *tmp; 1004 int t = name_convert(context, n, r, &tmp); 1005 if(t >= 0) { 1006 type = t; 1007 n = tmp; 1008 } 1009 } 1010 1011 if(type == KRB5_NT_SRV_HST){ 1012 char *p; 1013 1014 strlcpy (tmpinst, i, sizeof(tmpinst)); 1015 p = strchr(tmpinst, '.'); 1016 if(p) 1017 *p = 0; 1018 i = tmpinst; 1019 } 1020 1021 if (strlcpy (name, n, aname_sz) >= aname_sz) { 1022 krb5_set_error_string (context, 1023 "too long name component to convert"); 1024 return KRB5_PARSE_MALFORMED; 1025 } 1026 if (strlcpy (instance, i, aname_sz) >= aname_sz) { 1027 krb5_set_error_string (context, 1028 "too long instance component to convert"); 1029 return KRB5_PARSE_MALFORMED; 1030 } 1031 if (strlcpy (realm, r, aname_sz) >= aname_sz) { 1032 krb5_set_error_string (context, 1033 "too long realm component to convert"); 1034 return KRB5_PARSE_MALFORMED; 1035 } 1036 return 0; 1037} 1038 1039/* 1040 * Create a principal in `ret_princ' for the service `sname' running 1041 * on host `hostname'. */ 1042 1043krb5_error_code 1044krb5_sname_to_principal (krb5_context context, 1045 const char *hostname, 1046 const char *sname, 1047 int32_t type, 1048 krb5_principal *ret_princ) 1049{ 1050 krb5_error_code ret; 1051 char localhost[MAXHOSTNAMELEN]; 1052 char **realms, *host = NULL; 1053 1054 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) { 1055 krb5_set_error_string (context, "unsupported name type %d", 1056 type); 1057 return KRB5_SNAME_UNSUPP_NAMETYPE; 1058 } 1059 if(hostname == NULL) { 1060 gethostname(localhost, sizeof(localhost)); 1061 hostname = localhost; 1062 } 1063 if(sname == NULL) 1064 sname = "host"; 1065 if(type == KRB5_NT_SRV_HST) { 1066 ret = krb5_expand_hostname_realms (context, hostname, 1067 &host, &realms); 1068 if (ret) 1069 return ret; 1070 strlwr(host); 1071 hostname = host; 1072 } else { 1073 ret = krb5_get_host_realm(context, hostname, &realms); 1074 if(ret) 1075 return ret; 1076 } 1077 1078 ret = krb5_make_principal(context, ret_princ, realms[0], sname, 1079 hostname, NULL); 1080 if(host) 1081 free(host); 1082 krb5_free_host_realm(context, realms); 1083 return ret; 1084}
|