155682Smarkm/* 2233294Sstas * Copyright (c) 2001 - 2003 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "krb5_locl.h" 3555682Smarkm#include <resolve.h> 36178825Sdfr#include "locate_plugin.h" 3755682Smarkm 3890926Snectarstatic int 3990926Snectarstring_to_proto(const char *string) 4090926Snectar{ 4190926Snectar if(strcasecmp(string, "udp") == 0) 4290926Snectar return KRB5_KRBHST_UDP; 43233294Sstas else if(strcasecmp(string, "tcp") == 0) 4490926Snectar return KRB5_KRBHST_TCP; 45233294Sstas else if(strcasecmp(string, "http") == 0) 4690926Snectar return KRB5_KRBHST_HTTP; 4790926Snectar return -1; 4890926Snectar} 4990926Snectar 5055682Smarkm/* 5190926Snectar * set `res' and `count' to the result of looking up SRV RR in DNS for 5290926Snectar * `proto', `proto', `realm' using `dns_type'. 5390926Snectar * if `port' != 0, force that port number 5455682Smarkm */ 5555682Smarkm 5690926Snectarstatic krb5_error_code 57233294Sstassrv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, 5890926Snectar const char *realm, const char *dns_type, 5990926Snectar const char *proto, const char *service, int port) 6055682Smarkm{ 6190926Snectar char domain[1024]; 62233294Sstas struct rk_dns_reply *r; 63233294Sstas struct rk_resource_record *rr; 6490926Snectar int num_srv; 6590926Snectar int proto_num; 6690926Snectar int def_port; 6755682Smarkm 68178825Sdfr *res = NULL; 69178825Sdfr *count = 0; 70178825Sdfr 7190926Snectar proto_num = string_to_proto(proto); 7290926Snectar if(proto_num < 0) { 73233294Sstas krb5_set_error_message(context, EINVAL, 74233294Sstas N_("unknown protocol `%s' to lookup", ""), 75233294Sstas proto); 7690926Snectar return EINVAL; 7790926Snectar } 7890926Snectar 7990926Snectar if(proto_num == KRB5_KRBHST_HTTP) 8090926Snectar def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80)); 8190926Snectar else if(port == 0) 8290926Snectar def_port = ntohs(krb5_getportbyname (context, service, proto, 88)); 8390926Snectar else 8490926Snectar def_port = port; 8590926Snectar 8690926Snectar snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm); 8790926Snectar 88233294Sstas r = rk_dns_lookup(domain, dns_type); 89233294Sstas if(r == NULL) { 90233294Sstas _krb5_debug(context, 0, 91233294Sstas "DNS lookup failed domain: %s", domain); 9290926Snectar return KRB5_KDC_UNREACH; 93233294Sstas } 9490926Snectar 95233294Sstas for(num_srv = 0, rr = r->head; rr; rr = rr->next) 96233294Sstas if(rr->type == rk_ns_t_srv) 9790926Snectar num_srv++; 9890926Snectar 9990926Snectar *res = malloc(num_srv * sizeof(**res)); 10090926Snectar if(*res == NULL) { 101233294Sstas rk_dns_free_data(r); 102233294Sstas krb5_set_error_message(context, ENOMEM, 103233294Sstas N_("malloc: out of memory", "")); 10455682Smarkm return ENOMEM; 10578527Sassar } 10690926Snectar 107233294Sstas rk_dns_srv_order(r); 10890926Snectar 109233294Sstas for(num_srv = 0, rr = r->head; rr; rr = rr->next) 110233294Sstas if(rr->type == rk_ns_t_srv) { 11190926Snectar krb5_krbhst_info *hi; 112120945Snectar size_t len = strlen(rr->u.srv->target); 113120945Snectar 114120945Snectar hi = calloc(1, sizeof(*hi) + len); 11590926Snectar if(hi == NULL) { 116233294Sstas rk_dns_free_data(r); 11790926Snectar while(--num_srv >= 0) 11890926Snectar free((*res)[num_srv]); 11990926Snectar free(*res); 120178825Sdfr *res = NULL; 12190926Snectar return ENOMEM; 12290926Snectar } 12390926Snectar (*res)[num_srv++] = hi; 12490926Snectar 12590926Snectar hi->proto = proto_num; 126233294Sstas 12790926Snectar hi->def_port = def_port; 12890926Snectar if (port != 0) 12990926Snectar hi->port = port; 13090926Snectar else 13190926Snectar hi->port = rr->u.srv->port; 13290926Snectar 133120945Snectar strlcpy(hi->hostname, rr->u.srv->target, len + 1); 13478527Sassar } 13590926Snectar 13690926Snectar *count = num_srv; 137233294Sstas 138233294Sstas rk_dns_free_data(r); 13955682Smarkm return 0; 14055682Smarkm} 14155682Smarkm 14290926Snectar 14390926Snectarstruct krb5_krbhst_data { 14490926Snectar char *realm; 14590926Snectar unsigned int flags; 14690926Snectar int def_port; 14790926Snectar int port; /* hardwired port number if != 0 */ 148178825Sdfr#define KD_CONFIG 1 149178825Sdfr#define KD_SRV_UDP 2 150178825Sdfr#define KD_SRV_TCP 4 151178825Sdfr#define KD_SRV_HTTP 8 152178825Sdfr#define KD_FALLBACK 16 153178825Sdfr#define KD_CONFIG_EXISTS 32 154178825Sdfr#define KD_LARGE_MSG 64 155178825Sdfr#define KD_PLUGIN 128 156233294Sstas krb5_error_code (*get_next)(krb5_context, struct krb5_krbhst_data *, 15790926Snectar krb5_krbhst_info**); 15890926Snectar 15990926Snectar unsigned int fallback_count; 16090926Snectar 16190926Snectar struct krb5_krbhst_info *hosts, **index, **end; 16290926Snectar}; 16390926Snectar 16490926Snectarstatic krb5_boolean 16590926Snectarkrbhst_empty(const struct krb5_krbhst_data *kd) 16690926Snectar{ 16790926Snectar return kd->index == &kd->hosts; 16890926Snectar} 16990926Snectar 17072445Sassar/* 171178825Sdfr * Return the default protocol for the `kd' (either TCP or UDP) 172178825Sdfr */ 173178825Sdfr 174178825Sdfrstatic int 175178825Sdfrkrbhst_get_default_proto(struct krb5_krbhst_data *kd) 176178825Sdfr{ 177178825Sdfr if (kd->flags & KD_LARGE_MSG) 178178825Sdfr return KRB5_KRBHST_TCP; 179178825Sdfr return KRB5_KRBHST_UDP; 180178825Sdfr} 181178825Sdfr 182233294Sstas/* 183233294Sstas * 184233294Sstas */ 185178825Sdfr 186233294Sstasconst char * 187233294Sstas_krb5_krbhst_get_realm(krb5_krbhst_handle handle) 188233294Sstas{ 189233294Sstas return handle->realm; 190233294Sstas} 191233294Sstas 192178825Sdfr/* 19390926Snectar * parse `spec' into a krb5_krbhst_info, defaulting the port to `def_port' 19490926Snectar * and forcing it to `port' if port != 0 19572445Sassar */ 19672445Sassar 19790926Snectarstatic struct krb5_krbhst_info* 198178825Sdfrparse_hostspec(krb5_context context, struct krb5_krbhst_data *kd, 199178825Sdfr const char *spec, int def_port, int port) 20090926Snectar{ 201233294Sstas const char *p = spec, *q; 20290926Snectar struct krb5_krbhst_info *hi; 203233294Sstas 20490926Snectar hi = calloc(1, sizeof(*hi) + strlen(spec)); 20590926Snectar if(hi == NULL) 20690926Snectar return NULL; 207233294Sstas 208178825Sdfr hi->proto = krbhst_get_default_proto(kd); 20990926Snectar 21090926Snectar if(strncmp(p, "http://", 7) == 0){ 21190926Snectar hi->proto = KRB5_KRBHST_HTTP; 21290926Snectar p += 7; 21390926Snectar } else if(strncmp(p, "http/", 5) == 0) { 21490926Snectar hi->proto = KRB5_KRBHST_HTTP; 21590926Snectar p += 5; 21690926Snectar def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80)); 21790926Snectar }else if(strncmp(p, "tcp/", 4) == 0){ 21890926Snectar hi->proto = KRB5_KRBHST_TCP; 21990926Snectar p += 4; 22090926Snectar } else if(strncmp(p, "udp/", 4) == 0) { 22190926Snectar p += 4; 22290926Snectar } 22390926Snectar 224233294Sstas if (p[0] == '[' && (q = strchr(p, ']')) != NULL) { 225233294Sstas /* if address looks like [foo:bar] or [foo:bar]: its a ipv6 226233294Sstas adress, strip of [] */ 227233294Sstas memcpy(hi->hostname, &p[1], q - p - 1); 228233294Sstas hi->hostname[q - p - 1] = '\0'; 229233294Sstas p = q + 1; 230233294Sstas /* get trailing : */ 231233294Sstas if (p[0] == ':') 232233294Sstas p++; 233233294Sstas } else if(strsep_copy(&p, ":", hi->hostname, strlen(spec) + 1) < 0) { 234233294Sstas /* copy everything before : */ 23590926Snectar free(hi); 23690926Snectar return NULL; 23790926Snectar } 23890926Snectar /* get rid of trailing /, and convert to lower case */ 23990926Snectar hi->hostname[strcspn(hi->hostname, "/")] = '\0'; 24090926Snectar strlwr(hi->hostname); 24190926Snectar 24290926Snectar hi->port = hi->def_port = def_port; 243233294Sstas if(p != NULL && p[0]) { 24490926Snectar char *end; 24590926Snectar hi->port = strtol(p, &end, 0); 24690926Snectar if(end == p) { 24790926Snectar free(hi); 24890926Snectar return NULL; 24990926Snectar } 25090926Snectar } 25190926Snectar if (port) 25290926Snectar hi->port = port; 25390926Snectar return hi; 25490926Snectar} 25590926Snectar 256178825Sdfrvoid 257178825Sdfr_krb5_free_krbhst_info(krb5_krbhst_info *hi) 25890926Snectar{ 25990926Snectar if (hi->ai != NULL) 26090926Snectar freeaddrinfo(hi->ai); 26190926Snectar free(hi); 26290926Snectar} 26390926Snectar 264178825Sdfrkrb5_error_code 265178825Sdfr_krb5_krbhost_info_move(krb5_context context, 266178825Sdfr krb5_krbhst_info *from, 267178825Sdfr krb5_krbhst_info **to) 268178825Sdfr{ 269178825Sdfr size_t hostnamelen = strlen(from->hostname); 270178825Sdfr /* trailing NUL is included in structure */ 271233294Sstas *to = calloc(1, sizeof(**to) + hostnamelen); 272178825Sdfr if(*to == NULL) { 273233294Sstas krb5_set_error_message(context, ENOMEM, 274233294Sstas N_("malloc: out of memory", "")); 275178825Sdfr return ENOMEM; 276178825Sdfr } 277178825Sdfr 278178825Sdfr (*to)->proto = from->proto; 279178825Sdfr (*to)->port = from->port; 280178825Sdfr (*to)->def_port = from->def_port; 281178825Sdfr (*to)->ai = from->ai; 282178825Sdfr from->ai = NULL; 283178825Sdfr (*to)->next = NULL; 284178825Sdfr memcpy((*to)->hostname, from->hostname, hostnamelen + 1); 285178825Sdfr return 0; 286178825Sdfr} 287178825Sdfr 288178825Sdfr 28990926Snectarstatic void 29090926Snectarappend_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host) 29190926Snectar{ 29290926Snectar struct krb5_krbhst_info *h; 29390926Snectar 29490926Snectar for(h = kd->hosts; h; h = h->next) 295233294Sstas if(h->proto == host->proto && 296233294Sstas h->port == host->port && 29790926Snectar strcmp(h->hostname, host->hostname) == 0) { 298178825Sdfr _krb5_free_krbhst_info(host); 29990926Snectar return; 30090926Snectar } 30190926Snectar *kd->end = host; 30290926Snectar kd->end = &host->next; 30390926Snectar} 30490926Snectar 30555682Smarkmstatic krb5_error_code 30690926Snectarappend_host_string(krb5_context context, struct krb5_krbhst_data *kd, 30790926Snectar const char *host, int def_port, int port) 30855682Smarkm{ 30990926Snectar struct krb5_krbhst_info *hi; 31055682Smarkm 311178825Sdfr hi = parse_hostspec(context, kd, host, def_port, port); 31290926Snectar if(hi == NULL) 31390926Snectar return ENOMEM; 314233294Sstas 31590926Snectar append_host_hostinfo(kd, hi); 31690926Snectar return 0; 31790926Snectar} 31890926Snectar 31990926Snectar/* 32090926Snectar * return a readable representation of `host' in `hostname, hostlen' 32190926Snectar */ 32290926Snectar 323233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 324233294Sstaskrb5_krbhst_format_string(krb5_context context, const krb5_krbhst_info *host, 32590926Snectar char *hostname, size_t hostlen) 32690926Snectar{ 32790926Snectar const char *proto = ""; 32890926Snectar char portstr[7] = ""; 32990926Snectar if(host->proto == KRB5_KRBHST_TCP) 33090926Snectar proto = "tcp/"; 33190926Snectar else if(host->proto == KRB5_KRBHST_HTTP) 33290926Snectar proto = "http://"; 33390926Snectar if(host->port != host->def_port) 33490926Snectar snprintf(portstr, sizeof(portstr), ":%d", host->port); 33590926Snectar snprintf(hostname, hostlen, "%s%s%s", proto, host->hostname, portstr); 33690926Snectar return 0; 33790926Snectar} 33890926Snectar 33990926Snectar/* 34090926Snectar * create a getaddrinfo `hints' based on `proto' 34190926Snectar */ 34290926Snectar 34390926Snectarstatic void 34490926Snectarmake_hints(struct addrinfo *hints, int proto) 34590926Snectar{ 34690926Snectar memset(hints, 0, sizeof(*hints)); 34790926Snectar hints->ai_family = AF_UNSPEC; 34890926Snectar switch(proto) { 34990926Snectar case KRB5_KRBHST_UDP : 35090926Snectar hints->ai_socktype = SOCK_DGRAM; 35190926Snectar break; 35290926Snectar case KRB5_KRBHST_HTTP : 35390926Snectar case KRB5_KRBHST_TCP : 35490926Snectar hints->ai_socktype = SOCK_STREAM; 35590926Snectar break; 35655682Smarkm } 35790926Snectar} 35855682Smarkm 359233294Sstas/** 360233294Sstas * Return an `struct addrinfo *' for a KDC host. 361233294Sstas * 362233294Sstas * Returns an the struct addrinfo in in that corresponds to the 363233294Sstas * information in `host'. free:ing is handled by krb5_krbhst_free, so 364233294Sstas * the returned ai must not be released. 365233294Sstas * 366233294Sstas * @ingroup krb5 36790926Snectar */ 36855682Smarkm 369233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 37090926Snectarkrb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host, 37190926Snectar struct addrinfo **ai) 37290926Snectar{ 373233294Sstas int ret = 0; 37490926Snectar 37590926Snectar if (host->ai == NULL) { 376233294Sstas struct addrinfo hints; 377233294Sstas char portstr[NI_MAXSERV]; 378233294Sstas char *hostname = host->hostname; 379233294Sstas 380233294Sstas snprintf (portstr, sizeof(portstr), "%d", host->port); 38190926Snectar make_hints(&hints, host->proto); 382233294Sstas 383233294Sstas /** 384233294Sstas * First try this as an IP address, this allows us to add a 385233294Sstas * dot at the end to stop using the search domains. 386233294Sstas */ 387233294Sstas 388233294Sstas hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; 389233294Sstas 39090926Snectar ret = getaddrinfo(host->hostname, portstr, &hints, &host->ai); 391233294Sstas if (ret == 0) 392233294Sstas goto out; 393233294Sstas 394233294Sstas /** 395233294Sstas * If the hostname contains a dot, assumes it's a FQDN and 396233294Sstas * don't use search domains since that might be painfully slow 397233294Sstas * when machine is disconnected from that network. 398233294Sstas */ 399233294Sstas 400233294Sstas hints.ai_flags &= ~(AI_NUMERICHOST); 401233294Sstas 402233294Sstas if (strchr(hostname, '.') && hostname[strlen(hostname) - 1] != '.') { 403233294Sstas ret = asprintf(&hostname, "%s.", host->hostname); 404233294Sstas if (ret < 0 || hostname == NULL) 405233294Sstas return ENOMEM; 406233294Sstas } 407233294Sstas 408233294Sstas ret = getaddrinfo(hostname, portstr, &hints, &host->ai); 409233294Sstas if (hostname != host->hostname) 410233294Sstas free(hostname); 411233294Sstas if (ret) { 412233294Sstas ret = krb5_eai_to_heim_errno(ret, errno); 413233294Sstas goto out; 414233294Sstas } 41555682Smarkm } 416233294Sstas out: 41790926Snectar *ai = host->ai; 418233294Sstas return ret; 41955682Smarkm} 42055682Smarkm 42190926Snectarstatic krb5_boolean 42290926Snectarget_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host) 42390926Snectar{ 42490926Snectar struct krb5_krbhst_info *hi = *kd->index; 42590926Snectar if(hi != NULL) { 42690926Snectar *host = hi; 42790926Snectar kd->index = &(*kd->index)->next; 42890926Snectar return TRUE; 42990926Snectar } 43090926Snectar return FALSE; 43190926Snectar} 43290926Snectar 43390926Snectarstatic void 434233294Sstassrv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, 435178825Sdfr const char *proto, const char *service) 43690926Snectar{ 437233294Sstas krb5_error_code ret; 43890926Snectar krb5_krbhst_info **res; 43990926Snectar int count, i; 44090926Snectar 441233294Sstas ret = srv_find_realm(context, &res, &count, kd->realm, "SRV", proto, service, 442233294Sstas kd->port); 443233294Sstas _krb5_debug(context, 2, "searching DNS for realm %s %s.%s -> %d", 444233294Sstas kd->realm, proto, service, ret); 445233294Sstas if (ret) 446178825Sdfr return; 44790926Snectar for(i = 0; i < count; i++) 44890926Snectar append_host_hostinfo(kd, res[i]); 44990926Snectar free(res); 45090926Snectar} 45190926Snectar 45255682Smarkm/* 45390926Snectar * read the configuration for `conf_string', defaulting to kd->def_port and 45490926Snectar * forcing it to `kd->port' if kd->port != 0 45555682Smarkm */ 45655682Smarkm 45790926Snectarstatic void 458233294Sstasconfig_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, 45990926Snectar const char *conf_string) 46090926Snectar{ 46190926Snectar int i; 46290926Snectar char **hostlist; 463233294Sstas hostlist = krb5_config_get_strings(context, NULL, 46490926Snectar "realms", kd->realm, conf_string, NULL); 46590926Snectar 466233294Sstas _krb5_debug(context, 2, "configuration file for realm %s%s found", 467233294Sstas kd->realm, hostlist ? "" : " not"); 468233294Sstas 46990926Snectar if(hostlist == NULL) 47090926Snectar return; 47190926Snectar kd->flags |= KD_CONFIG_EXISTS; 47290926Snectar for(i = 0; hostlist && hostlist[i] != NULL; i++) 47390926Snectar append_host_string(context, kd, hostlist[i], kd->def_port, kd->port); 47490926Snectar 47590926Snectar krb5_config_free_strings(hostlist); 47690926Snectar} 47790926Snectar 47890926Snectar/* 47990926Snectar * as a fallback, look for `serv_string.kd->realm' (typically 48090926Snectar * kerberos.REALM, kerberos-1.REALM, ... 481233294Sstas * `port' is the default port for the service, and `proto' the 48290926Snectar * protocol 48390926Snectar */ 48490926Snectar 48555682Smarkmstatic krb5_error_code 486233294Sstasfallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, 48790926Snectar const char *serv_string, int port, int proto) 48855682Smarkm{ 489233294Sstas char *host = NULL; 49090926Snectar int ret; 49190926Snectar struct addrinfo *ai; 49290926Snectar struct addrinfo hints; 49390926Snectar char portstr[NI_MAXSERV]; 49490926Snectar 495233294Sstas _krb5_debug(context, 2, "fallback lookup %d for realm %s (service %s)", 496233294Sstas kd->fallback_count, kd->realm, serv_string); 497233294Sstas 498233294Sstas /* 499178825Sdfr * Don't try forever in case the DNS server keep returning us 500178825Sdfr * entries (like wildcard entries or the .nu TLD) 501178825Sdfr */ 502178825Sdfr if(kd->fallback_count >= 5) { 503178825Sdfr kd->flags |= KD_FALLBACK; 504178825Sdfr return 0; 505178825Sdfr } 506178825Sdfr 50790926Snectar if(kd->fallback_count == 0) 508233294Sstas ret = asprintf(&host, "%s.%s.", serv_string, kd->realm); 50990926Snectar else 510233294Sstas ret = asprintf(&host, "%s-%d.%s.", 511233294Sstas serv_string, kd->fallback_count, kd->realm); 51290926Snectar 513233294Sstas if (ret < 0 || host == NULL) 51490926Snectar return ENOMEM; 515233294Sstas 51690926Snectar make_hints(&hints, proto); 51790926Snectar snprintf(portstr, sizeof(portstr), "%d", port); 51890926Snectar ret = getaddrinfo(host, portstr, &hints, &ai); 51990926Snectar if (ret) { 52090926Snectar /* no more hosts, so we're done here */ 52190926Snectar free(host); 52290926Snectar kd->flags |= KD_FALLBACK; 52390926Snectar } else { 52490926Snectar struct krb5_krbhst_info *hi; 52590926Snectar size_t hostlen = strlen(host); 52690926Snectar 52790926Snectar hi = calloc(1, sizeof(*hi) + hostlen); 52890926Snectar if(hi == NULL) { 52990926Snectar free(host); 53090926Snectar return ENOMEM; 53190926Snectar } 53290926Snectar 53390926Snectar hi->proto = proto; 53490926Snectar hi->port = hi->def_port = port; 53590926Snectar hi->ai = ai; 536178825Sdfr memmove(hi->hostname, host, hostlen); 537178825Sdfr hi->hostname[hostlen] = '\0'; 53890926Snectar free(host); 53990926Snectar append_host_hostinfo(kd, hi); 54090926Snectar kd->fallback_count++; 54190926Snectar } 54290926Snectar return 0; 54390926Snectar} 54490926Snectar 545178825Sdfr/* 546178825Sdfr * Fetch hosts from plugin 547178825Sdfr */ 548178825Sdfr 549233294Sstasstatic krb5_error_code 550178825Sdfradd_locate(void *ctx, int type, struct sockaddr *addr) 551178825Sdfr{ 552178825Sdfr struct krb5_krbhst_info *hi; 553178825Sdfr struct krb5_krbhst_data *kd = ctx; 554178825Sdfr char host[NI_MAXHOST], port[NI_MAXSERV]; 555178825Sdfr struct addrinfo hints, *ai; 556178825Sdfr socklen_t socklen; 557178825Sdfr size_t hostlen; 558178825Sdfr int ret; 559178825Sdfr 560178825Sdfr socklen = socket_sockaddr_size(addr); 561178825Sdfr 562178825Sdfr ret = getnameinfo(addr, socklen, host, sizeof(host), port, sizeof(port), 563178825Sdfr NI_NUMERICHOST|NI_NUMERICSERV); 564178825Sdfr if (ret != 0) 565178825Sdfr return 0; 566178825Sdfr 567178825Sdfr make_hints(&hints, krbhst_get_default_proto(kd)); 568178825Sdfr ret = getaddrinfo(host, port, &hints, &ai); 569178825Sdfr if (ret) 570178825Sdfr return 0; 571178825Sdfr 572178825Sdfr hostlen = strlen(host); 573178825Sdfr 574178825Sdfr hi = calloc(1, sizeof(*hi) + hostlen); 575178825Sdfr if(hi == NULL) 576178825Sdfr return ENOMEM; 577233294Sstas 578178825Sdfr hi->proto = krbhst_get_default_proto(kd); 579178825Sdfr hi->port = hi->def_port = socket_get_port(addr); 580178825Sdfr hi->ai = ai; 581178825Sdfr memmove(hi->hostname, host, hostlen); 582178825Sdfr hi->hostname[hostlen] = '\0'; 583178825Sdfr append_host_hostinfo(kd, hi); 584178825Sdfr 585178825Sdfr return 0; 586178825Sdfr} 587178825Sdfr 588178825Sdfrstatic void 589178825Sdfrplugin_get_hosts(krb5_context context, 590178825Sdfr struct krb5_krbhst_data *kd, 591178825Sdfr enum locate_service_type type) 592178825Sdfr{ 593178825Sdfr struct krb5_plugin *list = NULL, *e; 594178825Sdfr krb5_error_code ret; 595178825Sdfr 596233294Sstas ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, 597233294Sstas KRB5_PLUGIN_LOCATE, &list); 598178825Sdfr if(ret != 0 || list == NULL) 599178825Sdfr return; 600178825Sdfr 601178825Sdfr for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) { 602178825Sdfr krb5plugin_service_locate_ftable *service; 603178825Sdfr void *ctx; 604178825Sdfr 605178825Sdfr service = _krb5_plugin_get_symbol(e); 606178825Sdfr if (service->minor_version != 0) 607178825Sdfr continue; 608233294Sstas 609178825Sdfr (*service->init)(context, &ctx); 610178825Sdfr ret = (*service->lookup)(ctx, type, kd->realm, 0, 0, add_locate, kd); 611178825Sdfr (*service->fini)(ctx); 612233294Sstas if (ret && ret != KRB5_PLUGIN_NO_HANDLE) { 613233294Sstas krb5_set_error_message(context, ret, 614233294Sstas N_("Locate plugin failed to lookup realm %s: %d", ""), 615233294Sstas kd->realm, ret); 616178825Sdfr break; 617233294Sstas } else if (ret == 0) { 618233294Sstas _krb5_debug(context, 2, "plugin found result for realm %s", kd->realm); 619233294Sstas kd->flags |= KD_CONFIG_EXISTS; 620178825Sdfr } 621233294Sstas 622178825Sdfr } 623178825Sdfr _krb5_plugin_free(list); 624178825Sdfr} 625178825Sdfr 626178825Sdfr/* 627178825Sdfr * 628178825Sdfr */ 629178825Sdfr 63090926Snectarstatic krb5_error_code 63190926Snectarkdc_get_next(krb5_context context, 63290926Snectar struct krb5_krbhst_data *kd, 63390926Snectar krb5_krbhst_info **host) 63490926Snectar{ 63555682Smarkm krb5_error_code ret; 63655682Smarkm 637178825Sdfr if ((kd->flags & KD_PLUGIN) == 0) { 638178825Sdfr plugin_get_hosts(context, kd, locate_service_kdc); 639178825Sdfr kd->flags |= KD_PLUGIN; 640178825Sdfr if(get_next(kd, host)) 641178825Sdfr return 0; 642178825Sdfr } 643178825Sdfr 64490926Snectar if((kd->flags & KD_CONFIG) == 0) { 64590926Snectar config_get_hosts(context, kd, "kdc"); 64690926Snectar kd->flags |= KD_CONFIG; 64790926Snectar if(get_next(kd, host)) 64890926Snectar return 0; 64990926Snectar } 65055682Smarkm 651233294Sstas if (kd->flags & KD_CONFIG_EXISTS) { 652233294Sstas _krb5_debug(context, 1, 653233294Sstas "Configuration exists for realm %s, wont go to DNS", 654233294Sstas kd->realm); 655233294Sstas return KRB5_KDC_UNREACH; 656233294Sstas } 65790926Snectar 65890926Snectar if(context->srv_lookup) { 659178825Sdfr if((kd->flags & KD_SRV_UDP) == 0 && (kd->flags & KD_LARGE_MSG) == 0) { 66090926Snectar srv_get_hosts(context, kd, "udp", "kerberos"); 66190926Snectar kd->flags |= KD_SRV_UDP; 66290926Snectar if(get_next(kd, host)) 66390926Snectar return 0; 66455682Smarkm } 66590926Snectar 66690926Snectar if((kd->flags & KD_SRV_TCP) == 0) { 66790926Snectar srv_get_hosts(context, kd, "tcp", "kerberos"); 66890926Snectar kd->flags |= KD_SRV_TCP; 66990926Snectar if(get_next(kd, host)) 67090926Snectar return 0; 67190926Snectar } 67290926Snectar if((kd->flags & KD_SRV_HTTP) == 0) { 67390926Snectar srv_get_hosts(context, kd, "http", "kerberos"); 67490926Snectar kd->flags |= KD_SRV_HTTP; 67590926Snectar if(get_next(kd, host)) 67690926Snectar return 0; 67790926Snectar } 67855682Smarkm } 67955682Smarkm 68090926Snectar while((kd->flags & KD_FALLBACK) == 0) { 68190926Snectar ret = fallback_get_hosts(context, kd, "kerberos", 682233294Sstas kd->def_port, 683178825Sdfr krbhst_get_default_proto(kd)); 68490926Snectar if(ret) 68555682Smarkm return ret; 68690926Snectar if(get_next(kd, host)) 68790926Snectar return 0; 68890926Snectar } 68990926Snectar 690233294Sstas _krb5_debug(context, 0, "No KDC entries found for %s", kd->realm); 691233294Sstas 69290926Snectar return KRB5_KDC_UNREACH; /* XXX */ 69390926Snectar} 69490926Snectar 69590926Snectarstatic krb5_error_code 69690926Snectaradmin_get_next(krb5_context context, 69790926Snectar struct krb5_krbhst_data *kd, 69890926Snectar krb5_krbhst_info **host) 69990926Snectar{ 70090926Snectar krb5_error_code ret; 70190926Snectar 702178825Sdfr if ((kd->flags & KD_PLUGIN) == 0) { 703178825Sdfr plugin_get_hosts(context, kd, locate_service_kadmin); 704178825Sdfr kd->flags |= KD_PLUGIN; 705178825Sdfr if(get_next(kd, host)) 706178825Sdfr return 0; 707178825Sdfr } 708178825Sdfr 70990926Snectar if((kd->flags & KD_CONFIG) == 0) { 71090926Snectar config_get_hosts(context, kd, "admin_server"); 71190926Snectar kd->flags |= KD_CONFIG; 71290926Snectar if(get_next(kd, host)) 71390926Snectar return 0; 71490926Snectar } 71590926Snectar 716233294Sstas if (kd->flags & KD_CONFIG_EXISTS) { 717233294Sstas _krb5_debug(context, 1, 718233294Sstas "Configuration exists for realm %s, wont go to DNS", 719233294Sstas kd->realm); 720233294Sstas return KRB5_KDC_UNREACH; 721233294Sstas } 72290926Snectar 72390926Snectar if(context->srv_lookup) { 72490926Snectar if((kd->flags & KD_SRV_TCP) == 0) { 72590926Snectar srv_get_hosts(context, kd, "tcp", "kerberos-adm"); 72690926Snectar kd->flags |= KD_SRV_TCP; 72790926Snectar if(get_next(kd, host)) 72890926Snectar return 0; 72955682Smarkm } 73055682Smarkm } 73190926Snectar 73290926Snectar if (krbhst_empty(kd) 73390926Snectar && (kd->flags & KD_FALLBACK) == 0) { 73490926Snectar ret = fallback_get_hosts(context, kd, "kerberos", 735178825Sdfr kd->def_port, 736178825Sdfr krbhst_get_default_proto(kd)); 73790926Snectar if(ret) 73890926Snectar return ret; 73990926Snectar kd->flags |= KD_FALLBACK; 74090926Snectar if(get_next(kd, host)) 74190926Snectar return 0; 74290926Snectar } 74390926Snectar 744233294Sstas _krb5_debug(context, 0, "No admin entries found for realm %s", kd->realm); 745233294Sstas 74690926Snectar return KRB5_KDC_UNREACH; /* XXX */ 74790926Snectar} 74890926Snectar 74990926Snectarstatic krb5_error_code 75090926Snectarkpasswd_get_next(krb5_context context, 75190926Snectar struct krb5_krbhst_data *kd, 75290926Snectar krb5_krbhst_info **host) 75390926Snectar{ 754102644Snectar krb5_error_code ret; 755102644Snectar 756178825Sdfr if ((kd->flags & KD_PLUGIN) == 0) { 757178825Sdfr plugin_get_hosts(context, kd, locate_service_kpasswd); 758178825Sdfr kd->flags |= KD_PLUGIN; 759178825Sdfr if(get_next(kd, host)) 760178825Sdfr return 0; 761178825Sdfr } 762178825Sdfr 76390926Snectar if((kd->flags & KD_CONFIG) == 0) { 76490926Snectar config_get_hosts(context, kd, "kpasswd_server"); 765178825Sdfr kd->flags |= KD_CONFIG; 76690926Snectar if(get_next(kd, host)) 76790926Snectar return 0; 76890926Snectar } 76990926Snectar 770233294Sstas if (kd->flags & KD_CONFIG_EXISTS) { 771233294Sstas _krb5_debug(context, 1, 772233294Sstas "Configuration exists for realm %s, wont go to DNS", 773233294Sstas kd->realm); 774233294Sstas return KRB5_KDC_UNREACH; 775233294Sstas } 77690926Snectar 77790926Snectar if(context->srv_lookup) { 77890926Snectar if((kd->flags & KD_SRV_UDP) == 0) { 77990926Snectar srv_get_hosts(context, kd, "udp", "kpasswd"); 78090926Snectar kd->flags |= KD_SRV_UDP; 78190926Snectar if(get_next(kd, host)) 78290926Snectar return 0; 78390926Snectar } 784178825Sdfr if((kd->flags & KD_SRV_TCP) == 0) { 785178825Sdfr srv_get_hosts(context, kd, "tcp", "kpasswd"); 786178825Sdfr kd->flags |= KD_SRV_TCP; 787178825Sdfr if(get_next(kd, host)) 788178825Sdfr return 0; 789178825Sdfr } 79090926Snectar } 79190926Snectar 79290926Snectar /* no matches -> try admin */ 79390926Snectar 79490926Snectar if (krbhst_empty(kd)) { 79590926Snectar kd->flags = 0; 79690926Snectar kd->port = kd->def_port; 79790926Snectar kd->get_next = admin_get_next; 798102644Snectar ret = (*kd->get_next)(context, kd, host); 799102644Snectar if (ret == 0) 800178825Sdfr (*host)->proto = krbhst_get_default_proto(kd); 801102644Snectar return ret; 80290926Snectar } 80390926Snectar 804233294Sstas _krb5_debug(context, 0, "No kpasswd entries found for realm %s", kd->realm); 805233294Sstas 806233294Sstas return KRB5_KDC_UNREACH; 80790926Snectar} 80890926Snectar 80990926Snectarstatic krb5_error_code 81090926Snectarkrb524_get_next(krb5_context context, 81190926Snectar struct krb5_krbhst_data *kd, 81290926Snectar krb5_krbhst_info **host) 81390926Snectar{ 814178825Sdfr if ((kd->flags & KD_PLUGIN) == 0) { 815178825Sdfr plugin_get_hosts(context, kd, locate_service_krb524); 816178825Sdfr kd->flags |= KD_PLUGIN; 817178825Sdfr if(get_next(kd, host)) 818178825Sdfr return 0; 819178825Sdfr } 820178825Sdfr 82190926Snectar if((kd->flags & KD_CONFIG) == 0) { 82290926Snectar config_get_hosts(context, kd, "krb524_server"); 82390926Snectar if(get_next(kd, host)) 82490926Snectar return 0; 82590926Snectar kd->flags |= KD_CONFIG; 82690926Snectar } 82790926Snectar 828233294Sstas if (kd->flags & KD_CONFIG_EXISTS) { 829233294Sstas _krb5_debug(context, 1, 830233294Sstas "Configuration exists for realm %s, wont go to DNS", 831233294Sstas kd->realm); 832233294Sstas return KRB5_KDC_UNREACH; 833233294Sstas } 83490926Snectar 83590926Snectar if(context->srv_lookup) { 83690926Snectar if((kd->flags & KD_SRV_UDP) == 0) { 83790926Snectar srv_get_hosts(context, kd, "udp", "krb524"); 83890926Snectar kd->flags |= KD_SRV_UDP; 83990926Snectar if(get_next(kd, host)) 84090926Snectar return 0; 84190926Snectar } 84290926Snectar 84390926Snectar if((kd->flags & KD_SRV_TCP) == 0) { 84490926Snectar srv_get_hosts(context, kd, "tcp", "krb524"); 84590926Snectar kd->flags |= KD_SRV_TCP; 84690926Snectar if(get_next(kd, host)) 84790926Snectar return 0; 84890926Snectar } 84990926Snectar } 85090926Snectar 85190926Snectar /* no matches -> try kdc */ 85290926Snectar 85390926Snectar if (krbhst_empty(kd)) { 85490926Snectar kd->flags = 0; 85590926Snectar kd->port = kd->def_port; 85690926Snectar kd->get_next = kdc_get_next; 85790926Snectar return (*kd->get_next)(context, kd, host); 85890926Snectar } 85990926Snectar 860233294Sstas _krb5_debug(context, 0, "No kpasswd entries found for realm %s", kd->realm); 861233294Sstas 862233294Sstas return KRB5_KDC_UNREACH; 86390926Snectar} 86490926Snectar 86590926Snectarstatic struct krb5_krbhst_data* 86690926Snectarcommon_init(krb5_context context, 867233294Sstas const char *service, 868178825Sdfr const char *realm, 869178825Sdfr int flags) 87090926Snectar{ 87190926Snectar struct krb5_krbhst_data *kd; 87290926Snectar 87390926Snectar if((kd = calloc(1, sizeof(*kd))) == NULL) 87490926Snectar return NULL; 87590926Snectar 87690926Snectar if((kd->realm = strdup(realm)) == NULL) { 87790926Snectar free(kd); 87890926Snectar return NULL; 87990926Snectar } 88090926Snectar 881233294Sstas _krb5_debug(context, 2, "Trying to find service %s for realm %s flags %x", 882233294Sstas service, realm, flags); 883233294Sstas 884178825Sdfr /* For 'realms' without a . do not even think of going to DNS */ 885178825Sdfr if (!strchr(realm, '.')) 886178825Sdfr kd->flags |= KD_CONFIG_EXISTS; 887178825Sdfr 888178825Sdfr if (flags & KRB5_KRBHST_FLAGS_LARGE_MSG) 889178825Sdfr kd->flags |= KD_LARGE_MSG; 89090926Snectar kd->end = kd->index = &kd->hosts; 89190926Snectar return kd; 89290926Snectar} 89390926Snectar 89490926Snectar/* 89590926Snectar * initialize `handle' to look for hosts of type `type' in realm `realm' 89690926Snectar */ 89790926Snectar 898233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 89990926Snectarkrb5_krbhst_init(krb5_context context, 90090926Snectar const char *realm, 90190926Snectar unsigned int type, 90290926Snectar krb5_krbhst_handle *handle) 90390926Snectar{ 904178825Sdfr return krb5_krbhst_init_flags(context, realm, type, 0, handle); 905178825Sdfr} 906178825Sdfr 907233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 908178825Sdfrkrb5_krbhst_init_flags(krb5_context context, 909178825Sdfr const char *realm, 910178825Sdfr unsigned int type, 911178825Sdfr int flags, 912178825Sdfr krb5_krbhst_handle *handle) 913178825Sdfr{ 91490926Snectar struct krb5_krbhst_data *kd; 915233294Sstas krb5_error_code (*next)(krb5_context, struct krb5_krbhst_data *, 916178825Sdfr krb5_krbhst_info **); 91790926Snectar int def_port; 918233294Sstas const char *service; 91990926Snectar 92090926Snectar switch(type) { 92190926Snectar case KRB5_KRBHST_KDC: 922178825Sdfr next = kdc_get_next; 92390926Snectar def_port = ntohs(krb5_getportbyname (context, "kerberos", "udp", 88)); 924233294Sstas service = "kdc"; 92590926Snectar break; 92690926Snectar case KRB5_KRBHST_ADMIN: 927178825Sdfr next = admin_get_next; 92890926Snectar def_port = ntohs(krb5_getportbyname (context, "kerberos-adm", 92990926Snectar "tcp", 749)); 930233294Sstas service = "admin"; 93190926Snectar break; 93290926Snectar case KRB5_KRBHST_CHANGEPW: 933178825Sdfr next = kpasswd_get_next; 93490926Snectar def_port = ntohs(krb5_getportbyname (context, "kpasswd", "udp", 93590926Snectar KPASSWD_PORT)); 936233294Sstas service = "change_password"; 93790926Snectar break; 93890926Snectar case KRB5_KRBHST_KRB524: 939178825Sdfr next = krb524_get_next; 94090926Snectar def_port = ntohs(krb5_getportbyname (context, "krb524", "udp", 4444)); 941233294Sstas service = "524"; 94290926Snectar break; 94390926Snectar default: 944233294Sstas krb5_set_error_message(context, ENOTTY, 945233294Sstas N_("unknown krbhst type (%u)", ""), type); 94690926Snectar return ENOTTY; 94790926Snectar } 948233294Sstas if((kd = common_init(context, service, realm, flags)) == NULL) 94990926Snectar return ENOMEM; 950178825Sdfr kd->get_next = next; 95190926Snectar kd->def_port = def_port; 95290926Snectar *handle = kd; 95355682Smarkm return 0; 95455682Smarkm} 95555682Smarkm 95672445Sassar/* 95790926Snectar * return the next host information from `handle' in `host' 95872445Sassar */ 95972445Sassar 960233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 96190926Snectarkrb5_krbhst_next(krb5_context context, 96290926Snectar krb5_krbhst_handle handle, 96390926Snectar krb5_krbhst_info **host) 96490926Snectar{ 96590926Snectar if(get_next(handle, host)) 96690926Snectar return 0; 96790926Snectar 96890926Snectar return (*handle->get_next)(context, handle, host); 96990926Snectar} 97090926Snectar 97190926Snectar/* 97290926Snectar * return the next host information from `handle' as a host name 97390926Snectar * in `hostname' (or length `hostlen) 97490926Snectar */ 97590926Snectar 976233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 97790926Snectarkrb5_krbhst_next_as_string(krb5_context context, 97890926Snectar krb5_krbhst_handle handle, 97990926Snectar char *hostname, 98090926Snectar size_t hostlen) 98190926Snectar{ 98290926Snectar krb5_error_code ret; 98390926Snectar krb5_krbhst_info *host; 98490926Snectar ret = krb5_krbhst_next(context, handle, &host); 98590926Snectar if(ret) 98690926Snectar return ret; 98790926Snectar return krb5_krbhst_format_string(context, host, hostname, hostlen); 98890926Snectar} 98990926Snectar 99090926Snectar 991233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 99290926Snectarkrb5_krbhst_reset(krb5_context context, krb5_krbhst_handle handle) 99390926Snectar{ 99490926Snectar handle->index = &handle->hosts; 99590926Snectar} 99690926Snectar 997233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 99890926Snectarkrb5_krbhst_free(krb5_context context, krb5_krbhst_handle handle) 99990926Snectar{ 100090926Snectar krb5_krbhst_info *h, *next; 100190926Snectar 100290926Snectar if (handle == NULL) 100390926Snectar return; 100490926Snectar 100590926Snectar for (h = handle->hosts; h != NULL; h = next) { 100690926Snectar next = h->next; 1007178825Sdfr _krb5_free_krbhst_info(h); 100890926Snectar } 100990926Snectar 101090926Snectar free(handle->realm); 101190926Snectar free(handle); 101290926Snectar} 101390926Snectar 101490926Snectar/* backwards compatibility ahead */ 101590926Snectar 101690926Snectarstatic krb5_error_code 1017233294Sstasgethostlist(krb5_context context, const char *realm, 101890926Snectar unsigned int type, char ***hostlist) 101990926Snectar{ 102090926Snectar krb5_error_code ret; 102190926Snectar int nhost = 0; 102290926Snectar krb5_krbhst_handle handle; 102390926Snectar char host[MAXHOSTNAMELEN]; 102490926Snectar krb5_krbhst_info *hostinfo; 102590926Snectar 102690926Snectar ret = krb5_krbhst_init(context, realm, type, &handle); 102790926Snectar if (ret) 102890926Snectar return ret; 102990926Snectar 103090926Snectar while(krb5_krbhst_next(context, handle, &hostinfo) == 0) 103190926Snectar nhost++; 1032178825Sdfr if(nhost == 0) { 1033233294Sstas krb5_set_error_message(context, KRB5_KDC_UNREACH, 1034233294Sstas N_("No KDC found for realm %s", ""), realm); 103590926Snectar return KRB5_KDC_UNREACH; 1036178825Sdfr } 103790926Snectar *hostlist = calloc(nhost + 1, sizeof(**hostlist)); 103890926Snectar if(*hostlist == NULL) { 103990926Snectar krb5_krbhst_free(context, handle); 104090926Snectar return ENOMEM; 104190926Snectar } 104290926Snectar 104390926Snectar krb5_krbhst_reset(context, handle); 104490926Snectar nhost = 0; 1045233294Sstas while(krb5_krbhst_next_as_string(context, handle, 104690926Snectar host, sizeof(host)) == 0) { 104790926Snectar if(((*hostlist)[nhost++] = strdup(host)) == NULL) { 104890926Snectar krb5_free_krbhst(context, *hostlist); 104990926Snectar krb5_krbhst_free(context, handle); 105090926Snectar return ENOMEM; 105190926Snectar } 105290926Snectar } 1053233294Sstas (*hostlist)[nhost] = NULL; 105490926Snectar krb5_krbhst_free(context, handle); 105590926Snectar return 0; 105690926Snectar} 105790926Snectar 105890926Snectar/* 105990926Snectar * return an malloced list of kadmin-hosts for `realm' in `hostlist' 106090926Snectar */ 106190926Snectar 1062233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 106355682Smarkmkrb5_get_krb_admin_hst (krb5_context context, 106455682Smarkm const krb5_realm *realm, 106555682Smarkm char ***hostlist) 106655682Smarkm{ 106790926Snectar return gethostlist(context, *realm, KRB5_KRBHST_ADMIN, hostlist); 106855682Smarkm} 106955682Smarkm 107072445Sassar/* 107190926Snectar * return an malloced list of changepw-hosts for `realm' in `hostlist' 107272445Sassar */ 107372445Sassar 1074233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 107555682Smarkmkrb5_get_krb_changepw_hst (krb5_context context, 107655682Smarkm const krb5_realm *realm, 107755682Smarkm char ***hostlist) 107855682Smarkm{ 107990926Snectar return gethostlist(context, *realm, KRB5_KRBHST_CHANGEPW, hostlist); 108090926Snectar} 108172445Sassar 108290926Snectar/* 108390926Snectar * return an malloced list of 524-hosts for `realm' in `hostlist' 108490926Snectar */ 108590926Snectar 1086233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 108790926Snectarkrb5_get_krb524hst (krb5_context context, 108890926Snectar const krb5_realm *realm, 108990926Snectar char ***hostlist) 109090926Snectar{ 109190926Snectar return gethostlist(context, *realm, KRB5_KRBHST_KRB524, hostlist); 109255682Smarkm} 109355682Smarkm 109490926Snectar 109572445Sassar/* 109690926Snectar * return an malloced list of KDC's for `realm' in `hostlist' 109772445Sassar */ 109872445Sassar 1099233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 110055682Smarkmkrb5_get_krbhst (krb5_context context, 110155682Smarkm const krb5_realm *realm, 110255682Smarkm char ***hostlist) 110355682Smarkm{ 110490926Snectar return gethostlist(context, *realm, KRB5_KRBHST_KDC, hostlist); 110555682Smarkm} 110655682Smarkm 110772445Sassar/* 110890926Snectar * free all the memory allocated in `hostlist' 110972445Sassar */ 111072445Sassar 1111233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 111255682Smarkmkrb5_free_krbhst (krb5_context context, 111355682Smarkm char **hostlist) 111455682Smarkm{ 111555682Smarkm char **p; 111655682Smarkm 111755682Smarkm for (p = hostlist; *p; ++p) 111855682Smarkm free (*p); 111955682Smarkm free (hostlist); 112055682Smarkm return 0; 112155682Smarkm} 1122