--- cups-1.3.9/cups/http-addr.c 2008-09-05 17:30:39.000000000 -0700
+++ cups-1.3.9/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);
--- cups-1.3.9/doc/help/ref-cupsd-conf.html.in 2008-06-17 11:27:16.000000000 -0700
+++ cups-1.3.9/doc/help/ref-cupsd-conf.html.in 2009-04-01 14:18:50.000000000 -0700
@@ -2477,6 +2477,37 @@
HREF="#ServerName">ServerName
.
+
+
+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 "*".
+
+
+
+
Examples
--- cups-1.3.9/man/cupsd.conf.man.in 2008-06-16 10:41:11.000000000 -0700
+++ cups-1.3.9/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
--- cups-1.3.9/scheduler/client.c 2008-09-16 17:42:56.000000000 -0700
+++ cups-1.3.9/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.
*/
--- cups-1.3.9/scheduler/client.h 2007-10-22 11:52:13.000000000 -0700
+++ cups-1.3.9/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);
--- cups-1.3.9/scheduler/conf.c 2008-09-07 14:58:01.000000000 -0700
+++ cups-1.3.9/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)
{
/*
--- cups-1.3.9/scheduler/conf.h 2008-02-15 15:26:51.000000000 -0800
+++ cups-1.3.9/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]
--- cups-1.3.9/scheduler/listen.c 2007-08-13 10:20:14.000000000 -0700
+++ cups-1.3.9/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...
*/
--- cups-1.3.9/scheduler/network.c 2008-08-25 20:43:28.000000000 -0700
+++ cups-1.3.9/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)
--- cups-1.3.9/scheduler/network.h 2007-07-11 14:46:42.000000000 -0700
+++ cups-1.3.9/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;