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