1 /* 2 * Copyright (c) 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 #include <resolve.h> 36 37 RCSID("$Id: krbhst.c,v 1.40 2001/07/19 16:57:15 assar Exp $"); 38 39 static int 40 string_to_proto(const char *string) 41 { 42 if(strcasecmp(string, "udp") == 0) 43 return KRB5_KRBHST_UDP; 44 else if(strcasecmp(string, "tcp") == 0) 45 return KRB5_KRBHST_TCP; 46 else if(strcasecmp(string, "http") == 0) 47 return KRB5_KRBHST_HTTP; 48 return -1; 49 } 50 51 /* 52 * set `res' and `count' to the result of looking up SRV RR in DNS for 53 * `proto', `proto', `realm' using `dns_type'. 54 * if `port' != 0, force that port number 55 */ 56 57 static krb5_error_code 58 srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, 59 const char *realm, const char *dns_type, 60 const char *proto, const char *service, int port) 61 { 62 char domain[1024]; 63 struct dns_reply *r; 64 struct resource_record *rr; 65 int num_srv; 66 int proto_num; 67 int def_port; 68 69 proto_num = string_to_proto(proto); 70 if(proto_num < 0) { 71 krb5_set_error_string(context, "unknown protocol `%s'", proto); 72 return EINVAL; 73 } 74 75 if(proto_num == KRB5_KRBHST_HTTP) 76 def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80)); 77 else if(port == 0) 78 def_port = ntohs(krb5_getportbyname (context, service, proto, 88)); 79 else 80 def_port = port; 81 82 snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm); 83 84 r = dns_lookup(domain, dns_type); 85 if(r == NULL) { 86 *res = NULL; 87 *count = 0; 88 return KRB5_KDC_UNREACH; 89 } 90 91 for(num_srv = 0, rr = r->head; rr; rr = rr->next) 92 if(rr->type == T_SRV) 93 num_srv++; 94 95 *res = malloc(num_srv * sizeof(**res)); 96 if(*res == NULL) { 97 dns_free_data(r); 98 krb5_set_error_string(context, "malloc: out of memory"); 99 return ENOMEM; 100 } 101 102 dns_srv_order(r); 103 104 for(num_srv = 0, rr = r->head; rr; rr = rr->next) 105 if(rr->type == T_SRV) { 106 krb5_krbhst_info *hi; 107 hi = calloc(1, sizeof(*hi) + strlen(rr->u.srv->target)); 108 if(hi == NULL) { 109 dns_free_data(r); 110 while(--num_srv >= 0) 111 free((*res)[num_srv]); 112 free(*res); 113 return ENOMEM; 114 } 115 (*res)[num_srv++] = hi; 116 117 hi->proto = proto_num; 118 119 hi->def_port = def_port; 120 if (port != 0) 121 hi->port = port; 122 else 123 hi->port = rr->u.srv->port; 124 125 strcpy(hi->hostname, rr->u.srv->target); 126 } 127 128 *count = num_srv; 129 130 dns_free_data(r); 131 return 0; 132 } 133 134 135 struct krb5_krbhst_data { 136 char *realm; 137 unsigned int flags; 138 int def_port; 139 int port; /* hardwired port number if != 0 */ 140 #define KD_CONFIG 1 141 #define KD_SRV_UDP 2 142 #define KD_SRV_TCP 4 143 #define KD_SRV_HTTP 8 144 #define KD_FALLBACK 16 145 #define KD_CONFIG_EXISTS 32 146 147 krb5_error_code (*get_next)(krb5_context, struct krb5_krbhst_data *, 148 krb5_krbhst_info**); 149 150 unsigned int fallback_count; 151 152 struct krb5_krbhst_info *hosts, **index, **end; 153 }; 154 155 static krb5_boolean 156 krbhst_empty(const struct krb5_krbhst_data *kd) 157 { 158 return kd->index == &kd->hosts; 159 } 160 161 /* 162 * parse `spec' into a krb5_krbhst_info, defaulting the port to `def_port' 163 * and forcing it to `port' if port != 0 164 */ 165 166 static struct krb5_krbhst_info* 167 parse_hostspec(krb5_context context, const char *spec, int def_port, int port) 168 { 169 const char *p = spec; 170 struct krb5_krbhst_info *hi; 171 172 hi = calloc(1, sizeof(*hi) + strlen(spec)); 173 if(hi == NULL) 174 return NULL; 175 176 hi->proto = KRB5_KRBHST_UDP; 177 178 if(strncmp(p, "http://", 7) == 0){ 179 hi->proto = KRB5_KRBHST_HTTP; 180 p += 7; 181 } else if(strncmp(p, "http/", 5) == 0) { 182 hi->proto = KRB5_KRBHST_HTTP; 183 p += 5; 184 def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80)); 185 }else if(strncmp(p, "tcp/", 4) == 0){ 186 hi->proto = KRB5_KRBHST_TCP; 187 p += 4; 188 } else if(strncmp(p, "udp/", 4) == 0) { 189 p += 4; 190 } 191 192 if(strsep_copy(&p, ":", hi->hostname, strlen(spec) + 1) < 0) { 193 free(hi); 194 return NULL; 195 } 196 /* get rid of trailing /, and convert to lower case */ 197 hi->hostname[strcspn(hi->hostname, "/")] = '\0'; 198 strlwr(hi->hostname); 199 200 hi->port = hi->def_port = def_port; 201 if(p != NULL) { 202 char *end; 203 hi->port = strtol(p, &end, 0); 204 if(end == p) { 205 free(hi); 206 return NULL; 207 } 208 } 209 if (port) 210 hi->port = port; 211 return hi; 212 } 213 214 static void 215 free_krbhst_info(krb5_krbhst_info *hi) 216 { 217 if (hi->ai != NULL) 218 freeaddrinfo(hi->ai); 219 free(hi); 220 } 221 222 static void 223 append_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host) 224 { 225 struct krb5_krbhst_info *h; 226 227 for(h = kd->hosts; h; h = h->next) 228 if(h->proto == host->proto && 229 h->port == host->port && 230 strcmp(h->hostname, host->hostname) == 0) { 231 free_krbhst_info(host); 232 return; 233 } 234 *kd->end = host; 235 kd->end = &host->next; 236 } 237 238 static krb5_error_code 239 append_host_string(krb5_context context, struct krb5_krbhst_data *kd, 240 const char *host, int def_port, int port) 241 { 242 struct krb5_krbhst_info *hi; 243 244 hi = parse_hostspec(context, host, def_port, port); 245 if(hi == NULL) 246 return ENOMEM; 247 248 append_host_hostinfo(kd, hi); 249 return 0; 250 } 251 252 /* 253 * return a readable representation of `host' in `hostname, hostlen' 254 */ 255 256 krb5_error_code 257 krb5_krbhst_format_string(krb5_context context, const krb5_krbhst_info *host, 258 char *hostname, size_t hostlen) 259 { 260 const char *proto = ""; 261 char portstr[7] = ""; 262 if(host->proto == KRB5_KRBHST_TCP) 263 proto = "tcp/"; 264 else if(host->proto == KRB5_KRBHST_HTTP) 265 proto = "http://"; 266 if(host->port != host->def_port) 267 snprintf(portstr, sizeof(portstr), ":%d", host->port); 268 snprintf(hostname, hostlen, "%s%s%s", proto, host->hostname, portstr); 269 return 0; 270 } 271 272 /* 273 * create a getaddrinfo `hints' based on `proto' 274 */ 275 276 static void 277 make_hints(struct addrinfo *hints, int proto) 278 { 279 memset(hints, 0, sizeof(*hints)); 280 hints->ai_family = AF_UNSPEC; 281 switch(proto) { 282 case KRB5_KRBHST_UDP : 283 hints->ai_socktype = SOCK_DGRAM; 284 break; 285 case KRB5_KRBHST_HTTP : 286 case KRB5_KRBHST_TCP : 287 hints->ai_socktype = SOCK_STREAM; 288 break; 289 } 290 } 291 292 /* 293 * return an `struct addrinfo *' in `ai' corresponding to the information 294 * in `host'. free:ing is handled by krb5_krbhst_free. 295 */ 296 297 krb5_error_code 298 krb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host, 299 struct addrinfo **ai) 300 { 301 struct addrinfo hints; 302 char portstr[NI_MAXSERV]; 303 int ret; 304 305 if (host->ai == NULL) { 306 make_hints(&hints, host->proto); 307 snprintf (portstr, sizeof(portstr), "%d", host->port); 308 ret = getaddrinfo(host->hostname, portstr, &hints, &host->ai); 309 if (ret) 310 return krb5_eai_to_heim_errno(ret, errno); 311 } 312 *ai = host->ai; 313 return 0; 314 } 315 316 static krb5_boolean 317 get_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host) 318 { 319 struct krb5_krbhst_info *hi = *kd->index; 320 if(hi != NULL) { 321 *host = hi; 322 kd->index = &(*kd->index)->next; 323 return TRUE; 324 } 325 return FALSE; 326 } 327 328 static void 329 srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, 330 const char *proto, const char *service) 331 { 332 krb5_krbhst_info **res; 333 int count, i; 334 335 srv_find_realm(context, &res, &count, kd->realm, "SRV", proto, service, 336 kd->port); 337 for(i = 0; i < count; i++) 338 append_host_hostinfo(kd, res[i]); 339 free(res); 340 } 341 342 /* 343 * read the configuration for `conf_string', defaulting to kd->def_port and 344 * forcing it to `kd->port' if kd->port != 0 345 */ 346 347 static void 348 config_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, 349 const char *conf_string) 350 { 351 int i; 352 353 char **hostlist; 354 hostlist = krb5_config_get_strings(context, NULL, 355 "realms", kd->realm, conf_string, NULL); 356 357 if(hostlist == NULL) 358 return; 359 kd->flags |= KD_CONFIG_EXISTS; 360 for(i = 0; hostlist && hostlist[i] != NULL; i++) 361 append_host_string(context, kd, hostlist[i], kd->def_port, kd->port); 362 363 krb5_config_free_strings(hostlist); 364 } 365 366 /* 367 * as a fallback, look for `serv_string.kd->realm' (typically 368 * kerberos.REALM, kerberos-1.REALM, ... 369 * `port' is the default port for the service, and `proto' the 370 * protocol 371 */ 372 373 static krb5_error_code 374 fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, 375 const char *serv_string, int port, int proto) 376 { 377 char *host; 378 int ret; 379 struct addrinfo *ai; 380 struct addrinfo hints; 381 char portstr[NI_MAXSERV]; 382 383 if(kd->fallback_count == 0) 384 asprintf(&host, "%s.%s.", serv_string, kd->realm); 385 else 386 asprintf(&host, "%s-%d.%s.", 387 serv_string, kd->fallback_count, kd->realm); 388 389 if (host == NULL) 390 return ENOMEM; 391 392 make_hints(&hints, proto); 393 snprintf(portstr, sizeof(portstr), "%d", port); 394 ret = getaddrinfo(host, portstr, &hints, &ai); 395 if (ret) { 396 /* no more hosts, so we're done here */ 397 free(host); 398 kd->flags |= KD_FALLBACK; 399 } else { 400 struct krb5_krbhst_info *hi; 401 size_t hostlen = strlen(host); 402 403 hi = calloc(1, sizeof(*hi) + hostlen); 404 if(hi == NULL) { 405 free(host); 406 return ENOMEM; 407 } 408 409 hi->proto = proto; 410 hi->port = hi->def_port = port; 411 hi->ai = ai; 412 memmove(hi->hostname, host, hostlen - 1); 413 hi->hostname[hostlen - 1] = '\0'; 414 free(host); 415 append_host_hostinfo(kd, hi); 416 kd->fallback_count++; 417 } 418 return 0; 419 } 420 421 static krb5_error_code 422 kdc_get_next(krb5_context context, 423 struct krb5_krbhst_data *kd, 424 krb5_krbhst_info **host) 425 { 426 krb5_error_code ret; 427 428 if((kd->flags & KD_CONFIG) == 0) { 429 config_get_hosts(context, kd, "kdc"); 430 kd->flags |= KD_CONFIG; 431 if(get_next(kd, host)) 432 return 0; 433 } 434 435 if (kd->flags & KD_CONFIG_EXISTS) 436 return KRB5_KDC_UNREACH; /* XXX */ 437 438 if(context->srv_lookup) { 439 if((kd->flags & KD_SRV_UDP) == 0) { 440 srv_get_hosts(context, kd, "udp", "kerberos"); 441 kd->flags |= KD_SRV_UDP; 442 if(get_next(kd, host)) 443 return 0; 444 } 445 446 if((kd->flags & KD_SRV_TCP) == 0) { 447 srv_get_hosts(context, kd, "tcp", "kerberos"); 448 kd->flags |= KD_SRV_TCP; 449 if(get_next(kd, host)) 450 return 0; 451 } 452 if((kd->flags & KD_SRV_HTTP) == 0) { 453 srv_get_hosts(context, kd, "http", "kerberos"); 454 kd->flags |= KD_SRV_HTTP; 455 if(get_next(kd, host)) 456 return 0; 457 } 458 } 459 460 while((kd->flags & KD_FALLBACK) == 0) { 461 ret = fallback_get_hosts(context, kd, "kerberos", 462 kd->def_port, KRB5_KRBHST_UDP); 463 if(ret) 464 return ret; 465 if(get_next(kd, host)) 466 return 0; 467 } 468 469 return KRB5_KDC_UNREACH; /* XXX */ 470 } 471 472 static krb5_error_code 473 admin_get_next(krb5_context context, 474 struct krb5_krbhst_data *kd, 475 krb5_krbhst_info **host) 476 { 477 krb5_error_code ret; 478 479 if((kd->flags & KD_CONFIG) == 0) { 480 config_get_hosts(context, kd, "admin_server"); 481 kd->flags |= KD_CONFIG; 482 if(get_next(kd, host)) 483 return 0; 484 } 485 486 if (kd->flags & KD_CONFIG_EXISTS) 487 return KRB5_KDC_UNREACH; /* XXX */ 488 489 if(context->srv_lookup) { 490 if((kd->flags & KD_SRV_TCP) == 0) { 491 srv_get_hosts(context, kd, "tcp", "kerberos-adm"); 492 kd->flags |= KD_SRV_TCP; 493 if(get_next(kd, host)) 494 return 0; 495 } 496 } 497 498 if (krbhst_empty(kd) 499 && (kd->flags & KD_FALLBACK) == 0) { 500 ret = fallback_get_hosts(context, kd, "kerberos", 501 kd->def_port, KRB5_KRBHST_UDP); 502 if(ret) 503 return ret; 504 kd->flags |= KD_FALLBACK; 505 if(get_next(kd, host)) 506 return 0; 507 } 508 509 return KRB5_KDC_UNREACH; /* XXX */ 510 } 511 512 static krb5_error_code 513 kpasswd_get_next(krb5_context context, 514 struct krb5_krbhst_data *kd, 515 krb5_krbhst_info **host) 516 { 517 if((kd->flags & KD_CONFIG) == 0) { 518 config_get_hosts(context, kd, "kpasswd_server"); 519 if(get_next(kd, host)) 520 return 0; 521 } 522 523 if (kd->flags & KD_CONFIG_EXISTS) 524 return KRB5_KDC_UNREACH; /* XXX */ 525 526 if(context->srv_lookup) { 527 if((kd->flags & KD_SRV_UDP) == 0) { 528 srv_get_hosts(context, kd, "udp", "kpasswd"); 529 kd->flags |= KD_SRV_UDP; 530 if(get_next(kd, host)) 531 return 0; 532 } 533 } 534 535 /* no matches -> try admin */ 536 537 if (krbhst_empty(kd)) { 538 kd->flags = 0; 539 kd->port = kd->def_port; 540 kd->get_next = admin_get_next; 541 return (*kd->get_next)(context, kd, host); 542 } 543 544 return KRB5_KDC_UNREACH; /* XXX */ 545 } 546 547 static krb5_error_code 548 krb524_get_next(krb5_context context, 549 struct krb5_krbhst_data *kd, 550 krb5_krbhst_info **host) 551 { 552 if((kd->flags & KD_CONFIG) == 0) { 553 config_get_hosts(context, kd, "krb524_server"); 554 if(get_next(kd, host)) 555 return 0; 556 kd->flags |= KD_CONFIG; 557 } 558 559 if (kd->flags & KD_CONFIG_EXISTS) 560 return KRB5_KDC_UNREACH; /* XXX */ 561 562 if(context->srv_lookup) { 563 if((kd->flags & KD_SRV_UDP) == 0) { 564 srv_get_hosts(context, kd, "udp", "krb524"); 565 kd->flags |= KD_SRV_UDP; 566 if(get_next(kd, host)) 567 return 0; 568 } 569 570 if((kd->flags & KD_SRV_TCP) == 0) { 571 srv_get_hosts(context, kd, "tcp", "krb524"); 572 kd->flags |= KD_SRV_TCP; 573 if(get_next(kd, host)) 574 return 0; 575 } 576 } 577 578 /* no matches -> try kdc */ 579 580 if (krbhst_empty(kd)) { 581 kd->flags = 0; 582 kd->port = kd->def_port; 583 kd->get_next = kdc_get_next; 584 return (*kd->get_next)(context, kd, host); 585 } 586 587 return KRB5_KDC_UNREACH; /* XXX */ 588 } 589 590 static struct krb5_krbhst_data* 591 common_init(krb5_context context, 592 const char *realm) 593 { 594 struct krb5_krbhst_data *kd; 595 596 if((kd = calloc(1, sizeof(*kd))) == NULL) 597 return NULL; 598 599 if((kd->realm = strdup(realm)) == NULL) { 600 free(kd); 601 return NULL; 602 } 603 604 kd->end = kd->index = &kd->hosts; 605 return kd; 606 } 607 608 /* 609 * initialize `handle' to look for hosts of type `type' in realm `realm' 610 */ 611 612 krb5_error_code 613 krb5_krbhst_init(krb5_context context, 614 const char *realm, 615 unsigned int type, 616 krb5_krbhst_handle *handle) 617 { 618 struct krb5_krbhst_data *kd; 619 krb5_error_code (*get_next)(krb5_context, struct krb5_krbhst_data *, 620 krb5_krbhst_info **); 621 int def_port; 622 623 switch(type) { 624 case KRB5_KRBHST_KDC: 625 get_next = kdc_get_next; 626 def_port = ntohs(krb5_getportbyname (context, "kerberos", "udp", 88)); 627 break; 628 case KRB5_KRBHST_ADMIN: 629 get_next = admin_get_next; 630 def_port = ntohs(krb5_getportbyname (context, "kerberos-adm", 631 "tcp", 749)); 632 break; 633 case KRB5_KRBHST_CHANGEPW: 634 get_next = kpasswd_get_next; 635 def_port = ntohs(krb5_getportbyname (context, "kpasswd", "udp", 636 KPASSWD_PORT)); 637 break; 638 case KRB5_KRBHST_KRB524: 639 get_next = krb524_get_next; 640 def_port = ntohs(krb5_getportbyname (context, "krb524", "udp", 4444)); 641 break; 642 default: 643 krb5_set_error_string(context, "unknown krbhst type (%u)", type); 644 return ENOTTY; 645 } 646 if((kd = common_init(context, realm)) == NULL) 647 return ENOMEM; 648 kd->get_next = get_next; 649 kd->def_port = def_port; 650 *handle = kd; 651 return 0; 652 } 653 654 /* 655 * return the next host information from `handle' in `host' 656 */ 657 658 krb5_error_code 659 krb5_krbhst_next(krb5_context context, 660 krb5_krbhst_handle handle, 661 krb5_krbhst_info **host) 662 { 663 if(get_next(handle, host)) 664 return 0; 665 666 return (*handle->get_next)(context, handle, host); 667 } 668 669 /* 670 * return the next host information from `handle' as a host name 671 * in `hostname' (or length `hostlen) 672 */ 673 674 krb5_error_code 675 krb5_krbhst_next_as_string(krb5_context context, 676 krb5_krbhst_handle handle, 677 char *hostname, 678 size_t hostlen) 679 { 680 krb5_error_code ret; 681 krb5_krbhst_info *host; 682 ret = krb5_krbhst_next(context, handle, &host); 683 if(ret) 684 return ret; 685 return krb5_krbhst_format_string(context, host, hostname, hostlen); 686 } 687 688 689 void 690 krb5_krbhst_reset(krb5_context context, krb5_krbhst_handle handle) 691 { 692 handle->index = &handle->hosts; 693 } 694 695 void 696 krb5_krbhst_free(krb5_context context, krb5_krbhst_handle handle) 697 { 698 krb5_krbhst_info *h, *next; 699 700 if (handle == NULL) 701 return; 702 703 for (h = handle->hosts; h != NULL; h = next) { 704 next = h->next; 705 free_krbhst_info(h); 706 } 707 708 free(handle->realm); 709 free(handle); 710 } 711 712 /* backwards compatibility ahead */ 713 714 static krb5_error_code 715 gethostlist(krb5_context context, const char *realm, 716 unsigned int type, char ***hostlist) 717 { 718 krb5_error_code ret; 719 int nhost = 0; 720 krb5_krbhst_handle handle; 721 char host[MAXHOSTNAMELEN]; 722 krb5_krbhst_info *hostinfo; 723 724 ret = krb5_krbhst_init(context, realm, type, &handle); 725 if (ret) 726 return ret; 727 728 while(krb5_krbhst_next(context, handle, &hostinfo) == 0) 729 nhost++; 730 if(nhost == 0) 731 return KRB5_KDC_UNREACH; 732 *hostlist = calloc(nhost + 1, sizeof(**hostlist)); 733 if(*hostlist == NULL) { 734 krb5_krbhst_free(context, handle); 735 return ENOMEM; 736 } 737 738 krb5_krbhst_reset(context, handle); 739 nhost = 0; 740 while(krb5_krbhst_next_as_string(context, handle, 741 host, sizeof(host)) == 0) { 742 if(((*hostlist)[nhost++] = strdup(host)) == NULL) { 743 krb5_free_krbhst(context, *hostlist); 744 krb5_krbhst_free(context, handle); 745 return ENOMEM; 746 } 747 } 748 (*hostlist)[nhost++] = NULL; 749 krb5_krbhst_free(context, handle); 750 return 0; 751 } 752 753 /* 754 * return an malloced list of kadmin-hosts for `realm' in `hostlist' 755 */ 756 757 krb5_error_code 758 krb5_get_krb_admin_hst (krb5_context context, 759 const krb5_realm *realm, 760 char ***hostlist) 761 { 762 return gethostlist(context, *realm, KRB5_KRBHST_ADMIN, hostlist); 763 } 764 765 /* 766 * return an malloced list of changepw-hosts for `realm' in `hostlist' 767 */ 768 769 krb5_error_code 770 krb5_get_krb_changepw_hst (krb5_context context, 771 const krb5_realm *realm, 772 char ***hostlist) 773 { 774 return gethostlist(context, *realm, KRB5_KRBHST_CHANGEPW, hostlist); 775 } 776 777 /* 778 * return an malloced list of 524-hosts for `realm' in `hostlist' 779 */ 780 781 krb5_error_code 782 krb5_get_krb524hst (krb5_context context, 783 const krb5_realm *realm, 784 char ***hostlist) 785 { 786 return gethostlist(context, *realm, KRB5_KRBHST_KRB524, hostlist); 787 } 788 789 790 /* 791 * return an malloced list of KDC's for `realm' in `hostlist' 792 */ 793 794 krb5_error_code 795 krb5_get_krbhst (krb5_context context, 796 const krb5_realm *realm, 797 char ***hostlist) 798 { 799 return gethostlist(context, *realm, KRB5_KRBHST_KDC, hostlist); 800 } 801 802 /* 803 * free all the memory allocated in `hostlist' 804 */ 805 806 krb5_error_code 807 krb5_free_krbhst (krb5_context context, 808 char **hostlist) 809 { 810 char **p; 811 812 for (p = hostlist; *p; ++p) 813 free (*p); 814 free (hostlist); 815 return 0; 816 } 817