LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - addr_families.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 62 676 9.2 %
Date: 2024-04-13 12:30:31 Functions: 11 52 21.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "krb5_locl.h"
      35             : 
      36             : struct addr_operations {
      37             :     int af;
      38             :     krb5_address_type atype;
      39             :     size_t max_sockaddr_size;
      40             :     krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *);
      41             :     krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *);
      42             :     void (*addr2sockaddr)(const krb5_address *, struct sockaddr *,
      43             :                           krb5_socklen_t *sa_size, int port);
      44             :     void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int);
      45             :     krb5_error_code (*h_addr2addr)(const char *, krb5_address *);
      46             :     krb5_boolean (*uninteresting)(const struct sockaddr *);
      47             :     krb5_boolean (*is_loopback)(const struct sockaddr *);
      48             :     void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int);
      49             :     int (*print_addr)(const krb5_address *, char *, size_t);
      50             :     int (*parse_addr)(krb5_context, const char*, krb5_address *);
      51             :     int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*);
      52             :     int (*free_addr)(krb5_context, krb5_address*);
      53             :     int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*);
      54             :     int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long,
      55             :                          krb5_address*, krb5_address*);
      56             : };
      57             : 
      58             : /*
      59             :  * AF_INET - aka IPv4 implementation
      60             :  */
      61             : 
      62             : static krb5_error_code
      63          29 : ipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a)
      64             : {
      65          29 :     const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
      66           0 :     unsigned char buf[4];
      67             : 
      68          29 :     a->addr_type = KRB5_ADDRESS_INET;
      69          29 :     memcpy (buf, &sin4->sin_addr, 4);
      70          29 :     return krb5_data_copy(&a->address, buf, 4);
      71             : }
      72             : 
      73             : static krb5_error_code
      74          29 : ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port)
      75             : {
      76          29 :     const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
      77             : 
      78          29 :     *port = sin4->sin_port;
      79          29 :     return 0;
      80             : }
      81             : 
      82             : static void
      83           0 : ipv4_addr2sockaddr (const krb5_address *a,
      84             :                     struct sockaddr *sa,
      85             :                     krb5_socklen_t *sa_size,
      86             :                     int port)
      87             : {
      88           0 :     struct sockaddr_in tmp;
      89             : 
      90           0 :     memset (&tmp, 0, sizeof(tmp));
      91           0 :     tmp.sin_family = AF_INET;
      92           0 :     memcpy (&tmp.sin_addr, a->address.data, 4);
      93           0 :     tmp.sin_port = port;
      94           0 :     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
      95           0 :     *sa_size = sizeof(tmp);
      96           0 : }
      97             : 
      98             : static void
      99           0 : ipv4_h_addr2sockaddr(const char *addr,
     100             :                      struct sockaddr *sa,
     101             :                      krb5_socklen_t *sa_size,
     102             :                      int port)
     103             : {
     104           0 :     struct sockaddr_in tmp;
     105             : 
     106           0 :     memset (&tmp, 0, sizeof(tmp));
     107           0 :     tmp.sin_family = AF_INET;
     108           0 :     tmp.sin_port   = port;
     109           0 :     tmp.sin_addr   = *((const struct in_addr *)addr);
     110           0 :     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
     111           0 :     *sa_size = sizeof(tmp);
     112           0 : }
     113             : 
     114             : static krb5_error_code
     115           0 : ipv4_h_addr2addr (const char *addr,
     116             :                   krb5_address *a)
     117             : {
     118           0 :     unsigned char buf[4];
     119             : 
     120           0 :     a->addr_type = KRB5_ADDRESS_INET;
     121           0 :     memcpy(buf, addr, 4);
     122           0 :     return krb5_data_copy(&a->address, buf, 4);
     123             : }
     124             : 
     125             : /*
     126             :  * Are there any addresses that should be considered `uninteresting'?
     127             :  */
     128             : 
     129             : static krb5_boolean
     130           0 : ipv4_uninteresting (const struct sockaddr *sa)
     131             : {
     132           0 :     const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
     133             : 
     134           0 :     if (sin4->sin_addr.s_addr == INADDR_ANY)
     135           0 :         return TRUE;
     136             : 
     137           0 :     return FALSE;
     138             : }
     139             : 
     140             : static krb5_boolean
     141           0 : ipv4_is_loopback (const struct sockaddr *sa)
     142             : {
     143           0 :     const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
     144             : 
     145           0 :     if ((ntohl(sin4->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET)
     146           0 :         return TRUE;
     147             : 
     148           0 :     return FALSE;
     149             : }
     150             : 
     151             : static void
     152           0 : ipv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port)
     153             : {
     154           0 :     struct sockaddr_in tmp;
     155             : 
     156           0 :     memset (&tmp, 0, sizeof(tmp));
     157           0 :     tmp.sin_family = AF_INET;
     158           0 :     tmp.sin_port   = port;
     159           0 :     tmp.sin_addr.s_addr = INADDR_ANY;
     160           0 :     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
     161           0 :     *sa_size = sizeof(tmp);
     162           0 : }
     163             : 
     164             : static int
     165           0 : ipv4_print_addr (const krb5_address *addr, char *str, size_t len)
     166             : {
     167           0 :     struct in_addr ia;
     168             : 
     169           0 :     memcpy (&ia, addr->address.data, 4);
     170             : 
     171           0 :     return snprintf (str, len, "IPv4:%s", inet_ntoa(ia));
     172             : }
     173             : 
     174             : static int
     175           0 : ipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr)
     176             : {
     177           0 :     const char *p;
     178           0 :     struct in_addr a;
     179             : 
     180           0 :     p = strchr(address, ':');
     181           0 :     if(p) {
     182           0 :         p++;
     183           0 :         if(strncasecmp(address, "ip:", p - address) != 0 &&
     184           0 :            strncasecmp(address, "ip4:", p - address) != 0 &&
     185           0 :            strncasecmp(address, "ipv4:", p - address) != 0 &&
     186           0 :            strncasecmp(address, "inet:", p - address) != 0)
     187           0 :             return -1;
     188             :     } else
     189           0 :         p = address;
     190           0 :     if(inet_aton(p, &a) == 0)
     191           0 :         return -1;
     192           0 :     addr->addr_type = KRB5_ADDRESS_INET;
     193           0 :     if(krb5_data_alloc(&addr->address, 4) != 0)
     194           0 :         return -1;
     195           0 :     _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length);
     196           0 :     return 0;
     197             : }
     198             : 
     199             : static int
     200           0 : ipv4_mask_boundary(krb5_context context, const krb5_address *inaddr,
     201             :                    unsigned long len, krb5_address *low, krb5_address *high)
     202             : {
     203           0 :     unsigned long ia;
     204           0 :     uint32_t l, h, m = 0xffffffff;
     205             : 
     206           0 :     if (len > 32) {
     207           0 :         krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
     208           0 :                                N_("IPv4 prefix too large (%ld)", "len"), len);
     209           0 :         return KRB5_PROG_ATYPE_NOSUPP;
     210             :     }
     211           0 :     m = m << (32 - len);
     212             : 
     213           0 :     _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length);
     214             : 
     215           0 :     l = ia & m;
     216           0 :     h = l | ~m;
     217             : 
     218           0 :     low->addr_type = KRB5_ADDRESS_INET;
     219           0 :     if(krb5_data_alloc(&low->address, 4) != 0)
     220           0 :         return -1;
     221           0 :     _krb5_put_int(low->address.data, l, low->address.length);
     222             : 
     223           0 :     high->addr_type = KRB5_ADDRESS_INET;
     224           0 :     if(krb5_data_alloc(&high->address, 4) != 0) {
     225           0 :         krb5_free_address(context, low);
     226           0 :         return -1;
     227             :     }
     228           0 :     _krb5_put_int(high->address.data, h, high->address.length);
     229             : 
     230           0 :     return 0;
     231             : }
     232             : 
     233             : 
     234             : /*
     235             :  * AF_INET6 - aka IPv6 implementation
     236             :  */
     237             : 
     238             : #ifdef HAVE_IPV6
     239             : 
     240             : static krb5_error_code
     241           0 : ipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a)
     242             : {
     243           0 :     const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
     244             : 
     245           0 :     if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
     246           0 :         unsigned char buf[4];
     247             : 
     248           0 :         a->addr_type      = KRB5_ADDRESS_INET;
     249             : #ifndef IN6_ADDR_V6_TO_V4
     250             : #ifdef IN6_EXTRACT_V4ADDR
     251             : #define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x))
     252             : #else
     253             : #define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12])
     254             : #endif
     255             : #endif
     256           0 :         memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4);
     257           0 :         return krb5_data_copy(&a->address, buf, 4);
     258             :     } else {
     259           0 :         a->addr_type = KRB5_ADDRESS_INET6;
     260           0 :         return krb5_data_copy(&a->address,
     261           0 :                               &sin6->sin6_addr,
     262             :                               sizeof(sin6->sin6_addr));
     263             :     }
     264             : }
     265             : 
     266             : static krb5_error_code
     267           0 : ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port)
     268             : {
     269           0 :     const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
     270             : 
     271           0 :     *port = sin6->sin6_port;
     272           0 :     return 0;
     273             : }
     274             : 
     275             : static void
     276           0 : ipv6_addr2sockaddr (const krb5_address *a,
     277             :                     struct sockaddr *sa,
     278             :                     krb5_socklen_t *sa_size,
     279             :                     int port)
     280             : {
     281           0 :     struct sockaddr_in6 tmp;
     282             : 
     283           0 :     memset (&tmp, 0, sizeof(tmp));
     284           0 :     tmp.sin6_family = AF_INET6;
     285           0 :     memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr));
     286           0 :     tmp.sin6_port = port;
     287           0 :     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
     288           0 :     *sa_size = sizeof(tmp);
     289           0 : }
     290             : 
     291             : static void
     292           0 : ipv6_h_addr2sockaddr(const char *addr,
     293             :                      struct sockaddr *sa,
     294             :                      krb5_socklen_t *sa_size,
     295             :                      int port)
     296             : {
     297           0 :     struct sockaddr_in6 tmp;
     298             : 
     299           0 :     memset (&tmp, 0, sizeof(tmp));
     300           0 :     tmp.sin6_family = AF_INET6;
     301           0 :     tmp.sin6_port   = port;
     302           0 :     tmp.sin6_addr   = *((const struct in6_addr *)addr);
     303           0 :     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
     304           0 :     *sa_size = sizeof(tmp);
     305           0 : }
     306             : 
     307             : static krb5_error_code
     308           0 : ipv6_h_addr2addr (const char *addr,
     309             :                   krb5_address *a)
     310             : {
     311           0 :     a->addr_type = KRB5_ADDRESS_INET6;
     312           0 :     return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr));
     313             : }
     314             : 
     315             : /*
     316             :  *
     317             :  */
     318             : 
     319             : static krb5_boolean
     320           0 : ipv6_uninteresting (const struct sockaddr *sa)
     321             : {
     322           0 :     const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
     323           0 :     const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr;
     324             : 
     325           0 :     return IN6_IS_ADDR_LINKLOCAL(in6)
     326           0 :         || IN6_IS_ADDR_V4COMPAT(in6);
     327             : }
     328             : 
     329             : static krb5_boolean
     330           0 : ipv6_is_loopback (const struct sockaddr *sa)
     331             : {
     332           0 :     const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
     333           0 :     const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr;
     334             : 
     335           0 :     return (IN6_IS_ADDR_LOOPBACK(in6));
     336             : }
     337             : 
     338             : static void
     339           0 : ipv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port)
     340             : {
     341           0 :     struct sockaddr_in6 tmp;
     342             : 
     343           0 :     memset (&tmp, 0, sizeof(tmp));
     344           0 :     tmp.sin6_family = AF_INET6;
     345           0 :     tmp.sin6_port   = port;
     346           0 :     tmp.sin6_addr   = in6addr_any;
     347           0 :     *sa_size = sizeof(tmp);
     348           0 : }
     349             : 
     350             : static int
     351           0 : ipv6_print_addr (const krb5_address *addr, char *str, size_t len)
     352             : {
     353           0 :     char buf[128], buf2[3];
     354           0 :     if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL)
     355             :         {
     356             :             /* XXX this is pretty ugly, but better than abort() */
     357           0 :             size_t i;
     358           0 :             unsigned char *p = addr->address.data;
     359           0 :             buf[0] = '\0';
     360           0 :             for(i = 0; i < addr->address.length; i++) {
     361           0 :                 snprintf(buf2, sizeof(buf2), "%02x", p[i]);
     362           0 :                 if(i > 0 && (i & 1) == 0)
     363           0 :                     strlcat(buf, ":", sizeof(buf));
     364           0 :                 strlcat(buf, buf2, sizeof(buf));
     365             :             }
     366             :         }
     367           0 :     return snprintf(str, len, "IPv6:%s", buf);
     368             : }
     369             : 
     370             : static int
     371           0 : ipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr)
     372             : {
     373           0 :     int ret;
     374           0 :     struct in6_addr in6;
     375           0 :     const char *p;
     376             : 
     377           0 :     p = strchr(address, ':');
     378           0 :     if(p) {
     379           0 :         p++;
     380           0 :         if(strncasecmp(address, "ip6:", p - address) == 0 ||
     381           0 :            strncasecmp(address, "ipv6:", p - address) == 0 ||
     382           0 :            strncasecmp(address, "inet6:", p - address) == 0)
     383           0 :             address = p;
     384             :     }
     385             : 
     386           0 :     ret = inet_pton(AF_INET6, address, &in6.s6_addr);
     387           0 :     if(ret == 1) {
     388           0 :         addr->addr_type = KRB5_ADDRESS_INET6;
     389           0 :         ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr));
     390           0 :         if (ret)
     391           0 :             return -1;
     392           0 :         memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr));
     393           0 :         return 0;
     394             :     }
     395           0 :     return -1;
     396             : }
     397             : 
     398             : static int
     399           0 : ipv6_mask_boundary(krb5_context context, const krb5_address *inaddr,
     400             :                    unsigned long len, krb5_address *low, krb5_address *high)
     401             : {
     402           0 :     struct in6_addr addr, laddr, haddr;
     403           0 :     uint32_t m;
     404           0 :     int i, sub_len;
     405             : 
     406           0 :     if (len > 128) {
     407           0 :         krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
     408           0 :                                N_("IPv6 prefix too large (%ld)", "length"), len);
     409           0 :         return KRB5_PROG_ATYPE_NOSUPP;
     410             :     }
     411             : 
     412           0 :     if (inaddr->address.length != sizeof(addr)) {
     413           0 :         krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
     414           0 :                                N_("IPv6 addr bad length", ""));
     415           0 :         return KRB5_PROG_ATYPE_NOSUPP;
     416             :     }
     417             : 
     418           0 :     memcpy(&addr, inaddr->address.data, inaddr->address.length);
     419             : 
     420           0 :     for (i = 0; i < 16; i++) {
     421           0 :         sub_len = min(8, len);
     422             : 
     423           0 :         m = 0xff << (8 - sub_len);
     424             : 
     425           0 :         laddr.s6_addr[i] = addr.s6_addr[i] & m;
     426           0 :         haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m;
     427             : 
     428           0 :         if (len > 8)
     429           0 :             len -= 8;
     430             :         else
     431           0 :             len = 0;
     432             :     }
     433             : 
     434           0 :     low->addr_type = KRB5_ADDRESS_INET6;
     435           0 :     if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0)
     436           0 :         return -1;
     437           0 :     memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr));
     438             : 
     439           0 :     high->addr_type = KRB5_ADDRESS_INET6;
     440           0 :     if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) {
     441           0 :         krb5_free_address(context, low);
     442           0 :         return -1;
     443             :     }
     444           0 :     memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr));
     445             : 
     446           0 :     return 0;
     447             : }
     448             : 
     449             : #endif /* IPv6 */
     450             : 
     451             : #ifndef HEIMDAL_SMALLER
     452             : 
     453             : /*
     454             :  * table
     455             :  */
     456             : 
     457             : #define KRB5_ADDRESS_ARANGE     (-100)
     458             : 
     459             : struct arange {
     460             :     krb5_address low;
     461             :     krb5_address high;
     462             : };
     463             : 
     464             : static int
     465           0 : arange_parse_addr (krb5_context context,
     466             :                    const char *address, krb5_address *addr)
     467             : {
     468           0 :     char buf[1024], *p;
     469           0 :     krb5_address low0, high0;
     470           0 :     struct arange *a;
     471           0 :     krb5_error_code ret;
     472             : 
     473           0 :     if(strncasecmp(address, "RANGE:", 6) != 0)
     474           0 :         return -1;
     475             : 
     476           0 :     address += 6;
     477             : 
     478           0 :     p = strrchr(address, '/');
     479           0 :     if (p) {
     480           0 :         krb5_addresses addrmask;
     481           0 :         char *q;
     482           0 :         long num;
     483             : 
     484           0 :         if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf))
     485           0 :             return -1;
     486           0 :         buf[p - address] = '\0';
     487           0 :         ret = krb5_parse_address(context, buf, &addrmask);
     488           0 :         if (ret)
     489           0 :             return ret;
     490           0 :         if(addrmask.len != 1) {
     491           0 :             krb5_free_addresses(context, &addrmask);
     492           0 :             return -1;
     493             :         }
     494             : 
     495           0 :         address += p - address + 1;
     496             : 
     497           0 :         num = strtol(address, &q, 10);
     498           0 :         if (q == address || *q != '\0' || num < 0) {
     499           0 :             krb5_free_addresses(context, &addrmask);
     500           0 :             return -1;
     501             :         }
     502             : 
     503           0 :         ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num,
     504             :                                               &low0, &high0);
     505           0 :         krb5_free_addresses(context, &addrmask);
     506           0 :         if (ret)
     507           0 :             return ret;
     508             : 
     509             :     } else {
     510           0 :         krb5_addresses low, high;
     511             : 
     512           0 :         strsep_copy(&address, "-", buf, sizeof(buf));
     513           0 :         ret = krb5_parse_address(context, buf, &low);
     514           0 :         if(ret)
     515           0 :             return ret;
     516           0 :         if(low.len != 1) {
     517           0 :             krb5_free_addresses(context, &low);
     518           0 :             return -1;
     519             :         }
     520             : 
     521           0 :         strsep_copy(&address, "-", buf, sizeof(buf));
     522           0 :         ret = krb5_parse_address(context, buf, &high);
     523           0 :         if(ret) {
     524           0 :             krb5_free_addresses(context, &low);
     525           0 :             return ret;
     526             :         }
     527             : 
     528           0 :         if(high.len != 1 || high.val[0].addr_type != low.val[0].addr_type) {
     529           0 :             krb5_free_addresses(context, &low);
     530           0 :             krb5_free_addresses(context, &high);
     531           0 :             return -1;
     532             :         }
     533             : 
     534           0 :         ret = krb5_copy_address(context, &high.val[0], &high0);
     535           0 :         if (ret == 0) {
     536           0 :             ret = krb5_copy_address(context, &low.val[0], &low0);
     537           0 :             if (ret)
     538           0 :                 krb5_free_address(context, &high0);
     539             :         }
     540           0 :         krb5_free_addresses(context, &low);
     541           0 :         krb5_free_addresses(context, &high);
     542           0 :         if (ret)
     543           0 :             return ret;
     544             :     }
     545             : 
     546           0 :     ret = krb5_data_alloc(&addr->address, sizeof(*a));
     547           0 :     if (ret) {
     548           0 :         krb5_free_address(context, &low0);
     549           0 :         krb5_free_address(context, &high0);
     550           0 :         return ret;
     551             :     }
     552             : 
     553           0 :     addr->addr_type = KRB5_ADDRESS_ARANGE;
     554           0 :     a = addr->address.data;
     555             : 
     556           0 :     if(krb5_address_order(context, &low0, &high0) < 0) {
     557           0 :         a->low = low0;
     558           0 :         a->high = high0;
     559             :     } else {
     560           0 :         a->low = high0;
     561           0 :         a->high = low0;
     562             :     }
     563           0 :     return 0;
     564             : }
     565             : 
     566             : static int
     567           0 : arange_free (krb5_context context, krb5_address *addr)
     568             : {
     569           0 :     struct arange *a;
     570           0 :     a = addr->address.data;
     571           0 :     krb5_free_address(context, &a->low);
     572           0 :     krb5_free_address(context, &a->high);
     573           0 :     krb5_data_free(&addr->address);
     574           0 :     return 0;
     575             : }
     576             : 
     577             : 
     578             : static int
     579           0 : arange_copy (krb5_context context, const krb5_address *inaddr,
     580             :              krb5_address *outaddr)
     581             : {
     582           0 :     krb5_error_code ret;
     583           0 :     struct arange *i, *o;
     584             : 
     585           0 :     outaddr->addr_type = KRB5_ADDRESS_ARANGE;
     586           0 :     ret = krb5_data_alloc(&outaddr->address, sizeof(*o));
     587           0 :     if(ret)
     588           0 :         return ret;
     589           0 :     i = inaddr->address.data;
     590           0 :     o = outaddr->address.data;
     591           0 :     ret = krb5_copy_address(context, &i->low, &o->low);
     592           0 :     if(ret) {
     593           0 :         krb5_data_free(&outaddr->address);
     594           0 :         return ret;
     595             :     }
     596           0 :     ret = krb5_copy_address(context, &i->high, &o->high);
     597           0 :     if(ret) {
     598           0 :         krb5_free_address(context, &o->low);
     599           0 :         krb5_data_free(&outaddr->address);
     600           0 :         return ret;
     601             :     }
     602           0 :     return 0;
     603             : }
     604             : 
     605             : static int
     606           0 : arange_print_addr (const krb5_address *addr, char *str, size_t len)
     607             : {
     608           0 :     struct arange *a;
     609           0 :     krb5_error_code ret;
     610           0 :     size_t l, size, ret_len;
     611             : 
     612           0 :     a = addr->address.data;
     613             : 
     614           0 :     l = strlcpy(str, "RANGE:", len);
     615           0 :     ret_len = l;
     616           0 :     if (l > len)
     617           0 :         l = len;
     618           0 :     size = l;
     619             : 
     620           0 :     ret = krb5_print_address (&a->low, str + size, len - size, &l);
     621           0 :     if (ret)
     622           0 :         return ret;
     623           0 :     ret_len += l;
     624           0 :     if (len - size > l)
     625           0 :         size += l;
     626             :     else
     627           0 :         size = len;
     628             : 
     629           0 :     l = strlcat(str + size, "-", len - size);
     630           0 :     ret_len += l;
     631           0 :     if (len - size > l)
     632           0 :         size += l;
     633             :     else
     634           0 :         size = len;
     635             : 
     636           0 :     ret = krb5_print_address (&a->high, str + size, len - size, &l);
     637           0 :     if (ret)
     638           0 :         return ret;
     639           0 :     ret_len += l;
     640             : 
     641           0 :     return ret_len;
     642             : }
     643             : 
     644             : static int
     645           0 : arange_order_addr(krb5_context context,
     646             :                   const krb5_address *addr1,
     647             :                   const krb5_address *addr2)
     648             : {
     649           0 :     int tmp1, tmp2, sign;
     650           0 :     struct arange *a;
     651           0 :     const krb5_address *a2;
     652             : 
     653           0 :     if(addr1->addr_type == KRB5_ADDRESS_ARANGE) {
     654           0 :         a = addr1->address.data;
     655           0 :         a2 = addr2;
     656           0 :         sign = 1;
     657           0 :     } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) {
     658           0 :         a = addr2->address.data;
     659           0 :         a2 = addr1;
     660           0 :         sign = -1;
     661             :     } else {
     662           0 :         abort();
     663           0 :         UNREACHABLE(return 0);
     664             :     }
     665             : 
     666           0 :     if(a2->addr_type == KRB5_ADDRESS_ARANGE) {
     667           0 :         struct arange *b = a2->address.data;
     668           0 :         tmp1 = krb5_address_order(context, &a->low, &b->low);
     669           0 :         if(tmp1 != 0)
     670           0 :             return sign * tmp1;
     671           0 :         return sign * krb5_address_order(context, &a->high, &b->high);
     672           0 :     } else if(a2->addr_type == a->low.addr_type) {
     673           0 :         tmp1 = krb5_address_order(context, &a->low, a2);
     674           0 :         if(tmp1 > 0)
     675           0 :             return sign;
     676           0 :         tmp2 = krb5_address_order(context, &a->high, a2);
     677           0 :         if(tmp2 < 0)
     678           0 :             return -sign;
     679           0 :         return 0;
     680             :     } else {
     681           0 :         return sign * (addr1->addr_type - addr2->addr_type);
     682             :     }
     683             : }
     684             : 
     685             : #endif /* HEIMDAL_SMALLER */
     686             : 
     687             : static int
     688           0 : addrport_print_addr (const krb5_address *addr, char *str, size_t len)
     689             : {
     690           0 :     krb5_error_code ret;
     691           0 :     krb5_address addr1, addr2;
     692           0 :     uint16_t port = 0;
     693           0 :     size_t ret_len = 0, l, size = 0;
     694           0 :     krb5_storage *sp;
     695             : 
     696           0 :     sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address));
     697           0 :     if (sp == NULL)
     698           0 :         return ENOMEM;
     699             : 
     700             :     /* for totally obscure reasons, these are not in network byteorder */
     701           0 :     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
     702             : 
     703           0 :     krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */
     704           0 :     krb5_ret_address(sp, &addr1);
     705             : 
     706           0 :     krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */
     707           0 :     krb5_ret_address(sp, &addr2);
     708           0 :     krb5_storage_free(sp);
     709           0 :     if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) {
     710           0 :         unsigned long value;
     711           0 :         _krb5_get_int(addr2.address.data, &value, 2);
     712           0 :         port = value;
     713             :     }
     714           0 :     l = strlcpy(str, "ADDRPORT:", len);
     715           0 :     ret_len += l;
     716           0 :     if (len > l)
     717           0 :         size += l;
     718             :     else
     719           0 :         size = len;
     720             : 
     721           0 :     ret = krb5_print_address(&addr1, str + size, len - size, &l);
     722           0 :     if (ret)
     723           0 :         return ret;
     724           0 :     ret_len += l;
     725           0 :     if (len - size > l)
     726           0 :         size += l;
     727             :     else
     728           0 :         size = len;
     729             : 
     730           0 :     ret = snprintf(str + size, len - size, ",PORT=%u", port);
     731           0 :     if (ret < 0)
     732           0 :         return EINVAL;
     733           0 :     ret_len += ret;
     734           0 :     return ret_len;
     735             : }
     736             : 
     737             : static const struct addr_operations at[] = {
     738             :     {
     739             :         AF_INET,        KRB5_ADDRESS_INET, sizeof(struct sockaddr_in),
     740             :         ipv4_sockaddr2addr,
     741             :         ipv4_sockaddr2port,
     742             :         ipv4_addr2sockaddr,
     743             :         ipv4_h_addr2sockaddr,
     744             :         ipv4_h_addr2addr,
     745             :         ipv4_uninteresting,
     746             :         ipv4_is_loopback,
     747             :         ipv4_anyaddr,
     748             :         ipv4_print_addr,
     749             :         ipv4_parse_addr,
     750             :         NULL,
     751             :         NULL,
     752             :         NULL,
     753             :      ipv4_mask_boundary
     754             :     },
     755             : #ifdef HAVE_IPV6
     756             :     {
     757             :         AF_INET6,       KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6),
     758             :         ipv6_sockaddr2addr,
     759             :         ipv6_sockaddr2port,
     760             :         ipv6_addr2sockaddr,
     761             :         ipv6_h_addr2sockaddr,
     762             :         ipv6_h_addr2addr,
     763             :         ipv6_uninteresting,
     764             :         ipv6_is_loopback,
     765             :         ipv6_anyaddr,
     766             :         ipv6_print_addr,
     767             :         ipv6_parse_addr,
     768             :         NULL,
     769             :         NULL,
     770             :         NULL,
     771             :         ipv6_mask_boundary
     772             :     } ,
     773             : #endif
     774             : #ifndef HEIMDAL_SMALLER
     775             :     /* fake address type */
     776             :     {
     777             :         KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange),
     778             :         NULL,
     779             :         NULL,
     780             :         NULL,
     781             :         NULL,
     782             :         NULL,
     783             :         NULL,
     784             :         NULL,
     785             :         NULL,
     786             :         arange_print_addr,
     787             :         arange_parse_addr,
     788             :         arange_order_addr,
     789             :         arange_free,
     790             :         arange_copy,
     791             :         NULL
     792             :     },
     793             : #endif
     794             :     {
     795             :         KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0,
     796             :         NULL,
     797             :         NULL,
     798             :         NULL,
     799             :         NULL,
     800             :         NULL,
     801             :         NULL,
     802             :         NULL,
     803             :         NULL,
     804             :         addrport_print_addr,
     805             :         NULL,
     806             :         NULL,
     807             :         NULL,
     808             :         NULL,
     809             :         NULL
     810             :     }
     811             : };
     812             : 
     813             : static const size_t num_addrs = sizeof(at) / sizeof(at[0]);
     814             : 
     815             : static size_t max_sockaddr_size = 0;
     816             : 
     817             : /*
     818             :  * generic functions
     819             :  */
     820             : 
     821             : static const struct addr_operations *
     822         164 : find_af(int af)
     823             : {
     824           0 :     size_t i;
     825             : 
     826         200 :     for (i = 0; i < num_addrs; i++) {
     827         191 :         if (af == at[i].af)
     828         155 :             return &at[i];
     829             :     }
     830           9 :     return NULL;
     831             : }
     832             : 
     833             : static const struct addr_operations *
     834         147 : find_atype(krb5_address_type atype)
     835             : {
     836           0 :     size_t i;
     837             : 
     838         619 :     for (i = 0; i < num_addrs; i++) {
     839         501 :         if (atype == at[i].atype)
     840          29 :             return &at[i];
     841             :     }
     842         118 :     return NULL;
     843             : }
     844             : 
     845             : /**
     846             :  * krb5_sockaddr2address stores a address a "struct sockaddr" sa in
     847             :  * the krb5_address addr.
     848             :  *
     849             :  * @param context a Keberos context
     850             :  * @param sa a struct sockaddr to extract the address from
     851             :  * @param addr an Kerberos 5 address to store the address in.
     852             :  *
     853             :  * @return Return an error code or 0.
     854             :  *
     855             :  * @ingroup krb5_address
     856             :  */
     857             : 
     858             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     859          29 : krb5_sockaddr2address (krb5_context context,
     860             :                        const struct sockaddr *sa, krb5_address *addr)
     861             : {
     862          29 :     const struct addr_operations *a = find_af(sa->sa_family);
     863          29 :     if (a == NULL) {
     864           0 :         krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
     865           0 :                                 N_("Address family %d not supported", ""),
     866           0 :                                 sa->sa_family);
     867           0 :         return KRB5_PROG_ATYPE_NOSUPP;
     868             :     }
     869          29 :     return (*a->sockaddr2addr)(sa, addr);
     870             : }
     871             : 
     872             : /**
     873             :  * krb5_sockaddr2port extracts a port (if possible) from a "struct
     874             :  * sockaddr.
     875             :  *
     876             :  * @param context a Keberos context
     877             :  * @param sa a struct sockaddr to extract the port from
     878             :  * @param port a pointer to an int16_t store the port in.
     879             :  *
     880             :  * @return Return an error code or 0. Will return
     881             :  * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
     882             :  *
     883             :  * @ingroup krb5_address
     884             :  */
     885             : 
     886             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     887          29 : krb5_sockaddr2port (krb5_context context,
     888             :                     const struct sockaddr *sa, int16_t *port)
     889             : {
     890          29 :     const struct addr_operations *a = find_af(sa->sa_family);
     891          29 :     if (a == NULL) {
     892           0 :         krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
     893           0 :                                 N_("Address family %d not supported", ""),
     894           0 :                                 sa->sa_family);
     895           0 :         return KRB5_PROG_ATYPE_NOSUPP;
     896             :     }
     897          29 :     return (*a->sockaddr2port)(sa, port);
     898             : }
     899             : 
     900             : /**
     901             :  * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr
     902             :  * and port. The argument sa_size should initially contain the size of
     903             :  * the sa and after the call, it will contain the actual length of the
     904             :  * address. In case of the sa is too small to fit the whole address,
     905             :  * the up to *sa_size will be stored, and then *sa_size will be set to
     906             :  * the required length.
     907             :  *
     908             :  * @param context a Keberos context
     909             :  * @param addr the address to copy the from
     910             :  * @param sa the struct sockaddr that will be filled in
     911             :  * @param sa_size pointer to length of sa, and after the call, it will
     912             :  * contain the actual length of the address.
     913             :  * @param port set port in sa.
     914             :  *
     915             :  * @return Return an error code or 0. Will return
     916             :  * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
     917             :  *
     918             :  * @ingroup krb5_address
     919             :  */
     920             : 
     921             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     922           0 : krb5_addr2sockaddr (krb5_context context,
     923             :                     const krb5_address *addr,
     924             :                     struct sockaddr *sa,
     925             :                     krb5_socklen_t *sa_size,
     926             :                     int port)
     927             : {
     928           0 :     const struct addr_operations *a = find_atype(addr->addr_type);
     929             : 
     930           0 :     if (a == NULL) {
     931           0 :         krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
     932           0 :                                 N_("Address type %d not supported",
     933             :                                    "krb5_address type"),
     934           0 :                                 addr->addr_type);
     935           0 :         return KRB5_PROG_ATYPE_NOSUPP;
     936             :     }
     937           0 :     if (a->addr2sockaddr == NULL) {
     938           0 :         krb5_set_error_message (context,
     939             :                                 KRB5_PROG_ATYPE_NOSUPP,
     940           0 :                                 N_("Can't convert address type %d to sockaddr", ""),
     941           0 :                                 addr->addr_type);
     942           0 :         return KRB5_PROG_ATYPE_NOSUPP;
     943             :     }
     944           0 :     (*a->addr2sockaddr)(addr, sa, sa_size, port);
     945           0 :     return 0;
     946             : }
     947             : 
     948             : /**
     949             :  * krb5_max_sockaddr_size returns the max size of the .Li struct
     950             :  * sockaddr that the Kerberos library will return.
     951             :  *
     952             :  * @return Return an size_t of the maximum struct sockaddr.
     953             :  *
     954             :  * @ingroup krb5_address
     955             :  */
     956             : 
     957             : KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
     958           0 : krb5_max_sockaddr_size (void)
     959             : {
     960           0 :     if (max_sockaddr_size == 0) {
     961             :         size_t i;
     962             : 
     963           0 :         for (i = 0; i < num_addrs; i++)
     964           0 :             max_sockaddr_size = max(max_sockaddr_size, at[i].max_sockaddr_size);
     965             :     }
     966           0 :     return max_sockaddr_size;
     967             : }
     968             : 
     969             : /**
     970             :  * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the
     971             :  * kerberos library thinks are uninteresting.  One example are link
     972             :  * local addresses.
     973             :  *
     974             :  * @param sa pointer to struct sockaddr that might be interesting.
     975             :  *
     976             :  * @return Return a non zero for uninteresting addresses.
     977             :  *
     978             :  * @ingroup krb5_address
     979             :  */
     980             : 
     981             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
     982           0 : krb5_sockaddr_uninteresting(const struct sockaddr *sa)
     983             : {
     984           0 :     const struct addr_operations *a = find_af(sa->sa_family);
     985           0 :     if (a == NULL || a->uninteresting == NULL)
     986           0 :         return TRUE;
     987           0 :     return (*a->uninteresting)(sa);
     988             : }
     989             : 
     990             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
     991           0 : krb5_sockaddr_is_loopback(const struct sockaddr *sa)
     992             : {
     993           0 :     const struct addr_operations *a = find_af(sa->sa_family);
     994           0 :     if (a == NULL || a->is_loopback == NULL)
     995           0 :         return TRUE;
     996           0 :     return (*a->is_loopback)(sa);
     997             : }
     998             : 
     999             : /**
    1000             :  * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and
    1001             :  * the "struct hostent" (see gethostbyname(3) ) h_addr_list
    1002             :  * component. The argument sa_size should initially contain the size
    1003             :  * of the sa, and after the call, it will contain the actual length of
    1004             :  * the address.
    1005             :  *
    1006             :  * @param context a Keberos context
    1007             :  * @param af addresses
    1008             :  * @param addr address
    1009             :  * @param sa returned struct sockaddr
    1010             :  * @param sa_size size of sa
    1011             :  * @param port port to set in sa.
    1012             :  *
    1013             :  * @return Return an error code or 0.
    1014             :  *
    1015             :  * @ingroup krb5_address
    1016             :  */
    1017             : 
    1018             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1019           0 : krb5_h_addr2sockaddr (krb5_context context,
    1020             :                       int af,
    1021             :                       const char *addr, struct sockaddr *sa,
    1022             :                       krb5_socklen_t *sa_size,
    1023             :                       int port)
    1024             : {
    1025           0 :     const struct addr_operations *a = find_af(af);
    1026           0 :     if (a == NULL) {
    1027           0 :         krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
    1028             :                                 "Address family %d not supported", af);
    1029           0 :         return KRB5_PROG_ATYPE_NOSUPP;
    1030             :     }
    1031           0 :     (*a->h_addr2sockaddr)(addr, sa, sa_size, port);
    1032           0 :     return 0;
    1033             : }
    1034             : 
    1035             : /**
    1036             :  * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception
    1037             :  * that it operates on a krb5_address instead of a struct sockaddr.
    1038             :  *
    1039             :  * @param context a Keberos context
    1040             :  * @param af address family
    1041             :  * @param haddr host address from struct hostent.
    1042             :  * @param addr returned krb5_address.
    1043             :  *
    1044             :  * @return Return an error code or 0.
    1045             :  *
    1046             :  * @ingroup krb5_address
    1047             :  */
    1048             : 
    1049             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1050           0 : krb5_h_addr2addr (krb5_context context,
    1051             :                   int af,
    1052             :                   const char *haddr, krb5_address *addr)
    1053             : {
    1054           0 :     const struct addr_operations *a = find_af(af);
    1055           0 :     if (a == NULL) {
    1056           0 :         krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
    1057           0 :                                 N_("Address family %d not supported", ""), af);
    1058           0 :         return KRB5_PROG_ATYPE_NOSUPP;
    1059             :     }
    1060           0 :     return (*a->h_addr2addr)(haddr, addr);
    1061             : }
    1062             : 
    1063             : /**
    1064             :  * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to
    1065             :  * bind(2) to.  The argument sa_size should initially contain the size
    1066             :  * of the sa, and after the call, it will contain the actual length
    1067             :  * of the address.
    1068             :  *
    1069             :  * @param context a Keberos context
    1070             :  * @param af address family
    1071             :  * @param sa sockaddr
    1072             :  * @param sa_size lenght of sa.
    1073             :  * @param port for to fill into sa.
    1074             :  *
    1075             :  * @return Return an error code or 0.
    1076             :  *
    1077             :  * @ingroup krb5_address
    1078             :  */
    1079             : 
    1080             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1081           0 : krb5_anyaddr (krb5_context context,
    1082             :               int af,
    1083             :               struct sockaddr *sa,
    1084             :               krb5_socklen_t *sa_size,
    1085             :               int port)
    1086             : {
    1087           0 :     const struct addr_operations *a = find_af (af);
    1088             : 
    1089           0 :     if (a == NULL) {
    1090           0 :         krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
    1091           0 :                                 N_("Address family %d not supported", ""), af);
    1092           0 :         return KRB5_PROG_ATYPE_NOSUPP;
    1093             :     }
    1094             : 
    1095           0 :     (*a->anyaddr)(sa, sa_size, port);
    1096           0 :     return 0;
    1097             : }
    1098             : 
    1099             : /**
    1100             :  * krb5_print_address prints the address in addr to the string string
    1101             :  * that have the length len. If ret_len is not NULL, it will be filled
    1102             :  * with the length of the string if size were unlimited (not including
    1103             :  * the final NUL) .
    1104             :  *
    1105             :  * @param addr address to be printed
    1106             :  * @param str pointer string to print the address into
    1107             :  * @param len length that will fit into area pointed to by "str".
    1108             :  * @param ret_len return length the str.
    1109             :  *
    1110             :  * @return Return an error code or 0.
    1111             :  *
    1112             :  * @ingroup krb5_address
    1113             :  */
    1114             : 
    1115             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1116         118 : krb5_print_address (const krb5_address *addr,
    1117             :                     char *str, size_t len, size_t *ret_len)
    1118             : {
    1119         118 :     const struct addr_operations *a = find_atype(addr->addr_type);
    1120           0 :     int ret;
    1121             : 
    1122         118 :     if (a == NULL || a->print_addr == NULL) {
    1123           0 :         char *s;
    1124           0 :         int l;
    1125           0 :         size_t i;
    1126             : 
    1127         118 :         s = str;
    1128         118 :         l = snprintf(s, len, "TYPE_%d:", addr->addr_type);
    1129         118 :         if (l < 0 || (size_t)l >= len)
    1130           0 :             return EINVAL;
    1131         118 :         s += l;
    1132         118 :         len -= l;
    1133        2006 :         for(i = 0; i < addr->address.length; i++) {
    1134        1888 :             l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]);
    1135        1888 :             if (l < 0 || (size_t)l >= len)
    1136           0 :                 return EINVAL;
    1137        1888 :             len -= l;
    1138        1888 :             s += l;
    1139             :         }
    1140         118 :         if(ret_len != NULL)
    1141           0 :             *ret_len = s - str;
    1142         118 :         return 0;
    1143             :     }
    1144           0 :     ret = (*a->print_addr)(addr, str, len);
    1145           0 :     if (ret < 0)
    1146           0 :         return EINVAL;
    1147           0 :     if(ret_len != NULL)
    1148           0 :         *ret_len = ret;
    1149           0 :     return 0;
    1150             : }
    1151             : 
    1152             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1153           0 : _krb5_parse_address_no_lookup(krb5_context context,
    1154             :                               const char *string,
    1155             :                               krb5_addresses *addresses)
    1156             : {
    1157           0 :     int i;
    1158             : 
    1159           0 :     addresses->len = 0;
    1160           0 :     addresses->val = NULL;
    1161             : 
    1162           0 :     for(i = 0; i < num_addrs; i++) {
    1163           0 :         if(at[i].parse_addr) {
    1164           0 :             krb5_address addr;
    1165           0 :             if((*at[i].parse_addr)(context, string, &addr) == 0) {
    1166           0 :                 ALLOC_SEQ(addresses, 1);
    1167           0 :                 if (addresses->val == NULL)
    1168           0 :                     return krb5_enomem(context);
    1169           0 :                 addresses->val[0] = addr;
    1170           0 :                 return 0;
    1171             :             }
    1172             :         }
    1173             :     }
    1174             : 
    1175           0 :     return -1;
    1176             : }
    1177             : 
    1178             : /**
    1179             :  * krb5_parse_address returns the resolved hostname in string to the
    1180             :  * krb5_addresses addresses .
    1181             :  *
    1182             :  * @param context a Keberos context
    1183             :  * @param string
    1184             :  * @param addresses
    1185             :  *
    1186             :  * @return Return an error code or 0.
    1187             :  *
    1188             :  * @ingroup krb5_address
    1189             :  */
    1190             : 
    1191             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1192           0 : krb5_parse_address(krb5_context context,
    1193             :                    const char *string,
    1194             :                    krb5_addresses *addresses)
    1195             : {
    1196           0 :     krb5_error_code ret;
    1197           0 :     int i, n;
    1198           0 :     struct addrinfo *ai, *a;
    1199           0 :     struct addrinfo hint;
    1200           0 :     int error;
    1201           0 :     int save_errno;
    1202             : 
    1203           0 :     addresses->len = 0;
    1204           0 :     addresses->val = NULL;
    1205             : 
    1206           0 :     ret = _krb5_parse_address_no_lookup(context, string, addresses);
    1207           0 :     if (ret == 0 || ret != -1)
    1208           0 :         return ret;
    1209             : 
    1210             :     /* if not parsed as numeric address, do a name lookup */
    1211           0 :     memset(&hint, 0, sizeof(hint));
    1212           0 :     hint.ai_family = AF_UNSPEC;
    1213           0 :     error = getaddrinfo (string, NULL, &hint, &ai);
    1214           0 :     if (error) {
    1215           0 :         krb5_error_code ret2;
    1216           0 :         save_errno = errno;
    1217           0 :         ret2 = krb5_eai_to_heim_errno(save_errno, error);
    1218           0 :         krb5_set_error_message (context, ret2, "%s: %s",
    1219             :                                 string, gai_strerror(error));
    1220           0 :         return ret2;
    1221             :     }
    1222             : 
    1223           0 :     n = 0;
    1224           0 :     for (a = ai; a != NULL; a = a->ai_next)
    1225           0 :         ++n;
    1226             : 
    1227           0 :     ALLOC_SEQ(addresses, n);
    1228           0 :     if (addresses->val == NULL) {
    1229           0 :         freeaddrinfo(ai);
    1230           0 :         return krb5_enomem(context);
    1231             :     }
    1232             : 
    1233           0 :     addresses->len = 0;
    1234           0 :     for (a = ai, i = 0; a != NULL; a = a->ai_next) {
    1235           0 :         if (krb5_sockaddr2address (context, a->ai_addr, &addresses->val[i]))
    1236           0 :             continue;
    1237           0 :         if(krb5_address_search(context, &addresses->val[i], addresses)) {
    1238           0 :             krb5_free_address(context, &addresses->val[i]);
    1239           0 :             continue;
    1240             :         }
    1241           0 :         i++;
    1242           0 :         addresses->len = i;
    1243             :     }
    1244           0 :     freeaddrinfo (ai);
    1245           0 :     return 0;
    1246             : }
    1247             : 
    1248             : /**
    1249             :  * krb5_address_order compares the addresses addr1 and addr2 so that
    1250             :  * it can be used for sorting addresses. If the addresses are the same
    1251             :  * address krb5_address_order will return 0. Behavies like memcmp(2).
    1252             :  *
    1253             :  * @param context a Keberos context
    1254             :  * @param addr1 krb5_address to compare
    1255             :  * @param addr2 krb5_address to compare
    1256             :  *
    1257             :  * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and
    1258             :  * addr2 is the same address, > 0 if addr2 is "less" then addr1.
    1259             :  *
    1260             :  * @ingroup krb5_address
    1261             :  */
    1262             : 
    1263             : KRB5_LIB_FUNCTION int KRB5_LIB_CALL
    1264           0 : krb5_address_order(krb5_context context,
    1265             :                    const krb5_address *addr1,
    1266             :                    const krb5_address *addr2)
    1267             : {
    1268             :     /* this sucks; what if both addresses have order functions, which
    1269             :        should we call? this works for now, though */
    1270           0 :     const struct addr_operations *a;
    1271           0 :     a = find_atype(addr1->addr_type);
    1272           0 :     if(a == NULL) {
    1273           0 :         krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
    1274           0 :                                 N_("Address family %d not supported", ""),
    1275           0 :                                 addr1->addr_type);
    1276           0 :         return KRB5_PROG_ATYPE_NOSUPP;
    1277             :     }
    1278           0 :     if(a->order_addr != NULL)
    1279           0 :         return (*a->order_addr)(context, addr1, addr2);
    1280           0 :     a = find_atype(addr2->addr_type);
    1281           0 :     if(a == NULL) {
    1282           0 :         krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
    1283           0 :                                 N_("Address family %d not supported", ""),
    1284           0 :                                 addr2->addr_type);
    1285           0 :         return KRB5_PROG_ATYPE_NOSUPP;
    1286             :     }
    1287           0 :     if(a->order_addr != NULL)
    1288           0 :         return (*a->order_addr)(context, addr1, addr2);
    1289             : 
    1290           0 :     if(addr1->addr_type != addr2->addr_type)
    1291           0 :         return addr1->addr_type - addr2->addr_type;
    1292           0 :     if(addr1->address.length != addr2->address.length)
    1293           0 :         return addr1->address.length - addr2->address.length;
    1294           0 :     return memcmp (addr1->address.data,
    1295           0 :                    addr2->address.data,
    1296           0 :                    addr1->address.length);
    1297             : }
    1298             : 
    1299             : /**
    1300             :  * krb5_address_compare compares the addresses  addr1 and addr2.
    1301             :  * Returns TRUE if the two addresses are the same.
    1302             :  *
    1303             :  * @param context a Keberos context
    1304             :  * @param addr1 address to compare
    1305             :  * @param addr2 address to compare
    1306             :  *
    1307             :  * @return Return an TRUE is the address are the same FALSE if not
    1308             :  *
    1309             :  * @ingroup krb5_address
    1310             :  */
    1311             : 
    1312             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1313           0 : krb5_address_compare(krb5_context context,
    1314             :                      const krb5_address *addr1,
    1315             :                      const krb5_address *addr2)
    1316             : {
    1317           0 :     return krb5_address_order (context, addr1, addr2) == 0;
    1318             : }
    1319             : 
    1320             : /**
    1321             :  * krb5_address_search checks if the address addr is a member of the
    1322             :  * address set list addrlist .
    1323             :  *
    1324             :  * @param context a Keberos context.
    1325             :  * @param addr address to search for.
    1326             :  * @param addrlist list of addresses to look in for addr.
    1327             :  *
    1328             :  * @return Return an error code or 0.
    1329             :  *
    1330             :  * @ingroup krb5_address
    1331             :  */
    1332             : 
    1333             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1334           0 : krb5_address_search(krb5_context context,
    1335             :                     const krb5_address *addr,
    1336             :                     const krb5_addresses *addrlist)
    1337             : {
    1338           0 :     size_t i;
    1339             : 
    1340           0 :     for (i = 0; i < addrlist->len; ++i)
    1341           0 :         if (krb5_address_compare (context, addr, &addrlist->val[i]))
    1342           0 :             return TRUE;
    1343           0 :     return FALSE;
    1344             : }
    1345             : 
    1346             : /**
    1347             :  * krb5_free_address frees the data stored in the address that is
    1348             :  * alloced with any of the krb5_address functions.
    1349             :  *
    1350             :  * @param context a Keberos context
    1351             :  * @param address addresss to be freed.
    1352             :  *
    1353             :  * @return Return an error code or 0.
    1354             :  *
    1355             :  * @ingroup krb5_address
    1356             :  */
    1357             : 
    1358             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1359          29 : krb5_free_address(krb5_context context,
    1360             :                   krb5_address *address)
    1361             : {
    1362          29 :     const struct addr_operations *a = find_atype (address->addr_type);
    1363          29 :     if(a != NULL && a->free_addr != NULL)
    1364           0 :         return (*a->free_addr)(context, address);
    1365          29 :     krb5_data_free (&address->address);
    1366          29 :     memset(address, 0, sizeof(*address));
    1367          29 :     return 0;
    1368             : }
    1369             : 
    1370             : /**
    1371             :  * krb5_free_addresses frees the data stored in the address that is
    1372             :  * alloced with any of the krb5_address functions.
    1373             :  *
    1374             :  * @param context a Keberos context
    1375             :  * @param addresses addressses to be freed.
    1376             :  *
    1377             :  * @return Return an error code or 0.
    1378             :  *
    1379             :  * @ingroup krb5_address
    1380             :  */
    1381             : 
    1382             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1383     2937009 : krb5_free_addresses(krb5_context context,
    1384             :                     krb5_addresses *addresses)
    1385             : {
    1386     2937009 :     free_HostAddresses(addresses);
    1387     2937009 :     return 0;
    1388             : }
    1389             : 
    1390             : /**
    1391             :  * krb5_copy_address copies the content of address
    1392             :  * inaddr to outaddr.
    1393             :  *
    1394             :  * @param context a Keberos context
    1395             :  * @param inaddr pointer to source address
    1396             :  * @param outaddr pointer to destination address
    1397             :  *
    1398             :  * @return Return an error code or 0.
    1399             :  *
    1400             :  * @ingroup krb5_address
    1401             :  */
    1402             : 
    1403             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1404         106 : krb5_copy_address(krb5_context context,
    1405             :                   const krb5_address *inaddr,
    1406             :                   krb5_address *outaddr)
    1407             : {
    1408         106 :     const struct addr_operations *a = find_af (inaddr->addr_type);
    1409         106 :     if(a != NULL && a->copy_addr != NULL)
    1410           0 :         return (*a->copy_addr)(context, inaddr, outaddr);
    1411         106 :     return copy_HostAddress(inaddr, outaddr);
    1412             : }
    1413             : 
    1414             : /**
    1415             :  * krb5_copy_addresses copies the content of addresses
    1416             :  * inaddr to outaddr.
    1417             :  *
    1418             :  * @param context a Keberos context
    1419             :  * @param inaddr pointer to source addresses
    1420             :  * @param outaddr pointer to destination addresses
    1421             :  *
    1422             :  * @return Return an error code or 0.
    1423             :  *
    1424             :  * @ingroup krb5_address
    1425             :  */
    1426             : 
    1427             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1428     2009656 : krb5_copy_addresses(krb5_context context,
    1429             :                     const krb5_addresses *inaddr,
    1430             :                     krb5_addresses *outaddr)
    1431             : {
    1432       42805 :     size_t i;
    1433     2009656 :     ALLOC_SEQ(outaddr, inaddr->len);
    1434     2009656 :     if(inaddr->len > 0 && outaddr->val == NULL)
    1435           0 :         return krb5_enomem(context);
    1436     2009665 :     for(i = 0; i < inaddr->len; i++)
    1437           9 :         krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]);
    1438     1966851 :     return 0;
    1439             : }
    1440             : 
    1441             : /**
    1442             :  * krb5_append_addresses adds the set of addresses in source to
    1443             :  * dest. While copying the addresses, duplicates are also sorted out.
    1444             :  *
    1445             :  * @param context a Keberos context
    1446             :  * @param dest destination of copy operation
    1447             :  * @param source adresses that are going to be added to dest
    1448             :  *
    1449             :  * @return Return an error code or 0.
    1450             :  *
    1451             :  * @ingroup krb5_address
    1452             :  */
    1453             : 
    1454             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1455           0 : krb5_append_addresses(krb5_context context,
    1456             :                       krb5_addresses *dest,
    1457             :                       const krb5_addresses *source)
    1458             : {
    1459           0 :     krb5_address *tmp;
    1460           0 :     krb5_error_code ret;
    1461           0 :     size_t i;
    1462           0 :     if(source->len > 0) {
    1463           0 :         tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp));
    1464           0 :         if (tmp == NULL)
    1465           0 :             return krb5_enomem(context);
    1466           0 :         dest->val = tmp;
    1467           0 :         for(i = 0; i < source->len; i++) {
    1468             :             /* skip duplicates */
    1469           0 :             if(krb5_address_search(context, &source->val[i], dest))
    1470           0 :                 continue;
    1471           0 :             ret = krb5_copy_address(context,
    1472           0 :                                     &source->val[i],
    1473           0 :                                     &dest->val[dest->len]);
    1474           0 :             if(ret)
    1475           0 :                 return ret;
    1476           0 :             dest->len++;
    1477             :         }
    1478             :     }
    1479           0 :     return 0;
    1480             : }
    1481             : 
    1482             : /**
    1483             :  * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port)
    1484             :  *
    1485             :  * @param context a Keberos context
    1486             :  * @param res built address from addr/port
    1487             :  * @param addr address to use
    1488             :  * @param port port to use
    1489             :  *
    1490             :  * @return Return an error code or 0.
    1491             :  *
    1492             :  * @ingroup krb5_address
    1493             :  */
    1494             : 
    1495             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1496           0 : krb5_make_addrport (krb5_context context,
    1497             :                     krb5_address **res, const krb5_address *addr, int16_t port)
    1498             : {
    1499           0 :     krb5_error_code ret;
    1500           0 :     size_t len = addr->address.length + 2 + 4 * 4;
    1501           0 :     u_char *p;
    1502             : 
    1503             :     /* XXX Make this assume port == 0 -> port is absent */
    1504             : 
    1505           0 :     *res = malloc (sizeof(**res));
    1506           0 :     if (*res == NULL)
    1507           0 :         return krb5_enomem(context);
    1508           0 :     (*res)->addr_type = KRB5_ADDRESS_ADDRPORT;
    1509           0 :     ret = krb5_data_alloc (&(*res)->address, len);
    1510           0 :     if (ret) {
    1511           0 :         free (*res);
    1512           0 :         *res = NULL;
    1513           0 :         return krb5_enomem(context);
    1514             :     }
    1515           0 :     p = (*res)->address.data;
    1516           0 :     *p++ = 0;
    1517           0 :     *p++ = 0;
    1518           0 :     *p++ = (addr->addr_type     ) & 0xFF;
    1519           0 :     *p++ = (addr->addr_type >> 8) & 0xFF;
    1520             : 
    1521           0 :     *p++ = (addr->address.length      ) & 0xFF;
    1522           0 :     *p++ = (addr->address.length >>  8) & 0xFF;
    1523           0 :     *p++ = (addr->address.length >> 16) & 0xFF;
    1524           0 :     *p++ = (addr->address.length >> 24) & 0xFF;
    1525             : 
    1526           0 :     memcpy (p, addr->address.data, addr->address.length);
    1527           0 :     p += addr->address.length;
    1528             : 
    1529           0 :     *p++ = 0;
    1530           0 :     *p++ = 0;
    1531           0 :     *p++ = (KRB5_ADDRESS_IPPORT     ) & 0xFF;
    1532           0 :     *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF;
    1533             : 
    1534           0 :     *p++ = (2      ) & 0xFF;
    1535           0 :     *p++ = (2 >>  8) & 0xFF;
    1536           0 :     *p++ = (2 >> 16) & 0xFF;
    1537           0 :     *p++ = (2 >> 24) & 0xFF;
    1538             : 
    1539           0 :     memcpy (p, &port, 2);
    1540             : 
    1541           0 :     return 0;
    1542             : }
    1543             : 
    1544             : /**
    1545             :  * Calculate the boundary addresses of `inaddr'/`prefixlen' and store
    1546             :  * them in `low' and `high'.
    1547             :  *
    1548             :  * @param context a Keberos context
    1549             :  * @param inaddr address in prefixlen that the bondery searched
    1550             :  * @param prefixlen width of boundery
    1551             :  * @param low lowest address
    1552             :  * @param high highest address
    1553             :  *
    1554             :  * @return Return an error code or 0.
    1555             :  *
    1556             :  * @ingroup krb5_address
    1557             :  */
    1558             : 
    1559             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1560           0 : krb5_address_prefixlen_boundary(krb5_context context,
    1561             :                                 const krb5_address *inaddr,
    1562             :                                 unsigned long prefixlen,
    1563             :                                 krb5_address *low,
    1564             :                                 krb5_address *high)
    1565             : {
    1566           0 :     const struct addr_operations *a = find_atype (inaddr->addr_type);
    1567           0 :     if(a != NULL && a->mask_boundary != NULL)
    1568           0 :         return (*a->mask_boundary)(context, inaddr, prefixlen, low, high);
    1569           0 :     krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
    1570           0 :                            N_("Address family %d doesn't support "
    1571             :                               "address mask operation", ""),
    1572           0 :                            inaddr->addr_type);
    1573           0 :     return KRB5_PROG_ATYPE_NOSUPP;
    1574             : }

Generated by: LCOV version 1.14