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