1 /* 2 * Copyright (c) 1997-2001 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.78 2001/09/20 09:46:20 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 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 = (char*)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 start = q = p = 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 const char *inst = NULL; 729 #ifdef USE_RESOLVER 730 struct dns_reply *r; 731 r = dns_lookup(instance, "a"); 732 if(r && r->head && r->head->type == T_A) 733 inst = r->head->domain; 734 #else 735 struct hostent *hp = roken_gethostbyname(instance); 736 if(hp) 737 inst = hp->h_name; 738 #endif 739 if(inst) { 740 char *low_inst = strdup(inst); 741 742 if (low_inst == NULL) { 743 #ifdef USE_RESOLVER 744 dns_free_data(r); 745 #endif 746 krb5_set_error_string (context, "malloc: out of memory"); 747 return ENOMEM; 748 } 749 ret = krb5_make_principal(context, &pr, realm, name, low_inst, 750 NULL); 751 free (low_inst); 752 if(ret == 0) { 753 if(func == NULL || (*func)(context, pr)){ 754 *princ = pr; 755 #ifdef USE_RESOLVER 756 dns_free_data(r); 757 #endif 758 return 0; 759 } 760 krb5_free_principal(context, pr); 761 } 762 } 763 #ifdef USE_RESOLVER 764 if(r) 765 dns_free_data(r); 766 #endif 767 } 768 if(func != NULL) { 769 snprintf(host, sizeof(host), "%s.%s", instance, realm); 770 strlwr(host); 771 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 772 if((*func)(context, pr)){ 773 *princ = pr; 774 return 0; 775 } 776 krb5_free_principal(context, pr); 777 } 778 779 /* 780 * if the instance is the first component of the local hostname, 781 * the converted host should be the long hostname. 782 */ 783 784 if (func == NULL && 785 gethostname (local_hostname, sizeof(local_hostname)) == 0 && 786 strncmp(instance, local_hostname, strlen(instance)) == 0 && 787 local_hostname[strlen(instance)] == '.') { 788 strlcpy(host, local_hostname, sizeof(host)); 789 goto local_host; 790 } 791 792 { 793 char **domains, **d; 794 domains = krb5_config_get_strings(context, NULL, "realms", realm, 795 "v4_domains", NULL); 796 for(d = domains; d && *d; d++){ 797 snprintf(host, sizeof(host), "%s.%s", instance, *d); 798 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 799 if(func == NULL || (*func)(context, pr)){ 800 *princ = pr; 801 krb5_config_free_strings(domains); 802 return 0; 803 } 804 krb5_free_principal(context, pr); 805 } 806 krb5_config_free_strings(domains); 807 } 808 809 810 p = krb5_config_get_string(context, NULL, "realms", realm, 811 "default_domain", NULL); 812 if(p == NULL){ 813 /* this should be an error, just faking a name is not good */ 814 krb5_clear_error_string (context); 815 return HEIM_ERR_V4_PRINC_NO_CONV; 816 } 817 818 if (*p == '.') 819 ++p; 820 snprintf(host, sizeof(host), "%s.%s", instance, p); 821 local_host: 822 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 823 if(func == NULL || (*func)(context, pr)){ 824 *princ = pr; 825 return 0; 826 } 827 krb5_free_principal(context, pr); 828 krb5_clear_error_string (context); 829 return HEIM_ERR_V4_PRINC_NO_CONV; 830 no_host: 831 p = krb5_config_get_string(context, NULL, 832 "realms", 833 realm, 834 "v4_name_convert", 835 "plain", 836 name, 837 NULL); 838 if(p == NULL) 839 p = krb5_config_get_string(context, NULL, 840 "libdefaults", 841 "v4_name_convert", 842 "plain", 843 name, 844 NULL); 845 if(p) 846 name = p; 847 848 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 849 if(func == NULL || (*func)(context, pr)){ 850 *princ = pr; 851 return 0; 852 } 853 krb5_free_principal(context, pr); 854 krb5_clear_error_string (context); 855 return HEIM_ERR_V4_PRINC_NO_CONV; 856 } 857 858 krb5_error_code 859 krb5_425_conv_principal(krb5_context context, 860 const char *name, 861 const char *instance, 862 const char *realm, 863 krb5_principal *princ) 864 { 865 krb5_boolean resolve = krb5_config_get_bool(context, 866 NULL, 867 "libdefaults", 868 "v4_instance_resolve", 869 NULL); 870 871 return krb5_425_conv_principal_ext(context, name, instance, realm, 872 NULL, resolve, princ); 873 } 874 875 876 static int 877 check_list(const krb5_config_binding *l, const char *name, const char **out) 878 { 879 while(l){ 880 if (l->type != krb5_config_string) 881 continue; 882 if(strcmp(name, l->u.string) == 0) { 883 *out = l->name; 884 return 1; 885 } 886 l = l->next; 887 } 888 return 0; 889 } 890 891 static int 892 name_convert(krb5_context context, const char *name, const char *realm, 893 const char **out) 894 { 895 const krb5_config_binding *l; 896 l = krb5_config_get_list (context, 897 NULL, 898 "realms", 899 realm, 900 "v4_name_convert", 901 "host", 902 NULL); 903 if(l && check_list(l, name, out)) 904 return KRB5_NT_SRV_HST; 905 l = krb5_config_get_list (context, 906 NULL, 907 "libdefaults", 908 "v4_name_convert", 909 "host", 910 NULL); 911 if(l && check_list(l, name, out)) 912 return KRB5_NT_SRV_HST; 913 l = krb5_config_get_list (context, 914 NULL, 915 "realms", 916 realm, 917 "v4_name_convert", 918 "plain", 919 NULL); 920 if(l && check_list(l, name, out)) 921 return KRB5_NT_UNKNOWN; 922 l = krb5_config_get_list (context, 923 NULL, 924 "libdefaults", 925 "v4_name_convert", 926 "host", 927 NULL); 928 if(l && check_list(l, name, out)) 929 return KRB5_NT_UNKNOWN; 930 931 /* didn't find it in config file, try built-in list */ 932 { 933 struct v4_name_convert *q; 934 for(q = default_v4_name_convert; q->from; q++) { 935 if(strcmp(name, q->to) == 0) { 936 *out = q->from; 937 return KRB5_NT_SRV_HST; 938 } 939 } 940 } 941 return -1; 942 } 943 944 /* 945 * convert the v5 principal in `principal' into a v4 corresponding one 946 * in `name, instance, realm' 947 * this is limited interface since there's no length given for these 948 * three parameters. They have to be 40 bytes each (ANAME_SZ). 949 */ 950 951 krb5_error_code 952 krb5_524_conv_principal(krb5_context context, 953 const krb5_principal principal, 954 char *name, 955 char *instance, 956 char *realm) 957 { 958 const char *n, *i, *r; 959 char tmpinst[40]; 960 int type = princ_type(principal); 961 const int aname_sz = 40; 962 963 r = principal->realm; 964 965 switch(principal->name.name_string.len){ 966 case 1: 967 n = principal->name.name_string.val[0]; 968 i = ""; 969 break; 970 case 2: 971 n = principal->name.name_string.val[0]; 972 i = principal->name.name_string.val[1]; 973 break; 974 default: 975 krb5_set_error_string (context, 976 "cannot convert a %d component principal", 977 principal->name.name_string.len); 978 return KRB5_PARSE_MALFORMED; 979 } 980 981 { 982 const char *tmp; 983 int t = name_convert(context, n, r, &tmp); 984 if(t >= 0) { 985 type = t; 986 n = tmp; 987 } 988 } 989 990 if(type == KRB5_NT_SRV_HST){ 991 char *p; 992 993 strlcpy (tmpinst, i, sizeof(tmpinst)); 994 p = strchr(tmpinst, '.'); 995 if(p) 996 *p = 0; 997 i = tmpinst; 998 } 999 1000 if (strlcpy (name, n, aname_sz) >= aname_sz) { 1001 krb5_set_error_string (context, 1002 "too long name component to convert"); 1003 return KRB5_PARSE_MALFORMED; 1004 } 1005 if (strlcpy (instance, i, aname_sz) >= aname_sz) { 1006 krb5_set_error_string (context, 1007 "too long instance component to convert"); 1008 return KRB5_PARSE_MALFORMED; 1009 } 1010 if (strlcpy (realm, r, aname_sz) >= aname_sz) { 1011 krb5_set_error_string (context, 1012 "too long realm component to convert"); 1013 return KRB5_PARSE_MALFORMED; 1014 } 1015 return 0; 1016 } 1017 1018 /* 1019 * Create a principal in `ret_princ' for the service `sname' running 1020 * on host `hostname'. */ 1021 1022 krb5_error_code 1023 krb5_sname_to_principal (krb5_context context, 1024 const char *hostname, 1025 const char *sname, 1026 int32_t type, 1027 krb5_principal *ret_princ) 1028 { 1029 krb5_error_code ret; 1030 char localhost[MAXHOSTNAMELEN]; 1031 char **realms, *host = NULL; 1032 1033 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) { 1034 krb5_set_error_string (context, "unsupported name type %d", 1035 type); 1036 return KRB5_SNAME_UNSUPP_NAMETYPE; 1037 } 1038 if(hostname == NULL) { 1039 gethostname(localhost, sizeof(localhost)); 1040 hostname = localhost; 1041 } 1042 if(sname == NULL) 1043 sname = "host"; 1044 if(type == KRB5_NT_SRV_HST) { 1045 ret = krb5_expand_hostname_realms (context, hostname, 1046 &host, &realms); 1047 if (ret) 1048 return ret; 1049 strlwr(host); 1050 hostname = host; 1051 } else { 1052 ret = krb5_get_host_realm(context, hostname, &realms); 1053 if(ret) 1054 return ret; 1055 } 1056 1057 ret = krb5_make_principal(context, ret_princ, realms[0], sname, 1058 hostname, NULL); 1059 if(host) 1060 free(host); 1061 krb5_free_host_realm(context, realms); 1062 return ret; 1063 } 1064