1 /* 2 * Copyright (c) 1997-2002 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 #ifdef HAVE_RES_SEARCH 36 #define USE_RESOLVER 37 #endif 38 #ifdef HAVE_ARPA_NAMESER_H 39 #include <arpa/nameser.h> 40 #endif 41 #include <fnmatch.h> 42 #include "resolve.h" 43 44 RCSID("$Id: principal.c,v 1.82.2.1 2003/08/15 14:30:07 lha Exp $"); 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 52 void 53 krb5_free_principal(krb5_context context, 54 krb5_principal p) 55 { 56 if(p){ 57 free_Principal(p); 58 free(p); 59 } 60 } 61 62 int 63 krb5_principal_get_type(krb5_context context, 64 krb5_principal principal) 65 { 66 return princ_type(principal); 67 } 68 69 const char * 70 krb5_principal_get_realm(krb5_context context, 71 krb5_principal principal) 72 { 73 return princ_realm(principal); 74 } 75 76 const char * 77 krb5_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 86 krb5_error_code 87 krb5_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; 215 exit: 216 while(n>0){ 217 free(comp[--n]); 218 } 219 free(comp); 220 free(s); 221 return ret; 222 } 223 224 static const char quotable_chars[] = " \n\t\b\\/@"; 225 static const char replace_chars[] = " ntb\\/@"; 226 227 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0); 228 229 static size_t 230 quote_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 246 static krb5_error_code 247 unparse_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 282 krb5_error_code 283 krb5_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 291 krb5_error_code 292 krb5_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 300 static krb5_error_code 301 unparse_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 len++; 325 *name = malloc(len); 326 if(*name == NULL) { 327 krb5_set_error_string (context, "malloc: out of memory"); 328 return ENOMEM; 329 } 330 ret = unparse_name_fixed(context, principal, *name, len, short_flag); 331 if(ret) { 332 free(*name); 333 *name = NULL; 334 } 335 return ret; 336 } 337 338 krb5_error_code 339 krb5_unparse_name(krb5_context context, 340 krb5_const_principal principal, 341 char **name) 342 { 343 return unparse_name(context, principal, name, FALSE); 344 } 345 346 krb5_error_code 347 krb5_unparse_name_short(krb5_context context, 348 krb5_const_principal principal, 349 char **name) 350 { 351 return unparse_name(context, principal, name, TRUE); 352 } 353 354 #if 0 /* not implemented */ 355 356 krb5_error_code 357 krb5_unparse_name_ext(krb5_context context, 358 krb5_const_principal principal, 359 char **name, 360 size_t *size) 361 { 362 krb5_abortx(context, "unimplemented krb5_unparse_name_ext called"); 363 } 364 365 #endif 366 367 krb5_realm* 368 krb5_princ_realm(krb5_context context, 369 krb5_principal principal) 370 { 371 return &princ_realm(principal); 372 } 373 374 375 void 376 krb5_princ_set_realm(krb5_context context, 377 krb5_principal principal, 378 krb5_realm *realm) 379 { 380 princ_realm(principal) = *realm; 381 } 382 383 384 krb5_error_code 385 krb5_build_principal(krb5_context context, 386 krb5_principal *principal, 387 int rlen, 388 krb5_const_realm realm, 389 ...) 390 { 391 krb5_error_code ret; 392 va_list ap; 393 va_start(ap, realm); 394 ret = krb5_build_principal_va(context, principal, rlen, realm, ap); 395 va_end(ap); 396 return ret; 397 } 398 399 static krb5_error_code 400 append_component(krb5_context context, krb5_principal p, 401 const char *comp, 402 size_t comp_len) 403 { 404 general_string *tmp; 405 size_t len = princ_num_comp(p); 406 407 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp)); 408 if(tmp == NULL) { 409 krb5_set_error_string (context, "malloc: out of memory"); 410 return ENOMEM; 411 } 412 princ_comp(p) = tmp; 413 princ_ncomp(p, len) = malloc(comp_len + 1); 414 if (princ_ncomp(p, len) == NULL) { 415 krb5_set_error_string (context, "malloc: out of memory"); 416 return ENOMEM; 417 } 418 memcpy (princ_ncomp(p, len), comp, comp_len); 419 princ_ncomp(p, len)[comp_len] = '\0'; 420 princ_num_comp(p)++; 421 return 0; 422 } 423 424 static void 425 va_ext_princ(krb5_context context, krb5_principal p, va_list ap) 426 { 427 while(1){ 428 const char *s; 429 int len; 430 len = va_arg(ap, int); 431 if(len == 0) 432 break; 433 s = va_arg(ap, const char*); 434 append_component(context, p, s, len); 435 } 436 } 437 438 static void 439 va_princ(krb5_context context, krb5_principal p, va_list ap) 440 { 441 while(1){ 442 const char *s; 443 s = va_arg(ap, const char*); 444 if(s == NULL) 445 break; 446 append_component(context, p, s, strlen(s)); 447 } 448 } 449 450 451 static krb5_error_code 452 build_principal(krb5_context context, 453 krb5_principal *principal, 454 int rlen, 455 krb5_const_realm realm, 456 void (*func)(krb5_context, krb5_principal, va_list), 457 va_list ap) 458 { 459 krb5_principal p; 460 461 p = calloc(1, sizeof(*p)); 462 if (p == NULL) { 463 krb5_set_error_string (context, "malloc: out of memory"); 464 return ENOMEM; 465 } 466 princ_type(p) = KRB5_NT_PRINCIPAL; 467 468 princ_realm(p) = strdup(realm); 469 if(p->realm == NULL){ 470 free(p); 471 krb5_set_error_string (context, "malloc: out of memory"); 472 return ENOMEM; 473 } 474 475 (*func)(context, p, ap); 476 *principal = p; 477 return 0; 478 } 479 480 krb5_error_code 481 krb5_make_principal(krb5_context context, 482 krb5_principal *principal, 483 krb5_const_realm realm, 484 ...) 485 { 486 krb5_error_code ret; 487 krb5_realm r = NULL; 488 va_list ap; 489 if(realm == NULL) { 490 ret = krb5_get_default_realm(context, &r); 491 if(ret) 492 return ret; 493 realm = r; 494 } 495 va_start(ap, realm); 496 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap); 497 va_end(ap); 498 if(r) 499 free(r); 500 return ret; 501 } 502 503 krb5_error_code 504 krb5_build_principal_va(krb5_context context, 505 krb5_principal *principal, 506 int rlen, 507 krb5_const_realm realm, 508 va_list ap) 509 { 510 return build_principal(context, principal, rlen, realm, va_princ, ap); 511 } 512 513 krb5_error_code 514 krb5_build_principal_va_ext(krb5_context context, 515 krb5_principal *principal, 516 int rlen, 517 krb5_const_realm realm, 518 va_list ap) 519 { 520 return build_principal(context, principal, rlen, realm, va_ext_princ, ap); 521 } 522 523 524 krb5_error_code 525 krb5_build_principal_ext(krb5_context context, 526 krb5_principal *principal, 527 int rlen, 528 krb5_const_realm realm, 529 ...) 530 { 531 krb5_error_code ret; 532 va_list ap; 533 va_start(ap, realm); 534 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap); 535 va_end(ap); 536 return ret; 537 } 538 539 540 krb5_error_code 541 krb5_copy_principal(krb5_context context, 542 krb5_const_principal inprinc, 543 krb5_principal *outprinc) 544 { 545 krb5_principal p = malloc(sizeof(*p)); 546 if (p == NULL) { 547 krb5_set_error_string (context, "malloc: out of memory"); 548 return ENOMEM; 549 } 550 if(copy_Principal(inprinc, p)) { 551 free(p); 552 krb5_set_error_string (context, "malloc: out of memory"); 553 return ENOMEM; 554 } 555 *outprinc = p; 556 return 0; 557 } 558 559 /* 560 * return TRUE iff princ1 == princ2 (without considering the realm) 561 */ 562 563 krb5_boolean 564 krb5_principal_compare_any_realm(krb5_context context, 565 krb5_const_principal princ1, 566 krb5_const_principal princ2) 567 { 568 int i; 569 if(princ_num_comp(princ1) != princ_num_comp(princ2)) 570 return FALSE; 571 for(i = 0; i < princ_num_comp(princ1); i++){ 572 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0) 573 return FALSE; 574 } 575 return TRUE; 576 } 577 578 /* 579 * return TRUE iff princ1 == princ2 580 */ 581 582 krb5_boolean 583 krb5_principal_compare(krb5_context context, 584 krb5_const_principal princ1, 585 krb5_const_principal princ2) 586 { 587 if(!krb5_realm_compare(context, princ1, princ2)) 588 return FALSE; 589 return krb5_principal_compare_any_realm(context, princ1, princ2); 590 } 591 592 /* 593 * return TRUE iff realm(princ1) == realm(princ2) 594 */ 595 596 krb5_boolean 597 krb5_realm_compare(krb5_context context, 598 krb5_const_principal princ1, 599 krb5_const_principal princ2) 600 { 601 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0; 602 } 603 604 /* 605 * return TRUE iff princ matches pattern 606 */ 607 608 krb5_boolean 609 krb5_principal_match(krb5_context context, 610 krb5_const_principal princ, 611 krb5_const_principal pattern) 612 { 613 int i; 614 if(princ_num_comp(princ) != princ_num_comp(pattern)) 615 return FALSE; 616 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0) 617 return FALSE; 618 for(i = 0; i < princ_num_comp(princ); i++){ 619 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0) 620 return FALSE; 621 } 622 return TRUE; 623 } 624 625 626 struct v4_name_convert { 627 const char *from; 628 const char *to; 629 } default_v4_name_convert[] = { 630 { "ftp", "ftp" }, 631 { "hprop", "hprop" }, 632 { "pop", "pop" }, 633 { "imap", "imap" }, 634 { "rcmd", "host" }, 635 { "smtp", "smtp" }, 636 { NULL, NULL } 637 }; 638 639 /* 640 * return the converted instance name of `name' in `realm'. 641 * look in the configuration file and then in the default set above. 642 * return NULL if no conversion is appropriate. 643 */ 644 645 static const char* 646 get_name_conversion(krb5_context context, const char *realm, const char *name) 647 { 648 struct v4_name_convert *q; 649 const char *p; 650 651 p = krb5_config_get_string(context, NULL, "realms", realm, 652 "v4_name_convert", "host", name, NULL); 653 if(p == NULL) 654 p = krb5_config_get_string(context, NULL, "libdefaults", 655 "v4_name_convert", "host", name, NULL); 656 if(p) 657 return p; 658 659 /* XXX should be possible to override default list */ 660 p = krb5_config_get_string(context, NULL, 661 "realms", 662 realm, 663 "v4_name_convert", 664 "plain", 665 name, 666 NULL); 667 if(p) 668 return NULL; 669 p = krb5_config_get_string(context, NULL, 670 "libdefaults", 671 "v4_name_convert", 672 "plain", 673 name, 674 NULL); 675 if(p) 676 return NULL; 677 for(q = default_v4_name_convert; q->from; q++) 678 if(strcmp(q->from, name) == 0) 679 return q->to; 680 return NULL; 681 } 682 683 /* 684 * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'. 685 * if `resolve', use DNS. 686 * if `func', use that function for validating the conversion 687 */ 688 689 krb5_error_code 690 krb5_425_conv_principal_ext(krb5_context context, 691 const char *name, 692 const char *instance, 693 const char *realm, 694 krb5_boolean (*func)(krb5_context, krb5_principal), 695 krb5_boolean resolve, 696 krb5_principal *princ) 697 { 698 const char *p; 699 krb5_error_code ret; 700 krb5_principal pr; 701 char host[MAXHOSTNAMELEN]; 702 char local_hostname[MAXHOSTNAMELEN]; 703 704 /* do the following: if the name is found in the 705 `v4_name_convert:host' part, is is assumed to be a `host' type 706 principal, and the instance is looked up in the 707 `v4_instance_convert' part. if not found there the name is 708 (optionally) looked up as a hostname, and if that doesn't yield 709 anything, the `default_domain' is appended to the instance 710 */ 711 712 if(instance == NULL) 713 goto no_host; 714 if(instance[0] == 0){ 715 instance = NULL; 716 goto no_host; 717 } 718 p = get_name_conversion(context, realm, name); 719 if(p == NULL) 720 goto no_host; 721 name = p; 722 p = krb5_config_get_string(context, NULL, "realms", realm, 723 "v4_instance_convert", instance, NULL); 724 if(p){ 725 instance = p; 726 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 727 if(func == NULL || (*func)(context, pr)){ 728 *princ = pr; 729 return 0; 730 } 731 krb5_free_principal(context, pr); 732 *princ = NULL; 733 krb5_clear_error_string (context); 734 return HEIM_ERR_V4_PRINC_NO_CONV; 735 } 736 if(resolve){ 737 krb5_boolean passed = FALSE; 738 char *inst = NULL; 739 #ifdef USE_RESOLVER 740 struct dns_reply *r; 741 742 r = dns_lookup(instance, "aaaa"); 743 if (r && r->head && r->head->type == T_AAAA) { 744 inst = strdup(r->head->domain); 745 dns_free_data(r); 746 passed = TRUE; 747 } else { 748 r = dns_lookup(instance, "a"); 749 if(r && r->head && r->head->type == T_A) { 750 inst = strdup(r->head->domain); 751 dns_free_data(r); 752 passed = TRUE; 753 } 754 } 755 #else 756 struct addrinfo hints, *ai; 757 int ret; 758 759 memset (&hints, 0, sizeof(hints)); 760 hints.ai_flags = AI_CANONNAME; 761 ret = getaddrinfo(instance, NULL, &hints, &ai); 762 if (ret == 0) { 763 const struct addrinfo *a; 764 for (a = ai; a != NULL; a = a->ai_next) { 765 if (a->ai_canonname != NULL) { 766 inst = strdup (a->ai_canonname); 767 passed = TRUE; 768 break; 769 } 770 } 771 freeaddrinfo (ai); 772 } 773 #endif 774 if (passed) { 775 if (inst == NULL) { 776 krb5_set_error_string (context, "malloc: out of memory"); 777 return ENOMEM; 778 } 779 strlwr(inst); 780 ret = krb5_make_principal(context, &pr, realm, name, inst, 781 NULL); 782 free (inst); 783 if(ret == 0) { 784 if(func == NULL || (*func)(context, pr)){ 785 *princ = pr; 786 return 0; 787 } 788 krb5_free_principal(context, pr); 789 } 790 } 791 } 792 if(func != NULL) { 793 snprintf(host, sizeof(host), "%s.%s", instance, realm); 794 strlwr(host); 795 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 796 if((*func)(context, pr)){ 797 *princ = pr; 798 return 0; 799 } 800 krb5_free_principal(context, pr); 801 } 802 803 /* 804 * if the instance is the first component of the local hostname, 805 * the converted host should be the long hostname. 806 */ 807 808 if (func == NULL && 809 gethostname (local_hostname, sizeof(local_hostname)) == 0 && 810 strncmp(instance, local_hostname, strlen(instance)) == 0 && 811 local_hostname[strlen(instance)] == '.') { 812 strlcpy(host, local_hostname, sizeof(host)); 813 goto local_host; 814 } 815 816 { 817 char **domains, **d; 818 domains = krb5_config_get_strings(context, NULL, "realms", realm, 819 "v4_domains", NULL); 820 for(d = domains; d && *d; d++){ 821 snprintf(host, sizeof(host), "%s.%s", instance, *d); 822 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 823 if(func == NULL || (*func)(context, pr)){ 824 *princ = pr; 825 krb5_config_free_strings(domains); 826 return 0; 827 } 828 krb5_free_principal(context, pr); 829 } 830 krb5_config_free_strings(domains); 831 } 832 833 834 p = krb5_config_get_string(context, NULL, "realms", realm, 835 "default_domain", NULL); 836 if(p == NULL){ 837 /* this should be an error, just faking a name is not good */ 838 krb5_clear_error_string (context); 839 return HEIM_ERR_V4_PRINC_NO_CONV; 840 } 841 842 if (*p == '.') 843 ++p; 844 snprintf(host, sizeof(host), "%s.%s", instance, p); 845 local_host: 846 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 847 if(func == NULL || (*func)(context, pr)){ 848 *princ = pr; 849 return 0; 850 } 851 krb5_free_principal(context, pr); 852 krb5_clear_error_string (context); 853 return HEIM_ERR_V4_PRINC_NO_CONV; 854 no_host: 855 p = krb5_config_get_string(context, NULL, 856 "realms", 857 realm, 858 "v4_name_convert", 859 "plain", 860 name, 861 NULL); 862 if(p == NULL) 863 p = krb5_config_get_string(context, NULL, 864 "libdefaults", 865 "v4_name_convert", 866 "plain", 867 name, 868 NULL); 869 if(p) 870 name = p; 871 872 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 873 if(func == NULL || (*func)(context, pr)){ 874 *princ = pr; 875 return 0; 876 } 877 krb5_free_principal(context, pr); 878 krb5_clear_error_string (context); 879 return HEIM_ERR_V4_PRINC_NO_CONV; 880 } 881 882 krb5_error_code 883 krb5_425_conv_principal(krb5_context context, 884 const char *name, 885 const char *instance, 886 const char *realm, 887 krb5_principal *princ) 888 { 889 krb5_boolean resolve = krb5_config_get_bool(context, 890 NULL, 891 "libdefaults", 892 "v4_instance_resolve", 893 NULL); 894 895 return krb5_425_conv_principal_ext(context, name, instance, realm, 896 NULL, resolve, princ); 897 } 898 899 900 static int 901 check_list(const krb5_config_binding *l, const char *name, const char **out) 902 { 903 while(l){ 904 if (l->type != krb5_config_string) 905 continue; 906 if(strcmp(name, l->u.string) == 0) { 907 *out = l->name; 908 return 1; 909 } 910 l = l->next; 911 } 912 return 0; 913 } 914 915 static int 916 name_convert(krb5_context context, const char *name, const char *realm, 917 const char **out) 918 { 919 const krb5_config_binding *l; 920 l = krb5_config_get_list (context, 921 NULL, 922 "realms", 923 realm, 924 "v4_name_convert", 925 "host", 926 NULL); 927 if(l && check_list(l, name, out)) 928 return KRB5_NT_SRV_HST; 929 l = krb5_config_get_list (context, 930 NULL, 931 "libdefaults", 932 "v4_name_convert", 933 "host", 934 NULL); 935 if(l && check_list(l, name, out)) 936 return KRB5_NT_SRV_HST; 937 l = krb5_config_get_list (context, 938 NULL, 939 "realms", 940 realm, 941 "v4_name_convert", 942 "plain", 943 NULL); 944 if(l && check_list(l, name, out)) 945 return KRB5_NT_UNKNOWN; 946 l = krb5_config_get_list (context, 947 NULL, 948 "libdefaults", 949 "v4_name_convert", 950 "host", 951 NULL); 952 if(l && check_list(l, name, out)) 953 return KRB5_NT_UNKNOWN; 954 955 /* didn't find it in config file, try built-in list */ 956 { 957 struct v4_name_convert *q; 958 for(q = default_v4_name_convert; q->from; q++) { 959 if(strcmp(name, q->to) == 0) { 960 *out = q->from; 961 return KRB5_NT_SRV_HST; 962 } 963 } 964 } 965 return -1; 966 } 967 968 /* 969 * convert the v5 principal in `principal' into a v4 corresponding one 970 * in `name, instance, realm' 971 * this is limited interface since there's no length given for these 972 * three parameters. They have to be 40 bytes each (ANAME_SZ). 973 */ 974 975 krb5_error_code 976 krb5_524_conv_principal(krb5_context context, 977 const krb5_principal principal, 978 char *name, 979 char *instance, 980 char *realm) 981 { 982 const char *n, *i, *r; 983 char tmpinst[40]; 984 int type = princ_type(principal); 985 const int aname_sz = 40; 986 987 r = principal->realm; 988 989 switch(principal->name.name_string.len){ 990 case 1: 991 n = principal->name.name_string.val[0]; 992 i = ""; 993 break; 994 case 2: 995 n = principal->name.name_string.val[0]; 996 i = principal->name.name_string.val[1]; 997 break; 998 default: 999 krb5_set_error_string (context, 1000 "cannot convert a %d component principal", 1001 principal->name.name_string.len); 1002 return KRB5_PARSE_MALFORMED; 1003 } 1004 1005 { 1006 const char *tmp; 1007 int t = name_convert(context, n, r, &tmp); 1008 if(t >= 0) { 1009 type = t; 1010 n = tmp; 1011 } 1012 } 1013 1014 if(type == KRB5_NT_SRV_HST){ 1015 char *p; 1016 1017 strlcpy (tmpinst, i, sizeof(tmpinst)); 1018 p = strchr(tmpinst, '.'); 1019 if(p) 1020 *p = 0; 1021 i = tmpinst; 1022 } 1023 1024 if (strlcpy (name, n, aname_sz) >= aname_sz) { 1025 krb5_set_error_string (context, 1026 "too long name component to convert"); 1027 return KRB5_PARSE_MALFORMED; 1028 } 1029 if (strlcpy (instance, i, aname_sz) >= aname_sz) { 1030 krb5_set_error_string (context, 1031 "too long instance component to convert"); 1032 return KRB5_PARSE_MALFORMED; 1033 } 1034 if (strlcpy (realm, r, aname_sz) >= aname_sz) { 1035 krb5_set_error_string (context, 1036 "too long realm component to convert"); 1037 return KRB5_PARSE_MALFORMED; 1038 } 1039 return 0; 1040 } 1041 1042 /* 1043 * Create a principal in `ret_princ' for the service `sname' running 1044 * on host `hostname'. */ 1045 1046 krb5_error_code 1047 krb5_sname_to_principal (krb5_context context, 1048 const char *hostname, 1049 const char *sname, 1050 int32_t type, 1051 krb5_principal *ret_princ) 1052 { 1053 krb5_error_code ret; 1054 char localhost[MAXHOSTNAMELEN]; 1055 char **realms, *host = NULL; 1056 1057 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) { 1058 krb5_set_error_string (context, "unsupported name type %d", 1059 type); 1060 return KRB5_SNAME_UNSUPP_NAMETYPE; 1061 } 1062 if(hostname == NULL) { 1063 gethostname(localhost, sizeof(localhost)); 1064 hostname = localhost; 1065 } 1066 if(sname == NULL) 1067 sname = "host"; 1068 if(type == KRB5_NT_SRV_HST) { 1069 ret = krb5_expand_hostname_realms (context, hostname, 1070 &host, &realms); 1071 if (ret) 1072 return ret; 1073 strlwr(host); 1074 hostname = host; 1075 } else { 1076 ret = krb5_get_host_realm(context, hostname, &realms); 1077 if(ret) 1078 return ret; 1079 } 1080 1081 ret = krb5_make_principal(context, ret_princ, realms[0], sname, 1082 hostname, NULL); 1083 if(host) 1084 free(host); 1085 krb5_free_host_realm(context, realms); 1086 return ret; 1087 } 1088