Coverage Report

Created: 2025-12-14 06:53

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