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