diff -up cups-1.4b2-svn8404/CHANGES-1.3.txt.CVE-2009-0164 cups-1.4b2-svn8404/CHANGES-1.3.txt --- cups-1.4b2-svn8404/CHANGES-1.3.txt.CVE-2009-0164 2009-03-05 10:54:00.000000000 +0000 +++ cups-1.4b2-svn8404/CHANGES-1.3.txt 2009-04-17 16:47:18.000000000 +0100 @@ -69,11 +69,6 @@ CHANGES IN CUPS V1.3.10 - The scheduler now rejects ATTR: messages with empty values. - The scheduler could consume all CPU handling closed connections (STR #2988) - - The scheduler now protects against DNS rebinding attacks on - localhost. - - SECURITY: The PNG image reading code did not validate the - image size properly, leading to a potential buffer overflow - (STR #2974) - Fixed some configure script bugs with rc/xinetd directories (STR #2970) - The Epson sample driver PPDs contained errors (STR #2979) diff -up cups-1.4b2-svn8404/cups/http-addr.c.CVE-2009-0164 cups-1.4b2-svn8404/cups/http-addr.c --- cups-1.4b2-svn8404/cups/http-addr.c.CVE-2009-0164 2009-02-17 17:45:27.000000000 +0000 +++ cups-1.4b2-svn8404/cups/http-addr.c 2009-04-17 16:47:18.000000000 +0100 @@ -154,7 +154,7 @@ httpAddrLocalhost( #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 -up cups-1.4b2-svn8404/cups/http.c.CVE-2009-0164 cups-1.4b2-svn8404/cups/http.c --- cups-1.4b2-svn8404/cups/http.c.CVE-2009-0164 2009-04-17 16:47:18.000000000 +0100 +++ cups-1.4b2-svn8404/cups/http.c 2009-04-17 16:47:18.000000000 +0100 @@ -1842,18 +1842,35 @@ httpSetField(http_t *http, /* I - strlcpy(http->fields[field], value, HTTP_MAX_VALUE); - /* - * Special case for Authorization: as its contents can be - * longer than HTTP_MAX_VALUE - */ - if (field == HTTP_FIELD_AUTHORIZATION) { + /* + * Special case for Authorization: as its contents can be + * longer than HTTP_MAX_VALUE + */ + if (http->field_authorization) free(http->field_authorization); http->field_authorization = strdup(value); } + else if (field == HTTP_FIELD_HOST) + { + /* + * Special-case for Host: as we don't want a trailing "." on the hostname. + */ + + char *ptr = http->fields[HTTP_FIELD_HOST]; + /* Pointer into Host: field */ + + if (*ptr) + { + ptr += strlen(ptr) - 1; + + if (*ptr == '.') + *ptr = '\0'; + } + } } diff -up cups-1.4b2-svn8404/man/cupsd.conf.man.in.CVE-2009-0164 cups-1.4b2-svn8404/man/cupsd.conf.man.in --- cups-1.4b2-svn8404/man/cupsd.conf.man.in.CVE-2009-0164 2009-02-17 17:45:27.000000000 +0000 +++ cups-1.4b2-svn8404/man/cupsd.conf.man.in 2009-04-17 16:47:18.000000000 +0100 @@ -617,6 +617,11 @@ ServerAdmin user@domain.com .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 -up cups-1.4b2-svn8404/scheduler/client.c.CVE-2009-0164 cups-1.4b2-svn8404/scheduler/client.c --- cups-1.4b2-svn8404/scheduler/client.c.CVE-2009-0164 2009-03-05 10:54:00.000000000 +0000 +++ cups-1.4b2-svn8404/scheduler/client.c 2009-04-17 16:47:48.000000000 +0100 @@ -39,6 +39,7 @@ * is_path_absolute() - Is a path absolute and free of relative elements. * make_certificate() - Make a self-signed SSL/TLS certificate. * pipe_command() - Pipe the output of a command to the remote client. + * valid_host() - Is the Host: field valid? * write_file() - Send a file via HTTP. * write_pipe() - Flag that data is available on the CGI pipe. */ @@ -108,6 +109,7 @@ static int make_certificate(cupsd_clien #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); @@ -1129,13 +1131,7 @@ cupsdReadClient(cupsd_client_t *con) /* return; } } - else if (httpAddrLocalhost(con->http.hostaddr) && - strcasecmp(con->http.fields[HTTP_FIELD_HOST], "localhost") && - strncasecmp(con->http.fields[HTTP_FIELD_HOST], "localhost:", 10) && - strcmp(con->http.fields[HTTP_FIELD_HOST], "127.0.0.1") && - strncmp(con->http.fields[HTTP_FIELD_HOST], "127.0.0.1:", 10) && - strcmp(con->http.fields[HTTP_FIELD_HOST], "[::1]") && - strncmp(con->http.fields[HTTP_FIELD_HOST], "[::1]:", 6)) + else if (!valid_host(con)) { /* * Access to localhost must use "localhost" or the corresponding IPv4 @@ -3278,6 +3274,10 @@ get_cdsa_certificate(cupsd_client_t *con ssl_options.ServerName = con->servername; ssl_options.ServerNameLen = strlen(con->servername); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "get_cdsa_certificate: Looking for certs for \"%s\"...", + con->servername); + options.Data = (uint8 *)&ssl_options; options.Length = sizeof(ssl_options); @@ -3970,7 +3970,7 @@ make_certificate(cupsd_client_t *con) /* envp[envc] = NULL; if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL, 0, - &pid)) + NULL, &pid)) { unlink(seedfile); return (0); @@ -4862,6 +4862,165 @@ pipe_command(cupsd_client_t *con, /* I - /* + * '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) || + !strcasecmp(end, ".local.") || !strncasecmp(end, ".local.:", 8))) + return (1); +#endif /* HAVE_DNSSD */ + + /* + * 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); + } + } + + /* + * 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 ":", ".", + * ".:", or nul... + */ + + end = host + a->namelen; + + if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':'))) + return (1); + } + } + +#ifdef HAVE_DNSSD + for (a = (cupsd_alias_t *)cupsArrayFirst(DNSSDAlias); + a; + a = (cupsd_alias_t *)cupsArrayNext(DNSSDAlias)) + { + /* + * "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 ":", ".", + * ".:", or nul... + */ + + end = host + a->namelen; + + if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':'))) + return (1); + } + } +#endif /* HAVE_DNSSD */ + + /* + * 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 ":", ".", + * ".:", or nul... + */ + + end = host + netif->hostlen; + + if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':'))) + return (1); + } + } + + return (0); +} + + +/* * 'write_file()' - Send a file via HTTP. */ diff -up cups-1.4b2-svn8404/scheduler/conf.c.CVE-2009-0164 cups-1.4b2-svn8404/scheduler/conf.c --- cups-1.4b2-svn8404/scheduler/conf.c.CVE-2009-0164 2009-04-17 16:47:18.000000000 +0100 +++ cups-1.4b2-svn8404/scheduler/conf.c 2009-04-17 16:47:18.000000000 +0100 @@ -14,13 +14,15 @@ * * Contents: * + * cupsdAddAlias() - Add a host alias. * cupsdCheckPermissions() - Fix the mode and ownership of a file or * directory. + * cupsdFreeAliases() - Free all of the alias entries. * cupsdReadConfiguration() - Read the cupsd.conf file. * get_address() - Get an address + port number from a line. * get_addr_and_mask() - Get an IP address and netmask. - * parse_aaa() - Parse authentication, authorization, and - * access control lines. + * parse_aaa() - Parse authentication, authorization, and access + * control lines. * parse_fatal_errors() - Parse FatalErrors values in a string. * parse_groups() - Parse system group names in a string. * parse_protocols() - Parse browse protocols in a string. @@ -197,6 +199,7 @@ static const unsigned zeros[4] = /* * Local functions... */ + static http_addrlist_t *get_address(const char *value, int defport); static int get_addr_and_mask(const char *value, unsigned *ip, unsigned *mask); @@ -211,6 +214,30 @@ static int read_policy(cups_file_t *fp, /* + * 'cupsdAddAlias()' - Add a host alias. + */ + +void +cupsdAddAlias(cups_array_t *aliases, /* I - Array of aliases */ + 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; + + a->namelen = namelen; + strcpy(a->name, name); /* OK since a->name is allocated */ + + cupsArrayAdd(aliases, a); +} + + +/* * 'cupsdCheckPermissions()' - Fix the mode and ownership of a file or directory. */ @@ -362,6 +389,25 @@ cupsdCheckPermissions( /* + * 'cupsdFreeAliases()' - Free all of the alias entries. + */ + +void +cupsdFreeAliases(cups_array_t *aliases) /* I - Array of aliases */ +{ + cupsd_alias_t *a; /* Current alias */ + + + for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias); + a; + a = (cupsd_alias_t *)cupsArrayNext(ServerAlias)) + free(a); + + cupsArrayDelete(aliases); +} + + +/* * 'cupsdReadConfiguration()' - Read the cupsd.conf file. */ @@ -433,6 +479,9 @@ cupsdReadConfiguration(void) * String options... */ + cupsdFreeAliases(ServerAlias); + ServerAlias = NULL; + cupsdClearString(&ServerName); cupsdClearString(&ServerAdmin); cupsdSetString(&ServerBin, CUPS_SERVERBIN); @@ -674,9 +723,7 @@ cupsdReadConfiguration(void) if (!ServerName) { - if (HostNameLookups || RemoteAccessEnabled) - httpGetHostname(NULL, temp, sizeof(temp)); - else if (gethostname(temp, sizeof(temp))) + if (gethostname(temp, sizeof(temp))) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get hostname: %s", strerror(errno)); @@ -684,6 +731,50 @@ cupsdReadConfiguration(void) } cupsdSetString(&ServerName, temp); + + if (!ServerAlias) + ServerAlias = cupsArrayNew(NULL, NULL); + + cupsdAddAlias(ServerAlias, temp); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", 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); + cupsdAddAlias(ServerAlias, host->h_name); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", + host->h_name); + } + + if (host->h_aliases) + { + for (i = 0; host->h_aliases[i]; i ++) + if (strcasecmp(temp, host->h_aliases[i])) + { + cupsdAddAlias(ServerAlias, host->h_aliases[i]); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", + host->h_aliases[i]); + } + } + } + } + + /* + * Make sure we have the base hostname added as an alias, too! + */ + + if ((slash = strchr(temp, '.')) != NULL) + { + *slash = '\0'; + cupsdAddAlias(ServerAlias, temp); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", temp); + } } for (slash = ServerName; isdigit(*slash & 255) || *slash == '.'; slash ++); @@ -3278,6 +3369,13 @@ read_configuration(cups_file_t *fp) /* I break; } } + else if (!strcasecmp(line, "ServerAlias") && value) + { + if (!ServerAlias) + ServerAlias = cupsArrayNew(NULL, NULL); + + cupsdAddAlias(ServerAlias, value); + } else if (!strcasecmp(line, "SetEnv") && value) { /* diff -up cups-1.4b2-svn8404/scheduler/conf.h.CVE-2009-0164 cups-1.4b2-svn8404/scheduler/conf.h --- cups-1.4b2-svn8404/scheduler/conf.h.CVE-2009-0164 2009-04-17 16:47:18.000000000 +0100 +++ cups-1.4b2-svn8404/scheduler/conf.h 2009-04-17 16:47:18.000000000 +0100 @@ -82,6 +82,17 @@ typedef enum /* + * ServerAlias data... + */ + +typedef struct +{ + size_t namelen; /* Length of alias name */ + char name[1]; /* Alias name */ +} cupsd_alias_t; + + +/* * Globals... */ @@ -105,6 +116,8 @@ VAR char *ConfigurationFile VALUE(NULL) /* Directory for request files */ *DocumentRoot VALUE(NULL); /* Root directory for documents */ +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); @@ -269,10 +282,12 @@ VAR char *SystemGroupAuthKey VALUE(NULL * Prototypes... */ +extern void cupsdAddAlias(cups_array_t *aliases, const char *name); extern int cupsdCheckPermissions(const char *filename, const char *suffix, int mode, int user, int group, int is_dir, int create_dir); +extern void cupsdFreeAliases(cups_array_t *aliases); extern char *cupsdGetDateTime(struct timeval *t, cupsd_time_t format); #ifdef HAVE_GSSAPI extern int cupsdLogGSSMessage(int level, int major_status, diff -up cups-1.4b2-svn8404/scheduler/dirsvc.c.CVE-2009-0164 cups-1.4b2-svn8404/scheduler/dirsvc.c --- cups-1.4b2-svn8404/scheduler/dirsvc.c.CVE-2009-0164 2009-04-17 16:47:18.000000000 +0100 +++ cups-1.4b2-svn8404/scheduler/dirsvc.c 2009-04-17 16:47:18.000000000 +0100 @@ -38,6 +38,7 @@ * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP... * cupsdUpdateSLPBrowse() - Get browsing information via SLP. * dequote() - Remote quotes from a string. + * dnssdAddAlias() - Add a DNS-SD alias name. * dnssdBuildTxtRecord() - Build a TXT record from printer info. * dnssdComparePrinters() - Compare the registered names of two printers. * dnssdDeregisterPrinter() - Stop sending broadcast information for a @@ -155,6 +156,10 @@ static void update_smb(int onoff); #ifdef HAVE_DNSSD +# ifdef HAVE_COREFOUNDATION +static void dnssdAddAlias(const void *key, const void *value, + void *context); +# endif /* HAVE_COREFOUNDATION */ static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p, int for_lpd); static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b); @@ -2199,6 +2204,38 @@ dequote(char *d, /* I - Destinat #ifdef HAVE_DNSSD +# ifdef HAVE_COREFOUNDATION +/* + * 'dnssdAddAlias()' - Add a DNS-SD alias name. + */ + +static void +dnssdAddAlias(const void *key, /* I - Key */ + const void *value, /* I - Value (domain) */ + void *context) /* I - Unused */ +{ + char valueStr[1024], /* Domain string */ + hostname[1024]; /* Complete hostname */ + + + (void)context; + + if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() && + CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr), + kCFStringEncodingUTF8)) + { + snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDName, valueStr); + if (!DNSSDAlias) + DNSSDAlias = cupsArrayNew(NULL, NULL); + + cupsdAddAlias(DNSSDAlias, hostname); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s", + hostname); + } +} +# endif /* HAVE_COREFOUNDATION */ + + /* * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info. */ diff -up cups-1.4b2-svn8404/scheduler/dirsvc.h.CVE-2009-0164 cups-1.4b2-svn8404/scheduler/dirsvc.h --- cups-1.4b2-svn8404/scheduler/dirsvc.h.CVE-2009-0164 2009-02-17 17:45:27.000000000 +0000 +++ cups-1.4b2-svn8404/scheduler/dirsvc.h 2009-04-17 16:47:18.000000000 +0100 @@ -4,7 +4,7 @@ * Directory services definitions for the Common UNIX Printing System * (CUPS) scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2009 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -135,6 +135,8 @@ VAR cupsd_statbuf_t *PollStatusBuffer VA #ifdef HAVE_DNSSD VAR char *DNSSDName VALUE(NULL); /* Computer/server name */ +VAR cups_array_t *DNSSDAlias VALUE(NULL); + /* List of dynamic ServerAlias's */ VAR int DNSSDPort VALUE(0); /* Port number to register */ VAR cups_array_t *DNSSDPrinters VALUE(NULL); diff -up cups-1.4b2-svn8404/scheduler/network.c.CVE-2009-0164 cups-1.4b2-svn8404/scheduler/network.c --- cups-1.4b2-svn8404/scheduler/network.c.CVE-2009-0164 2009-02-05 10:57:28.000000000 +0000 +++ cups-1.4b2-svn8404/scheduler/network.c 2009-04-17 16:47:18.000000000 +0100 @@ -101,6 +101,7 @@ cupsdNetIFUpdate(void) struct ifaddrs *addrs, /* Interface address list */ *addr; /* Current interface address */ char hostname[1024]; /* Hostname for address */ + size_t hostlen; /* Length of hostname */ /* @@ -176,8 +177,8 @@ cupsdNetIFUpdate(void) * 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; /* @@ -185,6 +186,7 @@ cupsdNetIFUpdate(void) */ 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 -up cups-1.4b2-svn8404/scheduler/network.h.CVE-2009-0164 cups-1.4b2-svn8404/scheduler/network.h --- cups-1.4b2-svn8404/scheduler/network.h.CVE-2009-0164 2008-12-03 15:39:53.000000000 +0000 +++ cups-1.4b2-svn8404/scheduler/network.h 2009-04-17 16:47:18.000000000 +0100 @@ -4,7 +4,7 @@ * Network interface definitions for the Common UNIX Printing System * (CUPS) scheduler. * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2009 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -25,6 +25,7 @@ typedef struct cupsd_netif_s /**** Netw 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;