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