1b528cefcSMark Murray /* 2*ae771770SStanislav Sedov * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #include "krb5_locl.h" 35b528cefcSMark Murray 36b528cefcSMark Murray struct addr_operations { 37b528cefcSMark Murray int af; 38b528cefcSMark Murray krb5_address_type atype; 39b528cefcSMark Murray size_t max_sockaddr_size; 40b528cefcSMark Murray krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *); 41b528cefcSMark Murray krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *); 42b528cefcSMark Murray void (*addr2sockaddr)(const krb5_address *, struct sockaddr *, 438373020dSJacques Vidrine krb5_socklen_t *sa_size, int port); 448373020dSJacques Vidrine void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int); 45b528cefcSMark Murray krb5_error_code (*h_addr2addr)(const char *, krb5_address *); 46b528cefcSMark Murray krb5_boolean (*uninteresting)(const struct sockaddr *); 47*ae771770SStanislav Sedov krb5_boolean (*is_loopback)(const struct sockaddr *); 488373020dSJacques Vidrine void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int); 49b528cefcSMark Murray int (*print_addr)(const krb5_address *, char *, size_t); 504137ff4cSJacques Vidrine int (*parse_addr)(krb5_context, const char*, krb5_address *); 514137ff4cSJacques Vidrine int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*); 524137ff4cSJacques Vidrine int (*free_addr)(krb5_context, krb5_address*); 534137ff4cSJacques Vidrine int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*); 54c19800e8SDoug Rabson int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long, 55c19800e8SDoug Rabson krb5_address*, krb5_address*); 56b528cefcSMark Murray }; 57b528cefcSMark Murray 58b528cefcSMark Murray /* 59b528cefcSMark Murray * AF_INET - aka IPv4 implementation 60b528cefcSMark Murray */ 61b528cefcSMark Murray 62b528cefcSMark Murray static krb5_error_code 63b528cefcSMark Murray ipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 64b528cefcSMark Murray { 65c19800e8SDoug Rabson const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 66b528cefcSMark Murray unsigned char buf[4]; 67b528cefcSMark Murray 68b528cefcSMark Murray a->addr_type = KRB5_ADDRESS_INET; 69c19800e8SDoug Rabson memcpy (buf, &sin4->sin_addr, 4); 70b528cefcSMark Murray return krb5_data_copy(&a->address, buf, 4); 71b528cefcSMark Murray } 72b528cefcSMark Murray 73b528cefcSMark Murray static krb5_error_code 74b528cefcSMark Murray ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port) 75b528cefcSMark Murray { 76c19800e8SDoug Rabson const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 77b528cefcSMark Murray 78c19800e8SDoug Rabson *port = sin4->sin_port; 79b528cefcSMark Murray return 0; 80b528cefcSMark Murray } 81b528cefcSMark Murray 82b528cefcSMark Murray static void 83b528cefcSMark Murray ipv4_addr2sockaddr (const krb5_address *a, 84b528cefcSMark Murray struct sockaddr *sa, 858373020dSJacques Vidrine krb5_socklen_t *sa_size, 86b528cefcSMark Murray int port) 87b528cefcSMark Murray { 888373020dSJacques Vidrine struct sockaddr_in tmp; 89b528cefcSMark Murray 908373020dSJacques Vidrine memset (&tmp, 0, sizeof(tmp)); 918373020dSJacques Vidrine tmp.sin_family = AF_INET; 928373020dSJacques Vidrine memcpy (&tmp.sin_addr, a->address.data, 4); 938373020dSJacques Vidrine tmp.sin_port = port; 948373020dSJacques Vidrine memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 958373020dSJacques Vidrine *sa_size = sizeof(tmp); 96b528cefcSMark Murray } 97b528cefcSMark Murray 98b528cefcSMark Murray static void 99b528cefcSMark Murray ipv4_h_addr2sockaddr(const char *addr, 1008373020dSJacques Vidrine struct sockaddr *sa, 1018373020dSJacques Vidrine krb5_socklen_t *sa_size, 1028373020dSJacques Vidrine int port) 103b528cefcSMark Murray { 1048373020dSJacques Vidrine struct sockaddr_in tmp; 105b528cefcSMark Murray 1068373020dSJacques Vidrine memset (&tmp, 0, sizeof(tmp)); 1078373020dSJacques Vidrine tmp.sin_family = AF_INET; 1088373020dSJacques Vidrine tmp.sin_port = port; 1098373020dSJacques Vidrine tmp.sin_addr = *((const struct in_addr *)addr); 1108373020dSJacques Vidrine memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 1118373020dSJacques Vidrine *sa_size = sizeof(tmp); 112b528cefcSMark Murray } 113b528cefcSMark Murray 114b528cefcSMark Murray static krb5_error_code 115b528cefcSMark Murray ipv4_h_addr2addr (const char *addr, 116b528cefcSMark Murray krb5_address *a) 117b528cefcSMark Murray { 118b528cefcSMark Murray unsigned char buf[4]; 119b528cefcSMark Murray 120b528cefcSMark Murray a->addr_type = KRB5_ADDRESS_INET; 121b528cefcSMark Murray memcpy(buf, addr, 4); 122b528cefcSMark Murray return krb5_data_copy(&a->address, buf, 4); 123b528cefcSMark Murray } 124b528cefcSMark Murray 125b528cefcSMark Murray /* 126b528cefcSMark Murray * Are there any addresses that should be considered `uninteresting'? 127b528cefcSMark Murray */ 128b528cefcSMark Murray 129b528cefcSMark Murray static krb5_boolean 130b528cefcSMark Murray ipv4_uninteresting (const struct sockaddr *sa) 131b528cefcSMark Murray { 132c19800e8SDoug Rabson const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 133b528cefcSMark Murray 134c19800e8SDoug Rabson if (sin4->sin_addr.s_addr == INADDR_ANY) 135b528cefcSMark Murray return TRUE; 136b528cefcSMark Murray 137b528cefcSMark Murray return FALSE; 138b528cefcSMark Murray } 139b528cefcSMark Murray 140*ae771770SStanislav Sedov static krb5_boolean 141*ae771770SStanislav Sedov ipv4_is_loopback (const struct sockaddr *sa) 142*ae771770SStanislav Sedov { 143*ae771770SStanislav Sedov const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 144*ae771770SStanislav Sedov 145*ae771770SStanislav Sedov if ((ntohl(sin4->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET) 146*ae771770SStanislav Sedov return TRUE; 147*ae771770SStanislav Sedov 148*ae771770SStanislav Sedov return FALSE; 149*ae771770SStanislav Sedov } 150*ae771770SStanislav Sedov 151b528cefcSMark Murray static void 1528373020dSJacques Vidrine ipv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) 153b528cefcSMark Murray { 1548373020dSJacques Vidrine struct sockaddr_in tmp; 155b528cefcSMark Murray 1568373020dSJacques Vidrine memset (&tmp, 0, sizeof(tmp)); 1578373020dSJacques Vidrine tmp.sin_family = AF_INET; 1588373020dSJacques Vidrine tmp.sin_port = port; 1598373020dSJacques Vidrine tmp.sin_addr.s_addr = INADDR_ANY; 1608373020dSJacques Vidrine memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 1618373020dSJacques Vidrine *sa_size = sizeof(tmp); 162b528cefcSMark Murray } 163b528cefcSMark Murray 164b528cefcSMark Murray static int 165b528cefcSMark Murray ipv4_print_addr (const krb5_address *addr, char *str, size_t len) 166b528cefcSMark Murray { 167b528cefcSMark Murray struct in_addr ia; 168b528cefcSMark Murray 169b528cefcSMark Murray memcpy (&ia, addr->address.data, 4); 170b528cefcSMark Murray 171b528cefcSMark Murray return snprintf (str, len, "IPv4:%s", inet_ntoa(ia)); 172b528cefcSMark Murray } 173b528cefcSMark Murray 174b528cefcSMark Murray static int 1754137ff4cSJacques Vidrine ipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr) 176b528cefcSMark Murray { 177b528cefcSMark Murray const char *p; 178b528cefcSMark Murray struct in_addr a; 179b528cefcSMark Murray 180b528cefcSMark Murray p = strchr(address, ':'); 181b528cefcSMark Murray if(p) { 182b528cefcSMark Murray p++; 183b528cefcSMark Murray if(strncasecmp(address, "ip:", p - address) != 0 && 184b528cefcSMark Murray strncasecmp(address, "ip4:", p - address) != 0 && 185b528cefcSMark Murray strncasecmp(address, "ipv4:", p - address) != 0 && 186b528cefcSMark Murray strncasecmp(address, "inet:", p - address) != 0) 187b528cefcSMark Murray return -1; 188b528cefcSMark Murray } else 189b528cefcSMark Murray p = address; 190b528cefcSMark Murray if(inet_aton(p, &a) == 0) 191b528cefcSMark Murray return -1; 192b528cefcSMark Murray addr->addr_type = KRB5_ADDRESS_INET; 193b528cefcSMark Murray if(krb5_data_alloc(&addr->address, 4) != 0) 194b528cefcSMark Murray return -1; 195b528cefcSMark Murray _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length); 196b528cefcSMark Murray return 0; 197b528cefcSMark Murray } 198b528cefcSMark Murray 199c19800e8SDoug Rabson static int 200c19800e8SDoug Rabson ipv4_mask_boundary(krb5_context context, const krb5_address *inaddr, 201c19800e8SDoug Rabson unsigned long len, krb5_address *low, krb5_address *high) 202c19800e8SDoug Rabson { 203c19800e8SDoug Rabson unsigned long ia; 204c19800e8SDoug Rabson uint32_t l, h, m = 0xffffffff; 205c19800e8SDoug Rabson 206c19800e8SDoug Rabson if (len > 32) { 207*ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 208*ae771770SStanislav Sedov N_("IPv4 prefix too large (%ld)", "len"), len); 209c19800e8SDoug Rabson return KRB5_PROG_ATYPE_NOSUPP; 210c19800e8SDoug Rabson } 211c19800e8SDoug Rabson m = m << (32 - len); 212c19800e8SDoug Rabson 213c19800e8SDoug Rabson _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length); 214c19800e8SDoug Rabson 215c19800e8SDoug Rabson l = ia & m; 216c19800e8SDoug Rabson h = l | ~m; 217c19800e8SDoug Rabson 218c19800e8SDoug Rabson low->addr_type = KRB5_ADDRESS_INET; 219c19800e8SDoug Rabson if(krb5_data_alloc(&low->address, 4) != 0) 220c19800e8SDoug Rabson return -1; 221c19800e8SDoug Rabson _krb5_put_int(low->address.data, l, low->address.length); 222c19800e8SDoug Rabson 223c19800e8SDoug Rabson high->addr_type = KRB5_ADDRESS_INET; 224c19800e8SDoug Rabson if(krb5_data_alloc(&high->address, 4) != 0) { 225c19800e8SDoug Rabson krb5_free_address(context, low); 226c19800e8SDoug Rabson return -1; 227c19800e8SDoug Rabson } 228c19800e8SDoug Rabson _krb5_put_int(high->address.data, h, high->address.length); 229c19800e8SDoug Rabson 230c19800e8SDoug Rabson return 0; 231c19800e8SDoug Rabson } 232c19800e8SDoug Rabson 233c19800e8SDoug Rabson 234b528cefcSMark Murray /* 235b528cefcSMark Murray * AF_INET6 - aka IPv6 implementation 236b528cefcSMark Murray */ 237b528cefcSMark Murray 238b528cefcSMark Murray #ifdef HAVE_IPV6 239b528cefcSMark Murray 240b528cefcSMark Murray static krb5_error_code 241b528cefcSMark Murray ipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 242b528cefcSMark Murray { 243b528cefcSMark Murray const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 244b528cefcSMark Murray 245b528cefcSMark Murray if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 246b528cefcSMark Murray unsigned char buf[4]; 247b528cefcSMark Murray 248b528cefcSMark Murray a->addr_type = KRB5_ADDRESS_INET; 249b528cefcSMark Murray #ifndef IN6_ADDR_V6_TO_V4 250b528cefcSMark Murray #ifdef IN6_EXTRACT_V4ADDR 251b528cefcSMark Murray #define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x)) 252b528cefcSMark Murray #else 253b528cefcSMark Murray #define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12]) 254b528cefcSMark Murray #endif 255b528cefcSMark Murray #endif 256b528cefcSMark Murray memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4); 257b528cefcSMark Murray return krb5_data_copy(&a->address, buf, 4); 258b528cefcSMark Murray } else { 259b528cefcSMark Murray a->addr_type = KRB5_ADDRESS_INET6; 260b528cefcSMark Murray return krb5_data_copy(&a->address, 261b528cefcSMark Murray &sin6->sin6_addr, 262b528cefcSMark Murray sizeof(sin6->sin6_addr)); 263b528cefcSMark Murray } 264b528cefcSMark Murray } 265b528cefcSMark Murray 266b528cefcSMark Murray static krb5_error_code 267b528cefcSMark Murray ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port) 268b528cefcSMark Murray { 269b528cefcSMark Murray const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 270b528cefcSMark Murray 271b528cefcSMark Murray *port = sin6->sin6_port; 272b528cefcSMark Murray return 0; 273b528cefcSMark Murray } 274b528cefcSMark Murray 275b528cefcSMark Murray static void 276b528cefcSMark Murray ipv6_addr2sockaddr (const krb5_address *a, 277b528cefcSMark Murray struct sockaddr *sa, 2788373020dSJacques Vidrine krb5_socklen_t *sa_size, 279b528cefcSMark Murray int port) 280b528cefcSMark Murray { 2818373020dSJacques Vidrine struct sockaddr_in6 tmp; 282b528cefcSMark Murray 2838373020dSJacques Vidrine memset (&tmp, 0, sizeof(tmp)); 2848373020dSJacques Vidrine tmp.sin6_family = AF_INET6; 2858373020dSJacques Vidrine memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr)); 2868373020dSJacques Vidrine tmp.sin6_port = port; 2878373020dSJacques Vidrine memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 2888373020dSJacques Vidrine *sa_size = sizeof(tmp); 289b528cefcSMark Murray } 290b528cefcSMark Murray 291b528cefcSMark Murray static void 292b528cefcSMark Murray ipv6_h_addr2sockaddr(const char *addr, 293b528cefcSMark Murray struct sockaddr *sa, 2948373020dSJacques Vidrine krb5_socklen_t *sa_size, 295b528cefcSMark Murray int port) 296b528cefcSMark Murray { 2978373020dSJacques Vidrine struct sockaddr_in6 tmp; 298b528cefcSMark Murray 2998373020dSJacques Vidrine memset (&tmp, 0, sizeof(tmp)); 3008373020dSJacques Vidrine tmp.sin6_family = AF_INET6; 3018373020dSJacques Vidrine tmp.sin6_port = port; 3028373020dSJacques Vidrine tmp.sin6_addr = *((const struct in6_addr *)addr); 3038373020dSJacques Vidrine memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 3048373020dSJacques Vidrine *sa_size = sizeof(tmp); 305b528cefcSMark Murray } 306b528cefcSMark Murray 307b528cefcSMark Murray static krb5_error_code 308b528cefcSMark Murray ipv6_h_addr2addr (const char *addr, 309b528cefcSMark Murray krb5_address *a) 310b528cefcSMark Murray { 311b528cefcSMark Murray a->addr_type = KRB5_ADDRESS_INET6; 312b528cefcSMark Murray return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr)); 313b528cefcSMark Murray } 314b528cefcSMark Murray 315b528cefcSMark Murray /* 316b528cefcSMark Murray * 317b528cefcSMark Murray */ 318b528cefcSMark Murray 319b528cefcSMark Murray static krb5_boolean 320b528cefcSMark Murray ipv6_uninteresting (const struct sockaddr *sa) 321b528cefcSMark Murray { 322b528cefcSMark Murray const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 323b528cefcSMark Murray const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; 324b528cefcSMark Murray 325*ae771770SStanislav Sedov return IN6_IS_ADDR_LINKLOCAL(in6) 326b528cefcSMark Murray || IN6_IS_ADDR_V4COMPAT(in6); 327b528cefcSMark Murray } 328b528cefcSMark Murray 329*ae771770SStanislav Sedov static krb5_boolean 330*ae771770SStanislav Sedov ipv6_is_loopback (const struct sockaddr *sa) 331*ae771770SStanislav Sedov { 332*ae771770SStanislav Sedov const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 333*ae771770SStanislav Sedov const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; 334*ae771770SStanislav Sedov 335*ae771770SStanislav Sedov return (IN6_IS_ADDR_LOOPBACK(in6)); 336*ae771770SStanislav Sedov } 337*ae771770SStanislav Sedov 338b528cefcSMark Murray static void 3398373020dSJacques Vidrine ipv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) 340b528cefcSMark Murray { 3418373020dSJacques Vidrine struct sockaddr_in6 tmp; 342b528cefcSMark Murray 3438373020dSJacques Vidrine memset (&tmp, 0, sizeof(tmp)); 3448373020dSJacques Vidrine tmp.sin6_family = AF_INET6; 3458373020dSJacques Vidrine tmp.sin6_port = port; 3468373020dSJacques Vidrine tmp.sin6_addr = in6addr_any; 3478373020dSJacques Vidrine *sa_size = sizeof(tmp); 348b528cefcSMark Murray } 349b528cefcSMark Murray 350b528cefcSMark Murray static int 351b528cefcSMark Murray ipv6_print_addr (const krb5_address *addr, char *str, size_t len) 352b528cefcSMark Murray { 353b528cefcSMark Murray char buf[128], buf2[3]; 354b528cefcSMark Murray if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL) 355b528cefcSMark Murray { 356b528cefcSMark Murray /* XXX this is pretty ugly, but better than abort() */ 357*ae771770SStanislav Sedov size_t i; 358b528cefcSMark Murray unsigned char *p = addr->address.data; 359b528cefcSMark Murray buf[0] = '\0'; 360b528cefcSMark Murray for(i = 0; i < addr->address.length; i++) { 361b528cefcSMark Murray snprintf(buf2, sizeof(buf2), "%02x", p[i]); 362b528cefcSMark Murray if(i > 0 && (i & 1) == 0) 363b528cefcSMark Murray strlcat(buf, ":", sizeof(buf)); 364b528cefcSMark Murray strlcat(buf, buf2, sizeof(buf)); 365b528cefcSMark Murray } 366b528cefcSMark Murray } 367b528cefcSMark Murray return snprintf(str, len, "IPv6:%s", buf); 368b528cefcSMark Murray } 369b528cefcSMark Murray 370b528cefcSMark Murray static int 3714137ff4cSJacques Vidrine ipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr) 372b528cefcSMark Murray { 373b528cefcSMark Murray int ret; 374b528cefcSMark Murray struct in6_addr in6; 3754137ff4cSJacques Vidrine const char *p; 3764137ff4cSJacques Vidrine 3774137ff4cSJacques Vidrine p = strchr(address, ':'); 3784137ff4cSJacques Vidrine if(p) { 3794137ff4cSJacques Vidrine p++; 3804137ff4cSJacques Vidrine if(strncasecmp(address, "ip6:", p - address) == 0 || 3814137ff4cSJacques Vidrine strncasecmp(address, "ipv6:", p - address) == 0 || 3824137ff4cSJacques Vidrine strncasecmp(address, "inet6:", p - address) == 0) 3834137ff4cSJacques Vidrine address = p; 3844137ff4cSJacques Vidrine } 385b528cefcSMark Murray 386b528cefcSMark Murray ret = inet_pton(AF_INET6, address, &in6.s6_addr); 387b528cefcSMark Murray if(ret == 1) { 388b528cefcSMark Murray addr->addr_type = KRB5_ADDRESS_INET6; 389b528cefcSMark Murray ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr)); 390b528cefcSMark Murray if (ret) 391b528cefcSMark Murray return -1; 392b528cefcSMark Murray memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr)); 393b528cefcSMark Murray return 0; 394b528cefcSMark Murray } 395b528cefcSMark Murray return -1; 396b528cefcSMark Murray } 397b528cefcSMark Murray 398c19800e8SDoug Rabson static int 399c19800e8SDoug Rabson ipv6_mask_boundary(krb5_context context, const krb5_address *inaddr, 400c19800e8SDoug Rabson unsigned long len, krb5_address *low, krb5_address *high) 401c19800e8SDoug Rabson { 402c19800e8SDoug Rabson struct in6_addr addr, laddr, haddr; 403c19800e8SDoug Rabson uint32_t m; 404c19800e8SDoug Rabson int i, sub_len; 405c19800e8SDoug Rabson 406c19800e8SDoug Rabson if (len > 128) { 407*ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 408*ae771770SStanislav Sedov N_("IPv6 prefix too large (%ld)", "length"), len); 409c19800e8SDoug Rabson return KRB5_PROG_ATYPE_NOSUPP; 410c19800e8SDoug Rabson } 411c19800e8SDoug Rabson 412c19800e8SDoug Rabson if (inaddr->address.length != sizeof(addr)) { 413*ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 414*ae771770SStanislav Sedov N_("IPv6 addr bad length", "")); 415c19800e8SDoug Rabson return KRB5_PROG_ATYPE_NOSUPP; 416c19800e8SDoug Rabson } 417c19800e8SDoug Rabson 418c19800e8SDoug Rabson memcpy(&addr, inaddr->address.data, inaddr->address.length); 419c19800e8SDoug Rabson 420c19800e8SDoug Rabson for (i = 0; i < 16; i++) { 421c19800e8SDoug Rabson sub_len = min(8, len); 422c19800e8SDoug Rabson 423c19800e8SDoug Rabson m = 0xff << (8 - sub_len); 424c19800e8SDoug Rabson 425c19800e8SDoug Rabson laddr.s6_addr[i] = addr.s6_addr[i] & m; 426c19800e8SDoug Rabson haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m; 427c19800e8SDoug Rabson 428c19800e8SDoug Rabson if (len > 8) 429c19800e8SDoug Rabson len -= 8; 430c19800e8SDoug Rabson else 431c19800e8SDoug Rabson len = 0; 432c19800e8SDoug Rabson } 433c19800e8SDoug Rabson 434c19800e8SDoug Rabson low->addr_type = KRB5_ADDRESS_INET6; 435c19800e8SDoug Rabson if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0) 436c19800e8SDoug Rabson return -1; 437c19800e8SDoug Rabson memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr)); 438c19800e8SDoug Rabson 439c19800e8SDoug Rabson high->addr_type = KRB5_ADDRESS_INET6; 440c19800e8SDoug Rabson if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) { 441c19800e8SDoug Rabson krb5_free_address(context, low); 442c19800e8SDoug Rabson return -1; 443c19800e8SDoug Rabson } 444c19800e8SDoug Rabson memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr)); 445c19800e8SDoug Rabson 446c19800e8SDoug Rabson return 0; 447c19800e8SDoug Rabson } 448c19800e8SDoug Rabson 449b528cefcSMark Murray #endif /* IPv6 */ 450b528cefcSMark Murray 451*ae771770SStanislav Sedov #ifndef HEIMDAL_SMALLER 452*ae771770SStanislav Sedov 453b528cefcSMark Murray /* 454b528cefcSMark Murray * table 455b528cefcSMark Murray */ 456b528cefcSMark Murray 4574137ff4cSJacques Vidrine #define KRB5_ADDRESS_ARANGE (-100) 4584137ff4cSJacques Vidrine 4594137ff4cSJacques Vidrine struct arange { 4604137ff4cSJacques Vidrine krb5_address low; 4614137ff4cSJacques Vidrine krb5_address high; 4624137ff4cSJacques Vidrine }; 4634137ff4cSJacques Vidrine 4644137ff4cSJacques Vidrine static int 4654137ff4cSJacques Vidrine arange_parse_addr (krb5_context context, 4664137ff4cSJacques Vidrine const char *address, krb5_address *addr) 4674137ff4cSJacques Vidrine { 468c19800e8SDoug Rabson char buf[1024], *p; 469c19800e8SDoug Rabson krb5_address low0, high0; 4704137ff4cSJacques Vidrine struct arange *a; 4714137ff4cSJacques Vidrine krb5_error_code ret; 4724137ff4cSJacques Vidrine 4734137ff4cSJacques Vidrine if(strncasecmp(address, "RANGE:", 6) != 0) 4744137ff4cSJacques Vidrine return -1; 4754137ff4cSJacques Vidrine 4764137ff4cSJacques Vidrine address += 6; 4774137ff4cSJacques Vidrine 478c19800e8SDoug Rabson p = strrchr(address, '/'); 479c19800e8SDoug Rabson if (p) { 480c19800e8SDoug Rabson krb5_addresses addrmask; 481c19800e8SDoug Rabson char *q; 482c19800e8SDoug Rabson long num; 483c19800e8SDoug Rabson 484c19800e8SDoug Rabson if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf)) 485c19800e8SDoug Rabson return -1; 486c19800e8SDoug Rabson buf[p - address] = '\0'; 487c19800e8SDoug Rabson ret = krb5_parse_address(context, buf, &addrmask); 488c19800e8SDoug Rabson if (ret) 489c19800e8SDoug Rabson return ret; 490c19800e8SDoug Rabson if(addrmask.len != 1) { 491c19800e8SDoug Rabson krb5_free_addresses(context, &addrmask); 492c19800e8SDoug Rabson return -1; 493c19800e8SDoug Rabson } 494c19800e8SDoug Rabson 495c19800e8SDoug Rabson address += p - address + 1; 496c19800e8SDoug Rabson 497c19800e8SDoug Rabson num = strtol(address, &q, 10); 498c19800e8SDoug Rabson if (q == address || *q != '\0' || num < 0) { 499c19800e8SDoug Rabson krb5_free_addresses(context, &addrmask); 500c19800e8SDoug Rabson return -1; 501c19800e8SDoug Rabson } 502c19800e8SDoug Rabson 503c19800e8SDoug Rabson ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num, 504c19800e8SDoug Rabson &low0, &high0); 505c19800e8SDoug Rabson krb5_free_addresses(context, &addrmask); 506c19800e8SDoug Rabson if (ret) 507c19800e8SDoug Rabson return ret; 508c19800e8SDoug Rabson 509c19800e8SDoug Rabson } else { 510c19800e8SDoug Rabson krb5_addresses low, high; 511c19800e8SDoug Rabson 5124137ff4cSJacques Vidrine strsep_copy(&address, "-", buf, sizeof(buf)); 5134137ff4cSJacques Vidrine ret = krb5_parse_address(context, buf, &low); 5144137ff4cSJacques Vidrine if(ret) 5154137ff4cSJacques Vidrine return ret; 5164137ff4cSJacques Vidrine if(low.len != 1) { 5174137ff4cSJacques Vidrine krb5_free_addresses(context, &low); 5184137ff4cSJacques Vidrine return -1; 5194137ff4cSJacques Vidrine } 5204137ff4cSJacques Vidrine 5214137ff4cSJacques Vidrine strsep_copy(&address, "-", buf, sizeof(buf)); 5224137ff4cSJacques Vidrine ret = krb5_parse_address(context, buf, &high); 5234137ff4cSJacques Vidrine if(ret) { 5244137ff4cSJacques Vidrine krb5_free_addresses(context, &low); 5254137ff4cSJacques Vidrine return ret; 5264137ff4cSJacques Vidrine } 5274137ff4cSJacques Vidrine 528c19800e8SDoug Rabson if(high.len != 1 && high.val[0].addr_type != low.val[0].addr_type) { 5294137ff4cSJacques Vidrine krb5_free_addresses(context, &low); 5304137ff4cSJacques Vidrine krb5_free_addresses(context, &high); 5314137ff4cSJacques Vidrine return -1; 5324137ff4cSJacques Vidrine } 5334137ff4cSJacques Vidrine 534c19800e8SDoug Rabson ret = krb5_copy_address(context, &high.val[0], &high0); 535c19800e8SDoug Rabson if (ret == 0) { 536c19800e8SDoug Rabson ret = krb5_copy_address(context, &low.val[0], &low0); 537c19800e8SDoug Rabson if (ret) 538c19800e8SDoug Rabson krb5_free_address(context, &high0); 539c19800e8SDoug Rabson } 540c19800e8SDoug Rabson krb5_free_addresses(context, &low); 541c19800e8SDoug Rabson krb5_free_addresses(context, &high); 542c19800e8SDoug Rabson if (ret) 543c19800e8SDoug Rabson return ret; 544c19800e8SDoug Rabson } 545c19800e8SDoug Rabson 5464137ff4cSJacques Vidrine krb5_data_alloc(&addr->address, sizeof(*a)); 5474137ff4cSJacques Vidrine addr->addr_type = KRB5_ADDRESS_ARANGE; 5484137ff4cSJacques Vidrine a = addr->address.data; 5494137ff4cSJacques Vidrine 550c19800e8SDoug Rabson if(krb5_address_order(context, &low0, &high0) < 0) { 551c19800e8SDoug Rabson a->low = low0; 552c19800e8SDoug Rabson a->high = high0; 5534137ff4cSJacques Vidrine } else { 554c19800e8SDoug Rabson a->low = high0; 555c19800e8SDoug Rabson a->high = low0; 5564137ff4cSJacques Vidrine } 5574137ff4cSJacques Vidrine return 0; 5584137ff4cSJacques Vidrine } 5594137ff4cSJacques Vidrine 5604137ff4cSJacques Vidrine static int 5614137ff4cSJacques Vidrine arange_free (krb5_context context, krb5_address *addr) 5624137ff4cSJacques Vidrine { 5634137ff4cSJacques Vidrine struct arange *a; 5644137ff4cSJacques Vidrine a = addr->address.data; 5654137ff4cSJacques Vidrine krb5_free_address(context, &a->low); 5664137ff4cSJacques Vidrine krb5_free_address(context, &a->high); 567c19800e8SDoug Rabson krb5_data_free(&addr->address); 5684137ff4cSJacques Vidrine return 0; 5694137ff4cSJacques Vidrine } 5704137ff4cSJacques Vidrine 5714137ff4cSJacques Vidrine 5724137ff4cSJacques Vidrine static int 5734137ff4cSJacques Vidrine arange_copy (krb5_context context, const krb5_address *inaddr, 5744137ff4cSJacques Vidrine krb5_address *outaddr) 5754137ff4cSJacques Vidrine { 5764137ff4cSJacques Vidrine krb5_error_code ret; 5774137ff4cSJacques Vidrine struct arange *i, *o; 5784137ff4cSJacques Vidrine 5794137ff4cSJacques Vidrine outaddr->addr_type = KRB5_ADDRESS_ARANGE; 5804137ff4cSJacques Vidrine ret = krb5_data_alloc(&outaddr->address, sizeof(*o)); 5814137ff4cSJacques Vidrine if(ret) 5824137ff4cSJacques Vidrine return ret; 5834137ff4cSJacques Vidrine i = inaddr->address.data; 5844137ff4cSJacques Vidrine o = outaddr->address.data; 5854137ff4cSJacques Vidrine ret = krb5_copy_address(context, &i->low, &o->low); 5864137ff4cSJacques Vidrine if(ret) { 5874137ff4cSJacques Vidrine krb5_data_free(&outaddr->address); 5884137ff4cSJacques Vidrine return ret; 5894137ff4cSJacques Vidrine } 5904137ff4cSJacques Vidrine ret = krb5_copy_address(context, &i->high, &o->high); 5914137ff4cSJacques Vidrine if(ret) { 5924137ff4cSJacques Vidrine krb5_free_address(context, &o->low); 5934137ff4cSJacques Vidrine krb5_data_free(&outaddr->address); 5944137ff4cSJacques Vidrine return ret; 5954137ff4cSJacques Vidrine } 5964137ff4cSJacques Vidrine return 0; 5974137ff4cSJacques Vidrine } 5984137ff4cSJacques Vidrine 5994137ff4cSJacques Vidrine static int 6004137ff4cSJacques Vidrine arange_print_addr (const krb5_address *addr, char *str, size_t len) 6014137ff4cSJacques Vidrine { 6024137ff4cSJacques Vidrine struct arange *a; 6034137ff4cSJacques Vidrine krb5_error_code ret; 604c19800e8SDoug Rabson size_t l, size, ret_len; 6054137ff4cSJacques Vidrine 6064137ff4cSJacques Vidrine a = addr->address.data; 6074137ff4cSJacques Vidrine 6084137ff4cSJacques Vidrine l = strlcpy(str, "RANGE:", len); 609c19800e8SDoug Rabson ret_len = l; 610c19800e8SDoug Rabson if (l > len) 611c19800e8SDoug Rabson l = len; 612c19800e8SDoug Rabson size = l; 6134137ff4cSJacques Vidrine 614c19800e8SDoug Rabson ret = krb5_print_address (&a->low, str + size, len - size, &l); 615c19800e8SDoug Rabson if (ret) 616c19800e8SDoug Rabson return ret; 6174137ff4cSJacques Vidrine ret_len += l; 618c19800e8SDoug Rabson if (len - size > l) 619c19800e8SDoug Rabson size += l; 620c19800e8SDoug Rabson else 621c19800e8SDoug Rabson size = len; 6224137ff4cSJacques Vidrine 623c19800e8SDoug Rabson l = strlcat(str + size, "-", len - size); 6244137ff4cSJacques Vidrine ret_len += l; 625c19800e8SDoug Rabson if (len - size > l) 626c19800e8SDoug Rabson size += l; 627c19800e8SDoug Rabson else 628c19800e8SDoug Rabson size = len; 6294137ff4cSJacques Vidrine 630c19800e8SDoug Rabson ret = krb5_print_address (&a->high, str + size, len - size, &l); 631c19800e8SDoug Rabson if (ret) 632c19800e8SDoug Rabson return ret; 6334137ff4cSJacques Vidrine ret_len += l; 6344137ff4cSJacques Vidrine 6354137ff4cSJacques Vidrine return ret_len; 6364137ff4cSJacques Vidrine } 6374137ff4cSJacques Vidrine 6384137ff4cSJacques Vidrine static int 6394137ff4cSJacques Vidrine arange_order_addr(krb5_context context, 6404137ff4cSJacques Vidrine const krb5_address *addr1, 6414137ff4cSJacques Vidrine const krb5_address *addr2) 6424137ff4cSJacques Vidrine { 6434137ff4cSJacques Vidrine int tmp1, tmp2, sign; 6444137ff4cSJacques Vidrine struct arange *a; 6454137ff4cSJacques Vidrine const krb5_address *a2; 6464137ff4cSJacques Vidrine 6474137ff4cSJacques Vidrine if(addr1->addr_type == KRB5_ADDRESS_ARANGE) { 6484137ff4cSJacques Vidrine a = addr1->address.data; 6494137ff4cSJacques Vidrine a2 = addr2; 6504137ff4cSJacques Vidrine sign = 1; 6514137ff4cSJacques Vidrine } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) { 6524137ff4cSJacques Vidrine a = addr2->address.data; 6534137ff4cSJacques Vidrine a2 = addr1; 6544137ff4cSJacques Vidrine sign = -1; 655*ae771770SStanislav Sedov } else { 6564137ff4cSJacques Vidrine abort(); 657*ae771770SStanislav Sedov UNREACHABLE(return 0); 658*ae771770SStanislav Sedov } 6594137ff4cSJacques Vidrine 6604137ff4cSJacques Vidrine if(a2->addr_type == KRB5_ADDRESS_ARANGE) { 6614137ff4cSJacques Vidrine struct arange *b = a2->address.data; 6624137ff4cSJacques Vidrine tmp1 = krb5_address_order(context, &a->low, &b->low); 6634137ff4cSJacques Vidrine if(tmp1 != 0) 6644137ff4cSJacques Vidrine return sign * tmp1; 6654137ff4cSJacques Vidrine return sign * krb5_address_order(context, &a->high, &b->high); 6664137ff4cSJacques Vidrine } else if(a2->addr_type == a->low.addr_type) { 6674137ff4cSJacques Vidrine tmp1 = krb5_address_order(context, &a->low, a2); 6684137ff4cSJacques Vidrine if(tmp1 > 0) 6694137ff4cSJacques Vidrine return sign; 6704137ff4cSJacques Vidrine tmp2 = krb5_address_order(context, &a->high, a2); 6714137ff4cSJacques Vidrine if(tmp2 < 0) 6724137ff4cSJacques Vidrine return -sign; 6734137ff4cSJacques Vidrine return 0; 6744137ff4cSJacques Vidrine } else { 6754137ff4cSJacques Vidrine return sign * (addr1->addr_type - addr2->addr_type); 6764137ff4cSJacques Vidrine } 6774137ff4cSJacques Vidrine } 6784137ff4cSJacques Vidrine 679*ae771770SStanislav Sedov #endif /* HEIMDAL_SMALLER */ 680*ae771770SStanislav Sedov 681bbd80c28SJacques Vidrine static int 682bbd80c28SJacques Vidrine addrport_print_addr (const krb5_address *addr, char *str, size_t len) 683bbd80c28SJacques Vidrine { 684c19800e8SDoug Rabson krb5_error_code ret; 685bbd80c28SJacques Vidrine krb5_address addr1, addr2; 686bbd80c28SJacques Vidrine uint16_t port = 0; 687c19800e8SDoug Rabson size_t ret_len = 0, l, size = 0; 688c19800e8SDoug Rabson krb5_storage *sp; 689c19800e8SDoug Rabson 690c19800e8SDoug Rabson sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address)); 691*ae771770SStanislav Sedov if (sp == NULL) 692*ae771770SStanislav Sedov return ENOMEM; 693*ae771770SStanislav Sedov 694bbd80c28SJacques Vidrine /* for totally obscure reasons, these are not in network byteorder */ 695bbd80c28SJacques Vidrine krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 696bbd80c28SJacques Vidrine 697bbd80c28SJacques Vidrine krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */ 698bbd80c28SJacques Vidrine krb5_ret_address(sp, &addr1); 699bbd80c28SJacques Vidrine 700bbd80c28SJacques Vidrine krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */ 701bbd80c28SJacques Vidrine krb5_ret_address(sp, &addr2); 702bbd80c28SJacques Vidrine krb5_storage_free(sp); 703bbd80c28SJacques Vidrine if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) { 704bbd80c28SJacques Vidrine unsigned long value; 705bbd80c28SJacques Vidrine _krb5_get_int(addr2.address.data, &value, 2); 706bbd80c28SJacques Vidrine port = value; 707bbd80c28SJacques Vidrine } 708bbd80c28SJacques Vidrine l = strlcpy(str, "ADDRPORT:", len); 709bbd80c28SJacques Vidrine ret_len += l; 710c19800e8SDoug Rabson if (len > l) 711c19800e8SDoug Rabson size += l; 712c19800e8SDoug Rabson else 713c19800e8SDoug Rabson size = len; 714c19800e8SDoug Rabson 715c19800e8SDoug Rabson ret = krb5_print_address(&addr1, str + size, len - size, &l); 716c19800e8SDoug Rabson if (ret) 717c19800e8SDoug Rabson return ret; 718bbd80c28SJacques Vidrine ret_len += l; 719c19800e8SDoug Rabson if (len - size > l) 720c19800e8SDoug Rabson size += l; 721c19800e8SDoug Rabson else 722c19800e8SDoug Rabson size = len; 723c19800e8SDoug Rabson 724c19800e8SDoug Rabson ret = snprintf(str + size, len - size, ",PORT=%u", port); 725c19800e8SDoug Rabson if (ret < 0) 726c19800e8SDoug Rabson return EINVAL; 727c19800e8SDoug Rabson ret_len += ret; 728bbd80c28SJacques Vidrine return ret_len; 729bbd80c28SJacques Vidrine } 730bbd80c28SJacques Vidrine 731b528cefcSMark Murray static struct addr_operations at[] = { 732*ae771770SStanislav Sedov { 733*ae771770SStanislav Sedov AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), 734b528cefcSMark Murray ipv4_sockaddr2addr, 735b528cefcSMark Murray ipv4_sockaddr2port, 736b528cefcSMark Murray ipv4_addr2sockaddr, 737b528cefcSMark Murray ipv4_h_addr2sockaddr, 738b528cefcSMark Murray ipv4_h_addr2addr, 739*ae771770SStanislav Sedov ipv4_uninteresting, 740*ae771770SStanislav Sedov ipv4_is_loopback, 741*ae771770SStanislav Sedov ipv4_anyaddr, 742*ae771770SStanislav Sedov ipv4_print_addr, 743*ae771770SStanislav Sedov ipv4_parse_addr, 744*ae771770SStanislav Sedov NULL, 745*ae771770SStanislav Sedov NULL, 746*ae771770SStanislav Sedov NULL, 747*ae771770SStanislav Sedov ipv4_mask_boundary 748*ae771770SStanislav Sedov }, 749b528cefcSMark Murray #ifdef HAVE_IPV6 750*ae771770SStanislav Sedov { 751*ae771770SStanislav Sedov AF_INET6, KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6), 752b528cefcSMark Murray ipv6_sockaddr2addr, 753b528cefcSMark Murray ipv6_sockaddr2port, 754b528cefcSMark Murray ipv6_addr2sockaddr, 755b528cefcSMark Murray ipv6_h_addr2sockaddr, 756b528cefcSMark Murray ipv6_h_addr2addr, 757*ae771770SStanislav Sedov ipv6_uninteresting, 758*ae771770SStanislav Sedov ipv6_is_loopback, 759*ae771770SStanislav Sedov ipv6_anyaddr, 760*ae771770SStanislav Sedov ipv6_print_addr, 761*ae771770SStanislav Sedov ipv6_parse_addr, 762*ae771770SStanislav Sedov NULL, 763*ae771770SStanislav Sedov NULL, 764*ae771770SStanislav Sedov NULL, 765*ae771770SStanislav Sedov ipv6_mask_boundary 766*ae771770SStanislav Sedov } , 767b528cefcSMark Murray #endif 768*ae771770SStanislav Sedov #ifndef HEIMDAL_SMALLER 7694137ff4cSJacques Vidrine /* fake address type */ 770*ae771770SStanislav Sedov { 771*ae771770SStanislav Sedov KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange), 772*ae771770SStanislav Sedov NULL, 773*ae771770SStanislav Sedov NULL, 774*ae771770SStanislav Sedov NULL, 775*ae771770SStanislav Sedov NULL, 776*ae771770SStanislav Sedov NULL, 777*ae771770SStanislav Sedov NULL, 778*ae771770SStanislav Sedov NULL, 779*ae771770SStanislav Sedov NULL, 780*ae771770SStanislav Sedov arange_print_addr, 781*ae771770SStanislav Sedov arange_parse_addr, 782*ae771770SStanislav Sedov arange_order_addr, 783*ae771770SStanislav Sedov arange_free, 784*ae771770SStanislav Sedov arange_copy, 785*ae771770SStanislav Sedov NULL 786*ae771770SStanislav Sedov }, 787*ae771770SStanislav Sedov #endif 788*ae771770SStanislav Sedov { 789*ae771770SStanislav Sedov KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0, 790*ae771770SStanislav Sedov NULL, 791*ae771770SStanislav Sedov NULL, 792*ae771770SStanislav Sedov NULL, 793*ae771770SStanislav Sedov NULL, 794*ae771770SStanislav Sedov NULL, 795*ae771770SStanislav Sedov NULL, 796*ae771770SStanislav Sedov NULL, 797*ae771770SStanislav Sedov NULL, 798*ae771770SStanislav Sedov addrport_print_addr, 799*ae771770SStanislav Sedov NULL, 800*ae771770SStanislav Sedov NULL, 801*ae771770SStanislav Sedov NULL, 802*ae771770SStanislav Sedov NULL 803*ae771770SStanislav Sedov } 804b528cefcSMark Murray }; 805b528cefcSMark Murray 806b528cefcSMark Murray static int num_addrs = sizeof(at) / sizeof(at[0]); 807b528cefcSMark Murray 808b528cefcSMark Murray static size_t max_sockaddr_size = 0; 809b528cefcSMark Murray 810b528cefcSMark Murray /* 811b528cefcSMark Murray * generic functions 812b528cefcSMark Murray */ 813b528cefcSMark Murray 814b528cefcSMark Murray static struct addr_operations * 815b528cefcSMark Murray find_af(int af) 816b528cefcSMark Murray { 817b528cefcSMark Murray struct addr_operations *a; 818b528cefcSMark Murray 819b528cefcSMark Murray for (a = at; a < at + num_addrs; ++a) 820b528cefcSMark Murray if (af == a->af) 821b528cefcSMark Murray return a; 822b528cefcSMark Murray return NULL; 823b528cefcSMark Murray } 824b528cefcSMark Murray 825b528cefcSMark Murray static struct addr_operations * 826*ae771770SStanislav Sedov find_atype(krb5_address_type atype) 827b528cefcSMark Murray { 828b528cefcSMark Murray struct addr_operations *a; 829b528cefcSMark Murray 830b528cefcSMark Murray for (a = at; a < at + num_addrs; ++a) 831b528cefcSMark Murray if (atype == a->atype) 832b528cefcSMark Murray return a; 833b528cefcSMark Murray return NULL; 834b528cefcSMark Murray } 835b528cefcSMark Murray 836c19800e8SDoug Rabson /** 837c19800e8SDoug Rabson * krb5_sockaddr2address stores a address a "struct sockaddr" sa in 838c19800e8SDoug Rabson * the krb5_address addr. 839c19800e8SDoug Rabson * 840c19800e8SDoug Rabson * @param context a Keberos context 841c19800e8SDoug Rabson * @param sa a struct sockaddr to extract the address from 842c19800e8SDoug Rabson * @param addr an Kerberos 5 address to store the address in. 843c19800e8SDoug Rabson * 844c19800e8SDoug Rabson * @return Return an error code or 0. 845c19800e8SDoug Rabson * 846c19800e8SDoug Rabson * @ingroup krb5_address 847c19800e8SDoug Rabson */ 848c19800e8SDoug Rabson 849*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 850adb0ddaeSAssar Westerlund krb5_sockaddr2address (krb5_context context, 851adb0ddaeSAssar Westerlund const struct sockaddr *sa, krb5_address *addr) 852b528cefcSMark Murray { 853b528cefcSMark Murray struct addr_operations *a = find_af(sa->sa_family); 854adb0ddaeSAssar Westerlund if (a == NULL) { 855*ae771770SStanislav Sedov krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 856*ae771770SStanislav Sedov N_("Address family %d not supported", ""), 857adb0ddaeSAssar Westerlund sa->sa_family); 858b528cefcSMark Murray return KRB5_PROG_ATYPE_NOSUPP; 859adb0ddaeSAssar Westerlund } 860b528cefcSMark Murray return (*a->sockaddr2addr)(sa, addr); 861b528cefcSMark Murray } 862b528cefcSMark Murray 863c19800e8SDoug Rabson /** 864c19800e8SDoug Rabson * krb5_sockaddr2port extracts a port (if possible) from a "struct 865c19800e8SDoug Rabson * sockaddr. 866c19800e8SDoug Rabson * 867c19800e8SDoug Rabson * @param context a Keberos context 868c19800e8SDoug Rabson * @param sa a struct sockaddr to extract the port from 869c19800e8SDoug Rabson * @param port a pointer to an int16_t store the port in. 870c19800e8SDoug Rabson * 871c19800e8SDoug Rabson * @return Return an error code or 0. Will return 872c19800e8SDoug Rabson * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 873c19800e8SDoug Rabson * 874c19800e8SDoug Rabson * @ingroup krb5_address 875c19800e8SDoug Rabson */ 876c19800e8SDoug Rabson 877*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 878adb0ddaeSAssar Westerlund krb5_sockaddr2port (krb5_context context, 879adb0ddaeSAssar Westerlund const struct sockaddr *sa, int16_t *port) 880b528cefcSMark Murray { 881b528cefcSMark Murray struct addr_operations *a = find_af(sa->sa_family); 882adb0ddaeSAssar Westerlund if (a == NULL) { 883*ae771770SStanislav Sedov krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 884*ae771770SStanislav Sedov N_("Address family %d not supported", ""), 885adb0ddaeSAssar Westerlund sa->sa_family); 886b528cefcSMark Murray return KRB5_PROG_ATYPE_NOSUPP; 887adb0ddaeSAssar Westerlund } 888b528cefcSMark Murray return (*a->sockaddr2port)(sa, port); 889b528cefcSMark Murray } 890b528cefcSMark Murray 891c19800e8SDoug Rabson /** 892c19800e8SDoug Rabson * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr 893c19800e8SDoug Rabson * and port. The argument sa_size should initially contain the size of 894c19800e8SDoug Rabson * the sa and after the call, it will contain the actual length of the 895c19800e8SDoug Rabson * address. In case of the sa is too small to fit the whole address, 896c19800e8SDoug Rabson * the up to *sa_size will be stored, and then *sa_size will be set to 897c19800e8SDoug Rabson * the required length. 898c19800e8SDoug Rabson * 899c19800e8SDoug Rabson * @param context a Keberos context 900c19800e8SDoug Rabson * @param addr the address to copy the from 901c19800e8SDoug Rabson * @param sa the struct sockaddr that will be filled in 902c19800e8SDoug Rabson * @param sa_size pointer to length of sa, and after the call, it will 903c19800e8SDoug Rabson * contain the actual length of the address. 904c19800e8SDoug Rabson * @param port set port in sa. 905c19800e8SDoug Rabson * 906c19800e8SDoug Rabson * @return Return an error code or 0. Will return 907c19800e8SDoug Rabson * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 908c19800e8SDoug Rabson * 909c19800e8SDoug Rabson * @ingroup krb5_address 910c19800e8SDoug Rabson */ 911c19800e8SDoug Rabson 912*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 913adb0ddaeSAssar Westerlund krb5_addr2sockaddr (krb5_context context, 914adb0ddaeSAssar Westerlund const krb5_address *addr, 915b528cefcSMark Murray struct sockaddr *sa, 9168373020dSJacques Vidrine krb5_socklen_t *sa_size, 917b528cefcSMark Murray int port) 918b528cefcSMark Murray { 919b528cefcSMark Murray struct addr_operations *a = find_atype(addr->addr_type); 920b528cefcSMark Murray 921adb0ddaeSAssar Westerlund if (a == NULL) { 922*ae771770SStanislav Sedov krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 923*ae771770SStanislav Sedov N_("Address type %d not supported", 924*ae771770SStanislav Sedov "krb5_address type"), 925adb0ddaeSAssar Westerlund addr->addr_type); 926b528cefcSMark Murray return KRB5_PROG_ATYPE_NOSUPP; 927adb0ddaeSAssar Westerlund } 9284137ff4cSJacques Vidrine if (a->addr2sockaddr == NULL) { 929*ae771770SStanislav Sedov krb5_set_error_message (context, 930*ae771770SStanislav Sedov KRB5_PROG_ATYPE_NOSUPP, 931*ae771770SStanislav Sedov N_("Can't convert address type %d to sockaddr", ""), 9324137ff4cSJacques Vidrine addr->addr_type); 9334137ff4cSJacques Vidrine return KRB5_PROG_ATYPE_NOSUPP; 9344137ff4cSJacques Vidrine } 935b528cefcSMark Murray (*a->addr2sockaddr)(addr, sa, sa_size, port); 936b528cefcSMark Murray return 0; 937b528cefcSMark Murray } 938b528cefcSMark Murray 939c19800e8SDoug Rabson /** 940c19800e8SDoug Rabson * krb5_max_sockaddr_size returns the max size of the .Li struct 941c19800e8SDoug Rabson * sockaddr that the Kerberos library will return. 942c19800e8SDoug Rabson * 943c19800e8SDoug Rabson * @return Return an size_t of the maximum struct sockaddr. 944c19800e8SDoug Rabson * 945c19800e8SDoug Rabson * @ingroup krb5_address 946c19800e8SDoug Rabson */ 947c19800e8SDoug Rabson 948*ae771770SStanislav Sedov KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 949b528cefcSMark Murray krb5_max_sockaddr_size (void) 950b528cefcSMark Murray { 951b528cefcSMark Murray if (max_sockaddr_size == 0) { 952b528cefcSMark Murray struct addr_operations *a; 953b528cefcSMark Murray 954b528cefcSMark Murray for(a = at; a < at + num_addrs; ++a) 955b528cefcSMark Murray max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size); 956b528cefcSMark Murray } 957b528cefcSMark Murray return max_sockaddr_size; 958b528cefcSMark Murray } 959b528cefcSMark Murray 960c19800e8SDoug Rabson /** 961c19800e8SDoug Rabson * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the 962c19800e8SDoug Rabson * kerberos library thinks are uninteresting. One example are link 963c19800e8SDoug Rabson * local addresses. 964c19800e8SDoug Rabson * 965c19800e8SDoug Rabson * @param sa pointer to struct sockaddr that might be interesting. 966c19800e8SDoug Rabson * 967c19800e8SDoug Rabson * @return Return a non zero for uninteresting addresses. 968c19800e8SDoug Rabson * 969c19800e8SDoug Rabson * @ingroup krb5_address 970c19800e8SDoug Rabson */ 971c19800e8SDoug Rabson 972*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 973b528cefcSMark Murray krb5_sockaddr_uninteresting(const struct sockaddr *sa) 974b528cefcSMark Murray { 975b528cefcSMark Murray struct addr_operations *a = find_af(sa->sa_family); 9764137ff4cSJacques Vidrine if (a == NULL || a->uninteresting == NULL) 977b528cefcSMark Murray return TRUE; 978b528cefcSMark Murray return (*a->uninteresting)(sa); 979b528cefcSMark Murray } 980b528cefcSMark Murray 981*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 982*ae771770SStanislav Sedov krb5_sockaddr_is_loopback(const struct sockaddr *sa) 983*ae771770SStanislav Sedov { 984*ae771770SStanislav Sedov struct addr_operations *a = find_af(sa->sa_family); 985*ae771770SStanislav Sedov if (a == NULL || a->is_loopback == NULL) 986*ae771770SStanislav Sedov return TRUE; 987*ae771770SStanislav Sedov return (*a->is_loopback)(sa); 988*ae771770SStanislav Sedov } 989*ae771770SStanislav Sedov 990c19800e8SDoug Rabson /** 991c19800e8SDoug Rabson * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and 992c19800e8SDoug Rabson * the "struct hostent" (see gethostbyname(3) ) h_addr_list 993c19800e8SDoug Rabson * component. The argument sa_size should initially contain the size 994c19800e8SDoug Rabson * of the sa, and after the call, it will contain the actual length of 995c19800e8SDoug Rabson * the address. 996c19800e8SDoug Rabson * 997c19800e8SDoug Rabson * @param context a Keberos context 998c19800e8SDoug Rabson * @param af addresses 999c19800e8SDoug Rabson * @param addr address 1000c19800e8SDoug Rabson * @param sa returned struct sockaddr 1001c19800e8SDoug Rabson * @param sa_size size of sa 1002c19800e8SDoug Rabson * @param port port to set in sa. 1003c19800e8SDoug Rabson * 1004c19800e8SDoug Rabson * @return Return an error code or 0. 1005c19800e8SDoug Rabson * 1006c19800e8SDoug Rabson * @ingroup krb5_address 1007c19800e8SDoug Rabson */ 1008c19800e8SDoug Rabson 1009*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1010adb0ddaeSAssar Westerlund krb5_h_addr2sockaddr (krb5_context context, 1011adb0ddaeSAssar Westerlund int af, 10128373020dSJacques Vidrine const char *addr, struct sockaddr *sa, 10138373020dSJacques Vidrine krb5_socklen_t *sa_size, 1014b528cefcSMark Murray int port) 1015b528cefcSMark Murray { 1016b528cefcSMark Murray struct addr_operations *a = find_af(af); 1017adb0ddaeSAssar Westerlund if (a == NULL) { 1018*ae771770SStanislav Sedov krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1019*ae771770SStanislav Sedov "Address family %d not supported", af); 1020b528cefcSMark Murray return KRB5_PROG_ATYPE_NOSUPP; 1021adb0ddaeSAssar Westerlund } 1022b528cefcSMark Murray (*a->h_addr2sockaddr)(addr, sa, sa_size, port); 1023b528cefcSMark Murray return 0; 1024b528cefcSMark Murray } 1025b528cefcSMark Murray 1026c19800e8SDoug Rabson /** 1027c19800e8SDoug Rabson * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception 1028c19800e8SDoug Rabson * that it operates on a krb5_address instead of a struct sockaddr. 1029c19800e8SDoug Rabson * 1030c19800e8SDoug Rabson * @param context a Keberos context 1031c19800e8SDoug Rabson * @param af address family 1032c19800e8SDoug Rabson * @param haddr host address from struct hostent. 1033c19800e8SDoug Rabson * @param addr returned krb5_address. 1034c19800e8SDoug Rabson * 1035c19800e8SDoug Rabson * @return Return an error code or 0. 1036c19800e8SDoug Rabson * 1037c19800e8SDoug Rabson * @ingroup krb5_address 1038c19800e8SDoug Rabson */ 1039c19800e8SDoug Rabson 1040*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1041adb0ddaeSAssar Westerlund krb5_h_addr2addr (krb5_context context, 1042adb0ddaeSAssar Westerlund int af, 1043b528cefcSMark Murray const char *haddr, krb5_address *addr) 1044b528cefcSMark Murray { 1045b528cefcSMark Murray struct addr_operations *a = find_af(af); 1046adb0ddaeSAssar Westerlund if (a == NULL) { 1047*ae771770SStanislav Sedov krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1048*ae771770SStanislav Sedov N_("Address family %d not supported", ""), af); 1049b528cefcSMark Murray return KRB5_PROG_ATYPE_NOSUPP; 1050adb0ddaeSAssar Westerlund } 1051b528cefcSMark Murray return (*a->h_addr2addr)(haddr, addr); 1052b528cefcSMark Murray } 1053b528cefcSMark Murray 1054c19800e8SDoug Rabson /** 1055c19800e8SDoug Rabson * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to 1056c19800e8SDoug Rabson * bind(2) to. The argument sa_size should initially contain the size 1057c19800e8SDoug Rabson * of the sa, and after the call, it will contain the actual length 1058c19800e8SDoug Rabson * of the address. 1059c19800e8SDoug Rabson * 1060c19800e8SDoug Rabson * @param context a Keberos context 1061c19800e8SDoug Rabson * @param af address family 1062c19800e8SDoug Rabson * @param sa sockaddr 1063c19800e8SDoug Rabson * @param sa_size lenght of sa. 1064c19800e8SDoug Rabson * @param port for to fill into sa. 1065c19800e8SDoug Rabson * 1066c19800e8SDoug Rabson * @return Return an error code or 0. 1067c19800e8SDoug Rabson * 1068c19800e8SDoug Rabson * @ingroup krb5_address 1069c19800e8SDoug Rabson */ 1070c19800e8SDoug Rabson 1071*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1072adb0ddaeSAssar Westerlund krb5_anyaddr (krb5_context context, 1073adb0ddaeSAssar Westerlund int af, 1074b528cefcSMark Murray struct sockaddr *sa, 10758373020dSJacques Vidrine krb5_socklen_t *sa_size, 1076b528cefcSMark Murray int port) 1077b528cefcSMark Murray { 1078b528cefcSMark Murray struct addr_operations *a = find_af (af); 1079b528cefcSMark Murray 1080adb0ddaeSAssar Westerlund if (a == NULL) { 1081*ae771770SStanislav Sedov krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1082*ae771770SStanislav Sedov N_("Address family %d not supported", ""), af); 1083b528cefcSMark Murray return KRB5_PROG_ATYPE_NOSUPP; 1084adb0ddaeSAssar Westerlund } 1085b528cefcSMark Murray 1086b528cefcSMark Murray (*a->anyaddr)(sa, sa_size, port); 1087b528cefcSMark Murray return 0; 1088b528cefcSMark Murray } 1089b528cefcSMark Murray 1090c19800e8SDoug Rabson /** 1091c19800e8SDoug Rabson * krb5_print_address prints the address in addr to the string string 1092c19800e8SDoug Rabson * that have the length len. If ret_len is not NULL, it will be filled 1093c19800e8SDoug Rabson * with the length of the string if size were unlimited (not including 1094c19800e8SDoug Rabson * the final NUL) . 1095c19800e8SDoug Rabson * 1096c19800e8SDoug Rabson * @param addr address to be printed 1097c19800e8SDoug Rabson * @param str pointer string to print the address into 1098c19800e8SDoug Rabson * @param len length that will fit into area pointed to by "str". 1099c19800e8SDoug Rabson * @param ret_len return length the str. 1100c19800e8SDoug Rabson * 1101c19800e8SDoug Rabson * @return Return an error code or 0. 1102c19800e8SDoug Rabson * 1103c19800e8SDoug Rabson * @ingroup krb5_address 1104c19800e8SDoug Rabson */ 1105c19800e8SDoug Rabson 1106*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1107b528cefcSMark Murray krb5_print_address (const krb5_address *addr, 1108b528cefcSMark Murray char *str, size_t len, size_t *ret_len) 1109b528cefcSMark Murray { 1110b528cefcSMark Murray struct addr_operations *a = find_atype(addr->addr_type); 1111c19800e8SDoug Rabson int ret; 1112b528cefcSMark Murray 1113bbd80c28SJacques Vidrine if (a == NULL || a->print_addr == NULL) { 1114b528cefcSMark Murray char *s; 11154137ff4cSJacques Vidrine int l; 1116*ae771770SStanislav Sedov size_t i; 11174137ff4cSJacques Vidrine 1118b528cefcSMark Murray s = str; 1119b528cefcSMark Murray l = snprintf(s, len, "TYPE_%d:", addr->addr_type); 1120*ae771770SStanislav Sedov if (l < 0 || (size_t)l >= len) 11214137ff4cSJacques Vidrine return EINVAL; 1122b528cefcSMark Murray s += l; 11234137ff4cSJacques Vidrine len -= l; 1124b528cefcSMark Murray for(i = 0; i < addr->address.length; i++) { 1125b528cefcSMark Murray l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); 1126*ae771770SStanislav Sedov if (l < 0 || (size_t)l >= len) 11274137ff4cSJacques Vidrine return EINVAL; 1128b528cefcSMark Murray len -= l; 1129b528cefcSMark Murray s += l; 1130b528cefcSMark Murray } 11318373020dSJacques Vidrine if(ret_len != NULL) 1132b528cefcSMark Murray *ret_len = s - str; 1133b528cefcSMark Murray return 0; 1134b528cefcSMark Murray } 11358373020dSJacques Vidrine ret = (*a->print_addr)(addr, str, len); 1136c19800e8SDoug Rabson if (ret < 0) 1137c19800e8SDoug Rabson return EINVAL; 11388373020dSJacques Vidrine if(ret_len != NULL) 11398373020dSJacques Vidrine *ret_len = ret; 1140b528cefcSMark Murray return 0; 1141b528cefcSMark Murray } 1142b528cefcSMark Murray 1143c19800e8SDoug Rabson /** 1144c19800e8SDoug Rabson * krb5_parse_address returns the resolved hostname in string to the 1145c19800e8SDoug Rabson * krb5_addresses addresses . 1146c19800e8SDoug Rabson * 1147c19800e8SDoug Rabson * @param context a Keberos context 1148c19800e8SDoug Rabson * @param string 1149c19800e8SDoug Rabson * @param addresses 1150c19800e8SDoug Rabson * 1151c19800e8SDoug Rabson * @return Return an error code or 0. 1152c19800e8SDoug Rabson * 1153c19800e8SDoug Rabson * @ingroup krb5_address 1154c19800e8SDoug Rabson */ 1155c19800e8SDoug Rabson 1156*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1157b528cefcSMark Murray krb5_parse_address(krb5_context context, 1158b528cefcSMark Murray const char *string, 1159b528cefcSMark Murray krb5_addresses *addresses) 1160b528cefcSMark Murray { 1161b528cefcSMark Murray int i, n; 1162b528cefcSMark Murray struct addrinfo *ai, *a; 1163b528cefcSMark Murray int error; 1164adb0ddaeSAssar Westerlund int save_errno; 1165b528cefcSMark Murray 1166c19800e8SDoug Rabson addresses->len = 0; 1167c19800e8SDoug Rabson addresses->val = NULL; 1168c19800e8SDoug Rabson 1169b528cefcSMark Murray for(i = 0; i < num_addrs; i++) { 1170b528cefcSMark Murray if(at[i].parse_addr) { 11718373020dSJacques Vidrine krb5_address addr; 11728373020dSJacques Vidrine if((*at[i].parse_addr)(context, string, &addr) == 0) { 1173b528cefcSMark Murray ALLOC_SEQ(addresses, 1); 1174c19800e8SDoug Rabson if (addresses->val == NULL) { 1175*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, 1176*ae771770SStanislav Sedov N_("malloc: out of memory", "")); 1177c19800e8SDoug Rabson return ENOMEM; 1178c19800e8SDoug Rabson } 11798373020dSJacques Vidrine addresses->val[0] = addr; 1180b528cefcSMark Murray return 0; 1181b528cefcSMark Murray } 1182b528cefcSMark Murray } 1183b528cefcSMark Murray } 1184b528cefcSMark Murray 1185b528cefcSMark Murray error = getaddrinfo (string, NULL, NULL, &ai); 1186adb0ddaeSAssar Westerlund if (error) { 1187*ae771770SStanislav Sedov krb5_error_code ret2; 1188adb0ddaeSAssar Westerlund save_errno = errno; 1189*ae771770SStanislav Sedov ret2 = krb5_eai_to_heim_errno(error, save_errno); 1190*ae771770SStanislav Sedov krb5_set_error_message (context, ret2, "%s: %s", 1191*ae771770SStanislav Sedov string, gai_strerror(error)); 1192*ae771770SStanislav Sedov return ret2; 1193adb0ddaeSAssar Westerlund } 1194b528cefcSMark Murray 1195b528cefcSMark Murray n = 0; 1196b528cefcSMark Murray for (a = ai; a != NULL; a = a->ai_next) 1197b528cefcSMark Murray ++n; 1198b528cefcSMark Murray 1199b528cefcSMark Murray ALLOC_SEQ(addresses, n); 1200c19800e8SDoug Rabson if (addresses->val == NULL) { 1201*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, 1202*ae771770SStanislav Sedov N_("malloc: out of memory", "")); 1203c19800e8SDoug Rabson freeaddrinfo(ai); 1204c19800e8SDoug Rabson return ENOMEM; 1205c19800e8SDoug Rabson } 1206b528cefcSMark Murray 1207c19800e8SDoug Rabson addresses->len = 0; 12088373020dSJacques Vidrine for (a = ai, i = 0; a != NULL; a = a->ai_next) { 1209c19800e8SDoug Rabson if (krb5_sockaddr2address (context, ai->ai_addr, &addresses->val[i])) 1210c19800e8SDoug Rabson continue; 1211*ae771770SStanislav Sedov if(krb5_address_search(context, &addresses->val[i], addresses)) { 1212*ae771770SStanislav Sedov krb5_free_address(context, &addresses->val[i]); 1213c19800e8SDoug Rabson continue; 1214*ae771770SStanislav Sedov } 12158373020dSJacques Vidrine i++; 1216*ae771770SStanislav Sedov addresses->len = i; 1217b528cefcSMark Murray } 1218b528cefcSMark Murray freeaddrinfo (ai); 1219b528cefcSMark Murray return 0; 1220b528cefcSMark Murray } 12214137ff4cSJacques Vidrine 1222c19800e8SDoug Rabson /** 1223c19800e8SDoug Rabson * krb5_address_order compares the addresses addr1 and addr2 so that 1224c19800e8SDoug Rabson * it can be used for sorting addresses. If the addresses are the same 1225c19800e8SDoug Rabson * address krb5_address_order will return 0. Behavies like memcmp(2). 1226c19800e8SDoug Rabson * 1227c19800e8SDoug Rabson * @param context a Keberos context 1228c19800e8SDoug Rabson * @param addr1 krb5_address to compare 1229c19800e8SDoug Rabson * @param addr2 krb5_address to compare 1230c19800e8SDoug Rabson * 1231c19800e8SDoug Rabson * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and 1232c19800e8SDoug Rabson * addr2 is the same address, > 0 if addr2 is "less" then addr1. 1233c19800e8SDoug Rabson * 1234c19800e8SDoug Rabson * @ingroup krb5_address 1235c19800e8SDoug Rabson */ 1236c19800e8SDoug Rabson 1237*ae771770SStanislav Sedov KRB5_LIB_FUNCTION int KRB5_LIB_CALL 12384137ff4cSJacques Vidrine krb5_address_order(krb5_context context, 12394137ff4cSJacques Vidrine const krb5_address *addr1, 12404137ff4cSJacques Vidrine const krb5_address *addr2) 12414137ff4cSJacques Vidrine { 12424137ff4cSJacques Vidrine /* this sucks; what if both addresses have order functions, which 12434137ff4cSJacques Vidrine should we call? this works for now, though */ 12444137ff4cSJacques Vidrine struct addr_operations *a; 12454137ff4cSJacques Vidrine a = find_atype(addr1->addr_type); 12464137ff4cSJacques Vidrine if(a == NULL) { 1247*ae771770SStanislav Sedov krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1248*ae771770SStanislav Sedov N_("Address family %d not supported", ""), 12494137ff4cSJacques Vidrine addr1->addr_type); 12504137ff4cSJacques Vidrine return KRB5_PROG_ATYPE_NOSUPP; 12514137ff4cSJacques Vidrine } 12524137ff4cSJacques Vidrine if(a->order_addr != NULL) 12534137ff4cSJacques Vidrine return (*a->order_addr)(context, addr1, addr2); 12544137ff4cSJacques Vidrine a = find_atype(addr2->addr_type); 12554137ff4cSJacques Vidrine if(a == NULL) { 1256*ae771770SStanislav Sedov krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1257*ae771770SStanislav Sedov N_("Address family %d not supported", ""), 12584137ff4cSJacques Vidrine addr2->addr_type); 12594137ff4cSJacques Vidrine return KRB5_PROG_ATYPE_NOSUPP; 12604137ff4cSJacques Vidrine } 12614137ff4cSJacques Vidrine if(a->order_addr != NULL) 12624137ff4cSJacques Vidrine return (*a->order_addr)(context, addr1, addr2); 12634137ff4cSJacques Vidrine 12644137ff4cSJacques Vidrine if(addr1->addr_type != addr2->addr_type) 12654137ff4cSJacques Vidrine return addr1->addr_type - addr2->addr_type; 12664137ff4cSJacques Vidrine if(addr1->address.length != addr2->address.length) 12674137ff4cSJacques Vidrine return addr1->address.length - addr2->address.length; 12684137ff4cSJacques Vidrine return memcmp (addr1->address.data, 12694137ff4cSJacques Vidrine addr2->address.data, 12704137ff4cSJacques Vidrine addr1->address.length); 12714137ff4cSJacques Vidrine } 12724137ff4cSJacques Vidrine 1273c19800e8SDoug Rabson /** 1274c19800e8SDoug Rabson * krb5_address_compare compares the addresses addr1 and addr2. 1275c19800e8SDoug Rabson * Returns TRUE if the two addresses are the same. 1276c19800e8SDoug Rabson * 1277c19800e8SDoug Rabson * @param context a Keberos context 1278c19800e8SDoug Rabson * @param addr1 address to compare 1279c19800e8SDoug Rabson * @param addr2 address to compare 1280c19800e8SDoug Rabson * 1281c19800e8SDoug Rabson * @return Return an TRUE is the address are the same FALSE if not 1282c19800e8SDoug Rabson * 1283c19800e8SDoug Rabson * @ingroup krb5_address 1284c19800e8SDoug Rabson */ 1285c19800e8SDoug Rabson 1286*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 12874137ff4cSJacques Vidrine krb5_address_compare(krb5_context context, 12884137ff4cSJacques Vidrine const krb5_address *addr1, 12894137ff4cSJacques Vidrine const krb5_address *addr2) 12904137ff4cSJacques Vidrine { 12914137ff4cSJacques Vidrine return krb5_address_order (context, addr1, addr2) == 0; 12924137ff4cSJacques Vidrine } 12934137ff4cSJacques Vidrine 1294c19800e8SDoug Rabson /** 1295c19800e8SDoug Rabson * krb5_address_search checks if the address addr is a member of the 1296c19800e8SDoug Rabson * address set list addrlist . 1297c19800e8SDoug Rabson * 1298c19800e8SDoug Rabson * @param context a Keberos context. 1299c19800e8SDoug Rabson * @param addr address to search for. 1300c19800e8SDoug Rabson * @param addrlist list of addresses to look in for addr. 1301c19800e8SDoug Rabson * 1302c19800e8SDoug Rabson * @return Return an error code or 0. 1303c19800e8SDoug Rabson * 1304c19800e8SDoug Rabson * @ingroup krb5_address 1305c19800e8SDoug Rabson */ 1306c19800e8SDoug Rabson 1307*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 13084137ff4cSJacques Vidrine krb5_address_search(krb5_context context, 13094137ff4cSJacques Vidrine const krb5_address *addr, 13104137ff4cSJacques Vidrine const krb5_addresses *addrlist) 13114137ff4cSJacques Vidrine { 1312*ae771770SStanislav Sedov size_t i; 13134137ff4cSJacques Vidrine 13144137ff4cSJacques Vidrine for (i = 0; i < addrlist->len; ++i) 13154137ff4cSJacques Vidrine if (krb5_address_compare (context, addr, &addrlist->val[i])) 13164137ff4cSJacques Vidrine return TRUE; 13174137ff4cSJacques Vidrine return FALSE; 13184137ff4cSJacques Vidrine } 13194137ff4cSJacques Vidrine 1320c19800e8SDoug Rabson /** 1321c19800e8SDoug Rabson * krb5_free_address frees the data stored in the address that is 1322c19800e8SDoug Rabson * alloced with any of the krb5_address functions. 1323c19800e8SDoug Rabson * 1324c19800e8SDoug Rabson * @param context a Keberos context 1325c19800e8SDoug Rabson * @param address addresss to be freed. 1326c19800e8SDoug Rabson * 1327c19800e8SDoug Rabson * @return Return an error code or 0. 1328c19800e8SDoug Rabson * 1329c19800e8SDoug Rabson * @ingroup krb5_address 1330c19800e8SDoug Rabson */ 1331c19800e8SDoug Rabson 1332*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 13334137ff4cSJacques Vidrine krb5_free_address(krb5_context context, 13344137ff4cSJacques Vidrine krb5_address *address) 13354137ff4cSJacques Vidrine { 1336c19800e8SDoug Rabson struct addr_operations *a = find_atype (address->addr_type); 13374137ff4cSJacques Vidrine if(a != NULL && a->free_addr != NULL) 13384137ff4cSJacques Vidrine return (*a->free_addr)(context, address); 13394137ff4cSJacques Vidrine krb5_data_free (&address->address); 1340c19800e8SDoug Rabson memset(address, 0, sizeof(*address)); 13414137ff4cSJacques Vidrine return 0; 13424137ff4cSJacques Vidrine } 13434137ff4cSJacques Vidrine 1344c19800e8SDoug Rabson /** 1345c19800e8SDoug Rabson * krb5_free_addresses frees the data stored in the address that is 1346c19800e8SDoug Rabson * alloced with any of the krb5_address functions. 1347c19800e8SDoug Rabson * 1348c19800e8SDoug Rabson * @param context a Keberos context 1349c19800e8SDoug Rabson * @param addresses addressses to be freed. 1350c19800e8SDoug Rabson * 1351c19800e8SDoug Rabson * @return Return an error code or 0. 1352c19800e8SDoug Rabson * 1353c19800e8SDoug Rabson * @ingroup krb5_address 1354c19800e8SDoug Rabson */ 1355c19800e8SDoug Rabson 1356*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 13574137ff4cSJacques Vidrine krb5_free_addresses(krb5_context context, 13584137ff4cSJacques Vidrine krb5_addresses *addresses) 13594137ff4cSJacques Vidrine { 1360*ae771770SStanislav Sedov size_t i; 13614137ff4cSJacques Vidrine for(i = 0; i < addresses->len; i++) 13624137ff4cSJacques Vidrine krb5_free_address(context, &addresses->val[i]); 13634137ff4cSJacques Vidrine free(addresses->val); 1364c19800e8SDoug Rabson addresses->len = 0; 1365c19800e8SDoug Rabson addresses->val = NULL; 13664137ff4cSJacques Vidrine return 0; 13674137ff4cSJacques Vidrine } 13684137ff4cSJacques Vidrine 1369c19800e8SDoug Rabson /** 1370c19800e8SDoug Rabson * krb5_copy_address copies the content of address 1371c19800e8SDoug Rabson * inaddr to outaddr. 1372c19800e8SDoug Rabson * 1373c19800e8SDoug Rabson * @param context a Keberos context 1374c19800e8SDoug Rabson * @param inaddr pointer to source address 1375c19800e8SDoug Rabson * @param outaddr pointer to destination address 1376c19800e8SDoug Rabson * 1377c19800e8SDoug Rabson * @return Return an error code or 0. 1378c19800e8SDoug Rabson * 1379c19800e8SDoug Rabson * @ingroup krb5_address 1380c19800e8SDoug Rabson */ 1381c19800e8SDoug Rabson 1382*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 13834137ff4cSJacques Vidrine krb5_copy_address(krb5_context context, 13844137ff4cSJacques Vidrine const krb5_address *inaddr, 13854137ff4cSJacques Vidrine krb5_address *outaddr) 13864137ff4cSJacques Vidrine { 13874137ff4cSJacques Vidrine struct addr_operations *a = find_af (inaddr->addr_type); 13884137ff4cSJacques Vidrine if(a != NULL && a->copy_addr != NULL) 13894137ff4cSJacques Vidrine return (*a->copy_addr)(context, inaddr, outaddr); 13904137ff4cSJacques Vidrine return copy_HostAddress(inaddr, outaddr); 13914137ff4cSJacques Vidrine } 13924137ff4cSJacques Vidrine 1393c19800e8SDoug Rabson /** 1394c19800e8SDoug Rabson * krb5_copy_addresses copies the content of addresses 1395c19800e8SDoug Rabson * inaddr to outaddr. 1396c19800e8SDoug Rabson * 1397c19800e8SDoug Rabson * @param context a Keberos context 1398c19800e8SDoug Rabson * @param inaddr pointer to source addresses 1399c19800e8SDoug Rabson * @param outaddr pointer to destination addresses 1400c19800e8SDoug Rabson * 1401c19800e8SDoug Rabson * @return Return an error code or 0. 1402c19800e8SDoug Rabson * 1403c19800e8SDoug Rabson * @ingroup krb5_address 1404c19800e8SDoug Rabson */ 1405c19800e8SDoug Rabson 1406*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 14074137ff4cSJacques Vidrine krb5_copy_addresses(krb5_context context, 14084137ff4cSJacques Vidrine const krb5_addresses *inaddr, 14094137ff4cSJacques Vidrine krb5_addresses *outaddr) 14104137ff4cSJacques Vidrine { 1411*ae771770SStanislav Sedov size_t i; 14124137ff4cSJacques Vidrine ALLOC_SEQ(outaddr, inaddr->len); 14134137ff4cSJacques Vidrine if(inaddr->len > 0 && outaddr->val == NULL) 14144137ff4cSJacques Vidrine return ENOMEM; 14154137ff4cSJacques Vidrine for(i = 0; i < inaddr->len; i++) 14164137ff4cSJacques Vidrine krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]); 14174137ff4cSJacques Vidrine return 0; 14184137ff4cSJacques Vidrine } 14194137ff4cSJacques Vidrine 1420c19800e8SDoug Rabson /** 1421c19800e8SDoug Rabson * krb5_append_addresses adds the set of addresses in source to 1422c19800e8SDoug Rabson * dest. While copying the addresses, duplicates are also sorted out. 1423c19800e8SDoug Rabson * 1424c19800e8SDoug Rabson * @param context a Keberos context 1425c19800e8SDoug Rabson * @param dest destination of copy operation 1426c19800e8SDoug Rabson * @param source adresses that are going to be added to dest 1427c19800e8SDoug Rabson * 1428c19800e8SDoug Rabson * @return Return an error code or 0. 1429c19800e8SDoug Rabson * 1430c19800e8SDoug Rabson * @ingroup krb5_address 1431c19800e8SDoug Rabson */ 1432c19800e8SDoug Rabson 1433*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 14344137ff4cSJacques Vidrine krb5_append_addresses(krb5_context context, 14354137ff4cSJacques Vidrine krb5_addresses *dest, 14364137ff4cSJacques Vidrine const krb5_addresses *source) 14374137ff4cSJacques Vidrine { 14384137ff4cSJacques Vidrine krb5_address *tmp; 14394137ff4cSJacques Vidrine krb5_error_code ret; 1440*ae771770SStanislav Sedov size_t i; 14414137ff4cSJacques Vidrine if(source->len > 0) { 14424137ff4cSJacques Vidrine tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp)); 14434137ff4cSJacques Vidrine if(tmp == NULL) { 1444*ae771770SStanislav Sedov krb5_set_error_message (context, ENOMEM, 1445*ae771770SStanislav Sedov N_("malloc: out of memory", "")); 14464137ff4cSJacques Vidrine return ENOMEM; 14474137ff4cSJacques Vidrine } 14484137ff4cSJacques Vidrine dest->val = tmp; 14494137ff4cSJacques Vidrine for(i = 0; i < source->len; i++) { 14504137ff4cSJacques Vidrine /* skip duplicates */ 14514137ff4cSJacques Vidrine if(krb5_address_search(context, &source->val[i], dest)) 14524137ff4cSJacques Vidrine continue; 14534137ff4cSJacques Vidrine ret = krb5_copy_address(context, 14544137ff4cSJacques Vidrine &source->val[i], 14554137ff4cSJacques Vidrine &dest->val[dest->len]); 14564137ff4cSJacques Vidrine if(ret) 14574137ff4cSJacques Vidrine return ret; 14584137ff4cSJacques Vidrine dest->len++; 14594137ff4cSJacques Vidrine } 14604137ff4cSJacques Vidrine } 14614137ff4cSJacques Vidrine return 0; 14624137ff4cSJacques Vidrine } 14634137ff4cSJacques Vidrine 1464c19800e8SDoug Rabson /** 14654137ff4cSJacques Vidrine * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port) 1466c19800e8SDoug Rabson * 1467c19800e8SDoug Rabson * @param context a Keberos context 1468c19800e8SDoug Rabson * @param res built address from addr/port 1469c19800e8SDoug Rabson * @param addr address to use 1470c19800e8SDoug Rabson * @param port port to use 1471c19800e8SDoug Rabson * 1472c19800e8SDoug Rabson * @return Return an error code or 0. 1473c19800e8SDoug Rabson * 1474c19800e8SDoug Rabson * @ingroup krb5_address 14754137ff4cSJacques Vidrine */ 14764137ff4cSJacques Vidrine 1477*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 14784137ff4cSJacques Vidrine krb5_make_addrport (krb5_context context, 14794137ff4cSJacques Vidrine krb5_address **res, const krb5_address *addr, int16_t port) 14804137ff4cSJacques Vidrine { 14814137ff4cSJacques Vidrine krb5_error_code ret; 14824137ff4cSJacques Vidrine size_t len = addr->address.length + 2 + 4 * 4; 14834137ff4cSJacques Vidrine u_char *p; 14844137ff4cSJacques Vidrine 14854137ff4cSJacques Vidrine *res = malloc (sizeof(**res)); 14864137ff4cSJacques Vidrine if (*res == NULL) { 1487*ae771770SStanislav Sedov krb5_set_error_message (context, ENOMEM, 1488*ae771770SStanislav Sedov N_("malloc: out of memory", "")); 14894137ff4cSJacques Vidrine return ENOMEM; 14904137ff4cSJacques Vidrine } 14914137ff4cSJacques Vidrine (*res)->addr_type = KRB5_ADDRESS_ADDRPORT; 14924137ff4cSJacques Vidrine ret = krb5_data_alloc (&(*res)->address, len); 14934137ff4cSJacques Vidrine if (ret) { 1494*ae771770SStanislav Sedov krb5_set_error_message (context, ret, 1495*ae771770SStanislav Sedov N_("malloc: out of memory", "")); 14964137ff4cSJacques Vidrine free (*res); 1497c19800e8SDoug Rabson *res = NULL; 14984137ff4cSJacques Vidrine return ret; 14994137ff4cSJacques Vidrine } 15004137ff4cSJacques Vidrine p = (*res)->address.data; 15014137ff4cSJacques Vidrine *p++ = 0; 15024137ff4cSJacques Vidrine *p++ = 0; 15034137ff4cSJacques Vidrine *p++ = (addr->addr_type ) & 0xFF; 15044137ff4cSJacques Vidrine *p++ = (addr->addr_type >> 8) & 0xFF; 15054137ff4cSJacques Vidrine 15064137ff4cSJacques Vidrine *p++ = (addr->address.length ) & 0xFF; 15074137ff4cSJacques Vidrine *p++ = (addr->address.length >> 8) & 0xFF; 15084137ff4cSJacques Vidrine *p++ = (addr->address.length >> 16) & 0xFF; 15094137ff4cSJacques Vidrine *p++ = (addr->address.length >> 24) & 0xFF; 15104137ff4cSJacques Vidrine 15114137ff4cSJacques Vidrine memcpy (p, addr->address.data, addr->address.length); 15124137ff4cSJacques Vidrine p += addr->address.length; 15134137ff4cSJacques Vidrine 15144137ff4cSJacques Vidrine *p++ = 0; 15154137ff4cSJacques Vidrine *p++ = 0; 15164137ff4cSJacques Vidrine *p++ = (KRB5_ADDRESS_IPPORT ) & 0xFF; 15174137ff4cSJacques Vidrine *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF; 15184137ff4cSJacques Vidrine 15194137ff4cSJacques Vidrine *p++ = (2 ) & 0xFF; 15204137ff4cSJacques Vidrine *p++ = (2 >> 8) & 0xFF; 15214137ff4cSJacques Vidrine *p++ = (2 >> 16) & 0xFF; 15224137ff4cSJacques Vidrine *p++ = (2 >> 24) & 0xFF; 15234137ff4cSJacques Vidrine 15244137ff4cSJacques Vidrine memcpy (p, &port, 2); 15254137ff4cSJacques Vidrine 15264137ff4cSJacques Vidrine return 0; 15274137ff4cSJacques Vidrine } 1528c19800e8SDoug Rabson 1529c19800e8SDoug Rabson /** 1530c19800e8SDoug Rabson * Calculate the boundary addresses of `inaddr'/`prefixlen' and store 1531c19800e8SDoug Rabson * them in `low' and `high'. 1532c19800e8SDoug Rabson * 1533c19800e8SDoug Rabson * @param context a Keberos context 1534c19800e8SDoug Rabson * @param inaddr address in prefixlen that the bondery searched 1535c19800e8SDoug Rabson * @param prefixlen width of boundery 1536c19800e8SDoug Rabson * @param low lowest address 1537c19800e8SDoug Rabson * @param high highest address 1538c19800e8SDoug Rabson * 1539c19800e8SDoug Rabson * @return Return an error code or 0. 1540c19800e8SDoug Rabson * 1541c19800e8SDoug Rabson * @ingroup krb5_address 1542c19800e8SDoug Rabson */ 1543c19800e8SDoug Rabson 1544*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1545c19800e8SDoug Rabson krb5_address_prefixlen_boundary(krb5_context context, 1546c19800e8SDoug Rabson const krb5_address *inaddr, 1547c19800e8SDoug Rabson unsigned long prefixlen, 1548c19800e8SDoug Rabson krb5_address *low, 1549c19800e8SDoug Rabson krb5_address *high) 1550c19800e8SDoug Rabson { 1551c19800e8SDoug Rabson struct addr_operations *a = find_atype (inaddr->addr_type); 1552c19800e8SDoug Rabson if(a != NULL && a->mask_boundary != NULL) 1553c19800e8SDoug Rabson return (*a->mask_boundary)(context, inaddr, prefixlen, low, high); 1554*ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 1555*ae771770SStanislav Sedov N_("Address family %d doesn't support " 1556*ae771770SStanislav Sedov "address mask operation", ""), 1557*ae771770SStanislav Sedov inaddr->addr_type); 1558c19800e8SDoug Rabson return KRB5_PROG_ATYPE_NOSUPP; 1559c19800e8SDoug Rabson } 1560