CUPS may be vulnerable to DNS rebinding attacks #3118

Closed
michaelrsweet opened this Issue Mar 6, 2009 · 6 comments

1 participant

@michaelrsweet

Version: 1.3-current
CUPS.org User: mike

The web interface of CUPS 1.3.x and earlier may be vulnerable to DNS rebinding attacks. The attached patch provides HTTP Host header validation for incoming requests and support for the Apache ServerAlias directive to list additional allowed hostnames that are not automatically detected.

@michaelrsweet

CUPS.org User: mike

Issues brought up on vendor-sec list for the original patch:

  1. Need to add localhost.localdomain on Linux for valid loopback hostnames.
  2. The httpAddrLocalhost() API does not treat all 127.* addresses as the localhost/loopback address. On Linux, any 127.* address will connect on 127.0.0.1.
  3. Need a way to disable non-loopback checks to prevent breakage during an update - "ServerAlias *".
  4. The patch needs to include the HTML and man documentation updates for cupsd.conf.
@michaelrsweet

CUPS.org User: mike

Additional contextual information for this bug:

Since CUPS uses IPP and IPP is layered over HTTP, it can be vulnerable to web browser-based attacks that typically collect information from the local system such as job history, printers, and so forth. POST requests can also perform specific CUPS tasks, however an authentication dialog is displayed for these requests.

The changes in this bug address a specific type of web browser attack that uses DNS rebinding to redirect an attacker's hostname (foo.bar.com) to a local network address. Since CUPS always listens on the local loopback interface, the most common address to use is 127.0.0.1 or ::1.

The change adds mandatory blocking of loopback interface and domain socket accesses with Host: headers containing names other than "localhost", "localhost.localdomain", or the IETF-reserved numeric addresses for loopback.

The change also adds default blocking of network accesses for Host: headers containing names that are not registered with the local system or domain name server. A new ServerAlias directive is added to allow for manual configuration of the allowed names, with the name "*" effectively disabling the network access checks. The scheduler does try to collect all of the known aliases for the hostname of the system and any network interfaces.

With printer sharing turned off, this change should not create any regressions. When printer sharing is enabled, it is possible that some sites may need to use the ServerAlias directive to allow additional hostnames to be used.

@michaelrsweet

CUPS.org User: mike

Here is the updated patch...

@michaelrsweet

CUPS.org User: mike

Fixed in Subversion repository.

@michaelrsweet

"cups-1.3-rebind-v2.patch":

diff -ur cups-1.3.9/scheduler/client.c cups-1.3.9-rebind/scheduler/client.c
--- cups-1.3.9/scheduler/client.c 2008-09-16 17:42:56.000000000 -0700
+++ cups-1.3.9-rebind/scheduler/client.c 2009-02-06 12:06:18.000000000 -0800
@@ -102,6 +105,7 @@
#endif /* HAVE_SSL */
static int pipe_command(cupsd_client_t *con, int infile, int *outfile,
char *command, char *options, int root);
+static int valid_host(cupsd_client_t *con);
static int write_file(cupsd_client_t *con, http_status_t code,
char *filename, char *type,
struct stat *filestats);
@@ -261,16 +265,7 @@
* Map accesses from the same host to the server name.
*/

  • for (addr = ServerAddrs; addr; addr = addr->next)
  • if (httpAddrEqual(con->http.hostaddr, &(addr->addr)))

- break;

  • if (addr)
  • {
  • strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname));
  • hostname = con->http.hostname;
  • }
  • else if (HostNameLookups)
  • if (HostNameLookups) hostname = httpAddrLookup(con->http.hostaddr, con->http.hostname, sizeof(con->http.hostname)); else @@ -1078,6 +1073,23 @@ return; } }
  • else if (!valid_host(con))
  • {
  • /*
  • * Access to localhost must use "localhost" or the corresponding IPv4
  • * or IPv6 values in the Host: field.
  • */ +
  • cupsdLogMessage(CUPSD_LOG_WARN,
  • "Request from \"%s\" using invalid Host: field \"%s\"",
  • con->http.hostname, con->http.fields[HTTP_FIELD_HOST]); +
  • if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
  • {
  • cupsdCloseClient(con);
  • return;
  • }
  • }
    else if (con->operation == HTTP_OPTIONS)
    {
    /*
    @@ -4805,6 +4817,124 @@

    /*

  • * 'valid_host()' - Is the Host: field valid?
  • / + +static int / O - 1 if valid, 0 if not / +valid_host(cupsd_client_t *con) / I - Client connection */ +{
  • cupsd_alias_t a; / Current alias */
  • cupsd_netif_t netif; / Current network interface */
  • const char host, / Host field */
  • end; / End character */ + +
  • host = con->http.fields[HTTP_FIELD_HOST]; +
  • if (httpAddrLocalhost(con->http.hostaddr))
  • {
  • /*
  • * Only allow "localhost" or the equivalent IPv4 or IPv6 numerical
  • * addresses when accessing CUPS via the loopback interface...
  • */ +
  • return (!strcasecmp(host, "localhost") ||
  • !strncasecmp(host, "localhost:", 10) ||
  • !strcmp(host, "127.0.0.1") ||
  • !strncmp(host, "127.0.0.1:", 10) ||
  • !strcmp(host, "[::1]") ||
  • !strncmp(host, "[::1]:", 6));
  • } + +#ifdef HAVE_DNSSD
  • /*
  • * Check if the hostname is something.local (Bonjour); if so, allow it.
  • */ +
  • if ((end = strrchr(host, '.')) != NULL &&
  • (!strcasecmp(end, ".local") || !strncasecmp(end, ".local:", 7)))
  • return (1); +#endif /* HAVE_DNSSD */ +
  • /*
  • * Check for (alias) name matches...
  • */ +
  • for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias);
  • a;
  • a = (cupsd_alias_t *)cupsArrayNext(ServerAlias))
  • {
  • if (!strncasecmp(host, a->name, a->namelen))
  • {
  • /*
  • * Prefix matches; check the character at the end - it must be either
  • * ":" or nul...
  • */ +
  • end = host + a->namelen; +
  • if (!*end || *end == ':')
  • return (1);
  • }
  • } +
  • /*
  • * Check for interface hostname matches...
  • */ +
  • for (netif = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
  • netif;
  • netif = (cupsd_netif_t *)cupsArrayNext(NetIFList))
  • {
  • if (!strncasecmp(host, netif->hostname, netif->hostlen))
  • {
  • /*
  • * Prefix matches; check the character at the end - it must be either
  • * ":" or nul...
  • */ +
  • end = host + netif->hostlen; +
  • if (!*end || *end == ':')
  • return (1);
  • }
  • } +
  • /*
  • * Check if the hostname is an IP address...
  • */ +
  • if (isdigit(*host & 255) || *host == '[')
  • {
  • /*
  • * Possible IPv4/IPv6 address...
  • */ +
  • char temp[1024], /* Temporary string */
  • ptr; / Pointer into temporary string */
  • http_addrlist_t addrlist; / List of addresses */ + +
  • strlcpy(temp, host, sizeof(temp));
  • if ((ptr = strrchr(temp, ':')) != NULL && !strchr(ptr, ']'))
  • ptr = '\0'; / Strip :port from host value */ +
  • if ((addrlist = httpAddrGetList(temp, AF_UNSPEC, NULL)) != NULL)
  • {
  • /*
  • * Good IPv4/IPv6 address...
  • */ +
  • httpAddrFreeList(addrlist);
  • return (1);
  • }
  • } +
  • return (0); +} + + +/*
    • 'write_file()' - Send a file via HTTP. */

Only in cups-1.3.9-rebind/scheduler: client.c.orig
diff -ur cups-1.3.9/scheduler/client.h cups-1.3.9-rebind/scheduler/client.h
--- cups-1.3.9/scheduler/client.h 2007-10-22 11:52:13.000000000 -0700
+++ cups-1.3.9-rebind/scheduler/client.h 2009-02-06 12:06:18.000000000 -0800
@@ -95,8 +95,6 @@
/* Time when listening was paused /
VAR cups_array_t *Clients VALUE(NULL);
/
HTTP clients */
-VAR http_addrlist_t *ServerAddrs VALUE(NULL);

  •               /* Server address(es) */
    

    VAR char ServerHeader VALUE(NULL);
    /
    Server header in requests /
    VAR int CGIPipes[2] VALUE2(-1,-1);
    diff -ur cups-1.3.9/scheduler/conf.c cups-1.3.9-rebind/scheduler/conf.c
    --- cups-1.3.9/scheduler/conf.c 2008-09-07 14:58:01.000000000 -0700
    +++ cups-1.3.9-rebind/scheduler/conf.c 2009-02-06 12:06:18.000000000 -0800
    @@ -187,6 +189,9 @@
    /

    • Local functions... */ + +static void add_alias(const char *name); +static void free_aliases(void); static http_addrlist_t *get_address(const char *value, int defport); static int get_addr_and_mask(const char *value, unsigned *ip, unsigned *mask); @@ -254,7 +259,8 @@ return (-1); }
  •  dir_created = 1;
    
  • dir_created = 1;
  •  fileinfo.st_mode = mode | S_IFDIR;
    

    }
    else
    return (create_dir ? -1 : 1);
    @@ -413,12 +419,16 @@

    cupsdDeleteAllListeners();

  • RemoteAccessEnabled = 0;
    +
    /*

    • String options... */
  • cupsdSetString(&ServerName, httpGetHostname(NULL, temp, sizeof(temp)));

  • cupsdSetStringf(&ServerAdmin, "root@%s", temp);
  • free_aliases(); +
  • cupsdClearString(&ServerName);
  • cupsdClearString(&ServerAdmin);
    cupsdSetString(&ServerBin, CUPS_SERVERBIN);
    cupsdSetString(&RequestRoot, CUPS_REQUESTS);
    cupsdSetString(&CacheDir, CUPS_CACHEDIR);
    @@ -626,15 +636,69 @@

    RunUser = getuid();

  • cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.",

  •              RemoteAccessEnabled ? "enabled" : "disabled");
    

    +
    /*

    • See if the ServerName is an IP address... */
  • if (!ServerName)

  • {
  • if (gethostname(temp, sizeof(temp)))
  • {
  • cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get hostname: %s",
  • strerror(errno));
  • strlcpy(temp, "localhost", sizeof(temp));
  • } +
  • cupsdSetString(&ServerName, temp);
  • add_alias(temp); +
  • if (HostNameLookups || RemoteAccessEnabled)
  • {
  • struct hostent host; / Host entry to get FQDN */ +
  • if ((host = gethostbyname(temp)) != NULL)
  • {
  • if (strcasecmp(temp, host->h_name))
  • {
  • cupsdSetString(&ServerName, host->h_name);
  • add_alias(host->h_name);
  • } +
  • if (host->h_aliases)
  • {
  • for (i = 0; host->h_aliases[i]; i ++)
  • if (strcasecmp(temp, host->h_aliases[i]))
  • add_alias(host->h_aliases[i]);
  • }
  • }
  • } +
  • /*
  • * Make sure we have the base hostname added as an alias, too!
  • */ +
  • if ((slash = strchr(temp, '.')) != NULL)
  • {
  • *slash = '\0';
  • add_alias(temp);
  • }
  • }
    +
    for (slash = ServerName; isdigit(*slash & 255) || *slash == '.'; slash ++);

    ServerNameIsIP = !*slash;

    /*

  • * Make sure ServerAdmin is initialized...
  • */ +
  • if (!ServerAdmin)
  • cupsdSetStringf(&ServerAdmin, "root@%s", ServerName); +
  • /*
    • Use the default system group if none was supplied in cupsd.conf... */

@@ -1246,6 +1310,52 @@

/*

  • * 'add_alias()' - Add a ServerAlias.
  • / + +static void +add_alias(const char *name) / I - Name to add */ +{
  • cupsd_alias_t a; / New alias */
  • size_t namelen; /* Length of name */ + +
  • namelen = strlen(name); +
  • if ((a = (cupsd_alias_t *)malloc(sizeof(cupsd_alias_t) + namelen)) == NULL)
  • return; +
  • if (!ServerAlias)
  • ServerAlias = cupsArrayNew(NULL, NULL); +
  • a->namelen = namelen;
  • strcpy(a->name, name); /* OK since a->name is allocated */ +
  • cupsArrayAdd(ServerAlias, a); +} + + +/*
  • * 'free_aliases()' - Free all of the ServerAlias entries.
  • */ + +static void +free_aliases(void) +{
  • cupsd_alias_t a; / Current alias */ + +
  • for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias);
  • a;
  • a = (cupsd_alias_t *)cupsArrayNext(ServerAlias))
  • free(a); +
  • cupsArrayDelete(ServerAlias);
  • ServerAlias = NULL; +} + + +/*
    • 'get_address()' - Get an address + port number from a line. */

@@ -2246,6 +2356,9 @@
#endif /* AF_LOCAL */
cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv4)", temp,
ntohs(lis->address.ipv4.sin_port));
+

  • if (!httpAddrLocalhost(&(lis->address)))
  • RemoteAccessEnabled = 1;
    

    }

    /*
    @@ -2977,6 +3090,8 @@
    break;
    }
    }

  • else if (!strcasecmp(line, "ServerAlias") && value)
  •  add_alias(value);
    

    else if (!strcasecmp(line, "SetEnv") && value)
    {
    /*
    Only in cups-1.3.9-rebind/scheduler: conf.c.orig
    diff -ur cups-1.3.9/scheduler/conf.h cups-1.3.9-rebind/scheduler/conf.h
    --- cups-1.3.9/scheduler/conf.h 2008-02-15 15:26:51.000000000 -0800
    +++ cups-1.3.9-rebind/scheduler/conf.h 2009-02-06 12:06:18.000000000 -0800
    @@ -46,6 +46,17 @@

    /*

  • * ServerAlias data...
  • */ + +typedef struct +{
  • size_t namelen; /* Length of alias name */
  • char name[1]; /* Alias name / +} cupsd_alias_t; + + +/
    • Globals... */

@@ -65,7 +76,12 @@
/* Directory for request files /
*DocumentRoot VALUE(NULL);
/
Root directory for documents */
-VAR int ServerNameIsIP VALUE(0);
+VAR cups_array_t *ServerAlias VALUE(NULL);

  • /* Alias names for server */ +VAR int RemoteAccessEnabled VALUE(0),
  • /* Are we listening on non-local addresses? */
  • ServerNameIsIP VALUE(0);
  •               /* Is the ServerName an IP address? */
    

    VAR int NumSystemGroups VALUE(0);
    /* Number of system group names */
    VAR char *SystemGroups[MAX_SYSTEM_GROUPS]
    diff -ur cups-1.3.9/scheduler/listen.c cups-1.3.9-rebind/scheduler/listen.c
    --- cups-1.3.9/scheduler/listen.c 2007-08-13 10:20:14.000000000 -0700
    +++ cups-1.3.9-rebind/scheduler/listen.c 2009-02-06 12:08:22.000000000 -0800
    @@ -143,18 +143,6 @@
    cupsArrayCount(Listeners));

    /*

  • * Get the server's IP address...

- */

  • if (ServerAddrs)

- httpAddrFreeList(ServerAddrs);

  • if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL)
  • cupsdLogMessage(CUPSD_LOG_ERROR,
  • "Unable to find IP address for server name \"%s\"!\n",

- ServerName);

  • /*
    • Setup socket listeners... */

diff -ur cups-1.3.9/scheduler/network.c cups-1.3.9-rebind/scheduler/network.c
--- cups-1.3.9/scheduler/network.c 2008-08-25 20:43:28.000000000 -0700
+++ cups-1.3.9-rebind/scheduler/network.c 2009-02-06 12:06:34.000000000 -0800
@@ -100,8 +100,8 @@
cupsd_netif_t temp; / New interface /
struct ifaddrs *addrs, /
Interface address list /
*addr; /
Current interface address */

  • http_addrlist_t saddr; / Current server address / char hostname[1024]; / Hostname for address */
  • size_t hostlen; /* Length of hostname */

    /*
    @@ -155,7 +155,7 @@

    • Try looking up the hostname for the address as needed... */
  • if (HostNameLookups)

  • if (HostNameLookups || RemoteAccessEnabled) httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname, sizeof(hostname)); else @@ -169,25 +169,16 @@ if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr))) strcpy(hostname, "localhost"); else
  • {
  • for (saddr = ServerAddrs; saddr; saddr = saddr->next)
  • if (httpAddrEqual((http_addr_t *)(addr->ifa_addr), &(saddr->addr)))

- break;

  • if (saddr)
  • strlcpy(hostname, ServerName, sizeof(hostname));
  • else
  • httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
  • sizeof(hostname));
  • }
  • httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
  •          sizeof(hostname));
    

    }

    /*

    • Create a new address element... */
  • if ((temp = calloc(1, sizeof(cupsd_netif_t) +

  • strlen(hostname))) == NULL)
  • hostlen = strlen(hostname);
  • if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL)
    break;

    /*
    @@ -195,6 +186,7 @@
    */

    strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));

  • temp->hostlen = hostlen;
    strcpy(temp->hostname, hostname); /* Safe because hostname is allocated */

    if (addr->ifa_addr->sa_family == AF_INET)
    Only in cups-1.3.9-rebind/scheduler: network.c.orig
    diff -ur cups-1.3.9/scheduler/network.h cups-1.3.9-rebind/scheduler/network.h
    --- cups-1.3.9/scheduler/network.h 2007-07-11 14:46:42.000000000 -0700
    +++ cups-1.3.9-rebind/scheduler/network.h 2009-02-06 12:06:18.000000000 -0800
    @@ -25,6 +25,7 @@
    http_addr_t address, /* Network address /
    mask, /
    Network mask /
    broadcast; /
    Broadcast address */

  • size_t hostlen; /* Length of hostname / char name[32], / Network interface name / hostname[1]; / Hostname associated with interface */ } cupsd_netif_t;
@michaelrsweet

"cups-1.3-rebind-v3.patch":

diff -ur cups-1.3.9/cups/http-addr.c cups-1.3.9-rebind/cups/http-addr.c
--- cups-1.3.9/cups/http-addr.c 2008-09-05 17:30:39.000000000 -0700
+++ cups-1.3.9-rebind/cups/http-addr.c 2009-04-01 14:05:33.000000000 -0700
@@ -153,7 +153,7 @@
#endif /* AF_LOCAL */

if (addr->addr.sa_family == AF_INET &&

  • ntohl(addr->ipv4.sin_addr.s_addr) == 0x7f000001)
  •  (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000)
    

    return (1);

    return (0);
    diff -ur cups-1.3.9/doc/help/ref-cupsd-conf.html.in cups-1.3.9-rebind/doc/help/ref-cupsd-conf.html.in
    --- cups-1.3.9/doc/help/ref-cupsd-conf.html.in 2008-06-17 11:27:16.000000000 -0700
    +++ cups-1.3.9-rebind/doc/help/ref-cupsd-conf.html.in 2009-04-01 14:18:50.000000000 -0700
    @@ -2477,6 +2477,37 @@
    HREF="#ServerName">ServerName.

+

CUPS 1.3.10ServerAlias


+
+

Examples


+
+

+ServerAlias althost
+ServerAlias althost.foo.com
+ServerAlias althost.bar.com
+ServerAlias *
+

+
+

Description


+
+

The ServerAlias directive specifies alternate names that the
+server is known by. By default it contains a list of all aliases associated
+with the ServerName. The special name
+"" can be used to allow any hostname when accessing CUPS via an external
+network interfaces.


+
+
Note
+
+

The ServerAlias directive is used for HTTP Host header
+validation when clients connect to the scheduler from external interfaces.
+Using the special name "
" can expose your system to known browser-based
+DNS rebinding attacks, even when accessing sites through a firewall. If the
+auto-discovery of alternate names does not work, we recommend listing each
+alternate name with a ServerAlias directive instead of using "*".


+
+

+
+

ServerBin

Examples


diff -ur cups-1.3.9/man/cupsd.conf.man.in cups-1.3.9-rebind/man/cupsd.conf.man.in
--- cups-1.3.9/man/cupsd.conf.man.in 2008-06-16 10:41:11.000000000 -0700
+++ cups-1.3.9-rebind/man/cupsd.conf.man.in 2009-04-01 14:19:00.000000000 -0700
@@ -12,7 +12,7 @@
.\" which should have been included with this file. If this file is
.\" file is missing or damaged, see the license at "http://www.cups.org/".
.\"
-.TH cupsd.conf 5 "Common UNIX Printing System" "16 June 2008" "Apple Inc."
+.TH cupsd.conf 5 "Common UNIX Printing System" "1 April 2009" "Apple Inc."
.SH NAME
cupsd.conf - server configuration file for cups
.SH DESCRIPTION
@@ -540,6 +540,11 @@
.br
Specifies the email address of the server administrator.
.TP 5
+ServerAlias hostname
+.br
+Specifies an alternate name that the server is known by. The special name ""
+allows any name to be used.
+.TP 5
ServerBin directory
.br
Specifies the directory where backends, CGIs, daemons, and filters may
diff -ur cups-1.3.9/scheduler/client.c cups-1.3.9-rebind/scheduler/client.c
--- cups-1.3.9/scheduler/client.c 2008-09-16 17:42:56.000000000 -0700
+++ cups-1.3.9-rebind/scheduler/client.c 2009-04-01 14:06:28.000000000 -0700
@@ -102,6 +102,7 @@
#endif /
HAVE_SSL */
static int pipe_command(cupsd_client_t *con, int infile, int *outfile,
char *command, char *options, int root);
+static int valid_host(cupsd_client_t *con);
static int write_file(cupsd_client_t *con, http_status_t code,
char *filename, char *type,
struct stat *filestats);
@@ -261,16 +262,7 @@
* Map accesses from the same host to the server name.
*/

  • for (addr = ServerAddrs; addr; addr = addr->next)
  • if (httpAddrEqual(con->http.hostaddr, &(addr->addr)))

- break;

  • if (addr)
  • {
  • strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname));
  • hostname = con->http.hostname;
  • }
  • else if (HostNameLookups)
  • if (HostNameLookups) hostname = httpAddrLookup(con->http.hostaddr, con->http.hostname, sizeof(con->http.hostname)); else @@ -1078,6 +1070,23 @@ return; } }
  • else if (!valid_host(con))
  • {
  • /*
  • * Access to localhost must use "localhost" or the corresponding IPv4
  • * or IPv6 values in the Host: field.
  • */ +
  • cupsdLogMessage(CUPSD_LOG_WARN,
  • "Request from \"%s\" using invalid Host: field \"%s\"",
  • con->http.hostname, con->http.fields[HTTP_FIELD_HOST]); +
  • if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
  • {
  • cupsdCloseClient(con);
  • return;
  • }
  • }
    else if (con->operation == HTTP_OPTIONS)
    {
    /*
    @@ -4805,6 +4814,137 @@

    /*

  • * 'valid_host()' - Is the Host: field valid?
  • / + +static int / O - 1 if valid, 0 if not / +valid_host(cupsd_client_t *con) / I - Client connection */ +{
  • cupsd_alias_t a; / Current alias */
  • cupsd_netif_t netif; / Current network interface */
  • const char host, / Host field */
  • end; / End character */ + +
  • host = con->http.fields[HTTP_FIELD_HOST]; +
  • if (httpAddrLocalhost(con->http.hostaddr))
  • {
  • /*
  • * Only allow "localhost" or the equivalent IPv4 or IPv6 numerical
  • * addresses when accessing CUPS via the loopback interface...
  • */ +
  • return (!strcasecmp(host, "localhost") ||
  • !strncasecmp(host, "localhost:", 10) ||
  • !strcasecmp(host, "localhost.") ||
  • !strncasecmp(host, "localhost.:", 11) || +#ifdef __linux
  • !strcasecmp(host, "localhost.localdomain") ||
  • !strncasecmp(host, "localhost.localdomain:", 22) || +#endif /* __linux */
  • !strcmp(host, "127.0.0.1") ||
  • !strncmp(host, "127.0.0.1:", 10) ||
  • !strcmp(host, "[::1]") ||
  • !strncmp(host, "[::1]:", 6));
  • } + +#ifdef HAVE_DNSSD
  • /*
  • * Check if the hostname is something.local (Bonjour); if so, allow it.
  • */ +
  • if ((end = strrchr(host, '.')) != NULL &&
  • (!strcasecmp(end, ".local") || !strncasecmp(end, ".local:", 7)))
  • return (1); +#endif /* HAVE_DNSSD */ +
  • /*
  • * Check for (alias) name matches...
  • */ +
  • for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias);
  • a;
  • a = (cupsd_alias_t *)cupsArrayNext(ServerAlias))
  • {
  • /*
  • * "ServerAlias *" allows all host values through...
  • */ +
  • if (!strcmp(a->name, "*"))
  • return (1); +
  • if (!strncasecmp(host, a->name, a->namelen))
  • {
  • /*
  • * Prefix matches; check the character at the end - it must be either
  • * ":" or nul...
  • */ +
  • end = host + a->namelen; +
  • if (!*end || *end == ':')
  • return (1);
  • }
  • } +
  • /*
  • * Check for interface hostname matches...
  • */ +
  • for (netif = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
  • netif;
  • netif = (cupsd_netif_t *)cupsArrayNext(NetIFList))
  • {
  • if (!strncasecmp(host, netif->hostname, netif->hostlen))
  • {
  • /*
  • * Prefix matches; check the character at the end - it must be either
  • * ":" or nul...
  • */ +
  • end = host + netif->hostlen; +
  • if (!*end || *end == ':')
  • return (1);
  • }
  • } +
  • /*
  • * Check if the hostname is an IP address...
  • */ +
  • if (isdigit(*host & 255) || *host == '[')
  • {
  • /*
  • * Possible IPv4/IPv6 address...
  • */ +
  • char temp[1024], /* Temporary string */
  • ptr; / Pointer into temporary string */
  • http_addrlist_t addrlist; / List of addresses */ + +
  • strlcpy(temp, host, sizeof(temp));
  • if ((ptr = strrchr(temp, ':')) != NULL && !strchr(ptr, ']'))
  • ptr = '\0'; / Strip :port from host value */ +
  • if ((addrlist = httpAddrGetList(temp, AF_UNSPEC, NULL)) != NULL)
  • {
  • /*
  • * Good IPv4/IPv6 address...
  • */ +
  • httpAddrFreeList(addrlist);
  • return (1);
  • }
  • } +
  • return (0); +} + + +/*
    • 'write_file()' - Send a file via HTTP. */

diff -ur cups-1.3.9/scheduler/client.h cups-1.3.9-rebind/scheduler/client.h
--- cups-1.3.9/scheduler/client.h 2007-10-22 11:52:13.000000000 -0700
+++ cups-1.3.9-rebind/scheduler/client.h 2009-04-01 14:05:26.000000000 -0700
@@ -95,8 +95,6 @@
/* Time when listening was paused /
VAR cups_array_t *Clients VALUE(NULL);
/
HTTP clients */
-VAR http_addrlist_t *ServerAddrs VALUE(NULL);

  •               /* Server address(es) */
    

    VAR char ServerHeader VALUE(NULL);
    /
    Server header in requests /
    VAR int CGIPipes[2] VALUE2(-1,-1);
    diff -ur cups-1.3.9/scheduler/conf.c cups-1.3.9-rebind/scheduler/conf.c
    --- cups-1.3.9/scheduler/conf.c 2008-09-07 14:58:01.000000000 -0700
    +++ cups-1.3.9-rebind/scheduler/conf.c 2009-04-01 14:05:26.000000000 -0700
    @@ -187,6 +187,9 @@
    /

    • Local functions... */ + +static void add_alias(const char *name); +static void free_aliases(void); static http_addrlist_t *get_address(const char *value, int defport); static int get_addr_and_mask(const char *value, unsigned *ip, unsigned *mask); @@ -254,7 +257,8 @@ return (-1); }
  •  dir_created = 1;
    
  • dir_created = 1;
  •  fileinfo.st_mode = mode | S_IFDIR;
    

    }
    else
    return (create_dir ? -1 : 1);
    @@ -413,12 +417,16 @@

    cupsdDeleteAllListeners();

  • RemoteAccessEnabled = 0;
    +
    /*

    • String options... */
  • cupsdSetString(&ServerName, httpGetHostname(NULL, temp, sizeof(temp)));

  • cupsdSetStringf(&ServerAdmin, "root@%s", temp);
  • free_aliases(); +
  • cupsdClearString(&ServerName);
  • cupsdClearString(&ServerAdmin);
    cupsdSetString(&ServerBin, CUPS_SERVERBIN);
    cupsdSetString(&RequestRoot, CUPS_REQUESTS);
    cupsdSetString(&CacheDir, CUPS_CACHEDIR);
    @@ -626,15 +634,69 @@

    RunUser = getuid();

  • cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.",

  •              RemoteAccessEnabled ? "enabled" : "disabled");
    

    +
    /*

    • See if the ServerName is an IP address... */
  • if (!ServerName)

  • {
  • if (gethostname(temp, sizeof(temp)))
  • {
  • cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get hostname: %s",
  • strerror(errno));
  • strlcpy(temp, "localhost", sizeof(temp));
  • } +
  • cupsdSetString(&ServerName, temp);
  • add_alias(temp); +
  • if (HostNameLookups || RemoteAccessEnabled)
  • {
  • struct hostent host; / Host entry to get FQDN */ +
  • if ((host = gethostbyname(temp)) != NULL)
  • {
  • if (strcasecmp(temp, host->h_name))
  • {
  • cupsdSetString(&ServerName, host->h_name);
  • add_alias(host->h_name);
  • } +
  • if (host->h_aliases)
  • {
  • for (i = 0; host->h_aliases[i]; i ++)
  • if (strcasecmp(temp, host->h_aliases[i]))
  • add_alias(host->h_aliases[i]);
  • }
  • }
  • } +
  • /*
  • * Make sure we have the base hostname added as an alias, too!
  • */ +
  • if ((slash = strchr(temp, '.')) != NULL)
  • {
  • *slash = '\0';
  • add_alias(temp);
  • }
  • }
    +
    for (slash = ServerName; isdigit(*slash & 255) || *slash == '.'; slash ++);

    ServerNameIsIP = !*slash;

    /*

  • * Make sure ServerAdmin is initialized...
  • */ +
  • if (!ServerAdmin)
  • cupsdSetStringf(&ServerAdmin, "root@%s", ServerName); +
  • /*
    • Use the default system group if none was supplied in cupsd.conf... */

@@ -1246,6 +1308,52 @@

/*

  • * 'add_alias()' - Add a ServerAlias.
  • / + +static void +add_alias(const char *name) / I - Name to add */ +{
  • cupsd_alias_t a; / New alias */
  • size_t namelen; /* Length of name */ + +
  • namelen = strlen(name); +
  • if ((a = (cupsd_alias_t *)malloc(sizeof(cupsd_alias_t) + namelen)) == NULL)
  • return; +
  • if (!ServerAlias)
  • ServerAlias = cupsArrayNew(NULL, NULL); +
  • a->namelen = namelen;
  • strcpy(a->name, name); /* OK since a->name is allocated */ +
  • cupsArrayAdd(ServerAlias, a); +} + + +/*
  • * 'free_aliases()' - Free all of the ServerAlias entries.
  • */ + +static void +free_aliases(void) +{
  • cupsd_alias_t a; / Current alias */ + +
  • for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias);
  • a;
  • a = (cupsd_alias_t *)cupsArrayNext(ServerAlias))
  • free(a); +
  • cupsArrayDelete(ServerAlias);
  • ServerAlias = NULL; +} + + +/*
    • 'get_address()' - Get an address + port number from a line. */

@@ -2246,6 +2354,9 @@
#endif /* AF_LOCAL */
cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv4)", temp,
ntohs(lis->address.ipv4.sin_port));
+

  • if (!httpAddrLocalhost(&(lis->address)))
  • RemoteAccessEnabled = 1;
    

    }

    /*
    @@ -2977,6 +3088,8 @@
    break;
    }
    }

  • else if (!strcasecmp(line, "ServerAlias") && value)
  •  add_alias(value);
    

    else if (!strcasecmp(line, "SetEnv") && value)
    {
    /*
    diff -ur cups-1.3.9/scheduler/conf.h cups-1.3.9-rebind/scheduler/conf.h
    --- cups-1.3.9/scheduler/conf.h 2008-02-15 15:26:51.000000000 -0800
    +++ cups-1.3.9-rebind/scheduler/conf.h 2009-04-01 14:05:26.000000000 -0700
    @@ -46,6 +46,17 @@

    /*

  • * ServerAlias data...
  • */ + +typedef struct +{
  • size_t namelen; /* Length of alias name */
  • char name[1]; /* Alias name / +} cupsd_alias_t; + + +/
    • Globals... */

@@ -65,7 +76,12 @@
/* Directory for request files /
*DocumentRoot VALUE(NULL);
/
Root directory for documents */
-VAR int ServerNameIsIP VALUE(0);
+VAR cups_array_t *ServerAlias VALUE(NULL);

  • /* Alias names for server */ +VAR int RemoteAccessEnabled VALUE(0),
  • /* Are we listening on non-local addresses? */
  • ServerNameIsIP VALUE(0);
  •               /* Is the ServerName an IP address? */
    

    VAR int NumSystemGroups VALUE(0);
    /* Number of system group names */
    VAR char *SystemGroups[MAX_SYSTEM_GROUPS]
    diff -ur cups-1.3.9/scheduler/listen.c cups-1.3.9-rebind/scheduler/listen.c
    --- cups-1.3.9/scheduler/listen.c 2007-08-13 10:20:14.000000000 -0700
    +++ cups-1.3.9-rebind/scheduler/listen.c 2009-04-01 14:05:26.000000000 -0700
    @@ -143,18 +143,6 @@
    cupsArrayCount(Listeners));

    /*

  • * Get the server's IP address...

- */

  • if (ServerAddrs)

- httpAddrFreeList(ServerAddrs);

  • if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL)
  • cupsdLogMessage(CUPSD_LOG_ERROR,
  • "Unable to find IP address for server name \"%s\"!\n",

- ServerName);

  • /*
    • Setup socket listeners... */

diff -ur cups-1.3.9/scheduler/network.c cups-1.3.9-rebind/scheduler/network.c
--- cups-1.3.9/scheduler/network.c 2008-08-25 20:43:28.000000000 -0700
+++ cups-1.3.9-rebind/scheduler/network.c 2009-04-01 14:05:26.000000000 -0700
@@ -100,8 +100,8 @@
cupsd_netif_t temp; / New interface /
struct ifaddrs *addrs, /
Interface address list /
*addr; /
Current interface address */

  • http_addrlist_t saddr; / Current server address / char hostname[1024]; / Hostname for address */
  • size_t hostlen; /* Length of hostname */

    /*
    @@ -155,7 +155,7 @@

    • Try looking up the hostname for the address as needed... */
  • if (HostNameLookups)

  • if (HostNameLookups || RemoteAccessEnabled) httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname, sizeof(hostname)); else @@ -169,25 +169,16 @@ if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr))) strcpy(hostname, "localhost"); else
  • {
  • for (saddr = ServerAddrs; saddr; saddr = saddr->next)
  • if (httpAddrEqual((http_addr_t *)(addr->ifa_addr), &(saddr->addr)))

- break;

  • if (saddr)
  • strlcpy(hostname, ServerName, sizeof(hostname));
  • else
  • httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
  • sizeof(hostname));
  • }
  • httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
  •          sizeof(hostname));
    

    }

    /*

    • Create a new address element... */
  • if ((temp = calloc(1, sizeof(cupsd_netif_t) +

  • strlen(hostname))) == NULL)
  • hostlen = strlen(hostname);
  • if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL)
    break;

    /*
    @@ -195,6 +186,7 @@
    */

    strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));

  • temp->hostlen = hostlen;
    strcpy(temp->hostname, hostname); /* Safe because hostname is allocated */

    if (addr->ifa_addr->sa_family == AF_INET)
    diff -ur cups-1.3.9/scheduler/network.h cups-1.3.9-rebind/scheduler/network.h
    --- cups-1.3.9/scheduler/network.h 2007-07-11 14:46:42.000000000 -0700
    +++ cups-1.3.9-rebind/scheduler/network.h 2009-04-01 14:05:26.000000000 -0700
    @@ -25,6 +25,7 @@
    http_addr_t address, /* Network address /
    mask, /
    Network mask /
    broadcast; /
    Broadcast address */

  • size_t hostlen; /* Length of hostname / char name[32], / Network interface name / hostname[1]; / Hostname associated with interface */ } cupsd_netif_t;
@michaelrsweet michaelrsweet added this to the Stable milestone Mar 17, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment