1 /* 2 * Copyright (c) 1997-2007 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 21741 2007-07-31 16:00:37Z lha $"); 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 KRB5_LIB_FUNCTION 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 void KRB5_LIB_FUNCTION 63 krb5_principal_set_type(krb5_context context, 64 krb5_principal principal, 65 int type) 66 { 67 princ_type(principal) = type; 68 } 69 70 int KRB5_LIB_FUNCTION 71 krb5_principal_get_type(krb5_context context, 72 krb5_const_principal principal) 73 { 74 return princ_type(principal); 75 } 76 77 const char* KRB5_LIB_FUNCTION 78 krb5_principal_get_realm(krb5_context context, 79 krb5_const_principal principal) 80 { 81 return princ_realm(principal); 82 } 83 84 const char* KRB5_LIB_FUNCTION 85 krb5_principal_get_comp_string(krb5_context context, 86 krb5_const_principal principal, 87 unsigned int component) 88 { 89 if(component >= princ_num_comp(principal)) 90 return NULL; 91 return princ_ncomp(principal, component); 92 } 93 94 krb5_error_code KRB5_LIB_FUNCTION 95 krb5_parse_name_flags(krb5_context context, 96 const char *name, 97 int flags, 98 krb5_principal *principal) 99 { 100 krb5_error_code ret; 101 heim_general_string *comp; 102 heim_general_string realm = NULL; 103 int ncomp; 104 105 const char *p; 106 char *q; 107 char *s; 108 char *start; 109 110 int n; 111 char c; 112 int got_realm = 0; 113 int first_at = 1; 114 int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE); 115 116 *principal = NULL; 117 118 #define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_MUST_REALM) 119 120 if ((flags & RFLAGS) == RFLAGS) { 121 krb5_set_error_string(context, "Can't require both realm and " 122 "no realm at the same time"); 123 return KRB5_ERR_NO_SERVICE; 124 } 125 #undef RFLAGS 126 127 /* count number of component, 128 * enterprise names only have one component 129 */ 130 ncomp = 1; 131 if (!enterprise) { 132 for(p = name; *p; p++){ 133 if(*p=='\\'){ 134 if(!p[1]) { 135 krb5_set_error_string (context, 136 "trailing \\ in principal name"); 137 return KRB5_PARSE_MALFORMED; 138 } 139 p++; 140 } else if(*p == '/') 141 ncomp++; 142 else if(*p == '@') 143 break; 144 } 145 } 146 comp = calloc(ncomp, sizeof(*comp)); 147 if (comp == NULL) { 148 krb5_set_error_string (context, "malloc: out of memory"); 149 return ENOMEM; 150 } 151 152 n = 0; 153 p = start = q = s = strdup(name); 154 if (start == NULL) { 155 free (comp); 156 krb5_set_error_string (context, "malloc: out of memory"); 157 return ENOMEM; 158 } 159 while(*p){ 160 c = *p++; 161 if(c == '\\'){ 162 c = *p++; 163 if(c == 'n') 164 c = '\n'; 165 else if(c == 't') 166 c = '\t'; 167 else if(c == 'b') 168 c = '\b'; 169 else if(c == '0') 170 c = '\0'; 171 else if(c == '\0') { 172 krb5_set_error_string (context, 173 "trailing \\ in principal name"); 174 ret = KRB5_PARSE_MALFORMED; 175 goto exit; 176 } 177 }else if(enterprise && first_at) { 178 if (c == '@') 179 first_at = 0; 180 }else if((c == '/' && !enterprise) || c == '@'){ 181 if(got_realm){ 182 krb5_set_error_string (context, 183 "part after realm in principal name"); 184 ret = KRB5_PARSE_MALFORMED; 185 goto exit; 186 }else{ 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 if(c == '@') 198 got_realm = 1; 199 start = q; 200 continue; 201 } 202 if(got_realm && (c == ':' || c == '/' || c == '\0')) { 203 krb5_set_error_string (context, 204 "part after realm in principal name"); 205 ret = KRB5_PARSE_MALFORMED; 206 goto exit; 207 } 208 *q++ = c; 209 } 210 if(got_realm){ 211 if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) { 212 krb5_set_error_string (context, "realm found in 'short' principal " 213 "expected to be without one"); 214 ret = KRB5_PARSE_MALFORMED; 215 goto exit; 216 } 217 realm = malloc(q - start + 1); 218 if (realm == NULL) { 219 krb5_set_error_string (context, "malloc: out of memory"); 220 ret = ENOMEM; 221 goto exit; 222 } 223 memcpy(realm, start, q - start); 224 realm[q - start] = 0; 225 }else{ 226 if (flags & KRB5_PRINCIPAL_PARSE_MUST_REALM) { 227 krb5_set_error_string (context, "realm NOT found in principal " 228 "expected to be with one"); 229 ret = KRB5_PARSE_MALFORMED; 230 goto exit; 231 } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) { 232 realm = NULL; 233 } else { 234 ret = krb5_get_default_realm (context, &realm); 235 if (ret) 236 goto exit; 237 } 238 239 comp[n] = malloc(q - start + 1); 240 if (comp[n] == NULL) { 241 krb5_set_error_string (context, "malloc: out of memory"); 242 ret = ENOMEM; 243 goto exit; 244 } 245 memcpy(comp[n], start, q - start); 246 comp[n][q - start] = 0; 247 n++; 248 } 249 *principal = malloc(sizeof(**principal)); 250 if (*principal == NULL) { 251 krb5_set_error_string (context, "malloc: out of memory"); 252 ret = ENOMEM; 253 goto exit; 254 } 255 if (enterprise) 256 (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL; 257 else 258 (*principal)->name.name_type = KRB5_NT_PRINCIPAL; 259 (*principal)->name.name_string.val = comp; 260 princ_num_comp(*principal) = n; 261 (*principal)->realm = realm; 262 free(s); 263 return 0; 264 exit: 265 while(n>0){ 266 free(comp[--n]); 267 } 268 free(comp); 269 free(realm); 270 free(s); 271 return ret; 272 } 273 274 krb5_error_code KRB5_LIB_FUNCTION 275 krb5_parse_name(krb5_context context, 276 const char *name, 277 krb5_principal *principal) 278 { 279 return krb5_parse_name_flags(context, name, 0, principal); 280 } 281 282 static const char quotable_chars[] = " \n\t\b\\/@"; 283 static const char replace_chars[] = " ntb\\/@"; 284 static const char nq_chars[] = " \\/@"; 285 286 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0); 287 288 static size_t 289 quote_string(const char *s, char *out, size_t idx, size_t len, int display) 290 { 291 const char *p, *q; 292 for(p = s; *p && idx < len; p++){ 293 q = strchr(quotable_chars, *p); 294 if (q && display) { 295 add_char(out, idx, len, replace_chars[q - quotable_chars]); 296 } else if (q) { 297 add_char(out, idx, len, '\\'); 298 add_char(out, idx, len, replace_chars[q - quotable_chars]); 299 }else 300 add_char(out, idx, len, *p); 301 } 302 if(idx < len) 303 out[idx] = '\0'; 304 return idx; 305 } 306 307 308 static krb5_error_code 309 unparse_name_fixed(krb5_context context, 310 krb5_const_principal principal, 311 char *name, 312 size_t len, 313 int flags) 314 { 315 size_t idx = 0; 316 int i; 317 int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0; 318 int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0; 319 int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0; 320 321 if (!no_realm && princ_realm(principal) == NULL) { 322 krb5_set_error_string(context, "Realm missing from principal, " 323 "can't unparse"); 324 return ERANGE; 325 } 326 327 for(i = 0; i < princ_num_comp(principal); i++){ 328 if(i) 329 add_char(name, idx, len, '/'); 330 idx = quote_string(princ_ncomp(principal, i), name, idx, len, display); 331 if(idx == len) { 332 krb5_set_error_string(context, "Out of space printing principal"); 333 return ERANGE; 334 } 335 } 336 /* add realm if different from default realm */ 337 if(short_form && !no_realm) { 338 krb5_realm r; 339 krb5_error_code ret; 340 ret = krb5_get_default_realm(context, &r); 341 if(ret) 342 return ret; 343 if(strcmp(princ_realm(principal), r) != 0) 344 short_form = 0; 345 free(r); 346 } 347 if(!short_form && !no_realm) { 348 add_char(name, idx, len, '@'); 349 idx = quote_string(princ_realm(principal), name, idx, len, display); 350 if(idx == len) { 351 krb5_set_error_string(context, 352 "Out of space printing realm of principal"); 353 return ERANGE; 354 } 355 } 356 return 0; 357 } 358 359 krb5_error_code KRB5_LIB_FUNCTION 360 krb5_unparse_name_fixed(krb5_context context, 361 krb5_const_principal principal, 362 char *name, 363 size_t len) 364 { 365 return unparse_name_fixed(context, principal, name, len, 0); 366 } 367 368 krb5_error_code KRB5_LIB_FUNCTION 369 krb5_unparse_name_fixed_short(krb5_context context, 370 krb5_const_principal principal, 371 char *name, 372 size_t len) 373 { 374 return unparse_name_fixed(context, principal, name, len, 375 KRB5_PRINCIPAL_UNPARSE_SHORT); 376 } 377 378 krb5_error_code KRB5_LIB_FUNCTION 379 krb5_unparse_name_fixed_flags(krb5_context context, 380 krb5_const_principal principal, 381 int flags, 382 char *name, 383 size_t len) 384 { 385 return unparse_name_fixed(context, principal, name, len, flags); 386 } 387 388 static krb5_error_code 389 unparse_name(krb5_context context, 390 krb5_const_principal principal, 391 char **name, 392 int flags) 393 { 394 size_t len = 0, plen; 395 int i; 396 krb5_error_code ret; 397 /* count length */ 398 if (princ_realm(principal)) { 399 plen = strlen(princ_realm(principal)); 400 401 if(strcspn(princ_realm(principal), quotable_chars) == plen) 402 len += plen; 403 else 404 len += 2*plen; 405 len++; /* '@' */ 406 } 407 for(i = 0; i < princ_num_comp(principal); i++){ 408 plen = strlen(princ_ncomp(principal, i)); 409 if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen) 410 len += plen; 411 else 412 len += 2*plen; 413 len++; 414 } 415 len++; /* '\0' */ 416 *name = malloc(len); 417 if(*name == NULL) { 418 krb5_set_error_string (context, "malloc: out of memory"); 419 return ENOMEM; 420 } 421 ret = unparse_name_fixed(context, principal, *name, len, flags); 422 if(ret) { 423 free(*name); 424 *name = NULL; 425 } 426 return ret; 427 } 428 429 krb5_error_code KRB5_LIB_FUNCTION 430 krb5_unparse_name(krb5_context context, 431 krb5_const_principal principal, 432 char **name) 433 { 434 return unparse_name(context, principal, name, 0); 435 } 436 437 krb5_error_code KRB5_LIB_FUNCTION 438 krb5_unparse_name_flags(krb5_context context, 439 krb5_const_principal principal, 440 int flags, 441 char **name) 442 { 443 return unparse_name(context, principal, name, flags); 444 } 445 446 krb5_error_code KRB5_LIB_FUNCTION 447 krb5_unparse_name_short(krb5_context context, 448 krb5_const_principal principal, 449 char **name) 450 { 451 return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT); 452 } 453 454 #if 0 /* not implemented */ 455 456 krb5_error_code KRB5_LIB_FUNCTION 457 krb5_unparse_name_ext(krb5_context context, 458 krb5_const_principal principal, 459 char **name, 460 size_t *size) 461 { 462 krb5_abortx(context, "unimplemented krb5_unparse_name_ext called"); 463 } 464 465 #endif 466 467 krb5_realm * KRB5_LIB_FUNCTION 468 krb5_princ_realm(krb5_context context, 469 krb5_principal principal) 470 { 471 return &princ_realm(principal); 472 } 473 474 475 void KRB5_LIB_FUNCTION 476 krb5_princ_set_realm(krb5_context context, 477 krb5_principal principal, 478 krb5_realm *realm) 479 { 480 princ_realm(principal) = *realm; 481 } 482 483 484 krb5_error_code KRB5_LIB_FUNCTION 485 krb5_build_principal(krb5_context context, 486 krb5_principal *principal, 487 int rlen, 488 krb5_const_realm realm, 489 ...) 490 { 491 krb5_error_code ret; 492 va_list ap; 493 va_start(ap, realm); 494 ret = krb5_build_principal_va(context, principal, rlen, realm, ap); 495 va_end(ap); 496 return ret; 497 } 498 499 static krb5_error_code 500 append_component(krb5_context context, krb5_principal p, 501 const char *comp, 502 size_t comp_len) 503 { 504 heim_general_string *tmp; 505 size_t len = princ_num_comp(p); 506 507 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp)); 508 if(tmp == NULL) { 509 krb5_set_error_string (context, "malloc: out of memory"); 510 return ENOMEM; 511 } 512 princ_comp(p) = tmp; 513 princ_ncomp(p, len) = malloc(comp_len + 1); 514 if (princ_ncomp(p, len) == NULL) { 515 krb5_set_error_string (context, "malloc: out of memory"); 516 return ENOMEM; 517 } 518 memcpy (princ_ncomp(p, len), comp, comp_len); 519 princ_ncomp(p, len)[comp_len] = '\0'; 520 princ_num_comp(p)++; 521 return 0; 522 } 523 524 static void 525 va_ext_princ(krb5_context context, krb5_principal p, va_list ap) 526 { 527 while(1){ 528 const char *s; 529 int len; 530 len = va_arg(ap, int); 531 if(len == 0) 532 break; 533 s = va_arg(ap, const char*); 534 append_component(context, p, s, len); 535 } 536 } 537 538 static void 539 va_princ(krb5_context context, krb5_principal p, va_list ap) 540 { 541 while(1){ 542 const char *s; 543 s = va_arg(ap, const char*); 544 if(s == NULL) 545 break; 546 append_component(context, p, s, strlen(s)); 547 } 548 } 549 550 551 static krb5_error_code 552 build_principal(krb5_context context, 553 krb5_principal *principal, 554 int rlen, 555 krb5_const_realm realm, 556 void (*func)(krb5_context, krb5_principal, va_list), 557 va_list ap) 558 { 559 krb5_principal p; 560 561 p = calloc(1, sizeof(*p)); 562 if (p == NULL) { 563 krb5_set_error_string (context, "malloc: out of memory"); 564 return ENOMEM; 565 } 566 princ_type(p) = KRB5_NT_PRINCIPAL; 567 568 princ_realm(p) = strdup(realm); 569 if(p->realm == NULL){ 570 free(p); 571 krb5_set_error_string (context, "malloc: out of memory"); 572 return ENOMEM; 573 } 574 575 (*func)(context, p, ap); 576 *principal = p; 577 return 0; 578 } 579 580 krb5_error_code KRB5_LIB_FUNCTION 581 krb5_make_principal(krb5_context context, 582 krb5_principal *principal, 583 krb5_const_realm realm, 584 ...) 585 { 586 krb5_error_code ret; 587 krb5_realm r = NULL; 588 va_list ap; 589 if(realm == NULL) { 590 ret = krb5_get_default_realm(context, &r); 591 if(ret) 592 return ret; 593 realm = r; 594 } 595 va_start(ap, realm); 596 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap); 597 va_end(ap); 598 if(r) 599 free(r); 600 return ret; 601 } 602 603 krb5_error_code KRB5_LIB_FUNCTION 604 krb5_build_principal_va(krb5_context context, 605 krb5_principal *principal, 606 int rlen, 607 krb5_const_realm realm, 608 va_list ap) 609 { 610 return build_principal(context, principal, rlen, realm, va_princ, ap); 611 } 612 613 krb5_error_code KRB5_LIB_FUNCTION 614 krb5_build_principal_va_ext(krb5_context context, 615 krb5_principal *principal, 616 int rlen, 617 krb5_const_realm realm, 618 va_list ap) 619 { 620 return build_principal(context, principal, rlen, realm, va_ext_princ, ap); 621 } 622 623 624 krb5_error_code KRB5_LIB_FUNCTION 625 krb5_build_principal_ext(krb5_context context, 626 krb5_principal *principal, 627 int rlen, 628 krb5_const_realm realm, 629 ...) 630 { 631 krb5_error_code ret; 632 va_list ap; 633 va_start(ap, realm); 634 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap); 635 va_end(ap); 636 return ret; 637 } 638 639 640 krb5_error_code KRB5_LIB_FUNCTION 641 krb5_copy_principal(krb5_context context, 642 krb5_const_principal inprinc, 643 krb5_principal *outprinc) 644 { 645 krb5_principal p = malloc(sizeof(*p)); 646 if (p == NULL) { 647 krb5_set_error_string (context, "malloc: out of memory"); 648 return ENOMEM; 649 } 650 if(copy_Principal(inprinc, p)) { 651 free(p); 652 krb5_set_error_string (context, "malloc: out of memory"); 653 return ENOMEM; 654 } 655 *outprinc = p; 656 return 0; 657 } 658 659 /* 660 * return TRUE iff princ1 == princ2 (without considering the realm) 661 */ 662 663 krb5_boolean KRB5_LIB_FUNCTION 664 krb5_principal_compare_any_realm(krb5_context context, 665 krb5_const_principal princ1, 666 krb5_const_principal princ2) 667 { 668 int i; 669 if(princ_num_comp(princ1) != princ_num_comp(princ2)) 670 return FALSE; 671 for(i = 0; i < princ_num_comp(princ1); i++){ 672 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0) 673 return FALSE; 674 } 675 return TRUE; 676 } 677 678 /* 679 * return TRUE iff princ1 == princ2 680 */ 681 682 krb5_boolean KRB5_LIB_FUNCTION 683 krb5_principal_compare(krb5_context context, 684 krb5_const_principal princ1, 685 krb5_const_principal princ2) 686 { 687 if(!krb5_realm_compare(context, princ1, princ2)) 688 return FALSE; 689 return krb5_principal_compare_any_realm(context, princ1, princ2); 690 } 691 692 /* 693 * return TRUE iff realm(princ1) == realm(princ2) 694 */ 695 696 krb5_boolean KRB5_LIB_FUNCTION 697 krb5_realm_compare(krb5_context context, 698 krb5_const_principal princ1, 699 krb5_const_principal princ2) 700 { 701 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0; 702 } 703 704 /* 705 * return TRUE iff princ matches pattern 706 */ 707 708 krb5_boolean KRB5_LIB_FUNCTION 709 krb5_principal_match(krb5_context context, 710 krb5_const_principal princ, 711 krb5_const_principal pattern) 712 { 713 int i; 714 if(princ_num_comp(princ) != princ_num_comp(pattern)) 715 return FALSE; 716 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0) 717 return FALSE; 718 for(i = 0; i < princ_num_comp(princ); i++){ 719 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0) 720 return FALSE; 721 } 722 return TRUE; 723 } 724 725 726 static struct v4_name_convert { 727 const char *from; 728 const char *to; 729 } default_v4_name_convert[] = { 730 { "ftp", "ftp" }, 731 { "hprop", "hprop" }, 732 { "pop", "pop" }, 733 { "imap", "imap" }, 734 { "rcmd", "host" }, 735 { "smtp", "smtp" }, 736 { NULL, NULL } 737 }; 738 739 /* 740 * return the converted instance name of `name' in `realm'. 741 * look in the configuration file and then in the default set above. 742 * return NULL if no conversion is appropriate. 743 */ 744 745 static const char* 746 get_name_conversion(krb5_context context, const char *realm, const char *name) 747 { 748 struct v4_name_convert *q; 749 const char *p; 750 751 p = krb5_config_get_string(context, NULL, "realms", realm, 752 "v4_name_convert", "host", name, NULL); 753 if(p == NULL) 754 p = krb5_config_get_string(context, NULL, "libdefaults", 755 "v4_name_convert", "host", name, NULL); 756 if(p) 757 return p; 758 759 /* XXX should be possible to override default list */ 760 p = krb5_config_get_string(context, NULL, 761 "realms", 762 realm, 763 "v4_name_convert", 764 "plain", 765 name, 766 NULL); 767 if(p) 768 return NULL; 769 p = krb5_config_get_string(context, NULL, 770 "libdefaults", 771 "v4_name_convert", 772 "plain", 773 name, 774 NULL); 775 if(p) 776 return NULL; 777 for(q = default_v4_name_convert; q->from; q++) 778 if(strcmp(q->from, name) == 0) 779 return q->to; 780 return NULL; 781 } 782 783 /* 784 * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'. 785 * if `resolve', use DNS. 786 * if `func', use that function for validating the conversion 787 */ 788 789 krb5_error_code KRB5_LIB_FUNCTION 790 krb5_425_conv_principal_ext2(krb5_context context, 791 const char *name, 792 const char *instance, 793 const char *realm, 794 krb5_boolean (*func)(krb5_context, 795 void *, krb5_principal), 796 void *funcctx, 797 krb5_boolean resolve, 798 krb5_principal *princ) 799 { 800 const char *p; 801 krb5_error_code ret; 802 krb5_principal pr; 803 char host[MAXHOSTNAMELEN]; 804 char local_hostname[MAXHOSTNAMELEN]; 805 806 /* do the following: if the name is found in the 807 `v4_name_convert:host' part, is assumed to be a `host' type 808 principal, and the instance is looked up in the 809 `v4_instance_convert' part. if not found there the name is 810 (optionally) looked up as a hostname, and if that doesn't yield 811 anything, the `default_domain' is appended to the instance 812 */ 813 814 if(instance == NULL) 815 goto no_host; 816 if(instance[0] == 0){ 817 instance = NULL; 818 goto no_host; 819 } 820 p = get_name_conversion(context, realm, name); 821 if(p == NULL) 822 goto no_host; 823 name = p; 824 p = krb5_config_get_string(context, NULL, "realms", realm, 825 "v4_instance_convert", instance, NULL); 826 if(p){ 827 instance = p; 828 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 829 if(func == NULL || (*func)(context, funcctx, pr)){ 830 *princ = pr; 831 return 0; 832 } 833 krb5_free_principal(context, pr); 834 *princ = NULL; 835 krb5_clear_error_string (context); 836 return HEIM_ERR_V4_PRINC_NO_CONV; 837 } 838 if(resolve){ 839 krb5_boolean passed = FALSE; 840 char *inst = NULL; 841 #ifdef USE_RESOLVER 842 struct dns_reply *r; 843 844 r = dns_lookup(instance, "aaaa"); 845 if (r) { 846 if (r->head && r->head->type == T_AAAA) { 847 inst = strdup(r->head->domain); 848 passed = TRUE; 849 } 850 dns_free_data(r); 851 } else { 852 r = dns_lookup(instance, "a"); 853 if (r) { 854 if(r->head && r->head->type == T_A) { 855 inst = strdup(r->head->domain); 856 passed = TRUE; 857 } 858 dns_free_data(r); 859 } 860 } 861 #else 862 struct addrinfo hints, *ai; 863 864 memset (&hints, 0, sizeof(hints)); 865 hints.ai_flags = AI_CANONNAME; 866 ret = getaddrinfo(instance, NULL, &hints, &ai); 867 if (ret == 0) { 868 const struct addrinfo *a; 869 for (a = ai; a != NULL; a = a->ai_next) { 870 if (a->ai_canonname != NULL) { 871 inst = strdup (a->ai_canonname); 872 passed = TRUE; 873 break; 874 } 875 } 876 freeaddrinfo (ai); 877 } 878 #endif 879 if (passed) { 880 if (inst == NULL) { 881 krb5_set_error_string (context, "malloc: out of memory"); 882 return ENOMEM; 883 } 884 strlwr(inst); 885 ret = krb5_make_principal(context, &pr, realm, name, inst, 886 NULL); 887 free (inst); 888 if(ret == 0) { 889 if(func == NULL || (*func)(context, funcctx, pr)){ 890 *princ = pr; 891 return 0; 892 } 893 krb5_free_principal(context, pr); 894 } 895 } 896 } 897 if(func != NULL) { 898 snprintf(host, sizeof(host), "%s.%s", instance, realm); 899 strlwr(host); 900 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 901 if((*func)(context, funcctx, pr)){ 902 *princ = pr; 903 return 0; 904 } 905 krb5_free_principal(context, pr); 906 } 907 908 /* 909 * if the instance is the first component of the local hostname, 910 * the converted host should be the long hostname. 911 */ 912 913 if (func == NULL && 914 gethostname (local_hostname, sizeof(local_hostname)) == 0 && 915 strncmp(instance, local_hostname, strlen(instance)) == 0 && 916 local_hostname[strlen(instance)] == '.') { 917 strlcpy(host, local_hostname, sizeof(host)); 918 goto local_host; 919 } 920 921 { 922 char **domains, **d; 923 domains = krb5_config_get_strings(context, NULL, "realms", realm, 924 "v4_domains", NULL); 925 for(d = domains; d && *d; d++){ 926 snprintf(host, sizeof(host), "%s.%s", instance, *d); 927 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 928 if(func == NULL || (*func)(context, funcctx, pr)){ 929 *princ = pr; 930 krb5_config_free_strings(domains); 931 return 0; 932 } 933 krb5_free_principal(context, pr); 934 } 935 krb5_config_free_strings(domains); 936 } 937 938 939 p = krb5_config_get_string(context, NULL, "realms", realm, 940 "default_domain", NULL); 941 if(p == NULL){ 942 /* this should be an error, just faking a name is not good */ 943 krb5_clear_error_string (context); 944 return HEIM_ERR_V4_PRINC_NO_CONV; 945 } 946 947 if (*p == '.') 948 ++p; 949 snprintf(host, sizeof(host), "%s.%s", instance, p); 950 local_host: 951 ret = krb5_make_principal(context, &pr, realm, name, host, NULL); 952 if(func == NULL || (*func)(context, funcctx, pr)){ 953 *princ = pr; 954 return 0; 955 } 956 krb5_free_principal(context, pr); 957 krb5_clear_error_string (context); 958 return HEIM_ERR_V4_PRINC_NO_CONV; 959 no_host: 960 p = krb5_config_get_string(context, NULL, 961 "realms", 962 realm, 963 "v4_name_convert", 964 "plain", 965 name, 966 NULL); 967 if(p == NULL) 968 p = krb5_config_get_string(context, NULL, 969 "libdefaults", 970 "v4_name_convert", 971 "plain", 972 name, 973 NULL); 974 if(p) 975 name = p; 976 977 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); 978 if(func == NULL || (*func)(context, funcctx, pr)){ 979 *princ = pr; 980 return 0; 981 } 982 krb5_free_principal(context, pr); 983 krb5_clear_error_string (context); 984 return HEIM_ERR_V4_PRINC_NO_CONV; 985 } 986 987 static krb5_boolean 988 convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal) 989 { 990 krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx; 991 return (*func)(conxtext, principal); 992 } 993 994 krb5_error_code KRB5_LIB_FUNCTION 995 krb5_425_conv_principal_ext(krb5_context context, 996 const char *name, 997 const char *instance, 998 const char *realm, 999 krb5_boolean (*func)(krb5_context, krb5_principal), 1000 krb5_boolean resolve, 1001 krb5_principal *principal) 1002 { 1003 return krb5_425_conv_principal_ext2(context, 1004 name, 1005 instance, 1006 realm, 1007 func ? convert_func : NULL, 1008 func, 1009 resolve, 1010 principal); 1011 } 1012 1013 1014 1015 krb5_error_code KRB5_LIB_FUNCTION 1016 krb5_425_conv_principal(krb5_context context, 1017 const char *name, 1018 const char *instance, 1019 const char *realm, 1020 krb5_principal *princ) 1021 { 1022 krb5_boolean resolve = krb5_config_get_bool(context, 1023 NULL, 1024 "libdefaults", 1025 "v4_instance_resolve", 1026 NULL); 1027 1028 return krb5_425_conv_principal_ext(context, name, instance, realm, 1029 NULL, resolve, princ); 1030 } 1031 1032 1033 static int 1034 check_list(const krb5_config_binding *l, const char *name, const char **out) 1035 { 1036 while(l){ 1037 if (l->type != krb5_config_string) 1038 continue; 1039 if(strcmp(name, l->u.string) == 0) { 1040 *out = l->name; 1041 return 1; 1042 } 1043 l = l->next; 1044 } 1045 return 0; 1046 } 1047 1048 static int 1049 name_convert(krb5_context context, const char *name, const char *realm, 1050 const char **out) 1051 { 1052 const krb5_config_binding *l; 1053 l = krb5_config_get_list (context, 1054 NULL, 1055 "realms", 1056 realm, 1057 "v4_name_convert", 1058 "host", 1059 NULL); 1060 if(l && check_list(l, name, out)) 1061 return KRB5_NT_SRV_HST; 1062 l = krb5_config_get_list (context, 1063 NULL, 1064 "libdefaults", 1065 "v4_name_convert", 1066 "host", 1067 NULL); 1068 if(l && check_list(l, name, out)) 1069 return KRB5_NT_SRV_HST; 1070 l = krb5_config_get_list (context, 1071 NULL, 1072 "realms", 1073 realm, 1074 "v4_name_convert", 1075 "plain", 1076 NULL); 1077 if(l && check_list(l, name, out)) 1078 return KRB5_NT_UNKNOWN; 1079 l = krb5_config_get_list (context, 1080 NULL, 1081 "libdefaults", 1082 "v4_name_convert", 1083 "host", 1084 NULL); 1085 if(l && check_list(l, name, out)) 1086 return KRB5_NT_UNKNOWN; 1087 1088 /* didn't find it in config file, try built-in list */ 1089 { 1090 struct v4_name_convert *q; 1091 for(q = default_v4_name_convert; q->from; q++) { 1092 if(strcmp(name, q->to) == 0) { 1093 *out = q->from; 1094 return KRB5_NT_SRV_HST; 1095 } 1096 } 1097 } 1098 return -1; 1099 } 1100 1101 /* 1102 * convert the v5 principal in `principal' into a v4 corresponding one 1103 * in `name, instance, realm' 1104 * this is limited interface since there's no length given for these 1105 * three parameters. They have to be 40 bytes each (ANAME_SZ). 1106 */ 1107 1108 krb5_error_code KRB5_LIB_FUNCTION 1109 krb5_524_conv_principal(krb5_context context, 1110 const krb5_principal principal, 1111 char *name, 1112 char *instance, 1113 char *realm) 1114 { 1115 const char *n, *i, *r; 1116 char tmpinst[40]; 1117 int type = princ_type(principal); 1118 const int aname_sz = 40; 1119 1120 r = principal->realm; 1121 1122 switch(principal->name.name_string.len){ 1123 case 1: 1124 n = principal->name.name_string.val[0]; 1125 i = ""; 1126 break; 1127 case 2: 1128 n = principal->name.name_string.val[0]; 1129 i = principal->name.name_string.val[1]; 1130 break; 1131 default: 1132 krb5_set_error_string (context, 1133 "cannot convert a %d component principal", 1134 principal->name.name_string.len); 1135 return KRB5_PARSE_MALFORMED; 1136 } 1137 1138 { 1139 const char *tmp; 1140 int t = name_convert(context, n, r, &tmp); 1141 if(t >= 0) { 1142 type = t; 1143 n = tmp; 1144 } 1145 } 1146 1147 if(type == KRB5_NT_SRV_HST){ 1148 char *p; 1149 1150 strlcpy (tmpinst, i, sizeof(tmpinst)); 1151 p = strchr(tmpinst, '.'); 1152 if(p) 1153 *p = 0; 1154 i = tmpinst; 1155 } 1156 1157 if (strlcpy (name, n, aname_sz) >= aname_sz) { 1158 krb5_set_error_string (context, 1159 "too long name component to convert"); 1160 return KRB5_PARSE_MALFORMED; 1161 } 1162 if (strlcpy (instance, i, aname_sz) >= aname_sz) { 1163 krb5_set_error_string (context, 1164 "too long instance component to convert"); 1165 return KRB5_PARSE_MALFORMED; 1166 } 1167 if (strlcpy (realm, r, aname_sz) >= aname_sz) { 1168 krb5_set_error_string (context, 1169 "too long realm component to convert"); 1170 return KRB5_PARSE_MALFORMED; 1171 } 1172 return 0; 1173 } 1174 1175 /* 1176 * Create a principal in `ret_princ' for the service `sname' running 1177 * on host `hostname'. */ 1178 1179 krb5_error_code KRB5_LIB_FUNCTION 1180 krb5_sname_to_principal (krb5_context context, 1181 const char *hostname, 1182 const char *sname, 1183 int32_t type, 1184 krb5_principal *ret_princ) 1185 { 1186 krb5_error_code ret; 1187 char localhost[MAXHOSTNAMELEN]; 1188 char **realms, *host = NULL; 1189 1190 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) { 1191 krb5_set_error_string (context, "unsupported name type %d", 1192 type); 1193 return KRB5_SNAME_UNSUPP_NAMETYPE; 1194 } 1195 if(hostname == NULL) { 1196 gethostname(localhost, sizeof(localhost)); 1197 hostname = localhost; 1198 } 1199 if(sname == NULL) 1200 sname = "host"; 1201 if(type == KRB5_NT_SRV_HST) { 1202 ret = krb5_expand_hostname_realms (context, hostname, 1203 &host, &realms); 1204 if (ret) 1205 return ret; 1206 strlwr(host); 1207 hostname = host; 1208 } else { 1209 ret = krb5_get_host_realm(context, hostname, &realms); 1210 if(ret) 1211 return ret; 1212 } 1213 1214 ret = krb5_make_principal(context, ret_princ, realms[0], sname, 1215 hostname, NULL); 1216 if(host) 1217 free(host); 1218 krb5_free_host_realm(context, realms); 1219 return ret; 1220 } 1221 1222 static const struct { 1223 const char *type; 1224 int32_t value; 1225 } nametypes[] = { 1226 { "UNKNOWN", KRB5_NT_UNKNOWN }, 1227 { "PRINCIPAL", KRB5_NT_PRINCIPAL }, 1228 { "SRV_INST", KRB5_NT_SRV_INST }, 1229 { "SRV_HST", KRB5_NT_SRV_HST }, 1230 { "SRV_XHST", KRB5_NT_SRV_XHST }, 1231 { "UID", KRB5_NT_UID }, 1232 { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL }, 1233 { "SMTP_NAME", KRB5_NT_SMTP_NAME }, 1234 { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL }, 1235 { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID }, 1236 { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL }, 1237 { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID }, 1238 { NULL } 1239 }; 1240 1241 krb5_error_code 1242 krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype) 1243 { 1244 size_t i; 1245 1246 for(i = 0; nametypes[i].type; i++) { 1247 if (strcasecmp(nametypes[i].type, str) == 0) { 1248 *nametype = nametypes[i].value; 1249 return 0; 1250 } 1251 } 1252 krb5_set_error_string(context, "Failed to find name type %s", str); 1253 return KRB5_PARSE_MALFORMED; 1254 } 1255