Load cups into easysw/current.
[thirdparty/cups.git] / cups / http-addr.c
1 /*
2  * "$Id: http-addr.c 4806 2005-10-21 18:49:24Z mike $"
3  *
4  *   HTTP address routines for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
7  *
8  *   These coded instructions, statements, and computer programs are the
9  *   property of Easy Software Products and are protected by Federal
10  *   copyright law.  Distribution and use rights are outlined in the file
11  *   "LICENSE.txt" which should have been included with this file.  If this
12  *   file is missing or damaged please contact Easy Software Products
13  *   at:
14  *
15  *       Attn: CUPS Licensing Information
16  *       Easy Software Products
17  *       44141 Airport View Drive, Suite 204
18  *       Hollywood, Maryland 20636 USA
19  *
20  *       Voice: (301) 373-9600
21  *       EMail: cups-info@cups.org
22  *         WWW: http://www.cups.org
23  *
24  * Contents:
25  *
26  *   httpAddrAny()       - Check for the "any" address.
27  *   httpAddrEqual()     - Compare two addresses.
28  *   httpAddrLocalhost() - Check for the local loopback address.
29  *   httpAddrLookup()    - Lookup the hostname associated with the address.
30  *   httpAddrString()    - Convert an IP address to a dotted string.
31  *   httpGetHostByName() - Lookup a hostname or IP address, and return
32  *                         address records for the specified name.
33  *   httpGetHostname()   - Get the FQDN for the local system.
34  */
35
36 /*
37  * Include necessary headers...
38  */
39
40 #include "globals.h"
41 #include "debug.h"
42 #include <stdlib.h>
43 #include <stddef.h>
44
45
46 /*
47  * 'httpAddrAny()' - Check for the "any" address.
48  *
49  * @since CUPS 1.2@
50  */
51
52 int                                     /* O - 1 if "any", 0 otherwise */
53 httpAddrAny(const http_addr_t *addr)    /* I - Address to check */
54 {
55 #ifdef AF_INET6
56   if (addr->addr.sa_family == AF_INET6 &&
57       IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
58     return (1);
59 #endif /* AF_INET6 */
60
61   if (addr->addr.sa_family == AF_INET &&
62       ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
63     return (1);
64
65   return (0);
66 }
67
68
69 /*
70  * 'httpAddrEqual()' - Compare two addresses.
71  *
72  * @since CUPS 1.2@
73  */
74
75 int                                             /* O - 1 if equal, 0 if != */
76 httpAddrEqual(const http_addr_t *addr1,         /* I - First address */
77               const http_addr_t *addr2)         /* I - Second address */
78 {
79   if (addr1->addr.sa_family != addr2->addr.sa_family)
80     return (0);
81
82 #ifdef AF_LOCAL
83   if (addr1->addr.sa_family == AF_LOCAL)
84     return (!strcmp(addr1->un.sun_path, addr2->un.sun_path));
85 #endif /* AF_LOCAL */
86
87 #ifdef AF_INET6
88   if (addr1->addr.sa_family == AF_INET6)
89     return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16));
90 #endif /* AF_INET6 */
91
92   return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
93 }
94
95
96 /*
97  * 'httpAddrLength()' - Return the length of the address in bytes.
98  *
99  * @since CUPS 1.2@
100  */
101
102 int                                     /* O - Length in bytes */
103 httpAddrLength(const http_addr_t *addr) /* I - Address */
104 {
105 #ifdef AF_INET6
106   if (addr->addr.sa_family == AF_INET6)
107     return (sizeof(addr->ipv6));
108   else
109 #endif /* AF_INET6 */
110 #ifdef AF_LOCAL
111   if (addr->addr.sa_family == AF_LOCAL)
112     return (offsetof(struct sockaddr_un, sun_path) +
113             strlen(addr->un.sun_path) + 1);
114   else
115 #endif /* AF_LOCAL */
116   if (addr->addr.sa_family == AF_INET)
117     return (sizeof(addr->ipv4));
118   else
119     return (0);
120
121 }
122
123
124 /*
125  * 'httpAddrLocalhost()' - Check for the local loopback address.
126  *
127  * @since CUPS 1.2@
128  */
129
130 int                                     /* O - 1 if local host, 0 otherwise */
131 httpAddrLocalhost(
132     const http_addr_t *addr)            /* I - Address to check */
133 {
134 #ifdef AF_INET6
135   if (addr->addr.sa_family == AF_INET6 &&
136       (IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)) ||
137        IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr))))
138     return (1);
139 #endif /* AF_INET6 */
140
141 #ifdef AF_LOCAL
142   if (addr->addr.sa_family == AF_LOCAL)
143     return (1);
144 #endif /* AF_LOCAL */
145
146   if (addr->addr.sa_family == AF_INET &&
147       ntohl(addr->ipv4.sin_addr.s_addr) == 0x7f000001)
148     return (1);
149
150   return (0);
151 }
152
153
154 #ifdef __sgi
155 #  define ADDR_CAST (struct sockaddr *)
156 #else
157 #  define ADDR_CAST (char *)
158 #endif /* __sgi */
159
160
161 /*
162  * 'httpAddrLookup()' - Lookup the hostname associated with the address.
163  *
164  * @since CUPS 1.2@
165  */
166
167 char *                                          /* O - Host name */
168 httpAddrLookup(const http_addr_t *addr,         /* I - Address to lookup */
169                char              *name,         /* I - Host name buffer */
170                int               namelen)       /* I - Size of name buffer */
171 {
172   DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)\n",
173                 addr, name, namelen));
174
175  /*
176   * Range check input...
177   */
178
179   if (!addr || !name || namelen <= 2)
180   {
181     if (name && namelen >= 1)
182       *name = '\0';
183
184     return (NULL);
185   }
186
187 #ifdef AF_LOCAL
188   if (addr->addr.sa_family == AF_LOCAL)
189     strlcpy(name, addr->un.sun_path, namelen);
190   else
191 #endif /* AF_LOCAL */
192 #ifdef HAVE_GETNAMEINFO
193   {
194     char        servname[1024];                 /* Service name (not used) */
195
196
197     if (getnameinfo(&addr->addr, httpAddrLength(addr), name, namelen,
198                     servname, sizeof(servname), 0))
199     {
200      /*
201       * If we get an error back, then the address type is not supported
202       * and we should zero out the buffer...
203       */
204
205       name[0] = '\0';
206
207       return (NULL);
208     }
209   }
210 #else
211   {
212     struct hostent      *host;                  /* Host from name service */
213
214
215 #  ifdef AF_INET6
216     if (addr->addr.sa_family == AF_INET6)
217       host = gethostbyaddr(ADDR_CAST &(addr->ipv6.sin6_addr),
218                            sizeof(struct in_addr), AF_INET6);
219     else
220 #  endif /* AF_INET6 */
221     host = gethostbyaddr(ADDR_CAST &(addr->ipv4.sin_addr),
222                          sizeof(struct in_addr), AF_INET);
223
224     if (host == NULL)
225     {
226      /*
227       * No hostname, so return the raw address...
228       */
229
230       httpAddrString(addr, name, namelen);
231       return (NULL);
232     }
233
234     strlcpy(name, host->h_name, namelen);
235   }
236 #endif /* HAVE_GETNAMEINFO */
237
238   return (name);
239 }
240
241
242 /*
243  * 'httpAddrString()' - Convert an IP address to a dotted string.
244  *
245  * @since CUPS 1.2@
246  */
247
248 char *                                          /* O - IP string */
249 httpAddrString(const http_addr_t *addr,         /* I - Address to convert */
250                char              *s,            /* I - String buffer */
251                int               slen)          /* I - Length of string */
252 {
253   DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)\n",
254                 addr, s, slen));
255
256  /*
257   * Range check input...
258   */
259
260   if (!addr || !s || slen <= 2)
261   {
262     if (s && slen >= 1)
263       *s = '\0';
264
265     return (NULL);
266   }
267
268 #ifdef AF_LOCAL
269   if (addr->addr.sa_family == AF_LOCAL)
270     strlcpy(s, addr->un.sun_path, slen);
271   else
272 #endif /* AF_LOCAL */
273 #ifdef HAVE_GETNAMEINFO
274   {
275     char        servname[1024];         /* Service name (not used) */
276
277
278     if (getnameinfo(&addr->addr, httpAddrLength(addr), s, slen,
279                     servname, sizeof(servname), NI_NUMERICHOST))
280     {
281      /*
282       * If we get an error back, then the address type is not supported
283       * and we should zero out the buffer...
284       */
285
286       s[0] = '\0';
287
288       return (NULL);
289     }
290   }
291 #else
292   {
293 #ifdef AF_INET6
294     if (addr->addr.sa_family == AF_INET6)
295     {
296       char              *sptr;          /* Pointer into string */
297       int               i;              /* Looping var */
298       unsigned          temp;           /* Current value */
299       const char        *prefix;        /* Prefix for address */
300
301
302       prefix = "";
303       for (sptr = s, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++)
304       {
305         temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
306
307         snprintf(sptr, slen, "%s%x", prefix, (temp >> 16) & 0xffff);
308         prefix = ":";
309         slen -= strlen(sptr);
310         sptr += strlen(sptr);
311
312         temp &= 0xffff;
313
314         if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1])
315         {
316           snprintf(sptr, slen, "%s%x", prefix, temp);
317           slen -= strlen(sptr);
318           sptr += strlen(sptr);
319         }
320       }
321
322       if (i < 4)
323       {
324         while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i])
325           i ++;
326
327         if (i < 4)
328         {
329           snprintf(sptr, slen, "%s:", prefix);
330           prefix = ":";
331           slen -= strlen(sptr);
332           sptr += strlen(sptr);
333
334           for (; i < 4; i ++)
335           {
336             temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
337
338             if ((temp & 0xffff0000) || addr->ipv6.sin6_addr.s6_addr32[i - 1])
339             {
340               snprintf(sptr, slen, "%s%x", prefix, (temp >> 16) & 0xffff);
341               slen -= strlen(sptr);
342               sptr += strlen(sptr);
343             }
344
345             snprintf(sptr, slen, "%s%x", prefix, temp & 0xffff);
346             slen -= strlen(sptr);
347             sptr += strlen(sptr);
348           }
349         }
350         else if (sptr == s)
351         {
352          /*
353           * Empty address...
354           */
355
356           strlcpy(s, "::", slen);
357           sptr = s + 2;
358           slen -= 2;
359         }
360         else
361         {
362          /*
363           * Empty at end...
364           */
365
366           strlcpy(sptr, "::", slen);
367           sptr += 2;
368           slen -= 2;
369         }
370       }
371     }
372     else
373 #endif /* AF_INET6 */
374     if (addr->addr.sa_family == AF_INET)
375     {
376       unsigned temp;                            /* Temporary address */
377
378
379       temp = ntohl(addr->ipv4.sin_addr.s_addr);
380
381       snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
382                (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
383     }
384     else
385       strlcpy(s, "UNKNOWN", slen);
386   }
387 #endif /* HAVE_GETNAMEINFO */
388
389   DEBUG_printf(("httpAddrString: returning \"%s\"...\n", s));
390
391   return (s);
392 }
393
394
395 /*
396  * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
397  *                         address records for the specified name.
398  *
399  * @deprecated@
400  */
401
402 struct hostent *                        /* O - Host entry */
403 httpGetHostByName(const char *name)     /* I - Hostname or IP address */
404 {
405   const char            *nameptr;       /* Pointer into name */
406   unsigned              ip[4];          /* IP address components */
407   _cups_globals_t       *cg = _cupsGlobals();
408                                         /* Pointer to library globals */
409
410
411   DEBUG_printf(("httpGetHostByName(name=\"%s\")\n", name));
412
413  /*
414   * Avoid lookup delays and configuration problems when connecting
415   * to the localhost address...
416   */
417
418   if (!strcmp(name, "localhost"))
419     name = "127.0.0.1";
420
421  /*
422   * This function is needed because some operating systems have a
423   * buggy implementation of gethostbyname() that does not support
424   * IP addresses.  If the first character of the name string is a
425   * number, then sscanf() is used to extract the IP components.
426   * We then pack the components into an IPv4 address manually,
427   * since the inet_aton() function is deprecated.  We use the
428   * htonl() macro to get the right byte order for the address.
429   *
430   * We also support domain sockets when supported by the underlying
431   * OS...
432   */
433
434 #ifdef AF_LOCAL
435   if (name[0] == '/')
436   {
437    /*
438     * A domain socket address, so make an AF_LOCAL entry and return it...
439     */
440
441     cg->hostent.h_name      = (char *)name;
442     cg->hostent.h_aliases   = NULL;
443     cg->hostent.h_addrtype  = AF_LOCAL;
444     cg->hostent.h_length    = strlen(name) + 1;
445     cg->hostent.h_addr_list = cg->ip_ptrs;
446     cg->ip_ptrs[0]          = (char *)name;
447     cg->ip_ptrs[1]          = NULL;
448
449     DEBUG_puts("httpGetHostByName: returning domain socket address...");
450
451     return (&cg->hostent);
452   }
453 #endif /* AF_LOCAL */
454
455   for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
456
457   if (!*nameptr)
458   {
459    /*
460     * We have an IPv4 address; break it up and provide the host entry
461     * to the caller.
462     */
463
464     if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
465       return (NULL);                    /* Must have 4 numbers */
466
467     if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
468       return (NULL);                    /* Invalid byte ranges! */
469
470     cg->ip_addr = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) |
471                          ip[3]));
472
473    /*
474     * Fill in the host entry and return it...
475     */
476
477     cg->hostent.h_name      = (char *)name;
478     cg->hostent.h_aliases   = NULL;
479     cg->hostent.h_addrtype  = AF_INET;
480     cg->hostent.h_length    = 4;
481     cg->hostent.h_addr_list = cg->ip_ptrs;
482     cg->ip_ptrs[0]          = (char *)&(cg->ip_addr);
483     cg->ip_ptrs[1]          = NULL;
484
485     DEBUG_puts("httpGetHostByName: returning IPv4 address...");
486
487     return (&cg->hostent);
488   }
489   else
490   {
491    /*
492     * Use the gethostbyname() function to get the IPv4 address for
493     * the name...
494     */
495
496     DEBUG_puts("httpGetHostByName: returning domain lookup address(es)...");
497
498     return (gethostbyname(name));
499   }
500 }
501
502
503 /*
504  * 'httpGetHostname()' - Get the FQDN for the local system.
505  *
506  * This function uses both gethostname() and gethostbyname() to
507  * get the local hostname with domain.
508  *
509  * @since CUPS 1.2@
510  */
511
512 const char *                            /* O - FQDN for this system */
513 httpGetHostname(char *s,                /* I - String buffer for name */
514                 int  slen)              /* I - Size of buffer */
515 {
516   struct hostent        *host;          /* Host entry to get FQDN */
517
518
519  /*
520   * Get the hostname...
521   */
522
523   gethostname(s, slen);
524
525   if (!strchr(s, '.'))
526   {
527    /*
528     * The hostname is not a FQDN, so look it up...
529     */
530
531     if ((host = gethostbyname(s)) != NULL)
532       strlcpy(s, host->h_name, slen);
533   }
534
535  /*
536   * Return the hostname with as much domain info as we have...
537   */
538
539   return (s);
540 }
541
542
543 /*
544  * End of "$Id: http-addr.c 4806 2005-10-21 18:49:24Z mike $".
545  */