1 /* $NetBSD: addr_families.c,v 1.1.1.2 2014/04/24 12:45:49 pettai 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 size_t 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 UNREACHABLE(return 0); 660 } 661 662 if(a2->addr_type == KRB5_ADDRESS_ARANGE) { 663 struct arange *b = a2->address.data; 664 tmp1 = krb5_address_order(context, &a->low, &b->low); 665 if(tmp1 != 0) 666 return sign * tmp1; 667 return sign * krb5_address_order(context, &a->high, &b->high); 668 } else if(a2->addr_type == a->low.addr_type) { 669 tmp1 = krb5_address_order(context, &a->low, a2); 670 if(tmp1 > 0) 671 return sign; 672 tmp2 = krb5_address_order(context, &a->high, a2); 673 if(tmp2 < 0) 674 return -sign; 675 return 0; 676 } else { 677 return sign * (addr1->addr_type - addr2->addr_type); 678 } 679 } 680 681 #endif /* HEIMDAL_SMALLER */ 682 683 static int 684 addrport_print_addr (const krb5_address *addr, char *str, size_t len) 685 { 686 krb5_error_code ret; 687 krb5_address addr1, addr2; 688 uint16_t port = 0; 689 size_t ret_len = 0, l, size = 0; 690 krb5_storage *sp; 691 692 sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address)); 693 if (sp == NULL) 694 return ENOMEM; 695 696 /* for totally obscure reasons, these are not in network byteorder */ 697 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 698 699 krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */ 700 krb5_ret_address(sp, &addr1); 701 702 krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */ 703 krb5_ret_address(sp, &addr2); 704 krb5_storage_free(sp); 705 if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) { 706 unsigned long value; 707 _krb5_get_int(addr2.address.data, &value, 2); 708 port = value; 709 } 710 l = strlcpy(str, "ADDRPORT:", len); 711 ret_len += l; 712 if (len > l) 713 size += l; 714 else 715 size = len; 716 717 ret = krb5_print_address(&addr1, str + size, len - size, &l); 718 if (ret) 719 return ret; 720 ret_len += l; 721 if (len - size > l) 722 size += l; 723 else 724 size = len; 725 726 ret = snprintf(str + size, len - size, ",PORT=%u", port); 727 if (ret < 0) 728 return EINVAL; 729 ret_len += ret; 730 return ret_len; 731 } 732 733 static struct addr_operations at[] = { 734 { 735 AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), 736 ipv4_sockaddr2addr, 737 ipv4_sockaddr2port, 738 ipv4_addr2sockaddr, 739 ipv4_h_addr2sockaddr, 740 ipv4_h_addr2addr, 741 ipv4_uninteresting, 742 ipv4_is_loopback, 743 ipv4_anyaddr, 744 ipv4_print_addr, 745 ipv4_parse_addr, 746 NULL, 747 NULL, 748 NULL, 749 ipv4_mask_boundary 750 }, 751 #ifdef HAVE_IPV6 752 { 753 AF_INET6, KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6), 754 ipv6_sockaddr2addr, 755 ipv6_sockaddr2port, 756 ipv6_addr2sockaddr, 757 ipv6_h_addr2sockaddr, 758 ipv6_h_addr2addr, 759 ipv6_uninteresting, 760 ipv6_is_loopback, 761 ipv6_anyaddr, 762 ipv6_print_addr, 763 ipv6_parse_addr, 764 NULL, 765 NULL, 766 NULL, 767 ipv6_mask_boundary 768 } , 769 #endif 770 #ifndef HEIMDAL_SMALLER 771 /* fake address type */ 772 { 773 KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange), 774 NULL, 775 NULL, 776 NULL, 777 NULL, 778 NULL, 779 NULL, 780 NULL, 781 NULL, 782 arange_print_addr, 783 arange_parse_addr, 784 arange_order_addr, 785 arange_free, 786 arange_copy, 787 NULL 788 }, 789 #endif 790 { 791 KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0, 792 NULL, 793 NULL, 794 NULL, 795 NULL, 796 NULL, 797 NULL, 798 NULL, 799 NULL, 800 addrport_print_addr, 801 NULL, 802 NULL, 803 NULL, 804 NULL 805 } 806 }; 807 808 static int num_addrs = sizeof(at) / sizeof(at[0]); 809 810 static size_t max_sockaddr_size = 0; 811 812 /* 813 * generic functions 814 */ 815 816 static struct addr_operations * 817 find_af(int af) 818 { 819 struct addr_operations *a; 820 821 for (a = at; a < at + num_addrs; ++a) 822 if (af == a->af) 823 return a; 824 return NULL; 825 } 826 827 static struct addr_operations * 828 find_atype(krb5_address_type atype) 829 { 830 struct addr_operations *a; 831 832 for (a = at; a < at + num_addrs; ++a) 833 if (atype == a->atype) 834 return a; 835 return NULL; 836 } 837 838 /** 839 * krb5_sockaddr2address stores a address a "struct sockaddr" sa in 840 * the krb5_address addr. 841 * 842 * @param context a Keberos context 843 * @param sa a struct sockaddr to extract the address from 844 * @param addr an Kerberos 5 address to store the address in. 845 * 846 * @return Return an error code or 0. 847 * 848 * @ingroup krb5_address 849 */ 850 851 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 852 krb5_sockaddr2address (krb5_context context, 853 const struct sockaddr *sa, krb5_address *addr) 854 { 855 struct addr_operations *a = find_af(sa->sa_family); 856 if (a == NULL) { 857 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 858 N_("Address family %d not supported", ""), 859 sa->sa_family); 860 return KRB5_PROG_ATYPE_NOSUPP; 861 } 862 return (*a->sockaddr2addr)(sa, addr); 863 } 864 865 /** 866 * krb5_sockaddr2port extracts a port (if possible) from a "struct 867 * sockaddr. 868 * 869 * @param context a Keberos context 870 * @param sa a struct sockaddr to extract the port from 871 * @param port a pointer to an int16_t store the port in. 872 * 873 * @return Return an error code or 0. Will return 874 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 875 * 876 * @ingroup krb5_address 877 */ 878 879 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 880 krb5_sockaddr2port (krb5_context context, 881 const struct sockaddr *sa, int16_t *port) 882 { 883 struct addr_operations *a = find_af(sa->sa_family); 884 if (a == NULL) { 885 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 886 N_("Address family %d not supported", ""), 887 sa->sa_family); 888 return KRB5_PROG_ATYPE_NOSUPP; 889 } 890 return (*a->sockaddr2port)(sa, port); 891 } 892 893 /** 894 * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr 895 * and port. The argument sa_size should initially contain the size of 896 * the sa and after the call, it will contain the actual length of the 897 * address. In case of the sa is too small to fit the whole address, 898 * the up to *sa_size will be stored, and then *sa_size will be set to 899 * the required length. 900 * 901 * @param context a Keberos context 902 * @param addr the address to copy the from 903 * @param sa the struct sockaddr that will be filled in 904 * @param sa_size pointer to length of sa, and after the call, it will 905 * contain the actual length of the address. 906 * @param port set port in sa. 907 * 908 * @return Return an error code or 0. Will return 909 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 910 * 911 * @ingroup krb5_address 912 */ 913 914 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 915 krb5_addr2sockaddr (krb5_context context, 916 const krb5_address *addr, 917 struct sockaddr *sa, 918 krb5_socklen_t *sa_size, 919 int port) 920 { 921 struct addr_operations *a = find_atype(addr->addr_type); 922 923 if (a == NULL) { 924 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 925 N_("Address type %d not supported", 926 "krb5_address type"), 927 addr->addr_type); 928 return KRB5_PROG_ATYPE_NOSUPP; 929 } 930 if (a->addr2sockaddr == NULL) { 931 krb5_set_error_message (context, 932 KRB5_PROG_ATYPE_NOSUPP, 933 N_("Can't convert address type %d to sockaddr", ""), 934 addr->addr_type); 935 return KRB5_PROG_ATYPE_NOSUPP; 936 } 937 (*a->addr2sockaddr)(addr, sa, sa_size, port); 938 return 0; 939 } 940 941 /** 942 * krb5_max_sockaddr_size returns the max size of the .Li struct 943 * sockaddr that the Kerberos library will return. 944 * 945 * @return Return an size_t of the maximum struct sockaddr. 946 * 947 * @ingroup krb5_address 948 */ 949 950 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 951 krb5_max_sockaddr_size (void) 952 { 953 if (max_sockaddr_size == 0) { 954 struct addr_operations *a; 955 956 for(a = at; a < at + num_addrs; ++a) 957 max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size); 958 } 959 return max_sockaddr_size; 960 } 961 962 /** 963 * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the 964 * kerberos library thinks are uninteresting. One example are link 965 * local addresses. 966 * 967 * @param sa pointer to struct sockaddr that might be interesting. 968 * 969 * @return Return a non zero for uninteresting addresses. 970 * 971 * @ingroup krb5_address 972 */ 973 974 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 975 krb5_sockaddr_uninteresting(const struct sockaddr *sa) 976 { 977 struct addr_operations *a = find_af(sa->sa_family); 978 if (a == NULL || a->uninteresting == NULL) 979 return TRUE; 980 return (*a->uninteresting)(sa); 981 } 982 983 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 984 krb5_sockaddr_is_loopback(const struct sockaddr *sa) 985 { 986 struct addr_operations *a = find_af(sa->sa_family); 987 if (a == NULL || a->is_loopback == NULL) 988 return TRUE; 989 return (*a->is_loopback)(sa); 990 } 991 992 /** 993 * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and 994 * the "struct hostent" (see gethostbyname(3) ) h_addr_list 995 * component. The argument sa_size should initially contain the size 996 * of the sa, and after the call, it will contain the actual length of 997 * the address. 998 * 999 * @param context a Keberos context 1000 * @param af addresses 1001 * @param addr address 1002 * @param sa returned struct sockaddr 1003 * @param sa_size size of sa 1004 * @param port port to set in sa. 1005 * 1006 * @return Return an error code or 0. 1007 * 1008 * @ingroup krb5_address 1009 */ 1010 1011 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1012 krb5_h_addr2sockaddr (krb5_context context, 1013 int af, 1014 const char *addr, struct sockaddr *sa, 1015 krb5_socklen_t *sa_size, 1016 int port) 1017 { 1018 struct addr_operations *a = find_af(af); 1019 if (a == NULL) { 1020 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1021 "Address family %d not supported", af); 1022 return KRB5_PROG_ATYPE_NOSUPP; 1023 } 1024 (*a->h_addr2sockaddr)(addr, sa, sa_size, port); 1025 return 0; 1026 } 1027 1028 /** 1029 * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception 1030 * that it operates on a krb5_address instead of a struct sockaddr. 1031 * 1032 * @param context a Keberos context 1033 * @param af address family 1034 * @param haddr host address from struct hostent. 1035 * @param addr returned krb5_address. 1036 * 1037 * @return Return an error code or 0. 1038 * 1039 * @ingroup krb5_address 1040 */ 1041 1042 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1043 krb5_h_addr2addr (krb5_context context, 1044 int af, 1045 const char *haddr, krb5_address *addr) 1046 { 1047 struct addr_operations *a = find_af(af); 1048 if (a == NULL) { 1049 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1050 N_("Address family %d not supported", ""), af); 1051 return KRB5_PROG_ATYPE_NOSUPP; 1052 } 1053 return (*a->h_addr2addr)(haddr, addr); 1054 } 1055 1056 /** 1057 * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to 1058 * bind(2) to. The argument sa_size should initially contain the size 1059 * of the sa, and after the call, it will contain the actual length 1060 * of the address. 1061 * 1062 * @param context a Keberos context 1063 * @param af address family 1064 * @param sa sockaddr 1065 * @param sa_size lenght of sa. 1066 * @param port for to fill into sa. 1067 * 1068 * @return Return an error code or 0. 1069 * 1070 * @ingroup krb5_address 1071 */ 1072 1073 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1074 krb5_anyaddr (krb5_context context, 1075 int af, 1076 struct sockaddr *sa, 1077 krb5_socklen_t *sa_size, 1078 int port) 1079 { 1080 struct addr_operations *a = find_af (af); 1081 1082 if (a == NULL) { 1083 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1084 N_("Address family %d not supported", ""), af); 1085 return KRB5_PROG_ATYPE_NOSUPP; 1086 } 1087 1088 (*a->anyaddr)(sa, sa_size, port); 1089 return 0; 1090 } 1091 1092 /** 1093 * krb5_print_address prints the address in addr to the string string 1094 * that have the length len. If ret_len is not NULL, it will be filled 1095 * with the length of the string if size were unlimited (not including 1096 * the final NUL) . 1097 * 1098 * @param addr address to be printed 1099 * @param str pointer string to print the address into 1100 * @param len length that will fit into area pointed to by "str". 1101 * @param ret_len return length the str. 1102 * 1103 * @return Return an error code or 0. 1104 * 1105 * @ingroup krb5_address 1106 */ 1107 1108 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1109 krb5_print_address (const krb5_address *addr, 1110 char *str, size_t len, size_t *ret_len) 1111 { 1112 struct addr_operations *a = find_atype(addr->addr_type); 1113 int ret; 1114 1115 if (a == NULL || a->print_addr == NULL) { 1116 char *s; 1117 int l; 1118 size_t i; 1119 1120 s = str; 1121 l = snprintf(s, len, "TYPE_%d:", addr->addr_type); 1122 if (l < 0 || (size_t)l >= len) 1123 return EINVAL; 1124 s += l; 1125 len -= l; 1126 for(i = 0; i < addr->address.length; i++) { 1127 l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); 1128 if (l < 0 || (size_t)l >= len) 1129 return EINVAL; 1130 len -= l; 1131 s += l; 1132 } 1133 if(ret_len != NULL) 1134 *ret_len = s - str; 1135 return 0; 1136 } 1137 ret = (*a->print_addr)(addr, str, len); 1138 if (ret < 0) 1139 return EINVAL; 1140 if(ret_len != NULL) 1141 *ret_len = ret; 1142 return 0; 1143 } 1144 1145 /** 1146 * krb5_parse_address returns the resolved hostname in string to the 1147 * krb5_addresses addresses . 1148 * 1149 * @param context a Keberos context 1150 * @param string 1151 * @param addresses 1152 * 1153 * @return Return an error code or 0. 1154 * 1155 * @ingroup krb5_address 1156 */ 1157 1158 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1159 krb5_parse_address(krb5_context context, 1160 const char *string, 1161 krb5_addresses *addresses) 1162 { 1163 int i, n; 1164 struct addrinfo *ai, *a; 1165 int error; 1166 int save_errno; 1167 1168 addresses->len = 0; 1169 addresses->val = NULL; 1170 1171 for(i = 0; i < num_addrs; i++) { 1172 if(at[i].parse_addr) { 1173 krb5_address addr; 1174 if((*at[i].parse_addr)(context, string, &addr) == 0) { 1175 ALLOC_SEQ(addresses, 1); 1176 if (addresses->val == NULL) { 1177 krb5_set_error_message(context, ENOMEM, 1178 N_("malloc: out of memory", "")); 1179 return ENOMEM; 1180 } 1181 addresses->val[0] = addr; 1182 return 0; 1183 } 1184 } 1185 } 1186 1187 error = getaddrinfo (string, NULL, NULL, &ai); 1188 if (error) { 1189 krb5_error_code ret2; 1190 save_errno = errno; 1191 ret2 = krb5_eai_to_heim_errno(error, save_errno); 1192 krb5_set_error_message (context, ret2, "%s: %s", 1193 string, gai_strerror(error)); 1194 return ret2; 1195 } 1196 1197 n = 0; 1198 for (a = ai; a != NULL; a = a->ai_next) 1199 ++n; 1200 1201 ALLOC_SEQ(addresses, n); 1202 if (addresses->val == NULL) { 1203 krb5_set_error_message(context, ENOMEM, 1204 N_("malloc: out of memory", "")); 1205 freeaddrinfo(ai); 1206 return ENOMEM; 1207 } 1208 1209 addresses->len = 0; 1210 for (a = ai, i = 0; a != NULL; a = a->ai_next) { 1211 if (krb5_sockaddr2address (context, a->ai_addr, &addresses->val[i])) 1212 continue; 1213 if(krb5_address_search(context, &addresses->val[i], addresses)) { 1214 krb5_free_address(context, &addresses->val[i]); 1215 continue; 1216 } 1217 i++; 1218 addresses->len = i; 1219 } 1220 freeaddrinfo (ai); 1221 return 0; 1222 } 1223 1224 /** 1225 * krb5_address_order compares the addresses addr1 and addr2 so that 1226 * it can be used for sorting addresses. If the addresses are the same 1227 * address krb5_address_order will return 0. Behavies like memcmp(2). 1228 * 1229 * @param context a Keberos context 1230 * @param addr1 krb5_address to compare 1231 * @param addr2 krb5_address to compare 1232 * 1233 * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and 1234 * addr2 is the same address, > 0 if addr2 is "less" then addr1. 1235 * 1236 * @ingroup krb5_address 1237 */ 1238 1239 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1240 krb5_address_order(krb5_context context, 1241 const krb5_address *addr1, 1242 const krb5_address *addr2) 1243 { 1244 /* this sucks; what if both addresses have order functions, which 1245 should we call? this works for now, though */ 1246 struct addr_operations *a; 1247 a = find_atype(addr1->addr_type); 1248 if(a == NULL) { 1249 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1250 N_("Address family %d not supported", ""), 1251 addr1->addr_type); 1252 return KRB5_PROG_ATYPE_NOSUPP; 1253 } 1254 if(a->order_addr != NULL) 1255 return (*a->order_addr)(context, addr1, addr2); 1256 a = find_atype(addr2->addr_type); 1257 if(a == NULL) { 1258 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1259 N_("Address family %d not supported", ""), 1260 addr2->addr_type); 1261 return KRB5_PROG_ATYPE_NOSUPP; 1262 } 1263 if(a->order_addr != NULL) 1264 return (*a->order_addr)(context, addr1, addr2); 1265 1266 if(addr1->addr_type != addr2->addr_type) 1267 return addr1->addr_type - addr2->addr_type; 1268 if(addr1->address.length != addr2->address.length) 1269 return addr1->address.length - addr2->address.length; 1270 return memcmp (addr1->address.data, 1271 addr2->address.data, 1272 addr1->address.length); 1273 } 1274 1275 /** 1276 * krb5_address_compare compares the addresses addr1 and addr2. 1277 * Returns TRUE if the two addresses are the same. 1278 * 1279 * @param context a Keberos context 1280 * @param addr1 address to compare 1281 * @param addr2 address to compare 1282 * 1283 * @return Return an TRUE is the address are the same FALSE if not 1284 * 1285 * @ingroup krb5_address 1286 */ 1287 1288 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1289 krb5_address_compare(krb5_context context, 1290 const krb5_address *addr1, 1291 const krb5_address *addr2) 1292 { 1293 return krb5_address_order (context, addr1, addr2) == 0; 1294 } 1295 1296 /** 1297 * krb5_address_search checks if the address addr is a member of the 1298 * address set list addrlist . 1299 * 1300 * @param context a Keberos context. 1301 * @param addr address to search for. 1302 * @param addrlist list of addresses to look in for addr. 1303 * 1304 * @return Return an error code or 0. 1305 * 1306 * @ingroup krb5_address 1307 */ 1308 1309 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1310 krb5_address_search(krb5_context context, 1311 const krb5_address *addr, 1312 const krb5_addresses *addrlist) 1313 { 1314 size_t i; 1315 1316 for (i = 0; i < addrlist->len; ++i) 1317 if (krb5_address_compare (context, addr, &addrlist->val[i])) 1318 return TRUE; 1319 return FALSE; 1320 } 1321 1322 /** 1323 * krb5_free_address frees the data stored in the address that is 1324 * alloced with any of the krb5_address functions. 1325 * 1326 * @param context a Keberos context 1327 * @param address addresss to be freed. 1328 * 1329 * @return Return an error code or 0. 1330 * 1331 * @ingroup krb5_address 1332 */ 1333 1334 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1335 krb5_free_address(krb5_context context, 1336 krb5_address *address) 1337 { 1338 struct addr_operations *a = find_atype (address->addr_type); 1339 if(a != NULL && a->free_addr != NULL) 1340 return (*a->free_addr)(context, address); 1341 krb5_data_free (&address->address); 1342 memset(address, 0, sizeof(*address)); 1343 return 0; 1344 } 1345 1346 /** 1347 * krb5_free_addresses frees the data stored in the address that is 1348 * alloced with any of the krb5_address functions. 1349 * 1350 * @param context a Keberos context 1351 * @param addresses addressses to be freed. 1352 * 1353 * @return Return an error code or 0. 1354 * 1355 * @ingroup krb5_address 1356 */ 1357 1358 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1359 krb5_free_addresses(krb5_context context, 1360 krb5_addresses *addresses) 1361 { 1362 size_t i; 1363 for(i = 0; i < addresses->len; i++) 1364 krb5_free_address(context, &addresses->val[i]); 1365 free(addresses->val); 1366 addresses->len = 0; 1367 addresses->val = NULL; 1368 return 0; 1369 } 1370 1371 /** 1372 * krb5_copy_address copies the content of address 1373 * inaddr to outaddr. 1374 * 1375 * @param context a Keberos context 1376 * @param inaddr pointer to source address 1377 * @param outaddr pointer to destination address 1378 * 1379 * @return Return an error code or 0. 1380 * 1381 * @ingroup krb5_address 1382 */ 1383 1384 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1385 krb5_copy_address(krb5_context context, 1386 const krb5_address *inaddr, 1387 krb5_address *outaddr) 1388 { 1389 struct addr_operations *a = find_af (inaddr->addr_type); 1390 if(a != NULL && a->copy_addr != NULL) 1391 return (*a->copy_addr)(context, inaddr, outaddr); 1392 return copy_HostAddress(inaddr, outaddr); 1393 } 1394 1395 /** 1396 * krb5_copy_addresses copies the content of addresses 1397 * inaddr to outaddr. 1398 * 1399 * @param context a Keberos context 1400 * @param inaddr pointer to source addresses 1401 * @param outaddr pointer to destination addresses 1402 * 1403 * @return Return an error code or 0. 1404 * 1405 * @ingroup krb5_address 1406 */ 1407 1408 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1409 krb5_copy_addresses(krb5_context context, 1410 const krb5_addresses *inaddr, 1411 krb5_addresses *outaddr) 1412 { 1413 size_t i; 1414 ALLOC_SEQ(outaddr, inaddr->len); 1415 if(inaddr->len > 0 && outaddr->val == NULL) 1416 return ENOMEM; 1417 for(i = 0; i < inaddr->len; i++) 1418 krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]); 1419 return 0; 1420 } 1421 1422 /** 1423 * krb5_append_addresses adds the set of addresses in source to 1424 * dest. While copying the addresses, duplicates are also sorted out. 1425 * 1426 * @param context a Keberos context 1427 * @param dest destination of copy operation 1428 * @param source adresses that are going to be added to dest 1429 * 1430 * @return Return an error code or 0. 1431 * 1432 * @ingroup krb5_address 1433 */ 1434 1435 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1436 krb5_append_addresses(krb5_context context, 1437 krb5_addresses *dest, 1438 const krb5_addresses *source) 1439 { 1440 krb5_address *tmp; 1441 krb5_error_code ret; 1442 size_t i; 1443 if(source->len > 0) { 1444 tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp)); 1445 if(tmp == NULL) { 1446 krb5_set_error_message (context, ENOMEM, 1447 N_("malloc: out of memory", "")); 1448 return ENOMEM; 1449 } 1450 dest->val = tmp; 1451 for(i = 0; i < source->len; i++) { 1452 /* skip duplicates */ 1453 if(krb5_address_search(context, &source->val[i], dest)) 1454 continue; 1455 ret = krb5_copy_address(context, 1456 &source->val[i], 1457 &dest->val[dest->len]); 1458 if(ret) 1459 return ret; 1460 dest->len++; 1461 } 1462 } 1463 return 0; 1464 } 1465 1466 /** 1467 * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port) 1468 * 1469 * @param context a Keberos context 1470 * @param res built address from addr/port 1471 * @param addr address to use 1472 * @param port port to use 1473 * 1474 * @return Return an error code or 0. 1475 * 1476 * @ingroup krb5_address 1477 */ 1478 1479 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1480 krb5_make_addrport (krb5_context context, 1481 krb5_address **res, const krb5_address *addr, int16_t port) 1482 { 1483 krb5_error_code ret; 1484 size_t len = addr->address.length + 2 + 4 * 4; 1485 u_char *p; 1486 1487 *res = malloc (sizeof(**res)); 1488 if (*res == NULL) { 1489 krb5_set_error_message (context, ENOMEM, 1490 N_("malloc: out of memory", "")); 1491 return ENOMEM; 1492 } 1493 (*res)->addr_type = KRB5_ADDRESS_ADDRPORT; 1494 ret = krb5_data_alloc (&(*res)->address, len); 1495 if (ret) { 1496 krb5_set_error_message (context, ret, 1497 N_("malloc: out of memory", "")); 1498 free (*res); 1499 *res = NULL; 1500 return ret; 1501 } 1502 p = (*res)->address.data; 1503 *p++ = 0; 1504 *p++ = 0; 1505 *p++ = (addr->addr_type ) & 0xFF; 1506 *p++ = (addr->addr_type >> 8) & 0xFF; 1507 1508 *p++ = (addr->address.length ) & 0xFF; 1509 *p++ = (addr->address.length >> 8) & 0xFF; 1510 *p++ = (addr->address.length >> 16) & 0xFF; 1511 *p++ = (addr->address.length >> 24) & 0xFF; 1512 1513 memcpy (p, addr->address.data, addr->address.length); 1514 p += addr->address.length; 1515 1516 *p++ = 0; 1517 *p++ = 0; 1518 *p++ = (KRB5_ADDRESS_IPPORT ) & 0xFF; 1519 *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF; 1520 1521 *p++ = (2 ) & 0xFF; 1522 *p++ = (2 >> 8) & 0xFF; 1523 *p++ = (2 >> 16) & 0xFF; 1524 *p++ = (2 >> 24) & 0xFF; 1525 1526 memcpy (p, &port, 2); 1527 1528 return 0; 1529 } 1530 1531 /** 1532 * Calculate the boundary addresses of `inaddr'/`prefixlen' and store 1533 * them in `low' and `high'. 1534 * 1535 * @param context a Keberos context 1536 * @param inaddr address in prefixlen that the bondery searched 1537 * @param prefixlen width of boundery 1538 * @param low lowest address 1539 * @param high highest address 1540 * 1541 * @return Return an error code or 0. 1542 * 1543 * @ingroup krb5_address 1544 */ 1545 1546 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1547 krb5_address_prefixlen_boundary(krb5_context context, 1548 const krb5_address *inaddr, 1549 unsigned long prefixlen, 1550 krb5_address *low, 1551 krb5_address *high) 1552 { 1553 struct addr_operations *a = find_atype (inaddr->addr_type); 1554 if(a != NULL && a->mask_boundary != NULL) 1555 return (*a->mask_boundary)(context, inaddr, prefixlen, low, high); 1556 krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 1557 N_("Address family %d doesn't support " 1558 "address mask operation", ""), 1559 inaddr->addr_type); 1560 return KRB5_PROG_ATYPE_NOSUPP; 1561 } 1562