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