155682Smarkm/* 2233294Sstas * Copyright (c) 1997-2007 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "krb5_locl.h" 3555682Smarkm 3655682Smarkmstruct addr_operations { 3755682Smarkm int af; 3855682Smarkm krb5_address_type atype; 3955682Smarkm size_t max_sockaddr_size; 4055682Smarkm krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *); 4155682Smarkm krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *); 4255682Smarkm void (*addr2sockaddr)(const krb5_address *, struct sockaddr *, 43102644Snectar krb5_socklen_t *sa_size, int port); 44102644Snectar void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int); 4555682Smarkm krb5_error_code (*h_addr2addr)(const char *, krb5_address *); 4655682Smarkm krb5_boolean (*uninteresting)(const struct sockaddr *); 47233294Sstas krb5_boolean (*is_loopback)(const struct sockaddr *); 48102644Snectar void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int); 4955682Smarkm int (*print_addr)(const krb5_address *, char *, size_t); 5090926Snectar int (*parse_addr)(krb5_context, const char*, krb5_address *); 5190926Snectar int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*); 5290926Snectar int (*free_addr)(krb5_context, krb5_address*); 5390926Snectar int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*); 54233294Sstas int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long, 55233294Sstas krb5_address*, krb5_address*); 5655682Smarkm}; 5755682Smarkm 5855682Smarkm/* 5955682Smarkm * AF_INET - aka IPv4 implementation 6055682Smarkm */ 6155682Smarkm 6255682Smarkmstatic krb5_error_code 6355682Smarkmipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 6455682Smarkm{ 65178825Sdfr const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 6655682Smarkm unsigned char buf[4]; 6755682Smarkm 6855682Smarkm a->addr_type = KRB5_ADDRESS_INET; 69178825Sdfr memcpy (buf, &sin4->sin_addr, 4); 7055682Smarkm return krb5_data_copy(&a->address, buf, 4); 7155682Smarkm} 7255682Smarkm 7355682Smarkmstatic krb5_error_code 7455682Smarkmipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port) 7555682Smarkm{ 76178825Sdfr const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 7755682Smarkm 78178825Sdfr *port = sin4->sin_port; 7955682Smarkm return 0; 8055682Smarkm} 8155682Smarkm 8255682Smarkmstatic void 8355682Smarkmipv4_addr2sockaddr (const krb5_address *a, 8455682Smarkm struct sockaddr *sa, 85102644Snectar krb5_socklen_t *sa_size, 8655682Smarkm int port) 8755682Smarkm{ 88102644Snectar struct sockaddr_in tmp; 8955682Smarkm 90102644Snectar memset (&tmp, 0, sizeof(tmp)); 91102644Snectar tmp.sin_family = AF_INET; 92102644Snectar memcpy (&tmp.sin_addr, a->address.data, 4); 93102644Snectar tmp.sin_port = port; 94102644Snectar memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 95102644Snectar *sa_size = sizeof(tmp); 9655682Smarkm} 9755682Smarkm 9855682Smarkmstatic void 9955682Smarkmipv4_h_addr2sockaddr(const char *addr, 100102644Snectar struct sockaddr *sa, 101102644Snectar krb5_socklen_t *sa_size, 102102644Snectar int port) 10355682Smarkm{ 104102644Snectar struct sockaddr_in tmp; 10555682Smarkm 106102644Snectar memset (&tmp, 0, sizeof(tmp)); 107102644Snectar tmp.sin_family = AF_INET; 108102644Snectar tmp.sin_port = port; 109102644Snectar tmp.sin_addr = *((const struct in_addr *)addr); 110102644Snectar memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 111102644Snectar *sa_size = sizeof(tmp); 11255682Smarkm} 11355682Smarkm 11455682Smarkmstatic krb5_error_code 11555682Smarkmipv4_h_addr2addr (const char *addr, 11655682Smarkm krb5_address *a) 11755682Smarkm{ 11855682Smarkm unsigned char buf[4]; 11955682Smarkm 12055682Smarkm a->addr_type = KRB5_ADDRESS_INET; 12155682Smarkm memcpy(buf, addr, 4); 12255682Smarkm return krb5_data_copy(&a->address, buf, 4); 12355682Smarkm} 12455682Smarkm 12555682Smarkm/* 12655682Smarkm * Are there any addresses that should be considered `uninteresting'? 12755682Smarkm */ 12855682Smarkm 12955682Smarkmstatic krb5_boolean 13055682Smarkmipv4_uninteresting (const struct sockaddr *sa) 13155682Smarkm{ 132178825Sdfr const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 13355682Smarkm 134178825Sdfr if (sin4->sin_addr.s_addr == INADDR_ANY) 13555682Smarkm return TRUE; 13655682Smarkm 13755682Smarkm return FALSE; 13855682Smarkm} 13955682Smarkm 140233294Sstasstatic krb5_boolean 141233294Sstasipv4_is_loopback (const struct sockaddr *sa) 142233294Sstas{ 143233294Sstas const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 144233294Sstas 145233294Sstas if ((ntohl(sin4->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET) 146233294Sstas return TRUE; 147233294Sstas 148233294Sstas return FALSE; 149233294Sstas} 150233294Sstas 15155682Smarkmstatic void 152102644Snectaripv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) 15355682Smarkm{ 154102644Snectar struct sockaddr_in tmp; 15555682Smarkm 156102644Snectar memset (&tmp, 0, sizeof(tmp)); 157102644Snectar tmp.sin_family = AF_INET; 158102644Snectar tmp.sin_port = port; 159102644Snectar tmp.sin_addr.s_addr = INADDR_ANY; 160102644Snectar memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 161102644Snectar *sa_size = sizeof(tmp); 16255682Smarkm} 16355682Smarkm 16455682Smarkmstatic int 16555682Smarkmipv4_print_addr (const krb5_address *addr, char *str, size_t len) 16655682Smarkm{ 16755682Smarkm struct in_addr ia; 16855682Smarkm 16955682Smarkm memcpy (&ia, addr->address.data, 4); 17055682Smarkm 17155682Smarkm return snprintf (str, len, "IPv4:%s", inet_ntoa(ia)); 17255682Smarkm} 17355682Smarkm 17455682Smarkmstatic int 17590926Snectaripv4_parse_addr (krb5_context context, const char *address, krb5_address *addr) 17655682Smarkm{ 17755682Smarkm const char *p; 17855682Smarkm struct in_addr a; 17955682Smarkm 18055682Smarkm p = strchr(address, ':'); 18155682Smarkm if(p) { 18255682Smarkm p++; 18355682Smarkm if(strncasecmp(address, "ip:", p - address) != 0 && 18455682Smarkm strncasecmp(address, "ip4:", p - address) != 0 && 18555682Smarkm strncasecmp(address, "ipv4:", p - address) != 0 && 18655682Smarkm strncasecmp(address, "inet:", p - address) != 0) 18755682Smarkm return -1; 18855682Smarkm } else 18955682Smarkm p = address; 19055682Smarkm if(inet_aton(p, &a) == 0) 19155682Smarkm return -1; 19255682Smarkm addr->addr_type = KRB5_ADDRESS_INET; 19355682Smarkm if(krb5_data_alloc(&addr->address, 4) != 0) 19455682Smarkm return -1; 19555682Smarkm _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length); 19655682Smarkm return 0; 19755682Smarkm} 19855682Smarkm 199178825Sdfrstatic int 200178825Sdfripv4_mask_boundary(krb5_context context, const krb5_address *inaddr, 201178825Sdfr unsigned long len, krb5_address *low, krb5_address *high) 202178825Sdfr{ 203178825Sdfr unsigned long ia; 204178825Sdfr uint32_t l, h, m = 0xffffffff; 205178825Sdfr 206178825Sdfr if (len > 32) { 207233294Sstas krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 208233294Sstas N_("IPv4 prefix too large (%ld)", "len"), len); 209178825Sdfr return KRB5_PROG_ATYPE_NOSUPP; 210178825Sdfr } 211178825Sdfr m = m << (32 - len); 212178825Sdfr 213178825Sdfr _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length); 214178825Sdfr 215178825Sdfr l = ia & m; 216178825Sdfr h = l | ~m; 217178825Sdfr 218178825Sdfr low->addr_type = KRB5_ADDRESS_INET; 219178825Sdfr if(krb5_data_alloc(&low->address, 4) != 0) 220178825Sdfr return -1; 221178825Sdfr _krb5_put_int(low->address.data, l, low->address.length); 222178825Sdfr 223178825Sdfr high->addr_type = KRB5_ADDRESS_INET; 224178825Sdfr if(krb5_data_alloc(&high->address, 4) != 0) { 225178825Sdfr krb5_free_address(context, low); 226178825Sdfr return -1; 227178825Sdfr } 228178825Sdfr _krb5_put_int(high->address.data, h, high->address.length); 229178825Sdfr 230178825Sdfr return 0; 231178825Sdfr} 232178825Sdfr 233178825Sdfr 23455682Smarkm/* 23555682Smarkm * AF_INET6 - aka IPv6 implementation 23655682Smarkm */ 23755682Smarkm 23855682Smarkm#ifdef HAVE_IPV6 23955682Smarkm 24055682Smarkmstatic krb5_error_code 24155682Smarkmipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 24255682Smarkm{ 24355682Smarkm const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 24455682Smarkm 24555682Smarkm if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 24655682Smarkm unsigned char buf[4]; 24755682Smarkm 24855682Smarkm a->addr_type = KRB5_ADDRESS_INET; 24955682Smarkm#ifndef IN6_ADDR_V6_TO_V4 25055682Smarkm#ifdef IN6_EXTRACT_V4ADDR 25155682Smarkm#define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x)) 25255682Smarkm#else 25355682Smarkm#define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12]) 25455682Smarkm#endif 25555682Smarkm#endif 25655682Smarkm memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4); 25755682Smarkm return krb5_data_copy(&a->address, buf, 4); 25855682Smarkm } else { 25955682Smarkm a->addr_type = KRB5_ADDRESS_INET6; 26055682Smarkm return krb5_data_copy(&a->address, 26155682Smarkm &sin6->sin6_addr, 26255682Smarkm sizeof(sin6->sin6_addr)); 26355682Smarkm } 26455682Smarkm} 26555682Smarkm 26655682Smarkmstatic krb5_error_code 26755682Smarkmipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port) 26855682Smarkm{ 26955682Smarkm const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 27055682Smarkm 27155682Smarkm *port = sin6->sin6_port; 27255682Smarkm return 0; 27355682Smarkm} 27455682Smarkm 27555682Smarkmstatic void 27655682Smarkmipv6_addr2sockaddr (const krb5_address *a, 27755682Smarkm struct sockaddr *sa, 278102644Snectar krb5_socklen_t *sa_size, 27955682Smarkm int port) 28055682Smarkm{ 281102644Snectar struct sockaddr_in6 tmp; 28255682Smarkm 283102644Snectar memset (&tmp, 0, sizeof(tmp)); 284102644Snectar tmp.sin6_family = AF_INET6; 285102644Snectar memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr)); 286102644Snectar tmp.sin6_port = port; 287102644Snectar memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 288102644Snectar *sa_size = sizeof(tmp); 28955682Smarkm} 29055682Smarkm 29155682Smarkmstatic void 29255682Smarkmipv6_h_addr2sockaddr(const char *addr, 29355682Smarkm struct sockaddr *sa, 294102644Snectar krb5_socklen_t *sa_size, 29555682Smarkm int port) 29655682Smarkm{ 297102644Snectar struct sockaddr_in6 tmp; 29855682Smarkm 299102644Snectar memset (&tmp, 0, sizeof(tmp)); 300102644Snectar tmp.sin6_family = AF_INET6; 301102644Snectar tmp.sin6_port = port; 302102644Snectar tmp.sin6_addr = *((const struct in6_addr *)addr); 303102644Snectar memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 304102644Snectar *sa_size = sizeof(tmp); 30555682Smarkm} 30655682Smarkm 30755682Smarkmstatic krb5_error_code 30855682Smarkmipv6_h_addr2addr (const char *addr, 30955682Smarkm krb5_address *a) 31055682Smarkm{ 31155682Smarkm a->addr_type = KRB5_ADDRESS_INET6; 31255682Smarkm return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr)); 31355682Smarkm} 31455682Smarkm 31555682Smarkm/* 316233294Sstas * 31755682Smarkm */ 31855682Smarkm 31955682Smarkmstatic krb5_boolean 32055682Smarkmipv6_uninteresting (const struct sockaddr *sa) 32155682Smarkm{ 32255682Smarkm const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 32355682Smarkm const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; 324233294Sstas 325233294Sstas return IN6_IS_ADDR_LINKLOCAL(in6) 32655682Smarkm || IN6_IS_ADDR_V4COMPAT(in6); 32755682Smarkm} 32855682Smarkm 329233294Sstasstatic krb5_boolean 330233294Sstasipv6_is_loopback (const struct sockaddr *sa) 331233294Sstas{ 332233294Sstas const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 333233294Sstas const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; 334233294Sstas 335233294Sstas return (IN6_IS_ADDR_LOOPBACK(in6)); 336233294Sstas} 337233294Sstas 33855682Smarkmstatic void 339102644Snectaripv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) 34055682Smarkm{ 341102644Snectar struct sockaddr_in6 tmp; 34255682Smarkm 343102644Snectar memset (&tmp, 0, sizeof(tmp)); 344102644Snectar tmp.sin6_family = AF_INET6; 345102644Snectar tmp.sin6_port = port; 346102644Snectar tmp.sin6_addr = in6addr_any; 347102644Snectar *sa_size = sizeof(tmp); 34855682Smarkm} 34955682Smarkm 35055682Smarkmstatic int 35155682Smarkmipv6_print_addr (const krb5_address *addr, char *str, size_t len) 35255682Smarkm{ 35355682Smarkm char buf[128], buf2[3]; 35455682Smarkm if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL) 35555682Smarkm { 35655682Smarkm /* XXX this is pretty ugly, but better than abort() */ 357233294Sstas size_t i; 35855682Smarkm unsigned char *p = addr->address.data; 35955682Smarkm buf[0] = '\0'; 36055682Smarkm for(i = 0; i < addr->address.length; i++) { 36155682Smarkm snprintf(buf2, sizeof(buf2), "%02x", p[i]); 36255682Smarkm if(i > 0 && (i & 1) == 0) 36355682Smarkm strlcat(buf, ":", sizeof(buf)); 36455682Smarkm strlcat(buf, buf2, sizeof(buf)); 36555682Smarkm } 36655682Smarkm } 36755682Smarkm return snprintf(str, len, "IPv6:%s", buf); 36855682Smarkm} 36955682Smarkm 37055682Smarkmstatic int 37190926Snectaripv6_parse_addr (krb5_context context, const char *address, krb5_address *addr) 37255682Smarkm{ 37355682Smarkm int ret; 37455682Smarkm struct in6_addr in6; 37590926Snectar const char *p; 37655682Smarkm 37790926Snectar p = strchr(address, ':'); 37890926Snectar if(p) { 37990926Snectar p++; 38090926Snectar if(strncasecmp(address, "ip6:", p - address) == 0 || 38190926Snectar strncasecmp(address, "ipv6:", p - address) == 0 || 38290926Snectar strncasecmp(address, "inet6:", p - address) == 0) 38390926Snectar address = p; 38490926Snectar } 38590926Snectar 38655682Smarkm ret = inet_pton(AF_INET6, address, &in6.s6_addr); 38755682Smarkm if(ret == 1) { 38855682Smarkm addr->addr_type = KRB5_ADDRESS_INET6; 38955682Smarkm ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr)); 39055682Smarkm if (ret) 39155682Smarkm return -1; 39255682Smarkm memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr)); 39355682Smarkm return 0; 39455682Smarkm } 39555682Smarkm return -1; 39655682Smarkm} 39755682Smarkm 398178825Sdfrstatic int 399178825Sdfripv6_mask_boundary(krb5_context context, const krb5_address *inaddr, 400178825Sdfr unsigned long len, krb5_address *low, krb5_address *high) 401178825Sdfr{ 402178825Sdfr struct in6_addr addr, laddr, haddr; 403178825Sdfr uint32_t m; 404178825Sdfr int i, sub_len; 405178825Sdfr 406178825Sdfr if (len > 128) { 407233294Sstas krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 408233294Sstas N_("IPv6 prefix too large (%ld)", "length"), len); 409178825Sdfr return KRB5_PROG_ATYPE_NOSUPP; 410178825Sdfr } 411178825Sdfr 412178825Sdfr if (inaddr->address.length != sizeof(addr)) { 413233294Sstas krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 414233294Sstas N_("IPv6 addr bad length", "")); 415178825Sdfr return KRB5_PROG_ATYPE_NOSUPP; 416178825Sdfr } 417178825Sdfr 418178825Sdfr memcpy(&addr, inaddr->address.data, inaddr->address.length); 419178825Sdfr 420178825Sdfr for (i = 0; i < 16; i++) { 421178825Sdfr sub_len = min(8, len); 422178825Sdfr 423178825Sdfr m = 0xff << (8 - sub_len); 424233294Sstas 425178825Sdfr laddr.s6_addr[i] = addr.s6_addr[i] & m; 426178825Sdfr haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m; 427178825Sdfr 428178825Sdfr if (len > 8) 429178825Sdfr len -= 8; 430178825Sdfr else 431178825Sdfr len = 0; 432178825Sdfr } 433178825Sdfr 434178825Sdfr low->addr_type = KRB5_ADDRESS_INET6; 435178825Sdfr if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0) 436178825Sdfr return -1; 437178825Sdfr memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr)); 438178825Sdfr 439178825Sdfr high->addr_type = KRB5_ADDRESS_INET6; 440178825Sdfr if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) { 441178825Sdfr krb5_free_address(context, low); 442178825Sdfr return -1; 443178825Sdfr } 444178825Sdfr memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr)); 445178825Sdfr 446178825Sdfr return 0; 447178825Sdfr} 448178825Sdfr 44955682Smarkm#endif /* IPv6 */ 45055682Smarkm 451233294Sstas#ifndef HEIMDAL_SMALLER 452233294Sstas 45355682Smarkm/* 45455682Smarkm * table 45555682Smarkm */ 45655682Smarkm 45790926Snectar#define KRB5_ADDRESS_ARANGE (-100) 45890926Snectar 45990926Snectarstruct arange { 46090926Snectar krb5_address low; 46190926Snectar krb5_address high; 46290926Snectar}; 46390926Snectar 46490926Snectarstatic int 465233294Sstasarange_parse_addr (krb5_context context, 466102644Snectar const char *address, krb5_address *addr) 46790926Snectar{ 468178825Sdfr char buf[1024], *p; 469178825Sdfr krb5_address low0, high0; 47090926Snectar struct arange *a; 47190926Snectar krb5_error_code ret; 472233294Sstas 47390926Snectar if(strncasecmp(address, "RANGE:", 6) != 0) 47490926Snectar return -1; 475233294Sstas 47690926Snectar address += 6; 47790926Snectar 478178825Sdfr p = strrchr(address, '/'); 479178825Sdfr if (p) { 480178825Sdfr krb5_addresses addrmask; 481178825Sdfr char *q; 482178825Sdfr long num; 48390926Snectar 484178825Sdfr if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf)) 485178825Sdfr return -1; 486178825Sdfr buf[p - address] = '\0'; 487178825Sdfr ret = krb5_parse_address(context, buf, &addrmask); 488178825Sdfr if (ret) 489178825Sdfr return ret; 490178825Sdfr if(addrmask.len != 1) { 491178825Sdfr krb5_free_addresses(context, &addrmask); 492178825Sdfr return -1; 493178825Sdfr } 494233294Sstas 495178825Sdfr address += p - address + 1; 49690926Snectar 497178825Sdfr num = strtol(address, &q, 10); 498178825Sdfr if (q == address || *q != '\0' || num < 0) { 499178825Sdfr krb5_free_addresses(context, &addrmask); 500178825Sdfr return -1; 501178825Sdfr } 502178825Sdfr 503178825Sdfr ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num, 504178825Sdfr &low0, &high0); 505178825Sdfr krb5_free_addresses(context, &addrmask); 506178825Sdfr if (ret) 507178825Sdfr return ret; 508178825Sdfr 509178825Sdfr } else { 510178825Sdfr krb5_addresses low, high; 511233294Sstas 512178825Sdfr strsep_copy(&address, "-", buf, sizeof(buf)); 513178825Sdfr ret = krb5_parse_address(context, buf, &low); 514178825Sdfr if(ret) 515178825Sdfr return ret; 516178825Sdfr if(low.len != 1) { 517178825Sdfr krb5_free_addresses(context, &low); 518178825Sdfr return -1; 519178825Sdfr } 520233294Sstas 521178825Sdfr strsep_copy(&address, "-", buf, sizeof(buf)); 522178825Sdfr ret = krb5_parse_address(context, buf, &high); 523178825Sdfr if(ret) { 524178825Sdfr krb5_free_addresses(context, &low); 525178825Sdfr return ret; 526178825Sdfr } 527233294Sstas 528178825Sdfr if(high.len != 1 && high.val[0].addr_type != low.val[0].addr_type) { 529178825Sdfr krb5_free_addresses(context, &low); 530178825Sdfr krb5_free_addresses(context, &high); 531178825Sdfr return -1; 532178825Sdfr } 533178825Sdfr 534178825Sdfr ret = krb5_copy_address(context, &high.val[0], &high0); 535178825Sdfr if (ret == 0) { 536178825Sdfr ret = krb5_copy_address(context, &low.val[0], &low0); 537178825Sdfr if (ret) 538178825Sdfr krb5_free_address(context, &high0); 539178825Sdfr } 54090926Snectar krb5_free_addresses(context, &low); 54190926Snectar krb5_free_addresses(context, &high); 542178825Sdfr if (ret) 543178825Sdfr return ret; 54490926Snectar } 54590926Snectar 54690926Snectar krb5_data_alloc(&addr->address, sizeof(*a)); 54790926Snectar addr->addr_type = KRB5_ADDRESS_ARANGE; 54890926Snectar a = addr->address.data; 54990926Snectar 550178825Sdfr if(krb5_address_order(context, &low0, &high0) < 0) { 551178825Sdfr a->low = low0; 552178825Sdfr a->high = high0; 55390926Snectar } else { 554178825Sdfr a->low = high0; 555178825Sdfr a->high = low0; 55690926Snectar } 55790926Snectar return 0; 55890926Snectar} 55990926Snectar 56090926Snectarstatic int 56190926Snectararange_free (krb5_context context, krb5_address *addr) 56290926Snectar{ 56390926Snectar struct arange *a; 56490926Snectar a = addr->address.data; 56590926Snectar krb5_free_address(context, &a->low); 56690926Snectar krb5_free_address(context, &a->high); 567178825Sdfr krb5_data_free(&addr->address); 56890926Snectar return 0; 56990926Snectar} 57090926Snectar 57190926Snectar 57290926Snectarstatic int 573233294Sstasarange_copy (krb5_context context, const krb5_address *inaddr, 57490926Snectar krb5_address *outaddr) 57590926Snectar{ 57690926Snectar krb5_error_code ret; 57790926Snectar struct arange *i, *o; 57890926Snectar 57990926Snectar outaddr->addr_type = KRB5_ADDRESS_ARANGE; 58090926Snectar ret = krb5_data_alloc(&outaddr->address, sizeof(*o)); 58190926Snectar if(ret) 58290926Snectar return ret; 58390926Snectar i = inaddr->address.data; 58490926Snectar o = outaddr->address.data; 58590926Snectar ret = krb5_copy_address(context, &i->low, &o->low); 58690926Snectar if(ret) { 58790926Snectar krb5_data_free(&outaddr->address); 58890926Snectar return ret; 58990926Snectar } 59090926Snectar ret = krb5_copy_address(context, &i->high, &o->high); 59190926Snectar if(ret) { 59290926Snectar krb5_free_address(context, &o->low); 59390926Snectar krb5_data_free(&outaddr->address); 59490926Snectar return ret; 59590926Snectar } 59690926Snectar return 0; 59790926Snectar} 59890926Snectar 59990926Snectarstatic int 60090926Snectararange_print_addr (const krb5_address *addr, char *str, size_t len) 60190926Snectar{ 60290926Snectar struct arange *a; 60390926Snectar krb5_error_code ret; 604178825Sdfr size_t l, size, ret_len; 60590926Snectar 60690926Snectar a = addr->address.data; 60790926Snectar 60890926Snectar l = strlcpy(str, "RANGE:", len); 609178825Sdfr ret_len = l; 610178825Sdfr if (l > len) 611178825Sdfr l = len; 612178825Sdfr size = l; 613233294Sstas 614178825Sdfr ret = krb5_print_address (&a->low, str + size, len - size, &l); 615178825Sdfr if (ret) 616178825Sdfr return ret; 61790926Snectar ret_len += l; 618178825Sdfr if (len - size > l) 619178825Sdfr size += l; 620178825Sdfr else 621178825Sdfr size = len; 62290926Snectar 623178825Sdfr l = strlcat(str + size, "-", len - size); 62490926Snectar ret_len += l; 625178825Sdfr if (len - size > l) 626178825Sdfr size += l; 627178825Sdfr else 628178825Sdfr size = len; 62990926Snectar 630178825Sdfr ret = krb5_print_address (&a->high, str + size, len - size, &l); 631178825Sdfr if (ret) 632178825Sdfr return ret; 63390926Snectar ret_len += l; 63490926Snectar 63590926Snectar return ret_len; 63690926Snectar} 63790926Snectar 63890926Snectarstatic int 639233294Sstasarange_order_addr(krb5_context context, 640233294Sstas const krb5_address *addr1, 641102644Snectar const krb5_address *addr2) 64290926Snectar{ 64390926Snectar int tmp1, tmp2, sign; 64490926Snectar struct arange *a; 64590926Snectar const krb5_address *a2; 64690926Snectar 64790926Snectar if(addr1->addr_type == KRB5_ADDRESS_ARANGE) { 64890926Snectar a = addr1->address.data; 64990926Snectar a2 = addr2; 65090926Snectar sign = 1; 65190926Snectar } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) { 65290926Snectar a = addr2->address.data; 65390926Snectar a2 = addr1; 65490926Snectar sign = -1; 655233294Sstas } else { 65690926Snectar abort(); 657233294Sstas UNREACHABLE(return 0); 658233294Sstas } 659233294Sstas 66090926Snectar if(a2->addr_type == KRB5_ADDRESS_ARANGE) { 66190926Snectar struct arange *b = a2->address.data; 66290926Snectar tmp1 = krb5_address_order(context, &a->low, &b->low); 66390926Snectar if(tmp1 != 0) 66490926Snectar return sign * tmp1; 66590926Snectar return sign * krb5_address_order(context, &a->high, &b->high); 66690926Snectar } else if(a2->addr_type == a->low.addr_type) { 66790926Snectar tmp1 = krb5_address_order(context, &a->low, a2); 66890926Snectar if(tmp1 > 0) 66990926Snectar return sign; 67090926Snectar tmp2 = krb5_address_order(context, &a->high, a2); 67190926Snectar if(tmp2 < 0) 67290926Snectar return -sign; 67390926Snectar return 0; 67490926Snectar } else { 67590926Snectar return sign * (addr1->addr_type - addr2->addr_type); 67690926Snectar } 67790926Snectar} 67890926Snectar 679233294Sstas#endif /* HEIMDAL_SMALLER */ 680233294Sstas 681120945Snectarstatic int 682120945Snectaraddrport_print_addr (const krb5_address *addr, char *str, size_t len) 683120945Snectar{ 684178825Sdfr krb5_error_code ret; 685120945Snectar krb5_address addr1, addr2; 686120945Snectar uint16_t port = 0; 687178825Sdfr size_t ret_len = 0, l, size = 0; 688178825Sdfr krb5_storage *sp; 689178825Sdfr 690178825Sdfr sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address)); 691233294Sstas if (sp == NULL) 692233294Sstas return ENOMEM; 693233294Sstas 694120945Snectar /* for totally obscure reasons, these are not in network byteorder */ 695120945Snectar krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 696120945Snectar 697120945Snectar krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */ 698120945Snectar krb5_ret_address(sp, &addr1); 699120945Snectar 700120945Snectar krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */ 701120945Snectar krb5_ret_address(sp, &addr2); 702120945Snectar krb5_storage_free(sp); 703120945Snectar if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) { 704120945Snectar unsigned long value; 705120945Snectar _krb5_get_int(addr2.address.data, &value, 2); 706120945Snectar port = value; 707120945Snectar } 708120945Snectar l = strlcpy(str, "ADDRPORT:", len); 709120945Snectar ret_len += l; 710178825Sdfr if (len > l) 711178825Sdfr size += l; 712178825Sdfr else 713178825Sdfr size = len; 714178825Sdfr 715178825Sdfr ret = krb5_print_address(&addr1, str + size, len - size, &l); 716178825Sdfr if (ret) 717178825Sdfr return ret; 718120945Snectar ret_len += l; 719178825Sdfr if (len - size > l) 720178825Sdfr size += l; 721178825Sdfr else 722178825Sdfr size = len; 723178825Sdfr 724178825Sdfr ret = snprintf(str + size, len - size, ",PORT=%u", port); 725178825Sdfr if (ret < 0) 726178825Sdfr return EINVAL; 727178825Sdfr ret_len += ret; 728120945Snectar return ret_len; 729120945Snectar} 730120945Snectar 73155682Smarkmstatic struct addr_operations at[] = { 732233294Sstas { 733233294Sstas AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), 734233294Sstas ipv4_sockaddr2addr, 735233294Sstas ipv4_sockaddr2port, 736233294Sstas ipv4_addr2sockaddr, 737233294Sstas ipv4_h_addr2sockaddr, 738233294Sstas ipv4_h_addr2addr, 739233294Sstas ipv4_uninteresting, 740233294Sstas ipv4_is_loopback, 741233294Sstas ipv4_anyaddr, 742233294Sstas ipv4_print_addr, 743233294Sstas ipv4_parse_addr, 744233294Sstas NULL, 745233294Sstas NULL, 746233294Sstas NULL, 747233294Sstas ipv4_mask_boundary 748233294Sstas }, 74955682Smarkm#ifdef HAVE_IPV6 750233294Sstas { 751233294Sstas AF_INET6, KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6), 752233294Sstas ipv6_sockaddr2addr, 753233294Sstas ipv6_sockaddr2port, 754233294Sstas ipv6_addr2sockaddr, 755233294Sstas ipv6_h_addr2sockaddr, 756233294Sstas ipv6_h_addr2addr, 757233294Sstas ipv6_uninteresting, 758233294Sstas ipv6_is_loopback, 759233294Sstas ipv6_anyaddr, 760233294Sstas ipv6_print_addr, 761233294Sstas ipv6_parse_addr, 762233294Sstas NULL, 763233294Sstas NULL, 764233294Sstas NULL, 765233294Sstas ipv6_mask_boundary 766233294Sstas } , 76755682Smarkm#endif 768233294Sstas#ifndef HEIMDAL_SMALLER 76990926Snectar /* fake address type */ 770233294Sstas { 771233294Sstas KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange), 772233294Sstas NULL, 773233294Sstas NULL, 774233294Sstas NULL, 775233294Sstas NULL, 776233294Sstas NULL, 777233294Sstas NULL, 778233294Sstas NULL, 779233294Sstas NULL, 780233294Sstas arange_print_addr, 781233294Sstas arange_parse_addr, 782233294Sstas arange_order_addr, 783233294Sstas arange_free, 784233294Sstas arange_copy, 785233294Sstas NULL 786233294Sstas }, 787233294Sstas#endif 788233294Sstas { 789233294Sstas KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0, 790233294Sstas NULL, 791233294Sstas NULL, 792233294Sstas NULL, 793233294Sstas NULL, 794233294Sstas NULL, 795233294Sstas NULL, 796233294Sstas NULL, 797233294Sstas NULL, 798233294Sstas addrport_print_addr, 799233294Sstas NULL, 800233294Sstas NULL, 801233294Sstas NULL, 802233294Sstas NULL 803233294Sstas } 80455682Smarkm}; 80555682Smarkm 80655682Smarkmstatic int num_addrs = sizeof(at) / sizeof(at[0]); 80755682Smarkm 80855682Smarkmstatic size_t max_sockaddr_size = 0; 80955682Smarkm 81055682Smarkm/* 81155682Smarkm * generic functions 81255682Smarkm */ 81355682Smarkm 81455682Smarkmstatic struct addr_operations * 81555682Smarkmfind_af(int af) 81655682Smarkm{ 81755682Smarkm struct addr_operations *a; 81855682Smarkm 81955682Smarkm for (a = at; a < at + num_addrs; ++a) 82055682Smarkm if (af == a->af) 82155682Smarkm return a; 82255682Smarkm return NULL; 82355682Smarkm} 82455682Smarkm 82555682Smarkmstatic struct addr_operations * 826233294Sstasfind_atype(krb5_address_type atype) 82755682Smarkm{ 82855682Smarkm struct addr_operations *a; 82955682Smarkm 83055682Smarkm for (a = at; a < at + num_addrs; ++a) 83155682Smarkm if (atype == a->atype) 83255682Smarkm return a; 83355682Smarkm return NULL; 83455682Smarkm} 83555682Smarkm 836178825Sdfr/** 837178825Sdfr * krb5_sockaddr2address stores a address a "struct sockaddr" sa in 838233294Sstas * the krb5_address addr. 839178825Sdfr * 840178825Sdfr * @param context a Keberos context 841178825Sdfr * @param sa a struct sockaddr to extract the address from 842178825Sdfr * @param addr an Kerberos 5 address to store the address in. 843178825Sdfr * 844178825Sdfr * @return Return an error code or 0. 845178825Sdfr * 846178825Sdfr * @ingroup krb5_address 847178825Sdfr */ 848178825Sdfr 849233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 85078527Sassarkrb5_sockaddr2address (krb5_context context, 85178527Sassar const struct sockaddr *sa, krb5_address *addr) 85255682Smarkm{ 85355682Smarkm struct addr_operations *a = find_af(sa->sa_family); 85478527Sassar if (a == NULL) { 855233294Sstas krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 856233294Sstas N_("Address family %d not supported", ""), 857233294Sstas sa->sa_family); 85855682Smarkm return KRB5_PROG_ATYPE_NOSUPP; 85978527Sassar } 86055682Smarkm return (*a->sockaddr2addr)(sa, addr); 86155682Smarkm} 86255682Smarkm 863178825Sdfr/** 864178825Sdfr * krb5_sockaddr2port extracts a port (if possible) from a "struct 865178825Sdfr * sockaddr. 866178825Sdfr * 867178825Sdfr * @param context a Keberos context 868178825Sdfr * @param sa a struct sockaddr to extract the port from 869178825Sdfr * @param port a pointer to an int16_t store the port in. 870178825Sdfr * 871178825Sdfr * @return Return an error code or 0. Will return 872178825Sdfr * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 873178825Sdfr * 874178825Sdfr * @ingroup krb5_address 875178825Sdfr */ 876178825Sdfr 877233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 87878527Sassarkrb5_sockaddr2port (krb5_context context, 87978527Sassar const struct sockaddr *sa, int16_t *port) 88055682Smarkm{ 88155682Smarkm struct addr_operations *a = find_af(sa->sa_family); 88278527Sassar if (a == NULL) { 883233294Sstas krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 884233294Sstas N_("Address family %d not supported", ""), 885233294Sstas sa->sa_family); 88655682Smarkm return KRB5_PROG_ATYPE_NOSUPP; 88778527Sassar } 88855682Smarkm return (*a->sockaddr2port)(sa, port); 88955682Smarkm} 89055682Smarkm 891178825Sdfr/** 892178825Sdfr * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr 893178825Sdfr * and port. The argument sa_size should initially contain the size of 894178825Sdfr * the sa and after the call, it will contain the actual length of the 895178825Sdfr * address. In case of the sa is too small to fit the whole address, 896178825Sdfr * the up to *sa_size will be stored, and then *sa_size will be set to 897178825Sdfr * the required length. 898178825Sdfr * 899178825Sdfr * @param context a Keberos context 900178825Sdfr * @param addr the address to copy the from 901178825Sdfr * @param sa the struct sockaddr that will be filled in 902178825Sdfr * @param sa_size pointer to length of sa, and after the call, it will 903178825Sdfr * contain the actual length of the address. 904178825Sdfr * @param port set port in sa. 905178825Sdfr * 906178825Sdfr * @return Return an error code or 0. Will return 907178825Sdfr * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 908178825Sdfr * 909178825Sdfr * @ingroup krb5_address 910178825Sdfr */ 911178825Sdfr 912233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 91378527Sassarkrb5_addr2sockaddr (krb5_context context, 91478527Sassar const krb5_address *addr, 91555682Smarkm struct sockaddr *sa, 916102644Snectar krb5_socklen_t *sa_size, 91755682Smarkm int port) 91855682Smarkm{ 91955682Smarkm struct addr_operations *a = find_atype(addr->addr_type); 92055682Smarkm 92178527Sassar if (a == NULL) { 922233294Sstas krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 923233294Sstas N_("Address type %d not supported", 924233294Sstas "krb5_address type"), 925233294Sstas addr->addr_type); 92655682Smarkm return KRB5_PROG_ATYPE_NOSUPP; 92778527Sassar } 92890926Snectar if (a->addr2sockaddr == NULL) { 929233294Sstas krb5_set_error_message (context, 930233294Sstas KRB5_PROG_ATYPE_NOSUPP, 931233294Sstas N_("Can't convert address type %d to sockaddr", ""), 932233294Sstas addr->addr_type); 93390926Snectar return KRB5_PROG_ATYPE_NOSUPP; 93490926Snectar } 93555682Smarkm (*a->addr2sockaddr)(addr, sa, sa_size, port); 93655682Smarkm return 0; 93755682Smarkm} 93855682Smarkm 939178825Sdfr/** 940178825Sdfr * krb5_max_sockaddr_size returns the max size of the .Li struct 941178825Sdfr * sockaddr that the Kerberos library will return. 942178825Sdfr * 943178825Sdfr * @return Return an size_t of the maximum struct sockaddr. 944178825Sdfr * 945178825Sdfr * @ingroup krb5_address 946178825Sdfr */ 947178825Sdfr 948233294SstasKRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 94955682Smarkmkrb5_max_sockaddr_size (void) 95055682Smarkm{ 95155682Smarkm if (max_sockaddr_size == 0) { 95255682Smarkm struct addr_operations *a; 95355682Smarkm 95455682Smarkm for(a = at; a < at + num_addrs; ++a) 95555682Smarkm max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size); 95655682Smarkm } 95755682Smarkm return max_sockaddr_size; 95855682Smarkm} 95955682Smarkm 960178825Sdfr/** 961178825Sdfr * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the 962178825Sdfr * kerberos library thinks are uninteresting. One example are link 963178825Sdfr * local addresses. 964178825Sdfr * 965178825Sdfr * @param sa pointer to struct sockaddr that might be interesting. 966178825Sdfr * 967178825Sdfr * @return Return a non zero for uninteresting addresses. 968178825Sdfr * 969178825Sdfr * @ingroup krb5_address 970178825Sdfr */ 971178825Sdfr 972233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 97355682Smarkmkrb5_sockaddr_uninteresting(const struct sockaddr *sa) 97455682Smarkm{ 97555682Smarkm struct addr_operations *a = find_af(sa->sa_family); 97690926Snectar if (a == NULL || a->uninteresting == NULL) 97755682Smarkm return TRUE; 97855682Smarkm return (*a->uninteresting)(sa); 97955682Smarkm} 98055682Smarkm 981233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 982233294Sstaskrb5_sockaddr_is_loopback(const struct sockaddr *sa) 983233294Sstas{ 984233294Sstas struct addr_operations *a = find_af(sa->sa_family); 985233294Sstas if (a == NULL || a->is_loopback == NULL) 986233294Sstas return TRUE; 987233294Sstas return (*a->is_loopback)(sa); 988233294Sstas} 989233294Sstas 990178825Sdfr/** 991178825Sdfr * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and 992178825Sdfr * the "struct hostent" (see gethostbyname(3) ) h_addr_list 993178825Sdfr * component. The argument sa_size should initially contain the size 994178825Sdfr * of the sa, and after the call, it will contain the actual length of 995178825Sdfr * the address. 996178825Sdfr * 997178825Sdfr * @param context a Keberos context 998178825Sdfr * @param af addresses 999178825Sdfr * @param addr address 1000178825Sdfr * @param sa returned struct sockaddr 1001178825Sdfr * @param sa_size size of sa 1002178825Sdfr * @param port port to set in sa. 1003178825Sdfr * 1004178825Sdfr * @return Return an error code or 0. 1005178825Sdfr * 1006178825Sdfr * @ingroup krb5_address 1007178825Sdfr */ 1008178825Sdfr 1009233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 101078527Sassarkrb5_h_addr2sockaddr (krb5_context context, 101178527Sassar int af, 1012102644Snectar const char *addr, struct sockaddr *sa, 1013102644Snectar krb5_socklen_t *sa_size, 101455682Smarkm int port) 101555682Smarkm{ 101655682Smarkm struct addr_operations *a = find_af(af); 101778527Sassar if (a == NULL) { 1018233294Sstas krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1019233294Sstas "Address family %d not supported", af); 102055682Smarkm return KRB5_PROG_ATYPE_NOSUPP; 102178527Sassar } 102255682Smarkm (*a->h_addr2sockaddr)(addr, sa, sa_size, port); 102355682Smarkm return 0; 102455682Smarkm} 102555682Smarkm 1026178825Sdfr/** 1027178825Sdfr * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception 1028178825Sdfr * that it operates on a krb5_address instead of a struct sockaddr. 1029178825Sdfr * 1030178825Sdfr * @param context a Keberos context 1031178825Sdfr * @param af address family 1032178825Sdfr * @param haddr host address from struct hostent. 1033178825Sdfr * @param addr returned krb5_address. 1034178825Sdfr * 1035178825Sdfr * @return Return an error code or 0. 1036178825Sdfr * 1037178825Sdfr * @ingroup krb5_address 1038178825Sdfr */ 1039178825Sdfr 1040233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 104178527Sassarkrb5_h_addr2addr (krb5_context context, 104278527Sassar int af, 104355682Smarkm const char *haddr, krb5_address *addr) 104455682Smarkm{ 104555682Smarkm struct addr_operations *a = find_af(af); 104678527Sassar if (a == NULL) { 1047233294Sstas krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1048233294Sstas N_("Address family %d not supported", ""), af); 104955682Smarkm return KRB5_PROG_ATYPE_NOSUPP; 105078527Sassar } 105155682Smarkm return (*a->h_addr2addr)(haddr, addr); 105255682Smarkm} 105355682Smarkm 1054178825Sdfr/** 1055178825Sdfr * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to 1056178825Sdfr * bind(2) to. The argument sa_size should initially contain the size 1057178825Sdfr * of the sa, and after the call, it will contain the actual length 1058178825Sdfr * of the address. 1059178825Sdfr * 1060178825Sdfr * @param context a Keberos context 1061178825Sdfr * @param af address family 1062178825Sdfr * @param sa sockaddr 1063178825Sdfr * @param sa_size lenght of sa. 1064178825Sdfr * @param port for to fill into sa. 1065178825Sdfr * 1066178825Sdfr * @return Return an error code or 0. 1067178825Sdfr * 1068178825Sdfr * @ingroup krb5_address 1069178825Sdfr */ 1070178825Sdfr 1071233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 107278527Sassarkrb5_anyaddr (krb5_context context, 107378527Sassar int af, 107455682Smarkm struct sockaddr *sa, 1075102644Snectar krb5_socklen_t *sa_size, 107655682Smarkm int port) 107755682Smarkm{ 107855682Smarkm struct addr_operations *a = find_af (af); 107955682Smarkm 108078527Sassar if (a == NULL) { 1081233294Sstas krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1082233294Sstas N_("Address family %d not supported", ""), af); 108355682Smarkm return KRB5_PROG_ATYPE_NOSUPP; 108478527Sassar } 108555682Smarkm 108655682Smarkm (*a->anyaddr)(sa, sa_size, port); 108755682Smarkm return 0; 108855682Smarkm} 108955682Smarkm 1090178825Sdfr/** 1091178825Sdfr * krb5_print_address prints the address in addr to the string string 1092178825Sdfr * that have the length len. If ret_len is not NULL, it will be filled 1093178825Sdfr * with the length of the string if size were unlimited (not including 1094178825Sdfr * the final NUL) . 1095178825Sdfr * 1096178825Sdfr * @param addr address to be printed 1097178825Sdfr * @param str pointer string to print the address into 1098178825Sdfr * @param len length that will fit into area pointed to by "str". 1099178825Sdfr * @param ret_len return length the str. 1100178825Sdfr * 1101178825Sdfr * @return Return an error code or 0. 1102178825Sdfr * 1103178825Sdfr * @ingroup krb5_address 1104178825Sdfr */ 1105178825Sdfr 1106233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1107233294Sstaskrb5_print_address (const krb5_address *addr, 110855682Smarkm char *str, size_t len, size_t *ret_len) 110955682Smarkm{ 111055682Smarkm struct addr_operations *a = find_atype(addr->addr_type); 1111178825Sdfr int ret; 111255682Smarkm 1113120945Snectar if (a == NULL || a->print_addr == NULL) { 111455682Smarkm char *s; 111590926Snectar int l; 1116233294Sstas size_t i; 111790926Snectar 111855682Smarkm s = str; 111955682Smarkm l = snprintf(s, len, "TYPE_%d:", addr->addr_type); 1120233294Sstas if (l < 0 || (size_t)l >= len) 112190926Snectar return EINVAL; 112255682Smarkm s += l; 112390926Snectar len -= l; 112455682Smarkm for(i = 0; i < addr->address.length; i++) { 112555682Smarkm l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); 1126233294Sstas if (l < 0 || (size_t)l >= len) 112790926Snectar return EINVAL; 112855682Smarkm len -= l; 112955682Smarkm s += l; 113055682Smarkm } 1131102644Snectar if(ret_len != NULL) 1132102644Snectar *ret_len = s - str; 113355682Smarkm return 0; 113455682Smarkm } 1135102644Snectar ret = (*a->print_addr)(addr, str, len); 1136178825Sdfr if (ret < 0) 1137178825Sdfr return EINVAL; 1138102644Snectar if(ret_len != NULL) 1139102644Snectar *ret_len = ret; 114055682Smarkm return 0; 114155682Smarkm} 114255682Smarkm 1143178825Sdfr/** 1144178825Sdfr * krb5_parse_address returns the resolved hostname in string to the 1145178825Sdfr * krb5_addresses addresses . 1146178825Sdfr * 1147178825Sdfr * @param context a Keberos context 1148178825Sdfr * @param string 1149178825Sdfr * @param addresses 1150178825Sdfr * 1151178825Sdfr * @return Return an error code or 0. 1152178825Sdfr * 1153178825Sdfr * @ingroup krb5_address 1154178825Sdfr */ 1155178825Sdfr 1156233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 115755682Smarkmkrb5_parse_address(krb5_context context, 115855682Smarkm const char *string, 115955682Smarkm krb5_addresses *addresses) 116055682Smarkm{ 116155682Smarkm int i, n; 116255682Smarkm struct addrinfo *ai, *a; 116355682Smarkm int error; 116478527Sassar int save_errno; 116555682Smarkm 1166178825Sdfr addresses->len = 0; 1167178825Sdfr addresses->val = NULL; 1168178825Sdfr 116955682Smarkm for(i = 0; i < num_addrs; i++) { 117055682Smarkm if(at[i].parse_addr) { 1171102644Snectar krb5_address addr; 1172102644Snectar if((*at[i].parse_addr)(context, string, &addr) == 0) { 117355682Smarkm ALLOC_SEQ(addresses, 1); 1174178825Sdfr if (addresses->val == NULL) { 1175233294Sstas krb5_set_error_message(context, ENOMEM, 1176233294Sstas N_("malloc: out of memory", "")); 1177178825Sdfr return ENOMEM; 1178178825Sdfr } 1179102644Snectar addresses->val[0] = addr; 118055682Smarkm return 0; 118155682Smarkm } 118255682Smarkm } 118355682Smarkm } 118455682Smarkm 118555682Smarkm error = getaddrinfo (string, NULL, NULL, &ai); 118678527Sassar if (error) { 1187233294Sstas krb5_error_code ret2; 118878527Sassar save_errno = errno; 1189233294Sstas ret2 = krb5_eai_to_heim_errno(error, save_errno); 1190233294Sstas krb5_set_error_message (context, ret2, "%s: %s", 1191233294Sstas string, gai_strerror(error)); 1192233294Sstas return ret2; 119378527Sassar } 1194233294Sstas 119555682Smarkm n = 0; 119655682Smarkm for (a = ai; a != NULL; a = a->ai_next) 119755682Smarkm ++n; 119855682Smarkm 119955682Smarkm ALLOC_SEQ(addresses, n); 1200178825Sdfr if (addresses->val == NULL) { 1201233294Sstas krb5_set_error_message(context, ENOMEM, 1202233294Sstas N_("malloc: out of memory", "")); 1203178825Sdfr freeaddrinfo(ai); 1204178825Sdfr return ENOMEM; 1205178825Sdfr } 120655682Smarkm 1207178825Sdfr addresses->len = 0; 1208102644Snectar for (a = ai, i = 0; a != NULL; a = a->ai_next) { 1209178825Sdfr if (krb5_sockaddr2address (context, ai->ai_addr, &addresses->val[i])) 1210178825Sdfr continue; 1211233294Sstas if(krb5_address_search(context, &addresses->val[i], addresses)) { 1212233294Sstas krb5_free_address(context, &addresses->val[i]); 1213178825Sdfr continue; 1214233294Sstas } 1215233294Sstas i++; 1216178825Sdfr addresses->len = i; 121755682Smarkm } 121855682Smarkm freeaddrinfo (ai); 121955682Smarkm return 0; 122055682Smarkm} 122190926Snectar 1222178825Sdfr/** 1223178825Sdfr * krb5_address_order compares the addresses addr1 and addr2 so that 1224178825Sdfr * it can be used for sorting addresses. If the addresses are the same 1225233294Sstas * address krb5_address_order will return 0. Behavies like memcmp(2). 1226178825Sdfr * 1227178825Sdfr * @param context a Keberos context 1228178825Sdfr * @param addr1 krb5_address to compare 1229178825Sdfr * @param addr2 krb5_address to compare 1230178825Sdfr * 1231178825Sdfr * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and 1232178825Sdfr * addr2 is the same address, > 0 if addr2 is "less" then addr1. 1233178825Sdfr * 1234178825Sdfr * @ingroup krb5_address 1235178825Sdfr */ 1236178825Sdfr 1237233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL 123890926Snectarkrb5_address_order(krb5_context context, 123990926Snectar const krb5_address *addr1, 124090926Snectar const krb5_address *addr2) 124190926Snectar{ 124290926Snectar /* this sucks; what if both addresses have order functions, which 124390926Snectar should we call? this works for now, though */ 124490926Snectar struct addr_operations *a; 1245233294Sstas a = find_atype(addr1->addr_type); 124690926Snectar if(a == NULL) { 1247233294Sstas krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1248233294Sstas N_("Address family %d not supported", ""), 1249233294Sstas addr1->addr_type); 125090926Snectar return KRB5_PROG_ATYPE_NOSUPP; 125190926Snectar } 1252233294Sstas if(a->order_addr != NULL) 1253233294Sstas return (*a->order_addr)(context, addr1, addr2); 1254233294Sstas a = find_atype(addr2->addr_type); 125590926Snectar if(a == NULL) { 1256233294Sstas krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1257233294Sstas N_("Address family %d not supported", ""), 1258233294Sstas addr2->addr_type); 125990926Snectar return KRB5_PROG_ATYPE_NOSUPP; 126090926Snectar } 1261233294Sstas if(a->order_addr != NULL) 126290926Snectar return (*a->order_addr)(context, addr1, addr2); 126390926Snectar 126490926Snectar if(addr1->addr_type != addr2->addr_type) 126590926Snectar return addr1->addr_type - addr2->addr_type; 126690926Snectar if(addr1->address.length != addr2->address.length) 126790926Snectar return addr1->address.length - addr2->address.length; 126890926Snectar return memcmp (addr1->address.data, 126990926Snectar addr2->address.data, 127090926Snectar addr1->address.length); 127190926Snectar} 127290926Snectar 1273178825Sdfr/** 1274178825Sdfr * krb5_address_compare compares the addresses addr1 and addr2. 1275178825Sdfr * Returns TRUE if the two addresses are the same. 1276178825Sdfr * 1277178825Sdfr * @param context a Keberos context 1278178825Sdfr * @param addr1 address to compare 1279178825Sdfr * @param addr2 address to compare 1280178825Sdfr * 1281178825Sdfr * @return Return an TRUE is the address are the same FALSE if not 1282178825Sdfr * 1283178825Sdfr * @ingroup krb5_address 1284178825Sdfr */ 1285178825Sdfr 1286233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 128790926Snectarkrb5_address_compare(krb5_context context, 128890926Snectar const krb5_address *addr1, 128990926Snectar const krb5_address *addr2) 129090926Snectar{ 129190926Snectar return krb5_address_order (context, addr1, addr2) == 0; 129290926Snectar} 129390926Snectar 1294178825Sdfr/** 1295178825Sdfr * krb5_address_search checks if the address addr is a member of the 1296178825Sdfr * address set list addrlist . 1297178825Sdfr * 1298178825Sdfr * @param context a Keberos context. 1299178825Sdfr * @param addr address to search for. 1300178825Sdfr * @param addrlist list of addresses to look in for addr. 1301178825Sdfr * 1302178825Sdfr * @return Return an error code or 0. 1303178825Sdfr * 1304178825Sdfr * @ingroup krb5_address 1305178825Sdfr */ 1306178825Sdfr 1307233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 130890926Snectarkrb5_address_search(krb5_context context, 130990926Snectar const krb5_address *addr, 131090926Snectar const krb5_addresses *addrlist) 131190926Snectar{ 1312233294Sstas size_t i; 131390926Snectar 131490926Snectar for (i = 0; i < addrlist->len; ++i) 131590926Snectar if (krb5_address_compare (context, addr, &addrlist->val[i])) 131690926Snectar return TRUE; 131790926Snectar return FALSE; 131890926Snectar} 131990926Snectar 1320178825Sdfr/** 1321178825Sdfr * krb5_free_address frees the data stored in the address that is 1322178825Sdfr * alloced with any of the krb5_address functions. 1323178825Sdfr * 1324178825Sdfr * @param context a Keberos context 1325178825Sdfr * @param address addresss to be freed. 1326178825Sdfr * 1327178825Sdfr * @return Return an error code or 0. 1328178825Sdfr * 1329178825Sdfr * @ingroup krb5_address 1330178825Sdfr */ 1331178825Sdfr 1332233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 133390926Snectarkrb5_free_address(krb5_context context, 133490926Snectar krb5_address *address) 133590926Snectar{ 1336178825Sdfr struct addr_operations *a = find_atype (address->addr_type); 133790926Snectar if(a != NULL && a->free_addr != NULL) 133890926Snectar return (*a->free_addr)(context, address); 133990926Snectar krb5_data_free (&address->address); 1340178825Sdfr memset(address, 0, sizeof(*address)); 134190926Snectar return 0; 134290926Snectar} 134390926Snectar 1344178825Sdfr/** 1345178825Sdfr * krb5_free_addresses frees the data stored in the address that is 1346178825Sdfr * alloced with any of the krb5_address functions. 1347178825Sdfr * 1348178825Sdfr * @param context a Keberos context 1349178825Sdfr * @param addresses addressses to be freed. 1350178825Sdfr * 1351178825Sdfr * @return Return an error code or 0. 1352178825Sdfr * 1353178825Sdfr * @ingroup krb5_address 1354178825Sdfr */ 1355178825Sdfr 1356233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 135790926Snectarkrb5_free_addresses(krb5_context context, 135890926Snectar krb5_addresses *addresses) 135990926Snectar{ 1360233294Sstas size_t i; 136190926Snectar for(i = 0; i < addresses->len; i++) 136290926Snectar krb5_free_address(context, &addresses->val[i]); 136390926Snectar free(addresses->val); 1364178825Sdfr addresses->len = 0; 1365178825Sdfr addresses->val = NULL; 136690926Snectar return 0; 136790926Snectar} 136890926Snectar 1369178825Sdfr/** 1370178825Sdfr * krb5_copy_address copies the content of address 1371178825Sdfr * inaddr to outaddr. 1372178825Sdfr * 1373178825Sdfr * @param context a Keberos context 1374178825Sdfr * @param inaddr pointer to source address 1375178825Sdfr * @param outaddr pointer to destination address 1376178825Sdfr * 1377178825Sdfr * @return Return an error code or 0. 1378178825Sdfr * 1379178825Sdfr * @ingroup krb5_address 1380178825Sdfr */ 1381178825Sdfr 1382233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 138390926Snectarkrb5_copy_address(krb5_context context, 138490926Snectar const krb5_address *inaddr, 138590926Snectar krb5_address *outaddr) 138690926Snectar{ 138790926Snectar struct addr_operations *a = find_af (inaddr->addr_type); 138890926Snectar if(a != NULL && a->copy_addr != NULL) 138990926Snectar return (*a->copy_addr)(context, inaddr, outaddr); 139090926Snectar return copy_HostAddress(inaddr, outaddr); 139190926Snectar} 139290926Snectar 1393178825Sdfr/** 1394178825Sdfr * krb5_copy_addresses copies the content of addresses 1395178825Sdfr * inaddr to outaddr. 1396178825Sdfr * 1397178825Sdfr * @param context a Keberos context 1398178825Sdfr * @param inaddr pointer to source addresses 1399178825Sdfr * @param outaddr pointer to destination addresses 1400178825Sdfr * 1401178825Sdfr * @return Return an error code or 0. 1402178825Sdfr * 1403178825Sdfr * @ingroup krb5_address 1404178825Sdfr */ 1405178825Sdfr 1406233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 140790926Snectarkrb5_copy_addresses(krb5_context context, 140890926Snectar const krb5_addresses *inaddr, 140990926Snectar krb5_addresses *outaddr) 141090926Snectar{ 1411233294Sstas size_t i; 141290926Snectar ALLOC_SEQ(outaddr, inaddr->len); 141390926Snectar if(inaddr->len > 0 && outaddr->val == NULL) 141490926Snectar return ENOMEM; 141590926Snectar for(i = 0; i < inaddr->len; i++) 141690926Snectar krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]); 141790926Snectar return 0; 141890926Snectar} 141990926Snectar 1420178825Sdfr/** 1421178825Sdfr * krb5_append_addresses adds the set of addresses in source to 1422178825Sdfr * dest. While copying the addresses, duplicates are also sorted out. 1423178825Sdfr * 1424178825Sdfr * @param context a Keberos context 1425178825Sdfr * @param dest destination of copy operation 1426178825Sdfr * @param source adresses that are going to be added to dest 1427178825Sdfr * 1428178825Sdfr * @return Return an error code or 0. 1429178825Sdfr * 1430178825Sdfr * @ingroup krb5_address 1431178825Sdfr */ 1432178825Sdfr 1433233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 143490926Snectarkrb5_append_addresses(krb5_context context, 143590926Snectar krb5_addresses *dest, 143690926Snectar const krb5_addresses *source) 143790926Snectar{ 143890926Snectar krb5_address *tmp; 143990926Snectar krb5_error_code ret; 1440233294Sstas size_t i; 144190926Snectar if(source->len > 0) { 144290926Snectar tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp)); 144390926Snectar if(tmp == NULL) { 1444233294Sstas krb5_set_error_message (context, ENOMEM, 1445233294Sstas N_("malloc: out of memory", "")); 144690926Snectar return ENOMEM; 144790926Snectar } 144890926Snectar dest->val = tmp; 144990926Snectar for(i = 0; i < source->len; i++) { 145090926Snectar /* skip duplicates */ 145190926Snectar if(krb5_address_search(context, &source->val[i], dest)) 145290926Snectar continue; 1453233294Sstas ret = krb5_copy_address(context, 1454233294Sstas &source->val[i], 145590926Snectar &dest->val[dest->len]); 145690926Snectar if(ret) 145790926Snectar return ret; 145890926Snectar dest->len++; 145990926Snectar } 146090926Snectar } 146190926Snectar return 0; 146290926Snectar} 146390926Snectar 1464178825Sdfr/** 146590926Snectar * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port) 1466178825Sdfr * 1467178825Sdfr * @param context a Keberos context 1468178825Sdfr * @param res built address from addr/port 1469178825Sdfr * @param addr address to use 1470178825Sdfr * @param port port to use 1471178825Sdfr * 1472178825Sdfr * @return Return an error code or 0. 1473178825Sdfr * 1474178825Sdfr * @ingroup krb5_address 147590926Snectar */ 147690926Snectar 1477233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 147890926Snectarkrb5_make_addrport (krb5_context context, 147990926Snectar krb5_address **res, const krb5_address *addr, int16_t port) 148090926Snectar{ 148190926Snectar krb5_error_code ret; 148290926Snectar size_t len = addr->address.length + 2 + 4 * 4; 148390926Snectar u_char *p; 148490926Snectar 148590926Snectar *res = malloc (sizeof(**res)); 148690926Snectar if (*res == NULL) { 1487233294Sstas krb5_set_error_message (context, ENOMEM, 1488233294Sstas N_("malloc: out of memory", "")); 148990926Snectar return ENOMEM; 149090926Snectar } 149190926Snectar (*res)->addr_type = KRB5_ADDRESS_ADDRPORT; 149290926Snectar ret = krb5_data_alloc (&(*res)->address, len); 149390926Snectar if (ret) { 1494233294Sstas krb5_set_error_message (context, ret, 1495233294Sstas N_("malloc: out of memory", "")); 149690926Snectar free (*res); 1497178825Sdfr *res = NULL; 149890926Snectar return ret; 149990926Snectar } 150090926Snectar p = (*res)->address.data; 150190926Snectar *p++ = 0; 150290926Snectar *p++ = 0; 150390926Snectar *p++ = (addr->addr_type ) & 0xFF; 150490926Snectar *p++ = (addr->addr_type >> 8) & 0xFF; 150590926Snectar 150690926Snectar *p++ = (addr->address.length ) & 0xFF; 150790926Snectar *p++ = (addr->address.length >> 8) & 0xFF; 150890926Snectar *p++ = (addr->address.length >> 16) & 0xFF; 150990926Snectar *p++ = (addr->address.length >> 24) & 0xFF; 151090926Snectar 151190926Snectar memcpy (p, addr->address.data, addr->address.length); 151290926Snectar p += addr->address.length; 151390926Snectar 151490926Snectar *p++ = 0; 151590926Snectar *p++ = 0; 151690926Snectar *p++ = (KRB5_ADDRESS_IPPORT ) & 0xFF; 151790926Snectar *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF; 151890926Snectar 151990926Snectar *p++ = (2 ) & 0xFF; 152090926Snectar *p++ = (2 >> 8) & 0xFF; 152190926Snectar *p++ = (2 >> 16) & 0xFF; 152290926Snectar *p++ = (2 >> 24) & 0xFF; 152390926Snectar 152490926Snectar memcpy (p, &port, 2); 152590926Snectar 152690926Snectar return 0; 152790926Snectar} 1528178825Sdfr 1529178825Sdfr/** 1530178825Sdfr * Calculate the boundary addresses of `inaddr'/`prefixlen' and store 1531178825Sdfr * them in `low' and `high'. 1532178825Sdfr * 1533178825Sdfr * @param context a Keberos context 1534178825Sdfr * @param inaddr address in prefixlen that the bondery searched 1535178825Sdfr * @param prefixlen width of boundery 1536178825Sdfr * @param low lowest address 1537178825Sdfr * @param high highest address 1538178825Sdfr * 1539178825Sdfr * @return Return an error code or 0. 1540178825Sdfr * 1541178825Sdfr * @ingroup krb5_address 1542178825Sdfr */ 1543178825Sdfr 1544233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1545178825Sdfrkrb5_address_prefixlen_boundary(krb5_context context, 1546178825Sdfr const krb5_address *inaddr, 1547178825Sdfr unsigned long prefixlen, 1548178825Sdfr krb5_address *low, 1549178825Sdfr krb5_address *high) 1550178825Sdfr{ 1551178825Sdfr struct addr_operations *a = find_atype (inaddr->addr_type); 1552178825Sdfr if(a != NULL && a->mask_boundary != NULL) 1553178825Sdfr return (*a->mask_boundary)(context, inaddr, prefixlen, low, high); 1554233294Sstas krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 1555233294Sstas N_("Address family %d doesn't support " 1556233294Sstas "address mask operation", ""), 1557233294Sstas inaddr->addr_type); 1558178825Sdfr return KRB5_PROG_ATYPE_NOSUPP; 1559178825Sdfr} 1560