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"
39 string_to_proto(const char *string
)
41 if(strcasecmp(string
, "udp") == 0)
42 return KRB5_KRBHST_UDP
;
43 else if(strcasecmp(string
, "tcp") == 0)
44 return KRB5_KRBHST_TCP
;
45 else if(strcasecmp(string
, "http") == 0)
46 return KRB5_KRBHST_HTTP
;
51 * set `res' and `count' to the result of looking up SRV RR in DNS for
52 * `proto', `proto', `realm' using `dns_type'.
53 * if `port' != 0, force that port number
56 static krb5_error_code
57 srv_find_realm(krb5_context context
, krb5_krbhst_info
***res
, int *count
,
58 const char *realm
, const char *dns_type
,
59 const char *proto
, const char *service
, int port
)
62 struct rk_dns_reply
*r
;
63 struct rk_resource_record
*rr
;
71 proto_num
= string_to_proto(proto
);
73 krb5_set_error_message(context
, EINVAL
,
74 N_("unknown protocol `%s' to lookup", ""),
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
= rk_dns_lookup(domain
, dns_type
);
90 return KRB5_KDC_UNREACH
;
92 for(num_srv
= 0, rr
= r
->head
; rr
; rr
= rr
->next
)
93 if(rr
->type
== rk_ns_t_srv
)
96 *res
= malloc(num_srv
* sizeof(**res
));
99 krb5_set_error_message(context
, ENOMEM
,
100 N_("malloc: out of memory", ""));
106 for(num_srv
= 0, rr
= r
->head
; rr
; rr
= rr
->next
)
107 if(rr
->type
== rk_ns_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
, *q
;
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 (p
[0] == '[' && (q
= strchr(p
, ']')) != NULL
) {
213 /* if address looks like [foo:bar] or [foo:bar]: its a ipv6
214 adress, strip of [] */
215 memcpy(hi
->hostname
, &p
[1], q
- p
- 1);
216 hi
->hostname
[q
- p
- 1] = '\0';
221 } else if(strsep_copy(&p
, ":", hi
->hostname
, strlen(spec
) + 1) < 0) {
222 /* copy everything before : */
226 /* get rid of trailing /, and convert to lower case */
227 hi
->hostname
[strcspn(hi
->hostname
, "/")] = '\0';
228 strlwr(hi
->hostname
);
230 hi
->port
= hi
->def_port
= def_port
;
231 if(p
!= NULL
&& p
[0]) {
233 hi
->port
= strtol(p
, &end
, 0);
245 _krb5_free_krbhst_info(krb5_krbhst_info
*hi
)
248 freeaddrinfo(hi
->ai
);
253 _krb5_krbhost_info_move(krb5_context context
,
254 krb5_krbhst_info
*from
,
255 krb5_krbhst_info
**to
)
257 size_t hostnamelen
= strlen(from
->hostname
);
258 /* trailing NUL is included in structure */
259 *to
= calloc(1, sizeof(**to
) + hostnamelen
);
261 krb5_set_error_message(context
, ENOMEM
,
262 N_("malloc: out of memory", ""));
266 (*to
)->proto
= from
->proto
;
267 (*to
)->port
= from
->port
;
268 (*to
)->def_port
= from
->def_port
;
269 (*to
)->ai
= from
->ai
;
272 memcpy((*to
)->hostname
, from
->hostname
, hostnamelen
+ 1);
278 append_host_hostinfo(struct krb5_krbhst_data
*kd
, struct krb5_krbhst_info
*host
)
280 struct krb5_krbhst_info
*h
;
282 for(h
= kd
->hosts
; h
; h
= h
->next
)
283 if(h
->proto
== host
->proto
&&
284 h
->port
== host
->port
&&
285 strcmp(h
->hostname
, host
->hostname
) == 0) {
286 _krb5_free_krbhst_info(host
);
290 kd
->end
= &host
->next
;
293 static krb5_error_code
294 append_host_string(krb5_context context
, struct krb5_krbhst_data
*kd
,
295 const char *host
, int def_port
, int port
)
297 struct krb5_krbhst_info
*hi
;
299 hi
= parse_hostspec(context
, kd
, host
, def_port
, port
);
303 append_host_hostinfo(kd
, hi
);
308 * return a readable representation of `host' in `hostname, hostlen'
311 krb5_error_code KRB5_LIB_FUNCTION
312 krb5_krbhst_format_string(krb5_context context
, const krb5_krbhst_info
*host
,
313 char *hostname
, size_t hostlen
)
315 const char *proto
= "";
316 char portstr
[7] = "";
317 if(host
->proto
== KRB5_KRBHST_TCP
)
319 else if(host
->proto
== KRB5_KRBHST_HTTP
)
321 if(host
->port
!= host
->def_port
)
322 snprintf(portstr
, sizeof(portstr
), ":%d", host
->port
);
323 snprintf(hostname
, hostlen
, "%s%s%s", proto
, host
->hostname
, portstr
);
328 * create a getaddrinfo `hints' based on `proto'
332 make_hints(struct addrinfo
*hints
, int proto
)
334 memset(hints
, 0, sizeof(*hints
));
335 hints
->ai_family
= AF_UNSPEC
;
337 case KRB5_KRBHST_UDP
:
338 hints
->ai_socktype
= SOCK_DGRAM
;
340 case KRB5_KRBHST_HTTP
:
341 case KRB5_KRBHST_TCP
:
342 hints
->ai_socktype
= SOCK_STREAM
;
348 * return an `struct addrinfo *' in `ai' corresponding to the information
349 * in `host'. free:ing is handled by krb5_krbhst_free.
352 krb5_error_code KRB5_LIB_FUNCTION
353 krb5_krbhst_get_addrinfo(krb5_context context
, krb5_krbhst_info
*host
,
354 struct addrinfo
**ai
)
356 struct addrinfo hints
;
357 char portstr
[NI_MAXSERV
];
360 if (host
->ai
== NULL
) {
361 make_hints(&hints
, host
->proto
);
362 snprintf (portstr
, sizeof(portstr
), "%d", host
->port
);
363 ret
= getaddrinfo(host
->hostname
, portstr
, &hints
, &host
->ai
);
365 return krb5_eai_to_heim_errno(ret
, errno
);
372 get_next(struct krb5_krbhst_data
*kd
, krb5_krbhst_info
**host
)
374 struct krb5_krbhst_info
*hi
= *kd
->index
;
377 kd
->index
= &(*kd
->index
)->next
;
384 srv_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
385 const char *proto
, const char *service
)
387 krb5_krbhst_info
**res
;
390 if (srv_find_realm(context
, &res
, &count
, kd
->realm
, "SRV", proto
, service
,
393 for(i
= 0; i
< count
; i
++)
394 append_host_hostinfo(kd
, res
[i
]);
399 * read the configuration for `conf_string', defaulting to kd->def_port and
400 * forcing it to `kd->port' if kd->port != 0
404 config_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
405 const char *conf_string
)
410 hostlist
= krb5_config_get_strings(context
, NULL
,
411 "realms", kd
->realm
, conf_string
, NULL
);
415 kd
->flags
|= KD_CONFIG_EXISTS
;
416 for(i
= 0; hostlist
&& hostlist
[i
] != NULL
; i
++)
417 append_host_string(context
, kd
, hostlist
[i
], kd
->def_port
, kd
->port
);
419 krb5_config_free_strings(hostlist
);
423 * as a fallback, look for `serv_string.kd->realm' (typically
424 * kerberos.REALM, kerberos-1.REALM, ...
425 * `port' is the default port for the service, and `proto' the
429 static krb5_error_code
430 fallback_get_hosts(krb5_context context
, struct krb5_krbhst_data
*kd
,
431 const char *serv_string
, int port
, int proto
)
436 struct addrinfo hints
;
437 char portstr
[NI_MAXSERV
];
440 * Don't try forever in case the DNS server keep returning us
441 * entries (like wildcard entries or the .nu TLD)
443 if(kd
->fallback_count
>= 5) {
444 kd
->flags
|= KD_FALLBACK
;
448 if(kd
->fallback_count
== 0)
449 asprintf(&host
, "%s.%s.", serv_string
, kd
->realm
);
451 asprintf(&host
, "%s-%d.%s.",
452 serv_string
, kd
->fallback_count
, kd
->realm
);
457 make_hints(&hints
, proto
);
458 snprintf(portstr
, sizeof(portstr
), "%d", port
);
459 ret
= getaddrinfo(host
, portstr
, &hints
, &ai
);
461 /* no more hosts, so we're done here */
463 kd
->flags
|= KD_FALLBACK
;
465 struct krb5_krbhst_info
*hi
;
466 size_t hostlen
= strlen(host
);
468 hi
= calloc(1, sizeof(*hi
) + hostlen
);
475 hi
->port
= hi
->def_port
= port
;
477 memmove(hi
->hostname
, host
, hostlen
);
478 hi
->hostname
[hostlen
] = '\0';
480 append_host_hostinfo(kd
, hi
);
481 kd
->fallback_count
++;
487 * Fetch hosts from plugin
490 static krb5_error_code
491 add_locate(void *ctx
, int type
, struct sockaddr
*addr
)
493 struct krb5_krbhst_info
*hi
;
494 struct krb5_krbhst_data
*kd
= ctx
;
495 char host
[NI_MAXHOST
], port
[NI_MAXSERV
];
496 struct addrinfo hints
, *ai
;
501 socklen
= socket_sockaddr_size(addr
);
503 ret
= getnameinfo(addr
, socklen
, host
, sizeof(host
), port
, sizeof(port
),
504 NI_NUMERICHOST
|NI_NUMERICSERV
);
508 make_hints(&hints
, krbhst_get_default_proto(kd
));
509 ret
= getaddrinfo(host
, port
, &hints
, &ai
);
513 hostlen
= strlen(host
);
515 hi
= calloc(1, sizeof(*hi
) + hostlen
);
519 hi
->proto
= krbhst_get_default_proto(kd
);
520 hi
->port
= hi
->def_port
= socket_get_port(addr
);
522 memmove(hi
->hostname
, host
, hostlen
);
523 hi
->hostname
[hostlen
] = '\0';
524 append_host_hostinfo(kd
, hi
);
530 plugin_get_hosts(krb5_context context
,
531 struct krb5_krbhst_data
*kd
,
532 enum locate_service_type type
)
534 struct krb5_plugin
*list
= NULL
, *e
;
537 ret
= _krb5_plugin_find(context
, PLUGIN_TYPE_DATA
,
538 KRB5_PLUGIN_LOCATE
, &list
);
539 if(ret
!= 0 || list
== NULL
)
542 for (e
= list
; e
!= NULL
; e
= _krb5_plugin_get_next(e
)) {
543 krb5plugin_service_locate_ftable
*service
;
546 service
= _krb5_plugin_get_symbol(e
);
547 if (service
->minor_version
!= 0)
550 (*service
->init
)(context
, &ctx
);
551 ret
= (*service
->lookup
)(ctx
, type
, kd
->realm
, 0, 0, add_locate
, kd
);
552 (*service
->fini
)(ctx
);
553 if (ret
&& ret
!= KRB5_PLUGIN_NO_HANDLE
) {
554 krb5_set_error_message(context
, ret
,
555 N_("Locate plugin failed to lookup realm %s: %d", ""),
559 kd
->flags
|= KD_CONFIG_EXISTS
;
562 _krb5_plugin_free(list
);
569 static krb5_error_code
570 kdc_get_next(krb5_context context
,
571 struct krb5_krbhst_data
*kd
,
572 krb5_krbhst_info
**host
)
576 if ((kd
->flags
& KD_PLUGIN
) == 0) {
577 plugin_get_hosts(context
, kd
, locate_service_kdc
);
578 kd
->flags
|= KD_PLUGIN
;
579 if(get_next(kd
, host
))
583 if((kd
->flags
& KD_CONFIG
) == 0) {
584 config_get_hosts(context
, kd
, "kdc");
585 kd
->flags
|= KD_CONFIG
;
586 if(get_next(kd
, host
))
590 if (kd
->flags
& KD_CONFIG_EXISTS
)
591 return KRB5_KDC_UNREACH
; /* XXX */
593 if(context
->srv_lookup
) {
594 if((kd
->flags
& KD_SRV_UDP
) == 0 && (kd
->flags
& KD_LARGE_MSG
) == 0) {
595 srv_get_hosts(context
, kd
, "udp", "kerberos");
596 kd
->flags
|= KD_SRV_UDP
;
597 if(get_next(kd
, host
))
601 if((kd
->flags
& KD_SRV_TCP
) == 0) {
602 srv_get_hosts(context
, kd
, "tcp", "kerberos");
603 kd
->flags
|= KD_SRV_TCP
;
604 if(get_next(kd
, host
))
607 if((kd
->flags
& KD_SRV_HTTP
) == 0) {
608 srv_get_hosts(context
, kd
, "http", "kerberos");
609 kd
->flags
|= KD_SRV_HTTP
;
610 if(get_next(kd
, host
))
615 while((kd
->flags
& KD_FALLBACK
) == 0) {
616 ret
= fallback_get_hosts(context
, kd
, "kerberos",
618 krbhst_get_default_proto(kd
));
621 if(get_next(kd
, host
))
625 return KRB5_KDC_UNREACH
; /* XXX */
628 static krb5_error_code
629 admin_get_next(krb5_context context
,
630 struct krb5_krbhst_data
*kd
,
631 krb5_krbhst_info
**host
)
635 if ((kd
->flags
& KD_PLUGIN
) == 0) {
636 plugin_get_hosts(context
, kd
, locate_service_kadmin
);
637 kd
->flags
|= KD_PLUGIN
;
638 if(get_next(kd
, host
))
642 if((kd
->flags
& KD_CONFIG
) == 0) {
643 config_get_hosts(context
, kd
, "admin_server");
644 kd
->flags
|= KD_CONFIG
;
645 if(get_next(kd
, host
))
649 if (kd
->flags
& KD_CONFIG_EXISTS
)
650 return KRB5_KDC_UNREACH
; /* XXX */
652 if(context
->srv_lookup
) {
653 if((kd
->flags
& KD_SRV_TCP
) == 0) {
654 srv_get_hosts(context
, kd
, "tcp", "kerberos-adm");
655 kd
->flags
|= KD_SRV_TCP
;
656 if(get_next(kd
, host
))
662 && (kd
->flags
& KD_FALLBACK
) == 0) {
663 ret
= fallback_get_hosts(context
, kd
, "kerberos",
665 krbhst_get_default_proto(kd
));
668 kd
->flags
|= KD_FALLBACK
;
669 if(get_next(kd
, host
))
673 return KRB5_KDC_UNREACH
; /* XXX */
676 static krb5_error_code
677 kpasswd_get_next(krb5_context context
,
678 struct krb5_krbhst_data
*kd
,
679 krb5_krbhst_info
**host
)
683 if ((kd
->flags
& KD_PLUGIN
) == 0) {
684 plugin_get_hosts(context
, kd
, locate_service_kpasswd
);
685 kd
->flags
|= KD_PLUGIN
;
686 if(get_next(kd
, host
))
690 if((kd
->flags
& KD_CONFIG
) == 0) {
691 config_get_hosts(context
, kd
, "kpasswd_server");
692 kd
->flags
|= KD_CONFIG
;
693 if(get_next(kd
, host
))
697 if (kd
->flags
& KD_CONFIG_EXISTS
)
698 return KRB5_KDC_UNREACH
; /* XXX */
700 if(context
->srv_lookup
) {
701 if((kd
->flags
& KD_SRV_UDP
) == 0) {
702 srv_get_hosts(context
, kd
, "udp", "kpasswd");
703 kd
->flags
|= KD_SRV_UDP
;
704 if(get_next(kd
, host
))
707 if((kd
->flags
& KD_SRV_TCP
) == 0) {
708 srv_get_hosts(context
, kd
, "tcp", "kpasswd");
709 kd
->flags
|= KD_SRV_TCP
;
710 if(get_next(kd
, host
))
715 /* no matches -> try admin */
717 if (krbhst_empty(kd
)) {
719 kd
->port
= kd
->def_port
;
720 kd
->get_next
= admin_get_next
;
721 ret
= (*kd
->get_next
)(context
, kd
, host
);
723 (*host
)->proto
= krbhst_get_default_proto(kd
);
727 return KRB5_KDC_UNREACH
; /* XXX */
730 static krb5_error_code
731 krb524_get_next(krb5_context context
,
732 struct krb5_krbhst_data
*kd
,
733 krb5_krbhst_info
**host
)
735 if ((kd
->flags
& KD_PLUGIN
) == 0) {
736 plugin_get_hosts(context
, kd
, locate_service_krb524
);
737 kd
->flags
|= KD_PLUGIN
;
738 if(get_next(kd
, host
))
742 if((kd
->flags
& KD_CONFIG
) == 0) {
743 config_get_hosts(context
, kd
, "krb524_server");
744 if(get_next(kd
, host
))
746 kd
->flags
|= KD_CONFIG
;
749 if (kd
->flags
& KD_CONFIG_EXISTS
)
750 return KRB5_KDC_UNREACH
; /* XXX */
752 if(context
->srv_lookup
) {
753 if((kd
->flags
& KD_SRV_UDP
) == 0) {
754 srv_get_hosts(context
, kd
, "udp", "krb524");
755 kd
->flags
|= KD_SRV_UDP
;
756 if(get_next(kd
, host
))
760 if((kd
->flags
& KD_SRV_TCP
) == 0) {
761 srv_get_hosts(context
, kd
, "tcp", "krb524");
762 kd
->flags
|= KD_SRV_TCP
;
763 if(get_next(kd
, host
))
768 /* no matches -> try kdc */
770 if (krbhst_empty(kd
)) {
772 kd
->port
= kd
->def_port
;
773 kd
->get_next
= kdc_get_next
;
774 return (*kd
->get_next
)(context
, kd
, host
);
777 return KRB5_KDC_UNREACH
; /* XXX */
780 static struct krb5_krbhst_data
*
781 common_init(krb5_context context
,
785 struct krb5_krbhst_data
*kd
;
787 if((kd
= calloc(1, sizeof(*kd
))) == NULL
)
790 if((kd
->realm
= strdup(realm
)) == NULL
) {
795 /* For 'realms' without a . do not even think of going to DNS */
796 if (!strchr(realm
, '.'))
797 kd
->flags
|= KD_CONFIG_EXISTS
;
799 if (flags
& KRB5_KRBHST_FLAGS_LARGE_MSG
)
800 kd
->flags
|= KD_LARGE_MSG
;
801 kd
->end
= kd
->index
= &kd
->hosts
;
806 * initialize `handle' to look for hosts of type `type' in realm `realm'
809 krb5_error_code KRB5_LIB_FUNCTION
810 krb5_krbhst_init(krb5_context context
,
813 krb5_krbhst_handle
*handle
)
815 return krb5_krbhst_init_flags(context
, realm
, type
, 0, handle
);
818 krb5_error_code KRB5_LIB_FUNCTION
819 krb5_krbhst_init_flags(krb5_context context
,
823 krb5_krbhst_handle
*handle
)
825 struct krb5_krbhst_data
*kd
;
826 krb5_error_code (*next
)(krb5_context
, struct krb5_krbhst_data
*,
827 krb5_krbhst_info
**);
831 case KRB5_KRBHST_KDC
:
833 def_port
= ntohs(krb5_getportbyname (context
, "kerberos", "udp", 88));
835 case KRB5_KRBHST_ADMIN
:
836 next
= admin_get_next
;
837 def_port
= ntohs(krb5_getportbyname (context
, "kerberos-adm",
840 case KRB5_KRBHST_CHANGEPW
:
841 next
= kpasswd_get_next
;
842 def_port
= ntohs(krb5_getportbyname (context
, "kpasswd", "udp",
845 case KRB5_KRBHST_KRB524
:
846 next
= krb524_get_next
;
847 def_port
= ntohs(krb5_getportbyname (context
, "krb524", "udp", 4444));
850 krb5_set_error_message(context
, ENOTTY
,
851 N_("unknown krbhst type (%u)", ""), type
);
854 if((kd
= common_init(context
, realm
, flags
)) == NULL
)
857 kd
->def_port
= def_port
;
863 * return the next host information from `handle' in `host'
866 krb5_error_code KRB5_LIB_FUNCTION
867 krb5_krbhst_next(krb5_context context
,
868 krb5_krbhst_handle handle
,
869 krb5_krbhst_info
**host
)
871 if(get_next(handle
, host
))
874 return (*handle
->get_next
)(context
, handle
, host
);
878 * return the next host information from `handle' as a host name
879 * in `hostname' (or length `hostlen)
882 krb5_error_code KRB5_LIB_FUNCTION
883 krb5_krbhst_next_as_string(krb5_context context
,
884 krb5_krbhst_handle handle
,
889 krb5_krbhst_info
*host
;
890 ret
= krb5_krbhst_next(context
, handle
, &host
);
893 return krb5_krbhst_format_string(context
, host
, hostname
, hostlen
);
897 void KRB5_LIB_FUNCTION
898 krb5_krbhst_reset(krb5_context context
, krb5_krbhst_handle handle
)
900 handle
->index
= &handle
->hosts
;
903 void KRB5_LIB_FUNCTION
904 krb5_krbhst_free(krb5_context context
, krb5_krbhst_handle handle
)
906 krb5_krbhst_info
*h
, *next
;
911 for (h
= handle
->hosts
; h
!= NULL
; h
= next
) {
913 _krb5_free_krbhst_info(h
);
920 /* backwards compatibility ahead */
922 static krb5_error_code
923 gethostlist(krb5_context context
, const char *realm
,
924 unsigned int type
, char ***hostlist
)
928 krb5_krbhst_handle handle
;
929 char host
[MAXHOSTNAMELEN
];
930 krb5_krbhst_info
*hostinfo
;
932 ret
= krb5_krbhst_init(context
, realm
, type
, &handle
);
936 while(krb5_krbhst_next(context
, handle
, &hostinfo
) == 0)
939 krb5_set_error_message(context
, KRB5_KDC_UNREACH
,
940 N_("No KDC found for realm %s", ""), realm
);
941 return KRB5_KDC_UNREACH
;
943 *hostlist
= calloc(nhost
+ 1, sizeof(**hostlist
));
944 if(*hostlist
== NULL
) {
945 krb5_krbhst_free(context
, handle
);
949 krb5_krbhst_reset(context
, handle
);
951 while(krb5_krbhst_next_as_string(context
, handle
,
952 host
, sizeof(host
)) == 0) {
953 if(((*hostlist
)[nhost
++] = strdup(host
)) == NULL
) {
954 krb5_free_krbhst(context
, *hostlist
);
955 krb5_krbhst_free(context
, handle
);
959 (*hostlist
)[nhost
] = NULL
;
960 krb5_krbhst_free(context
, handle
);
965 * return an malloced list of kadmin-hosts for `realm' in `hostlist'
968 krb5_error_code KRB5_LIB_FUNCTION
969 krb5_get_krb_admin_hst (krb5_context context
,
970 const krb5_realm
*realm
,
973 return gethostlist(context
, *realm
, KRB5_KRBHST_ADMIN
, hostlist
);
977 * return an malloced list of changepw-hosts for `realm' in `hostlist'
980 krb5_error_code KRB5_LIB_FUNCTION
981 krb5_get_krb_changepw_hst (krb5_context context
,
982 const krb5_realm
*realm
,
985 return gethostlist(context
, *realm
, KRB5_KRBHST_CHANGEPW
, hostlist
);
989 * return an malloced list of 524-hosts for `realm' in `hostlist'
992 krb5_error_code KRB5_LIB_FUNCTION
993 krb5_get_krb524hst (krb5_context context
,
994 const krb5_realm
*realm
,
997 return gethostlist(context
, *realm
, KRB5_KRBHST_KRB524
, hostlist
);
1002 * return an malloced list of KDC's for `realm' in `hostlist'
1005 krb5_error_code KRB5_LIB_FUNCTION
1006 krb5_get_krbhst (krb5_context context
,
1007 const krb5_realm
*realm
,
1010 return gethostlist(context
, *realm
, KRB5_KRBHST_KDC
, hostlist
);
1014 * free all the memory allocated in `hostlist'
1017 krb5_error_code KRB5_LIB_FUNCTION
1018 krb5_free_krbhst (krb5_context context
,
1023 for (p
= hostlist
; *p
; ++p
)