1/* 2 * "$Id: http-addr.c 12131 2014-08-28 23:38:16Z msweet $" 3 * 4 * HTTP address routines for CUPS. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 1997-2006 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * This file is subject to the Apple OS-Developed Software exception. 16 */ 17 18/* 19 * Include necessary headers... 20 */ 21 22#include "cups-private.h" 23#include <sys/stat.h> 24#ifdef HAVE_RESOLV_H 25# include <resolv.h> 26#endif /* HAVE_RESOLV_H */ 27#ifdef __APPLE__ 28# include <CoreFoundation/CoreFoundation.h> 29# include <SystemConfiguration/SystemConfiguration.h> 30#endif /* __APPLE__ */ 31 32 33/* 34 * 'httpAddrAny()' - Check for the "any" address. 35 * 36 * @since CUPS 1.2/OS X 10.5@ 37 */ 38 39int /* O - 1 if "any", 0 otherwise */ 40httpAddrAny(const http_addr_t *addr) /* I - Address to check */ 41{ 42 if (!addr) 43 return (0); 44 45#ifdef AF_INET6 46 if (addr->addr.sa_family == AF_INET6 && 47 IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr))) 48 return (1); 49#endif /* AF_INET6 */ 50 51 if (addr->addr.sa_family == AF_INET && 52 ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000) 53 return (1); 54 55 return (0); 56} 57 58 59/* 60 * 'httpAddrClose()' - Close a socket created by @link httpAddrConnect@ or 61 * @link httpAddrListen@. 62 * 63 * Pass @code NULL@ for sockets created with @link httpAddrConnect@ and the 64 * listen address for sockets created with @link httpAddrListen@. This will 65 * ensure that domain sockets are removed when closed. 66 * 67 * @since CUPS 2.0/OS 10.10@ 68 */ 69 70int /* O - 0 on success, -1 on failure */ 71httpAddrClose(http_addr_t *addr, /* I - Listen address or @code NULL@ */ 72 int fd) /* I - Socket file descriptor */ 73{ 74#ifdef WIN32 75 if (closesocket(fd)) 76#else 77 if (close(fd)) 78#endif /* WIN32 */ 79 return (-1); 80 81#ifdef AF_LOCAL 82 if (addr && addr->addr.sa_family == AF_LOCAL) 83 return (unlink(addr->un.sun_path)); 84#endif /* AF_LOCAL */ 85 86 return (0); 87} 88 89 90/* 91 * 'httpAddrEqual()' - Compare two addresses. 92 * 93 * @since CUPS 1.2/OS X 10.5@ 94 */ 95 96int /* O - 1 if equal, 0 if not */ 97httpAddrEqual(const http_addr_t *addr1, /* I - First address */ 98 const http_addr_t *addr2) /* I - Second address */ 99{ 100 if (!addr1 && !addr2) 101 return (1); 102 103 if (!addr1 || !addr2) 104 return (0); 105 106 if (addr1->addr.sa_family != addr2->addr.sa_family) 107 return (0); 108 109#ifdef AF_LOCAL 110 if (addr1->addr.sa_family == AF_LOCAL) 111 return (!strcmp(addr1->un.sun_path, addr2->un.sun_path)); 112#endif /* AF_LOCAL */ 113 114#ifdef AF_INET6 115 if (addr1->addr.sa_family == AF_INET6) 116 return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16)); 117#endif /* AF_INET6 */ 118 119 return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr); 120} 121 122 123/* 124 * 'httpAddrLength()' - Return the length of the address in bytes. 125 * 126 * @since CUPS 1.2/OS X 10.5@ 127 */ 128 129int /* O - Length in bytes */ 130httpAddrLength(const http_addr_t *addr) /* I - Address */ 131{ 132 if (!addr) 133 return (0); 134 135#ifdef AF_INET6 136 if (addr->addr.sa_family == AF_INET6) 137 return (sizeof(addr->ipv6)); 138 else 139#endif /* AF_INET6 */ 140#ifdef AF_LOCAL 141 if (addr->addr.sa_family == AF_LOCAL) 142 return ((int)(offsetof(struct sockaddr_un, sun_path) + strlen(addr->un.sun_path) + 1)); 143 else 144#endif /* AF_LOCAL */ 145 if (addr->addr.sa_family == AF_INET) 146 return (sizeof(addr->ipv4)); 147 else 148 return (0); 149 150} 151 152 153/* 154 * 'httpAddrListen()' - Create a listening socket bound to the specified 155 * address and port. 156 * 157 * @since CUPS 1.7/OS X 10.9@ 158 */ 159 160int /* O - Socket or -1 on error */ 161httpAddrListen(http_addr_t *addr, /* I - Address to bind to */ 162 int port) /* I - Port number to bind to */ 163{ 164 int fd = -1, /* Socket */ 165 val, /* Socket value */ 166 status; /* Bind status */ 167 168 169 /* 170 * Range check input... 171 */ 172 173 if (!addr || port < 0) 174 return (-1); 175 176 /* 177 * Create the socket and set options... 178 */ 179 180 if ((fd = socket(addr->addr.sa_family, SOCK_STREAM, 0)) < 0) 181 { 182 _cupsSetHTTPError(HTTP_STATUS_ERROR); 183 return (-1); 184 } 185 186 val = 1; 187 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val)); 188 189#ifdef IPV6_V6ONLY 190 if (addr->addr.sa_family == AF_INET6) 191 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, CUPS_SOCAST &val, sizeof(val)); 192#endif /* IPV6_V6ONLY */ 193 194 /* 195 * Bind the socket... 196 */ 197 198#ifdef AF_LOCAL 199 if (addr->addr.sa_family == AF_LOCAL) 200 { 201 mode_t mask; /* Umask setting */ 202 203 /* 204 * Remove any existing domain socket file... 205 */ 206 207 unlink(addr->un.sun_path); 208 209 /* 210 * Save the current umask and set it to 0 so that all users can access 211 * the domain socket... 212 */ 213 214 mask = umask(0); 215 216 /* 217 * Bind the domain socket... 218 */ 219 220 status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr)); 221 222 /* 223 * Restore the umask and fix permissions... 224 */ 225 226 umask(mask); 227 chmod(addr->un.sun_path, 0140777); 228 } 229 else 230#endif /* AF_LOCAL */ 231 { 232 _httpAddrSetPort(addr, port); 233 234 status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr)); 235 } 236 237 if (status) 238 { 239 _cupsSetHTTPError(HTTP_STATUS_ERROR); 240 241 close(fd); 242 243 return (-1); 244 } 245 246 /* 247 * Listen... 248 */ 249 250 if (listen(fd, 5)) 251 { 252 _cupsSetHTTPError(HTTP_STATUS_ERROR); 253 254 close(fd); 255 256 return (-1); 257 } 258 259 /* 260 * Close on exec... 261 */ 262 263#ifndef WIN32 264 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 265#endif /* !WIN32 */ 266 267#ifdef SO_NOSIGPIPE 268 /* 269 * Disable SIGPIPE for this socket. 270 */ 271 272 val = 1; 273 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); 274#endif /* SO_NOSIGPIPE */ 275 276 return (fd); 277} 278 279 280/* 281 * 'httpAddrLocalhost()' - Check for the local loopback address. 282 * 283 * @since CUPS 1.2/OS X 10.5@ 284 */ 285 286int /* O - 1 if local host, 0 otherwise */ 287httpAddrLocalhost( 288 const http_addr_t *addr) /* I - Address to check */ 289{ 290 if (!addr) 291 return (1); 292 293#ifdef AF_INET6 294 if (addr->addr.sa_family == AF_INET6 && 295 IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr))) 296 return (1); 297#endif /* AF_INET6 */ 298 299#ifdef AF_LOCAL 300 if (addr->addr.sa_family == AF_LOCAL) 301 return (1); 302#endif /* AF_LOCAL */ 303 304 if (addr->addr.sa_family == AF_INET && 305 (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000) 306 return (1); 307 308 return (0); 309} 310 311 312/* 313 * 'httpAddrLookup()' - Lookup the hostname associated with the address. 314 * 315 * @since CUPS 1.2/OS X 10.5@ 316 */ 317 318char * /* O - Host name */ 319httpAddrLookup( 320 const http_addr_t *addr, /* I - Address to lookup */ 321 char *name, /* I - Host name buffer */ 322 int namelen) /* I - Size of name buffer */ 323{ 324 _cups_globals_t *cg = _cupsGlobals(); 325 /* Global data */ 326 327 328 DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)", addr, name, 329 namelen)); 330 331 /* 332 * Range check input... 333 */ 334 335 if (!addr || !name || namelen <= 2) 336 { 337 if (name && namelen >= 1) 338 *name = '\0'; 339 340 return (NULL); 341 } 342 343#ifdef AF_LOCAL 344 if (addr->addr.sa_family == AF_LOCAL) 345 { 346 strlcpy(name, addr->un.sun_path, (size_t)namelen); 347 return (name); 348 } 349#endif /* AF_LOCAL */ 350 351 /* 352 * Optimize lookups for localhost/loopback addresses... 353 */ 354 355 if (httpAddrLocalhost(addr)) 356 { 357 strlcpy(name, "localhost", (size_t)namelen); 358 return (name); 359 } 360 361#ifdef HAVE_RES_INIT 362 /* 363 * STR #2920: Initialize resolver after failure in cups-polld 364 * 365 * If the previous lookup failed, re-initialize the resolver to prevent 366 * temporary network errors from persisting. This *should* be handled by 367 * the resolver libraries, but apparently the glibc folks do not agree. 368 * 369 * We set a flag at the end of this function if we encounter an error that 370 * requires reinitialization of the resolver functions. We then call 371 * res_init() if the flag is set on the next call here or in httpAddrLookup(). 372 */ 373 374 if (cg->need_res_init) 375 { 376 res_init(); 377 378 cg->need_res_init = 0; 379 } 380#endif /* HAVE_RES_INIT */ 381 382#ifdef HAVE_GETNAMEINFO 383 { 384 /* 385 * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN 386 * 387 * FWIW, I think this is really a bug in the implementation of 388 * getnameinfo(), but falling back on httpAddrString() is easy to 389 * do... 390 */ 391 392 int error = getnameinfo(&addr->addr, (socklen_t)httpAddrLength(addr), name, (socklen_t)namelen, NULL, 0, 0); 393 394 if (error) 395 { 396 if (error == EAI_FAIL) 397 cg->need_res_init = 1; 398 399 return (httpAddrString(addr, name, namelen)); 400 } 401 } 402#else 403 { 404 struct hostent *host; /* Host from name service */ 405 406 407# ifdef AF_INET6 408 if (addr->addr.sa_family == AF_INET6) 409 host = gethostbyaddr((char *)&(addr->ipv6.sin6_addr), 410 sizeof(struct in_addr), AF_INET6); 411 else 412# endif /* AF_INET6 */ 413 host = gethostbyaddr((char *)&(addr->ipv4.sin_addr), 414 sizeof(struct in_addr), AF_INET); 415 416 if (host == NULL) 417 { 418 /* 419 * No hostname, so return the raw address... 420 */ 421 422 if (h_errno == NO_RECOVERY) 423 cg->need_res_init = 1; 424 425 return (httpAddrString(addr, name, namelen)); 426 } 427 428 strlcpy(name, host->h_name, (size_t)namelen); 429 } 430#endif /* HAVE_GETNAMEINFO */ 431 432 DEBUG_printf(("1httpAddrLookup: returning \"%s\"...", name)); 433 434 return (name); 435} 436 437 438/* 439 * 'httpAddrFamily()' - Get the address family of an address. 440 */ 441 442int /* O - Address family */ 443httpAddrFamily(http_addr_t *addr) /* I - Address */ 444{ 445 if (addr) 446 return (addr->addr.sa_family); 447 else 448 return (0); 449} 450 451 452/* 453 * 'httpAddrPort()' - Get the port number associated with an address. 454 * 455 * @since CUPS 1.7/OS X 10.9@ 456 */ 457 458int /* O - Port number */ 459httpAddrPort(http_addr_t *addr) /* I - Address */ 460{ 461 if (!addr) 462 return (-1); 463#ifdef AF_INET6 464 else if (addr->addr.sa_family == AF_INET6) 465 return (ntohs(addr->ipv6.sin6_port)); 466#endif /* AF_INET6 */ 467 else if (addr->addr.sa_family == AF_INET) 468 return (ntohs(addr->ipv4.sin_port)); 469 else 470 return (0); 471} 472 473 474/* 475 * '_httpAddrSetPort()' - Set the port number associated with an address. 476 */ 477 478void 479_httpAddrSetPort(http_addr_t *addr, /* I - Address */ 480 int port) /* I - Port */ 481{ 482 if (!addr || port <= 0) 483 return; 484 485#ifdef AF_INET6 486 if (addr->addr.sa_family == AF_INET6) 487 addr->ipv6.sin6_port = htons(port); 488 else 489#endif /* AF_INET6 */ 490 if (addr->addr.sa_family == AF_INET) 491 addr->ipv4.sin_port = htons(port); 492} 493 494 495/* 496 * 'httpAddrString()' - Convert an address to a numeric string. 497 * 498 * @since CUPS 1.2/OS X 10.5@ 499 */ 500 501char * /* O - Numeric address string */ 502httpAddrString(const http_addr_t *addr, /* I - Address to convert */ 503 char *s, /* I - String buffer */ 504 int slen) /* I - Length of string */ 505{ 506 DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)", addr, s, slen)); 507 508 /* 509 * Range check input... 510 */ 511 512 if (!addr || !s || slen <= 2) 513 { 514 if (s && slen >= 1) 515 *s = '\0'; 516 517 return (NULL); 518 } 519 520#ifdef AF_LOCAL 521 if (addr->addr.sa_family == AF_LOCAL) 522 { 523 if (addr->un.sun_path[0] == '/') 524 strlcpy(s, addr->un.sun_path, (size_t)slen); 525 else 526 strlcpy(s, "localhost", (size_t)slen); 527 } 528 else 529#endif /* AF_LOCAL */ 530 if (addr->addr.sa_family == AF_INET) 531 { 532 unsigned temp; /* Temporary address */ 533 534 temp = ntohl(addr->ipv4.sin_addr.s_addr); 535 536 snprintf(s, (size_t)slen, "%d.%d.%d.%d", (temp >> 24) & 255, 537 (temp >> 16) & 255, (temp >> 8) & 255, temp & 255); 538 } 539#ifdef AF_INET6 540 else if (addr->addr.sa_family == AF_INET6) 541 { 542 char *sptr, /* Pointer into string */ 543 temps[64]; /* Temporary string for address */ 544 545# ifdef HAVE_GETNAMEINFO 546 if (getnameinfo(&addr->addr, (socklen_t)httpAddrLength(addr), temps, sizeof(temps), NULL, 0, NI_NUMERICHOST)) 547 { 548 /* 549 * If we get an error back, then the address type is not supported 550 * and we should zero out the buffer... 551 */ 552 553 s[0] = '\0'; 554 555 return (NULL); 556 } 557 else if ((sptr = strchr(temps, '%')) != NULL) 558 { 559 /* 560 * Convert "%zone" to "+zone" to match URI form... 561 */ 562 563 *sptr = '+'; 564 } 565 566# else 567 int i; /* Looping var */ 568 unsigned temp; /* Current value */ 569 const char *prefix; /* Prefix for address */ 570 571 572 prefix = ""; 573 for (sptr = temps, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++) 574 { 575 temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]); 576 577 snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, (temp >> 16) & 0xffff); 578 prefix = ":"; 579 sptr += strlen(sptr); 580 581 temp &= 0xffff; 582 583 if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1]) 584 { 585 snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, temp); 586 sptr += strlen(sptr); 587 } 588 } 589 590 if (i < 4) 591 { 592 while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i]) 593 i ++; 594 595 if (i < 4) 596 { 597 snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s:", prefix); 598 prefix = ":"; 599 sptr += strlen(sptr); 600 601 for (; i < 4; i ++) 602 { 603 temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]); 604 605 if ((temp & 0xffff0000) || 606 (i > 0 && addr->ipv6.sin6_addr.s6_addr32[i - 1])) 607 { 608 snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, (temp >> 16) & 0xffff); 609 sptr += strlen(sptr); 610 } 611 612 snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, temp & 0xffff); 613 sptr += strlen(sptr); 614 } 615 } 616 else if (sptr == s) 617 { 618 /* 619 * Empty address... 620 */ 621 622 strlcpy(temps, "::", sizeof(temps)); 623 } 624 else 625 { 626 /* 627 * Empty at end... 628 */ 629 630 strlcpy(sptr, "::", sizeof(temps) - (size_t)(sptr - temps)); 631 } 632 } 633# endif /* HAVE_GETNAMEINFO */ 634 635 /* 636 * Add "[v1." and "]" around IPv6 address to convert to URI form. 637 */ 638 639 snprintf(s, (size_t)slen, "[v1.%s]", temps); 640 } 641#endif /* AF_INET6 */ 642 else 643 strlcpy(s, "UNKNOWN", (size_t)slen); 644 645 DEBUG_printf(("1httpAddrString: returning \"%s\"...", s)); 646 647 return (s); 648} 649 650 651/* 652 * 'httpGetAddress()' - Get the address of the connected peer of a connection. 653 * 654 * Returns @code NULL@ if the socket is currently unconnected. 655 * 656 * @since CUPS 2.0/OS 10.10@ 657 */ 658 659http_addr_t * /* O - Connected address or @code NULL@ */ 660httpGetAddress(http_t *http) /* I - HTTP connection */ 661{ 662 if (http) 663 return (http->hostaddr); 664 else 665 return (NULL); 666} 667 668 669/* 670 * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return 671 * address records for the specified name. 672 * 673 * @deprecated@ 674 */ 675 676struct hostent * /* O - Host entry */ 677httpGetHostByName(const char *name) /* I - Hostname or IP address */ 678{ 679 const char *nameptr; /* Pointer into name */ 680 unsigned ip[4]; /* IP address components */ 681 _cups_globals_t *cg = _cupsGlobals(); 682 /* Pointer to library globals */ 683 684 685 DEBUG_printf(("httpGetHostByName(name=\"%s\")", name)); 686 687 /* 688 * Avoid lookup delays and configuration problems when connecting 689 * to the localhost address... 690 */ 691 692 if (!strcmp(name, "localhost")) 693 name = "127.0.0.1"; 694 695 /* 696 * This function is needed because some operating systems have a 697 * buggy implementation of gethostbyname() that does not support 698 * IP addresses. If the first character of the name string is a 699 * number, then sscanf() is used to extract the IP components. 700 * We then pack the components into an IPv4 address manually, 701 * since the inet_aton() function is deprecated. We use the 702 * htonl() macro to get the right byte order for the address. 703 * 704 * We also support domain sockets when supported by the underlying 705 * OS... 706 */ 707 708#ifdef AF_LOCAL 709 if (name[0] == '/') 710 { 711 /* 712 * A domain socket address, so make an AF_LOCAL entry and return it... 713 */ 714 715 cg->hostent.h_name = (char *)name; 716 cg->hostent.h_aliases = NULL; 717 cg->hostent.h_addrtype = AF_LOCAL; 718 cg->hostent.h_length = (int)strlen(name) + 1; 719 cg->hostent.h_addr_list = cg->ip_ptrs; 720 cg->ip_ptrs[0] = (char *)name; 721 cg->ip_ptrs[1] = NULL; 722 723 DEBUG_puts("1httpGetHostByName: returning domain socket address..."); 724 725 return (&cg->hostent); 726 } 727#endif /* AF_LOCAL */ 728 729 for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++); 730 731 if (!*nameptr) 732 { 733 /* 734 * We have an IPv4 address; break it up and provide the host entry 735 * to the caller. 736 */ 737 738 if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4) 739 return (NULL); /* Must have 4 numbers */ 740 741 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255) 742 return (NULL); /* Invalid byte ranges! */ 743 744 cg->ip_addr = htonl((((((((unsigned)ip[0] << 8) | (unsigned)ip[1]) << 8) | 745 (unsigned)ip[2]) << 8) | 746 (unsigned)ip[3])); 747 748 /* 749 * Fill in the host entry and return it... 750 */ 751 752 cg->hostent.h_name = (char *)name; 753 cg->hostent.h_aliases = NULL; 754 cg->hostent.h_addrtype = AF_INET; 755 cg->hostent.h_length = 4; 756 cg->hostent.h_addr_list = cg->ip_ptrs; 757 cg->ip_ptrs[0] = (char *)&(cg->ip_addr); 758 cg->ip_ptrs[1] = NULL; 759 760 DEBUG_puts("1httpGetHostByName: returning IPv4 address..."); 761 762 return (&cg->hostent); 763 } 764 else 765 { 766 /* 767 * Use the gethostbyname() function to get the IPv4 address for 768 * the name... 769 */ 770 771 DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)..."); 772 773 return (gethostbyname(name)); 774 } 775} 776 777 778/* 779 * 'httpGetHostname()' - Get the FQDN for the connection or local system. 780 * 781 * When "http" points to a connected socket, return the hostname or 782 * address that was used in the call to httpConnect() or httpConnectEncrypt(), 783 * or the address of the client for the connection from httpAcceptConnection(). 784 * Otherwise, return the FQDN for the local system using both gethostname() 785 * and gethostbyname() to get the local hostname with domain. 786 * 787 * @since CUPS 1.2/OS X 10.5@ 788 */ 789 790const char * /* O - FQDN for connection or system */ 791httpGetHostname(http_t *http, /* I - HTTP connection or NULL */ 792 char *s, /* I - String buffer for name */ 793 int slen) /* I - Size of buffer */ 794{ 795 if (http) 796 { 797 if (!s || slen <= 1) 798 { 799 if (http->hostname[0] == '/') 800 return ("localhost"); 801 else 802 return (http->hostname); 803 } 804 else if (http->hostname[0] == '/') 805 strlcpy(s, "localhost", (size_t)slen); 806 else 807 strlcpy(s, http->hostname, (size_t)slen); 808 } 809 else 810 { 811 /* 812 * Get the hostname... 813 */ 814 815 if (!s || slen <= 1) 816 return (NULL); 817 818 if (gethostname(s, (size_t)slen) < 0) 819 strlcpy(s, "localhost", (size_t)slen); 820 821 if (!strchr(s, '.')) 822 { 823#ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME 824 /* 825 * The hostname is not a FQDN, so use the local hostname from the 826 * SystemConfiguration framework... 827 */ 828 829 SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault, 830 CFSTR("libcups"), NULL, NULL); 831 /* System configuration data */ 832 CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL; 833 /* Local host name */ 834 char localStr[1024]; /* Local host name C string */ 835 836 if (local && CFStringGetCString(local, localStr, sizeof(localStr), 837 kCFStringEncodingUTF8)) 838 { 839 /* 840 * Append ".local." to the hostname we get... 841 */ 842 843 snprintf(s, (size_t)slen, "%s.local.", localStr); 844 } 845 846 if (local) 847 CFRelease(local); 848 if (sc) 849 CFRelease(sc); 850 851#else 852 /* 853 * The hostname is not a FQDN, so look it up... 854 */ 855 856 struct hostent *host; /* Host entry to get FQDN */ 857 858 if ((host = gethostbyname(s)) != NULL && host->h_name) 859 { 860 /* 861 * Use the resolved hostname... 862 */ 863 864 strlcpy(s, host->h_name, (size_t)slen); 865 } 866#endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */ 867 } 868 869 /* 870 * Make sure .local hostnames end with a period... 871 */ 872 873 if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local")) 874 strlcat(s, ".", (size_t)slen); 875 } 876 877 /* 878 * Return the hostname with as much domain info as we have... 879 */ 880 881 return (s); 882} 883 884 885/* 886 * 'httpResolveHostname()' - Resolve the hostname of the HTTP connection 887 * address. 888 * 889 * @since CUPS 2.0/OS 10.10@ 890 */ 891 892const char * /* O - Resolved hostname or @code NULL@ */ 893httpResolveHostname(http_t *http, /* I - HTTP connection */ 894 char *buffer, /* I - Hostname buffer */ 895 size_t bufsize) /* I - Size of buffer */ 896{ 897 if (!http) 898 return (NULL); 899 900 if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[') 901 { 902 char temp[1024]; /* Temporary string */ 903 904 if (httpAddrLookup(http->hostaddr, temp, sizeof(temp))) 905 strlcpy(http->hostname, temp, sizeof(http->hostname)); 906 else 907 return (NULL); 908 } 909 910 if (buffer) 911 { 912 if (http->hostname[0] == '/') 913 strlcpy(buffer, "localhost", bufsize); 914 else 915 strlcpy(buffer, http->hostname, bufsize); 916 917 return (buffer); 918 } 919 else if (http->hostname[0] == '/') 920 return ("localhost"); 921 else 922 return (http->hostname); 923} 924 925 926/* 927 * End of "$Id: http-addr.c 12131 2014-08-28 23:38:16Z msweet $". 928 */ 929