LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - krbhst.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 301 640 47.0 %
Date: 2024-05-31 13:13:24 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         170 : string_to_proto(const char *string)
      42             : {
      43         170 :     if(strcasecmp(string, "udp") == 0)
      44         101 :         return KRB5_KRBHST_UDP;
      45          69 :     else if(strcasecmp(string, "tcp") == 0)
      46          57 :         return KRB5_KRBHST_TCP;
      47          12 :     else if(strcasecmp(string, "http") == 0)
      48          12 :         return KRB5_KRBHST_HTTP;
      49           0 :     return -1;
      50             : }
      51             : 
      52             : static int
      53         134 : is_invalid_tld_srv_target(const char *target)
      54             : {
      55         134 :     return (strncmp("your-dns-needs-immediate-attention.",
      56             :                     target, 35) == 0
      57         134 :             && 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         170 : 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         170 :     *res = NULL;
      79         170 :     *count = 0;
      80             : 
      81         170 :     proto_num = string_to_proto(proto);
      82         170 :     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         170 :     if(proto_num == KRB5_KRBHST_HTTP)
      90          12 :         def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
      91         158 :     else if(port == 0)
      92         158 :         def_port = ntohs(krb5_getportbyname (context, service, proto, 88));
      93             :     else
      94           0 :         def_port = port;
      95             : 
      96         170 :     if (sitename)
      97           0 :         snprintf(domain, sizeof(domain), "_%s._%s.%s._sites.%s.",
      98             :                  service, proto, sitename, realm);
      99             :     else
     100         170 :         snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);
     101             : 
     102         170 :     r = rk_dns_lookup(domain, dns_type);
     103         170 :     if(r == NULL) {
     104           0 :         _krb5_debug(context, 0,
     105             :                     "DNS lookup failed domain: %s", domain);
     106           0 :         return KRB5_KDC_UNREACH;
     107             :     }
     108             : 
     109         438 :     for(num_srv = 0, rr = r->head; rr; rr = rr->next)
     110         268 :         if(rr->type == rk_ns_t_srv) {
     111         134 :             if (num_srv >= INT_MAX) {
     112           0 :                 rk_dns_free_data(r);
     113           0 :                 return KRB5_KDC_UNREACH;
     114             :             }
     115         134 :             if (num_srv >= SIZE_MAX / sizeof(**res)) {
     116           0 :                 rk_dns_free_data(r);
     117           0 :                 return KRB5_KDC_UNREACH;
     118             :             }
     119         134 :             num_srv++;
     120             :         }
     121             : 
     122         170 :     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         134 :     *res = malloc(num_srv * sizeof(**res));
     130         134 :     if(*res == NULL) {
     131           0 :         rk_dns_free_data(r);
     132           0 :         return krb5_enomem(context);
     133             :     }
     134             : 
     135         134 :     rk_dns_srv_order(r);
     136             : 
     137         402 :     for(num_srv = 0, rr = r->head; rr; rr = rr->next)
     138         268 :         if(rr->type == rk_ns_t_srv) {
     139         134 :             krb5_krbhst_info *hi = NULL;
     140           0 :             size_t len;
     141         134 :             int invalid_tld = 1;
     142             : 
     143             :             /* Test for top-level domain controlled interruptions */
     144         134 :             if (!is_invalid_tld_srv_target(rr->u.srv->target)) {
     145         134 :                 invalid_tld = 0;
     146         134 :                 len = strlen(rr->u.srv->target);
     147         134 :                 hi = calloc(1, sizeof(*hi) + len);
     148             :             }
     149         134 :             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         134 :             (*res)[num_srv++] = hi;
     166             : 
     167         134 :             hi->proto = proto_num;
     168             : 
     169         134 :             hi->def_port = def_port;
     170         134 :             if (port != 0)
     171           0 :                 hi->port = port;
     172             :             else
     173         134 :                 hi->port = rr->u.srv->port;
     174             : 
     175         134 :             strlcpy(hi->hostname, rr->u.srv->target, len + 1);
     176             :         }
     177             : 
     178         134 :     *count = num_srv;
     179             : 
     180         134 :     rk_dns_free_data(r);
     181         134 :     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       73959 : krbhst_get_default_proto(struct krb5_krbhst_data *kd)
     226             : {
     227       73959 :     if (kd->flags & KD_LARGE_MSG)
     228       49018 :         return KRB5_KRBHST_TCP;
     229       23757 :     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       73947 : parse_hostspec(krb5_context context, struct krb5_krbhst_data *kd,
     255             :                const char *spec, int def_port, int port)
     256             : {
     257       73947 :     const char *p = spec, *q;
     258        3448 :     struct krb5_krbhst_info *hi;
     259             : 
     260       73947 :     hi = calloc(1, sizeof(*hi) + strlen(spec));
     261       73947 :     if(hi == NULL)
     262           0 :         return NULL;
     263             : 
     264       73947 :     hi->proto = krbhst_get_default_proto(kd);
     265             : 
     266       73947 :     if(strncmp(p, "http://", 7) == 0){
     267           0 :         hi->proto = KRB5_KRBHST_HTTP;
     268           0 :         p += 7;
     269       73947 :     } 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       73947 :     }else if(strncmp(p, "tcp/", 4) == 0){
     274           0 :         hi->proto = KRB5_KRBHST_TCP;
     275           0 :         p += 4;
     276       73947 :     } else if(strncmp(p, "udp/", 4) == 0) {
     277           0 :         hi->proto = KRB5_KRBHST_UDP;
     278           0 :         p += 4;
     279             :     }
     280             : 
     281       73947 :     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         547 :         memcpy(hi->hostname, &p[1], q - p - 1);
     285         547 :         hi->hostname[q - p - 1] = '\0';
     286         547 :         p = q + 1;
     287             :         /* get trailing : */
     288         547 :         if (p[0] == ':')
     289         547 :             p++;
     290       73400 :     } 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       73947 :     hi->hostname[strcspn(hi->hostname, "/")] = '\0';
     297       73947 :     strlwr(hi->hostname);
     298             : 
     299       73947 :     hi->port = hi->def_port = def_port;
     300       73947 :     if(p != NULL && p[0]) {
     301        3448 :         char *end;
     302       73121 :         hi->port = strtol(p, &end, 0);
     303       73121 :         if(end == p) {
     304           0 :             free(hi);
     305           0 :             return NULL;
     306             :         }
     307             :     }
     308       73947 :     if (port)
     309           0 :         hi->port = port;
     310       70499 :     return hi;
     311             : }
     312             : 
     313             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     314       74081 : _krb5_free_krbhst_info(krb5_krbhst_info *hi)
     315             : {
     316       74081 :     if (hi->ai != NULL)
     317       73404 :         freeaddrinfo(hi->ai);
     318       74081 :     free(hi);
     319       74081 : }
     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       74081 : append_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host)
     345             : {
     346        3448 :     struct krb5_krbhst_info *h;
     347             : 
     348       74671 :     for(h = kd->hosts; h; h = h->next)
     349         677 :         if(h->proto == host->proto &&
     350         677 :            h->port == host->port &&
     351         677 :            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       73994 :     if (kd->end)
     361       73994 :         *kd->end = host;
     362       73994 :     kd->end = &host->next;
     363             : }
     364             : 
     365             : static krb5_error_code
     366       73947 : append_host_string(krb5_context context, struct krb5_krbhst_data *kd,
     367             :                    const char *host, int def_port, int port)
     368             : {
     369        3448 :     struct krb5_krbhst_info *hi;
     370             : 
     371       73947 :     hi = parse_hostspec(context, kd, host, def_port, port);
     372       73947 :     if(hi == NULL)
     373           0 :         return krb5_enomem(context);
     374             : 
     375       73947 :     append_host_hostinfo(kd, hi);
     376       73947 :     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       73416 : make_hints(struct addrinfo *hints, int proto)
     405             : {
     406       73416 :     memset(hints, 0, sizeof(*hints));
     407       73416 :     hints->ai_family = AF_UNSPEC;
     408       73416 :     switch(proto) {
     409       24752 :     case KRB5_KRBHST_UDP :
     410       24752 :         hints->ai_socktype = SOCK_DGRAM;
     411       24752 :         break;
     412       48664 :     case KRB5_KRBHST_HTTP :
     413             :     case KRB5_KRBHST_TCP :
     414       48664 :         hints->ai_socktype = SOCK_STREAM;
     415       48664 :         break;
     416             :     }
     417       73416 : }
     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       73404 : krb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host,
     431             :                          struct addrinfo **ai)
     432             : {
     433       73404 :     int ret = 0;
     434             : 
     435       73404 :     if (host->ai == NULL) {
     436        3448 :         struct addrinfo hints;
     437        3448 :         char portstr[NI_MAXSERV];
     438             : 
     439       73404 :         snprintf (portstr, sizeof(portstr), "%d", host->port);
     440       73404 :         make_hints(&hints, host->proto);
     441             : 
     442       73404 :         if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
     443             :                 NULL)) {
     444           0 :             hints.ai_flags &= ~AI_CANONNAME;
     445           0 :             hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV;
     446             :         }
     447       73404 :         ret = getaddrinfo(host->hostname, portstr, &hints, &host->ai);
     448       73404 :         if (ret) {
     449           0 :             ret = krb5_eai_to_heim_errno(ret, errno);
     450           0 :             goto out;
     451             :         }
     452             :     }
     453           0 :  out:
     454       73404 :     *ai = host->ai;
     455       73404 :     return ret;
     456             : }
     457             : 
     458             : static krb5_boolean
     459      298577 : get_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host)
     460             : {
     461      315817 :     struct krb5_krbhst_info *hi = kd ? *kd->index : NULL;
     462      288233 :     if(hi != NULL) {
     463       73404 :         *host = hi;
     464       73404 :         kd->index = &(*kd->index)->next;
     465       73404 :         return TRUE;
     466             :     }
     467      214829 :     return FALSE;
     468             : }
     469             : 
     470             : static void
     471         170 : srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
     472             :               const char *sitename, const char *proto, const char *service)
     473             : {
     474           0 :     krb5_error_code ret;
     475           0 :     krb5_krbhst_info **res;
     476           0 :     int count, i;
     477             : 
     478         170 :     if (krb5_realm_is_lkdc(kd->realm))
     479          36 :         return;
     480             : 
     481         170 :     ret = srv_find_realm(context, &res, &count, kd->realm, "SRV",
     482             :                          sitename, proto, service, kd->port);
     483         170 :     _krb5_debug(context, 2, "searching DNS for realm %s %s.%s -> %d",
     484             :                 kd->realm, proto, service, ret);
     485         170 :     if (ret)
     486          36 :         return;
     487         268 :     for(i = 0; i < count; i++)
     488         134 :         append_host_hostinfo(kd, res[i]);
     489         134 :     free(res);
     490             : }
     491             : 
     492             : /*
     493             :  * read the configuration for `conf_string', defaulting to kd->def_port and
     494             :  * forcing it to `kd->port' if kd->port != 0
     495             :  */
     496             : 
     497             : static void
     498       74605 : config_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
     499             :                  const char *conf_string)
     500             : {
     501        3448 :     int i;
     502        3448 :     char **hostlist;
     503       74605 :     hostlist = krb5_config_get_strings(context, NULL,
     504             :                                        "realms", kd->realm, conf_string, NULL);
     505             : 
     506       74605 :     _krb5_debug(context, 2, "configuration file for realm %s%s found",
     507             :                 kd->realm, hostlist ? "" : " not");
     508             : 
     509       74605 :     if(hostlist == NULL)
     510        1335 :         return;
     511       73270 :     kd->flags |= KD_CONFIG_EXISTS;
     512      147217 :     for(i = 0; hostlist && hostlist[i] != NULL; i++)
     513       73947 :         append_host_string(context, kd, hostlist[i], kd->def_port, kd->port);
     514             : 
     515       73270 :     krb5_config_free_strings(hostlist);
     516             : }
     517             : 
     518             : /*
     519             :  * as a fallback, look for `serv_string.kd->realm' (typically
     520             :  * kerberos.REALM, kerberos-1.REALM, ...
     521             :  * `port' is the default port for the service, and `proto' the
     522             :  * protocol
     523             :  */
     524             : 
     525             : static krb5_error_code
     526          12 : fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
     527             :                    const char *serv_string, int port, int proto)
     528             : {
     529          12 :     char *host = NULL;
     530           0 :     int ret;
     531           0 :     struct addrinfo *ai;
     532           0 :     struct addrinfo hints;
     533           0 :     char portstr[NI_MAXSERV];
     534             : 
     535          12 :     ret = krb5_config_get_bool_default(context, NULL, KRB5_FALLBACK_DEFAULT,
     536             :                                        "libdefaults", "use_fallback", NULL);
     537          12 :     if (!ret) {
     538           0 :         kd->flags |= KD_FALLBACK;
     539           0 :         return 0;
     540             :     }
     541             : 
     542          12 :     _krb5_debug(context, 2, "fallback lookup %d for realm %s (service %s)",
     543             :                 kd->fallback_count, kd->realm, serv_string);
     544             : 
     545             :     /*
     546             :      * Don't try forever in case the DNS server keep returning us
     547             :      * entries (like wildcard entries or the .nu TLD)
     548             :      *
     549             :      * Also don't try LKDC realms since fallback wont work on them at all.
     550             :      */
     551          12 :     if(kd->fallback_count >= 5 || krb5_realm_is_lkdc(kd->realm)) {
     552           0 :         kd->flags |= KD_FALLBACK;
     553           0 :         return 0;
     554             :     }
     555             : 
     556          12 :     if(kd->fallback_count == 0)
     557          12 :         ret = asprintf(&host, "%s.%s.", serv_string, kd->realm);
     558             :     else
     559           0 :         ret = asprintf(&host, "%s-%d.%s.",
     560             :                        serv_string, kd->fallback_count, kd->realm);
     561             : 
     562          12 :     if (ret < 0 || host == NULL)
     563           0 :         return krb5_enomem(context);
     564             : 
     565          12 :     make_hints(&hints, proto);
     566          12 :     snprintf(portstr, sizeof(portstr), "%d", port);
     567          12 :     if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
     568             :             NULL)) {
     569           0 :         hints.ai_flags &= ~AI_CANONNAME;
     570           0 :         hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV;
     571             :     }
     572          12 :     ret = getaddrinfo(host, portstr, &hints, &ai);
     573          12 :     if (ret) {
     574             :         /* no more hosts, so we're done here */
     575          12 :         free(host);
     576          12 :         kd->flags |= KD_FALLBACK;
     577             :     } else {
     578           0 :         struct krb5_krbhst_info *hi;
     579           0 :         size_t hostlen;
     580             : 
     581             :         /* Check for ICANN gTLD Name Collision address (127.0.53.53) */
     582           0 :         if (ai->ai_family == AF_INET) {
     583           0 :             struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
     584           0 :             if (sin->sin_addr.s_addr == htonl(0x7f003535)) {
     585           0 :                 krb5_warnx(context,
     586             :                            "Fallback lookup failed: "
     587             :                            "Realm %s needs immediate attention "
     588             :                            "see https://icann.org/namecollision",
     589             :                            kd->realm);
     590           0 :                 free(host);
     591           0 :                 freeaddrinfo(ai);
     592           0 :                 return KRB5_KDC_UNREACH;
     593             :             }
     594             :         }
     595             : 
     596           0 :         hostlen = strlen(host);
     597           0 :         hi = calloc(1, sizeof(*hi) + hostlen);
     598           0 :         if(hi == NULL) {
     599           0 :             free(host);
     600           0 :             freeaddrinfo(ai);
     601           0 :             return krb5_enomem(context);
     602             :         }
     603             : 
     604           0 :         hi->proto = proto;
     605           0 :         hi->port  = hi->def_port = port;
     606           0 :         hi->ai    = ai;
     607           0 :         memmove(hi->hostname, host, hostlen);
     608           0 :         hi->hostname[hostlen] = '\0';
     609           0 :         free(host);
     610           0 :         append_host_hostinfo(kd, hi);
     611           0 :         kd->fallback_count++;
     612             :     }
     613          12 :     return 0;
     614             : }
     615             : 
     616             : /*
     617             :  * Fetch hosts from plugin
     618             :  */
     619             : 
     620             : static krb5_error_code
     621           0 : add_plugin_host(struct krb5_krbhst_data *kd,
     622             :                 const char *host,
     623             :                 const char *port,
     624             :                 int portnum,
     625             :                 int proto)
     626             : {
     627           0 :     struct krb5_krbhst_info *hi;
     628           0 :     struct addrinfo hints, *ai;
     629           0 :     size_t hostlen;
     630           0 :     int ret;
     631             : 
     632           0 :     make_hints(&hints, proto);
     633           0 :     ret = getaddrinfo(host, port, &hints, &ai);
     634           0 :     if (ret)
     635           0 :         return 0;
     636             : 
     637           0 :     hostlen = strlen(host);
     638             : 
     639           0 :     hi = calloc(1, sizeof(*hi) + hostlen);
     640           0 :     if (hi == NULL) {
     641           0 :         freeaddrinfo(ai);
     642           0 :         return ENOMEM;
     643             :     }
     644             : 
     645           0 :     hi->proto = proto;
     646           0 :     hi->port  = hi->def_port = portnum;
     647           0 :     hi->ai    = ai;
     648           0 :     memmove(hi->hostname, host, hostlen);
     649           0 :     hi->hostname[hostlen] = '\0';
     650           0 :     append_host_hostinfo(kd, hi);
     651             : 
     652           0 :     return 0;
     653             : }
     654             : 
     655             : static krb5_error_code
     656           0 : add_locate(void *ctx, int type, struct sockaddr *addr)
     657             : {
     658           0 :     struct krb5_krbhst_data *kd = ctx;
     659           0 :     char host[NI_MAXHOST], port[NI_MAXSERV];
     660           0 :     socklen_t socklen;
     661           0 :     krb5_error_code ret;
     662           0 :     int proto, portnum;
     663             : 
     664           0 :     socklen = socket_sockaddr_size(addr);
     665           0 :     portnum = socket_get_port(addr);
     666             : 
     667           0 :     ret = getnameinfo(addr, socklen, host, sizeof(host), port, sizeof(port),
     668             :                       NI_NUMERICHOST|NI_NUMERICSERV|NI_NUMERICSCOPE);
     669           0 :     if (ret != 0)
     670           0 :         return 0;
     671             : 
     672           0 :     if (kd->port)
     673           0 :         snprintf(port, sizeof(port), "%d", kd->port);
     674           0 :     else if (atoi(port) == 0)
     675           0 :         snprintf(port, sizeof(port), "%d", krbhst_get_default_port(kd));
     676             : 
     677           0 :     proto = krbhst_get_default_proto(kd);
     678             : 
     679           0 :     ret = add_plugin_host(kd, host, port, portnum, proto);
     680           0 :     if (ret)
     681           0 :         return ret;
     682             : 
     683             :     /*
     684             :      * This is really kind of broken and should be solved a different
     685             :      * way, some sites block UDP, and we don't, in the general case,
     686             :      * fall back to TCP, that should also be done. But since that
     687             :      * should require us to invert the whole "find kdc" stack, let put
     688             :      * this in for now. 
     689             :      */
     690             : 
     691           0 :     if (proto == KRB5_KRBHST_UDP) {
     692           0 :         ret = add_plugin_host(kd, host, port, portnum, KRB5_KRBHST_TCP);
     693           0 :         if (ret)
     694           0 :             return ret;
     695             :     }
     696             : 
     697           0 :     return 0;
     698             : }
     699             : 
     700             : struct plctx {
     701             :     enum locate_service_type type;
     702             :     struct krb5_krbhst_data *kd;
     703             :     unsigned long flags;
     704             : };
     705             : 
     706             : static KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     707           0 : plcallback(krb5_context context,
     708             :            const void *plug, void *plugctx, void *userctx)
     709             : {
     710           0 :     const krb5plugin_service_locate_ftable *locate = plug;
     711           0 :     struct plctx *plctx = userctx;
     712             :     
     713           0 :     if (locate->minor_version >= KRB5_PLUGIN_LOCATE_VERSION_2)
     714           0 :         return locate->lookup(plugctx, plctx->flags, plctx->type, plctx->kd->realm, 0, 0, add_locate, plctx->kd);
     715             :     
     716           0 :     if (plctx->flags & KRB5_PLF_ALLOW_HOMEDIR)
     717           0 :         return locate->old_lookup(plugctx, plctx->type, plctx->kd->realm, 0, 0, add_locate, plctx->kd);
     718             :     
     719           0 :     return KRB5_PLUGIN_NO_HANDLE;
     720             : }
     721             : 
     722             : static const char *const locate_plugin_deps[] = { "krb5", NULL };
     723             : 
     724             : static const struct heim_plugin_data
     725             : locate_plugin_data = {
     726             :     "krb5",
     727             :     KRB5_PLUGIN_LOCATE,
     728             :     KRB5_PLUGIN_LOCATE_VERSION_0,
     729             :     locate_plugin_deps,
     730             :     krb5_get_instance
     731             : };
     732             : 
     733             : static void
     734       74605 : plugin_get_hosts(krb5_context context,
     735             :                  struct krb5_krbhst_data *kd,
     736             :                  enum locate_service_type type)
     737             : {
     738       74605 :     struct plctx ctx = { type, kd, 0 };
     739             : 
     740             :     /*
     741             :      * XXX Need a way to pass this through -- unsure if any of this is
     742             :      * useful without DNS, though.
     743             :      */
     744       74605 :     if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", NULL))
     745           0 :         return;
     746             : 
     747       74605 :     if (_krb5_homedir_access(context))
     748       74605 :         ctx.flags |= KRB5_PLF_ALLOW_HOMEDIR;
     749             : 
     750       74605 :     _krb5_plugin_run_f(context, &locate_plugin_data,
     751             :                        0, &ctx, plcallback);
     752             : }
     753             : 
     754             : /*
     755             :  *
     756             :  */
     757             : 
     758             : static void
     759       74576 : hostnames_get_hosts(krb5_context context,
     760             :                     struct krb5_krbhst_data *kd,
     761             :                     const char *type)
     762             : {
     763       74576 :     kd->flags |= KD_HOSTNAMES;
     764       74576 :     if (kd->hostname)
     765           0 :         append_host_string(context, kd, kd->hostname, kd->def_port, kd->port);
     766       74576 : }
     767             : 
     768             : 
     769             : /*
     770             :  *
     771             :  */
     772             : 
     773             : static krb5_error_code
     774       74580 : kdc_get_next(krb5_context context,
     775             :              struct krb5_krbhst_data *kd,
     776             :              krb5_krbhst_info **host)
     777             : {
     778        3448 :     krb5_error_code ret;
     779             : 
     780       74580 :     if ((kd->flags & KD_HOSTNAMES) == 0) {
     781       74576 :         hostnames_get_hosts(context, kd, "kdc");
     782       74576 :         if(get_next(kd, host))
     783           0 :             return 0;
     784             :     }
     785             : 
     786       74580 :     if ((kd->flags & KD_PLUGIN) == 0) {
     787       74576 :         plugin_get_hosts(context, kd, locate_service_kdc);
     788       74576 :         kd->flags |= KD_PLUGIN;
     789       74576 :         if(get_next(kd, host))
     790           0 :             return 0;
     791             :     }
     792             : 
     793       74580 :     if((kd->flags & KD_CONFIG) == 0) {
     794       74576 :         config_get_hosts(context, kd, kd->config_param);
     795       74576 :         kd->flags |= KD_CONFIG;
     796       74576 :         if(get_next(kd, host))
     797       73270 :             return 0;
     798             :     }
     799             : 
     800        1310 :     if (kd->flags & KD_CONFIG_EXISTS) {
     801        1193 :         _krb5_debug(context, 1,
     802             :                     "Configuration exists for realm %s, wont go to DNS",
     803             :                     kd->realm);
     804        1193 :         return KRB5_KDC_UNREACH;
     805             :     }
     806             : 
     807         117 :     if (!krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
     808         117 :             NULL) &&
     809         117 :         context->srv_lookup) {
     810         117 :         if(kd->sitename && (kd->flags & KD_SITE_SRV_TCP) == 0) {
     811           0 :             srv_get_hosts(context, kd, kd->sitename, "tcp", "kerberos");
     812           0 :             kd->flags |= KD_SITE_SRV_TCP;
     813           0 :             if(get_next(kd, host))
     814           0 :                 return 0;
     815             :         }
     816             : 
     817         117 :         if((kd->flags & KD_SRV_UDP) == 0 && (kd->flags & KD_LARGE_MSG) == 0) {
     818          72 :             srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
     819          72 :             kd->flags |= KD_SRV_UDP;
     820          72 :             if(get_next(kd, host))
     821          60 :                 return 0;
     822             :         }
     823             : 
     824          57 :         if((kd->flags & KD_SRV_TCP) == 0) {
     825          57 :             srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
     826          57 :             kd->flags |= KD_SRV_TCP;
     827          57 :             if(get_next(kd, host))
     828          45 :                 return 0;
     829             :         }
     830          12 :         if((kd->flags & KD_SRV_HTTP) == 0) {
     831          12 :             srv_get_hosts(context, kd, NULL, "http", kd->srv_label);
     832          12 :             kd->flags |= KD_SRV_HTTP;
     833          12 :             if(get_next(kd, host))
     834           0 :                 return 0;
     835             :         }
     836             :     }
     837             : 
     838          24 :     while((kd->flags & KD_FALLBACK) == 0) {
     839          12 :         ret = fallback_get_hosts(context, kd, "kerberos",
     840             :                                  kd->def_port,
     841             :                                  krbhst_get_default_proto(kd));
     842          12 :         if(ret)
     843           0 :             return ret;
     844          12 :         if(get_next(kd, host))
     845           0 :             return 0;
     846             :     }
     847             : 
     848          12 :     _krb5_debug(context, 0, "No KDC entries found for %s", kd->realm);
     849             : 
     850          12 :     return KRB5_KDC_UNREACH; /* XXX */
     851             : }
     852             : 
     853             : static krb5_error_code
     854           0 : admin_get_next(krb5_context context,
     855             :                struct krb5_krbhst_data *kd,
     856             :                krb5_krbhst_info **host)
     857             : {
     858           0 :     krb5_error_code ret;
     859             : 
     860           0 :     if ((kd->flags & KD_PLUGIN) == 0) {
     861           0 :         plugin_get_hosts(context, kd, locate_service_kadmin);
     862           0 :         kd->flags |= KD_PLUGIN;
     863           0 :         if(get_next(kd, host))
     864           0 :             return 0;
     865             :     }
     866             : 
     867           0 :     if((kd->flags & KD_CONFIG) == 0) {
     868           0 :         config_get_hosts(context, kd, kd->config_param);
     869           0 :         kd->flags |= KD_CONFIG;
     870           0 :         if(get_next(kd, host))
     871           0 :             return 0;
     872             :     }
     873             : 
     874           0 :     if (kd->flags & KD_CONFIG_EXISTS) {
     875           0 :         _krb5_debug(context, 1,
     876             :                     "Configuration exists for realm %s, wont go to DNS",
     877             :                     kd->realm);
     878           0 :         return KRB5_KDC_UNREACH;
     879             :     }
     880             : 
     881           0 :     if (!krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
     882           0 :             NULL) &&
     883           0 :         context->srv_lookup) {
     884           0 :         if((kd->flags & KD_SRV_TCP) == 0) {
     885           0 :             srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
     886           0 :             kd->flags |= KD_SRV_TCP;
     887           0 :             if(get_next(kd, host))
     888           0 :                 return 0;
     889             :         }
     890             :     }
     891             : 
     892           0 :     if (krbhst_empty(kd)
     893           0 :         && (kd->flags & KD_FALLBACK) == 0) {
     894           0 :         ret = fallback_get_hosts(context, kd, "kerberos",
     895             :                                  kd->def_port,
     896             :                                  krbhst_get_default_proto(kd));
     897           0 :         if(ret)
     898           0 :             return ret;
     899           0 :         kd->flags |= KD_FALLBACK;
     900           0 :         if(get_next(kd, host))
     901           0 :             return 0;
     902             :     }
     903             : 
     904           0 :     _krb5_debug(context, 0, "No admin entries found for realm %s", kd->realm);
     905             : 
     906           0 :     return KRB5_KDC_UNREACH;    /* XXX */
     907             : }
     908             : 
     909             : static krb5_error_code
     910          29 : kpasswd_get_next(krb5_context context,
     911             :                  struct krb5_krbhst_data *kd,
     912             :                  krb5_krbhst_info **host)
     913             : {
     914           0 :     krb5_error_code ret;
     915             : 
     916          29 :     if ((kd->flags & KD_PLUGIN) == 0) {
     917          29 :         plugin_get_hosts(context, kd, locate_service_kpasswd);
     918          29 :         kd->flags |= KD_PLUGIN;
     919          29 :         if(get_next(kd, host))
     920           0 :             return 0;
     921             :     }
     922             : 
     923          29 :     if((kd->flags & KD_CONFIG) == 0) {
     924          29 :         config_get_hosts(context, kd, kd->config_param);
     925          29 :         kd->flags |= KD_CONFIG;
     926          29 :         if(get_next(kd, host))
     927           0 :             return 0;
     928             :     }
     929             : 
     930          29 :     if (kd->flags & KD_CONFIG_EXISTS) {
     931           0 :         _krb5_debug(context, 1,
     932             :                     "Configuration exists for realm %s, wont go to DNS",
     933             :                     kd->realm);
     934           0 :         return KRB5_KDC_UNREACH;
     935             :     }
     936             : 
     937          29 :     if (!krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
     938          29 :             NULL) &&
     939          29 :         context->srv_lookup) {
     940          29 :         if((kd->flags & KD_SRV_UDP) == 0) {
     941          29 :             srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
     942          29 :             kd->flags |= KD_SRV_UDP;
     943          29 :             if(get_next(kd, host))
     944          29 :                 return 0;
     945             :         }
     946           0 :         if((kd->flags & KD_SRV_TCP) == 0) {
     947           0 :             srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
     948           0 :             kd->flags |= KD_SRV_TCP;
     949           0 :             if(get_next(kd, host))
     950           0 :                 return 0;
     951             :         }
     952             :     }
     953             : 
     954             :     /* no matches -> try admin */
     955             : 
     956           0 :     if (krbhst_empty(kd)) {
     957           0 :         kd->flags = 0;
     958           0 :         kd->port  = kd->def_port;
     959           0 :         kd->get_next = admin_get_next;
     960           0 :         ret = (*kd->get_next)(context, kd, host);
     961           0 :         if (ret == 0)
     962           0 :             (*host)->proto = krbhst_get_default_proto(kd);
     963           0 :         return ret;
     964             :     }
     965             : 
     966           0 :     _krb5_debug(context, 0, "No kpasswd entries found for realm %s", kd->realm);
     967             : 
     968           0 :     return KRB5_KDC_UNREACH;
     969             : }
     970             : 
     971             : static void KRB5_CALLCONV
     972       74605 : krbhost_dealloc(void *ptr)
     973             : {
     974       74605 :     struct krb5_krbhst_data *handle = (struct krb5_krbhst_data *)ptr;
     975        3448 :     krb5_krbhst_info *h, *next;
     976             : 
     977      148599 :     for (h = handle->hosts; h != NULL; h = next) {
     978       73994 :         next = h->next;
     979       73994 :         _krb5_free_krbhst_info(h);
     980             :     }
     981       74605 :     if (handle->hostname)
     982           0 :         free(handle->hostname);
     983       74605 :     if (handle->sitename)
     984           0 :         free(handle->sitename);
     985             : 
     986       74605 :     free(handle->realm);
     987       74605 : }
     988             : 
     989             : static struct krb5_krbhst_data*
     990       74605 : common_init(krb5_context context,
     991             :             const char *config_param,
     992             :             const char *srv_label,
     993             :             const char *service,
     994             :             const char *realm,
     995             :             int flags)
     996             : {
     997        3448 :     struct krb5_krbhst_data *kd;
     998             : 
     999       74605 :     if ((kd = heim_alloc(sizeof(*kd), "krbhst-context", krbhost_dealloc)) == NULL)
    1000           0 :         return NULL;
    1001             : 
    1002       74605 :     if((kd->realm = strdup(realm)) == NULL) {
    1003           0 :         heim_release(kd);
    1004           0 :         return NULL;
    1005             :     }
    1006             : 
    1007       74605 :     kd->config_param = config_param;
    1008       74605 :     kd->srv_label = srv_label;
    1009             : 
    1010       74605 :     _krb5_debug(context, 2, "Trying to find service %s for realm %s flags %x",
    1011             :                 service, realm, flags);
    1012             : 
    1013             :     /* For 'realms' without a . do not even think of going to DNS */
    1014       74605 :     if (!strchr(realm, '.'))
    1015        3849 :         kd->flags |= KD_CONFIG_EXISTS;
    1016             : 
    1017       74605 :     if (flags & KRB5_KRBHST_FLAGS_LARGE_MSG)
    1018       48664 :         kd->flags |= KD_LARGE_MSG;
    1019       74605 :     kd->end = kd->index = &kd->hosts;
    1020       74605 :     return kd;
    1021             : }
    1022             : 
    1023             : /*
    1024             :  * initialize `handle' to look for hosts of type `type' in realm `realm'
    1025             :  */
    1026             : 
    1027             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1028          29 : krb5_krbhst_init(krb5_context context,
    1029             :                  const char *realm,
    1030             :                  unsigned int type,
    1031             :                  krb5_krbhst_handle *handle)
    1032             : {
    1033          29 :     return krb5_krbhst_init_flags(context, realm, type, 0, handle);
    1034             : }
    1035             : 
    1036             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1037       74605 : krb5_krbhst_init_flags(krb5_context context,
    1038             :                        const char *realm,
    1039             :                        unsigned int type,
    1040             :                        int flags,
    1041             :                        krb5_krbhst_handle *handle)
    1042             : {
    1043        3448 :     struct krb5_krbhst_data *kd;
    1044        3448 :     krb5_error_code (*next)(krb5_context, struct krb5_krbhst_data *,
    1045             :                             krb5_krbhst_info **);
    1046        3448 :     int def_port;
    1047        3448 :     const char *config_param;
    1048        3448 :     const char *srv_label;
    1049        3448 :     const char *service;
    1050             : 
    1051       74605 :     *handle = NULL;
    1052             : 
    1053       74605 :     switch(type) {
    1054       74576 :     case KRB5_KRBHST_KDC:
    1055       74576 :         next = kdc_get_next;
    1056       74576 :         def_port = ntohs(krb5_getportbyname(context, "kerberos", "udp", 88));
    1057       74576 :         config_param = "kdc";
    1058       74576 :         srv_label = "kerberos";
    1059       74576 :         service = "kdc";
    1060       74576 :         break;
    1061           0 :     case KRB5_KRBHST_ADMIN:
    1062           0 :         next = admin_get_next;
    1063           0 :         def_port = ntohs(krb5_getportbyname(context, "kerberos-adm",
    1064             :                                             "tcp", 749));
    1065           0 :         config_param = "admin_server";
    1066           0 :         srv_label = "kerberos-adm";
    1067           0 :         service = "admin";
    1068           0 :         break;
    1069           0 :     case KRB5_KRBHST_READONLY_ADMIN:
    1070           0 :         next = admin_get_next;
    1071           0 :         def_port = ntohs(krb5_getportbyname(context, "kerberos-adm",
    1072             :                                             "tcp", 749));
    1073           0 :         config_param = "readonly_admin_server";
    1074           0 :         srv_label = "kerberos-adm-readonly";
    1075           0 :         service = "admin";
    1076           0 :         break;
    1077          29 :     case KRB5_KRBHST_CHANGEPW:
    1078          29 :         next = kpasswd_get_next;
    1079          29 :         def_port = ntohs(krb5_getportbyname(context, "kpasswd", "udp",
    1080             :                                             KPASSWD_PORT));
    1081          29 :         config_param = "kpasswd_server";
    1082          29 :         srv_label = "kpasswd";
    1083          29 :         service = "change_password";
    1084          29 :         break;
    1085           0 :     case KRB5_KRBHST_TKTBRIDGEAP:
    1086           0 :         next = kdc_get_next;
    1087           0 :         def_port = ntohs(krb5_getportbyname(context, "kerberos", "tcp", 88));
    1088           0 :         config_param = "tktbridgeap";
    1089           0 :         srv_label = "kerberos-tkt-bridge";
    1090           0 :         service = "kdc";
    1091           0 :         break;
    1092           0 :     default:
    1093           0 :         krb5_set_error_message(context, ENOTTY,
    1094           0 :                                N_("unknown krbhst type (%u)", ""), type);
    1095           0 :         return ENOTTY;
    1096             :     }
    1097       74605 :     if((kd = common_init(context, config_param, srv_label, service, realm,
    1098             :                          flags)) == NULL)
    1099           0 :         return ENOMEM;
    1100       74605 :     kd->get_next = next;
    1101       74605 :     kd->def_port = def_port;
    1102       74605 :     *handle = kd;
    1103       74605 :     return 0;
    1104             : }
    1105             : 
    1106             : /*
    1107             :  * return the next host information from `handle' in `host'
    1108             :  */
    1109             : 
    1110             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1111       74609 : krb5_krbhst_next(krb5_context context,
    1112             :                  krb5_krbhst_handle handle,
    1113             :                  krb5_krbhst_info **host)
    1114             : {
    1115       74609 :     if(get_next(handle, host))
    1116           0 :         return 0;
    1117             : 
    1118       74609 :     return (*handle->get_next)(context, handle, host);
    1119             : }
    1120             : 
    1121             : /*
    1122             :  * return the next host information from `handle' as a host name
    1123             :  * in `hostname' (or length `hostlen)
    1124             :  */
    1125             : 
    1126             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1127           0 : krb5_krbhst_next_as_string(krb5_context context,
    1128             :                            krb5_krbhst_handle handle,
    1129             :                            char *hostname,
    1130             :                            size_t hostlen)
    1131             : {
    1132           0 :     krb5_error_code ret;
    1133           0 :     krb5_krbhst_info *host;
    1134           0 :     ret = krb5_krbhst_next(context, handle, &host);
    1135           0 :     if(ret)
    1136           0 :         return ret;
    1137           0 :     return krb5_krbhst_format_string(context, host, hostname, hostlen);
    1138             : }
    1139             : 
    1140             : /*
    1141             :  *
    1142             :  */
    1143             : 
    1144             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1145           0 : krb5_krbhst_set_hostname(krb5_context context,
    1146             :                          krb5_krbhst_handle handle,
    1147             :                          const char *hostname)
    1148             : {
    1149           0 :     if (handle->hostname)
    1150           0 :         free(handle->hostname);
    1151           0 :     handle->hostname = strdup(hostname);
    1152           0 :     if (handle->hostname == NULL)
    1153           0 :         return ENOMEM;
    1154           0 :     return 0;
    1155             : }
    1156             : 
    1157             : krb5_error_code KRB5_LIB_FUNCTION
    1158           0 : krb5_krbhst_set_sitename(krb5_context context,
    1159             :                          krb5_krbhst_handle handle,
    1160             :                          const char *sitename)
    1161             : {
    1162           0 :     if (handle->sitename)
    1163           0 :         free(handle->sitename);
    1164           0 :     handle->sitename = strdup(sitename);
    1165           0 :     if (handle->sitename == NULL)
    1166           0 :         return krb5_enomem(context);
    1167           0 :     return 0;
    1168             : }
    1169             : 
    1170             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    1171           0 : krb5_krbhst_reset(krb5_context context, krb5_krbhst_handle handle)
    1172             : {
    1173           0 :     handle->index = &handle->hosts;
    1174           0 : }
    1175             : 
    1176             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    1177       74605 : krb5_krbhst_free(krb5_context context, krb5_krbhst_handle handle)
    1178             : {
    1179       74605 :     heim_release(handle);
    1180       74605 : }
    1181             : 
    1182             : #ifndef HEIMDAL_SMALLER
    1183             : 
    1184             : /* backwards compatibility ahead */
    1185             : 
    1186             : static krb5_error_code
    1187           0 : gethostlist(krb5_context context, const char *realm,
    1188             :             unsigned int type, char ***hostlist)
    1189             : {
    1190           0 :     krb5_error_code ret;
    1191           0 :     int nhost = 0;
    1192           0 :     krb5_krbhst_handle handle;
    1193           0 :     char host[MAXHOSTNAMELEN];
    1194           0 :     krb5_krbhst_info *hostinfo;
    1195             : 
    1196           0 :     ret = krb5_krbhst_init(context, realm, type, &handle);
    1197           0 :     if (ret)
    1198           0 :         return ret;
    1199             : 
    1200           0 :     while (krb5_krbhst_next(context, handle, &hostinfo) == 0)
    1201           0 :         nhost++;
    1202           0 :     if (nhost == 0) {
    1203           0 :         krb5_set_error_message(context, KRB5_KDC_UNREACH,
    1204           0 :                                N_("No KDC found for realm %s", ""), realm);
    1205           0 :         krb5_krbhst_free(context, handle);
    1206           0 :         return KRB5_KDC_UNREACH;
    1207             :     }
    1208           0 :     *hostlist = calloc(nhost + 1, sizeof(**hostlist));
    1209           0 :     if (*hostlist == NULL) {
    1210           0 :         krb5_krbhst_free(context, handle);
    1211           0 :         return krb5_enomem(context);
    1212             :     }
    1213             : 
    1214           0 :     krb5_krbhst_reset(context, handle);
    1215           0 :     nhost = 0;
    1216           0 :     while (krb5_krbhst_next_as_string(context, handle,
    1217           0 :                                       host, sizeof(host)) == 0) {
    1218           0 :         if (((*hostlist)[nhost++] = strdup(host)) == NULL) {
    1219           0 :             krb5_free_krbhst(context, *hostlist);
    1220           0 :             krb5_krbhst_free(context, handle);
    1221           0 :             return krb5_enomem(context);
    1222             :         }
    1223             :     }
    1224           0 :     (*hostlist)[nhost] = NULL;
    1225           0 :     krb5_krbhst_free(context, handle);
    1226           0 :     return 0;
    1227             : }
    1228             : 
    1229             : /*
    1230             :  * Return a malloced list of kadmin-hosts for `realm' in `hostlist'
    1231             :  */
    1232             : 
    1233             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1234           0 : krb5_get_krb_admin_hst(krb5_context context,
    1235             :                        const krb5_realm *realm,
    1236             :                        char ***hostlist)
    1237             : {
    1238           0 :     return gethostlist(context, *realm, KRB5_KRBHST_ADMIN, hostlist);
    1239             : }
    1240             : 
    1241             : /*
    1242             :  * Return a malloced list of writable kadmin-hosts for `realm' in `hostlist'
    1243             :  */
    1244             : 
    1245             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1246           0 : krb5_get_krb_readonly_admin_hst(krb5_context context,
    1247             :                                 const krb5_realm *realm,
    1248             :                                 char ***hostlist)
    1249             : {
    1250           0 :     return gethostlist(context, *realm, KRB5_KRBHST_READONLY_ADMIN, hostlist);
    1251             : }
    1252             : 
    1253             : /*
    1254             :  * return an malloced list of changepw-hosts for `realm' in `hostlist'
    1255             :  */
    1256             : 
    1257             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1258           0 : krb5_get_krb_changepw_hst (krb5_context context,
    1259             :                            const krb5_realm *realm,
    1260             :                            char ***hostlist)
    1261             : {
    1262           0 :     return gethostlist(context, *realm, KRB5_KRBHST_CHANGEPW, hostlist);
    1263             : }
    1264             : 
    1265             : /*
    1266             :  * return an malloced list of 524-hosts for `realm' in `hostlist'
    1267             :  */
    1268             : 
    1269             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1270           0 : krb5_get_krb524hst (krb5_context context,
    1271             :                     const krb5_realm *realm,
    1272             :                     char ***hostlist)
    1273             : {
    1274           0 :     return gethostlist(context, *realm, KRB5_KRBHST_KRB524, hostlist);
    1275             : }
    1276             : 
    1277             : /*
    1278             :  * return an malloced list of KDC's for `realm' in `hostlist'
    1279             :  */
    1280             : 
    1281             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1282           0 : krb5_get_krbhst (krb5_context context,
    1283             :                  const krb5_realm *realm,
    1284             :                  char ***hostlist)
    1285             : {
    1286           0 :     return gethostlist(context, *realm, KRB5_KRBHST_KDC, hostlist);
    1287             : }
    1288             : 
    1289             : /*
    1290             :  * free all the memory allocated in `hostlist'
    1291             :  */
    1292             : 
    1293             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1294           0 : krb5_free_krbhst (krb5_context context,
    1295             :                   char **hostlist)
    1296             : {
    1297           0 :     char **p;
    1298             : 
    1299           0 :     for (p = hostlist; *p; ++p)
    1300           0 :         free (*p);
    1301           0 :     free (hostlist);
    1302           0 :     return 0;
    1303             : }
    1304             : 
    1305             : #endif /* HEIMDAL_SMALLER */

Generated by: LCOV version 1.14