2 * Copyright (c) 2001 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
34 #include "krb5_locl.h"
36 #include "locate_plugin.h"
38 RCSID("$Id: krbhst.c,v 1.58 2006/11/12 20:05:20 lha Exp $");
41 string_to_proto(const char *string
)
43 if(strcasecmp(string
, "udp") == 0)
44 return KRB5_KRBHST_UDP
;
45 else if(strcasecmp(string
, "tcp") == 0)
46 return KRB5_KRBHST_TCP
;
47 else if(strcasecmp(string
, "http") == 0)
48 return KRB5_KRBHST_HTTP
;
53 * set `res' and `count' to the result of looking up SRV RR in DNS for
54 * `proto', `proto', `realm' using `dns_type'.
55 * if `port' != 0, force that port number
58 static krb5_error_code
59 srv_find_realm(krb5_context context
, krb5_krbhst_info
***res
, int *count
,
60 const char *realm
, const char *dns_type
,
61 const char *proto
, const char *service
, int port
)
65 struct resource_record
*rr
;
73 proto_num
= string_to_proto(proto
);
75 krb5_set_error_string(context
, "unknown protocol `%s'", proto
);
79 if(proto_num
== KRB5_KRBHST_HTTP
)
80 def_port
= ntohs(krb5_getportbyname (context
, "http", "tcp", 80));
82 def_port
= ntohs(krb5_getportbyname (context
, service
, proto
, 88));
86 snprintf(domain
, sizeof(domain
), "_%s._%s.%s.", service
, proto
, realm
);
88 r
= dns_lookup(domain
, dns_type
);
90 return KRB5_KDC_UNREACH
;
92 for(num_srv
= 0, rr
= r
->head
; rr
; rr
= rr
->next
)
96 *res
= malloc(num_srv
* sizeof(**res
));
99 krb5_set_error_string(context
, "malloc: out of memory");
105 for(num_srv
= 0, rr
= r
->head
; rr
; rr
= rr
->next
)
106 if(rr
->type
== T_SRV
) {
107 krb5_krbhst_info
*hi
;
108 size_t len
= strlen(rr
->u
.srv
->target
);
110 hi
= calloc(1, sizeof(*hi
) + len
);
113 while(--num_srv
>= 0)
114 free((*res
)[num_srv
]);
119 (*res
)[num_srv
++] = hi
;
121 hi
->proto
= proto_num
;
123 hi
->def_port
= def_port
;
127 hi
->port
= rr
->u
.srv
->port
;
129 strlcpy(hi
->hostname
, rr
->u
.srv
->target
, len
+ 1);
139 struct krb5_krbhst_data
{
143 int port
; /* hardwired port number if != 0 */
147 #define KD_SRV_HTTP 8
148 #define KD_FALLBACK 16
149 #define KD_CONFIG_EXISTS 32
150 #define KD_LARGE_MSG 64
151 #define KD_PLUGIN 128
152 krb5_error_code (*get_next
)(krb5_context
, struct krb5_krbhst_data
*,
155 unsigned int fallback_count
;
157 struct krb5_krbhst_info
*hosts
, **index
, **end
;
161 krbhst_empty(const struct krb5_krbhst_data
*kd
)
163 return kd
->index
== &kd
->hosts
;
167 * Return the default protocol for the `kd' (either TCP or UDP)
171 krbhst_get_default_proto(struct krb5_krbhst_data
*kd
)
173 if (kd
->flags
& KD_LARGE_MSG
)
174 return KRB5_KRBHST_TCP
;
175 return KRB5_KRBHST_UDP
;
180 * parse `spec' into a krb5_krbhst_info, defaulting the port to `def_port'
181 * and forcing it to `port' if port != 0
184 static struct krb5_krbhst_info
*
185 parse_hostspec(krb5_context context
, struct krb5_krbhst_data
*kd
,
186 const char *spec
, int def_port
, int port
)
188 const char *p
= spec
;
189 struct krb5_krbhst_info
*hi
;
191 hi
= calloc(1, sizeof(*hi
) + strlen(spec
));
195 hi
->proto
= krbhst_get_default_proto(kd
);
197 if(strncmp(p
, "http://", 7) == 0){
198 hi
->proto
= KRB5_KRBHST_HTTP
;
200 } else if(strncmp(p
, "http/", 5) == 0) {
201 hi
->proto
= KRB5_KRBHST_HTTP
;
203 def_port
= ntohs(krb5_getportbyname (context
, "http", "tcp", 80));
204 }else if(strncmp(p
, "tcp/", 4) == 0){
205 hi
->proto
= KRB5_KRBHST_TCP
;
207 } else if(strncmp(p
, "udp/", 4) == 0) {
211 if(strsep_copy(&p
, ":", hi
->hostname
, strlen(spec
) + 1) < 0) {
215 /* get rid of trailing /, and convert to lower case */
216 hi
->hostname
[strcspn(hi
->hostname
, "/")] = '\0';
217 strlwr(hi
->hostname
);
219 hi
->port
= hi
->def_port
= def_port
;
222 hi
->port
= strtol(p
, &end
, 0);
234 _krb5_free_krbhst_info(krb5_krbhst_info
*hi
)
237 freeaddrinfo(hi
->ai
);
242 _krb5_krbhost_info_move(krb5_context context
,
243 krb5_krbhst_info
*from
,
244 krb5_krbhst_info
**to
)
246 size_t hostnamelen
= strlen(from
->hostname
);
247 /* trailing NUL is included in structure */
248 *to
= calloc(1, sizeof(**to
) + hostnamelen
);
250 krb5_set_error_string(context
, "malloc - out of memory");
254 (*to
)->proto
= from
->proto
;
255 (*to
)->port
= from
->port
;
256 (*to
)->def_port
= from
->def_port
;
257 (*to
)->ai
= from
->ai
;
260 memcpy((*to
)->hostname
, from
->hostname
, hostnamelen
+ 1);
266 append_host_hostinfo(struct krb5_krbhst_data
*kd
, struct krb5_krbhst_info
*host
)
268 struct krb5_krbhst_info
*h
;
270 for(h
= kd
->hosts
; h
; h
= h
->next
)
271 if(h
->proto
== host
->proto
&&
272 h
->port
== host
->port
&&
273 strcmp(h
->hostname
, host
->hostname
) == 0) {
274 _krb5_free_krbhst_info(host
);
278 kd
->end
= &host
->next
;
281 static krb5_error_code
282 append_host_string(krb5_context context
, struct krb5_krbhst_data
*kd
,
283 const char *host
, int def_port
, int port
)
285 struct krb5_krbhst_info
*hi
;
287 hi
= parse_hostspec(context
, kd
, host
, def_port
, port
);
291 append_host_hostinfo(kd
, hi
);
296 * return a readable representation of `host' in `hostname, hostlen'
299 krb5_error_code KRB5_LIB_FUNCTION
300 krb5_krbhst_format_string(krb5_context context
, const krb5_krbhst_info
*host
,
301 char *hostname
, size_t hostlen
)
303 const char *proto
= "";
304 char portstr
[7] = "";
305 if(host
->proto
== KRB5_KRBHST_TCP
)
307 else if(host
->proto
== KRB5_KRBHST_HTTP
)
309 if(host
->port
!= host
->def_port
)
310 snprintf(portstr
, sizeof(portstr
), ":%d", host
->port
);
311 snprintf(hostname
, hostlen
, "%s%s%s", proto
, host
->hostname
, portstr
);
316 * create a getaddrinfo `hints' based on `proto'
320 make_hints(struct addrinfo
*hints
, int proto
)
322 memset(hints
, 0, sizeof(*hints
));
323 hints
->ai_family
= AF_UNSPEC
;
325 case KRB5_KRBHST_UDP
:
326 hints
->ai_socktype
= SOCK_DGRAM
;
328 case KRB5_KRBHST_HTTP
:
329 case KRB5_KRBHST_TCP
:
330 hints
->ai_socktype
= SOCK_STREAM
;
336 * return an `struct addrinfo *' in `ai' corresponding to the information
337 * in `host'. free:ing is handled by krb5_krbhst_free.
340 krb5_error_code KRB5_LIB_FUNCTION
341 krb5_krbhst_get_addrinfo(krb5_context context
, krb5_krbhst_info
*host
,
342 struct addrinfo
**ai
)
344 struct addrinfo hints
;
345 char portstr
[NI_MAXSERV
];
348 if (host
->ai
== NULL
) {
349 make_hints(&hints
, host
->proto
);
350 snprintf (portstr
, sizeof(portstr
), "%d", host
->port
);
351 ret
= getaddrinfo(host
->hostname
, portstr
, &hints
, &host
->ai
);
353 return krb5_eai_to_heim_errno(ret
, errno
);
360 get_next(struct krb5_krbhst_data
*kd
, krb5_krbhst_info
**host
)
362 struct krb5_krbhst_info
*hi
= *kd
->index
;
365 kd
->index
= &(*kd
->index
)->next
;
372 srv_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
373 const char *proto
, const char *service
)
375 krb5_krbhst_info
**res
;
378 if (srv_find_realm(context
, &res
, &count
, kd
->realm
, "SRV", proto
, service
,
381 for(i
= 0; i
< count
; i
++)
382 append_host_hostinfo(kd
, res
[i
]);
387 * read the configuration for `conf_string', defaulting to kd->def_port and
388 * forcing it to `kd->port' if kd->port != 0
392 config_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
393 const char *conf_string
)
398 hostlist
= krb5_config_get_strings(context
, NULL
,
399 "realms", kd
->realm
, conf_string
, NULL
);
403 kd
->flags
|= KD_CONFIG_EXISTS
;
404 for(i
= 0; hostlist
&& hostlist
[i
] != NULL
; i
++)
405 append_host_string(context
, kd
, hostlist
[i
], kd
->def_port
, kd
->port
);
407 krb5_config_free_strings(hostlist
);
411 * as a fallback, look for `serv_string.kd->realm' (typically
412 * kerberos.REALM, kerberos-1.REALM, ...
413 * `port' is the default port for the service, and `proto' the
417 static krb5_error_code
418 fallback_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
419 const char *serv_string
, int port
, int proto
)
424 struct addrinfo hints
;
425 char portstr
[NI_MAXSERV
];
428 * Don't try forever in case the DNS server keep returning us
429 * entries (like wildcard entries or the .nu TLD)
431 if(kd
->fallback_count
>= 5) {
432 kd
->flags
|= KD_FALLBACK
;
436 if(kd
->fallback_count
== 0)
437 asprintf(&host
, "%s.%s.", serv_string
, kd
->realm
);
439 asprintf(&host
, "%s-%d.%s.",
440 serv_string
, kd
->fallback_count
, kd
->realm
);
445 make_hints(&hints
, proto
);
446 snprintf(portstr
, sizeof(portstr
), "%d", port
);
447 ret
= getaddrinfo(host
, portstr
, &hints
, &ai
);
449 /* no more hosts, so we're done here */
451 kd
->flags
|= KD_FALLBACK
;
453 struct krb5_krbhst_info
*hi
;
454 size_t hostlen
= strlen(host
);
456 hi
= calloc(1, sizeof(*hi
) + hostlen
);
463 hi
->port
= hi
->def_port
= port
;
465 memmove(hi
->hostname
, host
, hostlen
);
466 hi
->hostname
[hostlen
] = '\0';
468 append_host_hostinfo(kd
, hi
);
469 kd
->fallback_count
++;
475 * Fetch hosts from plugin
478 static krb5_error_code
479 add_locate(void *ctx
, int type
, struct sockaddr
*addr
)
481 struct krb5_krbhst_info
*hi
;
482 struct krb5_krbhst_data
*kd
= ctx
;
483 char host
[NI_MAXHOST
], port
[NI_MAXSERV
];
484 struct addrinfo hints
, *ai
;
489 socklen
= socket_sockaddr_size(addr
);
491 ret
= getnameinfo(addr
, socklen
, host
, sizeof(host
), port
, sizeof(port
),
492 NI_NUMERICHOST
|NI_NUMERICSERV
);
496 memset(&hints
, 0, sizeof(hints
));
497 ret
= getaddrinfo(host
, port
, &hints
, &ai
);
501 hostlen
= strlen(host
);
503 hi
= calloc(1, sizeof(*hi
) + hostlen
);
509 hi
->proto
= krbhst_get_default_proto(kd
);
510 hi
->port
= hi
->def_port
= socket_get_port(addr
);
512 memmove(hi
->hostname
, host
, hostlen
);
513 hi
->hostname
[hostlen
] = '\0';
514 append_host_hostinfo(kd
, hi
);
520 plugin_get_hosts(krb5_context context
,
521 struct krb5_krbhst_data
*kd
,
522 enum locate_service_type type
)
524 struct krb5_plugin
*list
, *e
;
527 ret
= _krb5_plugin_find(context
, PLUGIN_TYPE_DATA
, "resolve", &list
);
528 if(ret
!= 0 || list
== NULL
)
531 kd
->flags
|= KD_CONFIG_EXISTS
;
533 for (e
= list
; e
!= NULL
; e
= _krb5_plugin_get_next(e
)) {
534 krb5plugin_service_locate_ftable
*service
;
537 service
= _krb5_plugin_get_symbol(e
);
538 if (service
->minor_version
!= 0)
541 (*service
->init
)(context
, &ctx
);
542 ret
= (*service
->lookup
)(ctx
, type
, kd
->realm
, 0, 0, add_locate
, kd
);
543 (*service
->fini
)(ctx
);
545 krb5_set_error_string(context
, "Plugin failed to lookup");
549 _krb5_plugin_free(list
);
556 static krb5_error_code
557 kdc_get_next(krb5_context context
,
558 struct krb5_krbhst_data
*kd
,
559 krb5_krbhst_info
**host
)
563 if ((kd
->flags
& KD_PLUGIN
) == 0) {
564 plugin_get_hosts(context
, kd
, locate_service_kdc
);
565 kd
->flags
|= KD_PLUGIN
;
566 if(get_next(kd
, host
))
570 if((kd
->flags
& KD_CONFIG
) == 0) {
571 config_get_hosts(context
, kd
, "kdc");
572 kd
->flags
|= KD_CONFIG
;
573 if(get_next(kd
, host
))
577 if (kd
->flags
& KD_CONFIG_EXISTS
)
578 return KRB5_KDC_UNREACH
; /* XXX */
580 if(context
->srv_lookup
) {
581 if((kd
->flags
& KD_SRV_UDP
) == 0 && (kd
->flags
& KD_LARGE_MSG
) == 0) {
582 srv_get_hosts(context
, kd
, "udp", "kerberos");
583 kd
->flags
|= KD_SRV_UDP
;
584 if(get_next(kd
, host
))
588 if((kd
->flags
& KD_SRV_TCP
) == 0) {
589 srv_get_hosts(context
, kd
, "tcp", "kerberos");
590 kd
->flags
|= KD_SRV_TCP
;
591 if(get_next(kd
, host
))
594 if((kd
->flags
& KD_SRV_HTTP
) == 0) {
595 srv_get_hosts(context
, kd
, "http", "kerberos");
596 kd
->flags
|= KD_SRV_HTTP
;
597 if(get_next(kd
, host
))
602 while((kd
->flags
& KD_FALLBACK
) == 0) {
603 ret
= fallback_get_hosts(context
, kd
, "kerberos",
605 krbhst_get_default_proto(kd
));
608 if(get_next(kd
, host
))
612 return KRB5_KDC_UNREACH
; /* XXX */
615 static krb5_error_code
616 admin_get_next(krb5_context context
,
617 struct krb5_krbhst_data
*kd
,
618 krb5_krbhst_info
**host
)
622 if((kd
->flags
& KD_CONFIG
) == 0) {
623 config_get_hosts(context
, kd
, "admin_server");
624 kd
->flags
|= KD_CONFIG
;
625 if(get_next(kd
, host
))
629 if (kd
->flags
& KD_CONFIG_EXISTS
)
630 return KRB5_KDC_UNREACH
; /* XXX */
632 if(context
->srv_lookup
) {
633 if((kd
->flags
& KD_SRV_TCP
) == 0) {
634 srv_get_hosts(context
, kd
, "tcp", "kerberos-adm");
635 kd
->flags
|= KD_SRV_TCP
;
636 if(get_next(kd
, host
))
642 && (kd
->flags
& KD_FALLBACK
) == 0) {
643 ret
= fallback_get_hosts(context
, kd
, "kerberos",
645 krbhst_get_default_proto(kd
));
648 kd
->flags
|= KD_FALLBACK
;
649 if(get_next(kd
, host
))
653 return KRB5_KDC_UNREACH
; /* XXX */
656 static krb5_error_code
657 kpasswd_get_next(krb5_context context
,
658 struct krb5_krbhst_data
*kd
,
659 krb5_krbhst_info
**host
)
663 if((kd
->flags
& KD_CONFIG
) == 0) {
664 config_get_hosts(context
, kd
, "kpasswd_server");
665 kd
->flags
|= KD_CONFIG
;
666 if(get_next(kd
, host
))
670 if (kd
->flags
& KD_CONFIG_EXISTS
)
671 return KRB5_KDC_UNREACH
; /* XXX */
673 if(context
->srv_lookup
) {
674 if((kd
->flags
& KD_SRV_UDP
) == 0) {
675 srv_get_hosts(context
, kd
, "udp", "kpasswd");
676 kd
->flags
|= KD_SRV_UDP
;
677 if(get_next(kd
, host
))
680 if((kd
->flags
& KD_SRV_TCP
) == 0) {
681 srv_get_hosts(context
, kd
, "tcp", "kpasswd");
682 kd
->flags
|= KD_SRV_TCP
;
683 if(get_next(kd
, host
))
688 /* no matches -> try admin */
690 if (krbhst_empty(kd
)) {
692 kd
->port
= kd
->def_port
;
693 kd
->get_next
= admin_get_next
;
694 ret
= (*kd
->get_next
)(context
, kd
, host
);
696 (*host
)->proto
= krbhst_get_default_proto(kd
);
700 return KRB5_KDC_UNREACH
; /* XXX */
703 static krb5_error_code
704 krb524_get_next(krb5_context context
,
705 struct krb5_krbhst_data
*kd
,
706 krb5_krbhst_info
**host
)
708 if((kd
->flags
& KD_CONFIG
) == 0) {
709 config_get_hosts(context
, kd
, "krb524_server");
710 if(get_next(kd
, host
))
712 kd
->flags
|= KD_CONFIG
;
715 if (kd
->flags
& KD_CONFIG_EXISTS
)
716 return KRB5_KDC_UNREACH
; /* XXX */
718 if(context
->srv_lookup
) {
719 if((kd
->flags
& KD_SRV_UDP
) == 0) {
720 srv_get_hosts(context
, kd
, "udp", "krb524");
721 kd
->flags
|= KD_SRV_UDP
;
722 if(get_next(kd
, host
))
726 if((kd
->flags
& KD_SRV_TCP
) == 0) {
727 srv_get_hosts(context
, kd
, "tcp", "krb524");
728 kd
->flags
|= KD_SRV_TCP
;
729 if(get_next(kd
, host
))
734 /* no matches -> try kdc */
736 if (krbhst_empty(kd
)) {
738 kd
->port
= kd
->def_port
;
739 kd
->get_next
= kdc_get_next
;
740 return (*kd
->get_next
)(context
, kd
, host
);
743 return KRB5_KDC_UNREACH
; /* XXX */
746 static struct krb5_krbhst_data
*
747 common_init(krb5_context context
,
751 struct krb5_krbhst_data
*kd
;
753 if((kd
= calloc(1, sizeof(*kd
))) == NULL
)
756 if((kd
->realm
= strdup(realm
)) == NULL
) {
761 /* For 'realms' without a . do not even think of going to DNS */
762 if (!strchr(realm
, '.'))
763 kd
->flags
|= KD_CONFIG_EXISTS
;
765 if (flags
& KRB5_KRBHST_FLAGS_LARGE_MSG
)
766 kd
->flags
|= KD_LARGE_MSG
;
767 kd
->end
= kd
->index
= &kd
->hosts
;
772 * initialize `handle' to look for hosts of type `type' in realm `realm'
775 krb5_error_code KRB5_LIB_FUNCTION
776 krb5_krbhst_init(krb5_context context
,
779 krb5_krbhst_handle
*handle
)
781 return krb5_krbhst_init_flags(context
, realm
, type
, 0, handle
);
784 krb5_error_code KRB5_LIB_FUNCTION
785 krb5_krbhst_init_flags(krb5_context context
,
789 krb5_krbhst_handle
*handle
)
791 struct krb5_krbhst_data
*kd
;
792 krb5_error_code (*next
)(krb5_context
, struct krb5_krbhst_data
*,
793 krb5_krbhst_info
**);
797 case KRB5_KRBHST_KDC
:
799 def_port
= ntohs(krb5_getportbyname (context
, "kerberos", "udp", 88));
801 case KRB5_KRBHST_ADMIN
:
802 next
= admin_get_next
;
803 def_port
= ntohs(krb5_getportbyname (context
, "kerberos-adm",
806 case KRB5_KRBHST_CHANGEPW
:
807 next
= kpasswd_get_next
;
808 def_port
= ntohs(krb5_getportbyname (context
, "kpasswd", "udp",
811 case KRB5_KRBHST_KRB524
:
812 next
= krb524_get_next
;
813 def_port
= ntohs(krb5_getportbyname (context
, "krb524", "udp", 4444));
816 krb5_set_error_string(context
, "unknown krbhst type (%u)", type
);
819 if((kd
= common_init(context
, realm
, flags
)) == NULL
)
822 kd
->def_port
= def_port
;
828 * return the next host information from `handle' in `host'
831 krb5_error_code KRB5_LIB_FUNCTION
832 krb5_krbhst_next(krb5_context context
,
833 krb5_krbhst_handle handle
,
834 krb5_krbhst_info
**host
)
836 if(get_next(handle
, host
))
839 return (*handle
->get_next
)(context
, handle
, host
);
843 * return the next host information from `handle' as a host name
844 * in `hostname' (or length `hostlen)
847 krb5_error_code KRB5_LIB_FUNCTION
848 krb5_krbhst_next_as_string(krb5_context context
,
849 krb5_krbhst_handle handle
,
854 krb5_krbhst_info
*host
;
855 ret
= krb5_krbhst_next(context
, handle
, &host
);
858 return krb5_krbhst_format_string(context
, host
, hostname
, hostlen
);
862 void KRB5_LIB_FUNCTION
863 krb5_krbhst_reset(krb5_context context
, krb5_krbhst_handle handle
)
865 handle
->index
= &handle
->hosts
;
868 void KRB5_LIB_FUNCTION
869 krb5_krbhst_free(krb5_context context
, krb5_krbhst_handle handle
)
871 krb5_krbhst_info
*h
, *next
;
876 for (h
= handle
->hosts
; h
!= NULL
; h
= next
) {
878 _krb5_free_krbhst_info(h
);
885 /* backwards compatibility ahead */
887 static krb5_error_code
888 gethostlist(krb5_context context
, const char *realm
,
889 unsigned int type
, char ***hostlist
)
893 krb5_krbhst_handle handle
;
894 char host
[MAXHOSTNAMELEN
];
895 krb5_krbhst_info
*hostinfo
;
897 ret
= krb5_krbhst_init(context
, realm
, type
, &handle
);
901 while(krb5_krbhst_next(context
, handle
, &hostinfo
) == 0)
904 return KRB5_KDC_UNREACH
;
905 *hostlist
= calloc(nhost
+ 1, sizeof(**hostlist
));
906 if(*hostlist
== NULL
) {
907 krb5_krbhst_free(context
, handle
);
911 krb5_krbhst_reset(context
, handle
);
913 while(krb5_krbhst_next_as_string(context
, handle
,
914 host
, sizeof(host
)) == 0) {
915 if(((*hostlist
)[nhost
++] = strdup(host
)) == NULL
) {
916 krb5_free_krbhst(context
, *hostlist
);
917 krb5_krbhst_free(context
, handle
);
921 (*hostlist
)[nhost
++] = NULL
;
922 krb5_krbhst_free(context
, handle
);
927 * return an malloced list of kadmin-hosts for `realm' in `hostlist'
930 krb5_error_code KRB5_LIB_FUNCTION
931 krb5_get_krb_admin_hst (krb5_context context
,
932 const krb5_realm
*realm
,
935 return gethostlist(context
, *realm
, KRB5_KRBHST_ADMIN
, hostlist
);
939 * return an malloced list of changepw-hosts for `realm' in `hostlist'
942 krb5_error_code KRB5_LIB_FUNCTION
943 krb5_get_krb_changepw_hst (krb5_context context
,
944 const krb5_realm
*realm
,
947 return gethostlist(context
, *realm
, KRB5_KRBHST_CHANGEPW
, hostlist
);
951 * return an malloced list of 524-hosts for `realm' in `hostlist'
954 krb5_error_code KRB5_LIB_FUNCTION
955 krb5_get_krb524hst (krb5_context context
,
956 const krb5_realm
*realm
,
959 return gethostlist(context
, *realm
, KRB5_KRBHST_KRB524
, hostlist
);
964 * return an malloced list of KDC's for `realm' in `hostlist'
967 krb5_error_code KRB5_LIB_FUNCTION
968 krb5_get_krbhst (krb5_context context
,
969 const krb5_realm
*realm
,
972 return gethostlist(context
, *realm
, KRB5_KRBHST_KDC
, hostlist
);
976 * free all the memory allocated in `hostlist'
979 krb5_error_code KRB5_LIB_FUNCTION
980 krb5_free_krbhst (krb5_context context
,
985 for (p
= hostlist
; *p
; ++p
)