-const char parsers_rcs[] = "$Id: parsers.c,v 1.93 2007/03/20 15:21:44 fabiankeil Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.94 2007/03/21 12:23:53 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/parsers.c,v $
*
* Revisions :
* $Log: parsers.c,v $
+ * Revision 1.94 2007/03/21 12:23:53 fabiankeil
+ * - Add better protection against malicious gzip headers.
+ * - Stop logging the first hundred bytes of decompressed content.
+ * It looks like it's working and there is always debug 16.
+ * - Log the content size after decompression in decompress_iob()
+ * instead of pcrs_filter_response().
+ *
* Revision 1.93 2007/03/20 15:21:44 fabiankeil
* - Use dedicated header filter actions instead of abusing "filter".
* Replace "filter-client-headers" and "filter-client-headers"
#include <ctype.h>
#include <assert.h>
#include <string.h>
+
+#ifdef __GLIBC__
+/*
+ * Convince GNU's libc to provide a strptime prototype.
+ */
+#define __USE_XOPEN
+#endif /*__GLIBC__ */
#include <time.h>
#ifdef FEATURE_ZLIB
}
else if (0 == strcmpic(newval, "randomize"))
{
+ const char *header_time = *header + sizeof("Last-Modified:");
+
log_error(LOG_LEVEL_HEADER, "Randomizing: %s", *header);
now = time(NULL);
#ifdef HAVE_GMTIME_R
#else
timeptr = gmtime(&now);
#endif
- if ((timeptr = parse_header_time(*header, &last_modified)) == NULL)
+ if (JB_ERR_OK != parse_header_time(header_time, &last_modified))
{
- log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s (crunching!)", *header);
+ log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header);
freez(*header);
}
else
}
else /* add random value */
{
- if ((timeptr = parse_header_time(*header, &tm)) == NULL)
+ const char *header_time = *header + sizeof("If-Modified-Since:");
+
+ if (JB_ERR_OK != parse_header_time(header_time, &tm))
{
- log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s (crunching!)", *header);
+ log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header);
freez(*header);
}
else
time_t now;
time_t cookie_time;
struct tm tm_now;
- struct tm tm_cookie;
time(&now);
#ifdef FEATURE_COOKIE_JAR
if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
{
- log_error(LOG_LEVEL_HEADER, "Crunched incoming cookie -- yum!");
- return crumble(csp, header);
+ log_error(LOG_LEVEL_HEADER, "Crunching incoming cookie: %s", *header);
+ freez(*header);
}
else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
{
*/
if ((strncmpic(cur_tag, "expires=", 8) == 0) && *(cur_tag + 8))
{
- char *match;
- const char *expiration_date = cur_tag + 8; /* Skip "[Ee]xpires=" */
- memset(&tm_cookie, 0, sizeof(tm_cookie));
- /*
- * Try the valid time formats we know about.
- *
- * XXX: This should be moved to parse_header_time().
- *
- * XXX: Maybe the log messages should be removed
- * for the next stable release. They just exist to
- * see which time format gets the most hits and
- * should be checked for first.
- */
- if (NULL != (match = strptime(expiration_date, "%a, %e-%b-%y %H:%M:%S ", &tm_cookie)))
- {
- /* 22-Feb-2008 12:01:18 GMT */
- log_error(LOG_LEVEL_HEADER,
- "cookie \'%s\' send by %s appears to be using time format 1.",
- *header, csp->http->url);
- }
- else if (NULL != (match = strptime(expiration_date, "%A, %e-%b-%Y %H:%M:%S ", &tm_cookie)))
- {
- /* Tue, 02-Jun-2037 20:00:00 GMT */
- log_error(LOG_LEVEL_HEADER,
- "cookie \'%s\' send by %s appears to be using time format 2.",
- *header, csp->http->url);
- }
- else if (NULL != (match = strptime(expiration_date, "%a, %e-%b-%Y %H:%M:%S ", &tm_cookie)))
- {
- /* Tuesday, 02-Jun-2037 20:00:00 GMT */
- /*
- * On FreeBSD this is never reached because it's handled
- * by "format 2" as well. I am, however, not sure if all
- * strptime() implementations behave that way.
- */
- log_error(LOG_LEVEL_HEADER,
- "cookie \'%s\' send by %s appears to be using time format 3.",
- *header, csp->http->url);
- }
- else if (NULL != (match = strptime(expiration_date, "%a, %e %b %Y %H:%M:%S ", &tm_cookie)))
- {
- /* Fri, 22 Feb 2008 19:20:05 GMT */
- log_error(LOG_LEVEL_HEADER,
- "cookie \'%s\' send by %s appears to be using time format 4.",
- *header, csp->http->url);
- }
- else if (NULL != (match = strptime(expiration_date, "%A %b %e %H:%M:%S %Y", &tm_cookie)))
- {
- /* Thu Mar 08 23:00:00 2007 GMT */
- log_error(LOG_LEVEL_HEADER,
- "cookie \'%s\' send by %s appears to be using time format 5.",
- *header, csp->http->url);
- }
+ char *expiration_date = cur_tag + 8; /* Skip "[Ee]xpires=" */
- /* Did any of them match? */
- if (NULL == match)
+ /* Did we detect the date properly? */
+ if (JB_ERR_OK != parse_header_time(expiration_date, &cookie_time))
{
/*
* Nope, treat it as if it was still valid.
* anyway, which in many cases will be shorter
* than a browser session.
*/
- cookie_time = timegm(&tm_cookie);
if (cookie_time - now < 0)
{
log_error(LOG_LEVEL_HEADER,
*
* Function : parse_header_time
*
- * Description : Transforms time inside a HTTP header into
- * the usual time format.
+ * Description : Parses time formats used in HTTP header strings
+ * to get the numerical respresentation.
*
* Parameters :
- * 1 : header = header to parse
- * 2 : tm = storage for the resulting time in seconds
+ * 1 : header_time = HTTP header time as string.
+ * 2 : result = storage for header_time in seconds
*
- * Returns : Time struct containing the header time, or
- * NULL in case of a parsing problems.
+ * Returns : JB_ERR_OK if the time format was recognized, or
+ * JB_ERR_PARSE otherwise.
*
*********************************************************************/
-struct tm *parse_header_time(char *header, time_t *tm) {
-
- char * timestring;
+jb_err parse_header_time(const char *header_time, time_t *result)
+{
struct tm gmt;
- struct tm * timeptr;
/*
- * Initializing gmt to prevent time zone offsets.
+ * Zero out gmt to prevent time zone offsets.
*
* While this is only necessary on some platforms
* (mingw32 for example), I don't know how to
* detect these automatically and doing it everywhere
* shouldn't hurt.
*/
- time(tm);
-#ifdef HAVE_LOCALTIME_R
- gmt = *localtime_r(tm, &gmt);
-#elif FEATURE_PTHREAD
- pthread_mutex_lock(&localtime_mutex);
- gmt = *localtime(tm);
- pthread_mutex_unlock(&localtime_mutex);
-#else
- gmt = *localtime(tm);
-#endif
-
- /* Skipping header name */
- timestring = strstr(header, ": ");
- if (strptime(timestring, ": %a, %d %b %Y %H:%M:%S", &gmt) == NULL)
- {
- timeptr = NULL;
- }
- else
+ memset(&gmt, 0, sizeof(gmt));
+
+ /* Tue, 02 Jun 2037 20:00:00 */
+ if ((NULL == strptime(header_time, "%a, %d %b %Y %H:%M:%S", &gmt))
+ /* Tue, 02-Jun-2037 20:00:00 */
+ && (NULL == strptime(header_time, "%a, %d-%b-%Y %H:%M:%S", &gmt))
+ /* Tue, 02-Jun-37 20:00:00 */
+ && (NULL == strptime(header_time, "%a, %d-%b-%y %H:%M:%S", &gmt))
+ /* Tuesday, 02-Jun-2037 20:00:00 */
+ && (NULL == strptime(header_time, "%A, %d-%b-%Y %H:%M:%S", &gmt))
+ /* Tuesday Jun 02 20:00:00 2037 */
+ && (NULL == strptime(header_time, "%A %b %d %H:%M:%S %Y", &gmt)))
{
- *tm = timegm(&gmt);
- timeptr = &gmt;
+ return JB_ERR_PARSE;
}
- return(timeptr);
+
+ *result = timegm(&gmt);
+
+ return JB_ERR_OK;
}