1 /* 2 * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 36 struct 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 62 static krb5_error_code 63 ipv4_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 73 static krb5_error_code 74 ipv4_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 82 static void 83 ipv4_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 98 static void 99 ipv4_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 114 static krb5_error_code 115 ipv4_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 129 static krb5_boolean 130 ipv4_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 140 static krb5_boolean 141 ipv4_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 151 static void 152 ipv4_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 164 static int 165 ipv4_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 174 static int 175 ipv4_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 199 static int 200 ipv4_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 240 static krb5_error_code 241 ipv6_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 266 static krb5_error_code 267 ipv6_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 275 static void 276 ipv6_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 291 static void 292 ipv6_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 307 static krb5_error_code 308 ipv6_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 319 static krb5_boolean 320 ipv6_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 329 static krb5_boolean 330 ipv6_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 338 static void 339 ipv6_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 *sa_size = sizeof(tmp); 348 } 349 350 static int 351 ipv6_print_addr (const krb5_address *addr, char *str, size_t len) 352 { 353 char buf[128], buf2[3]; 354 if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL) 355 { 356 /* XXX this is pretty ugly, but better than abort() */ 357 size_t i; 358 unsigned char *p = addr->address.data; 359 buf[0] = '\0'; 360 for(i = 0; i < addr->address.length; i++) { 361 snprintf(buf2, sizeof(buf2), "%02x", p[i]); 362 if(i > 0 && (i & 1) == 0) 363 strlcat(buf, ":", sizeof(buf)); 364 strlcat(buf, buf2, sizeof(buf)); 365 } 366 } 367 return snprintf(str, len, "IPv6:%s", buf); 368 } 369 370 static int 371 ipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr) 372 { 373 int ret; 374 struct in6_addr in6; 375 const char *p; 376 377 p = strchr(address, ':'); 378 if(p) { 379 p++; 380 if(strncasecmp(address, "ip6:", p - address) == 0 || 381 strncasecmp(address, "ipv6:", p - address) == 0 || 382 strncasecmp(address, "inet6:", p - address) == 0) 383 address = p; 384 } 385 386 ret = inet_pton(AF_INET6, address, &in6.s6_addr); 387 if(ret == 1) { 388 addr->addr_type = KRB5_ADDRESS_INET6; 389 ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr)); 390 if (ret) 391 return -1; 392 memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr)); 393 return 0; 394 } 395 return -1; 396 } 397 398 static int 399 ipv6_mask_boundary(krb5_context context, const krb5_address *inaddr, 400 unsigned long len, krb5_address *low, krb5_address *high) 401 { 402 struct in6_addr addr, laddr, haddr; 403 uint32_t m; 404 int i, sub_len; 405 406 if (len > 128) { 407 krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 408 N_("IPv6 prefix too large (%ld)", "length"), len); 409 return KRB5_PROG_ATYPE_NOSUPP; 410 } 411 412 if (inaddr->address.length != sizeof(addr)) { 413 krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 414 N_("IPv6 addr bad length", "")); 415 return KRB5_PROG_ATYPE_NOSUPP; 416 } 417 418 memcpy(&addr, inaddr->address.data, inaddr->address.length); 419 420 for (i = 0; i < 16; i++) { 421 sub_len = min(8, len); 422 423 m = 0xff << (8 - sub_len); 424 425 laddr.s6_addr[i] = addr.s6_addr[i] & m; 426 haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m; 427 428 if (len > 8) 429 len -= 8; 430 else 431 len = 0; 432 } 433 434 low->addr_type = KRB5_ADDRESS_INET6; 435 if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0) 436 return -1; 437 memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr)); 438 439 high->addr_type = KRB5_ADDRESS_INET6; 440 if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) { 441 krb5_free_address(context, low); 442 return -1; 443 } 444 memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr)); 445 446 return 0; 447 } 448 449 #endif /* IPv6 */ 450 451 #ifndef HEIMDAL_SMALLER 452 453 /* 454 * table 455 */ 456 457 #define KRB5_ADDRESS_ARANGE (-100) 458 459 struct arange { 460 krb5_address low; 461 krb5_address high; 462 }; 463 464 static int 465 arange_parse_addr (krb5_context context, 466 const char *address, krb5_address *addr) 467 { 468 char buf[1024], *p; 469 krb5_address low0, high0; 470 struct arange *a; 471 krb5_error_code ret; 472 473 if(strncasecmp(address, "RANGE:", 6) != 0) 474 return -1; 475 476 address += 6; 477 478 p = strrchr(address, '/'); 479 if (p) { 480 krb5_addresses addrmask; 481 char *q; 482 long num; 483 484 if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf)) 485 return -1; 486 buf[p - address] = '\0'; 487 ret = krb5_parse_address(context, buf, &addrmask); 488 if (ret) 489 return ret; 490 if(addrmask.len != 1) { 491 krb5_free_addresses(context, &addrmask); 492 return -1; 493 } 494 495 address += p - address + 1; 496 497 num = strtol(address, &q, 10); 498 if (q == address || *q != '\0' || num < 0) { 499 krb5_free_addresses(context, &addrmask); 500 return -1; 501 } 502 503 ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num, 504 &low0, &high0); 505 krb5_free_addresses(context, &addrmask); 506 if (ret) 507 return ret; 508 509 } else { 510 krb5_addresses low, high; 511 512 strsep_copy(&address, "-", buf, sizeof(buf)); 513 ret = krb5_parse_address(context, buf, &low); 514 if(ret) 515 return ret; 516 if(low.len != 1) { 517 krb5_free_addresses(context, &low); 518 return -1; 519 } 520 521 strsep_copy(&address, "-", buf, sizeof(buf)); 522 ret = krb5_parse_address(context, buf, &high); 523 if(ret) { 524 krb5_free_addresses(context, &low); 525 return ret; 526 } 527 528 if(high.len != 1 && high.val[0].addr_type != low.val[0].addr_type) { 529 krb5_free_addresses(context, &low); 530 krb5_free_addresses(context, &high); 531 return -1; 532 } 533 534 ret = krb5_copy_address(context, &high.val[0], &high0); 535 if (ret == 0) { 536 ret = krb5_copy_address(context, &low.val[0], &low0); 537 if (ret) 538 krb5_free_address(context, &high0); 539 } 540 krb5_free_addresses(context, &low); 541 krb5_free_addresses(context, &high); 542 if (ret) 543 return ret; 544 } 545 546 krb5_data_alloc(&addr->address, sizeof(*a)); 547 addr->addr_type = KRB5_ADDRESS_ARANGE; 548 a = addr->address.data; 549 550 if(krb5_address_order(context, &low0, &high0) < 0) { 551 a->low = low0; 552 a->high = high0; 553 } else { 554 a->low = high0; 555 a->high = low0; 556 } 557 return 0; 558 } 559 560 static int 561 arange_free (krb5_context context, krb5_address *addr) 562 { 563 struct arange *a; 564 a = addr->address.data; 565 krb5_free_address(context, &a->low); 566 krb5_free_address(context, &a->high); 567 krb5_data_free(&addr->address); 568 return 0; 569 } 570 571 572 static int 573 arange_copy (krb5_context context, const krb5_address *inaddr, 574 krb5_address *outaddr) 575 { 576 krb5_error_code ret; 577 struct arange *i, *o; 578 579 outaddr->addr_type = KRB5_ADDRESS_ARANGE; 580 ret = krb5_data_alloc(&outaddr->address, sizeof(*o)); 581 if(ret) 582 return ret; 583 i = inaddr->address.data; 584 o = outaddr->address.data; 585 ret = krb5_copy_address(context, &i->low, &o->low); 586 if(ret) { 587 krb5_data_free(&outaddr->address); 588 return ret; 589 } 590 ret = krb5_copy_address(context, &i->high, &o->high); 591 if(ret) { 592 krb5_free_address(context, &o->low); 593 krb5_data_free(&outaddr->address); 594 return ret; 595 } 596 return 0; 597 } 598 599 static int 600 arange_print_addr (const krb5_address *addr, char *str, size_t len) 601 { 602 struct arange *a; 603 krb5_error_code ret; 604 size_t l, size, ret_len; 605 606 a = addr->address.data; 607 608 l = strlcpy(str, "RANGE:", len); 609 ret_len = l; 610 if (l > len) 611 l = len; 612 size = l; 613 614 ret = krb5_print_address (&a->low, str + size, len - size, &l); 615 if (ret) 616 return ret; 617 ret_len += l; 618 if (len - size > l) 619 size += l; 620 else 621 size = len; 622 623 l = strlcat(str + size, "-", len - size); 624 ret_len += l; 625 if (len - size > l) 626 size += l; 627 else 628 size = len; 629 630 ret = krb5_print_address (&a->high, str + size, len - size, &l); 631 if (ret) 632 return ret; 633 ret_len += l; 634 635 return ret_len; 636 } 637 638 static int 639 arange_order_addr(krb5_context context, 640 const krb5_address *addr1, 641 const krb5_address *addr2) 642 { 643 int tmp1, tmp2, sign; 644 struct arange *a; 645 const krb5_address *a2; 646 647 if(addr1->addr_type == KRB5_ADDRESS_ARANGE) { 648 a = addr1->address.data; 649 a2 = addr2; 650 sign = 1; 651 } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) { 652 a = addr2->address.data; 653 a2 = addr1; 654 sign = -1; 655 } else { 656 abort(); 657 UNREACHABLE(return 0); 658 } 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 { 733 AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), 734 ipv4_sockaddr2addr, 735 ipv4_sockaddr2port, 736 ipv4_addr2sockaddr, 737 ipv4_h_addr2sockaddr, 738 ipv4_h_addr2addr, 739 ipv4_uninteresting, 740 ipv4_is_loopback, 741 ipv4_anyaddr, 742 ipv4_print_addr, 743 ipv4_parse_addr, 744 NULL, 745 NULL, 746 NULL, 747 ipv4_mask_boundary 748 }, 749 #ifdef HAVE_IPV6 750 { 751 AF_INET6, KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6), 752 ipv6_sockaddr2addr, 753 ipv6_sockaddr2port, 754 ipv6_addr2sockaddr, 755 ipv6_h_addr2sockaddr, 756 ipv6_h_addr2addr, 757 ipv6_uninteresting, 758 ipv6_is_loopback, 759 ipv6_anyaddr, 760 ipv6_print_addr, 761 ipv6_parse_addr, 762 NULL, 763 NULL, 764 NULL, 765 ipv6_mask_boundary 766 } , 767 #endif 768 #ifndef HEIMDAL_SMALLER 769 /* fake address type */ 770 { 771 KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange), 772 NULL, 773 NULL, 774 NULL, 775 NULL, 776 NULL, 777 NULL, 778 NULL, 779 NULL, 780 arange_print_addr, 781 arange_parse_addr, 782 arange_order_addr, 783 arange_free, 784 arange_copy, 785 NULL 786 }, 787 #endif 788 { 789 KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0, 790 NULL, 791 NULL, 792 NULL, 793 NULL, 794 NULL, 795 NULL, 796 NULL, 797 NULL, 798 addrport_print_addr, 799 NULL, 800 NULL, 801 NULL, 802 NULL 803 } 804 }; 805 806 static int num_addrs = sizeof(at) / sizeof(at[0]); 807 808 static size_t max_sockaddr_size = 0; 809 810 /* 811 * generic functions 812 */ 813 814 static struct addr_operations * 815 find_af(int af) 816 { 817 struct addr_operations *a; 818 819 for (a = at; a < at + num_addrs; ++a) 820 if (af == a->af) 821 return a; 822 return NULL; 823 } 824 825 static struct addr_operations * 826 find_atype(krb5_address_type atype) 827 { 828 struct addr_operations *a; 829 830 for (a = at; a < at + num_addrs; ++a) 831 if (atype == a->atype) 832 return a; 833 return NULL; 834 } 835 836 /** 837 * krb5_sockaddr2address stores a address a "struct sockaddr" sa in 838 * the krb5_address addr. 839 * 840 * @param context a Keberos context 841 * @param sa a struct sockaddr to extract the address from 842 * @param addr an Kerberos 5 address to store the address in. 843 * 844 * @return Return an error code or 0. 845 * 846 * @ingroup krb5_address 847 */ 848 849 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 850 krb5_sockaddr2address (krb5_context context, 851 const struct sockaddr *sa, krb5_address *addr) 852 { 853 struct addr_operations *a = find_af(sa->sa_family); 854 if (a == NULL) { 855 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 856 N_("Address family %d not supported", ""), 857 sa->sa_family); 858 return KRB5_PROG_ATYPE_NOSUPP; 859 } 860 return (*a->sockaddr2addr)(sa, addr); 861 } 862 863 /** 864 * krb5_sockaddr2port extracts a port (if possible) from a "struct 865 * sockaddr. 866 * 867 * @param context a Keberos context 868 * @param sa a struct sockaddr to extract the port from 869 * @param port a pointer to an int16_t store the port in. 870 * 871 * @return Return an error code or 0. Will return 872 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 873 * 874 * @ingroup krb5_address 875 */ 876 877 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 878 krb5_sockaddr2port (krb5_context context, 879 const struct sockaddr *sa, int16_t *port) 880 { 881 struct addr_operations *a = find_af(sa->sa_family); 882 if (a == NULL) { 883 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 884 N_("Address family %d not supported", ""), 885 sa->sa_family); 886 return KRB5_PROG_ATYPE_NOSUPP; 887 } 888 return (*a->sockaddr2port)(sa, port); 889 } 890 891 /** 892 * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr 893 * and port. The argument sa_size should initially contain the size of 894 * the sa and after the call, it will contain the actual length of the 895 * address. In case of the sa is too small to fit the whole address, 896 * the up to *sa_size will be stored, and then *sa_size will be set to 897 * the required length. 898 * 899 * @param context a Keberos context 900 * @param addr the address to copy the from 901 * @param sa the struct sockaddr that will be filled in 902 * @param sa_size pointer to length of sa, and after the call, it will 903 * contain the actual length of the address. 904 * @param port set port in sa. 905 * 906 * @return Return an error code or 0. Will return 907 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 908 * 909 * @ingroup krb5_address 910 */ 911 912 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 913 krb5_addr2sockaddr (krb5_context context, 914 const krb5_address *addr, 915 struct sockaddr *sa, 916 krb5_socklen_t *sa_size, 917 int port) 918 { 919 struct addr_operations *a = find_atype(addr->addr_type); 920 921 if (a == NULL) { 922 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 923 N_("Address type %d not supported", 924 "krb5_address type"), 925 addr->addr_type); 926 return KRB5_PROG_ATYPE_NOSUPP; 927 } 928 if (a->addr2sockaddr == NULL) { 929 krb5_set_error_message (context, 930 KRB5_PROG_ATYPE_NOSUPP, 931 N_("Can't convert address type %d to sockaddr", ""), 932 addr->addr_type); 933 return KRB5_PROG_ATYPE_NOSUPP; 934 } 935 (*a->addr2sockaddr)(addr, sa, sa_size, port); 936 return 0; 937 } 938 939 /** 940 * krb5_max_sockaddr_size returns the max size of the .Li struct 941 * sockaddr that the Kerberos library will return. 942 * 943 * @return Return an size_t of the maximum struct sockaddr. 944 * 945 * @ingroup krb5_address 946 */ 947 948 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 949 krb5_max_sockaddr_size (void) 950 { 951 if (max_sockaddr_size == 0) { 952 struct addr_operations *a; 953 954 for(a = at; a < at + num_addrs; ++a) 955 max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size); 956 } 957 return max_sockaddr_size; 958 } 959 960 /** 961 * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the 962 * kerberos library thinks are uninteresting. One example are link 963 * local addresses. 964 * 965 * @param sa pointer to struct sockaddr that might be interesting. 966 * 967 * @return Return a non zero for uninteresting addresses. 968 * 969 * @ingroup krb5_address 970 */ 971 972 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 973 krb5_sockaddr_uninteresting(const struct sockaddr *sa) 974 { 975 struct addr_operations *a = find_af(sa->sa_family); 976 if (a == NULL || a->uninteresting == NULL) 977 return TRUE; 978 return (*a->uninteresting)(sa); 979 } 980 981 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 982 krb5_sockaddr_is_loopback(const struct sockaddr *sa) 983 { 984 struct addr_operations *a = find_af(sa->sa_family); 985 if (a == NULL || a->is_loopback == NULL) 986 return TRUE; 987 return (*a->is_loopback)(sa); 988 } 989 990 /** 991 * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and 992 * the "struct hostent" (see gethostbyname(3) ) h_addr_list 993 * component. The argument sa_size should initially contain the size 994 * of the sa, and after the call, it will contain the actual length of 995 * the address. 996 * 997 * @param context a Keberos context 998 * @param af addresses 999 * @param addr address 1000 * @param sa returned struct sockaddr 1001 * @param sa_size size of sa 1002 * @param port port to set in sa. 1003 * 1004 * @return Return an error code or 0. 1005 * 1006 * @ingroup krb5_address 1007 */ 1008 1009 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1010 krb5_h_addr2sockaddr (krb5_context context, 1011 int af, 1012 const char *addr, struct sockaddr *sa, 1013 krb5_socklen_t *sa_size, 1014 int port) 1015 { 1016 struct addr_operations *a = find_af(af); 1017 if (a == NULL) { 1018 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1019 "Address family %d not supported", af); 1020 return KRB5_PROG_ATYPE_NOSUPP; 1021 } 1022 (*a->h_addr2sockaddr)(addr, sa, sa_size, port); 1023 return 0; 1024 } 1025 1026 /** 1027 * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception 1028 * that it operates on a krb5_address instead of a struct sockaddr. 1029 * 1030 * @param context a Keberos context 1031 * @param af address family 1032 * @param haddr host address from struct hostent. 1033 * @param addr returned krb5_address. 1034 * 1035 * @return Return an error code or 0. 1036 * 1037 * @ingroup krb5_address 1038 */ 1039 1040 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1041 krb5_h_addr2addr (krb5_context context, 1042 int af, 1043 const char *haddr, krb5_address *addr) 1044 { 1045 struct addr_operations *a = find_af(af); 1046 if (a == NULL) { 1047 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1048 N_("Address family %d not supported", ""), af); 1049 return KRB5_PROG_ATYPE_NOSUPP; 1050 } 1051 return (*a->h_addr2addr)(haddr, addr); 1052 } 1053 1054 /** 1055 * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to 1056 * bind(2) to. The argument sa_size should initially contain the size 1057 * of the sa, and after the call, it will contain the actual length 1058 * of the address. 1059 * 1060 * @param context a Keberos context 1061 * @param af address family 1062 * @param sa sockaddr 1063 * @param sa_size lenght of sa. 1064 * @param port for to fill into sa. 1065 * 1066 * @return Return an error code or 0. 1067 * 1068 * @ingroup krb5_address 1069 */ 1070 1071 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1072 krb5_anyaddr (krb5_context context, 1073 int af, 1074 struct sockaddr *sa, 1075 krb5_socklen_t *sa_size, 1076 int port) 1077 { 1078 struct addr_operations *a = find_af (af); 1079 1080 if (a == NULL) { 1081 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1082 N_("Address family %d not supported", ""), af); 1083 return KRB5_PROG_ATYPE_NOSUPP; 1084 } 1085 1086 (*a->anyaddr)(sa, sa_size, port); 1087 return 0; 1088 } 1089 1090 /** 1091 * krb5_print_address prints the address in addr to the string string 1092 * that have the length len. If ret_len is not NULL, it will be filled 1093 * with the length of the string if size were unlimited (not including 1094 * the final NUL) . 1095 * 1096 * @param addr address to be printed 1097 * @param str pointer string to print the address into 1098 * @param len length that will fit into area pointed to by "str". 1099 * @param ret_len return length the str. 1100 * 1101 * @return Return an error code or 0. 1102 * 1103 * @ingroup krb5_address 1104 */ 1105 1106 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1107 krb5_print_address (const krb5_address *addr, 1108 char *str, size_t len, size_t *ret_len) 1109 { 1110 struct addr_operations *a = find_atype(addr->addr_type); 1111 int ret; 1112 1113 if (a == NULL || a->print_addr == NULL) { 1114 char *s; 1115 int l; 1116 size_t i; 1117 1118 s = str; 1119 l = snprintf(s, len, "TYPE_%d:", addr->addr_type); 1120 if (l < 0 || (size_t)l >= len) 1121 return EINVAL; 1122 s += l; 1123 len -= l; 1124 for(i = 0; i < addr->address.length; i++) { 1125 l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); 1126 if (l < 0 || (size_t)l >= len) 1127 return EINVAL; 1128 len -= l; 1129 s += l; 1130 } 1131 if(ret_len != NULL) 1132 *ret_len = s - str; 1133 return 0; 1134 } 1135 ret = (*a->print_addr)(addr, str, len); 1136 if (ret < 0) 1137 return EINVAL; 1138 if(ret_len != NULL) 1139 *ret_len = ret; 1140 return 0; 1141 } 1142 1143 /** 1144 * krb5_parse_address returns the resolved hostname in string to the 1145 * krb5_addresses addresses . 1146 * 1147 * @param context a Keberos context 1148 * @param string 1149 * @param addresses 1150 * 1151 * @return Return an error code or 0. 1152 * 1153 * @ingroup krb5_address 1154 */ 1155 1156 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1157 krb5_parse_address(krb5_context context, 1158 const char *string, 1159 krb5_addresses *addresses) 1160 { 1161 int i, n; 1162 struct addrinfo *ai, *a; 1163 int error; 1164 int save_errno; 1165 1166 addresses->len = 0; 1167 addresses->val = NULL; 1168 1169 for(i = 0; i < num_addrs; i++) { 1170 if(at[i].parse_addr) { 1171 krb5_address addr; 1172 if((*at[i].parse_addr)(context, string, &addr) == 0) { 1173 ALLOC_SEQ(addresses, 1); 1174 if (addresses->val == NULL) { 1175 krb5_set_error_message(context, ENOMEM, 1176 N_("malloc: out of memory", "")); 1177 return ENOMEM; 1178 } 1179 addresses->val[0] = addr; 1180 return 0; 1181 } 1182 } 1183 } 1184 1185 error = getaddrinfo (string, NULL, NULL, &ai); 1186 if (error) { 1187 krb5_error_code ret2; 1188 save_errno = errno; 1189 ret2 = krb5_eai_to_heim_errno(error, save_errno); 1190 krb5_set_error_message (context, ret2, "%s: %s", 1191 string, gai_strerror(error)); 1192 return ret2; 1193 } 1194 1195 n = 0; 1196 for (a = ai; a != NULL; a = a->ai_next) 1197 ++n; 1198 1199 ALLOC_SEQ(addresses, n); 1200 if (addresses->val == NULL) { 1201 krb5_set_error_message(context, ENOMEM, 1202 N_("malloc: out of memory", "")); 1203 freeaddrinfo(ai); 1204 return ENOMEM; 1205 } 1206 1207 addresses->len = 0; 1208 for (a = ai, i = 0; a != NULL; a = a->ai_next) { 1209 if (krb5_sockaddr2address (context, ai->ai_addr, &addresses->val[i])) 1210 continue; 1211 if(krb5_address_search(context, &addresses->val[i], addresses)) { 1212 krb5_free_address(context, &addresses->val[i]); 1213 continue; 1214 } 1215 i++; 1216 addresses->len = i; 1217 } 1218 freeaddrinfo (ai); 1219 return 0; 1220 } 1221 1222 /** 1223 * krb5_address_order compares the addresses addr1 and addr2 so that 1224 * it can be used for sorting addresses. If the addresses are the same 1225 * address krb5_address_order will return 0. Behavies like memcmp(2). 1226 * 1227 * @param context a Keberos context 1228 * @param addr1 krb5_address to compare 1229 * @param addr2 krb5_address to compare 1230 * 1231 * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and 1232 * addr2 is the same address, > 0 if addr2 is "less" then addr1. 1233 * 1234 * @ingroup krb5_address 1235 */ 1236 1237 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1238 krb5_address_order(krb5_context context, 1239 const krb5_address *addr1, 1240 const krb5_address *addr2) 1241 { 1242 /* this sucks; what if both addresses have order functions, which 1243 should we call? this works for now, though */ 1244 struct addr_operations *a; 1245 a = find_atype(addr1->addr_type); 1246 if(a == NULL) { 1247 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1248 N_("Address family %d not supported", ""), 1249 addr1->addr_type); 1250 return KRB5_PROG_ATYPE_NOSUPP; 1251 } 1252 if(a->order_addr != NULL) 1253 return (*a->order_addr)(context, addr1, addr2); 1254 a = find_atype(addr2->addr_type); 1255 if(a == NULL) { 1256 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1257 N_("Address family %d not supported", ""), 1258 addr2->addr_type); 1259 return KRB5_PROG_ATYPE_NOSUPP; 1260 } 1261 if(a->order_addr != NULL) 1262 return (*a->order_addr)(context, addr1, addr2); 1263 1264 if(addr1->addr_type != addr2->addr_type) 1265 return addr1->addr_type - addr2->addr_type; 1266 if(addr1->address.length != addr2->address.length) 1267 return addr1->address.length - addr2->address.length; 1268 return memcmp (addr1->address.data, 1269 addr2->address.data, 1270 addr1->address.length); 1271 } 1272 1273 /** 1274 * krb5_address_compare compares the addresses addr1 and addr2. 1275 * Returns TRUE if the two addresses are the same. 1276 * 1277 * @param context a Keberos context 1278 * @param addr1 address to compare 1279 * @param addr2 address to compare 1280 * 1281 * @return Return an TRUE is the address are the same FALSE if not 1282 * 1283 * @ingroup krb5_address 1284 */ 1285 1286 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1287 krb5_address_compare(krb5_context context, 1288 const krb5_address *addr1, 1289 const krb5_address *addr2) 1290 { 1291 return krb5_address_order (context, addr1, addr2) == 0; 1292 } 1293 1294 /** 1295 * krb5_address_search checks if the address addr is a member of the 1296 * address set list addrlist . 1297 * 1298 * @param context a Keberos context. 1299 * @param addr address to search for. 1300 * @param addrlist list of addresses to look in for addr. 1301 * 1302 * @return Return an error code or 0. 1303 * 1304 * @ingroup krb5_address 1305 */ 1306 1307 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1308 krb5_address_search(krb5_context context, 1309 const krb5_address *addr, 1310 const krb5_addresses *addrlist) 1311 { 1312 size_t i; 1313 1314 for (i = 0; i < addrlist->len; ++i) 1315 if (krb5_address_compare (context, addr, &addrlist->val[i])) 1316 return TRUE; 1317 return FALSE; 1318 } 1319 1320 /** 1321 * krb5_free_address frees the data stored in the address that is 1322 * alloced with any of the krb5_address functions. 1323 * 1324 * @param context a Keberos context 1325 * @param address addresss to be freed. 1326 * 1327 * @return Return an error code or 0. 1328 * 1329 * @ingroup krb5_address 1330 */ 1331 1332 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1333 krb5_free_address(krb5_context context, 1334 krb5_address *address) 1335 { 1336 struct addr_operations *a = find_atype (address->addr_type); 1337 if(a != NULL && a->free_addr != NULL) 1338 return (*a->free_addr)(context, address); 1339 krb5_data_free (&address->address); 1340 memset(address, 0, sizeof(*address)); 1341 return 0; 1342 } 1343 1344 /** 1345 * krb5_free_addresses frees the data stored in the address that is 1346 * alloced with any of the krb5_address functions. 1347 * 1348 * @param context a Keberos context 1349 * @param addresses addressses to be freed. 1350 * 1351 * @return Return an error code or 0. 1352 * 1353 * @ingroup krb5_address 1354 */ 1355 1356 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1357 krb5_free_addresses(krb5_context context, 1358 krb5_addresses *addresses) 1359 { 1360 size_t i; 1361 for(i = 0; i < addresses->len; i++) 1362 krb5_free_address(context, &addresses->val[i]); 1363 free(addresses->val); 1364 addresses->len = 0; 1365 addresses->val = NULL; 1366 return 0; 1367 } 1368 1369 /** 1370 * krb5_copy_address copies the content of address 1371 * inaddr to outaddr. 1372 * 1373 * @param context a Keberos context 1374 * @param inaddr pointer to source address 1375 * @param outaddr pointer to destination address 1376 * 1377 * @return Return an error code or 0. 1378 * 1379 * @ingroup krb5_address 1380 */ 1381 1382 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1383 krb5_copy_address(krb5_context context, 1384 const krb5_address *inaddr, 1385 krb5_address *outaddr) 1386 { 1387 struct addr_operations *a = find_af (inaddr->addr_type); 1388 if(a != NULL && a->copy_addr != NULL) 1389 return (*a->copy_addr)(context, inaddr, outaddr); 1390 return copy_HostAddress(inaddr, outaddr); 1391 } 1392 1393 /** 1394 * krb5_copy_addresses copies the content of addresses 1395 * inaddr to outaddr. 1396 * 1397 * @param context a Keberos context 1398 * @param inaddr pointer to source addresses 1399 * @param outaddr pointer to destination addresses 1400 * 1401 * @return Return an error code or 0. 1402 * 1403 * @ingroup krb5_address 1404 */ 1405 1406 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1407 krb5_copy_addresses(krb5_context context, 1408 const krb5_addresses *inaddr, 1409 krb5_addresses *outaddr) 1410 { 1411 size_t i; 1412 ALLOC_SEQ(outaddr, inaddr->len); 1413 if(inaddr->len > 0 && outaddr->val == NULL) 1414 return ENOMEM; 1415 for(i = 0; i < inaddr->len; i++) 1416 krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]); 1417 return 0; 1418 } 1419 1420 /** 1421 * krb5_append_addresses adds the set of addresses in source to 1422 * dest. While copying the addresses, duplicates are also sorted out. 1423 * 1424 * @param context a Keberos context 1425 * @param dest destination of copy operation 1426 * @param source adresses that are going to be added to dest 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_append_addresses(krb5_context context, 1435 krb5_addresses *dest, 1436 const krb5_addresses *source) 1437 { 1438 krb5_address *tmp; 1439 krb5_error_code ret; 1440 size_t i; 1441 if(source->len > 0) { 1442 tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp)); 1443 if(tmp == NULL) { 1444 krb5_set_error_message (context, ENOMEM, 1445 N_("malloc: out of memory", "")); 1446 return ENOMEM; 1447 } 1448 dest->val = tmp; 1449 for(i = 0; i < source->len; i++) { 1450 /* skip duplicates */ 1451 if(krb5_address_search(context, &source->val[i], dest)) 1452 continue; 1453 ret = krb5_copy_address(context, 1454 &source->val[i], 1455 &dest->val[dest->len]); 1456 if(ret) 1457 return ret; 1458 dest->len++; 1459 } 1460 } 1461 return 0; 1462 } 1463 1464 /** 1465 * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port) 1466 * 1467 * @param context a Keberos context 1468 * @param res built address from addr/port 1469 * @param addr address to use 1470 * @param port port to use 1471 * 1472 * @return Return an error code or 0. 1473 * 1474 * @ingroup krb5_address 1475 */ 1476 1477 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1478 krb5_make_addrport (krb5_context context, 1479 krb5_address **res, const krb5_address *addr, int16_t port) 1480 { 1481 krb5_error_code ret; 1482 size_t len = addr->address.length + 2 + 4 * 4; 1483 u_char *p; 1484 1485 *res = malloc (sizeof(**res)); 1486 if (*res == NULL) { 1487 krb5_set_error_message (context, ENOMEM, 1488 N_("malloc: out of memory", "")); 1489 return ENOMEM; 1490 } 1491 (*res)->addr_type = KRB5_ADDRESS_ADDRPORT; 1492 ret = krb5_data_alloc (&(*res)->address, len); 1493 if (ret) { 1494 krb5_set_error_message (context, ret, 1495 N_("malloc: out of memory", "")); 1496 free (*res); 1497 *res = NULL; 1498 return ret; 1499 } 1500 p = (*res)->address.data; 1501 *p++ = 0; 1502 *p++ = 0; 1503 *p++ = (addr->addr_type ) & 0xFF; 1504 *p++ = (addr->addr_type >> 8) & 0xFF; 1505 1506 *p++ = (addr->address.length ) & 0xFF; 1507 *p++ = (addr->address.length >> 8) & 0xFF; 1508 *p++ = (addr->address.length >> 16) & 0xFF; 1509 *p++ = (addr->address.length >> 24) & 0xFF; 1510 1511 memcpy (p, addr->address.data, addr->address.length); 1512 p += addr->address.length; 1513 1514 *p++ = 0; 1515 *p++ = 0; 1516 *p++ = (KRB5_ADDRESS_IPPORT ) & 0xFF; 1517 *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF; 1518 1519 *p++ = (2 ) & 0xFF; 1520 *p++ = (2 >> 8) & 0xFF; 1521 *p++ = (2 >> 16) & 0xFF; 1522 *p++ = (2 >> 24) & 0xFF; 1523 1524 memcpy (p, &port, 2); 1525 1526 return 0; 1527 } 1528 1529 /** 1530 * Calculate the boundary addresses of `inaddr'/`prefixlen' and store 1531 * them in `low' and `high'. 1532 * 1533 * @param context a Keberos context 1534 * @param inaddr address in prefixlen that the bondery searched 1535 * @param prefixlen width of boundery 1536 * @param low lowest address 1537 * @param high highest address 1538 * 1539 * @return Return an error code or 0. 1540 * 1541 * @ingroup krb5_address 1542 */ 1543 1544 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1545 krb5_address_prefixlen_boundary(krb5_context context, 1546 const krb5_address *inaddr, 1547 unsigned long prefixlen, 1548 krb5_address *low, 1549 krb5_address *high) 1550 { 1551 struct addr_operations *a = find_atype (inaddr->addr_type); 1552 if(a != NULL && a->mask_boundary != NULL) 1553 return (*a->mask_boundary)(context, inaddr, prefixlen, low, high); 1554 krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 1555 N_("Address family %d doesn't support " 1556 "address mask operation", ""), 1557 inaddr->addr_type); 1558 return KRB5_PROG_ATYPE_NOSUPP; 1559 } 1560