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"
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 make_hints(&hints
, krbhst_get_default_proto(kd
));
497 ret
= getaddrinfo(host
, port
, &hints
, &ai
);
501 hostlen
= strlen(host
);
503 hi
= calloc(1, sizeof(*hi
) + hostlen
);
507 hi
->proto
= krbhst_get_default_proto(kd
);
508 hi
->port
= hi
->def_port
= socket_get_port(addr
);
510 memmove(hi
->hostname
, host
, hostlen
);
511 hi
->hostname
[hostlen
] = '\0';
512 append_host_hostinfo(kd
, hi
);
518 plugin_get_hosts(krb5_context context
,
519 struct krb5_krbhst_data
*kd
,
520 enum locate_service_type type
)
522 struct krb5_plugin
*list
= NULL
, *e
;
525 ret
= _krb5_plugin_find(context
, PLUGIN_TYPE_DATA
, "resolve", &list
);
526 if(ret
!= 0 || list
== NULL
)
529 kd
->flags
|= KD_CONFIG_EXISTS
;
531 for (e
= list
; e
!= NULL
; e
= _krb5_plugin_get_next(e
)) {
532 krb5plugin_service_locate_ftable
*service
;
535 service
= _krb5_plugin_get_symbol(e
);
536 if (service
->minor_version
!= 0)
539 (*service
->init
)(context
, &ctx
);
540 ret
= (*service
->lookup
)(ctx
, type
, kd
->realm
, 0, 0, add_locate
, kd
);
541 (*service
->fini
)(ctx
);
543 krb5_set_error_string(context
, "Plugin failed to lookup");
547 _krb5_plugin_free(list
);
554 static krb5_error_code
555 kdc_get_next(krb5_context context
,
556 struct krb5_krbhst_data
*kd
,
557 krb5_krbhst_info
**host
)
561 if ((kd
->flags
& KD_PLUGIN
) == 0) {
562 plugin_get_hosts(context
, kd
, locate_service_kdc
);
563 kd
->flags
|= KD_PLUGIN
;
564 if(get_next(kd
, host
))
568 if((kd
->flags
& KD_CONFIG
) == 0) {
569 config_get_hosts(context
, kd
, "kdc");
570 kd
->flags
|= KD_CONFIG
;
571 if(get_next(kd
, host
))
575 if (kd
->flags
& KD_CONFIG_EXISTS
)
576 return KRB5_KDC_UNREACH
; /* XXX */
578 if(context
->srv_lookup
) {
579 if((kd
->flags
& KD_SRV_UDP
) == 0 && (kd
->flags
& KD_LARGE_MSG
) == 0) {
580 srv_get_hosts(context
, kd
, "udp", "kerberos");
581 kd
->flags
|= KD_SRV_UDP
;
582 if(get_next(kd
, host
))
586 if((kd
->flags
& KD_SRV_TCP
) == 0) {
587 srv_get_hosts(context
, kd
, "tcp", "kerberos");
588 kd
->flags
|= KD_SRV_TCP
;
589 if(get_next(kd
, host
))
592 if((kd
->flags
& KD_SRV_HTTP
) == 0) {
593 srv_get_hosts(context
, kd
, "http", "kerberos");
594 kd
->flags
|= KD_SRV_HTTP
;
595 if(get_next(kd
, host
))
600 while((kd
->flags
& KD_FALLBACK
) == 0) {
601 ret
= fallback_get_hosts(context
, kd
, "kerberos",
603 krbhst_get_default_proto(kd
));
606 if(get_next(kd
, host
))
610 return KRB5_KDC_UNREACH
; /* XXX */
613 static krb5_error_code
614 admin_get_next(krb5_context context
,
615 struct krb5_krbhst_data
*kd
,
616 krb5_krbhst_info
**host
)
620 if ((kd
->flags
& KD_PLUGIN
) == 0) {
621 plugin_get_hosts(context
, kd
, locate_service_kadmin
);
622 kd
->flags
|= KD_PLUGIN
;
623 if(get_next(kd
, host
))
627 if((kd
->flags
& KD_CONFIG
) == 0) {
628 config_get_hosts(context
, kd
, "admin_server");
629 kd
->flags
|= KD_CONFIG
;
630 if(get_next(kd
, host
))
634 if (kd
->flags
& KD_CONFIG_EXISTS
)
635 return KRB5_KDC_UNREACH
; /* XXX */
637 if(context
->srv_lookup
) {
638 if((kd
->flags
& KD_SRV_TCP
) == 0) {
639 srv_get_hosts(context
, kd
, "tcp", "kerberos-adm");
640 kd
->flags
|= KD_SRV_TCP
;
641 if(get_next(kd
, host
))
647 && (kd
->flags
& KD_FALLBACK
) == 0) {
648 ret
= fallback_get_hosts(context
, kd
, "kerberos",
650 krbhst_get_default_proto(kd
));
653 kd
->flags
|= KD_FALLBACK
;
654 if(get_next(kd
, host
))
658 return KRB5_KDC_UNREACH
; /* XXX */
661 static krb5_error_code
662 kpasswd_get_next(krb5_context context
,
663 struct krb5_krbhst_data
*kd
,
664 krb5_krbhst_info
**host
)
668 if ((kd
->flags
& KD_PLUGIN
) == 0) {
669 plugin_get_hosts(context
, kd
, locate_service_kpasswd
);
670 kd
->flags
|= KD_PLUGIN
;
671 if(get_next(kd
, host
))
675 if((kd
->flags
& KD_CONFIG
) == 0) {
676 config_get_hosts(context
, kd
, "kpasswd_server");
677 kd
->flags
|= KD_CONFIG
;
678 if(get_next(kd
, host
))
682 if (kd
->flags
& KD_CONFIG_EXISTS
)
683 return KRB5_KDC_UNREACH
; /* XXX */
685 if(context
->srv_lookup
) {
686 if((kd
->flags
& KD_SRV_UDP
) == 0) {
687 srv_get_hosts(context
, kd
, "udp", "kpasswd");
688 kd
->flags
|= KD_SRV_UDP
;
689 if(get_next(kd
, host
))
692 if((kd
->flags
& KD_SRV_TCP
) == 0) {
693 srv_get_hosts(context
, kd
, "tcp", "kpasswd");
694 kd
->flags
|= KD_SRV_TCP
;
695 if(get_next(kd
, host
))
700 /* no matches -> try admin */
702 if (krbhst_empty(kd
)) {
704 kd
->port
= kd
->def_port
;
705 kd
->get_next
= admin_get_next
;
706 ret
= (*kd
->get_next
)(context
, kd
, host
);
708 (*host
)->proto
= krbhst_get_default_proto(kd
);
712 return KRB5_KDC_UNREACH
; /* XXX */
715 static krb5_error_code
716 krb524_get_next(krb5_context context
,
717 struct krb5_krbhst_data
*kd
,
718 krb5_krbhst_info
**host
)
720 if ((kd
->flags
& KD_PLUGIN
) == 0) {
721 plugin_get_hosts(context
, kd
, locate_service_krb524
);
722 kd
->flags
|= KD_PLUGIN
;
723 if(get_next(kd
, host
))
727 if((kd
->flags
& KD_CONFIG
) == 0) {
728 config_get_hosts(context
, kd
, "krb524_server");
729 if(get_next(kd
, host
))
731 kd
->flags
|= KD_CONFIG
;
734 if (kd
->flags
& KD_CONFIG_EXISTS
)
735 return KRB5_KDC_UNREACH
; /* XXX */
737 if(context
->srv_lookup
) {
738 if((kd
->flags
& KD_SRV_UDP
) == 0) {
739 srv_get_hosts(context
, kd
, "udp", "krb524");
740 kd
->flags
|= KD_SRV_UDP
;
741 if(get_next(kd
, host
))
745 if((kd
->flags
& KD_SRV_TCP
) == 0) {
746 srv_get_hosts(context
, kd
, "tcp", "krb524");
747 kd
->flags
|= KD_SRV_TCP
;
748 if(get_next(kd
, host
))
753 /* no matches -> try kdc */
755 if (krbhst_empty(kd
)) {
757 kd
->port
= kd
->def_port
;
758 kd
->get_next
= kdc_get_next
;
759 return (*kd
->get_next
)(context
, kd
, host
);
762 return KRB5_KDC_UNREACH
; /* XXX */
765 static struct krb5_krbhst_data
*
766 common_init(krb5_context context
,
770 struct krb5_krbhst_data
*kd
;
772 if((kd
= calloc(1, sizeof(*kd
))) == NULL
)
775 if((kd
->realm
= strdup(realm
)) == NULL
) {
780 /* For 'realms' without a . do not even think of going to DNS */
781 if (!strchr(realm
, '.'))
782 kd
->flags
|= KD_CONFIG_EXISTS
;
784 if (flags
& KRB5_KRBHST_FLAGS_LARGE_MSG
)
785 kd
->flags
|= KD_LARGE_MSG
;
786 kd
->end
= kd
->index
= &kd
->hosts
;
791 * initialize `handle' to look for hosts of type `type' in realm `realm'
794 krb5_error_code KRB5_LIB_FUNCTION
795 krb5_krbhst_init(krb5_context context
,
798 krb5_krbhst_handle
*handle
)
800 return krb5_krbhst_init_flags(context
, realm
, type
, 0, handle
);
803 krb5_error_code KRB5_LIB_FUNCTION
804 krb5_krbhst_init_flags(krb5_context context
,
808 krb5_krbhst_handle
*handle
)
810 struct krb5_krbhst_data
*kd
;
811 krb5_error_code (*next
)(krb5_context
, struct krb5_krbhst_data
*,
812 krb5_krbhst_info
**);
816 case KRB5_KRBHST_KDC
:
818 def_port
= ntohs(krb5_getportbyname (context
, "kerberos", "udp", 88));
820 case KRB5_KRBHST_ADMIN
:
821 next
= admin_get_next
;
822 def_port
= ntohs(krb5_getportbyname (context
, "kerberos-adm",
825 case KRB5_KRBHST_CHANGEPW
:
826 next
= kpasswd_get_next
;
827 def_port
= ntohs(krb5_getportbyname (context
, "kpasswd", "udp",
830 case KRB5_KRBHST_KRB524
:
831 next
= krb524_get_next
;
832 def_port
= ntohs(krb5_getportbyname (context
, "krb524", "udp", 4444));
835 krb5_set_error_string(context
, "unknown krbhst type (%u)", type
);
838 if((kd
= common_init(context
, realm
, flags
)) == NULL
)
841 kd
->def_port
= def_port
;
847 * return the next host information from `handle' in `host'
850 krb5_error_code KRB5_LIB_FUNCTION
851 krb5_krbhst_next(krb5_context context
,
852 krb5_krbhst_handle handle
,
853 krb5_krbhst_info
**host
)
855 if(get_next(handle
, host
))
858 return (*handle
->get_next
)(context
, handle
, host
);
862 * return the next host information from `handle' as a host name
863 * in `hostname' (or length `hostlen)
866 krb5_error_code KRB5_LIB_FUNCTION
867 krb5_krbhst_next_as_string(krb5_context context
,
868 krb5_krbhst_handle handle
,
873 krb5_krbhst_info
*host
;
874 ret
= krb5_krbhst_next(context
, handle
, &host
);
877 return krb5_krbhst_format_string(context
, host
, hostname
, hostlen
);
881 void KRB5_LIB_FUNCTION
882 krb5_krbhst_reset(krb5_context context
, krb5_krbhst_handle handle
)
884 handle
->index
= &handle
->hosts
;
887 void KRB5_LIB_FUNCTION
888 krb5_krbhst_free(krb5_context context
, krb5_krbhst_handle handle
)
890 krb5_krbhst_info
*h
, *next
;
895 for (h
= handle
->hosts
; h
!= NULL
; h
= next
) {
897 _krb5_free_krbhst_info(h
);
904 /* backwards compatibility ahead */
906 static krb5_error_code
907 gethostlist(krb5_context context
, const char *realm
,
908 unsigned int type
, char ***hostlist
)
912 krb5_krbhst_handle handle
;
913 char host
[MAXHOSTNAMELEN
];
914 krb5_krbhst_info
*hostinfo
;
916 ret
= krb5_krbhst_init(context
, realm
, type
, &handle
);
920 while(krb5_krbhst_next(context
, handle
, &hostinfo
) == 0)
923 krb5_set_error_string(context
, "No KDC found for realm %s", realm
);
924 return KRB5_KDC_UNREACH
;
926 *hostlist
= calloc(nhost
+ 1, sizeof(**hostlist
));
927 if(*hostlist
== NULL
) {
928 krb5_krbhst_free(context
, handle
);
932 krb5_krbhst_reset(context
, handle
);
934 while(krb5_krbhst_next_as_string(context
, handle
,
935 host
, sizeof(host
)) == 0) {
936 if(((*hostlist
)[nhost
++] = strdup(host
)) == NULL
) {
937 krb5_free_krbhst(context
, *hostlist
);
938 krb5_krbhst_free(context
, handle
);
942 (*hostlist
)[nhost
++] = NULL
;
943 krb5_krbhst_free(context
, handle
);
948 * return an malloced list of kadmin-hosts for `realm' in `hostlist'
951 krb5_error_code KRB5_LIB_FUNCTION
952 krb5_get_krb_admin_hst (krb5_context context
,
953 const krb5_realm
*realm
,
956 return gethostlist(context
, *realm
, KRB5_KRBHST_ADMIN
, hostlist
);
960 * return an malloced list of changepw-hosts for `realm' in `hostlist'
963 krb5_error_code KRB5_LIB_FUNCTION
964 krb5_get_krb_changepw_hst (krb5_context context
,
965 const krb5_realm
*realm
,
968 return gethostlist(context
, *realm
, KRB5_KRBHST_CHANGEPW
, hostlist
);
972 * return an malloced list of 524-hosts for `realm' in `hostlist'
975 krb5_error_code KRB5_LIB_FUNCTION
976 krb5_get_krb524hst (krb5_context context
,
977 const krb5_realm
*realm
,
980 return gethostlist(context
, *realm
, KRB5_KRBHST_KRB524
, hostlist
);
985 * return an malloced list of KDC's for `realm' in `hostlist'
988 krb5_error_code KRB5_LIB_FUNCTION
989 krb5_get_krbhst (krb5_context context
,
990 const krb5_realm
*realm
,
993 return gethostlist(context
, *realm
, KRB5_KRBHST_KDC
, hostlist
);
997 * free all the memory allocated in `hostlist'
1000 krb5_error_code KRB5_LIB_FUNCTION
1001 krb5_free_krbhst (krb5_context context
,
1006 for (p
= hostlist
; *p
; ++p
)