Revert manifest to default one
[external/cups.git] / cups / http-addr.c
1 /*
2  * "$Id: http-addr.c 9868 2011-08-06 04:53:00Z mike $"
3  *
4  *   HTTP address routines for CUPS.
5  *
6  *   Copyright 2007-2011 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  * Contents:
16  *
17  *   httpAddrAny()       - Check for the "any" address.
18  *   httpAddrEqual()     - Compare two addresses.
19  *   httpAddrLocalhost() - Check for the local loopback address.
20  *   httpAddrLookup()    - Lookup the hostname associated with the address.
21  *   _httpAddrPort()     - Get the port number associated with an address.
22  *   _httpAddrSetPort()  - Set the port number associated with an address.
23  *   httpAddrString()    - Convert an IP address to a dotted string.
24  *   httpGetHostByName() - Lookup a hostname or IP address, and return
25  *                         address records for the specified name.
26  *   httpGetHostname()   - Get the FQDN for the local system.
27  */
28
29 /*
30  * Include necessary headers...
31  */
32
33 #include "cups-private.h"
34 #ifdef HAVE_RESOLV_H
35 #  include <resolv.h>
36 #endif /* HAVE_RESOLV_H */
37 #ifdef HAVE_COREFOUNDATION
38 #  include <CoreFoundation/CoreFoundation.h>
39 #endif /* HAVE_COREFOUNDATION */
40 #ifdef HAVE_SYSTEMCONFIGURATION
41 #  include <SystemConfiguration/SystemConfiguration.h>
42 #endif /* HAVE_SYSTEMCONFIGURATION */
43
44
45 /*
46  * 'httpAddrAny()' - Check for the "any" address.
47  *
48  * @since CUPS 1.2/Mac OS X 10.5@
49  */
50
51 int                                     /* O - 1 if "any", 0 otherwise */
52 httpAddrAny(const http_addr_t *addr)    /* I - Address to check */
53 {
54   if (!addr)
55     return (0);
56
57 #ifdef AF_INET6
58   if (addr->addr.sa_family == AF_INET6 &&
59       IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
60     return (1);
61 #endif /* AF_INET6 */
62
63   if (addr->addr.sa_family == AF_INET &&
64       ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
65     return (1);
66
67   return (0);
68 }
69
70
71 /*
72  * 'httpAddrEqual()' - Compare two addresses.
73  *
74  * @since CUPS 1.2/Mac OS X 10.5@
75  */
76
77 int                                             /* O - 1 if equal, 0 if not */
78 httpAddrEqual(const http_addr_t *addr1,         /* I - First address */
79               const http_addr_t *addr2)         /* I - Second address */
80 {
81   if (!addr1 && !addr2)
82     return (1);
83
84   if (!addr1 || !addr2)
85     return (0);
86
87   if (addr1->addr.sa_family != addr2->addr.sa_family)
88     return (0);
89
90 #ifdef AF_LOCAL
91   if (addr1->addr.sa_family == AF_LOCAL)
92     return (!strcmp(addr1->un.sun_path, addr2->un.sun_path));
93 #endif /* AF_LOCAL */
94
95 #ifdef AF_INET6
96   if (addr1->addr.sa_family == AF_INET6)
97     return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16));
98 #endif /* AF_INET6 */
99
100   return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
101 }
102
103
104 /*
105  * 'httpAddrLength()' - Return the length of the address in bytes.
106  *
107  * @since CUPS 1.2/Mac OS X 10.5@
108  */
109
110 int                                     /* O - Length in bytes */
111 httpAddrLength(const http_addr_t *addr) /* I - Address */
112 {
113   if (!addr)
114     return (0);
115
116 #ifdef AF_INET6
117   if (addr->addr.sa_family == AF_INET6)
118     return (sizeof(addr->ipv6));
119   else
120 #endif /* AF_INET6 */
121 #ifdef AF_LOCAL
122   if (addr->addr.sa_family == AF_LOCAL)
123     return (offsetof(struct sockaddr_un, sun_path) +
124             strlen(addr->un.sun_path) + 1);
125   else
126 #endif /* AF_LOCAL */
127   if (addr->addr.sa_family == AF_INET)
128     return (sizeof(addr->ipv4));
129   else
130     return (0);
131
132 }
133
134
135 /*
136  * 'httpAddrLocalhost()' - Check for the local loopback address.
137  *
138  * @since CUPS 1.2/Mac OS X 10.5@
139  */
140
141 int                                     /* O - 1 if local host, 0 otherwise */
142 httpAddrLocalhost(
143     const http_addr_t *addr)            /* I - Address to check */
144 {
145   if (!addr)
146     return (1);
147
148 #ifdef AF_INET6
149   if (addr->addr.sa_family == AF_INET6 &&
150       IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)))
151     return (1);
152 #endif /* AF_INET6 */
153
154 #ifdef AF_LOCAL
155   if (addr->addr.sa_family == AF_LOCAL)
156     return (1);
157 #endif /* AF_LOCAL */
158
159   if (addr->addr.sa_family == AF_INET &&
160       (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000)
161     return (1);
162
163   return (0);
164 }
165
166
167 #ifdef __sgi
168 #  define ADDR_CAST (struct sockaddr *)
169 #else
170 #  define ADDR_CAST (char *)
171 #endif /* __sgi */
172
173
174 /*
175  * 'httpAddrLookup()' - Lookup the hostname associated with the address.
176  *
177  * @since CUPS 1.2/Mac OS X 10.5@
178  */
179
180 char *                                  /* O - Host name */
181 httpAddrLookup(
182     const http_addr_t *addr,            /* I - Address to lookup */
183     char              *name,            /* I - Host name buffer */
184     int               namelen)          /* I - Size of name buffer */
185 {
186   _cups_globals_t       *cg = _cupsGlobals();
187                                         /* Global data */
188
189
190   DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)", addr, name,
191                 namelen));
192
193  /*
194   * Range check input...
195   */
196
197   if (!addr || !name || namelen <= 2)
198   {
199     if (name && namelen >= 1)
200       *name = '\0';
201
202     return (NULL);
203   }
204
205 #ifdef AF_LOCAL
206   if (addr->addr.sa_family == AF_LOCAL)
207   {
208     strlcpy(name, addr->un.sun_path, namelen);
209     return (name);
210   }
211 #endif /* AF_LOCAL */
212
213  /*
214   * Optimize lookups for localhost/loopback addresses...
215   */
216
217   if (httpAddrLocalhost(addr))
218   {
219     strlcpy(name, "localhost", namelen);
220     return (name);
221   }
222
223 #ifdef HAVE_RES_INIT
224  /*
225   * STR #2920: Initialize resolver after failure in cups-polld
226   *
227   * If the previous lookup failed, re-initialize the resolver to prevent
228   * temporary network errors from persisting.  This *should* be handled by
229   * the resolver libraries, but apparently the glibc folks do not agree.
230   *
231   * We set a flag at the end of this function if we encounter an error that
232   * requires reinitialization of the resolver functions.  We then call
233   * res_init() if the flag is set on the next call here or in httpAddrLookup().
234   */
235
236   if (cg->need_res_init)
237   {
238     res_init();
239
240     cg->need_res_init = 0;
241   }
242 #endif /* HAVE_RES_INIT */
243
244 #ifdef HAVE_GETNAMEINFO
245   {
246    /*
247     * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN
248     *
249     * FWIW, I think this is really a bug in the implementation of
250     * getnameinfo(), but falling back on httpAddrString() is easy to
251     * do...
252     */
253
254     int error = getnameinfo(&addr->addr, httpAddrLength(addr), name, namelen,
255                             NULL, 0, 0);
256
257     if (error)
258     {
259       if (error == EAI_FAIL)
260         cg->need_res_init = 1;
261
262       return (httpAddrString(addr, name, namelen));
263     }
264   }
265 #else
266   {
267     struct hostent      *host;                  /* Host from name service */
268
269
270 #  ifdef AF_INET6
271     if (addr->addr.sa_family == AF_INET6)
272       host = gethostbyaddr(ADDR_CAST &(addr->ipv6.sin6_addr),
273                            sizeof(struct in_addr), AF_INET6);
274     else
275 #  endif /* AF_INET6 */
276     host = gethostbyaddr(ADDR_CAST &(addr->ipv4.sin_addr),
277                          sizeof(struct in_addr), AF_INET);
278
279     if (host == NULL)
280     {
281      /*
282       * No hostname, so return the raw address...
283       */
284
285       if (h_errno == NO_RECOVERY)
286         cg->need_res_init = 1;
287
288       return (httpAddrString(addr, name, namelen));
289     }
290
291     strlcpy(name, host->h_name, namelen);
292   }
293 #endif /* HAVE_GETNAMEINFO */
294
295   DEBUG_printf(("1httpAddrLookup: returning \"%s\"...", name));
296
297   return (name);
298 }
299
300
301 /*
302  * '_httpAddrPort()' - Get the port number associated with an address.
303  */
304
305 int                                     /* O - Port number */
306 _httpAddrPort(http_addr_t *addr)        /* I - Address */
307 {
308   if (!addr)
309     return (ippPort());
310 #ifdef AF_INET6
311   else if (addr->addr.sa_family == AF_INET6)
312     return (ntohs(addr->ipv6.sin6_port));
313 #endif /* AF_INET6 */
314   else if (addr->addr.sa_family == AF_INET)
315     return (ntohs(addr->ipv4.sin_port));
316   else
317     return (ippPort());
318 }
319
320
321 /*
322  * '_httpAddrSetPort()' - Set the port number associated with an address.
323  */
324
325 void
326 _httpAddrSetPort(http_addr_t *addr,     /* I - Address */
327                  int         port)      /* I - Port */
328 {
329   if (!addr || port <= 0)
330     return;
331
332 #ifdef AF_INET6
333   if (addr->addr.sa_family == AF_INET6)
334     addr->ipv6.sin6_port = htons(port);
335   else
336 #endif /* AF_INET6 */
337   if (addr->addr.sa_family == AF_INET)
338     addr->ipv4.sin_port = htons(port);
339 }
340
341
342 /*
343  * 'httpAddrString()' - Convert an address to a numeric string.
344  *
345  * @since CUPS 1.2/Mac OS X 10.5@
346  */
347
348 char *                                  /* O - Numeric address string */
349 httpAddrString(const http_addr_t *addr, /* I - Address to convert */
350                char              *s,    /* I - String buffer */
351                int               slen)  /* I - Length of string */
352 {
353   DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)", addr, s, slen));
354
355  /*
356   * Range check input...
357   */
358
359   if (!addr || !s || slen <= 2)
360   {
361     if (s && slen >= 1)
362       *s = '\0';
363
364     return (NULL);
365   }
366
367 #ifdef AF_LOCAL
368   if (addr->addr.sa_family == AF_LOCAL)
369   {
370     if (addr->un.sun_path[0] == '/')
371       strlcpy(s, addr->un.sun_path, slen);
372     else
373       strlcpy(s, "localhost", slen);
374   }
375   else
376 #endif /* AF_LOCAL */
377   if (addr->addr.sa_family == AF_INET)
378   {
379     unsigned temp;                      /* Temporary address */
380
381
382     temp = ntohl(addr->ipv4.sin_addr.s_addr);
383
384     snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
385              (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
386   }
387 #ifdef AF_INET6
388   else if (addr->addr.sa_family == AF_INET6)
389   {
390     char        *sptr,                  /* Pointer into string */
391                 temps[64];              /* Temporary string for address */
392
393 #  ifdef HAVE_GETNAMEINFO
394     if (getnameinfo(&addr->addr, httpAddrLength(addr), temps, sizeof(temps),
395                     NULL, 0, NI_NUMERICHOST))
396     {
397      /*
398       * If we get an error back, then the address type is not supported
399       * and we should zero out the buffer...
400       */
401
402       s[0] = '\0';
403
404       return (NULL);
405     }
406     else if ((sptr = strchr(temps, '%')) != NULL)
407     {
408      /*
409       * Convert "%zone" to "+zone" to match URI form...
410       */
411
412       *sptr = '+';
413     }
414
415 #  else
416     int         i;                      /* Looping var */
417     unsigned    temp;                   /* Current value */
418     const char  *prefix;                /* Prefix for address */
419
420
421     prefix = "";
422     for (sptr = temps, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++)
423     {
424       temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
425
426       snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
427                (temp >> 16) & 0xffff);
428       prefix = ":";
429       sptr += strlen(sptr);
430
431       temp &= 0xffff;
432
433       if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1])
434       {
435         snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix, temp);
436         sptr += strlen(sptr);
437       }
438     }
439
440     if (i < 4)
441     {
442       while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i])
443         i ++;
444
445       if (i < 4)
446       {
447         snprintf(sptr, sizeof(temps) - (sptr - temps), "%s:", prefix);
448         prefix = ":";
449         sptr += strlen(sptr);
450
451         for (; i < 4; i ++)
452         {
453           temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
454
455           if ((temp & 0xffff0000) ||
456               (i > 0 && addr->ipv6.sin6_addr.s6_addr32[i - 1]))
457           {
458             snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
459                      (temp >> 16) & 0xffff);
460             sptr += strlen(sptr);
461           }
462
463           snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
464                    temp & 0xffff);
465           sptr += strlen(sptr);
466         }
467       }
468       else if (sptr == s)
469       {
470        /*
471         * Empty address...
472         */
473
474         strlcpy(temps, "::", sizeof(temps));
475       }
476       else
477       {
478        /*
479         * Empty at end...
480         */
481
482         strlcpy(sptr, "::", sizeof(temps) - (sptr - temps));
483       }
484     }
485 #  endif /* HAVE_GETNAMEINFO */
486
487    /*
488     * Add "[v1." and "]" around IPv6 address to convert to URI form.
489     */
490
491     snprintf(s, slen, "[v1.%s]", temps);
492   }
493 #endif /* AF_INET6 */
494   else
495     strlcpy(s, "UNKNOWN", slen);
496
497   DEBUG_printf(("1httpAddrString: returning \"%s\"...", s));
498
499   return (s);
500 }
501
502
503 /*
504  * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
505  *                         address records for the specified name.
506  *
507  * @deprecated@
508  */
509
510 struct hostent *                        /* O - Host entry */
511 httpGetHostByName(const char *name)     /* I - Hostname or IP address */
512 {
513   const char            *nameptr;       /* Pointer into name */
514   unsigned              ip[4];          /* IP address components */
515   _cups_globals_t       *cg = _cupsGlobals();
516                                         /* Pointer to library globals */
517
518
519   DEBUG_printf(("httpGetHostByName(name=\"%s\")", name));
520
521  /*
522   * Avoid lookup delays and configuration problems when connecting
523   * to the localhost address...
524   */
525
526   if (!strcmp(name, "localhost"))
527     name = "127.0.0.1";
528
529  /*
530   * This function is needed because some operating systems have a
531   * buggy implementation of gethostbyname() that does not support
532   * IP addresses.  If the first character of the name string is a
533   * number, then sscanf() is used to extract the IP components.
534   * We then pack the components into an IPv4 address manually,
535   * since the inet_aton() function is deprecated.  We use the
536   * htonl() macro to get the right byte order for the address.
537   *
538   * We also support domain sockets when supported by the underlying
539   * OS...
540   */
541
542 #ifdef AF_LOCAL
543   if (name[0] == '/')
544   {
545    /*
546     * A domain socket address, so make an AF_LOCAL entry and return it...
547     */
548
549     cg->hostent.h_name      = (char *)name;
550     cg->hostent.h_aliases   = NULL;
551     cg->hostent.h_addrtype  = AF_LOCAL;
552     cg->hostent.h_length    = strlen(name) + 1;
553     cg->hostent.h_addr_list = cg->ip_ptrs;
554     cg->ip_ptrs[0]          = (char *)name;
555     cg->ip_ptrs[1]          = NULL;
556
557     DEBUG_puts("1httpGetHostByName: returning domain socket address...");
558
559     return (&cg->hostent);
560   }
561 #endif /* AF_LOCAL */
562
563   for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
564
565   if (!*nameptr)
566   {
567    /*
568     * We have an IPv4 address; break it up and provide the host entry
569     * to the caller.
570     */
571
572     if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
573       return (NULL);                    /* Must have 4 numbers */
574
575     if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
576       return (NULL);                    /* Invalid byte ranges! */
577
578     cg->ip_addr = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) |
579                          ip[3]));
580
581    /*
582     * Fill in the host entry and return it...
583     */
584
585     cg->hostent.h_name      = (char *)name;
586     cg->hostent.h_aliases   = NULL;
587     cg->hostent.h_addrtype  = AF_INET;
588     cg->hostent.h_length    = 4;
589     cg->hostent.h_addr_list = cg->ip_ptrs;
590     cg->ip_ptrs[0]          = (char *)&(cg->ip_addr);
591     cg->ip_ptrs[1]          = NULL;
592
593     DEBUG_puts("1httpGetHostByName: returning IPv4 address...");
594
595     return (&cg->hostent);
596   }
597   else
598   {
599    /*
600     * Use the gethostbyname() function to get the IPv4 address for
601     * the name...
602     */
603
604     DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)...");
605
606     return (gethostbyname(name));
607   }
608 }
609
610
611 /*
612  * 'httpGetHostname()' - Get the FQDN for the connection or local system.
613  *
614  * When "http" points to a connected socket, return the hostname or
615  * address that was used in the call to httpConnect() or httpConnectEncrypt().
616  * Otherwise, return the FQDN for the local system using both gethostname()
617  * and gethostbyname() to get the local hostname with domain.
618  *
619  * @since CUPS 1.2/Mac OS X 10.5@
620  */
621
622 const char *                            /* O - FQDN for connection or system */
623 httpGetHostname(http_t *http,           /* I - HTTP connection or NULL */
624                 char   *s,              /* I - String buffer for name */
625                 int    slen)            /* I - Size of buffer */
626 {
627   if (!s || slen <= 1)
628     return (NULL);
629
630   if (http)
631   {
632     if (http->hostname[0] == '/')
633       strlcpy(s, "localhost", slen);
634     else
635       strlcpy(s, http->hostname, slen);
636   }
637   else
638   {
639    /*
640     * Get the hostname...
641     */
642
643     if (gethostname(s, slen) < 0)
644       strlcpy(s, "localhost", slen);
645
646     if (!strchr(s, '.'))
647     {
648 #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME
649      /*
650       * The hostname is not a FQDN, so use the local hostname from the
651       * SystemConfiguration framework...
652       */
653
654       SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault,
655                                                   CFSTR("libcups"), NULL, NULL);
656                                         /* System configuration data */
657       CFStringRef       local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL;
658                                         /* Local host name */
659       char              localStr[1024]; /* Local host name C string */
660
661       if (local && CFStringGetCString(local, localStr, sizeof(localStr),
662                                       kCFStringEncodingUTF8))
663       {
664        /*
665         * Append ".local." to the hostname we get...
666         */
667
668         snprintf(s, slen, "%s.local.", localStr);
669       }
670
671       if (local)
672         CFRelease(local);
673       if (sc)
674         CFRelease(sc);
675
676 #else
677      /*
678       * The hostname is not a FQDN, so look it up...
679       */
680
681       struct hostent    *host;          /* Host entry to get FQDN */
682
683       if ((host = gethostbyname(s)) != NULL && host->h_name)
684       {
685        /*
686         * Use the resolved hostname...
687         */
688
689         strlcpy(s, host->h_name, slen);
690       }
691 #endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
692     }
693   }
694
695  /*
696   * Return the hostname with as much domain info as we have...
697   */
698
699   return (s);
700 }
701
702
703 /*
704  * End of "$Id: http-addr.c 9868 2011-08-06 04:53:00Z mike $".
705  */