X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=filters.c;h=744af6a204abdd067c6a1e0f7bedeb1dcba871fa;hp=b703e1de35938e1c0df0e6dfee46d6257869081a;hb=72081f829de368392d04076728f8c991178c0080;hpb=85075982fad8fb5107a6b2651aeef855ba8bace7 diff --git a/filters.c b/filters.c index b703e1de..744af6a2 100644 --- a/filters.c +++ b/filters.c @@ -1,7 +1,7 @@ -const char filters_rcs[] = "$Id: filters.c,v 1.44 2002/03/07 03:49:31 oes Exp $"; +const char filters_rcs[] = "$Id: filters.c,v 1.58.2.9 2006/01/29 23:10:56 david__schmidt Exp $"; /********************************************************************* * - * File : $Source: /cvsroot/ijbswa/current/filters.c,v $ + * File : $Source: /cvsroot/ijbswa/current/Attic/filters.c,v $ * * Purpose : Declares functions to parse/crunch headers and pages. * Functions declared include: @@ -9,10 +9,11 @@ const char filters_rcs[] = "$Id: filters.c,v 1.44 2002/03/07 03:49:31 oes Exp $" * `block_url', `url_actions', `domain_split', * `filter_popups', `forward_url', 'redirect_url', * `ij_untrusted_url', `intercept_url', `pcrs_filter_respose', - * 'ijb_send_banner', and `trust_url' + * `ijb_send_banner', `trust_url', `gif_deanimate_response', + * `jpeg_inspect_response' * - * Copyright : Written by and Copyright (C) 2001 the SourceForge - * IJBSWA team. http://ijbswa.sourceforge.net + * Copyright : Written by and Copyright (C) 2001, 2004 the SourceForge + * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and @@ -38,6 +39,90 @@ const char filters_rcs[] = "$Id: filters.c,v 1.44 2002/03/07 03:49:31 oes Exp $" * * Revisions : * $Log: filters.c,v $ + * Revision 1.58.2.9 2006/01/29 23:10:56 david__schmidt + * Multiple filter file support + * + * Revision 1.58.2.8 2005/05/07 21:50:55 david__schmidt + * A few memory leaks plugged (mostly on error paths) + * + * Revision 1.58.2.7 2004/10/03 12:53:32 david__schmidt + * Add the ability to check jpeg images for invalid + * lengths of comment blocks. Defensive strategy + * against the exploit: + * Microsoft Security Bulletin MS04-028 + * Buffer Overrun in JPEG Processing (GDI+) Could + * Allow Code Execution (833987) + * Enabled with +inspect-jpegs in actions files. + * + * Revision 1.58.2.6 2003/12/06 22:18:27 gliptak + * Correcting compile problem with FEATURE_IMAGE_BLOCKING + * + * Revision 1.58.2.5 2003/11/11 13:10:31 oes + * Fixed bug #839859: "See why" link URL now gets url-encoded. + * + * Revision 1.58.2.4 2003/02/28 12:52:45 oes + * Fixed a typo + * + * Revision 1.58.2.3 2002/09/25 14:51:51 oes + * Added basic support for OPTIONS and TRACE HTTP methods: + * New function direct_response which handles OPTIONS and + * TRACE requests whose Max-Forwards header field is zero. + * + * Revision 1.58.2.2 2002/08/01 17:18:28 oes + * Fixed BR 537651 / SR 579724 (MSIE image detect improper for IE/Mac) + * + * Revision 1.58.2.1 2002/07/26 15:18:53 oes + * - Bugfix: Executing a filters without jobs no longer results in + * turing off *all* filters. + * - Security fix: Malicious web servers can't cause a seg fault + * through bogus chunk sizes anymore + * + * Revision 1.58 2002/04/24 02:11:17 oes + * Jon's multiple AF patch: url_actions now evaluates rules + * from all AFs. + * + * Revision 1.57 2002/04/08 20:38:34 swa + * fixed JB spelling + * + * Revision 1.56 2002/04/05 15:51:24 oes + * - bugfix: error-pages now get correct request protocol + * - fix for invalid HTML in trust info + * + * Revision 1.55 2002/04/02 16:13:51 oes + * Fix: No "Go there anyway" for SSL + * + * Revision 1.54 2002/04/02 14:55:56 oes + * Bugfix: is_untrusted_url() now depends on FEATURE_TRUST, not FEATURE_COOKIE_JAR + * + * Revision 1.53 2002/03/26 22:29:54 swa + * we have a new homepage! + * + * Revision 1.52 2002/03/24 16:35:57 jongfoster + * Removing logo + * + * Revision 1.51 2002/03/24 15:23:33 jongfoster + * Name changes + * + * Revision 1.50 2002/03/24 13:25:43 swa + * name change related issues + * + * Revision 1.49 2002/03/16 20:29:14 oes + * Cosmetics + * + * Revision 1.48 2002/03/13 20:25:34 oes + * Better logging for content filters + * + * Revision 1.47 2002/03/13 00:30:52 jongfoster + * Killing warnings + * Added option of always sending redirect for imageblock, + * currently disabled with #if 0. + * + * Revision 1.46 2002/03/12 01:42:49 oes + * Introduced modular filters + * + * Revision 1.45 2002/03/08 16:47:50 oes + * Added choice beween GIF and PNG built-in images + * * Revision 1.44 2002/03/07 03:49:31 oes * - Fixed compiler warnings etc * - Changed built-in images from GIF to PNG @@ -331,7 +416,7 @@ const char filters_rcs[] = "$Id: filters.c,v 1.44 2002/03/07 03:49:31 oes Exp $" * a lot! ;-) * * Revision 1.3 2001/05/20 16:44:47 jongfoster - * Removing last hardcoded JunkBusters.com URLs. + * Removing last hardcoded Junkbusters.com URLs. * * Revision 1.2 2001/05/20 01:21:20 jongfoster * Version 2.9.4 checkin. @@ -487,7 +572,7 @@ int acl_addr(char *aspec, struct access_control_addr *aca) masklength = 32; port = 0; - if ((p = strchr(aspec, '/'))) + if ((p = strchr(aspec, '/')) != NULL) { *p++ = '\0'; @@ -503,7 +588,7 @@ int acl_addr(char *aspec, struct access_control_addr *aca) return(-1); } - if ((p = strchr(aspec, ':'))) + if ((p = strchr(aspec, ':')) != NULL) { *p++ = '\0'; @@ -635,9 +720,6 @@ int match_portlist(const char *portlist, int port) *********************************************************************/ struct http_response *block_url(struct client_state *csp) { -#ifdef FEATURE_IMAGE_BLOCKING - char *p; -#endif /* def FEATURE_IMAGE_BLOCKING */ struct http_response *rsp; /* @@ -664,19 +746,22 @@ struct http_response *block_url(struct client_state *csp) if (((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0) && is_imageurl(csp)) { + char *p; /* determine HOW images should be blocked */ p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER]; +#if 1 /* Two alternative strategies, use this one for now: */ + /* and handle accordingly: */ - if ((p == NULL) || (0 == strcmpic(p, "logo"))) + if ((p == NULL) || (0 == strcmpic(p, "pattern"))) { - rsp->body = bindup(image_logo_data, image_logo_length); + rsp->body = bindup(image_pattern_data, image_pattern_length); if (rsp->body == NULL) { free_http_response(rsp); return cgi_error_memory(); } - rsp->content_length = image_logo_length; + rsp->content_length = image_pattern_length; if (enlist_unique_header(rsp->headers, "Content-Type", BUILTIN_IMAGE_MIMETYPE)) { @@ -702,38 +787,46 @@ struct http_response *block_url(struct client_state *csp) } } - else if (0 == strcmpic(p, "pattern")) + else { - rsp->body = bindup(image_pattern_data, image_pattern_length); - if (rsp->body == NULL) + rsp->status = strdup("302 Local Redirect from Privoxy"); + if (rsp->status == NULL) { free_http_response(rsp); return cgi_error_memory(); } - rsp->content_length = image_pattern_length; - if (enlist_unique_header(rsp->headers, "Content-Type", BUILTIN_IMAGE_MIMETYPE)) + if (enlist_unique_header(rsp->headers, "Location", p)) { free_http_response(rsp); return cgi_error_memory(); } } - else +#else /* Following code is disabled for now */ + + /* and handle accordingly: */ + if ((p == NULL) || (0 == strcmpic(p, "pattern"))) { - rsp->status = strdup("302 Local Redirect from Junkbuster"); - if (rsp->status == NULL) - { - free_http_response(rsp); - return cgi_error_memory(); - } + p = CGI_PREFIX "send-banner?type=pattern"; + } + else if (0 == strcmpic(p, "blank")) + { + p = CGI_PREFIX "send-banner?type=blank"; + } + rsp->status = strdup("302 Local Redirect from Privoxy"); + if (rsp->status == NULL) + { + free_http_response(rsp); + return cgi_error_memory(); + } - if (enlist_unique_header(rsp->headers, "Location", p)) - { - free_http_response(rsp); - return cgi_error_memory(); - } + if (enlist_unique_header(rsp->headers, "Location", p)) + { + free_http_response(rsp); + return cgi_error_memory(); } +#endif /* Preceeding code is disabled for now */ } else #endif /* def FEATURE_IMAGE_BLOCKING */ @@ -744,6 +837,7 @@ struct http_response *block_url(struct client_state *csp) { jb_err err; struct map * exports; + char *p; /* * Workaround for stupid Netscape bug which prevents @@ -779,12 +873,16 @@ struct http_response *block_url(struct client_state *csp) #ifdef FEATURE_FORCE_LOAD err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1); -#else /* ifndef FEATURE_FORCE_LOAD */ - err = map_block_killer(exports, "force-support"); + if (csp->http->ssl != 0) #endif /* ndef FEATURE_FORCE_LOAD */ + { + err = map_block_killer(exports, "force-support"); + } + if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0); if (!err) err = map(exports, "path", 1, html_encode(csp->http->path), 0); + if (!err) err = map(exports, "path-ue", 1, url_encode(csp->http->path), 0); if (err) { @@ -854,9 +952,10 @@ struct http_response *trust_url(struct client_state *csp) } /* - * Export the host, port, and referrer information + * Export the protocol, host, port, and referrer information */ err = map(exports, "hostport", 1, csp->http->hostport, 1); + if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); if (!err) err = map(exports, "path", 1, csp->http->path, 1); if (NULL != (p = get_header_value(csp->headers, "Referer:"))) @@ -879,12 +978,13 @@ struct http_response *trust_url(struct client_state *csp) * Export the trust list */ p = strdup(""); - for (tl = csp->config->trust_list; (t = *tl) ; tl++) + for (tl = csp->config->trust_list; (t = *tl) != NULL ; tl++) { sprintf(buf, "
  • %s
  • \n", t->spec); string_append(&p, buf); } err = map(exports, "trusted-referrers", 1, p, 0); + freez(p); if (err) { @@ -903,10 +1003,11 @@ struct http_response *trust_url(struct client_state *csp) p = strdup(""); for (l = csp->config->trust_info->first; l ; l = l->next) { - sprintf(buf, "
  • %s
    \n",l->str, l->str); + sprintf(buf, "
  • %s
    \n",l->str, l->str); string_append(&p, buf); } err = map(exports, "trust-info", 1, p, 0); + freez(p); } else { @@ -976,7 +1077,7 @@ struct http_response *redirect_url(struct client_state *csp) /* * find the last URL encoded in the request */ - while ((p = strstr(p, "http://"))) + while ((p = strstr(p, "http://")) != NULL) { q = p++; } @@ -994,7 +1095,7 @@ struct http_response *redirect_url(struct client_state *csp) } if ( enlist_unique_header(rsp->headers, "Location", q) - || (NULL == (rsp->status = strdup("302 Local Redirect from Junkbuster"))) ) + || (NULL == (rsp->status = strdup("302 Local Redirect from Privoxy"))) ) { free_http_response(rsp); return cgi_error_memory(); @@ -1018,8 +1119,9 @@ struct http_response *redirect_url(struct client_state *csp) * * Description : Given a URL, decide whether it is an image or not, * using either the info from a previous +image action - * or, #ifdef FEATURE_IMAGE_DETECT_MSIE, the info from - * the browser's accept header. + * or, #ifdef FEATURE_IMAGE_DETECT_MSIE, and the browser + * is MSIE and not on a Mac, tell from the browser's accept + * header. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) @@ -1034,7 +1136,7 @@ int is_imageurl(struct client_state *csp) char *tmp; tmp = get_header_value(csp->headers, "User-Agent:"); - if (tmp && strstr(tmp, "MSIE")) + if (tmp && strstr(tmp, "MSIE") && !strstr(tmp, "Mac_")) { tmp = get_header_value(csp->headers, "Accept:"); if (tmp && strstr(tmp, "image/gif")) @@ -1057,7 +1159,7 @@ int is_imageurl(struct client_state *csp) #endif /* def FEATURE_IMAGE_BLOCKING */ -#ifdef FEATURE_COOKIE_JAR +#ifdef FEATURE_TRUST /********************************************************************* * * Function : is_untrusted_url @@ -1111,15 +1213,10 @@ int is_untrusted_url(struct client_state *csp) return 1; } - /* - * If not, do we maybe trust its referrer? - */ - /* - * Parse the URL from the referrer + * If not, do we maybe trust its referrer? */ - err = parse_http_url(referer, rhttp, csp); if (err) { @@ -1137,7 +1234,7 @@ int is_untrusted_url(struct client_state *csp) FILE *fp; - if ((fp = fopen(csp->config->trustfile, "a"))) + if (NULL != (fp = fopen(csp->config->trustfile, "a"))) { char * path; char * path_end; @@ -1181,23 +1278,24 @@ int is_untrusted_url(struct client_state *csp) } return 1; } -#endif /* def FEATURE_COOKIE_JAR */ +#endif /* def FEATURE_TRUST */ /********************************************************************* * * Function : pcrs_filter_response * - * Description : Apply all the pcrs jobs from the joblist (re_filterfile) - * to the text buffer that's been accumulated in - * csp->iob->buf and set csp->content_length to the modified - * size and raise the CSP_FLAG_MODIFIED flag if appropriate. + * Description : Execute all text substitutions from all applying + * +filter actions on the text buffer that's been accumulated + * in csp->iob->buf. If this changes the contents, set + * csp->content_length to the modified size and raise the + * CSP_FLAG_MODIFIED flag. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : a pointer to the (newly allocated) modified buffer. - * or NULL in case something went wrong + * or NULL if there were no hits or something went wrong * *********************************************************************/ char *pcrs_filter_response(struct client_state *csp) @@ -1210,14 +1308,41 @@ char *pcrs_filter_response(struct client_state *csp) struct file_list *fl; struct re_filterfile_spec *b; + struct list_entry *filtername; + + int i, found_filters = 0; - /* Sanity first */ + /* + * Sanity first + */ if (csp->iob->cur >= csp->iob->eod) { return(NULL); } size = csp->iob->eod - csp->iob->cur; + /* + * Need to check the set of re_filterfiles... + */ + for (i = 0; i < MAX_AF_FILES; i++) + { + fl = csp->rlist[i]; + if (NULL != fl) + { + if (NULL != fl->f) + { + found_filters = 1; + break; + } + } + } + + if (0 == found_filters) + { + log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering."); + return(NULL); + } + /* * If the body has a "chunked" transfer-encoding, * get rid of it first, adjusting size and iob->eod @@ -1233,30 +1358,48 @@ char *pcrs_filter_response(struct client_state *csp) csp->flags |= CSP_FLAG_MODIFIED; } - if ( ( NULL == (fl = csp->rlist) ) || ( NULL == (b = fl->f) ) ) + for (i = 0; i < MAX_AF_FILES; i++) { - log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering."); - return(NULL); - } - - if ( NULL == b->joblist ) + fl = csp->rlist[i]; + if ((NULL == fl) || (NULL == fl->f)) + break; + /* + * For all applying +filter actions, look if a filter by that + * name exists and if yes, execute it's pcrs_joblist on the + * buffer. + */ + for (b = fl->f; b; b = b->next) { - log_error(LOG_LEVEL_RE_FILTER, "Empty joblist. Nothing to do."); - return(NULL); - } + for (filtername = csp->action->multi[ACTION_MULTI_FILTER]->first; + filtername ; filtername = filtername->next) + { + if (strcmp(b->name, filtername->str) == 0) + { + int current_hits = 0; - log_error(LOG_LEVEL_RE_FILTER, "re_filtering %s%s (size %d) ...", - csp->http->hostport, csp->http->path, size); + if ( NULL == b->joblist ) + { + log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name); + continue; + } - /* Apply all jobs from the joblist */ - for (job = b->joblist; NULL != job; job = job->next) - { - hits += pcrs_execute(job, old, size, &new, &size); - if (old != csp->iob->cur) free(old); - old=new; - } + log_error(LOG_LEVEL_RE_FILTER, "re_filtering %s%s (size %d) with filter %s...", + csp->http->hostport, csp->http->path, size, b->name); - log_error(LOG_LEVEL_RE_FILTER, " produced %d hits (new size %d).", hits, size); + /* Apply all jobs from the joblist */ + for (job = b->joblist; NULL != job; job = job->next) + { + current_hits += pcrs_execute(job, old, size, &new, &size); + if (old != csp->iob->cur) free(old); + old=new; + } + + log_error(LOG_LEVEL_RE_FILTER, " ...produced %d hits (new size %d).", current_hits, size); + hits += current_hits; + } + } + } + } /* * If there were no hits, destroy our copy and let @@ -1332,7 +1475,88 @@ char *gif_deanimate_response(struct client_state *csp) } else { - log_error(LOG_LEVEL_DEANIMATE, "Success! GIF shrunk from %d bytes to %d.", size, out->offset); + if ((int)size == out->offset) + { + log_error(LOG_LEVEL_DEANIMATE, "GIF not changed."); + } + else + { + log_error(LOG_LEVEL_DEANIMATE, "Success! GIF shrunk from %d bytes to %d.", size, out->offset); + } + csp->content_length = out->offset; + csp->flags |= CSP_FLAG_MODIFIED; + p = out->buffer; + free(in); + free(out); + return(p); + } + +} + + +/********************************************************************* + * + * Function : jpeg_inspect_response + * + * Description : + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : a pointer to the (newly allocated) modified buffer + * or NULL in case something went wrong. + * + *********************************************************************/ +char *jpeg_inspect_response(struct client_state *csp) +{ + struct binbuffer *in = NULL, *out = NULL; + char *p = NULL; + size_t size = csp->iob->eod - csp->iob->cur; + + /* + * If the body has a "chunked" transfer-encoding, + * get rid of it first, adjusting size and iob->eod + */ + if (csp->flags & CSP_FLAG_CHUNKED) + { + log_error(LOG_LEVEL_DEANIMATE, "Need to de-chunk first"); + if (0 == (size = remove_chunked_transfer_coding(csp->iob->cur, size))) + { + return(NULL); + } + csp->iob->eod = csp->iob->cur + size; + csp->flags |= CSP_FLAG_MODIFIED; + } + + if (NULL == (in = (struct binbuffer *)zalloc(sizeof *in ))) + { + log_error(LOG_LEVEL_DEANIMATE, "failed! (jpeg no mem 1)"); + return NULL; + } + + if (NULL == (out = (struct binbuffer *)zalloc(sizeof *out))) + { + log_error(LOG_LEVEL_DEANIMATE, "failed! (jpeg no mem 2)"); + return NULL; + } + + in->buffer = csp->iob->cur; + in->size = size; + + /* + * Calling jpeg_inspect has the side-effect of creating and + * modifying the image buffer of "out" directly. + */ + if (jpeg_inspect(in, out)) + { + log_error(LOG_LEVEL_DEANIMATE, "failed! (jpeg parsing)"); + free(in); + buf_free(out); + return(NULL); + + } + else + { csp->content_length = out->offset; csp->flags |= CSP_FLAG_MODIFIED; p = out->buffer; @@ -1382,7 +1606,12 @@ int remove_chunked_transfer_coding(char *buffer, const size_t size) log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding"); return(0); } - newsize += chunksize; + + if ((newsize += chunksize) >= size) + { + log_error(LOG_LEVEL_ERROR, "Chunksize exceeds buffer in \"chunked\" transfer coding"); + return(0); + } from_p += 2; memmove(to_p, from_p, (size_t) chunksize); @@ -1421,16 +1650,21 @@ void url_actions(struct http_request *http, { struct file_list *fl; struct url_actions *b; + int i; init_current_action(csp->action); - if (((fl = csp->actions_list) == NULL) || ((b = fl->f) == NULL)) + for (i = 0; i < MAX_AF_FILES; i++) { - return; - } + if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL)) + { + return; + } - apply_url_actions(csp->action, http, b); + apply_url_actions(csp->action, http, b); + } + return; } @@ -1505,6 +1739,63 @@ const struct forward_spec * forward_url(struct http_request *http, } +/********************************************************************* + * + * Function : direct_response + * + * Description : Check if Max-Forwards == 0 for an OPTIONS or TRACE + * request and if so, return a HTTP 501 to the client. + * + * FIXME: I have a stupid name and I should handle the + * requests properly. Still, what we do here is rfc- + * compliant, whereas ignoring or forwarding are not. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : http_response if , NULL if nonmatch or handler fail + * + *********************************************************************/ +struct http_response *direct_response(struct client_state *csp) +{ + struct http_response *rsp; + struct list_entry *p; + + if ((0 == strcmpic(csp->http->gpc, "trace")) + || (0 == strcmpic(csp->http->gpc, "options"))) + { + for (p = csp->headers->first; (p != NULL) ; p = p->next) + { + if (!strncmp("Max-Forwards:", p->str, 13) + && (*(p->str+13) != '\0') && (atoi(p->str+13) == 0)) + { + /* FIXME: We could handle at least TRACE here, + but that would require a verbatim copy of + the request which we don't have anymore */ + + log_error(LOG_LEVEL_HEADER, "Found Max-Forwards:0 in OPTIONS or TRACE request -- Returning 501"); + + /* Get mem for response or fail*/ + if (NULL == (rsp = alloc_http_response())) + { + return cgi_error_memory(); + } + + if (NULL == (rsp->status = strdup("501 Not Implemented"))) + { + free_http_response(rsp); + return cgi_error_memory(); + } + + rsp->is_static = 1; + return(finish_http_response(rsp)); + } + } + } + return NULL; +} + + /* Local Variables: tab-width: 3