X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=filters.c;h=72719095dd9ced444bf293b310649c7a1e27b3dc;hp=902381ba2456575b00a751eb9209a7a5e475acc8;hb=777f23fd554b0811d16bc2323ced6fe9dc0cff72;hpb=27fb49fcf62210f91a9d7b206947ad279511676a diff --git a/filters.c b/filters.c index 902381ba..72719095 100644 --- a/filters.c +++ b/filters.c @@ -1,11 +1,11 @@ -const char filters_rcs[] = "$Id: filters.c,v 1.188 2014/10/18 11:25:57 fabiankeil Exp $"; +const char filters_rcs[] = "$Id: filters.c,v 1.198 2016/01/16 12:30:43 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/filters.c,v $ * * Purpose : Declares functions to parse/crunch headers and pages. * - * Copyright : Written by and Copyright (C) 2001-2014 the + * Copyright : Written by and Copyright (C) 2001-2016 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -347,12 +347,7 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) * Use a temporary acl spec copy so we can log * the unmodified original in case of parse errors. */ - acl_spec = strdup(aspec); - if (acl_spec == NULL) - { - /* XXX: This will be logged as parse error. */ - return(-1); - } + acl_spec = strdup_or_die(aspec); if ((p = strchr(acl_spec, '/')) != NULL) { @@ -391,13 +386,19 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) { p = strchr(acl_spec, ':'); } + if (p != NULL) + { + assert(*p == ':'); + *p = '\0'; + p++; + } #ifdef HAVE_RFC2553 memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - i = getaddrinfo(acl_spec, ((p) ? ++p : NULL), &hints, &result); + i = getaddrinfo(acl_spec, p, &hints, &result); if (i != 0) { @@ -416,7 +417,6 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) { char *endptr; - *p++ = '\0'; port = strtol(p, &endptr, 10); if (port <= 0 || port > 65535 || *endptr != '\0') @@ -582,12 +582,7 @@ struct http_response *block_url(struct client_state *csp) /* and handle accordingly: */ if ((p == NULL) || (0 == strcmpic(p, "pattern"))) { - rsp->status = strdup("403 Request blocked by Privoxy"); - if (rsp->status == NULL) - { - free_http_response(rsp); - return cgi_error_memory(); - } + rsp->status = strdup_or_die("403 Request blocked by Privoxy"); rsp->body = bindup(image_pattern_data, image_pattern_length); if (rsp->body == NULL) { @@ -604,12 +599,7 @@ struct http_response *block_url(struct client_state *csp) } else if (0 == strcmpic(p, "blank")) { - rsp->status = strdup("403 Request blocked by Privoxy"); - if (rsp->status == NULL) - { - free_http_response(rsp); - return cgi_error_memory(); - } + rsp->status = strdup_or_die("403 Request blocked by Privoxy"); rsp->body = bindup(image_blank_data, image_blank_length); if (rsp->body == NULL) { @@ -626,12 +616,7 @@ struct http_response *block_url(struct client_state *csp) } else { - rsp->status = strdup("302 Local Redirect from Privoxy"); - if (rsp->status == NULL) - { - free_http_response(rsp); - return cgi_error_memory(); - } + rsp->status = strdup_or_die("302 Local Redirect from Privoxy"); if (enlist_unique_header(rsp->headers, "Location", p)) { @@ -651,7 +636,7 @@ struct http_response *block_url(struct client_state *csp) new_content_type = csp->action->string[ACTION_STRING_CONTENT_TYPE]; freez(rsp->body); - rsp->body = strdup(" "); + rsp->body = strdup_or_die(" "); rsp->content_length = 1; if (csp->config->feature_flags & RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK) @@ -662,18 +647,13 @@ struct http_response *block_url(struct client_state *csp) * Return a 200 OK status for pages blocked with +handle-as-empty-document * if the "handle-as-empty-doc-returns-ok" runtime config option is set. */ - rsp->status = strdup("200 Request blocked by Privoxy"); + rsp->status = strdup_or_die("200 Request blocked by Privoxy"); } else { - rsp->status = strdup("403 Request blocked by Privoxy"); + rsp->status = strdup_or_die("403 Request blocked by Privoxy"); } - if (rsp->status == NULL) - { - free_http_response(rsp); - return cgi_error_memory(); - } if (new_content_type != 0) { log_error(LOG_LEVEL_HEADER, "Overwriting Content-Type with %s", new_content_type); @@ -693,12 +673,7 @@ struct http_response *block_url(struct client_state *csp) jb_err err; struct map * exports; - rsp->status = strdup("403 Request blocked by Privoxy"); - if (rsp->status == NULL) - { - free_http_response(rsp); - return cgi_error_memory(); - } + rsp->status = strdup_or_die("403 Request blocked by Privoxy"); exports = default_exports(csp, NULL); if (exports == NULL) @@ -802,9 +777,9 @@ struct http_response *trust_url(struct client_state *csp) return cgi_error_memory(); } - rsp->status = strdup("403 Request blocked by Privoxy"); + rsp->status = strdup_or_die("403 Request blocked by Privoxy"); exports = default_exports(csp, NULL); - if (exports == NULL || rsp->status == NULL) + if (exports == NULL) { free_http_response(rsp); return cgi_error_memory(); @@ -836,7 +811,7 @@ struct http_response *trust_url(struct client_state *csp) /* * Export the trust list */ - p = strdup(""); + p = strdup_or_die(""); for (tl = csp->config->trust_list; (t = *tl) != NULL ; tl++) { snprintf(buf, sizeof(buf), "
  • %s
  • \n", t->spec); @@ -858,7 +833,7 @@ struct http_response *trust_url(struct client_state *csp) { struct list_entry *l; - p = strdup(""); + p = strdup_or_die(""); for (l = csp->config->trust_info->first; l ; l = l->next) { snprintf(buf, sizeof(buf), "
  • %s
    \n", l->str, l->str); @@ -1131,14 +1106,8 @@ char *get_last_url(char *subject, const char *redirect_mode) } if (NULL != url_segment) { - url_segment = strdup(url_segment); + url_segment = strdup_or_die(url_segment); freez(dtoken); - if (url_segment == NULL) - { - log_error(LOG_LEVEL_ERROR, - "Out of memory while searching for redirects."); - return NULL; - } break; } freez(dtoken); @@ -1324,8 +1293,8 @@ struct http_response *redirect_url(struct client_state *csp) return cgi_error_memory(); } - if (enlist_unique_header(rsp->headers, "Location", new_url) - || (NULL == (rsp->status = strdup("302 Local Redirect from Privoxy")))) + rsp->status = strdup_or_die("302 Local Redirect from Privoxy"); + if (enlist_unique_header(rsp->headers, "Location", new_url)) { freez(new_url); free_http_response(rsp); @@ -1470,7 +1439,7 @@ int is_untrusted_url(const struct client_state *csp) { char * path; char * path_end; - char * new_entry = strdup("~"); + char * new_entry = strdup_or_die("~"); string_append(&new_entry, csp->http->hostport); @@ -1907,7 +1876,8 @@ static char *execute_external_filter(const struct client_state *csp, return NULL; } - filter_output = malloc_or_die(*size); + /* Allocate at least one byte */ + filter_output = malloc_or_die(*size + 1); new_size = 0; while (!feof(fp) && !ferror(fp)) @@ -1921,7 +1891,7 @@ static char *execute_external_filter(const struct client_state *csp, char *p; /* Could be considered wasteful if the content is 'large'. */ - *size = (*size != 0) ? *size * 2 : READ_LENGTH; + *size += (*size >= READ_LENGTH) ? *size : READ_LENGTH; p = realloc(filter_output, *size); if (p == NULL) @@ -1932,6 +1902,7 @@ static char *execute_external_filter(const struct client_state *csp, } filter_output = p; } + assert(new_size + READ_LENGTH < *size); len = fread(&filter_output[new_size], 1, READ_LENGTH, fp); if (len > 0) { @@ -2045,7 +2016,6 @@ static filter_function_ptr get_filter_function(const struct client_state *csp) * the content type and action settings. */ if ((csp->content_type & CT_TEXT) && - (csp->rlist != NULL) && (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) { filter_function = pcrs_filter_response; @@ -2083,6 +2053,7 @@ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size) size_t newsize = 0; unsigned int chunksize = 0; char *from_p, *to_p; + const char *end_of_buffer = buffer + *size; assert(buffer); from_p = to_p = buffer; @@ -2095,27 +2066,62 @@ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size) while (chunksize > 0U) { + /* + * If the chunk-size is valid, we should have at least + * chunk-size bytes of chunk-data and five bytes of + * meta data (chunk-size, CRLF, CRLF) left in the buffer. + */ + if (chunksize + 5 >= *size - newsize) + { + log_error(LOG_LEVEL_ERROR, + "Chunk size %u exceeds buffered data left. " + "Already digested %u of %u buffered bytes.", + chunksize, (unsigned int)newsize, (unsigned int)*size); + return JB_ERR_PARSE; + } + + /* + * Skip the chunk-size, the optional chunk-ext and the CRLF + * that is supposed to be located directly before the start + * of chunk-data. + */ if (NULL == (from_p = strstr(from_p, "\r\n"))) { log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding"); return JB_ERR_PARSE; } + from_p += 2; - if (chunksize >= *size - newsize) + /* + * The previous strstr() does not enforce chunk-validity + * and is sattisfied as long a CRLF is left in the buffer. + * + * Make sure the bytes we consider chunk-data are within + * the valid range. + */ + if (from_p + chunksize >= end_of_buffer) { log_error(LOG_LEVEL_ERROR, - "Chunk size %u exceeds buffered data left. " - "Already digested %u of %u buffered bytes.", - chunksize, (unsigned int)newsize, (unsigned int)*size); + "End of chunk is beyond the end of the buffer."); return JB_ERR_PARSE; } - newsize += chunksize; - from_p += 2; memmove(to_p, from_p, (size_t) chunksize); + newsize += chunksize; to_p = buffer + newsize; - from_p += chunksize + 2; + from_p += chunksize; + /* + * Not merging this check with the previous one allows us + * to keep chunks without trailing CRLF. It's not clear + * if we actually have to care about those, though. + */ + if (from_p + 2 >= end_of_buffer) + { + log_error(LOG_LEVEL_ERROR, "Not enough room for trailing CRLF."); + return JB_ERR_PARSE; + } + from_p += 2; if (sscanf(from_p, "%x", &chunksize) != 1) { log_error(LOG_LEVEL_INFO, "Invalid \"chunked\" transfer encoding detected and ignored."); @@ -2258,7 +2264,6 @@ char *execute_content_filters(struct client_state *csp) #ifdef FEATURE_EXTERNAL_FILTERS if ((csp->content_type & CT_TEXT) && - (csp->rlist != NULL) && !list_is_empty(csp->action->multi[ACTION_MULTI_EXTERNAL_FILTER])) { struct list_entry *filtername; @@ -2436,6 +2441,14 @@ static const struct forward_spec *get_forward_override_settings(struct client_st /* Parse the parent HTTP proxy host:port */ http_parent = vec[1]; + } + else if ((vec_count == 2) && !strcasecmp(vec[0], "forward-webserver")) + { + fwd->type = FORWARD_WEBSERVER; + + /* Parse the parent HTTP server host:port */ + http_parent = vec[1]; + } else if (vec_count == 3) { @@ -2591,12 +2604,7 @@ struct http_response *direct_response(struct client_state *csp) return cgi_error_memory(); } - if (NULL == (rsp->status = strdup("501 Not Implemented"))) - { - free_http_response(rsp); - return cgi_error_memory(); - } - + rsp->status = strdup_or_die("501 Not Implemented"); rsp->is_static = 1; rsp->crunch_reason = UNSUPPORTED; @@ -2668,7 +2676,6 @@ int content_requires_filtering(struct client_state *csp) * the content type and action settings. */ if ((csp->content_type & CT_TEXT) && - (csp->rlist != NULL) && (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]) || !list_is_empty(csp->action->multi[ACTION_MULTI_EXTERNAL_FILTER]))) {