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

Generated by: LCOV version 1.13