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 httpAddrConnect@ and the 62 * listen address for sockets created with @link httpAddrListen@. This will 63 * ensure 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 * Returns @code NULL@ if the socket is currently unconnected. 652 * 653 * @since CUPS 2.0/OS 10.10@ 654 */ 655 656 http_addr_t * /* O - Connected address or @code NULL@ */ 657 httpGetAddress(http_t *http) /* I - HTTP connection */ 658 { 659 if (http) 660 return (http->hostaddr); 661 else 662 return (NULL); 663 } 664 665 666 /* 667 * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return 668 * address records for the specified name. 669 * 670 * @deprecated@ 671 */ 672 673 struct hostent * /* O - Host entry */ 674 httpGetHostByName(const char *name) /* I - Hostname or IP address */ 675 { 676 const char *nameptr; /* Pointer into name */ 677 unsigned ip[4]; /* IP address components */ 678 _cups_globals_t *cg = _cupsGlobals(); 679 /* Pointer to library globals */ 680 681 682 DEBUG_printf(("httpGetHostByName(name=\"%s\")", name)); 683 684 /* 685 * Avoid lookup delays and configuration problems when connecting 686 * to the localhost address... 687 */ 688 689 if (!strcmp(name, "localhost")) 690 name = "127.0.0.1"; 691 692 /* 693 * This function is needed because some operating systems have a 694 * buggy implementation of gethostbyname() that does not support 695 * IP addresses. If the first character of the name string is a 696 * number, then sscanf() is used to extract the IP components. 697 * We then pack the components into an IPv4 address manually, 698 * since the inet_aton() function is deprecated. We use the 699 * htonl() macro to get the right byte order for the address. 700 * 701 * We also support domain sockets when supported by the underlying 702 * OS... 703 */ 704 705 #ifdef AF_LOCAL 706 if (name[0] == '/') 707 { 708 /* 709 * A domain socket address, so make an AF_LOCAL entry and return it... 710 */ 711 712 cg->hostent.h_name = (char *)name; 713 cg->hostent.h_aliases = NULL; 714 cg->hostent.h_addrtype = AF_LOCAL; 715 cg->hostent.h_length = (int)strlen(name) + 1; 716 cg->hostent.h_addr_list = cg->ip_ptrs; 717 cg->ip_ptrs[0] = (char *)name; 718 cg->ip_ptrs[1] = NULL; 719 720 DEBUG_puts("1httpGetHostByName: returning domain socket address..."); 721 722 return (&cg->hostent); 723 } 724 #endif /* AF_LOCAL */ 725 726 for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++); 727 728 if (!*nameptr) 729 { 730 /* 731 * We have an IPv4 address; break it up and provide the host entry 732 * to the caller. 733 */ 734 735 if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4) 736 return (NULL); /* Must have 4 numbers */ 737 738 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255) 739 return (NULL); /* Invalid byte ranges! */ 740 741 cg->ip_addr = htonl((((((((unsigned)ip[0] << 8) | (unsigned)ip[1]) << 8) | 742 (unsigned)ip[2]) << 8) | 743 (unsigned)ip[3])); 744 745 /* 746 * Fill in the host entry and return it... 747 */ 748 749 cg->hostent.h_name = (char *)name; 750 cg->hostent.h_aliases = NULL; 751 cg->hostent.h_addrtype = AF_INET; 752 cg->hostent.h_length = 4; 753 cg->hostent.h_addr_list = cg->ip_ptrs; 754 cg->ip_ptrs[0] = (char *)&(cg->ip_addr); 755 cg->ip_ptrs[1] = NULL; 756 757 DEBUG_puts("1httpGetHostByName: returning IPv4 address..."); 758 759 return (&cg->hostent); 760 } 761 else 762 { 763 /* 764 * Use the gethostbyname() function to get the IPv4 address for 765 * the name... 766 */ 767 768 DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)..."); 769 770 return (gethostbyname(name)); 771 } 772 } 773 774 775 /* 776 * 'httpGetHostname()' - Get the FQDN for the connection or local system. 777 * 778 * When "http" points to a connected socket, return the hostname or 779 * address that was used in the call to httpConnect() or httpConnectEncrypt(), 780 * or the address of the client for the connection from httpAcceptConnection(). 781 * Otherwise, return the FQDN for the local system using both gethostname() 782 * and gethostbyname() to get the local hostname with domain. 783 * 784 * @since CUPS 1.2/macOS 10.5@ 785 */ 786 787 const char * /* O - FQDN for connection or system */ 788 httpGetHostname(http_t *http, /* I - HTTP connection or NULL */ 789 char *s, /* I - String buffer for name */ 790 int slen) /* I - Size of buffer */ 791 { 792 if (http) 793 { 794 if (!s || slen <= 1) 795 { 796 if (http->hostname[0] == '/') 797 return ("localhost"); 798 else 799 return (http->hostname); 800 } 801 else if (http->hostname[0] == '/') 802 strlcpy(s, "localhost", (size_t)slen); 803 else 804 strlcpy(s, http->hostname, (size_t)slen); 805 } 806 else 807 { 808 /* 809 * Get the hostname... 810 */ 811 812 if (!s || slen <= 1) 813 return (NULL); 814 815 if (gethostname(s, (size_t)slen) < 0) 816 strlcpy(s, "localhost", (size_t)slen); 817 818 if (!strchr(s, '.')) 819 { 820 #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME 821 /* 822 * The hostname is not a FQDN, so use the local hostname from the 823 * SystemConfiguration framework... 824 */ 825 826 SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault, 827 CFSTR("libcups"), NULL, NULL); 828 /* System configuration data */ 829 CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL; 830 /* Local host name */ 831 char localStr[1024]; /* Local host name C string */ 832 833 if (local && CFStringGetCString(local, localStr, sizeof(localStr), 834 kCFStringEncodingUTF8)) 835 { 836 /* 837 * Append ".local." to the hostname we get... 838 */ 839 840 snprintf(s, (size_t)slen, "%s.local.", localStr); 841 } 842 843 if (local) 844 CFRelease(local); 845 if (sc) 846 CFRelease(sc); 847 848 #else 849 /* 850 * The hostname is not a FQDN, so look it up... 851 */ 852 853 struct hostent *host; /* Host entry to get FQDN */ 854 855 if ((host = gethostbyname(s)) != NULL && host->h_name) 856 { 857 /* 858 * Use the resolved hostname... 859 */ 860 861 strlcpy(s, host->h_name, (size_t)slen); 862 } 863 #endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */ 864 } 865 866 /* 867 * Make sure .local hostnames end with a period... 868 */ 869 870 if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local")) 871 strlcat(s, ".", (size_t)slen); 872 } 873 874 /* 875 * Convert the hostname to lowercase as needed... 876 */ 877 878 if (s[0] != '/') 879 { 880 char *ptr; /* Pointer into string */ 881 882 for (ptr = s; *ptr; ptr ++) 883 *ptr = (char)_cups_tolower((int)*ptr); 884 } 885 886 /* 887 * Return the hostname with as much domain info as we have... 888 */ 889 890 return (s); 891 } 892 893 894 /* 895 * 'httpResolveHostname()' - Resolve the hostname of the HTTP connection 896 * address. 897 * 898 * @since CUPS 2.0/OS 10.10@ 899 */ 900 901 const char * /* O - Resolved hostname or @code NULL@ */ 902 httpResolveHostname(http_t *http, /* I - HTTP connection */ 903 char *buffer, /* I - Hostname buffer */ 904 size_t bufsize) /* I - Size of buffer */ 905 { 906 if (!http) 907 return (NULL); 908 909 if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[') 910 { 911 char temp[1024]; /* Temporary string */ 912 913 if (httpAddrLookup(http->hostaddr, temp, sizeof(temp))) 914 strlcpy(http->hostname, temp, sizeof(http->hostname)); 915 else 916 return (NULL); 917 } 918 919 if (buffer) 920 { 921 if (http->hostname[0] == '/') 922 strlcpy(buffer, "localhost", bufsize); 923 else 924 strlcpy(buffer, http->hostname, bufsize); 925 926 return (buffer); 927 } 928 else if (http->hostname[0] == '/') 929 return ("localhost"); 930 else 931 return (http->hostname); 932 } 933