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.81.2.1 2002/10/21 16:08:25 joda 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 *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 335 krb5_error_code 336 krb5_unparse_name(krb5_context context, 337 krb5_const_principal principal, 338 char **name) 339 { 340 return unparse_name(context, principal, name, FALSE); 341 } 342 343 krb5_error_code 344 krb5_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 353 krb5_error_code 354 krb5_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 364 krb5_realm* 365 krb5_princ_realm(krb5_context context, 366 krb5_principal principal) 367 { 368 return &princ_realm(principal); 369 } 370 371 372 void 373 krb5_princ_set_realm(krb5_context context, 374 krb5_principal principal, 375 krb5_realm *realm) 376 { 377 princ_realm(principal) = *realm; 378 } 379 380 381 krb5_error_code 382 krb5_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 396 static krb5_error_code 397 append_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 421 static void 422 va_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 435 static void 436 va_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 448 static krb5_error_code 449 build_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 477 krb5_error_code 478 krb5_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 500 krb5_error_code 501 krb5_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 510 krb5_error_code 511 krb5_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 521 krb5_error_code 522 krb5_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 537 krb5_error_code 538 krb5_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 560 krb5_boolean 561 krb5_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 579 krb5_boolean 580 krb5_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 593 krb5_boolean 594 krb5_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 605 krb5_boolean 606 krb5_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 623 struct 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 642 static const char* 643 get_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 686 krb5_error_code 687 krb5_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); 842 local_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; 851 no_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 879 krb5_error_code 880 krb5_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 897 static int 898 check_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 912 static int 913 name_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 972 krb5_error_code 973 krb5_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 1043 krb5_error_code 1044 krb5_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 } 1085