1#ifndef lint 2static char *rcsid = "$Id: resolver.c,v 1.1 2003/06/04 00:27:12 marka Exp $"; 3#endif 4 5/* 6 * Copyright (c) 2001 Japan Network Information Center. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set forth bellow. 9 * 10 * LICENSE TERMS AND CONDITIONS 11 * 12 * The following License Terms and Conditions apply, unless a different 13 * license is obtained from Japan Network Information Center ("JPNIC"), 14 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, 15 * Chiyoda-ku, Tokyo 101-0047, Japan. 16 * 17 * 1. Use, Modification and Redistribution (including distribution of any 18 * modified or derived work) in source and/or binary forms is permitted 19 * under this License Terms and Conditions. 20 * 21 * 2. Redistribution of source code must retain the copyright notices as they 22 * appear in each source code file, this License Terms and Conditions. 23 * 24 * 3. Redistribution in binary form must reproduce the Copyright Notice, 25 * this License Terms and Conditions, in the documentation and/or other 26 * materials provided with the distribution. For the purposes of binary 27 * distribution the "Copyright Notice" refers to the following language: 28 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." 29 * 30 * 4. The name of JPNIC may not be used to endorse or promote products 31 * derived from this Software without specific prior written approval of 32 * JPNIC. 33 * 34 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC 35 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 37 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE 38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 42 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 43 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 44 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 45 */ 46 47#include <config.h> 48 49#include <stdio.h> 50#include <stddef.h> 51#include <stdarg.h> 52#include <stdlib.h> 53#include <string.h> 54#include <sys/types.h> 55#include <sys/socket.h> 56#include <netdb.h> 57#include <errno.h> 58 59#include <idn/api.h> 60#include <idn/log.h> 61#include <idn/logmacro.h> 62#include <idn/debug.h> 63 64#ifdef FOR_RUNIDN 65/* 66 * This file is specially compiled for runidn. 67 * runidn replaces existing resolver functions dynamically with ones 68 * with IDN processing (encoding conversion and normalization). 69 * So entry names must be same as the system's one. 70 */ 71#include "stub.h" 72 73#define ENTRY(name) name 74#define REAL(name) idn_stub_ ## name 75#else 76/* 77 * For normal use. All the entry names are prefixed with "idn_resolver_". 78 * <idn/resolver.h> has bunch of #defines to substitute the standard 79 * name resolver functions with ones provided here. 80 */ 81#include "resolver.h" 82#undef gethostbyname 83#undef gethostbyname2 84#undef gethostbyaddr 85#undef gethostbyname_r 86#undef gethostbyname2_r 87#undef gethostbyaddr_r 88#undef getipnodebyname 89#undef getipnodebyaddr 90#undef getaddrinfo 91#undef getnameinfo 92 93#define ENTRY(name) idn_resolver_ ## name 94#define REAL(name) name 95#endif 96 97#define IDN_NAME_SIZE 512 98 99#define IDN_HOSTBUF_SIZE 2048 100typedef union { 101 char *dummy_for_alignment; 102 char data[IDN_HOSTBUF_SIZE]; 103} hostbuf_t; 104 105typedef struct obj_lock { 106 void *key; 107 struct obj_lock *next; 108} obj_lock_t; 109 110#define OBJLOCKHASH_SIZE 127 111static obj_lock_t *obj_lock_hash[OBJLOCKHASH_SIZE]; 112 113/* 114 * This variable is to prevent IDN processing occuring more than once for 115 * a single name resolution. This will happen if some resolver function 116 * is implemented using another function (e.g. gethostbyname() implemented 117 * using gethostbyname2()). 118 * No, using the static variable is not a correct thing to do for a multi- 119 * threading environment, but I don't think of a better solution.. 120 */ 121static int idn_isprocessing = 0; 122 123static int obj_hash(void *key); 124static int obj_islocked(void *key); 125static void obj_lock(void *key); 126static void obj_unlock(void *key); 127static struct hostent *copy_decode_hostent_static(struct hostent *hp, 128 struct hostent *newhp, 129 char *buf, size_t buflen, 130 int *errp); 131static char *decode_name_dynamic(const char *name); 132static struct hostent *copy_decode_hostent_dynamic(struct hostent *hp, 133 int *errp); 134static void free_copied_hostent(struct hostent *hp); 135#ifdef HAVE_GETADDRINFO 136static struct addrinfo *copy_decode_addrinfo_dynamic(struct addrinfo *aip); 137#endif 138#ifdef HAVE_FREEADDRINFO 139static void free_copied_addrinfo(struct addrinfo *aip); 140#endif 141 142/* 143 * Object locking facility. 144 */ 145 146static int 147obj_hash(void *key) { 148 /* 149 * Hash function for obj_*. 150 * 'key' is supposed to be an address. 151 */ 152 unsigned long v = (unsigned long)key; 153 154 return ((v >> 3) % OBJLOCKHASH_SIZE); 155} 156 157static int 158obj_islocked(void *key) 159{ 160 /* 161 * Check if the object specified by 'key' is locked. 162 * Return 1 if so, 0 otherwise. 163 */ 164 int h = obj_hash(key); 165 obj_lock_t *olp = obj_lock_hash[h]; 166 167 while (olp != NULL) { 168 if (olp->key == key) 169 return (1); 170 olp = olp->next; 171 } 172 return (0); 173} 174 175static void 176obj_lock(void *key) 177{ 178 /* 179 * Lock an object specified by 'key'. 180 */ 181 int h = obj_hash(key); 182 obj_lock_t *olp; 183 184 olp = malloc(sizeof(obj_lock_t)); 185 if (olp != NULL) { 186 olp->key = key; 187 olp->next = obj_lock_hash[h]; 188 obj_lock_hash[h] = olp; 189 } 190} 191 192static void 193obj_unlock(void *key) 194{ 195 /* 196 * Unlock an object specified by 'key'. 197 */ 198 int h = obj_hash(key); 199 obj_lock_t *olp, *olp0; 200 201 olp = obj_lock_hash[h]; 202 olp0 = NULL; 203 while (olp != NULL) { 204 if (olp->key == key) { 205 if (olp0 == NULL) 206 obj_lock_hash[h] = olp->next; 207 else 208 olp0->next = olp->next; 209 free(olp); 210 return; 211 } 212 olp0 = olp; 213 olp = olp->next; 214 } 215} 216 217static struct hostent * 218copy_decode_hostent_static(struct hostent *hp, struct hostent *newhp, 219 char *buf, size_t buflen, int *errp) 220{ 221 /* 222 * Copy "struct hostent" data referenced by 'hp' to 'newhp'. 223 * It's a deep-copy, meaning all the data referenced by 'hp' are 224 * also copied. They are copied into 'buf', whose length is 'buflen'. 225 * The domain names ('hp->h_name' and 'hp->h_aliases') are 226 * decoded from ACE to the local encoding before they are copied. 227 * If 'buf' is too small to hold all the data, NULL will be 228 * returned and '*errp' is set to NO_RECOVERY. 229 */ 230 int naliases = 0; 231 int naddrs = 0; 232 233 if (hp == NULL) 234 return (NULL); 235 236 *newhp = *hp; 237 238 if (hp->h_aliases != NULL) { 239 /* 240 * Allocate aliase table in 'buf'. 241 */ 242 size_t sz; 243 244 while (hp->h_aliases[naliases] != NULL) 245 naliases++; 246 247 newhp->h_aliases = (char **)buf; 248 sz = sizeof(char *) * (naliases + 1); 249 250 if (buflen < sz) 251 goto overflow; 252 253 buf += sz; 254 buflen -= sz; 255 } 256 257 if (hp->h_addr_list != NULL) { 258 /* 259 * Allocate address table in 'buf'. 260 */ 261 size_t sz; 262 int i; 263 264 while (hp->h_addr_list[naddrs] != NULL) 265 naddrs++; 266 267 newhp->h_addr_list = (char **)buf; 268 sz = sizeof(char *) * (naddrs + 1); 269 270 if (buflen < sz) 271 goto overflow; 272 273 buf += sz; 274 buflen -= sz; 275 276 /* 277 * Copy the addresses. 278 */ 279 sz = hp->h_length * naddrs; 280 if (buflen < sz) 281 goto overflow; 282 283 for (i = 0; i < naddrs; i++) { 284 newhp->h_addr_list[i] = buf; 285 memcpy(buf, hp->h_addr_list[i], hp->h_length); 286 buf += hp->h_length; 287 } 288 newhp->h_addr_list[naddrs] = NULL; 289 290 buf += sz; 291 buflen -= sz; 292 } 293 294 if (hp->h_name != NULL) { 295 /* 296 * Decode the name in h_name. 297 */ 298 idn_result_t r; 299 size_t slen; 300 301 idn_enable(1); 302 idn_nameinit(1); 303 r = idn_decodename(IDN_DECODE_APP, hp->h_name, 304 buf, buflen); 305 switch (r) { 306 case idn_success: 307 newhp->h_name = buf; 308 break; 309 default: 310 /* Copy hp->h_name verbatim. */ 311 if (strlen(hp->h_name) + 1 <= buflen) { 312 newhp->h_name = buf; 313 strcpy(buf, hp->h_name); 314 break; 315 } 316 /* falllthrough */ 317 case idn_buffer_overflow: 318 goto overflow; 319 } 320 321 slen = strlen(buf) + 1; 322 buf += slen; 323 buflen -= slen; 324 } 325 326 if (hp->h_aliases != NULL) { 327 /* 328 * Decode the names in h_aliases. 329 */ 330 char **aliases = hp->h_aliases; 331 char **newaliases = newhp->h_aliases; 332 int i; 333 334 for (i = 0; i < naliases; i++) { 335 idn_result_t r; 336 size_t slen; 337 338 idn_enable(1); 339 idn_nameinit(1); 340 r = idn_decodename(IDN_DECODE_APP, aliases[i], 341 buf, buflen); 342 343 switch (r) { 344 case idn_success: 345 newaliases[i] = buf; 346 break; 347 default: 348 /* Copy hp->h_name verbatim. */ 349 if (strlen(aliases[i]) + 1 <= buflen) { 350 newaliases[i] = buf; 351 strcpy(buf, aliases[i]); 352 break; 353 } 354 /* falllthrough */ 355 case idn_buffer_overflow: 356 goto overflow; 357 } 358 359 slen = strlen(buf) + 1; 360 buf += slen; 361 buflen -= slen; 362 } 363 newaliases[naliases] = NULL; 364 } 365 366 return (newhp); 367 368 overflow: 369 *errp = NO_RECOVERY; 370 return (NULL); 371} 372 373static char * 374decode_name_dynamic(const char *name) { 375 idn_result_t r; 376 char buf[IDN_NAME_SIZE]; 377 char *s; 378 379 idn_enable(1); 380 idn_nameinit(1); 381 r = idn_decodename(IDN_DECODE_APP, name, buf, sizeof(buf)); 382 if (r == idn_success) { 383 name = buf; 384 } 385 s = malloc(strlen(name) + 1); 386 if (s == NULL) 387 return (NULL); 388 else 389 return (strcpy(s, name)); 390} 391 392static struct hostent * 393copy_decode_hostent_dynamic(struct hostent *hp, int *errp) { 394 /* 395 * Make a deep-copy of the data referenced by 'hp', and return 396 * a pointer to the copied data. 397 * All the data are dynamically allocated using malloc(). 398 * The domain names ('hp->h_name' and 'hp->h_aliases') are 399 * decoded from ACE to the local encoding before they are copied. 400 * If malloc() fails, NULL will be returned and '*errp' is set to 401 * NO_RECOVERY. 402 */ 403 struct hostent *newhp; 404 char **pp; 405 size_t alloc_size; 406 int naliases = 0; 407 int naddrs = 0; 408 int i; 409 410 if (hp == NULL) 411 return (NULL); 412 413 if (hp->h_aliases != NULL) { 414 while (hp->h_aliases[naliases] != NULL) 415 naliases++; 416 } 417 418 if (hp->h_addr_list != NULL) { 419 while (hp->h_addr_list[naddrs] != NULL) 420 naddrs++; 421 } 422 423 alloc_size = sizeof(struct hostent) + 424 sizeof(char *) * (naliases + 1) + 425 sizeof(char *) * (naddrs + 1) + 426 hp->h_length * naddrs; 427 428 if ((newhp = malloc(alloc_size)) == NULL) { 429 return (hp); 430 } 431 432 memset(newhp, 0, alloc_size); 433 434 pp = (char **)(newhp + 1); 435 436 if (hp->h_name != NULL) { 437 newhp->h_name = decode_name_dynamic(hp->h_name); 438 if (newhp->h_name == NULL) 439 goto alloc_fail; 440 } 441 442 newhp->h_addrtype = hp->h_addrtype; 443 newhp->h_length = hp->h_length; 444 445 if (hp->h_aliases != NULL) { 446 newhp->h_aliases = pp; 447 for (i = 0; i < naliases; i++) { 448 newhp->h_aliases[i] = 449 decode_name_dynamic(hp->h_aliases[i]); 450 if (newhp->h_aliases[i] == NULL) 451 goto alloc_fail; 452 } 453 newhp->h_aliases[naliases] = NULL; 454 pp += naliases + 1; 455 } 456 457 if (hp->h_addr_list != NULL) { 458 char *p; 459 460 newhp->h_addr_list = pp; 461 pp += naddrs + 1; 462 p = (char *)pp; 463 464 for (i = 0; i < naddrs; i++) { 465 newhp->h_addr_list[i] = p; 466 memcpy(p, hp->h_addr_list[i], hp->h_length); 467 p += hp->h_length; 468 } 469 newhp->h_addr_list[naddrs] = NULL; 470 } 471 472 return (newhp); 473 474 alloc_fail: 475 free_copied_hostent(hp); 476 *errp = NO_RECOVERY; 477 return (NULL); 478} 479 480static void 481free_copied_hostent(struct hostent *hp) { 482 /* 483 * Free all the memory allocated by copy_decode_hostent_dynamic(). 484 */ 485 if (hp->h_name != NULL) 486 free(hp->h_name); 487 if (hp->h_aliases != NULL) { 488 char **pp = hp->h_aliases; 489 while (*pp != NULL) 490 free(*pp++); 491 } 492 free(hp); 493} 494 495#ifdef HAVE_GETNAMEINFO 496static struct addrinfo * 497copy_decode_addrinfo_dynamic(struct addrinfo *aip) { 498 struct addrinfo *newaip; 499 500 if (aip == NULL) 501 return (NULL); 502 503 newaip = malloc(sizeof(struct addrinfo) + aip->ai_addrlen); 504 if (newaip == NULL) 505 return (NULL); 506 507 *newaip = *aip; 508 newaip->ai_addr = (struct sockaddr *)(newaip + 1); 509 memcpy(newaip->ai_addr, aip->ai_addr, aip->ai_addrlen); 510 511 if (newaip->ai_canonname != NULL) 512 newaip->ai_canonname = decode_name_dynamic(aip->ai_canonname); 513 514 newaip->ai_next = copy_decode_addrinfo_dynamic(aip->ai_next); 515 return (newaip); 516} 517#endif 518 519#ifdef HAVE_FREEADDRINFO 520static void 521free_copied_addrinfo(struct addrinfo *aip) { 522 while (aip != NULL) { 523 struct addrinfo *next = aip->ai_next; 524 525 if (aip->ai_canonname != NULL) 526 free(aip->ai_canonname); 527 free(aip); 528 aip = next; 529 } 530} 531#endif 532 533#ifdef HAVE_GETHOSTBYNAME 534struct hostent * 535ENTRY(gethostbyname)(const char *name) { 536 static hostbuf_t buf; 537 static struct hostent he; 538 idn_result_t r; 539 struct hostent *hp; 540 541 if (idn_isprocessing) 542 return (REAL(gethostbyname)(name)); 543 544 TRACE(("gethostbyname(name=%s)\n", idn__debug_xstring(name, 60))); 545 546 idn_isprocessing = 1; 547 idn_enable(1); 548 idn_nameinit(1); 549 r = idn_encodename(IDN_ENCODE_APP, name, buf.data, sizeof(buf)); 550 if (r == idn_success) 551 name = buf.data; 552 553 hp = copy_decode_hostent_static(REAL(gethostbyname)(name), 554 &he, buf.data, sizeof(buf), 555 &h_errno); 556 idn_isprocessing = 0; 557 return (hp); 558} 559#endif 560 561#ifdef HAVE_GETHOSTBYNAME2 562struct hostent * 563ENTRY(gethostbyname2)(const char *name, int af) { 564 static hostbuf_t buf; 565 static struct hostent he; 566 idn_result_t r; 567 struct hostent *hp; 568 569 if (idn_isprocessing) 570 return (REAL(gethostbyname2)(name, af)); 571 572 TRACE(("gethostbyname2(name=%s)\n", idn__debug_xstring(name, 60), af)); 573 574 idn_isprocessing = 1; 575 idn_enable(1); 576 idn_nameinit(1); 577 r = idn_encodename(IDN_ENCODE_APP, name, buf.data, sizeof(buf)); 578 if (r == idn_success) 579 name = buf.data; 580 581 hp = copy_decode_hostent_static(REAL(gethostbyname2)(name, af), 582 &he, buf.data, sizeof(buf), 583 &h_errno); 584 idn_isprocessing = 0; 585 return (hp); 586} 587#endif 588 589#ifdef HAVE_GETHOSTBYADDR 590struct hostent * 591ENTRY(gethostbyaddr)(GHBA_ADDR_T addr, GHBA_ADDRLEN_T len, int type) { 592 static hostbuf_t buf; 593 static struct hostent he; 594 struct hostent *hp; 595 596 if (idn_isprocessing) 597 return (REAL(gethostbyaddr)(addr, len, type)); 598 599 TRACE(("gethostbyaddr()\n")); 600 601 idn_isprocessing = 1; 602 hp = copy_decode_hostent_static(REAL(gethostbyaddr)(addr, len, type), 603 &he, buf.data, sizeof(buf), 604 &h_errno); 605 idn_isprocessing = 0; 606 return (hp); 607} 608#endif 609 610#ifdef GETHOST_R_GLIBC_FLAVOR 611 612#ifdef HAVE_GETHOSTBYNAME_R 613int 614ENTRY(gethostbyname_r)(const char *name, struct hostent *result, 615 char *buffer, size_t buflen, 616 struct hostent **rp, int *errp) 617{ 618 char namebuf[IDN_NAME_SIZE]; 619 char *data; 620 size_t datalen; 621 idn_result_t r; 622 struct hostent he; 623 hostbuf_t buf; 624 int n; 625 626 if (idn_isprocessing) 627 return (REAL(gethostbyname_r)(name, result, buffer, 628 buflen, rp, errp)); 629 630 TRACE(("gethostbyname_r(name=%s,buflen=%d)\n", 631 idn__debug_xstring(name, 60), buflen)); 632 633 if (buflen <= sizeof(buf)) { 634 data = buf.data; 635 datalen = sizeof(buf); 636 } else { 637 data = malloc(buflen); 638 datalen = buflen; 639 if (data == NULL) { 640 *errp = NO_RECOVERY; 641 return (ENOMEM); 642 } 643 } 644 645 idn_isprocessing = 1; 646 idn_enable(1); 647 idn_nameinit(1); 648 r = idn_encodename(IDN_ENCODE_APP, name, namebuf, sizeof(namebuf)); 649 if (r == idn_success) 650 name = namebuf; 651 652 *errp = 0; 653 n = REAL(gethostbyname_r)(name, &he, data, datalen, rp, errp); 654 655 if (n == 0 && *rp != NULL) 656 *rp = copy_decode_hostent_static(*rp, result, buffer, buflen, 657 errp); 658 idn_isprocessing = 0; 659 660 if (data != buf.data) 661 free(data); 662 663 if (*errp != 0) 664 n = EINVAL; /* XXX */ 665 666 return (n); 667} 668#endif 669 670#ifdef HAVE_GETHOSTBYNAME2_R 671int 672ENTRY(gethostbyname2_r)(const char *name, int af, struct hostent *result, 673 char *buffer, size_t buflen, 674 struct hostent **rp, int *errp) 675{ 676 char namebuf[IDN_NAME_SIZE]; 677 char *data; 678 size_t datalen; 679 idn_result_t r; 680 struct hostent he; 681 hostbuf_t buf; 682 int n; 683 684 if (idn_isprocessing) 685 return (REAL(gethostbyname2_r)(name, af, result, buffer, 686 buflen, rp, errp)); 687 688 TRACE(("gethostbyname2_r(name=%s,buflen=%d)\n", 689 idn__debug_xstring(name, 60), buflen)); 690 691 if (buflen <= sizeof(buf)) { 692 data = buf.data; 693 datalen = sizeof(buf); 694 } else { 695 data = malloc(buflen); 696 datalen = buflen; 697 if (data == NULL) { 698 *errp = NO_RECOVERY; 699 return (ENOMEM); 700 } 701 } 702 703 idn_isprocessing = 1; 704 idn_enable(1); 705 idn_nameinit(1); 706 r = idn_encodename(IDN_ENCODE_APP, name, namebuf, sizeof(namebuf)); 707 if (r == idn_success) 708 name = namebuf; 709 710 n = REAL(gethostbyname2_r)(name, af, &he, data, datalen, rp, errp); 711 712 if (n == 0 && *rp != NULL) 713 *rp = copy_decode_hostent_static(*rp, result, buffer, buflen, 714 errp); 715 idn_isprocessing = 0; 716 717 if (data != buf.data) 718 free(data); 719 720 if (*errp != 0) 721 n = EINVAL; /* XXX */ 722 723 return (n); 724} 725#endif 726 727#ifdef HAVE_GETHOSTBYADDR_R 728int 729ENTRY(gethostbyaddr_r)(GHBA_ADDR_T addr, GHBA_ADDRLEN_T len, int type, 730 struct hostent *result, 731 char *buffer, size_t buflen, 732 struct hostent **rp, int *errp) 733{ 734 char *data; 735 size_t datalen; 736 struct hostent he; 737 hostbuf_t buf; 738 int n; 739 740 if (idn_isprocessing) { 741 return (REAL(gethostbyaddr_r)(addr, len, type, result, 742 buffer, buflen, rp, errp)); 743 } 744 745 TRACE(("gethostbyaddr_r(buflen=%d)\n", buflen)); 746 747 if (buflen <= sizeof(buf)) { 748 data = buf.data; 749 datalen = sizeof(buf); 750 } else { 751 data = malloc(buflen); 752 datalen = buflen; 753 if (data == NULL) { 754 *errp = NO_RECOVERY; 755 return (ENOMEM); 756 } 757 } 758 759 idn_isprocessing = 1; 760 n = REAL(gethostbyaddr_r)(addr, len, type, &he, 761 data, datalen, rp, errp); 762 763 if (n == 0 && *rp != NULL) 764 *rp = copy_decode_hostent_static(*rp, result, buffer, buflen, 765 errp); 766 idn_isprocessing = 0; 767 768 if (data != buf.data) 769 free(data); 770 771 if (*errp != 0) 772 n = EINVAL; /* XXX */ 773 774 return (0); 775} 776#endif 777 778#else /* GETHOST_R_GLIBC_FLAVOR */ 779 780#ifdef HAVE_GETHOSTBYNAME_R 781struct hostent * 782ENTRY(gethostbyname_r)(const char *name, struct hostent *result, 783 char *buffer, int buflen, int *errp) 784{ 785 char namebuf[IDN_NAME_SIZE]; 786 char *data; 787 size_t datalen; 788 idn_result_t r; 789 struct hostent *hp, he; 790 hostbuf_t buf; 791 792 if (idn_isprocessing) 793 return (REAL(gethostbyname_r)(name, result, buffer, 794 buflen, errp)); 795 796 TRACE(("gethostbyname_r(name=%s,buflen=%d)\n", 797 idn__debug_xstring(name, 60), buflen)); 798 799 if (buflen <= sizeof(buf)) { 800 data = buf.data; 801 datalen = sizeof(buf); 802 } else { 803 data = malloc(buflen); 804 datalen = buflen; 805 if (data == NULL) { 806 *errp = NO_RECOVERY; 807 return (NULL); 808 } 809 } 810 811 idn_isprocessing = 1; 812 idn_enable(1); 813 idn_nameinit(1); 814 r = idn_encodename(IDN_ENCODE_APP, name, namebuf, sizeof(namebuf)); 815 if (r == idn_success) 816 name = namebuf; 817 818 hp = REAL(gethostbyname_r)(name, &he, data, datalen, errp); 819 820 if (hp != NULL) 821 hp = copy_decode_hostent_static(hp, result, buffer, buflen, 822 errp); 823 idn_isprocessing = 0; 824 825 if (data != buf.data) 826 free(data); 827 828 return (hp); 829} 830#endif 831 832#ifdef HAVE_GETHOSTBYADDR_R 833struct hostent * 834ENTRY(gethostbyaddr_r)(GHBA_ADDR_T addr, GHBA_ADDRLEN_T len, int type, 835 struct hostent *result, 836 char *buffer, int buflen, int *errp) 837{ 838 char *data; 839 size_t datalen; 840 struct hostent *hp, he; 841 hostbuf_t buf; 842 843 if (idn_isprocessing) { 844 return (REAL(gethostbyaddr_r)(addr, len, type, result, 845 buffer, buflen, errp)); 846 } 847 848 TRACE(("gethostbyaddr_r(buflen=%d)\n", buflen)); 849 850 if (buflen <= sizeof(buf)) { 851 data = buf.data; 852 datalen = sizeof(buf); 853 } else { 854 data = malloc(buflen); 855 datalen = buflen; 856 if (data == NULL) { 857 *errp = NO_RECOVERY; 858 return (NULL); 859 } 860 } 861 862 idn_isprocessing = 1; 863 hp = REAL(gethostbyaddr_r)(addr, len, type, &he, data, datalen, errp); 864 865 if (hp != NULL) 866 hp = copy_decode_hostent_static(hp, result, buffer, buflen, 867 errp); 868 idn_isprocessing = 0; 869 870 if (data != buf.data) 871 free(data); 872 873 return (hp); 874} 875#endif 876 877#endif /* GETHOST_R_GLIBC_FLAVOR */ 878 879#ifdef HAVE_GETIPNODEBYNAME 880struct hostent * 881ENTRY(getipnodebyname)(const char *name, int af, int flags, int *errp) { 882 char namebuf[IDN_NAME_SIZE]; 883 idn_result_t r; 884 struct hostent *hp; 885 886 if (idn_isprocessing) 887 return (REAL(getipnodebyname)(name, af, flags, errp)); 888 889 TRACE(("getipnodebyname(name=%s)\n", idn__debug_xstring(name, 60), af)); 890 891 idn_isprocessing = 1; 892 idn_enable(1); 893 idn_nameinit(1); 894 r = idn_encodename(IDN_ENCODE_APP, name, namebuf, sizeof(namebuf)); 895 if (r == idn_success) 896 name = namebuf; 897 898 hp = REAL(getipnodebyname)(name, af, flags, errp); 899 if (hp != NULL) { 900 struct hostent *newhp = copy_decode_hostent_dynamic(hp, errp); 901 if (newhp != hp) { 902 REAL(freehostent)(hp); 903 obj_lock(newhp); 904 hp = newhp; 905 } 906 } 907 idn_isprocessing = 0; 908 return (hp); 909} 910#endif 911 912#ifdef HAVE_GETIPNODEBYADDR 913struct hostent * 914ENTRY(getipnodebyaddr)(const void *src, size_t len, int af, int *errp) { 915 struct hostent *hp; 916 917 if (idn_isprocessing) 918 return (REAL(getipnodebyaddr)(src, len, af, errp)); 919 920 TRACE(("getipnodebyaddr()\n")); 921 922 idn_isprocessing = 1; 923 hp = REAL(getipnodebyaddr)(src, len, af, errp); 924 if (hp != NULL) { 925 struct hostent *newhp = copy_decode_hostent_dynamic(hp, errp); 926 if (newhp != hp) { 927 REAL(freehostent)(hp); 928 obj_lock(newhp); 929 hp = newhp; 930 } 931 } 932 idn_isprocessing = 0; 933 return (hp); 934} 935#endif 936 937#ifdef HAVE_FREEHOSTENT 938void 939ENTRY(freehostent)(struct hostent *hp) { 940 TRACE(("freehostent(hp=%p)\n", (void *)hp)); 941 942 if (obj_islocked(hp)) { 943 /* 944 * We allocated the data. 945 */ 946 obj_unlock(hp); 947 free_copied_hostent(hp); 948 } else { 949 /* 950 * It was allocated the original getipnodeby*(). 951 */ 952 REAL(freehostent)(hp); 953 } 954} 955#endif 956 957#ifdef HAVE_GETADDRINFO 958int 959ENTRY(getaddrinfo)(const char *nodename, const char *servname, 960 const struct addrinfo *hints, struct addrinfo **res) 961{ 962 char namebuf[IDN_NAME_SIZE]; 963 idn_result_t r; 964 struct addrinfo *aip; 965 int err; 966 967 if (nodename == NULL || idn_isprocessing) 968 return (REAL(getaddrinfo)(nodename, servname, hints, res)); 969 970 TRACE(("getaddrinfo(nodename=%s)\n", idn__debug_xstring(nodename, 60))); 971 972 idn_isprocessing = 1; 973 idn_enable(1); 974 idn_nameinit(1); 975 r = idn_encodename(IDN_ENCODE_APP, nodename, 976 namebuf, sizeof(namebuf)); 977 if (r == idn_success) 978 nodename = namebuf; 979 980 err = REAL(getaddrinfo)(nodename, servname, hints, &aip); 981 if (err == 0 && aip != NULL) { 982 *res = copy_decode_addrinfo_dynamic(aip); 983 if (*res == NULL) 984 err = EAI_FAIL; 985 else 986 obj_lock(*res); 987 if (aip != NULL) 988 REAL(freeaddrinfo)(aip); 989 } 990 idn_isprocessing = 0; 991 return (err); 992} 993#endif 994 995#ifdef HAVE_FREEADDRINFO 996void 997ENTRY(freeaddrinfo)(struct addrinfo *aip) { 998 TRACE(("freeaddrinfo(aip=%p)\n", (void *)aip)); 999 1000 if (obj_islocked(aip)) { 1001 /* 1002 * We allocated the data. 1003 */ 1004 obj_unlock(aip); 1005 free_copied_addrinfo(aip); 1006 } else { 1007 /* 1008 * It was allocated the original getaddrinfo(). 1009 */ 1010 REAL(freeaddrinfo)(aip); 1011 } 1012} 1013#endif 1014 1015#ifdef HAVE_GETNAMEINFO 1016int 1017ENTRY(getnameinfo)(const struct sockaddr *sa, GNI_SALEN_T salen, 1018 char *host, GNI_HOSTLEN_T hostlen, char *serv, 1019 GNI_SERVLEN_T servlen, GNI_FLAGS_T flags) 1020{ 1021 char name[IDN_NAME_SIZE]; 1022 size_t namelen = sizeof(name); 1023 int code; 1024 idn_result_t r; 1025 1026 if (host == NULL || hostlen == 0 || idn_isprocessing) { 1027 return (REAL(getnameinfo)(sa, salen, host, hostlen, 1028 serv, servlen, flags)); 1029 } 1030 1031 TRACE(("getnameinfo(hostlen=%u)\n", hostlen)); 1032 1033 idn_isprocessing = 1; 1034 code = REAL(getnameinfo)(sa, salen, name, namelen, 1035 serv, servlen, flags); 1036 if (code == 0 && name[0] != '\0') { 1037 idn_enable(1); 1038 idn_nameinit(1); 1039 r = idn_decodename(IDN_DECODE_APP, name, host, hostlen); 1040 switch (r) { 1041 case idn_success: 1042 code = 0; 1043 break; 1044 case idn_buffer_overflow: 1045 case idn_nomemory: 1046 code = EAI_MEMORY; 1047 break; 1048 default: 1049 code = EAI_FAIL; 1050 break; 1051 } 1052 } 1053 idn_isprocessing = 0; 1054 return (code); 1055} 1056#endif 1057