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