1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * lib/krb5/os/locate_kdc.c 8 * 9 * Copyright 1990,2000,2001,2002,2003,2004,2006 Massachusetts Institute of Technology. 10 * All Rights Reserved. 11 * 12 * Export of this software from the United States of America may 13 * require a specific license from the United States Government. 14 * It is the responsibility of any person or organization contemplating 15 * export to obtain such a license before exporting. 16 * 17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 18 * distribute this software and its documentation for any purpose and 19 * without fee is hereby granted, provided that the above copyright 20 * notice appear in all copies and that both that copyright notice and 21 * this permission notice appear in supporting documentation, and that 22 * the name of M.I.T. not be used in advertising or publicity pertaining 23 * to distribution of the software without specific, written prior 24 * permission. Furthermore if you modify this software you must label 25 * your software as modified software and not distribute it in such a 26 * fashion that it might be confused with the original M.I.T. software. 27 * M.I.T. makes no representations about the suitability of 28 * this software for any purpose. It is provided "as is" without express 29 * or implied warranty. 30 * 31 * 32 * get socket addresses for KDC. 33 */ 34 35 #include "fake-addrinfo.h" 36 #include "k5-int.h" 37 #include "os-proto.h" 38 #include <stdio.h> 39 #ifdef KRB5_DNS_LOOKUP 40 #ifdef WSHELPER 41 #include <wshelper.h> 42 #else /* WSHELPER */ 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 #include <arpa/nameser.h> 46 #include <resolv.h> 47 #include <netdb.h> 48 #endif /* WSHELPER */ 49 #ifndef T_SRV 50 #define T_SRV 33 51 #endif /* T_SRV */ 52 53 /* for old Unixes and friends ... */ 54 #ifndef MAXHOSTNAMELEN 55 #define MAXHOSTNAMELEN 64 56 #endif 57 58 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1) 59 60 /* Solaris Kerberos: default to dns lookup for the KDC but not the realm */ 61 #define DEFAULT_LOOKUP_KDC 1 62 #define DEFAULT_LOOKUP_REALM 0 63 64 static int 65 maybe_use_dns (krb5_context context, const char *name, int defalt) 66 { 67 krb5_error_code code; 68 char * value = NULL; 69 int use_dns = 0; 70 71 code = profile_get_string(context->profile, "libdefaults", 72 name, 0, 0, &value); 73 if (value == 0 && code == 0) 74 code = profile_get_string(context->profile, "libdefaults", 75 "dns_fallback", 0, 0, &value); 76 if (code) 77 return defalt; 78 79 if (value == 0) 80 return defalt; 81 82 use_dns = _krb5_conf_boolean(value); 83 profile_release_string(value); 84 return use_dns; 85 } 86 87 int 88 _krb5_use_dns_kdc(krb5_context context) 89 { 90 return maybe_use_dns (context, "dns_lookup_kdc", DEFAULT_LOOKUP_KDC); 91 } 92 93 int 94 _krb5_use_dns_realm(krb5_context context) 95 { 96 return maybe_use_dns (context, "dns_lookup_realm", DEFAULT_LOOKUP_REALM); 97 } 98 99 #endif /* KRB5_DNS_LOOKUP */ 100 101 int 102 krb5int_grow_addrlist (struct addrlist *lp, int nmore) 103 { 104 int i; 105 int newspace = lp->space + nmore; 106 size_t newsize = newspace * sizeof (*lp->addrs); 107 void *newaddrs; 108 109 newaddrs = realloc (lp->addrs, newsize); 110 if (newaddrs == NULL) 111 return errno; 112 lp->addrs = newaddrs; 113 for (i = lp->space; i < newspace; i++) { 114 lp->addrs[i].ai = NULL; 115 lp->addrs[i].freefn = NULL; 116 lp->addrs[i].data = NULL; 117 } 118 lp->space = newspace; 119 return 0; 120 } 121 #define grow_list krb5int_grow_addrlist 122 123 /* Free up everything pointed to by the addrlist structure, but don't 124 free the structure itself. */ 125 void 126 krb5int_free_addrlist (struct addrlist *lp) 127 { 128 int i; 129 for (i = 0; i < lp->naddrs; i++) 130 if (lp->addrs[i].freefn) 131 (lp->addrs[i].freefn)(lp->addrs[i].data); 132 free (lp->addrs); 133 lp->addrs = NULL; 134 lp->naddrs = lp->space = 0; 135 } 136 #define free_list krb5int_free_addrlist 137 138 static int translate_ai_error (int err) 139 { 140 switch (err) { 141 case 0: 142 return 0; 143 case EAI_BADFLAGS: 144 case EAI_FAMILY: 145 case EAI_SOCKTYPE: 146 case EAI_SERVICE: 147 /* All of these indicate bad inputs to getaddrinfo. */ 148 return EINVAL; 149 case EAI_AGAIN: 150 /* Translate to standard errno code. */ 151 return EAGAIN; 152 case EAI_MEMORY: 153 /* Translate to standard errno code. */ 154 return ENOMEM; 155 #ifdef EAI_ADDRFAMILY 156 case EAI_ADDRFAMILY: 157 #endif 158 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME 159 case EAI_NODATA: 160 #endif 161 case EAI_NONAME: 162 /* Name not known or no address data, but no error. Do 163 nothing more. */ 164 return 0; 165 #ifdef EAI_OVERFLOW 166 case EAI_OVERFLOW: 167 /* An argument buffer overflowed. */ 168 return EINVAL; /* XXX */ 169 #endif 170 #ifdef EAI_SYSTEM 171 case EAI_SYSTEM: 172 /* System error, obviously. */ 173 return errno; 174 #endif 175 default: 176 /* An error code we haven't handled? */ 177 return EINVAL; 178 } 179 } 180 181 /* Solaris Kerberos: want dbg messages to syslog */ 182 #include <stdarg.h> 183 static inline void Tprintf(const char *fmt, ...) 184 { 185 #ifdef TEST 186 va_list ap; 187 char err_str[2048]; 188 189 va_start(ap, fmt); 190 vsnprintf(err_str, sizeof (err_str), fmt, args); 191 syslog(LOG_DEBUG, err_str); 192 va_end(ap); 193 #endif 194 } 195 196 #if 0 197 extern void krb5int_debug_fprint(const char *, ...); 198 #define dprint krb5int_debug_fprint 199 #define print_addrlist krb5int_print_addrlist 200 extern void print_addrlist (const struct addrlist *a); 201 #else 202 static inline void dprint(const char *fmt, ...) { } 203 static inline void print_addrlist(const struct addrlist *a) { } 204 #endif 205 206 static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a, 207 void (*freefn)(void *), void *data) 208 { 209 int err; 210 211 dprint("\tadding %p=%A to %p (naddrs=%d space=%d)\n", a, a, lp, 212 lp->naddrs, lp->space); 213 214 if (lp->naddrs == lp->space) { 215 err = grow_list (lp, 1); 216 if (err) { 217 Tprintf ("grow_list failed %d\n", err); 218 return err; 219 } 220 } 221 Tprintf("setting element %d\n", lp->naddrs); 222 lp->addrs[lp->naddrs].ai = a; 223 lp->addrs[lp->naddrs].freefn = freefn; 224 lp->addrs[lp->naddrs].data = data; 225 lp->naddrs++; 226 Tprintf ("\tcount is now %d: ", lp->naddrs); 227 print_addrlist(lp); 228 Tprintf("\n"); 229 return 0; 230 } 231 232 #define add_host_to_list krb5int_add_host_to_list 233 234 static void call_freeaddrinfo(void *data) 235 { 236 /* Strict interpretation of the C standard says we can't assume 237 that the ABI for f(void*) and f(struct foo *) will be 238 compatible. Use this stub just to be paranoid. */ 239 freeaddrinfo(data); 240 } 241 242 int 243 krb5int_add_host_to_list (struct addrlist *lp, const char *hostname, 244 int port, int secport, 245 int socktype, int family) 246 { 247 struct addrinfo *addrs, *a, *anext, hint; 248 int err; 249 char portbuf[10], secportbuf[10]; 250 void (*freefn)(void *); 251 252 Tprintf ("adding hostname %s, ports %d,%d, family %d, socktype %d\n", 253 hostname, ntohs (port), ntohs (secport), 254 family, socktype); 255 256 memset(&hint, 0, sizeof(hint)); 257 hint.ai_family = family; 258 hint.ai_socktype = socktype; 259 #ifdef AI_NUMERICSERV 260 hint.ai_flags = AI_NUMERICSERV; 261 #endif 262 sprintf(portbuf, "%d", ntohs(port)); 263 sprintf(secportbuf, "%d", ntohs(secport)); 264 err = getaddrinfo (hostname, portbuf, &hint, &addrs); 265 if (err) { 266 Tprintf ("\tgetaddrinfo(\"%s\", \"%s\", ...)\n\treturns %d: %s\n", 267 hostname, portbuf, err, gai_strerror (err)); 268 return translate_ai_error (err); 269 } 270 freefn = call_freeaddrinfo; 271 anext = 0; 272 for (a = addrs; a != 0 && err == 0; a = anext, freefn = 0) { 273 anext = a->ai_next; 274 err = add_addrinfo_to_list (lp, a, freefn, a); 275 } 276 if (err || secport == 0) 277 goto egress; 278 if (socktype == 0) 279 socktype = SOCK_DGRAM; 280 else if (socktype != SOCK_DGRAM) 281 goto egress; 282 hint.ai_family = AF_INET; 283 err = getaddrinfo (hostname, secportbuf, &hint, &addrs); 284 if (err) { 285 err = translate_ai_error (err); 286 goto egress; 287 } 288 freefn = call_freeaddrinfo; 289 for (a = addrs; a != 0 && err == 0; a = anext, freefn = 0) { 290 anext = a->ai_next; 291 err = add_addrinfo_to_list (lp, a, freefn, a); 292 } 293 egress: 294 /* Solaris Kerberos */ 295 if (anext) 296 freeaddrinfo (anext); 297 return err; 298 } 299 300 /* 301 * returns count of number of addresses found 302 * if master is non-NULL, it is filled in with the index of 303 * the master kdc 304 */ 305 306 static krb5_error_code 307 krb5_locate_srv_conf_1(krb5_context context, const krb5_data *realm, 308 const char * name, struct addrlist *addrlist, 309 int get_masters, int socktype, 310 int udpport, int sec_udpport, int family) 311 { 312 const char *realm_srv_names[4]; 313 char **masterlist, **hostlist, *host, *port, *cp; 314 krb5_error_code code; 315 int i, j, count, ismaster; 316 317 Tprintf ("looking in krb5.conf for realm %s entry %s; ports %d,%d\n", 318 realm->data, name, ntohs (udpport), ntohs (sec_udpport)); 319 320 if ((host = malloc(realm->length + 1)) == NULL) 321 return ENOMEM; 322 323 strncpy(host, realm->data, realm->length); 324 host[realm->length] = '\0'; 325 hostlist = 0; 326 327 masterlist = NULL; 328 329 realm_srv_names[0] = "realms"; 330 realm_srv_names[1] = host; 331 realm_srv_names[2] = name; 332 realm_srv_names[3] = 0; 333 334 code = profile_get_values(context->profile, realm_srv_names, &hostlist); 335 336 if (code) { 337 Tprintf ("config file lookup failed: %s\n", 338 error_message(code)); 339 if (code == PROF_NO_SECTION || code == PROF_NO_RELATION) 340 code = KRB5_REALM_UNKNOWN; 341 krb5_xfree(host); 342 return code; 343 } 344 345 count = 0; 346 while (hostlist && hostlist[count]) 347 count++; 348 Tprintf ("found %d entries under 'kdc'\n", count); 349 350 if (count == 0) { 351 profile_free_list(hostlist); 352 krb5_xfree(host); 353 addrlist->naddrs = 0; 354 return 0; 355 } 356 357 if (get_masters) { 358 realm_srv_names[0] = "realms"; 359 realm_srv_names[1] = host; 360 realm_srv_names[2] = "admin_server"; 361 realm_srv_names[3] = 0; 362 363 code = profile_get_values(context->profile, realm_srv_names, 364 &masterlist); 365 366 krb5_xfree(host); 367 368 if (code == 0) { 369 for (i=0; masterlist[i]; i++) { 370 host = masterlist[i]; 371 372 /* 373 * Strip off excess whitespace 374 */ 375 cp = strchr(host, ' '); 376 if (cp) 377 *cp = 0; 378 cp = strchr(host, '\t'); 379 if (cp) 380 *cp = 0; 381 cp = strchr(host, ':'); 382 if (cp) 383 *cp = 0; 384 } 385 } 386 } else { 387 krb5_xfree(host); 388 } 389 390 /* at this point, if master is non-NULL, then either the master kdc 391 is required, and there is one, or the master kdc is not required, 392 and there may or may not be one. */ 393 394 #ifdef HAVE_NETINET_IN_H 395 if (sec_udpport) 396 count = count * 2; 397 #endif 398 399 for (i=0; hostlist[i]; i++) { 400 int p1, p2; 401 402 host = hostlist[i]; 403 Tprintf ("entry %d is '%s'\n", i, host); 404 /* 405 * Strip off excess whitespace 406 */ 407 cp = strchr(host, ' '); 408 if (cp) 409 *cp = 0; 410 cp = strchr(host, '\t'); 411 if (cp) 412 *cp = 0; 413 port = strchr(host, ':'); 414 if (port) { 415 *port = 0; 416 port++; 417 } 418 419 ismaster = 0; 420 if (masterlist) { 421 for (j=0; masterlist[j]; j++) { 422 if (strcasecmp(hostlist[i], masterlist[j]) == 0) { 423 ismaster = 1; 424 } 425 } 426 } 427 428 if (get_masters && !ismaster) 429 continue; 430 431 if (port) { 432 unsigned long l; 433 #ifdef HAVE_STROUL 434 char *endptr; 435 l = strtoul (port, &endptr, 10); 436 if (endptr == NULL || *endptr != 0) 437 return EINVAL; 438 #else 439 l = atoi (port); 440 #endif 441 /* L is unsigned, don't need to check <0. */ 442 if (l > 65535) 443 return EINVAL; 444 p1 = htons (l); 445 p2 = 0; 446 } else { 447 p1 = udpport; 448 p2 = sec_udpport; 449 } 450 451 if (socktype != 0) 452 code = add_host_to_list (addrlist, hostlist[i], p1, p2, 453 socktype, family); 454 else { 455 code = add_host_to_list (addrlist, hostlist[i], p1, p2, 456 SOCK_DGRAM, family); 457 if (code == 0) 458 code = add_host_to_list (addrlist, hostlist[i], p1, p2, 459 SOCK_STREAM, family); 460 } 461 if (code) { 462 Tprintf ("error %d (%s) returned from add_host_to_list\n", code, 463 error_message (code)); 464 if (hostlist) 465 profile_free_list (hostlist); 466 if (masterlist) 467 profile_free_list (masterlist); 468 return code; 469 } 470 } 471 472 if (hostlist) 473 profile_free_list(hostlist); 474 if (masterlist) 475 profile_free_list(masterlist); 476 477 return 0; 478 } 479 480 #ifdef TEST 481 static krb5_error_code 482 krb5_locate_srv_conf(krb5_context context, const krb5_data *realm, 483 const char *name, struct addrlist *al, int get_masters, 484 int udpport, int sec_udpport) 485 { 486 krb5_error_code ret; 487 488 ret = krb5_locate_srv_conf_1 (context, realm, name, al, 489 get_masters, 0, udpport, sec_udpport, 0); 490 if (ret) 491 return ret; 492 if (al->naddrs == 0) /* Couldn't resolve any KDC names */ 493 return KRB5_REALM_CANT_RESOLVE; 494 return 0; 495 } 496 #endif 497 498 #ifdef KRB5_DNS_LOOKUP 499 static krb5_error_code 500 krb5_locate_srv_dns_1 (const krb5_data *realm, 501 const char *service, 502 const char *protocol, 503 struct addrlist *addrlist, 504 int family) 505 { 506 struct srv_dns_entry *head = NULL; 507 struct srv_dns_entry *entry = NULL, *next; 508 krb5_error_code code = 0; 509 510 code = krb5int_make_srv_query_realm(realm, service, protocol, &head); 511 if (code) 512 return 0; 513 514 /* 515 * Okay! Now we've got a linked list of entries sorted by 516 * priority. Start looking up A records and returning 517 * addresses. 518 */ 519 520 if (head == NULL) 521 return 0; 522 523 /* Check for the "." case indicating no support. */ 524 if (head->next == 0 && head->host[0] == 0) { 525 free(head->host); 526 free(head); 527 return KRB5_ERR_NO_SERVICE; 528 } 529 530 Tprintf ("walking answer list:\n"); 531 for (entry = head; entry != NULL; entry = next) { 532 Tprintf ("\tport=%d host=%s\n", entry->port, entry->host); 533 next = entry->next; 534 code = add_host_to_list (addrlist, entry->host, htons (entry->port), 0, 535 (strcmp("_tcp", protocol) 536 ? SOCK_DGRAM 537 : SOCK_STREAM), family); 538 if (code) { 539 break; 540 } 541 if (entry == head) { 542 free(entry->host); 543 free(entry); 544 head = next; 545 entry = 0; 546 } 547 } 548 Tprintf ("[end]\n"); 549 550 krb5int_free_srv_dns_data(head); 551 return code; 552 } 553 #endif 554 555 #include <locate_plugin.h> 556 557 #if TARGET_OS_MAC 558 static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/libkrb5", NULL }; /* should be a list */ 559 #else 560 static const char *objdirs[] = { LIBDIR "/krb5/plugins/libkrb5", NULL }; 561 #endif 562 563 struct module_callback_data { 564 int out_of_mem; 565 struct addrlist *lp; 566 }; 567 568 static int 569 module_callback (void *cbdata, int socktype, struct sockaddr *sa) 570 { 571 struct module_callback_data *d = cbdata; 572 struct { 573 struct addrinfo ai; 574 union { 575 struct sockaddr_in sin; 576 struct sockaddr_in6 sin6; 577 } u; 578 } *x; 579 580 if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM) 581 return 0; 582 if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) 583 return 0; 584 x = malloc (sizeof (*x)); 585 if (x == 0) { 586 d->out_of_mem = 1; 587 return 1; 588 } 589 memset(x, 0, sizeof (*x)); 590 x->ai.ai_addr = (struct sockaddr *) &x->u; 591 x->ai.ai_socktype = socktype; 592 x->ai.ai_family = sa->sa_family; 593 if (sa->sa_family == AF_INET) { 594 x->u.sin = *(struct sockaddr_in *)sa; 595 x->ai.ai_addrlen = sizeof(struct sockaddr_in); 596 } 597 if (sa->sa_family == AF_INET6) { 598 x->u.sin6 = *(struct sockaddr_in6 *)sa; 599 x->ai.ai_addrlen = sizeof(struct sockaddr_in6); 600 } 601 if (add_addrinfo_to_list (d->lp, &x->ai, free, x) != 0) { 602 /* Assumes only error is ENOMEM. */ 603 d->out_of_mem = 1; 604 return 1; 605 } 606 return 0; 607 } 608 609 static krb5_error_code 610 module_locate_server (krb5_context ctx, const krb5_data *realm, 611 struct addrlist *addrlist, 612 enum locate_service_type svc, int socktype, int family) 613 { 614 struct krb5plugin_service_locate_result *res = NULL; 615 krb5_error_code code; 616 struct krb5plugin_service_locate_ftable *vtbl = NULL; 617 void **ptrs; 618 int i; 619 struct module_callback_data cbdata = { 0, }; 620 621 Tprintf("in module_locate_server\n"); 622 cbdata.lp = addrlist; 623 if (!PLUGIN_DIR_OPEN (&ctx->libkrb5_plugins)) { 624 625 code = krb5int_open_plugin_dirs (objdirs, NULL, &ctx->libkrb5_plugins, 626 &ctx->err); 627 if (code) 628 return KRB5_PLUGIN_NO_HANDLE; 629 } 630 631 code = krb5int_get_plugin_dir_data (&ctx->libkrb5_plugins, 632 "service_locator", &ptrs, &ctx->err); 633 if (code) { 634 Tprintf("error looking up plugin symbols: %s\n", 635 krb5_get_error_message(ctx, code)); 636 return KRB5_PLUGIN_NO_HANDLE; 637 } 638 639 for (i = 0; ptrs[i]; i++) { 640 void *blob; 641 642 vtbl = ptrs[i]; 643 Tprintf("element %d is %p\n", i, ptrs[i]); 644 645 /* For now, don't keep the plugin data alive. For long-lived 646 contexts, it may be desirable to change that later. */ 647 code = vtbl->init(ctx, &blob); 648 if (code) 649 continue; 650 651 code = vtbl->lookup(blob, svc, realm->data, socktype, family, 652 module_callback, &cbdata); 653 vtbl->fini(blob); 654 if (code == KRB5_PLUGIN_NO_HANDLE) { 655 /* Module passes, keep going. */ 656 /* XXX */ 657 Tprintf("plugin doesn't handle this realm (KRB5_PLUGIN_NO_HANDLE)\n"); 658 continue; 659 } 660 if (code != 0) { 661 /* Module encountered an actual error. */ 662 Tprintf("plugin lookup routine returned error %d: %s\n", 663 code, error_message(code)); 664 krb5int_free_plugin_dir_data (ptrs); 665 return code; 666 } 667 break; 668 } 669 if (ptrs[i] == NULL) { 670 Tprintf("ran off end of plugin list\n"); 671 krb5int_free_plugin_dir_data (ptrs); 672 return KRB5_PLUGIN_NO_HANDLE; 673 } 674 Tprintf("stopped with plugin #%d, res=%p\n", i, res); 675 676 /* Got something back, yippee. */ 677 Tprintf("now have %d addrs in list %p\n", addrlist->naddrs, addrlist); 678 print_addrlist(addrlist); 679 krb5int_free_plugin_dir_data (ptrs); 680 return 0; 681 } 682 683 static krb5_error_code 684 prof_locate_server (krb5_context context, const krb5_data *realm, 685 struct addrlist *addrlist, 686 enum locate_service_type svc, int socktype, int family) 687 { 688 const char *profname; 689 int dflport1, dflport2 = 0; 690 struct servent *serv; 691 692 switch (svc) { 693 case locate_service_kdc: 694 profname = "kdc"; 695 /* We used to use /etc/services for these, but enough systems 696 have old, crufty, wrong settings that this is probably 697 better. */ 698 kdc_ports: 699 dflport1 = htons(KRB5_DEFAULT_PORT); 700 dflport2 = htons(KRB5_DEFAULT_SEC_PORT); 701 break; 702 case locate_service_master_kdc: 703 profname = "master_kdc"; 704 goto kdc_ports; 705 case locate_service_kadmin: 706 profname = "admin_server"; 707 dflport1 = htons(DEFAULT_KADM5_PORT); 708 break; 709 case locate_service_krb524: 710 profname = "krb524_server"; 711 serv = getservbyname(KRB524_SERVICE, "udp"); 712 dflport1 = serv ? serv->s_port : htons (KRB524_PORT); 713 break; 714 case locate_service_kpasswd: 715 profname = "kpasswd_server"; 716 dflport1 = htons(DEFAULT_KPASSWD_PORT); 717 break; 718 default: 719 return EBUSY; /* XXX */ 720 } 721 722 return krb5_locate_srv_conf_1 (context, realm, profname, addrlist, 723 0, socktype, 724 dflport1, dflport2, family); 725 } 726 727 static krb5_error_code 728 dns_locate_server (krb5_context context, const krb5_data *realm, 729 struct addrlist *addrlist, 730 enum locate_service_type svc, int socktype, int family) 731 { 732 const char *dnsname; 733 int use_dns = _krb5_use_dns_kdc(context); 734 krb5_error_code code; 735 736 if (!use_dns) 737 return KRB5_PLUGIN_NO_HANDLE; 738 739 switch (svc) { 740 case locate_service_kdc: 741 dnsname = "_kerberos"; 742 break; 743 case locate_service_master_kdc: 744 dnsname = "_kerberos-master"; 745 break; 746 case locate_service_kadmin: 747 dnsname = "_kerberos-adm"; 748 break; 749 case locate_service_krb524: 750 dnsname = "_krb524"; 751 break; 752 case locate_service_kpasswd: 753 dnsname = "_kpasswd"; 754 break; 755 default: 756 return KRB5_PLUGIN_NO_HANDLE; 757 } 758 759 code = 0; 760 if (socktype == SOCK_DGRAM || socktype == 0) { 761 code = krb5_locate_srv_dns_1(realm, dnsname, "_udp", addrlist, family); 762 if (code) 763 Tprintf("dns udp lookup returned error %d\n", code); 764 } 765 if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) { 766 code = krb5_locate_srv_dns_1(realm, dnsname, "_tcp", addrlist, family); 767 if (code) 768 Tprintf("dns tcp lookup returned error %d\n", code); 769 } 770 return code; 771 } 772 773 /* 774 * Wrapper function for the various backends 775 */ 776 777 krb5_error_code 778 krb5int_locate_server (krb5_context context, const krb5_data *realm, 779 struct addrlist *addrlist, 780 enum locate_service_type svc, 781 int socktype, int family) 782 { 783 krb5_error_code code; 784 struct addrlist al = ADDRLIST_INIT; 785 786 *addrlist = al; 787 788 code = module_locate_server(context, realm, &al, svc, socktype, family); 789 Tprintf("module_locate_server returns %d\n", code); 790 if (code == KRB5_PLUGIN_NO_HANDLE) { 791 /* 792 * We always try the local file before DNS. Note that there 793 * is no way to indicate "service not available" via the 794 * config file. 795 */ 796 797 code = prof_locate_server(context, realm, &al, svc, socktype, family); 798 799 #ifdef KRB5_DNS_LOOKUP 800 /* 801 * Solaris Kerberos: 802 * There is no point in trying to locate the KDC in DNS if "realm" 803 * is empty. 804 */ 805 /* Try DNS for all profile errors? */ 806 if (code && !krb5_is_referral_realm(realm)) { 807 krb5_error_code code2; 808 code2 = dns_locate_server(context, realm, &al, svc, socktype, 809 family); 810 if (code2 != KRB5_PLUGIN_NO_HANDLE) 811 code = code2; 812 } 813 #endif /* KRB5_DNS_LOOKUP */ 814 815 /* We could put more heuristics here, like looking up a hostname 816 of "kerberos."+REALM, etc. */ 817 } 818 if (code == 0) 819 Tprintf ("krb5int_locate_server found %d addresses\n", 820 al.naddrs); 821 else 822 Tprintf ("krb5int_locate_server returning error code %d/%s\n", 823 code, error_message(code)); 824 if (code != 0) { 825 if (al.space) 826 free_list (&al); 827 return code; 828 } 829 if (al.naddrs == 0) { /* No good servers */ 830 if (al.space) 831 free_list (&al); 832 krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, 833 "Cannot resolve network address for KDC in realm %.*s", 834 realm->length, realm->data); 835 836 return KRB5_REALM_CANT_RESOLVE; 837 } 838 *addrlist = al; 839 return 0; 840 } 841 842 krb5_error_code 843 krb5_locate_kdc(krb5_context context, const krb5_data *realm, 844 struct addrlist *addrlist, 845 int get_masters, int socktype, int family) 846 { 847 return krb5int_locate_server(context, realm, addrlist, 848 (get_masters 849 ? locate_service_master_kdc 850 : locate_service_kdc), 851 socktype, family); 852 } 853 854 /* 855 * Solaris Kerberos: for backward compat. Avoid using this 856 * function! 857 */ 858 krb5_error_code 859 krb5_get_servername(krb5_context context, 860 const krb5_data *realm, 861 const char *name, const char *proto, 862 char *srvhost, 863 unsigned short *port) 864 { 865 krb5_error_code code = KRB5_REALM_UNKNOWN; 866 867 #ifdef KRB5_DNS_LOOKUP 868 { 869 int use_dns = _krb5_use_dns_kdc(context); 870 871 if (use_dns) { 872 struct srv_dns_entry *head = NULL; 873 874 code = krb5int_make_srv_query_realm(realm, name, proto, &head); 875 if (code) 876 return (code); 877 878 if (head == NULL) 879 return KRB5_REALM_CANT_RESOLVE; 880 881 *port = head->port; 882 (void) strlcpy(srvhost, head->host, MAX_DNS_NAMELEN); 883 884 #ifdef DEBUG 885 fprintf (stderr, "krb5_get_servername svrhost %s, port %d\n", 886 srvhost, *port); 887 #endif 888 krb5int_free_srv_dns_data(head); 889 } 890 } 891 #endif /* KRB5_DNS_LOOKUP */ 892 893 return (code); 894 } 895