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