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 36struct addr_operations { 37 int af; 38 krb5_address_type atype; 39 size_t max_sockaddr_size; 40 krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *); 41 krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *); 42 void (*addr2sockaddr)(const krb5_address *, struct sockaddr *, 43 krb5_socklen_t *sa_size, int port); 44 void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int); 45 krb5_error_code (*h_addr2addr)(const char *, krb5_address *); 46 krb5_boolean (*uninteresting)(const struct sockaddr *); 47 krb5_boolean (*is_loopback)(const struct sockaddr *); 48 void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int); 49 int (*print_addr)(const krb5_address *, char *, size_t); 50 int (*parse_addr)(krb5_context, const char*, krb5_address *); 51 int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*); 52 int (*free_addr)(krb5_context, krb5_address*); 53 int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*); 54 int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long, 55 krb5_address*, krb5_address*); 56}; 57 58/* 59 * AF_INET - aka IPv4 implementation 60 */ 61 62static krb5_error_code 63ipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 64{ 65 const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 66 unsigned char buf[4]; 67 68 a->addr_type = KRB5_ADDRESS_INET; 69 memcpy (buf, &sin4->sin_addr, 4); 70 return krb5_data_copy(&a->address, buf, 4); 71} 72 73static krb5_error_code 74ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port) 75{ 76 const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 77 78 *port = sin4->sin_port; 79 return 0; 80} 81 82static void 83ipv4_addr2sockaddr (const krb5_address *a, 84 struct sockaddr *sa, 85 krb5_socklen_t *sa_size, 86 int port) 87{ 88 struct sockaddr_in tmp; 89 90 memset (&tmp, 0, sizeof(tmp)); 91 tmp.sin_family = AF_INET; 92 memcpy (&tmp.sin_addr, a->address.data, 4); 93 tmp.sin_port = port; 94 memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 95 *sa_size = sizeof(tmp); 96} 97 98static void 99ipv4_h_addr2sockaddr(const char *addr, 100 struct sockaddr *sa, 101 krb5_socklen_t *sa_size, 102 int port) 103{ 104 struct sockaddr_in tmp; 105 106 memset (&tmp, 0, sizeof(tmp)); 107 tmp.sin_family = AF_INET; 108 tmp.sin_port = port; 109 tmp.sin_addr = *((const struct in_addr *)addr); 110 memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 111 *sa_size = sizeof(tmp); 112} 113 114static krb5_error_code 115ipv4_h_addr2addr (const char *addr, 116 krb5_address *a) 117{ 118 unsigned char buf[4]; 119 120 a->addr_type = KRB5_ADDRESS_INET; 121 memcpy(buf, addr, 4); 122 return krb5_data_copy(&a->address, buf, 4); 123} 124 125/* 126 * Are there any addresses that should be considered `uninteresting'? 127 */ 128 129static krb5_boolean 130ipv4_uninteresting (const struct sockaddr *sa) 131{ 132 const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 133 134 if (sin4->sin_addr.s_addr == INADDR_ANY) 135 return TRUE; 136 137 return FALSE; 138} 139 140static krb5_boolean 141ipv4_is_loopback (const struct sockaddr *sa) 142{ 143 const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; 144 145 if ((ntohl(sin4->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET) 146 return TRUE; 147 148 return FALSE; 149} 150 151static void 152ipv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) 153{ 154 struct sockaddr_in tmp; 155 156 memset (&tmp, 0, sizeof(tmp)); 157 tmp.sin_family = AF_INET; 158 tmp.sin_port = port; 159 tmp.sin_addr.s_addr = INADDR_ANY; 160 memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 161 *sa_size = sizeof(tmp); 162} 163 164static int 165ipv4_print_addr (const krb5_address *addr, char *str, size_t len) 166{ 167 struct in_addr ia; 168 169 memcpy (&ia, addr->address.data, 4); 170 171 return snprintf (str, len, "IPv4:%s", inet_ntoa(ia)); 172} 173 174static int 175ipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr) 176{ 177 const char *p; 178 struct in_addr a; 179 180 p = strchr(address, ':'); 181 if(p) { 182 p++; 183 if(strncasecmp(address, "ip:", p - address) != 0 && 184 strncasecmp(address, "ip4:", p - address) != 0 && 185 strncasecmp(address, "ipv4:", p - address) != 0 && 186 strncasecmp(address, "inet:", p - address) != 0) 187 return -1; 188 } else 189 p = address; 190 if(inet_aton(p, &a) == 0) 191 return -1; 192 addr->addr_type = KRB5_ADDRESS_INET; 193 if(krb5_data_alloc(&addr->address, 4) != 0) 194 return -1; 195 _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length); 196 return 0; 197} 198 199static int 200ipv4_mask_boundary(krb5_context context, const krb5_address *inaddr, 201 unsigned long len, krb5_address *low, krb5_address *high) 202{ 203 unsigned long ia; 204 uint32_t l, h, m = 0xffffffff; 205 206 if (len > 32) { 207 krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 208 N_("IPv4 prefix too large (%ld)", "len"), len); 209 return KRB5_PROG_ATYPE_NOSUPP; 210 } 211 m = m << (32 - len); 212 213 _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length); 214 215 l = ia & m; 216 h = l | ~m; 217 218 low->addr_type = KRB5_ADDRESS_INET; 219 if(krb5_data_alloc(&low->address, 4) != 0) 220 return -1; 221 _krb5_put_int(low->address.data, l, low->address.length); 222 223 high->addr_type = KRB5_ADDRESS_INET; 224 if(krb5_data_alloc(&high->address, 4) != 0) { 225 krb5_free_address(context, low); 226 return -1; 227 } 228 _krb5_put_int(high->address.data, h, high->address.length); 229 230 return 0; 231} 232 233 234/* 235 * AF_INET6 - aka IPv6 implementation 236 */ 237 238#ifdef HAVE_IPV6 239 240static krb5_error_code 241ipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 242{ 243 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 244 245 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 246 unsigned char buf[4]; 247 248 a->addr_type = KRB5_ADDRESS_INET; 249#ifndef IN6_ADDR_V6_TO_V4 250#ifdef IN6_EXTRACT_V4ADDR 251#define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x)) 252#else 253#define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12]) 254#endif 255#endif 256 memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4); 257 return krb5_data_copy(&a->address, buf, 4); 258 } else { 259 a->addr_type = KRB5_ADDRESS_INET6; 260 return krb5_data_copy(&a->address, 261 &sin6->sin6_addr, 262 sizeof(sin6->sin6_addr)); 263 } 264} 265 266static krb5_error_code 267ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port) 268{ 269 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 270 271 *port = sin6->sin6_port; 272 return 0; 273} 274 275static void 276ipv6_addr2sockaddr (const krb5_address *a, 277 struct sockaddr *sa, 278 krb5_socklen_t *sa_size, 279 int port) 280{ 281 struct sockaddr_in6 tmp; 282 283 memset (&tmp, 0, sizeof(tmp)); 284 tmp.sin6_family = AF_INET6; 285 memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr)); 286 tmp.sin6_port = port; 287 memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 288 *sa_size = sizeof(tmp); 289} 290 291static void 292ipv6_h_addr2sockaddr(const char *addr, 293 struct sockaddr *sa, 294 krb5_socklen_t *sa_size, 295 int port) 296{ 297 struct sockaddr_in6 tmp; 298 299 memset (&tmp, 0, sizeof(tmp)); 300 tmp.sin6_family = AF_INET6; 301 tmp.sin6_port = port; 302 tmp.sin6_addr = *((const struct in6_addr *)addr); 303 memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 304 *sa_size = sizeof(tmp); 305} 306 307static krb5_error_code 308ipv6_h_addr2addr (const char *addr, 309 krb5_address *a) 310{ 311 a->addr_type = KRB5_ADDRESS_INET6; 312 return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr)); 313} 314 315/* 316 * 317 */ 318 319static krb5_boolean 320ipv6_uninteresting (const struct sockaddr *sa) 321{ 322 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 323 const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; 324 325 return IN6_IS_ADDR_LINKLOCAL(in6) 326 || IN6_IS_ADDR_V4COMPAT(in6); 327} 328 329static krb5_boolean 330ipv6_is_loopback (const struct sockaddr *sa) 331{ 332 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 333 const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; 334 335 return (IN6_IS_ADDR_LOOPBACK(in6)); 336} 337 338static void 339ipv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) 340{ 341 struct sockaddr_in6 tmp; 342 343 memset (&tmp, 0, sizeof(tmp)); 344 tmp.sin6_family = AF_INET6; 345 tmp.sin6_port = port; 346 tmp.sin6_addr = in6addr_any; 347 memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); 348 *sa_size = sizeof(tmp); 349} 350 351static int 352ipv6_print_addr (const krb5_address *addr, char *str, size_t len) 353{ 354 char buf[128], buf2[3]; 355 if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL) 356 { 357 /* XXX this is pretty ugly, but better than abort() */ 358 size_t i; 359 unsigned char *p = addr->address.data; 360 buf[0] = '\0'; 361 for(i = 0; i < addr->address.length; i++) { 362 snprintf(buf2, sizeof(buf2), "%02x", p[i]); 363 if(i > 0 && (i & 1) == 0) 364 strlcat(buf, ":", sizeof(buf)); 365 strlcat(buf, buf2, sizeof(buf)); 366 } 367 } 368 return snprintf(str, len, "IPv6:%s", buf); 369} 370 371static int 372ipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr) 373{ 374 int ret; 375 struct in6_addr in6; 376 const char *p; 377 378 p = strchr(address, ':'); 379 if(p) { 380 p++; 381 if(strncasecmp(address, "ip6:", p - address) == 0 || 382 strncasecmp(address, "ipv6:", p - address) == 0 || 383 strncasecmp(address, "inet6:", p - address) == 0) 384 address = p; 385 } 386 387 ret = inet_pton(AF_INET6, address, &in6.s6_addr); 388 if(ret == 1) { 389 addr->addr_type = KRB5_ADDRESS_INET6; 390 ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr)); 391 if (ret) 392 return -1; 393 memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr)); 394 return 0; 395 } 396 return -1; 397} 398 399static int 400ipv6_mask_boundary(krb5_context context, const krb5_address *inaddr, 401 unsigned long len, krb5_address *low, krb5_address *high) 402{ 403 struct in6_addr addr, laddr, haddr; 404 size_t sub_len; 405 uint32_t m; 406 int i; 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 461struct arange { 462 krb5_address low; 463 krb5_address high; 464}; 465 466static int 467arange_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 562static int 563arange_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 574static int 575arange_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 601static int 602arange_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 640static int 641arange_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 683static int 684addrport_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 -1; 729 ret_len += ret; 730 return (int)ret_len; 731} 732 733static 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 808static int num_addrs = sizeof(at) / sizeof(at[0]); 809 810static size_t max_sockaddr_size = 0; 811 812/* 813 * generic functions 814 */ 815 816static struct addr_operations * 817find_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 827static struct addr_operations * 828find_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 851KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 852krb5_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 879KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 880krb5_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 914KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 915krb5_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 950KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 951krb5_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 974KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 975krb5_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 983KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 984krb5_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 1011KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1012krb5_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 1042KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1043krb5_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 1073KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1074krb5_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 1108KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1109krb5_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 string to parse as an address 1151 * @param addresses return address, free with krb5_free_addresses() 1152 * 1153 * @return Return an error code or 0. 1154 * 1155 * @ingroup krb5_address 1156 */ 1157 1158KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1159krb5_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 1239KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1240krb5_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 (int)(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 1288KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1289krb5_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 1309KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1310krb5_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 1334KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1335krb5_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 1358KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1359krb5_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 1384KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1385krb5_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 1408KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1409krb5_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 1435KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1436krb5_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 1479KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1480krb5_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 1546KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1547krb5_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