1 /* $NetBSD: addr_families.c,v 1.3 2023/06/19 21:41:44 christos 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 NULL 806 } 807 }; 808 809 static int num_addrs = sizeof(at) / sizeof(at[0]); 810 811 static size_t max_sockaddr_size = 0; 812 813 /* 814 * generic functions 815 */ 816 817 static struct addr_operations * 818 find_af(int af) 819 { 820 struct addr_operations *a; 821 822 for (a = at; a < at + num_addrs; ++a) 823 if (af == a->af) 824 return a; 825 return NULL; 826 } 827 828 static struct addr_operations * 829 find_atype(krb5_address_type atype) 830 { 831 struct addr_operations *a; 832 833 for (a = at; a < at + num_addrs; ++a) 834 if (atype == a->atype) 835 return a; 836 return NULL; 837 } 838 839 /** 840 * krb5_sockaddr2address stores a address a "struct sockaddr" sa in 841 * the krb5_address addr. 842 * 843 * @param context a Keberos context 844 * @param sa a struct sockaddr to extract the address from 845 * @param addr an Kerberos 5 address to store the address in. 846 * 847 * @return Return an error code or 0. 848 * 849 * @ingroup krb5_address 850 */ 851 852 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 853 krb5_sockaddr2address (krb5_context context, 854 const struct sockaddr *sa, krb5_address *addr) 855 { 856 struct addr_operations *a = find_af(sa->sa_family); 857 if (a == NULL) { 858 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 859 N_("Address family %d not supported", ""), 860 sa->sa_family); 861 return KRB5_PROG_ATYPE_NOSUPP; 862 } 863 return (*a->sockaddr2addr)(sa, addr); 864 } 865 866 /** 867 * krb5_sockaddr2port extracts a port (if possible) from a "struct 868 * sockaddr. 869 * 870 * @param context a Keberos context 871 * @param sa a struct sockaddr to extract the port from 872 * @param port a pointer to an int16_t store the port in. 873 * 874 * @return Return an error code or 0. Will return 875 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 876 * 877 * @ingroup krb5_address 878 */ 879 880 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 881 krb5_sockaddr2port (krb5_context context, 882 const struct sockaddr *sa, int16_t *port) 883 { 884 struct addr_operations *a = find_af(sa->sa_family); 885 if (a == NULL) { 886 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 887 N_("Address family %d not supported", ""), 888 sa->sa_family); 889 return KRB5_PROG_ATYPE_NOSUPP; 890 } 891 return (*a->sockaddr2port)(sa, port); 892 } 893 894 /** 895 * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr 896 * and port. The argument sa_size should initially contain the size of 897 * the sa and after the call, it will contain the actual length of the 898 * address. In case of the sa is too small to fit the whole address, 899 * the up to *sa_size will be stored, and then *sa_size will be set to 900 * the required length. 901 * 902 * @param context a Keberos context 903 * @param addr the address to copy the from 904 * @param sa the struct sockaddr that will be filled in 905 * @param sa_size pointer to length of sa, and after the call, it will 906 * contain the actual length of the address. 907 * @param port set port in sa. 908 * 909 * @return Return an error code or 0. Will return 910 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. 911 * 912 * @ingroup krb5_address 913 */ 914 915 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 916 krb5_addr2sockaddr (krb5_context context, 917 const krb5_address *addr, 918 struct sockaddr *sa, 919 krb5_socklen_t *sa_size, 920 int port) 921 { 922 struct addr_operations *a = find_atype(addr->addr_type); 923 924 if (a == NULL) { 925 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 926 N_("Address type %d not supported", 927 "krb5_address type"), 928 addr->addr_type); 929 return KRB5_PROG_ATYPE_NOSUPP; 930 } 931 if (a->addr2sockaddr == NULL) { 932 krb5_set_error_message (context, 933 KRB5_PROG_ATYPE_NOSUPP, 934 N_("Can't convert address type %d to sockaddr", ""), 935 addr->addr_type); 936 return KRB5_PROG_ATYPE_NOSUPP; 937 } 938 (*a->addr2sockaddr)(addr, sa, sa_size, port); 939 return 0; 940 } 941 942 /** 943 * krb5_max_sockaddr_size returns the max size of the .Li struct 944 * sockaddr that the Kerberos library will return. 945 * 946 * @return Return an size_t of the maximum struct sockaddr. 947 * 948 * @ingroup krb5_address 949 */ 950 951 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 952 krb5_max_sockaddr_size (void) 953 { 954 if (max_sockaddr_size == 0) { 955 struct addr_operations *a; 956 957 for(a = at; a < at + num_addrs; ++a) 958 max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size); 959 } 960 return max_sockaddr_size; 961 } 962 963 /** 964 * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the 965 * kerberos library thinks are uninteresting. One example are link 966 * local addresses. 967 * 968 * @param sa pointer to struct sockaddr that might be interesting. 969 * 970 * @return Return a non zero for uninteresting addresses. 971 * 972 * @ingroup krb5_address 973 */ 974 975 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 976 krb5_sockaddr_uninteresting(const struct sockaddr *sa) 977 { 978 struct addr_operations *a = find_af(sa->sa_family); 979 if (a == NULL || a->uninteresting == NULL) 980 return TRUE; 981 return (*a->uninteresting)(sa); 982 } 983 984 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 985 krb5_sockaddr_is_loopback(const struct sockaddr *sa) 986 { 987 struct addr_operations *a = find_af(sa->sa_family); 988 if (a == NULL || a->is_loopback == NULL) 989 return TRUE; 990 return (*a->is_loopback)(sa); 991 } 992 993 /** 994 * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and 995 * the "struct hostent" (see gethostbyname(3) ) h_addr_list 996 * component. The argument sa_size should initially contain the size 997 * of the sa, and after the call, it will contain the actual length of 998 * the address. 999 * 1000 * @param context a Keberos context 1001 * @param af addresses 1002 * @param addr address 1003 * @param sa returned struct sockaddr 1004 * @param sa_size size of sa 1005 * @param port port to set in sa. 1006 * 1007 * @return Return an error code or 0. 1008 * 1009 * @ingroup krb5_address 1010 */ 1011 1012 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1013 krb5_h_addr2sockaddr (krb5_context context, 1014 int af, 1015 const char *addr, struct sockaddr *sa, 1016 krb5_socklen_t *sa_size, 1017 int port) 1018 { 1019 struct addr_operations *a = find_af(af); 1020 if (a == NULL) { 1021 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1022 "Address family %d not supported", af); 1023 return KRB5_PROG_ATYPE_NOSUPP; 1024 } 1025 (*a->h_addr2sockaddr)(addr, sa, sa_size, port); 1026 return 0; 1027 } 1028 1029 /** 1030 * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception 1031 * that it operates on a krb5_address instead of a struct sockaddr. 1032 * 1033 * @param context a Keberos context 1034 * @param af address family 1035 * @param haddr host address from struct hostent. 1036 * @param addr returned krb5_address. 1037 * 1038 * @return Return an error code or 0. 1039 * 1040 * @ingroup krb5_address 1041 */ 1042 1043 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1044 krb5_h_addr2addr (krb5_context context, 1045 int af, 1046 const char *haddr, krb5_address *addr) 1047 { 1048 struct addr_operations *a = find_af(af); 1049 if (a == NULL) { 1050 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1051 N_("Address family %d not supported", ""), af); 1052 return KRB5_PROG_ATYPE_NOSUPP; 1053 } 1054 return (*a->h_addr2addr)(haddr, addr); 1055 } 1056 1057 /** 1058 * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to 1059 * bind(2) to. The argument sa_size should initially contain the size 1060 * of the sa, and after the call, it will contain the actual length 1061 * of the address. 1062 * 1063 * @param context a Keberos context 1064 * @param af address family 1065 * @param sa sockaddr 1066 * @param sa_size lenght of sa. 1067 * @param port for to fill into sa. 1068 * 1069 * @return Return an error code or 0. 1070 * 1071 * @ingroup krb5_address 1072 */ 1073 1074 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1075 krb5_anyaddr (krb5_context context, 1076 int af, 1077 struct sockaddr *sa, 1078 krb5_socklen_t *sa_size, 1079 int port) 1080 { 1081 struct addr_operations *a = find_af (af); 1082 1083 if (a == NULL) { 1084 krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, 1085 N_("Address family %d not supported", ""), af); 1086 return KRB5_PROG_ATYPE_NOSUPP; 1087 } 1088 1089 (*a->anyaddr)(sa, sa_size, port); 1090 return 0; 1091 } 1092 1093 /** 1094 * krb5_print_address prints the address in addr to the string string 1095 * that have the length len. If ret_len is not NULL, it will be filled 1096 * with the length of the string if size were unlimited (not including 1097 * the final NUL) . 1098 * 1099 * @param addr address to be printed 1100 * @param str pointer string to print the address into 1101 * @param len length that will fit into area pointed to by "str". 1102 * @param ret_len return length the str. 1103 * 1104 * @return Return an error code or 0. 1105 * 1106 * @ingroup krb5_address 1107 */ 1108 1109 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1110 krb5_print_address (const krb5_address *addr, 1111 char *str, size_t len, size_t *ret_len) 1112 { 1113 struct addr_operations *a = find_atype(addr->addr_type); 1114 int ret; 1115 1116 if (a == NULL || a->print_addr == NULL) { 1117 char *s; 1118 int l; 1119 size_t i; 1120 1121 s = str; 1122 l = snprintf(s, len, "TYPE_%d:", addr->addr_type); 1123 if (l < 0 || (size_t)l >= len) 1124 return EINVAL; 1125 s += l; 1126 len -= l; 1127 for(i = 0; i < addr->address.length; i++) { 1128 l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); 1129 if (l < 0 || (size_t)l >= len) 1130 return EINVAL; 1131 len -= l; 1132 s += l; 1133 } 1134 if(ret_len != NULL) 1135 *ret_len = s - str; 1136 return 0; 1137 } 1138 ret = (*a->print_addr)(addr, str, len); 1139 if (ret < 0) 1140 return EINVAL; 1141 if(ret_len != NULL) 1142 *ret_len = ret; 1143 return 0; 1144 } 1145 1146 /** 1147 * krb5_parse_address returns the resolved hostname in string to the 1148 * krb5_addresses addresses . 1149 * 1150 * @param context a Keberos context 1151 * @param string 1152 * @param addresses 1153 * 1154 * @return Return an error code or 0. 1155 * 1156 * @ingroup krb5_address 1157 */ 1158 1159 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1160 krb5_parse_address(krb5_context context, 1161 const char *string, 1162 krb5_addresses *addresses) 1163 { 1164 int i, n; 1165 struct addrinfo *ai, *a; 1166 struct addrinfo hint; 1167 int error; 1168 int save_errno; 1169 1170 addresses->len = 0; 1171 addresses->val = NULL; 1172 1173 for(i = 0; i < num_addrs; i++) { 1174 if(at[i].parse_addr) { 1175 krb5_address addr; 1176 if((*at[i].parse_addr)(context, string, &addr) == 0) { 1177 ALLOC_SEQ(addresses, 1); 1178 if (addresses->val == NULL) 1179 return krb5_enomem(context); 1180 addresses->val[0] = addr; 1181 return 0; 1182 } 1183 } 1184 } 1185 1186 /* if not parsed as numeric address, do a name lookup */ 1187 memset(&hint, 0, sizeof(hint)); 1188 hint.ai_family = AF_UNSPEC; 1189 error = getaddrinfo (string, NULL, &hint, &ai); 1190 if (error) { 1191 krb5_error_code ret2; 1192 save_errno = errno; 1193 ret2 = krb5_eai_to_heim_errno(error, save_errno); 1194 krb5_set_error_message (context, ret2, "%s: %s", 1195 string, gai_strerror(error)); 1196 return ret2; 1197 } 1198 1199 n = 0; 1200 for (a = ai; a != NULL; a = a->ai_next) 1201 ++n; 1202 1203 ALLOC_SEQ(addresses, n); 1204 if (addresses->val == NULL) { 1205 freeaddrinfo(ai); 1206 return krb5_enomem(context); 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 krb5_enomem(context); 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 return krb5_enomem(context); 1447 dest->val = tmp; 1448 for(i = 0; i < source->len; i++) { 1449 /* skip duplicates */ 1450 if(krb5_address_search(context, &source->val[i], dest)) 1451 continue; 1452 ret = krb5_copy_address(context, 1453 &source->val[i], 1454 &dest->val[dest->len]); 1455 if(ret) 1456 return ret; 1457 dest->len++; 1458 } 1459 } 1460 return 0; 1461 } 1462 1463 /** 1464 * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port) 1465 * 1466 * @param context a Keberos context 1467 * @param res built address from addr/port 1468 * @param addr address to use 1469 * @param port port to use 1470 * 1471 * @return Return an error code or 0. 1472 * 1473 * @ingroup krb5_address 1474 */ 1475 1476 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1477 krb5_make_addrport (krb5_context context, 1478 krb5_address **res, const krb5_address *addr, int16_t port) 1479 { 1480 krb5_error_code ret; 1481 size_t len = addr->address.length + 2 + 4 * 4; 1482 u_char *p; 1483 1484 *res = malloc (sizeof(**res)); 1485 if (*res == NULL) 1486 return krb5_enomem(context); 1487 (*res)->addr_type = KRB5_ADDRESS_ADDRPORT; 1488 ret = krb5_data_alloc (&(*res)->address, len); 1489 if (ret) { 1490 free (*res); 1491 *res = NULL; 1492 return krb5_enomem(context); 1493 } 1494 p = (*res)->address.data; 1495 *p++ = 0; 1496 *p++ = 0; 1497 *p++ = (addr->addr_type ) & 0xFF; 1498 *p++ = (addr->addr_type >> 8) & 0xFF; 1499 1500 *p++ = (addr->address.length ) & 0xFF; 1501 *p++ = (addr->address.length >> 8) & 0xFF; 1502 *p++ = (addr->address.length >> 16) & 0xFF; 1503 *p++ = (addr->address.length >> 24) & 0xFF; 1504 1505 memcpy (p, addr->address.data, addr->address.length); 1506 p += addr->address.length; 1507 1508 *p++ = 0; 1509 *p++ = 0; 1510 *p++ = (KRB5_ADDRESS_IPPORT ) & 0xFF; 1511 *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF; 1512 1513 *p++ = (2 ) & 0xFF; 1514 *p++ = (2 >> 8) & 0xFF; 1515 *p++ = (2 >> 16) & 0xFF; 1516 *p++ = (2 >> 24) & 0xFF; 1517 1518 memcpy (p, &port, 2); 1519 1520 return 0; 1521 } 1522 1523 /** 1524 * Calculate the boundary addresses of `inaddr'/`prefixlen' and store 1525 * them in `low' and `high'. 1526 * 1527 * @param context a Keberos context 1528 * @param inaddr address in prefixlen that the bondery searched 1529 * @param prefixlen width of boundery 1530 * @param low lowest address 1531 * @param high highest address 1532 * 1533 * @return Return an error code or 0. 1534 * 1535 * @ingroup krb5_address 1536 */ 1537 1538 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1539 krb5_address_prefixlen_boundary(krb5_context context, 1540 const krb5_address *inaddr, 1541 unsigned long prefixlen, 1542 krb5_address *low, 1543 krb5_address *high) 1544 { 1545 struct addr_operations *a = find_atype (inaddr->addr_type); 1546 if(a != NULL && a->mask_boundary != NULL) 1547 return (*a->mask_boundary)(context, inaddr, prefixlen, low, high); 1548 krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, 1549 N_("Address family %d doesn't support " 1550 "address mask operation", ""), 1551 inaddr->addr_type); 1552 return KRB5_PROG_ATYPE_NOSUPP; 1553 } 1554