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