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("$Heimdal: krbhst.c 21457 2007-07-10 12:53:25Z lha $"
42 string_to_proto(const char *string
)
44 if(strcasecmp(string
, "udp") == 0)
45 return KRB5_KRBHST_UDP
;
46 else if(strcasecmp(string
, "tcp") == 0)
47 return KRB5_KRBHST_TCP
;
48 else if(strcasecmp(string
, "http") == 0)
49 return KRB5_KRBHST_HTTP
;
54 * set `res' and `count' to the result of looking up SRV RR in DNS for
55 * `proto', `proto', `realm' using `dns_type'.
56 * if `port' != 0, force that port number
59 static krb5_error_code
60 srv_find_realm(krb5_context context
, krb5_krbhst_info
***res
, int *count
,
61 const char *realm
, const char *dns_type
,
62 const char *proto
, const char *service
, int port
)
66 struct resource_record
*rr
;
74 proto_num
= string_to_proto(proto
);
76 krb5_set_error_string(context
, "unknown protocol `%s'", proto
);
80 if(proto_num
== KRB5_KRBHST_HTTP
)
81 def_port
= ntohs(krb5_getportbyname (context
, "http", "tcp", 80));
83 def_port
= ntohs(krb5_getportbyname (context
, service
, proto
, 88));
87 snprintf(domain
, sizeof(domain
), "_%s._%s.%s.", service
, proto
, realm
);
89 r
= dns_lookup(domain
, dns_type
);
91 return KRB5_KDC_UNREACH
;
93 for(num_srv
= 0, rr
= r
->head
; rr
; rr
= rr
->next
)
97 *res
= malloc(num_srv
* sizeof(**res
));
100 krb5_set_error_string(context
, "malloc: out of memory");
106 for(num_srv
= 0, rr
= r
->head
; rr
; rr
= rr
->next
)
107 if(rr
->type
== T_SRV
) {
108 krb5_krbhst_info
*hi
;
109 size_t len
= strlen(rr
->u
.srv
->target
);
111 hi
= calloc(1, sizeof(*hi
) + len
);
114 while(--num_srv
>= 0)
115 free((*res
)[num_srv
]);
120 (*res
)[num_srv
++] = hi
;
122 hi
->proto
= proto_num
;
124 hi
->def_port
= def_port
;
128 hi
->port
= rr
->u
.srv
->port
;
130 strlcpy(hi
->hostname
, rr
->u
.srv
->target
, len
+ 1);
140 struct krb5_krbhst_data
{
144 int port
; /* hardwired port number if != 0 */
148 #define KD_SRV_HTTP 8
149 #define KD_FALLBACK 16
150 #define KD_CONFIG_EXISTS 32
151 #define KD_LARGE_MSG 64
152 #define KD_PLUGIN 128
153 krb5_error_code (*get_next
)(krb5_context
, struct krb5_krbhst_data
*,
156 unsigned int fallback_count
;
158 struct krb5_krbhst_info
*hosts
, **index
, **end
;
162 krbhst_empty(const struct krb5_krbhst_data
*kd
)
164 return kd
->index
== &kd
->hosts
;
168 * Return the default protocol for the `kd' (either TCP or UDP)
172 krbhst_get_default_proto(struct krb5_krbhst_data
*kd
)
174 if (kd
->flags
& KD_LARGE_MSG
)
175 return KRB5_KRBHST_TCP
;
176 return KRB5_KRBHST_UDP
;
181 * parse `spec' into a krb5_krbhst_info, defaulting the port to `def_port'
182 * and forcing it to `port' if port != 0
185 static struct krb5_krbhst_info
*
186 parse_hostspec(krb5_context context
, struct krb5_krbhst_data
*kd
,
187 const char *spec
, int def_port
, int port
)
189 const char *p
= spec
;
190 struct krb5_krbhst_info
*hi
;
192 hi
= calloc(1, sizeof(*hi
) + strlen(spec
));
196 hi
->proto
= krbhst_get_default_proto(kd
);
198 if(strncmp(p
, "http://", 7) == 0){
199 hi
->proto
= KRB5_KRBHST_HTTP
;
201 } else if(strncmp(p
, "http/", 5) == 0) {
202 hi
->proto
= KRB5_KRBHST_HTTP
;
204 def_port
= ntohs(krb5_getportbyname (context
, "http", "tcp", 80));
205 }else if(strncmp(p
, "tcp/", 4) == 0){
206 hi
->proto
= KRB5_KRBHST_TCP
;
208 } else if(strncmp(p
, "udp/", 4) == 0) {
212 if(strsep_copy(&p
, ":", hi
->hostname
, strlen(spec
) + 1) < 0) {
216 /* get rid of trailing /, and convert to lower case */
217 hi
->hostname
[strcspn(hi
->hostname
, "/")] = '\0';
218 strlwr(hi
->hostname
);
220 hi
->port
= hi
->def_port
= def_port
;
223 hi
->port
= strtol(p
, &end
, 0);
235 _krb5_free_krbhst_info(krb5_krbhst_info
*hi
)
238 freeaddrinfo(hi
->ai
);
243 _krb5_krbhost_info_move(krb5_context context
,
244 krb5_krbhst_info
*from
,
245 krb5_krbhst_info
**to
)
247 size_t hostnamelen
= strlen(from
->hostname
);
248 /* trailing NUL is included in structure */
249 *to
= calloc(1, sizeof(**to
) + hostnamelen
);
251 krb5_set_error_string(context
, "malloc - out of memory");
255 (*to
)->proto
= from
->proto
;
256 (*to
)->port
= from
->port
;
257 (*to
)->def_port
= from
->def_port
;
258 (*to
)->ai
= from
->ai
;
261 memcpy((*to
)->hostname
, from
->hostname
, hostnamelen
+ 1);
267 append_host_hostinfo(struct krb5_krbhst_data
*kd
, struct krb5_krbhst_info
*host
)
269 struct krb5_krbhst_info
*h
;
271 for(h
= kd
->hosts
; h
; h
= h
->next
)
272 if(h
->proto
== host
->proto
&&
273 h
->port
== host
->port
&&
274 strcmp(h
->hostname
, host
->hostname
) == 0) {
275 _krb5_free_krbhst_info(host
);
279 kd
->end
= &host
->next
;
282 static krb5_error_code
283 append_host_string(krb5_context context
, struct krb5_krbhst_data
*kd
,
284 const char *host
, int def_port
, int port
)
286 struct krb5_krbhst_info
*hi
;
288 hi
= parse_hostspec(context
, kd
, host
, def_port
, port
);
292 append_host_hostinfo(kd
, hi
);
297 * return a readable representation of `host' in `hostname, hostlen'
300 krb5_error_code KRB5_LIB_FUNCTION
301 krb5_krbhst_format_string(krb5_context context
, const krb5_krbhst_info
*host
,
302 char *hostname
, size_t hostlen
)
304 const char *proto
= "";
305 char portstr
[7] = "";
306 if(host
->proto
== KRB5_KRBHST_TCP
)
308 else if(host
->proto
== KRB5_KRBHST_HTTP
)
310 if(host
->port
!= host
->def_port
)
311 snprintf(portstr
, sizeof(portstr
), ":%d", host
->port
);
312 snprintf(hostname
, hostlen
, "%s%s%s", proto
, host
->hostname
, portstr
);
317 * create a getaddrinfo `hints' based on `proto'
321 make_hints(struct addrinfo
*hints
, int proto
)
323 memset(hints
, 0, sizeof(*hints
));
324 hints
->ai_family
= AF_UNSPEC
;
326 case KRB5_KRBHST_UDP
:
327 hints
->ai_socktype
= SOCK_DGRAM
;
329 case KRB5_KRBHST_HTTP
:
330 case KRB5_KRBHST_TCP
:
331 hints
->ai_socktype
= SOCK_STREAM
;
337 * return an `struct addrinfo *' in `ai' corresponding to the information
338 * in `host'. free:ing is handled by krb5_krbhst_free.
341 krb5_error_code KRB5_LIB_FUNCTION
342 krb5_krbhst_get_addrinfo(krb5_context context
, krb5_krbhst_info
*host
,
343 struct addrinfo
**ai
)
345 struct addrinfo hints
;
346 char portstr
[NI_MAXSERV
];
349 if (host
->ai
== NULL
) {
350 make_hints(&hints
, host
->proto
);
351 snprintf (portstr
, sizeof(portstr
), "%d", host
->port
);
352 ret
= getaddrinfo(host
->hostname
, portstr
, &hints
, &host
->ai
);
354 return krb5_eai_to_heim_errno(ret
, errno
);
361 get_next(struct krb5_krbhst_data
*kd
, krb5_krbhst_info
**host
)
363 struct krb5_krbhst_info
*hi
= *kd
->index
;
366 kd
->index
= &(*kd
->index
)->next
;
373 srv_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
374 const char *proto
, const char *service
)
376 krb5_krbhst_info
**res
;
379 if (srv_find_realm(context
, &res
, &count
, kd
->realm
, "SRV", proto
, service
,
382 for(i
= 0; i
< count
; i
++)
383 append_host_hostinfo(kd
, res
[i
]);
388 * read the configuration for `conf_string', defaulting to kd->def_port and
389 * forcing it to `kd->port' if kd->port != 0
393 config_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
394 const char *conf_string
)
399 hostlist
= krb5_config_get_strings(context
, NULL
,
400 "realms", kd
->realm
, conf_string
, NULL
);
404 kd
->flags
|= KD_CONFIG_EXISTS
;
405 for(i
= 0; hostlist
&& hostlist
[i
] != NULL
; i
++)
406 append_host_string(context
, kd
, hostlist
[i
], kd
->def_port
, kd
->port
);
408 krb5_config_free_strings(hostlist
);
412 * as a fallback, look for `serv_string.kd->realm' (typically
413 * kerberos.REALM, kerberos-1.REALM, ...
414 * `port' is the default port for the service, and `proto' the
418 static krb5_error_code
419 fallback_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
420 const char *serv_string
, int port
, int proto
)
425 struct addrinfo hints
;
426 char portstr
[NI_MAXSERV
];
429 * Don't try forever in case the DNS server keep returning us
430 * entries (like wildcard entries or the .nu TLD)
432 if(kd
->fallback_count
>= 5) {
433 kd
->flags
|= KD_FALLBACK
;
437 if(kd
->fallback_count
== 0)
438 asprintf(&host
, "%s.%s.", serv_string
, kd
->realm
);
440 asprintf(&host
, "%s-%d.%s.",
441 serv_string
, kd
->fallback_count
, kd
->realm
);
446 make_hints(&hints
, proto
);
447 snprintf(portstr
, sizeof(portstr
), "%d", port
);
448 ret
= getaddrinfo(host
, portstr
, &hints
, &ai
);
450 /* no more hosts, so we're done here */
452 kd
->flags
|= KD_FALLBACK
;
454 struct krb5_krbhst_info
*hi
;
455 size_t hostlen
= strlen(host
);
457 hi
= calloc(1, sizeof(*hi
) + hostlen
);
464 hi
->port
= hi
->def_port
= port
;
466 memmove(hi
->hostname
, host
, hostlen
);
467 hi
->hostname
[hostlen
] = '\0';
469 append_host_hostinfo(kd
, hi
);
470 kd
->fallback_count
++;
476 * Fetch hosts from plugin
479 static krb5_error_code
480 add_locate(void *ctx
, int type
, struct sockaddr
*addr
)
482 struct krb5_krbhst_info
*hi
;
483 struct krb5_krbhst_data
*kd
= ctx
;
484 char host
[NI_MAXHOST
], port
[NI_MAXSERV
];
485 struct addrinfo hints
, *ai
;
490 socklen
= socket_sockaddr_size(addr
);
492 ret
= getnameinfo(addr
, socklen
, host
, sizeof(host
), port
, sizeof(port
),
493 NI_NUMERICHOST
|NI_NUMERICSERV
);
497 make_hints(&hints
, krbhst_get_default_proto(kd
));
498 ret
= getaddrinfo(host
, port
, &hints
, &ai
);
502 hostlen
= strlen(host
);
504 hi
= calloc(1, sizeof(*hi
) + hostlen
);
508 hi
->proto
= krbhst_get_default_proto(kd
);
509 hi
->port
= hi
->def_port
= socket_get_port(addr
);
511 memmove(hi
->hostname
, host
, hostlen
);
512 hi
->hostname
[hostlen
] = '\0';
513 append_host_hostinfo(kd
, hi
);
519 plugin_get_hosts(krb5_context context
,
520 struct krb5_krbhst_data
*kd
,
521 enum locate_service_type type
)
523 struct krb5_plugin
*list
= NULL
, *e
;
526 ret
= _krb5_plugin_find(context
, PLUGIN_TYPE_DATA
, "resolve", &list
);
527 if(ret
!= 0 || list
== NULL
)
530 kd
->flags
|= KD_CONFIG_EXISTS
;
532 for (e
= list
; e
!= NULL
; e
= _krb5_plugin_get_next(e
)) {
533 krb5plugin_service_locate_ftable
*service
;
536 service
= _krb5_plugin_get_symbol(e
);
537 if (service
->minor_version
!= 0)
540 (*service
->init
)(context
, &ctx
);
541 ret
= (*service
->lookup
)(ctx
, type
, kd
->realm
, 0, 0, add_locate
, kd
);
542 (*service
->fini
)(ctx
);
544 krb5_set_error_string(context
, "Plugin failed to lookup");
548 _krb5_plugin_free(list
);
555 static krb5_error_code
556 kdc_get_next(krb5_context context
,
557 struct krb5_krbhst_data
*kd
,
558 krb5_krbhst_info
**host
)
562 if ((kd
->flags
& KD_PLUGIN
) == 0) {
563 plugin_get_hosts(context
, kd
, locate_service_kdc
);
564 kd
->flags
|= KD_PLUGIN
;
565 if(get_next(kd
, host
))
569 if((kd
->flags
& KD_CONFIG
) == 0) {
570 config_get_hosts(context
, kd
, "kdc");
571 kd
->flags
|= KD_CONFIG
;
572 if(get_next(kd
, host
))
576 if (kd
->flags
& KD_CONFIG_EXISTS
)
577 return KRB5_KDC_UNREACH
; /* XXX */
579 if(context
->srv_lookup
) {
580 if((kd
->flags
& KD_SRV_UDP
) == 0 && (kd
->flags
& KD_LARGE_MSG
) == 0) {
581 srv_get_hosts(context
, kd
, "udp", "kerberos");
582 kd
->flags
|= KD_SRV_UDP
;
583 if(get_next(kd
, host
))
587 if((kd
->flags
& KD_SRV_TCP
) == 0) {
588 srv_get_hosts(context
, kd
, "tcp", "kerberos");
589 kd
->flags
|= KD_SRV_TCP
;
590 if(get_next(kd
, host
))
593 if((kd
->flags
& KD_SRV_HTTP
) == 0) {
594 srv_get_hosts(context
, kd
, "http", "kerberos");
595 kd
->flags
|= KD_SRV_HTTP
;
596 if(get_next(kd
, host
))
601 while((kd
->flags
& KD_FALLBACK
) == 0) {
602 ret
= fallback_get_hosts(context
, kd
, "kerberos",
604 krbhst_get_default_proto(kd
));
607 if(get_next(kd
, host
))
611 return KRB5_KDC_UNREACH
; /* XXX */
614 static krb5_error_code
615 admin_get_next(krb5_context context
,
616 struct krb5_krbhst_data
*kd
,
617 krb5_krbhst_info
**host
)
621 if ((kd
->flags
& KD_PLUGIN
) == 0) {
622 plugin_get_hosts(context
, kd
, locate_service_kadmin
);
623 kd
->flags
|= KD_PLUGIN
;
624 if(get_next(kd
, host
))
628 if((kd
->flags
& KD_CONFIG
) == 0) {
629 config_get_hosts(context
, kd
, "admin_server");
630 kd
->flags
|= KD_CONFIG
;
631 if(get_next(kd
, host
))
635 if (kd
->flags
& KD_CONFIG_EXISTS
)
636 return KRB5_KDC_UNREACH
; /* XXX */
638 if(context
->srv_lookup
) {
639 if((kd
->flags
& KD_SRV_TCP
) == 0) {
640 srv_get_hosts(context
, kd
, "tcp", "kerberos-adm");
641 kd
->flags
|= KD_SRV_TCP
;
642 if(get_next(kd
, host
))
648 && (kd
->flags
& KD_FALLBACK
) == 0) {
649 ret
= fallback_get_hosts(context
, kd
, "kerberos",
651 krbhst_get_default_proto(kd
));
654 kd
->flags
|= KD_FALLBACK
;
655 if(get_next(kd
, host
))
659 return KRB5_KDC_UNREACH
; /* XXX */
662 static krb5_error_code
663 kpasswd_get_next(krb5_context context
,
664 struct krb5_krbhst_data
*kd
,
665 krb5_krbhst_info
**host
)
669 if ((kd
->flags
& KD_PLUGIN
) == 0) {
670 plugin_get_hosts(context
, kd
, locate_service_kpasswd
);
671 kd
->flags
|= KD_PLUGIN
;
672 if(get_next(kd
, host
))
676 if((kd
->flags
& KD_CONFIG
) == 0) {
677 config_get_hosts(context
, kd
, "kpasswd_server");
678 kd
->flags
|= KD_CONFIG
;
679 if(get_next(kd
, host
))
683 if (kd
->flags
& KD_CONFIG_EXISTS
)
684 return KRB5_KDC_UNREACH
; /* XXX */
686 if(context
->srv_lookup
) {
687 if((kd
->flags
& KD_SRV_UDP
) == 0) {
688 srv_get_hosts(context
, kd
, "udp", "kpasswd");
689 kd
->flags
|= KD_SRV_UDP
;
690 if(get_next(kd
, host
))
693 if((kd
->flags
& KD_SRV_TCP
) == 0) {
694 srv_get_hosts(context
, kd
, "tcp", "kpasswd");
695 kd
->flags
|= KD_SRV_TCP
;
696 if(get_next(kd
, host
))
701 /* no matches -> try admin */
703 if (krbhst_empty(kd
)) {
705 kd
->port
= kd
->def_port
;
706 kd
->get_next
= admin_get_next
;
707 ret
= (*kd
->get_next
)(context
, kd
, host
);
709 (*host
)->proto
= krbhst_get_default_proto(kd
);
713 return KRB5_KDC_UNREACH
; /* XXX */
716 static krb5_error_code
717 krb524_get_next(krb5_context context
,
718 struct krb5_krbhst_data
*kd
,
719 krb5_krbhst_info
**host
)
721 if ((kd
->flags
& KD_PLUGIN
) == 0) {
722 plugin_get_hosts(context
, kd
, locate_service_krb524
);
723 kd
->flags
|= KD_PLUGIN
;
724 if(get_next(kd
, host
))
728 if((kd
->flags
& KD_CONFIG
) == 0) {
729 config_get_hosts(context
, kd
, "krb524_server");
730 if(get_next(kd
, host
))
732 kd
->flags
|= KD_CONFIG
;
735 if (kd
->flags
& KD_CONFIG_EXISTS
)
736 return KRB5_KDC_UNREACH
; /* XXX */
738 if(context
->srv_lookup
) {
739 if((kd
->flags
& KD_SRV_UDP
) == 0) {
740 srv_get_hosts(context
, kd
, "udp", "krb524");
741 kd
->flags
|= KD_SRV_UDP
;
742 if(get_next(kd
, host
))
746 if((kd
->flags
& KD_SRV_TCP
) == 0) {
747 srv_get_hosts(context
, kd
, "tcp", "krb524");
748 kd
->flags
|= KD_SRV_TCP
;
749 if(get_next(kd
, host
))
754 /* no matches -> try kdc */
756 if (krbhst_empty(kd
)) {
758 kd
->port
= kd
->def_port
;
759 kd
->get_next
= kdc_get_next
;
760 return (*kd
->get_next
)(context
, kd
, host
);
763 return KRB5_KDC_UNREACH
; /* XXX */
766 static struct krb5_krbhst_data
*
767 common_init(krb5_context context
,
771 struct krb5_krbhst_data
*kd
;
773 if((kd
= calloc(1, sizeof(*kd
))) == NULL
)
776 if((kd
->realm
= strdup(realm
)) == NULL
) {
781 /* For 'realms' without a . do not even think of going to DNS */
782 if (!strchr(realm
, '.'))
783 kd
->flags
|= KD_CONFIG_EXISTS
;
785 if (flags
& KRB5_KRBHST_FLAGS_LARGE_MSG
)
786 kd
->flags
|= KD_LARGE_MSG
;
787 kd
->end
= kd
->index
= &kd
->hosts
;
792 * initialize `handle' to look for hosts of type `type' in realm `realm'
795 krb5_error_code KRB5_LIB_FUNCTION
796 krb5_krbhst_init(krb5_context context
,
799 krb5_krbhst_handle
*handle
)
801 return krb5_krbhst_init_flags(context
, realm
, type
, 0, handle
);
804 krb5_error_code KRB5_LIB_FUNCTION
805 krb5_krbhst_init_flags(krb5_context context
,
809 krb5_krbhst_handle
*handle
)
811 struct krb5_krbhst_data
*kd
;
812 krb5_error_code (*next
)(krb5_context
, struct krb5_krbhst_data
*,
813 krb5_krbhst_info
**);
817 case KRB5_KRBHST_KDC
:
819 def_port
= ntohs(krb5_getportbyname (context
, "kerberos", "udp", 88));
821 case KRB5_KRBHST_ADMIN
:
822 next
= admin_get_next
;
823 def_port
= ntohs(krb5_getportbyname (context
, "kerberos-adm",
826 case KRB5_KRBHST_CHANGEPW
:
827 next
= kpasswd_get_next
;
828 def_port
= ntohs(krb5_getportbyname (context
, "kpasswd", "udp",
831 case KRB5_KRBHST_KRB524
:
832 next
= krb524_get_next
;
833 def_port
= ntohs(krb5_getportbyname (context
, "krb524", "udp", 4444));
836 krb5_set_error_string(context
, "unknown krbhst type (%u)", type
);
839 if((kd
= common_init(context
, realm
, flags
)) == NULL
)
842 kd
->def_port
= def_port
;
848 * return the next host information from `handle' in `host'
851 krb5_error_code KRB5_LIB_FUNCTION
852 krb5_krbhst_next(krb5_context context
,
853 krb5_krbhst_handle handle
,
854 krb5_krbhst_info
**host
)
856 if(get_next(handle
, host
))
859 return (*handle
->get_next
)(context
, handle
, host
);
863 * return the next host information from `handle' as a host name
864 * in `hostname' (or length `hostlen)
867 krb5_error_code KRB5_LIB_FUNCTION
868 krb5_krbhst_next_as_string(krb5_context context
,
869 krb5_krbhst_handle handle
,
874 krb5_krbhst_info
*host
;
875 ret
= krb5_krbhst_next(context
, handle
, &host
);
878 return krb5_krbhst_format_string(context
, host
, hostname
, hostlen
);
882 void KRB5_LIB_FUNCTION
883 krb5_krbhst_reset(krb5_context context
, krb5_krbhst_handle handle
)
885 handle
->index
= &handle
->hosts
;
888 void KRB5_LIB_FUNCTION
889 krb5_krbhst_free(krb5_context context
, krb5_krbhst_handle handle
)
891 krb5_krbhst_info
*h
, *next
;
896 for (h
= handle
->hosts
; h
!= NULL
; h
= next
) {
898 _krb5_free_krbhst_info(h
);
905 /* backwards compatibility ahead */
907 static krb5_error_code
908 gethostlist(krb5_context context
, const char *realm
,
909 unsigned int type
, char ***hostlist
)
913 krb5_krbhst_handle handle
;
914 char host
[MAXHOSTNAMELEN
];
915 krb5_krbhst_info
*hostinfo
;
917 ret
= krb5_krbhst_init(context
, realm
, type
, &handle
);
921 while(krb5_krbhst_next(context
, handle
, &hostinfo
) == 0)
924 krb5_set_error_string(context
, "No KDC found for realm %s", realm
);
925 return KRB5_KDC_UNREACH
;
927 *hostlist
= calloc(nhost
+ 1, sizeof(**hostlist
));
928 if(*hostlist
== NULL
) {
929 krb5_krbhst_free(context
, handle
);
933 krb5_krbhst_reset(context
, handle
);
935 while(krb5_krbhst_next_as_string(context
, handle
,
936 host
, sizeof(host
)) == 0) {
937 if(((*hostlist
)[nhost
++] = strdup(host
)) == NULL
) {
938 krb5_free_krbhst(context
, *hostlist
);
939 krb5_krbhst_free(context
, handle
);
943 (*hostlist
)[nhost
++] = NULL
;
944 krb5_krbhst_free(context
, handle
);
949 * return an malloced list of kadmin-hosts for `realm' in `hostlist'
952 krb5_error_code KRB5_LIB_FUNCTION
953 krb5_get_krb_admin_hst (krb5_context context
,
954 const krb5_realm
*realm
,
957 return gethostlist(context
, *realm
, KRB5_KRBHST_ADMIN
, hostlist
);
961 * return an malloced list of changepw-hosts for `realm' in `hostlist'
964 krb5_error_code KRB5_LIB_FUNCTION
965 krb5_get_krb_changepw_hst (krb5_context context
,
966 const krb5_realm
*realm
,
969 return gethostlist(context
, *realm
, KRB5_KRBHST_CHANGEPW
, hostlist
);
973 * return an malloced list of 524-hosts for `realm' in `hostlist'
976 krb5_error_code KRB5_LIB_FUNCTION
977 krb5_get_krb524hst (krb5_context context
,
978 const krb5_realm
*realm
,
981 return gethostlist(context
, *realm
, KRB5_KRBHST_KRB524
, hostlist
);
986 * return an malloced list of KDC's for `realm' in `hostlist'
989 krb5_error_code KRB5_LIB_FUNCTION
990 krb5_get_krbhst (krb5_context context
,
991 const krb5_realm
*realm
,
994 return gethostlist(context
, *realm
, KRB5_KRBHST_KDC
, hostlist
);
998 * free all the memory allocated in `hostlist'
1001 krb5_error_code KRB5_LIB_FUNCTION
1002 krb5_free_krbhst (krb5_context context
,
1007 for (p
= hostlist
; *p
; ++p
)