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;