LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - krbhst.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 297 627 47.4 %
Date: 2024-04-13 12:30:31 Functions: 24 44 54.5 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2001 - 2003 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include "krb5_locl.h"
      37             : #include <resolve.h>
      38             : #include "locate_plugin.h"
      39             : 
      40             : static int
      41         154 : string_to_proto(const char *string)
      42             : {
      43         154 :     if(strcasecmp(string, "udp") == 0)
      44          71 :         return KRB5_KRBHST_UDP;
      45          83 :     else if(strcasecmp(string, "tcp") == 0)
      46          47 :         return KRB5_KRBHST_TCP;
      47          36 :     else if(strcasecmp(string, "http") == 0)
      48          36 :         return KRB5_KRBHST_HTTP;
      49           0 :     return -1;
      50             : }
      51             : 
      52             : static int
      53          46 : is_invalid_tld_srv_target(const char *target)
      54             : {
      55          46 :     return (strncmp("your-dns-needs-immediate-attention.",
      56             :                     target, 35) == 0
      57          46 :             && strchr(&target[35], '.') == NULL);
      58             : }
      59             : 
      60             : /*
      61             :  * set `res' and `count' to the result of looking up SRV RR in DNS for
      62             :  * `proto', `proto', `realm' using `dns_type'.
      63             :  * if `port' != 0, force that port number
      64             :  */
      65             : 
      66             : static krb5_error_code
      67         154 : srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count,
      68             :                const char *realm, const char *dns_type, const char *sitename,
      69             :                const char *proto, const char *service, int port)
      70             : {
      71           0 :     char domain[1024];
      72           0 :     struct rk_dns_reply *r;
      73           0 :     struct rk_resource_record *rr;
      74           0 :     int num_srv;
      75           0 :     int proto_num;
      76           0 :     int def_port;
      77             : 
      78         154 :     *res = NULL;
      79         154 :     *count = 0;
      80             : 
      81         154 :     proto_num = string_to_proto(proto);
      82         154 :     if(proto_num < 0) {
      83           0 :         krb5_set_error_message(context, EINVAL,
      84           0 :                                N_("unknown protocol `%s' to lookup", ""),
      85             :                                proto);
      86           0 :         return EINVAL;
      87             :     }
      88             : 
      89         154 :     if(proto_num == KRB5_KRBHST_HTTP)
      90          36 :         def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
      91         118 :     else if(port == 0)
      92         118 :         def_port = ntohs(krb5_getportbyname (context, service, proto, 88));
      93             :     else
      94           0 :         def_port = port;
      95             : 
      96         154 :     if (sitename)
      97           0 :         snprintf(domain, sizeof(domain), "_%s._%s.%s._sites.%s.",
      98             :                  service, proto, sitename, realm);
      99             :     else
     100         154 :         snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);
     101             : 
     102         154 :     r = rk_dns_lookup(domain, dns_type);
     103         154 :     if(r == NULL) {
     104          72 :         _krb5_debug(context, 0,
     105             :                     "DNS lookup failed domain: %s", domain);
     106          72 :         return KRB5_KDC_UNREACH;
     107             :     }
     108             : 
     109         174 :     for(num_srv = 0, rr = r->head; rr; rr = rr->next)
     110          92 :         if(rr->type == rk_ns_t_srv) {
     111          46 :             if (num_srv >= INT_MAX) {
     112           0 :                 rk_dns_free_data(r);
     113           0 :                 return KRB5_KDC_UNREACH;
     114             :             }
     115          46 :             if (num_srv >= SIZE_MAX / sizeof(**res)) {
     116           0 :                 rk_dns_free_data(r);
     117           0 :                 return KRB5_KDC_UNREACH;
     118             :             }
     119          46 :             num_srv++;
     120             :         }
     121             : 
     122          82 :     if (num_srv == 0) {
     123          36 :         _krb5_debug(context, 0,
     124             :                     "DNS SRV RR lookup domain nodata: %s", domain);
     125          36 :         rk_dns_free_data(r);
     126          36 :         return KRB5_KDC_UNREACH;
     127             :     }
     128             : 
     129          46 :     *res = malloc(num_srv * sizeof(**res));
     130          46 :     if(*res == NULL) {
     131           0 :         rk_dns_free_data(r);
     132           0 :         return krb5_enomem(context);
     133             :     }
     134             : 
     135          46 :     rk_dns_srv_order(r);
     136             : 
     137         138 :     for(num_srv = 0, rr = r->head; rr; rr = rr->next)
     138          92 :         if(rr->type == rk_ns_t_srv) {
     139          46 :             krb5_krbhst_info *hi = NULL;
     140           0 :             size_t len;
     141          46 :             int invalid_tld = 1;
     142             : 
     143             :             /* Test for top-level domain controlled interruptions */
     144          46 :             if (!is_invalid_tld_srv_target(rr->u.srv->target)) {
     145          46 :                 invalid_tld = 0;
     146          46 :                 len = strlen(rr->u.srv->target);
     147          46 :                 hi = calloc(1, sizeof(*hi) + len);
     148             :             }
     149          46 :             if(hi == NULL) {
     150           0 :                 rk_dns_free_data(r);
     151           0 :                 while(--num_srv >= 0)
     152           0 :                     free((*res)[num_srv]);
     153           0 :                 free(*res);
     154           0 :                 *res = NULL;
     155           0 :                 if (invalid_tld) {
     156           0 :                     krb5_warnx(context,
     157             :                                "Domain lookup failed: "
     158             :                                "Realm %s needs immediate attention "
     159             :                                "see https://icann.org/namecollision",
     160             :                                realm);
     161           0 :                     return KRB5_KDC_UNREACH;
     162             :                 }
     163           0 :                 return krb5_enomem(context);
     164             :             }
     165          46 :             (*res)[num_srv++] = hi;
     166             : 
     167          46 :             hi->proto = proto_num;
     168             : 
     169          46 :             hi->def_port = def_port;
     170          46 :             if (port != 0)
     171           0 :                 hi->port = port;
     172             :             else
     173          46 :                 hi->port = rr->u.srv->port;
     174             : 
     175          46 :             strlcpy(hi->hostname, rr->u.srv->target, len + 1);
     176             :         }
     177             : 
     178          46 :     *count = num_srv;
     179             : 
     180          46 :     rk_dns_free_data(r);
     181          46 :     return 0;
     182             : }
     183             : 
     184             : 
     185             : struct krb5_krbhst_data {
     186             :     const char *config_param;
     187             :     const char *srv_label;
     188             :     char *realm;
     189             :     unsigned int flags;
     190             :     int def_port;
     191             :     int port;                   /* hardwired port number if != 0 */
     192             : #define KD_CONFIG               0x0001
     193             : #define KD_SRV_UDP              0x0002
     194             : #define KD_SRV_TCP              0x0004
     195             : #define KD_SITE_SRV_UDP         0x0008
     196             : #define KD_SITE_SRV_TCP         0x0010
     197             : #define KD_SRV_HTTP             0x0020
     198             : #define KD_SRV_KKDCP            0x0040
     199             : #define KD_FALLBACK             0x0080
     200             : #define KD_CONFIG_EXISTS        0x0100
     201             : #define KD_LARGE_MSG            0x0200
     202             : #define KD_PLUGIN               0x0400
     203             : #define KD_HOSTNAMES            0x0800
     204             :     krb5_error_code (*get_next)(krb5_context, struct krb5_krbhst_data *,
     205             :                                 krb5_krbhst_info**);
     206             : 
     207             :     char *hostname;
     208             :     char *sitename;
     209             :     unsigned int fallback_count;
     210             : 
     211             :     struct krb5_krbhst_info *hosts, **index, **end;
     212             : };
     213             : 
     214             : static krb5_boolean
     215           0 : krbhst_empty(const struct krb5_krbhst_data *kd)
     216             : {
     217           0 :     return kd->index == &kd->hosts;
     218             : }
     219             : 
     220             : /*
     221             :  * Return the default protocol for the `kd' (either TCP or UDP)
     222             :  */
     223             : 
     224             : static int
     225       74170 : krbhst_get_default_proto(struct krb5_krbhst_data *kd)
     226             : {
     227       74170 :     if (kd->flags & KD_LARGE_MSG)
     228       48930 :         return KRB5_KRBHST_TCP;
     229       24070 :     return KRB5_KRBHST_UDP;
     230             : }
     231             : 
     232             : static int
     233           0 : krbhst_get_default_port(struct krb5_krbhst_data *kd)
     234             : {
     235           0 :     return kd->def_port;
     236             : }
     237             : 
     238             : /*
     239             :  *
     240             :  */
     241             : 
     242             : KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
     243           0 : _krb5_krbhst_get_realm(krb5_krbhst_handle handle)
     244             : {
     245           0 :     return handle->realm;
     246             : }
     247             : 
     248             : /*
     249             :  * parse `spec' into a krb5_krbhst_info, defaulting the port to `def_port'
     250             :  * and forcing it to `port' if port != 0
     251             :  */
     252             : 
     253             : static struct krb5_krbhst_info*
     254       74134 : parse_hostspec(krb5_context context, struct krb5_krbhst_data *kd,
     255             :                const char *spec, int def_port, int port)
     256             : {
     257       74134 :     const char *p = spec, *q;
     258        3413 :     struct krb5_krbhst_info *hi;
     259             : 
     260       74134 :     hi = calloc(1, sizeof(*hi) + strlen(spec));
     261       74134 :     if(hi == NULL)
     262           0 :         return NULL;
     263             : 
     264       74134 :     hi->proto = krbhst_get_default_proto(kd);
     265             : 
     266       74134 :     if(strncmp(p, "http://", 7) == 0){
     267           0 :         hi->proto = KRB5_KRBHST_HTTP;
     268           0 :         p += 7;
     269       74134 :     } else if(strncmp(p, "http/", 5) == 0) {
     270           0 :         hi->proto = KRB5_KRBHST_HTTP;
     271           0 :         p += 5;
     272           0 :         def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
     273       74134 :     }else if(strncmp(p, "tcp/", 4) == 0){
     274           0 :         hi->proto = KRB5_KRBHST_TCP;
     275           0 :         p += 4;
     276       74134 :     } else if(strncmp(p, "udp/", 4) == 0) {
     277           0 :         hi->proto = KRB5_KRBHST_UDP;
     278           0 :         p += 4;
     279             :     }
     280             : 
     281       74134 :     if (p[0] == '[' && (q = strchr(p, ']')) != NULL) {
     282             :         /* if address looks like [foo:bar] or [foo:bar]: its a ipv6
     283             :            adress, strip of [] */
     284         652 :         memcpy(hi->hostname, &p[1], q - p - 1);
     285         652 :         hi->hostname[q - p - 1] = '\0';
     286         652 :         p = q + 1;
     287             :         /* get trailing : */
     288         652 :         if (p[0] == ':')
     289         652 :             p++;
     290       73482 :     } else if(strsep_copy(&p, ":", hi->hostname, strlen(spec) + 1) < 0) {
     291             :         /* copy everything before : */
     292           0 :         free(hi);
     293           0 :         return NULL;
     294             :     }
     295             :     /* get rid of trailing /, and convert to lower case */
     296       74134 :     hi->hostname[strcspn(hi->hostname, "/")] = '\0';
     297       74134 :     strlwr(hi->hostname);
     298             : 
     299       74134 :     hi->port = hi->def_port = def_port;
     300       74134 :     if(p != NULL && p[0]) {
     301        3413 :         char *end;
     302       73155 :         hi->port = strtol(p, &end, 0);
     303       73155 :         if(end == p) {
     304           0 :             free(hi);
     305           0 :             return NULL;
     306             :         }
     307             :     }
     308       74134 :     if (port)
     309           0 :         hi->port = port;
     310       70721 :     return hi;
     311             : }
     312             : 
     313             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     314       74180 : _krb5_free_krbhst_info(krb5_krbhst_info *hi)
     315             : {
     316       74180 :     if (hi->ai != NULL)
     317       73390 :         freeaddrinfo(hi->ai);
     318       74180 :     free(hi);
     319       74180 : }
     320             : 
     321             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     322           0 : _krb5_krbhost_info_move(krb5_context context,
     323             :                         krb5_krbhst_info *from,
     324             :                         krb5_krbhst_info **to)
     325             : {
     326           0 :     size_t hostnamelen = strlen(from->hostname);
     327             :     /* trailing NUL is included in structure */
     328           0 :     *to = calloc(1, sizeof(**to) + hostnamelen);
     329           0 :     if (*to == NULL)
     330           0 :         return krb5_enomem(context);
     331             : 
     332           0 :     (*to)->proto = from->proto;
     333           0 :     (*to)->port = from->port;
     334           0 :     (*to)->def_port = from->def_port;
     335           0 :     (*to)->ai = from->ai;
     336           0 :     from->ai = NULL;
     337           0 :     (*to)->next = NULL;
     338           0 :     memcpy((*to)->hostname, from->hostname, hostnamelen + 1);
     339           0 :     return 0;
     340             : }
     341             : 
     342             : 
     343             : static void
     344       74180 : append_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host)
     345             : {
     346        3413 :     struct krb5_krbhst_info *h;
     347             : 
     348       74883 :     for(h = kd->hosts; h; h = h->next)
     349         790 :         if(h->proto == host->proto &&
     350         790 :            h->port == host->port &&
     351         790 :            strcmp(h->hostname, host->hostname) == 0) {
     352          87 :             _krb5_free_krbhst_info(host);
     353          87 :             return;
     354             :         }
     355             :     /*
     356             :      * We should always initialize kd->end in common_init(), but static
     357             :      * analyzers may not see that we do, and the compiler might conclude
     358             :      * there's UB here.
     359             :      */
     360       74093 :     if (kd->end)
     361       74093 :         *kd->end = host;
     362       74093 :     kd->end = &host->next;
     363             : }
     364             : 
     365             : static krb5_error_code
     366       74134 : append_host_string(krb5_context context, struct krb5_krbhst_data *kd,
     367             :                    const char *host, int def_port, int port)
     368             : {
     369        3413 :     struct krb5_krbhst_info *hi;
     370             : 
     371       74134 :     hi = parse_hostspec(context, kd, host, def_port, port);
     372       74134 :     if(hi == NULL)
     373           0 :         return krb5_enomem(context);
     374             : 
     375       74134 :     append_host_hostinfo(kd, hi);
     376       74134 :     return 0;
     377             : }
     378             : 
     379             : /*
     380             :  * return a readable representation of `host' in `hostname, hostlen'
     381             :  */
     382             : 
     383             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     384           0 : krb5_krbhst_format_string(krb5_context context, const krb5_krbhst_info *host,
     385             :                           char *hostname, size_t hostlen)
     386             : {
     387           0 :     const char *proto = "";
     388           0 :     if(host->proto == KRB5_KRBHST_TCP)
     389           0 :         proto = "tcp/";
     390           0 :     else if(host->proto == KRB5_KRBHST_HTTP)
     391           0 :         proto = "http://";
     392           0 :     if (host->port != host->def_port)
     393           0 :         snprintf(hostname, hostlen, "%s%s:%d", proto, host->hostname, (int)host->port);
     394             :     else
     395           0 :         snprintf(hostname, hostlen, "%s%s", proto, host->hostname);
     396           0 :     return 0;
     397             : }
     398             : 
     399             : /*
     400             :  * create a getaddrinfo `hints' based on `proto'
     401             :  */
     402             : 
     403             : static void
     404       73426 : make_hints(struct addrinfo *hints, int proto)
     405             : {
     406       73426 :     memset(hints, 0, sizeof(*hints));
     407       73426 :     hints->ai_family = AF_UNSPEC;
     408       73426 :     switch(proto) {
     409       24913 :     case KRB5_KRBHST_UDP :
     410       24913 :         hints->ai_socktype = SOCK_DGRAM;
     411       24913 :         break;
     412       48513 :     case KRB5_KRBHST_HTTP :
     413             :     case KRB5_KRBHST_TCP :
     414       48513 :         hints->ai_socktype = SOCK_STREAM;
     415       48513 :         break;
     416             :     }
     417       73426 : }
     418             : 
     419             : /**
     420             :  * Return an `struct addrinfo *' for a KDC host.
     421             :  *
     422             :  * Returns an the struct addrinfo in in that corresponds to the
     423             :  * information in `host'.  free:ing is handled by krb5_krbhst_free, so
     424             :  * the returned ai must not be released.
     425             :  *
     426             :  * @ingroup krb5
     427             :  */
     428             : 
     429             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     430       73390 : krb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host,
     431             :                          struct addrinfo **ai)
     432             : {
     433       73390 :     int ret = 0;
     434             : 
     435       73390 :     if (host->ai == NULL) {
     436        3413 :         struct addrinfo hints;
     437        3413 :         char portstr[NI_MAXSERV];
     438             : 
     439       73390 :         snprintf (portstr, sizeof(portstr), "%d", host->port);
     440       73390 :         make_hints(&hints, host->proto);
     441             : 
     442       73390 :         ret = getaddrinfo(host->hostname, portstr, &hints, &host->ai);
     443       73390 :         if (ret) {
     444           0 :             ret = krb5_eai_to_heim_errno(ret, errno);
     445           0 :             goto out;
     446             :         }
     447             :     }
     448           0 :  out:
     449       73390 :     *ai = host->ai;
     450       73390 :     return ret;
     451             : }
     452             : 
     453             : static krb5_boolean
     454      323885 : get_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host)
     455             : {
     456      340950 :     struct krb5_krbhst_info *hi = kd ? *kd->index : NULL;
     457      313646 :     if(hi != NULL) {
     458       73390 :         *host = hi;
     459       73390 :         kd->index = &(*kd->index)->next;
     460       73390 :         return TRUE;
     461             :     }
     462      240256 :     return FALSE;
     463             : }
     464             : 
     465             : static void
     466         154 : srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
     467             :               const char *sitename, const char *proto, const char *service)
     468             : {
     469           0 :     krb5_error_code ret;
     470           0 :     krb5_krbhst_info **res;
     471           0 :     int count, i;
     472             : 
     473         154 :     if (krb5_realm_is_lkdc(kd->realm))
     474         108 :         return;
     475             : 
     476         154 :     ret = srv_find_realm(context, &res, &count, kd->realm, "SRV",
     477             :                          sitename, proto, service, kd->port);
     478         154 :     _krb5_debug(context, 2, "searching DNS for realm %s %s.%s -> %d",
     479             :                 kd->realm, proto, service, ret);
     480         154 :     if (ret)
     481         108 :         return;
     482          92 :     for(i = 0; i < count; i++)
     483          46 :         append_host_hostinfo(kd, res[i]);
     484          46 :     free(res);
     485             : }
     486             : 
     487             : /*
     488             :  * read the configuration for `conf_string', defaulting to kd->def_port and
     489             :  * forcing it to `kd->port' if kd->port != 0
     490             :  */
     491             : 
     492             : static void
     493       80930 : config_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
     494             :                  const char *conf_string)
     495             : {
     496        3413 :     int i;
     497        3413 :     char **hostlist;
     498       80930 :     hostlist = krb5_config_get_strings(context, NULL,
     499             :                                        "realms", kd->realm, conf_string, NULL);
     500             : 
     501       80930 :     _krb5_debug(context, 2, "configuration file for realm %s%s found",
     502             :                 kd->realm, hostlist ? "" : " not");
     503             : 
     504       80930 :     if(hostlist == NULL)
     505        7586 :         return;
     506       73344 :     kd->flags |= KD_CONFIG_EXISTS;
     507      147478 :     for(i = 0; hostlist && hostlist[i] != NULL; i++)
     508       74134 :         append_host_string(context, kd, hostlist[i], kd->def_port, kd->port);
     509             : 
     510       73344 :     krb5_config_free_strings(hostlist);
     511             : }
     512             : 
     513             : /*
     514             :  * as a fallback, look for `serv_string.kd->realm' (typically
     515             :  * kerberos.REALM, kerberos-1.REALM, ...
     516             :  * `port' is the default port for the service, and `proto' the
     517             :  * protocol
     518             :  */
     519             : 
     520             : static krb5_error_code
     521          36 : fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
     522             :                    const char *serv_string, int port, int proto)
     523             : {
     524          36 :     char *host = NULL;
     525           0 :     int ret;
     526           0 :     struct addrinfo *ai;
     527           0 :     struct addrinfo hints;
     528           0 :     char portstr[NI_MAXSERV];
     529             : 
     530          36 :     ret = krb5_config_get_bool_default(context, NULL, KRB5_FALLBACK_DEFAULT,
     531             :                                        "libdefaults", "use_fallback", NULL);
     532          36 :     if (!ret) {
     533           0 :         kd->flags |= KD_FALLBACK;
     534           0 :         return 0;
     535             :     }
     536             : 
     537          36 :     _krb5_debug(context, 2, "fallback lookup %d for realm %s (service %s)",
     538             :                 kd->fallback_count, kd->realm, serv_string);
     539             : 
     540             :     /*
     541             :      * Don't try forever in case the DNS server keep returning us
     542             :      * entries (like wildcard entries or the .nu TLD)
     543             :      *
     544             :      * Also don't try LKDC realms since fallback wont work on them at all.
     545             :      */
     546          36 :     if(kd->fallback_count >= 5 || krb5_realm_is_lkdc(kd->realm)) {
     547           0 :         kd->flags |= KD_FALLBACK;
     548           0 :         return 0;
     549             :     }
     550             : 
     551          36 :     if(kd->fallback_count == 0)
     552          36 :         ret = asprintf(&host, "%s.%s.", serv_string, kd->realm);
     553             :     else
     554           0 :         ret = asprintf(&host, "%s-%d.%s.",
     555             :                        serv_string, kd->fallback_count, kd->realm);
     556             : 
     557          36 :     if (ret < 0 || host == NULL)
     558           0 :         return krb5_enomem(context);
     559             : 
     560          36 :     make_hints(&hints, proto);
     561          36 :     snprintf(portstr, sizeof(portstr), "%d", port);
     562          36 :     ret = getaddrinfo(host, portstr, &hints, &ai);
     563          36 :     if (ret) {
     564             :         /* no more hosts, so we're done here */
     565          36 :         free(host);
     566          36 :         kd->flags |= KD_FALLBACK;
     567             :     } else {
     568           0 :         struct krb5_krbhst_info *hi;
     569           0 :         size_t hostlen;
     570             : 
     571             :         /* Check for ICANN gTLD Name Collision address (127.0.53.53) */
     572           0 :         if (ai->ai_family == AF_INET) {
     573           0 :             struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
     574           0 :             if (sin->sin_addr.s_addr == htonl(0x7f003535)) {
     575           0 :                 krb5_warnx(context,
     576             :                            "Fallback lookup failed: "
     577             :                            "Realm %s needs immediate attention "
     578             :                            "see https://icann.org/namecollision",
     579             :                            kd->realm);
     580           0 :                 free(host);
     581           0 :                 freeaddrinfo(ai);
     582           0 :                 return KRB5_KDC_UNREACH;
     583             :             }
     584             :         }
     585             : 
     586           0 :         hostlen = strlen(host);
     587           0 :         hi = calloc(1, sizeof(*hi) + hostlen);
     588           0 :         if(hi == NULL) {
     589           0 :             free(host);
     590           0 :             freeaddrinfo(ai);
     591           0 :             return krb5_enomem(context);
     592             :         }
     593             : 
     594           0 :         hi->proto = proto;
     595           0 :         hi->port  = hi->def_port = port;
     596           0 :         hi->ai    = ai;
     597           0 :         memmove(hi->hostname, host, hostlen);
     598           0 :         hi->hostname[hostlen] = '\0';
     599           0 :         free(host);
     600           0 :         append_host_hostinfo(kd, hi);
     601           0 :         kd->fallback_count++;
     602             :     }
     603          36 :     return 0;
     604             : }
     605             : 
     606             : /*
     607             :  * Fetch hosts from plugin
     608             :  */
     609             : 
     610             : static krb5_error_code
     611           0 : add_plugin_host(struct krb5_krbhst_data *kd,
     612             :                 const char *host,
     613             :                 const char *port,
     614             :                 int portnum,
     615             :                 int proto)
     616             : {
     617           0 :     struct krb5_krbhst_info *hi;
     618           0 :     struct addrinfo hints, *ai;
     619           0 :     size_t hostlen;
     620           0 :     int ret;
     621             : 
     622           0 :     make_hints(&hints, proto);
     623           0 :     ret = getaddrinfo(host, port, &hints, &ai);
     624           0 :     if (ret)
     625           0 :         return 0;
     626             : 
     627           0 :     hostlen = strlen(host);
     628             : 
     629           0 :     hi = calloc(1, sizeof(*hi) + hostlen);
     630           0 :     if (hi == NULL) {
     631           0 :         freeaddrinfo(ai);
     632           0 :         return ENOMEM;
     633             :     }
     634             : 
     635           0 :     hi->proto = proto;
     636           0 :     hi->port  = hi->def_port = portnum;
     637           0 :     hi->ai    = ai;
     638           0 :     memmove(hi->hostname, host, hostlen);
     639           0 :     hi->hostname[hostlen] = '\0';
     640           0 :     append_host_hostinfo(kd, hi);
     641             : 
     642           0 :     return 0;
     643             : }
     644             : 
     645             : static krb5_error_code
     646           0 : add_locate(void *ctx, int type, struct sockaddr *addr)
     647             : {
     648           0 :     struct krb5_krbhst_data *kd = ctx;
     649           0 :     char host[NI_MAXHOST], port[NI_MAXSERV];
     650           0 :     socklen_t socklen;
     651           0 :     krb5_error_code ret;
     652           0 :     int proto, portnum;
     653             : 
     654           0 :     socklen = socket_sockaddr_size(addr);
     655           0 :     portnum = socket_get_port(addr);
     656             : 
     657           0 :     ret = getnameinfo(addr, socklen, host, sizeof(host), port, sizeof(port),
     658             :                       NI_NUMERICHOST|NI_NUMERICSERV);
     659           0 :     if (ret != 0)
     660           0 :         return 0;
     661             : 
     662           0 :     if (kd->port)
     663           0 :         snprintf(port, sizeof(port), "%d", kd->port);
     664           0 :     else if (atoi(port) == 0)
     665           0 :         snprintf(port, sizeof(port), "%d", krbhst_get_default_port(kd));
     666             : 
     667           0 :     proto = krbhst_get_default_proto(kd);
     668             : 
     669           0 :     ret = add_plugin_host(kd, host, port, portnum, proto);
     670           0 :     if (ret)
     671           0 :         return ret;
     672             : 
     673             :     /*
     674             :      * This is really kind of broken and should be solved a different
     675             :      * way, some sites block UDP, and we don't, in the general case,
     676             :      * fall back to TCP, that should also be done. But since that
     677             :      * should require us to invert the whole "find kdc" stack, let put
     678             :      * this in for now. 
     679             :      */
     680             : 
     681           0 :     if (proto == KRB5_KRBHST_UDP) {
     682           0 :         ret = add_plugin_host(kd, host, port, portnum, KRB5_KRBHST_TCP);
     683           0 :         if (ret)
     684           0 :             return ret;
     685             :     }
     686             : 
     687           0 :     return 0;
     688             : }
     689             : 
     690             : struct plctx {
     691             :     enum locate_service_type type;
     692             :     struct krb5_krbhst_data *kd;
     693             :     unsigned long flags;
     694             : };
     695             : 
     696             : static KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     697           0 : plcallback(krb5_context context,
     698             :            const void *plug, void *plugctx, void *userctx)
     699             : {
     700           0 :     const krb5plugin_service_locate_ftable *locate = plug;
     701           0 :     struct plctx *plctx = userctx;
     702             :     
     703           0 :     if (locate->minor_version >= KRB5_PLUGIN_LOCATE_VERSION_2)
     704           0 :         return locate->lookup(plugctx, plctx->flags, plctx->type, plctx->kd->realm, 0, 0, add_locate, plctx->kd);
     705             :     
     706           0 :     if (plctx->flags & KRB5_PLF_ALLOW_HOMEDIR)
     707           0 :         return locate->old_lookup(plugctx, plctx->type, plctx->kd->realm, 0, 0, add_locate, plctx->kd);
     708             :     
     709           0 :     return KRB5_PLUGIN_NO_HANDLE;
     710             : }
     711             : 
     712             : static const char *const locate_plugin_deps[] = { "krb5", NULL };
     713             : 
     714             : static const struct heim_plugin_data
     715             : locate_plugin_data = {
     716             :     "krb5",
     717             :     KRB5_PLUGIN_LOCATE,
     718             :     KRB5_PLUGIN_LOCATE_VERSION_0,
     719             :     locate_plugin_deps,
     720             :     krb5_get_instance
     721             : };
     722             : 
     723             : static void
     724       80930 : plugin_get_hosts(krb5_context context,
     725             :                  struct krb5_krbhst_data *kd,
     726             :                  enum locate_service_type type)
     727             : {
     728       80930 :     struct plctx ctx = { type, kd, 0 };
     729             : 
     730       80930 :     if (_krb5_homedir_access(context))
     731       80930 :         ctx.flags |= KRB5_PLF_ALLOW_HOMEDIR;
     732             : 
     733       80930 :     _krb5_plugin_run_f(context, &locate_plugin_data,
     734             :                        0, &ctx, plcallback);
     735       80930 : }
     736             : 
     737             : /*
     738             :  *
     739             :  */
     740             : 
     741             : static void
     742       80901 : hostnames_get_hosts(krb5_context context,
     743             :                     struct krb5_krbhst_data *kd,
     744             :                     const char *type)
     745             : {
     746       80901 :     kd->flags |= KD_HOSTNAMES;
     747       80901 :     if (kd->hostname)
     748           0 :         append_host_string(context, kd, kd->hostname, kd->def_port, kd->port);
     749       80901 : }
     750             : 
     751             : 
     752             : /*
     753             :  *
     754             :  */
     755             : 
     756             : static krb5_error_code
     757       80905 : kdc_get_next(krb5_context context,
     758             :              struct krb5_krbhst_data *kd,
     759             :              krb5_krbhst_info **host)
     760             : {
     761        3413 :     krb5_error_code ret;
     762             : 
     763       80905 :     if ((kd->flags & KD_HOSTNAMES) == 0) {
     764       80901 :         hostnames_get_hosts(context, kd, "kdc");
     765       80901 :         if(get_next(kd, host))
     766           0 :             return 0;
     767             :     }
     768             : 
     769       80905 :     if ((kd->flags & KD_PLUGIN) == 0) {
     770       80901 :         plugin_get_hosts(context, kd, locate_service_kdc);
     771       80901 :         kd->flags |= KD_PLUGIN;
     772       80901 :         if(get_next(kd, host))
     773           0 :             return 0;
     774             :     }
     775             : 
     776       80905 :     if((kd->flags & KD_CONFIG) == 0) {
     777       80901 :         config_get_hosts(context, kd, kd->config_param);
     778       80901 :         kd->flags |= KD_CONFIG;
     779       80901 :         if(get_next(kd, host))
     780       73344 :             return 0;
     781             :     }
     782             : 
     783        7561 :     if (kd->flags & KD_CONFIG_EXISTS) {
     784        7508 :         _krb5_debug(context, 1,
     785             :                     "Configuration exists for realm %s, wont go to DNS",
     786             :                     kd->realm);
     787        7508 :         return KRB5_KDC_UNREACH;
     788             :     }
     789             : 
     790          53 :     if(context->srv_lookup) {
     791          53 :         if(kd->sitename && (kd->flags & KD_SITE_SRV_TCP) == 0) {
     792           0 :             srv_get_hosts(context, kd, kd->sitename, "tcp", "kerberos");
     793           0 :             kd->flags |= KD_SITE_SRV_TCP;
     794           0 :             if(get_next(kd, host))
     795           0 :                 return 0;
     796             :         }
     797             : 
     798          53 :         if((kd->flags & KD_SRV_UDP) == 0 && (kd->flags & KD_LARGE_MSG) == 0) {
     799          42 :             srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
     800          42 :             kd->flags |= KD_SRV_UDP;
     801          42 :             if(get_next(kd, host))
     802           6 :                 return 0;
     803             :         }
     804             : 
     805          47 :         if((kd->flags & KD_SRV_TCP) == 0) {
     806          47 :             srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
     807          47 :             kd->flags |= KD_SRV_TCP;
     808          47 :             if(get_next(kd, host))
     809          11 :                 return 0;
     810             :         }
     811          36 :         if((kd->flags & KD_SRV_HTTP) == 0) {
     812          36 :             srv_get_hosts(context, kd, NULL, "http", kd->srv_label);
     813          36 :             kd->flags |= KD_SRV_HTTP;
     814          36 :             if(get_next(kd, host))
     815           0 :                 return 0;
     816             :         }
     817             :     }
     818             : 
     819          72 :     while((kd->flags & KD_FALLBACK) == 0) {
     820          36 :         ret = fallback_get_hosts(context, kd, "kerberos",
     821             :                                  kd->def_port,
     822             :                                  krbhst_get_default_proto(kd));
     823          36 :         if(ret)
     824           0 :             return ret;
     825          36 :         if(get_next(kd, host))
     826           0 :             return 0;
     827             :     }
     828             : 
     829          36 :     _krb5_debug(context, 0, "No KDC entries found for %s", kd->realm);
     830             : 
     831          36 :     return KRB5_KDC_UNREACH; /* XXX */
     832             : }
     833             : 
     834             : static krb5_error_code
     835           0 : admin_get_next(krb5_context context,
     836             :                struct krb5_krbhst_data *kd,
     837             :                krb5_krbhst_info **host)
     838             : {
     839           0 :     krb5_error_code ret;
     840             : 
     841           0 :     if ((kd->flags & KD_PLUGIN) == 0) {
     842           0 :         plugin_get_hosts(context, kd, locate_service_kadmin);
     843           0 :         kd->flags |= KD_PLUGIN;
     844           0 :         if(get_next(kd, host))
     845           0 :             return 0;
     846             :     }
     847             : 
     848           0 :     if((kd->flags & KD_CONFIG) == 0) {
     849           0 :         config_get_hosts(context, kd, kd->config_param);
     850           0 :         kd->flags |= KD_CONFIG;
     851           0 :         if(get_next(kd, host))
     852           0 :             return 0;
     853             :     }
     854             : 
     855           0 :     if (kd->flags & KD_CONFIG_EXISTS) {
     856           0 :         _krb5_debug(context, 1,
     857             :                     "Configuration exists for realm %s, wont go to DNS",
     858             :                     kd->realm);
     859           0 :         return KRB5_KDC_UNREACH;
     860             :     }
     861             : 
     862           0 :     if(context->srv_lookup) {
     863           0 :         if((kd->flags & KD_SRV_TCP) == 0) {
     864           0 :             srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
     865           0 :             kd->flags |= KD_SRV_TCP;
     866           0 :             if(get_next(kd, host))
     867           0 :                 return 0;
     868             :         }
     869             :     }
     870             : 
     871           0 :     if (krbhst_empty(kd)
     872           0 :         && (kd->flags & KD_FALLBACK) == 0) {
     873           0 :         ret = fallback_get_hosts(context, kd, "kerberos",
     874             :                                  kd->def_port,
     875             :                                  krbhst_get_default_proto(kd));
     876           0 :         if(ret)
     877           0 :             return ret;
     878           0 :         kd->flags |= KD_FALLBACK;
     879           0 :         if(get_next(kd, host))
     880           0 :             return 0;
     881             :     }
     882             : 
     883           0 :     _krb5_debug(context, 0, "No admin entries found for realm %s", kd->realm);
     884             : 
     885           0 :     return KRB5_KDC_UNREACH;    /* XXX */
     886             : }
     887             : 
     888             : static krb5_error_code
     889          29 : kpasswd_get_next(krb5_context context,
     890             :                  struct krb5_krbhst_data *kd,
     891             :                  krb5_krbhst_info **host)
     892             : {
     893           0 :     krb5_error_code ret;
     894             : 
     895          29 :     if ((kd->flags & KD_PLUGIN) == 0) {
     896          29 :         plugin_get_hosts(context, kd, locate_service_kpasswd);
     897          29 :         kd->flags |= KD_PLUGIN;
     898          29 :         if(get_next(kd, host))
     899           0 :             return 0;
     900             :     }
     901             : 
     902          29 :     if((kd->flags & KD_CONFIG) == 0) {
     903          29 :         config_get_hosts(context, kd, kd->config_param);
     904          29 :         kd->flags |= KD_CONFIG;
     905          29 :         if(get_next(kd, host))
     906           0 :             return 0;
     907             :     }
     908             : 
     909          29 :     if (kd->flags & KD_CONFIG_EXISTS) {
     910           0 :         _krb5_debug(context, 1,
     911             :                     "Configuration exists for realm %s, wont go to DNS",
     912             :                     kd->realm);
     913           0 :         return KRB5_KDC_UNREACH;
     914             :     }
     915             : 
     916          29 :     if(context->srv_lookup) {
     917          29 :         if((kd->flags & KD_SRV_UDP) == 0) {
     918          29 :             srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
     919          29 :             kd->flags |= KD_SRV_UDP;
     920          29 :             if(get_next(kd, host))
     921          29 :                 return 0;
     922             :         }
     923           0 :         if((kd->flags & KD_SRV_TCP) == 0) {
     924           0 :             srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
     925           0 :             kd->flags |= KD_SRV_TCP;
     926           0 :             if(get_next(kd, host))
     927           0 :                 return 0;
     928             :         }
     929             :     }
     930             : 
     931             :     /* no matches -> try admin */
     932             : 
     933           0 :     if (krbhst_empty(kd)) {
     934           0 :         kd->flags = 0;
     935           0 :         kd->port  = kd->def_port;
     936           0 :         kd->get_next = admin_get_next;
     937           0 :         ret = (*kd->get_next)(context, kd, host);
     938           0 :         if (ret == 0)
     939           0 :             (*host)->proto = krbhst_get_default_proto(kd);
     940           0 :         return ret;
     941             :     }
     942             : 
     943           0 :     _krb5_debug(context, 0, "No kpasswd entries found for realm %s", kd->realm);
     944             : 
     945           0 :     return KRB5_KDC_UNREACH;
     946             : }
     947             : 
     948             : static void KRB5_CALLCONV
     949       80930 : krbhost_dealloc(void *ptr)
     950             : {
     951       80930 :     struct krb5_krbhst_data *handle = (struct krb5_krbhst_data *)ptr;
     952        3413 :     krb5_krbhst_info *h, *next;
     953             : 
     954      155023 :     for (h = handle->hosts; h != NULL; h = next) {
     955       74093 :         next = h->next;
     956       74093 :         _krb5_free_krbhst_info(h);
     957             :     }
     958       80930 :     if (handle->hostname)
     959           0 :         free(handle->hostname);
     960       80930 :     if (handle->sitename)
     961           0 :         free(handle->sitename);
     962             : 
     963       80930 :     free(handle->realm);
     964       80930 : }
     965             : 
     966             : static struct krb5_krbhst_data*
     967       80930 : common_init(krb5_context context,
     968             :             const char *config_param,
     969             :             const char *srv_label,
     970             :             const char *service,
     971             :             const char *realm,
     972             :             int flags)
     973             : {
     974        3413 :     struct krb5_krbhst_data *kd;
     975             : 
     976       80930 :     if ((kd = heim_alloc(sizeof(*kd), "krbhst-context", krbhost_dealloc)) == NULL)
     977           0 :         return NULL;
     978             : 
     979       80930 :     if((kd->realm = strdup(realm)) == NULL) {
     980           0 :         heim_release(kd);
     981           0 :         return NULL;
     982             :     }
     983             : 
     984       80930 :     kd->config_param = config_param;
     985       80930 :     kd->srv_label = srv_label;
     986             : 
     987       80930 :     _krb5_debug(context, 2, "Trying to find service %s for realm %s flags %x",
     988             :                 service, realm, flags);
     989             : 
     990             :     /* For 'realms' without a . do not even think of going to DNS */
     991       80930 :     if (!strchr(realm, '.'))
     992       10164 :         kd->flags |= KD_CONFIG_EXISTS;
     993             : 
     994       80930 :     if (flags & KRB5_KRBHST_FLAGS_LARGE_MSG)
     995       48513 :         kd->flags |= KD_LARGE_MSG;
     996       80930 :     kd->end = kd->index = &kd->hosts;
     997       80930 :     return kd;
     998             : }
     999             : 
    1000             : /*
    1001             :  * initialize `handle' to look for hosts of type `type' in realm `realm'
    1002             :  */
    1003             : 
    1004             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1005          29 : krb5_krbhst_init(krb5_context context,
    1006             :                  const char *realm,
    1007             :                  unsigned int type,
    1008             :                  krb5_krbhst_handle *handle)
    1009             : {
    1010          29 :     return krb5_krbhst_init_flags(context, realm, type, 0, handle);
    1011             : }
    1012             : 
    1013             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1014       80930 : krb5_krbhst_init_flags(krb5_context context,
    1015             :                        const char *realm,
    1016             :                        unsigned int type,
    1017             :                        int flags,
    1018             :                        krb5_krbhst_handle *handle)
    1019             : {
    1020        3413 :     struct krb5_krbhst_data *kd;
    1021        3413 :     krb5_error_code (*next)(krb5_context, struct krb5_krbhst_data *,
    1022             :                             krb5_krbhst_info **);
    1023        3413 :     int def_port;
    1024        3413 :     const char *config_param;
    1025        3413 :     const char *srv_label;
    1026        3413 :     const char *service;
    1027             : 
    1028       80930 :     *handle = NULL;
    1029             : 
    1030       80930 :     switch(type) {
    1031       80901 :     case KRB5_KRBHST_KDC:
    1032       80901 :         next = kdc_get_next;
    1033       80901 :         def_port = ntohs(krb5_getportbyname(context, "kerberos", "udp", 88));
    1034       80901 :         config_param = "kdc";
    1035       80901 :         srv_label = "kerberos";
    1036       80901 :         service = "kdc";
    1037       80901 :         break;
    1038           0 :     case KRB5_KRBHST_ADMIN:
    1039           0 :         next = admin_get_next;
    1040           0 :         def_port = ntohs(krb5_getportbyname(context, "kerberos-adm",
    1041             :                                             "tcp", 749));
    1042           0 :         config_param = "admin_server";
    1043           0 :         srv_label = "kerberos-adm";
    1044           0 :         service = "admin";
    1045           0 :         break;
    1046           0 :     case KRB5_KRBHST_READONLY_ADMIN:
    1047           0 :         next = admin_get_next;
    1048           0 :         def_port = ntohs(krb5_getportbyname(context, "kerberos-adm",
    1049             :                                             "tcp", 749));
    1050           0 :         config_param = "readonly_admin_server";
    1051           0 :         srv_label = "kerberos-adm-readonly";
    1052           0 :         service = "admin";
    1053           0 :         break;
    1054          29 :     case KRB5_KRBHST_CHANGEPW:
    1055          29 :         next = kpasswd_get_next;
    1056          29 :         def_port = ntohs(krb5_getportbyname(context, "kpasswd", "udp",
    1057             :                                             KPASSWD_PORT));
    1058          29 :         config_param = "kpasswd_server";
    1059          29 :         srv_label = "kpasswd";
    1060          29 :         service = "change_password";
    1061          29 :         break;
    1062           0 :     case KRB5_KRBHST_TKTBRIDGEAP:
    1063           0 :         next = kdc_get_next;
    1064           0 :         def_port = ntohs(krb5_getportbyname(context, "kerberos", "tcp", 88));
    1065           0 :         config_param = "tktbridgeap";
    1066           0 :         srv_label = "kerberos-tkt-bridge";
    1067           0 :         service = "kdc";
    1068           0 :         break;
    1069           0 :     default:
    1070           0 :         krb5_set_error_message(context, ENOTTY,
    1071           0 :                                N_("unknown krbhst type (%u)", ""), type);
    1072           0 :         return ENOTTY;
    1073             :     }
    1074       80930 :     if((kd = common_init(context, config_param, srv_label, service, realm,
    1075             :                          flags)) == NULL)
    1076           0 :         return ENOMEM;
    1077       80930 :     kd->get_next = next;
    1078       80930 :     kd->def_port = def_port;
    1079       80930 :     *handle = kd;
    1080       80930 :     return 0;
    1081             : }
    1082             : 
    1083             : /*
    1084             :  * return the next host information from `handle' in `host'
    1085             :  */
    1086             : 
    1087             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1088       80934 : krb5_krbhst_next(krb5_context context,
    1089             :                  krb5_krbhst_handle handle,
    1090             :                  krb5_krbhst_info **host)
    1091             : {
    1092       80934 :     if(get_next(handle, host))
    1093           0 :         return 0;
    1094             : 
    1095       80934 :     return (*handle->get_next)(context, handle, host);
    1096             : }
    1097             : 
    1098             : /*
    1099             :  * return the next host information from `handle' as a host name
    1100             :  * in `hostname' (or length `hostlen)
    1101             :  */
    1102             : 
    1103             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1104           0 : krb5_krbhst_next_as_string(krb5_context context,
    1105             :                            krb5_krbhst_handle handle,
    1106             :                            char *hostname,
    1107             :                            size_t hostlen)
    1108             : {
    1109           0 :     krb5_error_code ret;
    1110           0 :     krb5_krbhst_info *host;
    1111           0 :     ret = krb5_krbhst_next(context, handle, &host);
    1112           0 :     if(ret)
    1113           0 :         return ret;
    1114           0 :     return krb5_krbhst_format_string(context, host, hostname, hostlen);
    1115             : }
    1116             : 
    1117             : /*
    1118             :  *
    1119             :  */
    1120             : 
    1121             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1122           0 : krb5_krbhst_set_hostname(krb5_context context,
    1123             :                          krb5_krbhst_handle handle,
    1124             :                          const char *hostname)
    1125             : {
    1126           0 :     if (handle->hostname)
    1127           0 :         free(handle->hostname);
    1128           0 :     handle->hostname = strdup(hostname);
    1129           0 :     if (handle->hostname == NULL)
    1130           0 :         return ENOMEM;
    1131           0 :     return 0;
    1132             : }
    1133             : 
    1134             : krb5_error_code KRB5_LIB_FUNCTION
    1135           0 : krb5_krbhst_set_sitename(krb5_context context,
    1136             :                          krb5_krbhst_handle handle,
    1137             :                          const char *sitename)
    1138             : {
    1139           0 :     if (handle->sitename)
    1140           0 :         free(handle->sitename);
    1141           0 :     handle->sitename = strdup(sitename);
    1142           0 :     if (handle->sitename == NULL)
    1143           0 :         return krb5_enomem(context);
    1144           0 :     return 0;
    1145             : }
    1146             : 
    1147             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    1148           0 : krb5_krbhst_reset(krb5_context context, krb5_krbhst_handle handle)
    1149             : {
    1150           0 :     handle->index = &handle->hosts;
    1151           0 : }
    1152             : 
    1153             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    1154       80930 : krb5_krbhst_free(krb5_context context, krb5_krbhst_handle handle)
    1155             : {
    1156       80930 :     heim_release(handle);
    1157       80930 : }
    1158             : 
    1159             : #ifndef HEIMDAL_SMALLER
    1160             : 
    1161             : /* backwards compatibility ahead */
    1162             : 
    1163             : static krb5_error_code
    1164           0 : gethostlist(krb5_context context, const char *realm,
    1165             :             unsigned int type, char ***hostlist)
    1166             : {
    1167           0 :     krb5_error_code ret;
    1168           0 :     int nhost = 0;
    1169           0 :     krb5_krbhst_handle handle;
    1170           0 :     char host[MAXHOSTNAMELEN];
    1171           0 :     krb5_krbhst_info *hostinfo;
    1172             : 
    1173           0 :     ret = krb5_krbhst_init(context, realm, type, &handle);
    1174           0 :     if (ret)
    1175           0 :         return ret;
    1176             : 
    1177           0 :     while (krb5_krbhst_next(context, handle, &hostinfo) == 0)
    1178           0 :         nhost++;
    1179           0 :     if (nhost == 0) {
    1180           0 :         krb5_set_error_message(context, KRB5_KDC_UNREACH,
    1181           0 :                                N_("No KDC found for realm %s", ""), realm);
    1182           0 :         krb5_krbhst_free(context, handle);
    1183           0 :         return KRB5_KDC_UNREACH;
    1184             :     }
    1185           0 :     *hostlist = calloc(nhost + 1, sizeof(**hostlist));
    1186           0 :     if (*hostlist == NULL) {
    1187           0 :         krb5_krbhst_free(context, handle);
    1188           0 :         return krb5_enomem(context);
    1189             :     }
    1190             : 
    1191           0 :     krb5_krbhst_reset(context, handle);
    1192           0 :     nhost = 0;
    1193           0 :     while (krb5_krbhst_next_as_string(context, handle,
    1194           0 :                                       host, sizeof(host)) == 0) {
    1195           0 :         if (((*hostlist)[nhost++] = strdup(host)) == NULL) {
    1196           0 :             krb5_free_krbhst(context, *hostlist);
    1197           0 :             krb5_krbhst_free(context, handle);
    1198           0 :             return krb5_enomem(context);
    1199             :         }
    1200             :     }
    1201           0 :     (*hostlist)[nhost] = NULL;
    1202           0 :     krb5_krbhst_free(context, handle);
    1203           0 :     return 0;
    1204             : }
    1205             : 
    1206             : /*
    1207             :  * Return a malloced list of kadmin-hosts for `realm' in `hostlist'
    1208             :  */
    1209             : 
    1210             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1211           0 : krb5_get_krb_admin_hst(krb5_context context,
    1212             :                        const krb5_realm *realm,
    1213             :                        char ***hostlist)
    1214             : {
    1215           0 :     return gethostlist(context, *realm, KRB5_KRBHST_ADMIN, hostlist);
    1216             : }
    1217             : 
    1218             : /*
    1219             :  * Return a malloced list of writable kadmin-hosts for `realm' in `hostlist'
    1220             :  */
    1221             : 
    1222             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1223           0 : krb5_get_krb_readonly_admin_hst(krb5_context context,
    1224             :                                 const krb5_realm *realm,
    1225             :                                 char ***hostlist)
    1226             : {
    1227           0 :     return gethostlist(context, *realm, KRB5_KRBHST_READONLY_ADMIN, hostlist);
    1228             : }
    1229             : 
    1230             : /*
    1231             :  * return an malloced list of changepw-hosts for `realm' in `hostlist'
    1232             :  */
    1233             : 
    1234             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1235           0 : krb5_get_krb_changepw_hst (krb5_context context,
    1236             :                            const krb5_realm *realm,
    1237             :                            char ***hostlist)
    1238             : {
    1239           0 :     return gethostlist(context, *realm, KRB5_KRBHST_CHANGEPW, hostlist);
    1240             : }
    1241             : 
    1242             : /*
    1243             :  * return an malloced list of 524-hosts for `realm' in `hostlist'
    1244             :  */
    1245             : 
    1246             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1247           0 : krb5_get_krb524hst (krb5_context context,
    1248             :                     const krb5_realm *realm,
    1249             :                     char ***hostlist)
    1250             : {
    1251           0 :     return gethostlist(context, *realm, KRB5_KRBHST_KRB524, hostlist);
    1252             : }
    1253             : 
    1254             : /*
    1255             :  * return an malloced list of KDC's for `realm' in `hostlist'
    1256             :  */
    1257             : 
    1258             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1259           0 : krb5_get_krbhst (krb5_context context,
    1260             :                  const krb5_realm *realm,
    1261             :                  char ***hostlist)
    1262             : {
    1263           0 :     return gethostlist(context, *realm, KRB5_KRBHST_KDC, hostlist);
    1264             : }
    1265             : 
    1266             : /*
    1267             :  * free all the memory allocated in `hostlist'
    1268             :  */
    1269             : 
    1270             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1271           0 : krb5_free_krbhst (krb5_context context,
    1272             :                   char **hostlist)
    1273             : {
    1274           0 :     char **p;
    1275             : 
    1276           0 :     for (p = hostlist; *p; ++p)
    1277           0 :         free (*p);
    1278           0 :     free (hostlist);
    1279           0 :     return 0;
    1280             : }
    1281             : 
    1282             : #endif /* HEIMDAL_SMALLER */

Generated by: LCOV version 1.14