X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=9b0fd4b19b826597c410afbe1299b55d4bc04d97;hp=14ce3b6bb14c4fcf08753818ae3fc921b91e8c3f;hb=779ede384c30caf7614196588440f0bb4665111f;hpb=22de1764b6460768a49d33328fe00e7320e7e618 diff --git a/parsers.c b/parsers.c index 14ce3b6b..9b0fd4b1 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.96 2007/04/12 12:53:58 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.116 2007/12/01 13:04:22 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -44,6 +44,83 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.96 2007/04/12 12:53:58 fabiankeil * * Revisions : * $Log: parsers.c,v $ + * Revision 1.116 2007/12/01 13:04:22 fabiankeil + * Fix a crash on mingw32 with some Last Modified times in the future. + * + * Revision 1.115 2007/11/02 16:52:50 fabiankeil + * Remove a "can't happen" error block which, over + * time, mutated into a "guaranteed to happen" block. + * + * Revision 1.114 2007/10/19 16:56:26 fabiankeil + * - Downgrade "Buffer limit reached" message to LOG_LEVEL_INFO. + * - Use shiny new content_filters_enabled() in client_range(). + * + * Revision 1.113 2007/10/10 17:29:57 fabiankeil + * I forgot about Poland. + * + * Revision 1.112 2007/10/09 16:38:40 fabiankeil + * Remove Range and If-Range headers if content filtering is enabled. + * + * Revision 1.111 2007/10/04 18:07:00 fabiankeil + * Move ACTION_VANILLA_WAFER handling from jcc's chat() into + * client_cookie_adder() to make sure send-vanilla-wafer can be + * controlled through tags (and thus regression-tested). + * + * Revision 1.110 2007/09/29 10:42:37 fabiankeil + * - Remove "scanning headers for" log message again. + * - Some more whitespace fixes. + * + * Revision 1.109 2007/09/08 14:25:48 fabiankeil + * Refactor client_referrer() and add conditional-forge parameter. + * + * Revision 1.108 2007/08/28 18:21:03 fabiankeil + * A bunch of whitespace fixes, pointy hat to me. + * + * Revision 1.107 2007/08/28 18:16:32 fabiankeil + * Fix possible memory corruption in server_http, make sure it's not + * executed for ordinary server headers and mark some problems for later. + * + * Revision 1.106 2007/08/18 14:30:32 fabiankeil + * Let content-type-overwrite{} honour force-text-mode again. + * + * Revision 1.105 2007/08/11 14:49:49 fabiankeil + * - Add prototpyes for the header parsers and make them static. + * - Comment out client_accept_encoding_adder() which isn't used right now. + * + * Revision 1.104 2007/07/14 07:38:19 fabiankeil + * Move the ACTION_FORCE_TEXT_MODE check out of + * server_content_type(). Signal other functions + * whether or not a content type has been declared. + * Part of the fix for BR#1750917. + * + * Revision 1.103 2007/06/01 16:31:54 fabiankeil + * Change sed() to return a jb_err in preparation for forward-override{}. + * + * Revision 1.102 2007/05/27 12:39:32 fabiankeil + * Adjust "X-Filter: No" to disable dedicated header filters. + * + * Revision 1.101 2007/05/14 10:16:41 fabiankeil + * Streamline client_cookie_adder(). + * + * Revision 1.100 2007/04/30 15:53:11 fabiankeil + * Make sure filters with dynamic jobs actually use them. + * + * Revision 1.99 2007/04/30 15:06:26 fabiankeil + * - Introduce dynamic pcrs jobs that can resolve variables. + * - Remove unnecessary update_action_bits_for_all_tags() call. + * + * Revision 1.98 2007/04/17 18:32:10 fabiankeil + * - Make tagging based on tags set by earlier taggers + * of the same kind possible. + * - Log whether or not new tags cause action bits updates + * (in which case a matching tag-pattern section exists). + * - Log if the user tries to set a tag that is already set. + * + * Revision 1.97 2007/04/15 16:39:21 fabiankeil + * Introduce tags as alternative way to specify which + * actions apply to a request. At the moment tags can be + * created based on client and server headers. + * * Revision 1.96 2007/04/12 12:53:58 fabiankeil * Log a warning if the content is compressed, filtering is * enabled and Privoxy was compiled without zlib support. @@ -694,6 +771,7 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.96 2007/04/12 12:53:58 fabiankeil #include "miscutil.h" #include "list.h" #include "actions.h" +#include "filters.h" #ifndef HAVE_STRPTIME #include "strptime.h" @@ -714,8 +792,49 @@ const char parsers_h_rcs[] = PARSERS_H_VERSION; #define ijb_isupper(__X) isupper((int)(unsigned char)(__X)) #define ijb_tolower(__X) tolower((int)(unsigned char)(__X)) -jb_err header_tagger(struct client_state *csp, char *header); -jb_err scan_headers(struct client_state *csp); +static jb_err scan_headers(struct client_state *csp); +static jb_err header_tagger(struct client_state *csp, char *header); +static jb_err parse_header_time(const char *header_time, time_t *result); + +static jb_err crumble (struct client_state *csp, char **header); +static jb_err connection (struct client_state *csp, char **header); +static jb_err filter_header (struct client_state *csp, char **header); +static jb_err client_referrer (struct client_state *csp, char **header); +static jb_err client_uagent (struct client_state *csp, char **header); +static jb_err client_ua (struct client_state *csp, char **header); +static jb_err client_from (struct client_state *csp, char **header); +static jb_err client_send_cookie (struct client_state *csp, char **header); +static jb_err client_x_forwarded (struct client_state *csp, char **header); +static jb_err client_accept_encoding (struct client_state *csp, char **header); +static jb_err client_te (struct client_state *csp, char **header); +static jb_err client_max_forwards (struct client_state *csp, char **header); +static jb_err client_host (struct client_state *csp, char **header); +static jb_err client_if_modified_since (struct client_state *csp, char **header); +static jb_err client_accept_language (struct client_state *csp, char **header); +static jb_err client_if_none_match (struct client_state *csp, char **header); +static jb_err crunch_client_header (struct client_state *csp, char **header); +static jb_err client_x_filter (struct client_state *csp, char **header); +static jb_err client_range (struct client_state *csp, char **header); +static jb_err server_set_cookie (struct client_state *csp, char **header); +static jb_err server_content_type (struct client_state *csp, char **header); +static jb_err server_content_length (struct client_state *csp, char **header); +static jb_err server_content_md5 (struct client_state *csp, char **header); +static jb_err server_content_encoding (struct client_state *csp, char **header); +static jb_err server_transfer_coding (struct client_state *csp, char **header); +static jb_err server_http (struct client_state *csp, char **header); +static jb_err crunch_server_header (struct client_state *csp, char **header); +static jb_err server_last_modified (struct client_state *csp, char **header); +static jb_err server_content_disposition(struct client_state *csp, char **header); + +static jb_err client_host_adder (struct client_state *csp); +static jb_err client_cookie_adder (struct client_state *csp); +static jb_err client_xtra_adder (struct client_state *csp); +static jb_err connection_close_adder (struct client_state *csp); + +static jb_err create_forged_referrer(char **header, const char *hostport); +static jb_err create_fake_referrer(char **header, const char *fake_referrer); +static jb_err handle_conditional_hide_referrer_parameter(char **header, + const char *host, const int parameter_conditional_block); const struct parsers client_patterns[] = { { "referer:", 8, client_referrer }, @@ -734,6 +853,8 @@ const struct parsers client_patterns[] = { { "max-forwards:", 13, client_max_forwards }, { "Accept-Language:", 16, client_accept_language }, { "if-none-match:", 14, client_if_none_match }, + { "Range:", 6, client_range }, + { "If-Range:", 9, client_range }, { "X-Filter:", 9, client_x_filter }, { "*", 0, crunch_client_header }, { "*", 0, filter_header }, @@ -741,7 +862,7 @@ const struct parsers client_patterns[] = { }; const struct parsers server_patterns[] = { - { "HTTP", 4, server_http }, + { "HTTP/", 5, server_http }, { "set-cookie:", 11, server_set_cookie }, { "connection:", 11, connection }, { "Content-Type:", 13, server_content_type }, @@ -768,19 +889,27 @@ const struct parsers server_patterns_light[] = { const add_header_func_ptr add_client_headers[] = { client_host_adder, client_cookie_adder, - client_x_forwarded_adder, client_xtra_adder, /* Temporarily disabled: client_accept_encoding_adder, */ connection_close_adder, NULL }; - const add_header_func_ptr add_server_headers[] = { connection_close_adder, NULL }; +/* The vanilla wafer. */ +static const char VANILLA_WAFER[] = + "NOTICE=TO_WHOM_IT_MAY_CONCERN_" + "Do_not_send_me_any_copyrighted_information_other_than_the_" + "document_that_I_am_requesting_or_any_of_its_necessary_components._" + "In_particular_do_not_send_me_any_cookies_that_" + "are_subject_to_a_claim_of_copyright_by_anybody._" + "Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_" + "(copyright_or_otherwise)_applying_to_any_cookie._"; + /********************************************************************* * * Function : flush_socket @@ -853,7 +982,7 @@ jb_err add_to_iob(struct client_state *csp, char *buf, int n) */ if (need > csp->config->buffer_limit) { - log_error(LOG_LEVEL_ERROR, "Buffer limit reached while extending the buffer (iob)"); + log_error(LOG_LEVEL_INFO, "Buffer limit reached while extending the buffer (iob)"); return JB_ERR_MEMORY; } @@ -940,7 +1069,7 @@ jb_err decompress_iob(struct client_state *csp) * This is to protect the parsing of gzipped data, * but it should(?) be valid for deflated data also. */ - log_error (LOG_LEVEL_ERROR, "Buffer too small decompressing iob"); + log_error(LOG_LEVEL_ERROR, "Buffer too small decompressing iob"); return JB_ERR_COMPRESS; } @@ -962,7 +1091,7 @@ jb_err decompress_iob(struct client_state *csp) || (*cur++ != (char)0x8b) || (*cur++ != Z_DEFLATED)) { - log_error (LOG_LEVEL_ERROR, "Invalid gzip header when decompressing"); + log_error(LOG_LEVEL_ERROR, "Invalid gzip header when decompressing"); return JB_ERR_COMPRESS; } else @@ -975,7 +1104,7 @@ jb_err decompress_iob(struct client_state *csp) if (flags & 0xe0) { /* The gzip header has reserved bits set; bail out. */ - log_error (LOG_LEVEL_ERROR, "Invalid gzip header flags when decompressing"); + log_error(LOG_LEVEL_ERROR, "Invalid gzip header flags when decompressing"); return JB_ERR_COMPRESS; } cur += 6; @@ -1014,14 +1143,14 @@ jb_err decompress_iob(struct client_state *csp) * The number of bytes to skip should be positive * and we'd like to stay in the buffer. */ - if((skip_bytes < 0) || (skip_bytes >= (csp->iob->eod - cur))) + if ((skip_bytes < 0) || (skip_bytes >= (csp->iob->eod - cur))) { - log_error (LOG_LEVEL_ERROR, + log_error(LOG_LEVEL_ERROR, "Unreasonable amount of bytes to skip (%d). Stopping decompression", skip_bytes); return JB_ERR_COMPRESS; } - log_error (LOG_LEVEL_INFO, + log_error(LOG_LEVEL_INFO, "Skipping %d bytes for gzip compression. Does this sound right?", skip_bytes); cur += skip_bytes; @@ -1055,7 +1184,7 @@ jb_err decompress_iob(struct client_state *csp) * the buffer end, we were obviously tricked to skip * too much. */ - log_error (LOG_LEVEL_ERROR, + log_error(LOG_LEVEL_ERROR, "Malformed gzip header detected. Aborting decompression."); return JB_ERR_COMPRESS; } @@ -1067,7 +1196,7 @@ jb_err decompress_iob(struct client_state *csp) * XXX: The debug level should be lowered * before the next stable release. */ - log_error (LOG_LEVEL_INFO, "Decompressing deflated iob: %d", *cur); + log_error(LOG_LEVEL_INFO, "Decompressing deflated iob: %d", *cur); /* * In theory (that is, according to RFC 1950), deflate-compressed * data should begin with a two-byte zlib header and have an @@ -1087,7 +1216,7 @@ jb_err decompress_iob(struct client_state *csp) } else { - log_error (LOG_LEVEL_ERROR, + log_error(LOG_LEVEL_ERROR, "Unable to determine compression format for decompression"); return JB_ERR_COMPRESS; } @@ -1105,7 +1234,7 @@ jb_err decompress_iob(struct client_state *csp) */ if (inflateInit2 (&zstr, -MAX_WBITS) != Z_OK) { - log_error (LOG_LEVEL_ERROR, "Error initializing decompression"); + log_error(LOG_LEVEL_ERROR, "Error initializing decompression"); return JB_ERR_COMPRESS; } @@ -1114,10 +1243,10 @@ jb_err decompress_iob(struct client_state *csp) * We don't modify the existing iob yet, so in case there * is error in decompression we can recover gracefully. */ - buf = zalloc (bufsize); + buf = zalloc(bufsize); if (NULL == buf) { - log_error (LOG_LEVEL_ERROR, "Out of memory decompressing iob"); + log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob"); return JB_ERR_MEMORY; } @@ -1386,13 +1515,11 @@ char *get_header_value(const struct list *header_list, const char *header_name) * Returns : JB_ERR_OK * *********************************************************************/ -jb_err scan_headers(struct client_state *csp) +static jb_err scan_headers(struct client_state *csp) { struct list_entry *h; /* Header */ jb_err err = JB_ERR_OK; - log_error(LOG_LEVEL_HEADER, "scanning headers for: %s", csp->http->url); - for (h = csp->headers->first; (err == JB_ERR_OK) && (h != NULL) ; h = h->next) { /* Header crunch()ed in previous run? -> ignore */ @@ -1401,8 +1528,6 @@ jb_err scan_headers(struct client_state *csp) err = header_tagger(csp, h->str); } - update_action_bits(csp); - return err; } @@ -1419,19 +1544,21 @@ jb_err scan_headers(struct client_state *csp) * As a side effect it frees the space used by the original * header lines. * + * XXX: should be split to remove the first_run hack. + * * Parameters : * 1 : pats = list of patterns to match against headers * 2 : more_headers = list of functions to add more * headers (client or server) * 3 : csp = Current client state (buffers, headers, etc...) * - * Returns : Single pointer to a fully formed header, or NULL - * on out-of-memory error. + * Returns : JB_ERR_OK in case off success, or + * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -char *sed(const struct parsers pats[], - const add_header_func_ptr more_headers[], - struct client_state *csp) +jb_err sed(const struct parsers pats[], + const add_header_func_ptr more_headers[], + struct client_state *csp) { struct list_entry *p; const struct parsers *v; @@ -1495,12 +1622,7 @@ char *sed(const struct parsers pats[], } } - if (err != JB_ERR_OK) - { - return NULL; - } - - return list_to_text(csp->headers); + return err; } @@ -1522,7 +1644,7 @@ char *sed(const struct parsers pats[], * Returns : JB_ERR_OK on success and always succeeds * *********************************************************************/ -jb_err header_tagger(struct client_state *csp, char *header) +static jb_err header_tagger(struct client_state *csp, char *header) { int wanted_filter_type; int multi_action_index; @@ -1602,8 +1724,11 @@ jb_err header_tagger(struct client_state *csp, char *header) char *modified_tag = NULL; char *tag = header; size_t size = header_length; + pcrs_job *joblist = b->joblist; + + if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b); - if (NULL == b->joblist) + if (NULL == joblist) { log_error(LOG_LEVEL_RE_FILTER, "Tagger %s has empty joblist. Nothing to do.", b->name); @@ -1611,7 +1736,7 @@ jb_err header_tagger(struct client_state *csp, char *header) } /* execute their pcrs_joblist on the header. */ - for (job = b->joblist; NULL != job; job = job->next) + for (job = joblist; NULL != job; job = job->next) { const int hits = pcrs_execute(job, tag, size, &modified_tag, &size); @@ -1638,14 +1763,28 @@ jb_err header_tagger(struct client_state *csp, char *header) } } + if (b->dynamic) pcrs_free_joblist(joblist); + /* If this tagger matched */ if (tag != header) { - /* and there is something left to save, */ - if (0 < size) + if (0 == size) + { + /* + * There is to technical limitation which makes + * it impossible to use empty tags, but I assume + * no one would do it intentionally. + */ + freez(tag); + log_error(LOG_LEVEL_INFO, + "Tagger \'%s\' created an empty tag. Ignored.", + b->name); + continue; + } + + if (!list_contains_item(csp->tags, tag)) { - /* enlist a unique version of it as tag. */ - if (JB_ERR_OK != enlist_unique(csp->tags, tag, 0)) + if (JB_ERR_OK != enlist(csp->tags, tag)) { log_error(LOG_LEVEL_ERROR, "Insufficient memory to add tag \'%s\', " @@ -1654,13 +1793,35 @@ jb_err header_tagger(struct client_state *csp, char *header) } else { + char *action_message; + /* + * update the action bits right away, to make + * tagging based on tags set by earlier taggers + * of the same kind possible. + */ + if (update_action_bits_for_tag(csp, tag)) + { + action_message = "Action bits updated accordingly."; + } + else + { + action_message = "No action bits update necessary."; + } + log_error(LOG_LEVEL_HEADER, - "Adding tag \'%s\' created by header tagger \'%s\'", - tag, b->name); + "Tagger \'%s\' added tag \'%s\'. %s", + b->name, tag, action_message); } } + else + { + /* XXX: Is this log-worthy? */ + log_error(LOG_LEVEL_HEADER, + "Tagger \'%s\' didn't add tag \'%s\'. " + "Tag already present", b->name, tag); + } freez(tag); - } + } /* if the tagger matched */ } /* if the tagger applies */ } /* for every tagger that could apply */ } /* for all filters */ @@ -1690,7 +1851,7 @@ jb_err header_tagger(struct client_state *csp, char *header) * Returns : JB_ERR_OK on success and always succeeds * *********************************************************************/ -jb_err filter_header(struct client_state *csp, char **header) +static jb_err filter_header(struct client_state *csp, char **header) { int hits=0; int matches; @@ -1707,6 +1868,11 @@ jb_err filter_header(struct client_state *csp, char **header) int wanted_filter_type; int multi_action_index; + if (csp->flags & CSP_FLAG_NO_FILTERING) + { + return JB_ERR_OK; + } + if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) { wanted_filter_type = FT_SERVER_HEADER_FILTER; @@ -1775,8 +1941,11 @@ jb_err filter_header(struct client_state *csp, char **header) if (strcmp(b->name, filtername->str) == 0) { int current_hits = 0; + pcrs_job *joblist = b->joblist; + + if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b); - if ( NULL == b->joblist ) + if (NULL == joblist) { log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name); continue; @@ -1786,7 +1955,7 @@ jb_err filter_header(struct client_state *csp, char **header) *header, size, b->name); /* Apply all jobs from the joblist */ - for (job = b->joblist; NULL != job; job = job->next) + for (job = joblist; NULL != job; job = job->next) { matches = pcrs_execute(job, *header, size, &newheader, &size); if ( 0 < matches ) @@ -1806,13 +1975,16 @@ jb_err filter_header(struct client_state *csp, char **header) /* RegEx failure */ log_error(LOG_LEVEL_ERROR, "Filtering \'%s\' with \'%s\' didn't work out: %s", *header, b->name, pcrs_strerror(matches)); - if( newheader != NULL) + if (newheader != NULL) { log_error(LOG_LEVEL_ERROR, "Freeing what's left: %s", newheader); freez(newheader); } } } + + if (b->dynamic) pcrs_free_joblist(joblist); + log_error(LOG_LEVEL_RE_FILTER, "... produced %d hits (new size %d).", current_hits, size); hits += current_hits; } @@ -1854,7 +2026,7 @@ jb_err filter_header(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err connection(struct client_state *csp, char **header) +static jb_err connection(struct client_state *csp, char **header) { char *old_header = *header; @@ -1902,13 +2074,14 @@ jb_err connection(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err crumble(struct client_state *csp, char **header) +static jb_err crumble(struct client_state *csp, char **header) { log_error(LOG_LEVEL_HEADER, "crumble crunched: %s!", *header); freez(*header); return JB_ERR_OK; } + /********************************************************************* * * Function : crunch_server_header @@ -1926,7 +2099,7 @@ jb_err crumble(struct client_state *csp, char **header) * Returns : JB_ERR_OK on success and always succeeds * *********************************************************************/ -jb_err crunch_server_header(struct client_state *csp, char **header) +static jb_err crunch_server_header(struct client_state *csp, char **header) { const char *crunch_pattern; @@ -1969,10 +2142,10 @@ jb_err crunch_server_header(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_content_type(struct client_state *csp, char **header) +static jb_err server_content_type(struct client_state *csp, char **header) { /* Remove header if it isn't the first Content-Type header */ - if(csp->content_type && (csp->content_type != CT_TABOO)) + if ((csp->content_type & CT_DECLARED)) { /* * Another, slightly slower, way to see if @@ -1988,6 +2161,11 @@ jb_err server_content_type(struct client_state *csp, char **header) return JB_ERR_OK; } + /* + * Signal that the Content-Type has been set. + */ + csp->content_type |= CT_DECLARED; + if (!(csp->content_type & CT_TABOO)) { if ((strstr(*header, " text/") && !strstr(*header, "plain")) @@ -2004,29 +2182,8 @@ jb_err server_content_type(struct client_state *csp, char **header) { csp->content_type |= CT_JPEG; } - else - { - csp->content_type = 0; - } - } - /* - * Are we enabling text mode by force? - */ - if (csp->action->flags & ACTION_FORCE_TEXT_MODE) - { - /* - * Do we really have to? - */ - if (csp->content_type & CT_TEXT) - { - log_error(LOG_LEVEL_HEADER, "Text mode is already enabled."); - } - else - { - csp->content_type |= CT_TEXT; - log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!"); - } } + /* * Are we messing with the content type? */ @@ -2036,7 +2193,7 @@ jb_err server_content_type(struct client_state *csp, char **header) * Make sure the user doesn't accidently * change the content type of binary documents. */ - if (csp->content_type & CT_TEXT) + if ((csp->content_type & CT_TEXT) || (csp->action->flags & ACTION_FORCE_TEXT_MODE)) { freez(*header); *header = strdup("Content-Type: "); @@ -2055,6 +2212,7 @@ jb_err server_content_type(struct client_state *csp, char **header) "Enable force-text-mode if you know what you're doing.", *header); } } + return JB_ERR_OK; } @@ -2079,7 +2237,7 @@ jb_err server_content_type(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_transfer_coding(struct client_state *csp, char **header) +static jb_err server_transfer_coding(struct client_state *csp, char **header) { /* * Turn off pcrs and gif filtering if body compressed @@ -2147,7 +2305,7 @@ jb_err server_transfer_coding(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_content_encoding(struct client_state *csp, char **header) +static jb_err server_content_encoding(struct client_state *csp, char **header) { #ifdef FEATURE_ZLIB if ((csp->flags & CSP_FLAG_MODIFIED) @@ -2227,7 +2385,7 @@ jb_err server_content_encoding(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_content_length(struct client_state *csp, char **header) +static jb_err server_content_length(struct client_state *csp, char **header) { const size_t max_header_length = 80; @@ -2269,7 +2427,7 @@ jb_err server_content_length(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_content_md5(struct client_state *csp, char **header) +static jb_err server_content_md5(struct client_state *csp, char **header) { if (csp->flags & CSP_FLAG_MODIFIED) { @@ -2280,6 +2438,7 @@ jb_err server_content_md5(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : server_content_disposition @@ -2298,7 +2457,7 @@ jb_err server_content_md5(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_content_disposition(struct client_state *csp, char **header) +static jb_err server_content_disposition(struct client_state *csp, char **header) { const char *newval; @@ -2343,6 +2502,7 @@ jb_err server_content_disposition(struct client_state *csp, char **header) return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } + /********************************************************************* * * Function : server_last_modified @@ -2362,7 +2522,7 @@ jb_err server_content_disposition(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_last_modified(struct client_state *csp, char **header) +static jb_err server_last_modified(struct client_state *csp, char **header) { const char *newval; char buf[BUFFER_SIZE]; @@ -2440,7 +2600,16 @@ jb_err server_last_modified(struct client_state *csp, char **header) rtime = (long int)difftime(now, last_modified); if (rtime) { + int negative = 0; + + if (rtime < 0) + { + rtime *= -1; + negative = 1; + log_error(LOG_LEVEL_HEADER, "Server time in the future."); + } rtime = pick_from_range(rtime); + if (negative) rtime *= -1; last_modified += rtime; #ifdef HAVE_GMTIME_R timeptr = gmtime_r(&last_modified, &gmt); @@ -2462,7 +2631,7 @@ jb_err server_last_modified(struct client_state *csp, char **header) return JB_ERR_MEMORY; } - if(LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */ + if (LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */ { days = rtime / (3600 * 24); hours = rtime / 3600 % 24; @@ -2504,7 +2673,7 @@ jb_err server_last_modified(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_accept_encoding(struct client_state *csp, char **header) +static jb_err client_accept_encoding(struct client_state *csp, char **header) { if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0) { @@ -2549,7 +2718,7 @@ jb_err client_accept_encoding(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_te(struct client_state *csp, char **header) +static jb_err client_te(struct client_state *csp, char **header) { if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0) { @@ -2560,6 +2729,7 @@ jb_err client_te(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_referrer @@ -2578,115 +2748,67 @@ jb_err client_te(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_referrer(struct client_state *csp, char **header) +static jb_err client_referrer(struct client_state *csp, char **header) { - const char *newval; - const char *host; - char *referer; - size_t hostlenght; + const char *parameter; + /* booleans for parameters we have to check multiple times */ + int parameter_conditional_block; + int parameter_conditional_forge; #ifdef FEATURE_FORCE_LOAD - /* Since the referrer can include the prefix even + /* + * Since the referrer can include the prefix even * if the request itself is non-forced, we must - * clean it unconditionally + * clean it unconditionally. + * + * XXX: strclean is too broad */ strclean(*header, FORCE_PREFIX); #endif /* def FEATURE_FORCE_LOAD */ - /* - * Are we sending referer? - */ if ((csp->action->flags & ACTION_HIDE_REFERER) == 0) { + /* Nothing left to do */ return JB_ERR_OK; } - newval = csp->action->string[ACTION_STRING_REFERER]; + parameter = csp->action->string[ACTION_STRING_REFERER]; + assert(parameter != NULL); + parameter_conditional_block = (0 == strcmpic(parameter, "conditional-block")); + parameter_conditional_forge = (0 == strcmpic(parameter, "conditional-forge")); - if ((0 != strcmpic(newval, "conditional-block"))) - { - freez(*header); - } - if ((newval == NULL) || (0 == strcmpic(newval, "block")) ) + if (!parameter_conditional_block && !parameter_conditional_forge) { /* - * Blocking referer + * As conditional-block and conditional-forge are the only + * parameters that rely on the original referrer, we can + * remove it now for all the others. */ + freez(*header); + } + + if (0 == strcmpic(parameter, "block")) + { log_error(LOG_LEVEL_HEADER, "Referer crunched!"); return JB_ERR_OK; } - else if (0 == strcmpic(newval, "conditional-block")) + else if (parameter_conditional_block || parameter_conditional_forge) { - /* - * Block referer if host has changed. - */ - - if (NULL == (host = strdup(csp->http->hostport))) - { - freez(*header); - log_error(LOG_LEVEL_HEADER, "Referer crunched! Couldn't allocate memory for temporary host copy."); - return JB_ERR_MEMORY; - } - if (NULL == (referer = strdup(*header))) - { - freez(*header); - freez(host); - log_error(LOG_LEVEL_HEADER, "Referer crunched! Couldn't allocate memory for temporary referer copy."); - return JB_ERR_MEMORY; - } - hostlenght = strlen(host); - if ( hostlenght < (strlen(referer)-17) ) /*referer begins with 'Referer: http[s]://'*/ - { - /*Shorten referer to make sure the referer is blocked - *if www.example.org/www.example.com-shall-see-the-referer/ - *links to www.example.com/ - */ - referer[hostlenght+17] = '\0'; - } - if ( 0 == strstr(referer, host)) /*Host has changed*/ - { - log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header); - freez(*header); - } - else - { - log_error(LOG_LEVEL_HEADER, "%s (not modified, still on %s)", *header, host); - } - freez(referer); - freez(host); - return JB_ERR_OK; + return handle_conditional_hide_referrer_parameter(header, + csp->http->hostport, parameter_conditional_block); } - else if (0 != strcmpic(newval, "forge")) + else if (0 == strcmpic(parameter, "forge")) { - /* - * We have a specific (fixed) referer we want to send. - */ - if ((0 != strncmpic(newval, "http://", 7)) && (0 != strncmpic(newval, "https://", 8))) - { - log_error(LOG_LEVEL_HEADER, "Parameter: +referrer{%s} is a bad idea, but I don't care.", newval); - } - *header = strdup("Referer: "); - string_append(header, newval); - log_error(LOG_LEVEL_HEADER, "Referer overwritten with: %s", *header); - - return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; + return create_forged_referrer(header, csp->http->hostport); } else { - /* - * Forge a referer as http://[hostname:port of REQUEST]/ - * to fool stupid checks for in-site links - */ - - *header = strdup("Referer: http://"); - string_append(header, csp->http->hostport); - string_append(header, "/"); - log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); - - return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; + /* interpret parameter as user-supplied referer to fake */ + return create_fake_referrer(header, parameter); } } + /********************************************************************* * * Function : client_accept_language @@ -2705,7 +2827,7 @@ jb_err client_referrer(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_accept_language(struct client_state *csp, char **header) +static jb_err client_accept_language(struct client_state *csp, char **header) { const char *newval; @@ -2752,6 +2874,7 @@ jb_err client_accept_language(struct client_state *csp, char **header) return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } + /********************************************************************* * * Function : crunch_client_header @@ -2769,7 +2892,7 @@ jb_err client_accept_language(struct client_state *csp, char **header) * Returns : JB_ERR_OK on success and always succeeds * *********************************************************************/ -jb_err crunch_client_header(struct client_state *csp, char **header) +static jb_err crunch_client_header(struct client_state *csp, char **header) { const char *crunch_pattern; @@ -2808,7 +2931,7 @@ jb_err crunch_client_header(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_uagent(struct client_state *csp, char **header) +static jb_err client_uagent(struct client_state *csp, char **header) { const char *newval; @@ -2832,6 +2955,7 @@ jb_err client_uagent(struct client_state *csp, char **header) return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } + /********************************************************************* * * Function : client_ua @@ -2849,7 +2973,7 @@ jb_err client_uagent(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_ua(struct client_state *csp, char **header) +static jb_err client_ua(struct client_state *csp, char **header) { if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0) { @@ -2879,7 +3003,7 @@ jb_err client_ua(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_from(struct client_state *csp, char **header) +static jb_err client_from(struct client_state *csp, char **header) { const char *newval; @@ -2930,7 +3054,7 @@ jb_err client_from(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_send_cookie(struct client_state *csp, char **header) +static jb_err client_send_cookie(struct client_state *csp, char **header) { if (csp->action->flags & ACTION_NO_COOKIE_READ) { @@ -2962,19 +3086,7 @@ jb_err client_send_cookie(struct client_state *csp, char **header) *********************************************************************/ jb_err client_x_forwarded(struct client_state *csp, char **header) { - if ((csp->action->flags & ACTION_HIDE_FORWARDED) == 0) - { - /* Save it so we can re-add it later */ - freez(csp->x_forwarded); - csp->x_forwarded = *header; - - /* - * Always set *header = NULL, since this information - * will be sent at the end of the header. - */ - *header = NULL; - } - else + if ((csp->action->flags & ACTION_HIDE_FORWARDED) != 0) { freez(*header); log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!"); @@ -3002,7 +3114,7 @@ jb_err client_x_forwarded(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_max_forwards(struct client_state *csp, char **header) +static jb_err client_max_forwards(struct client_state *csp, char **header) { int max_forwards; @@ -3023,17 +3135,6 @@ jb_err client_max_forwards(struct client_state *csp, char **header) log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); } - else - { - /* - * Not supposed to be reached. direct_response() which - * was already called earlier in chat() should have - * intercepted the request. - */ - log_error(LOG_LEVEL_ERROR, - "Non-intercepted %s request with Max-Forwards zero!", csp->http->gpc); - assert(max_forwards != 0); - } } else { @@ -3068,7 +3169,7 @@ jb_err client_max_forwards(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_host(struct client_state *csp, char **header) +static jb_err client_host(struct client_state *csp, char **header) { char *p, *q; @@ -3125,6 +3226,7 @@ jb_err client_host(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_if_modified_since @@ -3142,7 +3244,7 @@ jb_err client_host(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_if_modified_since(struct client_state *csp, char **header) +static jb_err client_if_modified_since(struct client_state *csp, char **header) { char newheader[50]; #ifdef HAVE_GMTIME_R @@ -3189,11 +3291,11 @@ jb_err client_if_modified_since(struct client_state *csp, char **header) else { rtime = strtol(newval, &endptr, 0); - if(rtime) + if (rtime) { log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)", *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es"); - if(rtime < 0) + if (rtime < 0) { rtime *= -1; negative = 1; @@ -3228,7 +3330,7 @@ jb_err client_if_modified_since(struct client_state *csp, char **header) return JB_ERR_MEMORY; } - if(LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */ + if (LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */ { hours = rtime / 3600; minutes = rtime / 60 % 60; @@ -3245,6 +3347,7 @@ jb_err client_if_modified_since(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_if_none_match @@ -3262,7 +3365,7 @@ jb_err client_if_modified_since(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_if_none_match(struct client_state *csp, char **header) +static jb_err client_if_none_match(struct client_state *csp, char **header) { if (csp->action->flags & ACTION_CRUNCH_IF_NONE_MATCH) { @@ -3273,6 +3376,7 @@ jb_err client_if_none_match(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_x_filter @@ -3307,9 +3411,8 @@ jb_err client_x_filter(struct client_state *csp, char **header) } else { - csp->content_type = CT_TABOO; - csp->action->flags &= ~ACTION_FILTER_SERVER_HEADERS; - csp->action->flags &= ~ACTION_FILTER_CLIENT_HEADERS; + csp->content_type = CT_TABOO; /* XXX: This hack shouldn't be necessary */ + csp->flags |= CSP_FLAG_NO_FILTERING; log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering."); } log_error(LOG_LEVEL_HEADER, "Crunching %s", *header); @@ -3319,6 +3422,40 @@ jb_err client_x_filter(struct client_state *csp, char **header) return JB_ERR_OK; } + +/********************************************************************* + * + * Function : client_range + * + * Description : Removes Range and If-Range headers if content + * filtering is enabled. If the client's version of + * the document has been altered by Privoxy, the server + * could interpret the range differently than the client + * intended in which case the user could end up with + * corrupted content. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : header = On input, pointer to header to modify. + * On output, pointer to the modified header, or NULL + * to remove the header. This function frees the + * original string if necessary. + * + * Returns : JB_ERR_OK + * + *********************************************************************/ +static jb_err client_range(struct client_state *csp, char **header) +{ + if (content_filters_enabled(csp)) + { + log_error(LOG_LEVEL_HEADER, "Content filtering is enabled." + " Crunching: \'%s\' to prevent range-mismatch problems.", *header); + freez(*header); + } + + return JB_ERR_OK; +} + /* the following functions add headers directly to the header list */ /********************************************************************* @@ -3335,7 +3472,7 @@ jb_err client_x_filter(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_host_adder(struct client_state *csp) +static jb_err client_host_adder(struct client_state *csp) { char *p; jb_err err; @@ -3377,9 +3514,8 @@ jb_err client_host_adder(struct client_state *csp) * * Function : client_cookie_adder * - * Description : Used in the add_client_headers list. Called from `sed'. - * - * XXX: Remove csp->cookie_list which is no longer used. + * Description : Used in the add_client_headers list to add "wafers". + * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) @@ -3390,45 +3526,39 @@ jb_err client_host_adder(struct client_state *csp) *********************************************************************/ jb_err client_cookie_adder(struct client_state *csp) { - struct list_entry *lst; char *tmp; - struct list_entry *list1 = csp->cookie_list->first; - struct list_entry *list2 = csp->action->multi[ACTION_MULTI_WAFER]->first; - int first_cookie = 1; + struct list_entry *wafer; + struct list_entry *wafer_list; jb_err err; - if ((list1 == NULL) && (list2 == NULL)) + /* + * If the user has not supplied any wafers, and the user has not + * told us to suppress the vanilla wafer, then send the vanilla wafer. + */ + if ((0 != (csp->action->flags & ACTION_VANILLA_WAFER)) + && list_is_empty(csp->action->multi[ACTION_MULTI_WAFER])) { - /* Nothing to do */ - return JB_ERR_OK; + enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER); } - tmp = strdup("Cookie: "); + wafer_list = csp->action->multi[ACTION_MULTI_WAFER]->first; - for (lst = list1; lst ; lst = lst->next) + if (NULL == wafer_list) { - if (first_cookie) - { - first_cookie = 0; - } - else - { - string_append(&tmp, "; "); - } - string_append(&tmp, lst->str); + /* Nothing to do */ + return JB_ERR_OK; } - for (lst = list2; lst ; lst = lst->next) + tmp = strdup("Cookie: "); + + for (wafer = wafer_list; (NULL != tmp) && (NULL != wafer); wafer = wafer->next) { - if (first_cookie) - { - first_cookie = 0; - } - else + if (wafer != wafer_list) { + /* As this isn't the first wafer, we need a delimiter. */ string_append(&tmp, "; "); } - string_join(&tmp, cookie_encode(lst->str)); + string_join(&tmp, cookie_encode(wafer->str)); } if (tmp == NULL) @@ -3443,6 +3573,7 @@ jb_err client_cookie_adder(struct client_state *csp) } +#if 0 /********************************************************************* * * Function : client_accept_encoding_adder @@ -3459,10 +3590,8 @@ jb_err client_cookie_adder(struct client_state *csp) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_accept_encoding_adder(struct client_state *csp) +static jb_err client_accept_encoding_adder(struct client_state *csp) { - assert(0); /* Not in use */ - if ( ((csp->action->flags & ACTION_NO_COMPRESSION) != 0) && (!strcmpic(csp->http->ver, "HTTP/1.1")) ) { @@ -3471,6 +3600,7 @@ jb_err client_accept_encoding_adder(struct client_state *csp) return JB_ERR_OK; } +#endif /********************************************************************* @@ -3486,7 +3616,7 @@ jb_err client_accept_encoding_adder(struct client_state *csp) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err client_xtra_adder(struct client_state *csp) +static jb_err client_xtra_adder(struct client_state *csp) { struct list_entry *lst; jb_err err; @@ -3507,53 +3637,6 @@ jb_err client_xtra_adder(struct client_state *csp) } -/********************************************************************* - * - * Function : client_x_forwarded_adder - * - * Description : Used in the add_client_headers list. Called from `sed'. - * - * Parameters : - * 1 : csp = Current client state (buffers, headers, etc...) - * - * Returns : JB_ERR_OK on success, or - * JB_ERR_MEMORY on out-of-memory error. - * - *********************************************************************/ -jb_err client_x_forwarded_adder(struct client_state *csp) -{ - char *p = NULL; - jb_err err; - - if ((csp->action->flags & ACTION_HIDE_FORWARDED) != 0) - { - return JB_ERR_OK; - } - - if (csp->x_forwarded) - { - p = strdup(csp->x_forwarded); - string_append(&p, ", "); - } - else - { - p = strdup("X-Forwarded-For: "); - } - string_append(&p, csp->ip_addr_str); - - if (p == NULL) - { - return JB_ERR_MEMORY; - } - - log_error(LOG_LEVEL_HEADER, "addh: %s", p); - err = enlist(csp->headers, p); - free(p); - - return err; -} - - /********************************************************************* * * Function : connection_close_adder @@ -3571,7 +3654,7 @@ jb_err client_x_forwarded_adder(struct client_state *csp) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err connection_close_adder(struct client_state *csp) +static jb_err connection_close_adder(struct client_state *csp) { const unsigned int flags = csp->flags; @@ -3619,7 +3702,7 @@ jb_err connection_close_adder(struct client_state *csp) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_http(struct client_state *csp, char **header) +static jb_err server_http(struct client_state *csp, char **header) { sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status)); if (csp->http->status == 206) @@ -3629,8 +3712,21 @@ jb_err server_http(struct client_state *csp, char **header) if ((csp->action->flags & ACTION_DOWNGRADE) != 0) { - (*header)[7] = '0'; - log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0"); + /* XXX: Should we do a real validity check here? */ + if (strlen(*header) > 8) + { + (*header)[7] = '0'; + log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0"); + } + else + { + /* + * XXX: Should we block the request or + * enlist a valid status code line here? + */ + log_error(LOG_LEVEL_INFO, "Malformed server response detected. " + "Downgrading to HTTP/1.0 impossible."); + } } return JB_ERR_OK; @@ -3661,7 +3757,7 @@ jb_err server_http(struct client_state *csp, char **header) * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ -jb_err server_set_cookie(struct client_state *csp, char **header) +static jb_err server_set_cookie(struct client_state *csp, char **header) { time_t now; time_t cookie_time; @@ -3885,6 +3981,7 @@ int strclean(const char *string, const char *substring) } #endif /* def FEATURE_FORCE_LOAD */ + /********************************************************************* * * Function : parse_header_time @@ -3900,7 +3997,7 @@ int strclean(const char *string, const char *substring) * JB_ERR_PARSE otherwise. * *********************************************************************/ -jb_err parse_header_time(const char *header_time, time_t *result) +static jb_err parse_header_time(const char *header_time, time_t *result) { struct tm gmt; @@ -3934,6 +4031,7 @@ jb_err parse_header_time(const char *header_time, time_t *result) } + /********************************************************************* * * Function : get_destination_from_headers @@ -4016,6 +4114,142 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ } +/********************************************************************* + * + * Function : create_forged_referrer + * + * Description : Helper for client_referrer to forge a referer as + * 'http://[hostname:port/' to fool stupid + * checks for in-site links + * + * Parameters : + * 1 : header = Pointer to header pointer + * 2 : hostport = Host and optionally port as string + * + * Returns : JB_ERR_OK in case of success, or + * JB_ERR_MEMORY in case of memory problems. + * + *********************************************************************/ +static jb_err create_forged_referrer(char **header, const char *hostport) +{ + assert(NULL == *header); + + *header = strdup("Referer: http://"); + string_append(header, hostport); + string_append(header, "/"); + + if (NULL == *header) + { + return JB_ERR_MEMORY; + } + + log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); + + return JB_ERR_OK; + +} + + +/********************************************************************* + * + * Function : create_fake_referrer + * + * Description : Helper for client_referrer to create a fake referrer + * based on a string supplied by the user. + * + * Parameters : + * 1 : header = Pointer to header pointer + * 2 : hosthost = Referrer to fake + * + * Returns : JB_ERR_OK in case of success, or + * JB_ERR_MEMORY in case of memory problems. + * + *********************************************************************/ +static jb_err create_fake_referrer(char **header, const char *fake_referrer) +{ + assert(NULL == *header); + + if ((0 != strncmpic(fake_referrer, "http://", 7)) && (0 != strncmpic(fake_referrer, "https://", 8))) + { + log_error(LOG_LEVEL_HEADER, + "Parameter: +hide-referrer{%s} is a bad idea, but I don't care.", fake_referrer); + } + *header = strdup("Referer: "); + string_append(header, fake_referrer); + + if (NULL == *header) + { + return JB_ERR_MEMORY; + } + + log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header); + + return JB_ERR_OK; + +} + + +/********************************************************************* + * + * Function : handle_conditional_hide_referrer_parameter + * + * Description : Helper for client_referrer to crunch or forge + * the referrer header if the host has changed. + * + * Parameters : + * 1 : header = Pointer to header pointer + * 2 : host = The target host (may include the port) + * 3 : parameter_conditional_block = Boolean to signal + * if we're in conditional-block mode. If not set, + * we're in conditional-forge mode. + * + * Returns : JB_ERR_OK in case of success, or + * JB_ERR_MEMORY in case of memory problems. + * + *********************************************************************/ +static jb_err handle_conditional_hide_referrer_parameter(char **header, + const char *host, const int parameter_conditional_block) +{ + char *referer = strdup(*header); + const size_t hostlenght = strlen(host); + + if (NULL == referer) + { + freez(*header); + return JB_ERR_MEMORY; + } + + /* referer begins with 'Referer: http[s]://' */ + if (hostlenght < (strlen(referer)-17)) + { + /* + * Shorten referer to make sure the referer is blocked + * if www.example.org/www.example.com-shall-see-the-referer/ + * links to www.example.com/ + */ + referer[hostlenght+17] = '\0'; + } + if (NULL == strstr(referer, host)) + { + /* Host has changed */ + if (parameter_conditional_block) + { + log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header); + freez(*header); + } + else + { + freez(*header); + freez(referer); + return create_forged_referrer(header, host); + } + } + freez(referer); + + return JB_ERR_OK; + +} + /* Local Variables: tab-width: 3