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