X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=3b08cf91ff2885399eff80377319e69f8e74f28c;hp=397deee64ef2a45090e7528d7e788c09cd315195;hb=36f5fa200c2685ff053539184c83f1d909f0da05;hpb=939b75b6da234e281a9701f572cdebe392403dcc diff --git a/parsers.c b/parsers.c index 397deee6..3b08cf91 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.107 2007/08/28 18:16:32 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.121 2008/01/05 21:37:03 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -44,6 +44,64 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.107 2007/08/28 18:16:32 fabiankei * * Revisions : * $Log: parsers.c,v $ + * Revision 1.121 2008/01/05 21:37:03 fabiankeil + * Let client_range() also handle Request-Range headers + * which apparently are still supported by many servers. + * + * Revision 1.120 2008/01/04 17:43:45 fabiankeil + * Improve the warning messages that get logged if the action files + * "enable" filters but no filters of that type have been loaded. + * + * Revision 1.119 2007/12/28 18:32:51 fabiankeil + * In server_content_type(): + * - Don't require leading white space when detecting image content types. + * - Change '... not replaced ...' message to sound less crazy if the text + * type actually is 'text/plain'. + * - Mark the 'text/plain == binary data' assumption for removal. + * - Remove a bunch of trailing white space. + * + * Revision 1.118 2007/12/28 16:56:35 fabiankeil + * Minor server_content_disposition() changes: + * - Don't regenerate the header name all lower-case. + * - Some white space fixes. + * - Remove useless log message in case of ENOMEM. + * + * Revision 1.117 2007/12/06 18:11:50 fabiankeil + * Garbage-collect the code to add a X-Forwarded-For + * header as it seems to be mostly used by accident. + * + * 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. @@ -782,6 +840,7 @@ 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); @@ -796,9 +855,13 @@ 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 client_x_forwarded_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 }, { "user-agent:", 11, client_uagent }, @@ -816,6 +879,9 @@ 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 }, + { "Request-Range:", 14, client_range }, + { "If-Range:", 9, client_range }, { "X-Filter:", 9, client_x_filter }, { "*", 0, crunch_client_header }, { "*", 0, filter_header }, @@ -850,19 +916,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 @@ -935,7 +1009,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; } @@ -1096,7 +1170,7 @@ 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, "Unreasonable amount of bytes to skip (%d). Stopping decompression", @@ -1473,8 +1547,6 @@ 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 */ @@ -1499,6 +1571,8 @@ static 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 @@ -1638,7 +1712,8 @@ static jb_err header_tagger(struct client_state *csp, char *header) if (0 == found_filters) { - log_error(LOG_LEVEL_ERROR, "Unable to get current state of regex tagging."); + log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " + "tagging enabled, but no taggers available."); return(JB_ERR_OK); } @@ -1855,7 +1930,8 @@ static jb_err filter_header(struct client_state *csp, char **header) if (0 == found_filters) { - log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering."); + log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " + "header filtering enabled, but no matching filters available."); return(JB_ERR_OK); } @@ -1928,7 +2004,7 @@ static 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); @@ -2034,6 +2110,7 @@ static jb_err crumble(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : crunch_server_header @@ -2120,39 +2197,40 @@ static jb_err server_content_type(struct client_state *csp, char **header) if (!(csp->content_type & CT_TABOO)) { - if ((strstr(*header, " text/") && !strstr(*header, "plain")) + /* + * XXX: The assumption that text/plain is a sign of + * binary data seems to be somewhat unreasonable nowadays + * and should be dropped after 3.0.8 is out. + */ + if ((strstr(*header, "text/") && !strstr(*header, "plain")) || strstr(*header, "xml") || strstr(*header, "application/x-javascript")) { csp->content_type |= CT_TEXT; } - else if (strstr(*header, " image/gif")) + else if (strstr(*header, "image/gif")) { csp->content_type |= CT_GIF; } - else if (strstr(*header, " image/jpeg")) - { - csp->content_type |= CT_JPEG; - } } /* * Are we messing with the content type? - */ + */ if (csp->action->flags & ACTION_CONTENT_TYPE_OVERWRITE) - { + { /* * Make sure the user doesn't accidently * change the content type of binary documents. - */ + */ if ((csp->content_type & CT_TEXT) || (csp->action->flags & ACTION_FORCE_TEXT_MODE)) - { + { freez(*header); *header = strdup("Content-Type: "); string_append(header, csp->action->string[ACTION_STRING_CONTENT_TYPE]); if (header == NULL) - { + { log_error(LOG_LEVEL_HEADER, "Insufficient memory to replace Content-Type!"); return JB_ERR_MEMORY; } @@ -2160,10 +2238,11 @@ static jb_err server_content_type(struct client_state *csp, char **header) } else { - log_error(LOG_LEVEL_HEADER, "%s not replaced. It doesn't look like text. " - "Enable force-text-mode if you know what you're doing.", *header); + log_error(LOG_LEVEL_HEADER, "%s not replaced. " + "It doesn't look like a content type that should be filtered. " + "Enable force-text-mode if you know what you're doing.", *header); } - } + } return JB_ERR_OK; } @@ -2390,11 +2469,12 @@ static jb_err server_content_md5(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : server_content_disposition * - * Description : If enabled, blocks or modifies the "content-disposition" header. + * Description : If enabled, blocks or modifies the "Content-Disposition" header. * Called from `sed'. * * Parameters : @@ -2413,17 +2493,17 @@ static jb_err server_content_disposition(struct client_state *csp, char **header const char *newval; /* - * Are we messing with the content-disposition header? + * Are we messing with the Content-Disposition header? */ if ((csp->action->flags & ACTION_HIDE_CONTENT_DISPOSITION) == 0) { - /*Me tinks not*/ + /* Me tinks not */ return JB_ERR_OK; } newval = csp->action->string[ACTION_STRING_CONTENT_DISPOSITION]; - if ((newval == NULL) || (0 == strcmpic(newval, "block")) ) + if ((newval == NULL) || (0 == strcmpic(newval, "block"))) { /* * Blocking content-disposition header @@ -2435,24 +2515,22 @@ static jb_err server_content_disposition(struct client_state *csp, char **header else { /* - * Replacing content-disposition header + * Replacing Content-Disposition header */ freez(*header); - *header = strdup("content-disposition: "); - string_append(header, newval); + *header = strdup("Content-Disposition: "); + string_append(header, newval); - if (*header == NULL) + if (*header != NULL) { - log_error(LOG_LEVEL_HEADER, "Insufficent memory. content-disposition header not fully replaced."); - } - else - { - log_error(LOG_LEVEL_HEADER, "content-disposition header crunched and replaced with: %s", *header); + log_error(LOG_LEVEL_HEADER, + "Content-Disposition header crunched and replaced with: %s", *header); } } return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } + /********************************************************************* * * Function : server_last_modified @@ -2550,7 +2628,16 @@ static 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); @@ -2572,7 +2659,7 @@ static 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; @@ -2670,6 +2757,7 @@ static jb_err client_te(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_referrer @@ -2690,113 +2778,65 @@ static jb_err client_te(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 @@ -2943,6 +2983,7 @@ static jb_err client_uagent(struct client_state *csp, char **header) return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } + /********************************************************************* * * Function : client_ua @@ -3073,19 +3114,7 @@ static 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!"); @@ -3134,17 +3163,6 @@ static 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 { @@ -3236,6 +3254,7 @@ static jb_err client_host(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_if_modified_since @@ -3300,11 +3319,11 @@ static 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; @@ -3339,7 +3358,7 @@ static 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; @@ -3356,6 +3375,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_if_none_match @@ -3384,6 +3404,7 @@ static jb_err client_if_none_match(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_x_filter @@ -3429,6 +3450,40 @@ jb_err client_x_filter(struct client_state *csp, char **header) return JB_ERR_OK; } + +/********************************************************************* + * + * Function : client_range + * + * Description : Removes Range, Request-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 */ /********************************************************************* @@ -3501,9 +3556,21 @@ jb_err client_cookie_adder(struct client_state *csp) { char *tmp; struct list_entry *wafer; - struct list_entry *wafer_list = csp->action->multi[ACTION_MULTI_WAFER]->first; + struct list_entry *wafer_list; jb_err err; + /* + * 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])) + { + enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER); + } + + wafer_list = csp->action->multi[ACTION_MULTI_WAFER]->first; + if (NULL == wafer_list) { /* Nothing to do */ @@ -3533,6 +3600,7 @@ jb_err client_cookie_adder(struct client_state *csp) return err; } + #if 0 /********************************************************************* * @@ -3562,6 +3630,7 @@ static jb_err client_accept_encoding_adder(struct client_state *csp) } #endif + /********************************************************************* * * Function : client_xtra_adder @@ -3596,53 +3665,6 @@ static 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. - * - *********************************************************************/ -static 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 @@ -3710,7 +3732,6 @@ static jb_err connection_close_adder(struct client_state *csp) *********************************************************************/ static jb_err server_http(struct client_state *csp, char **header) { - /* XXX: Doesn't belong here. */ sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status)); if (csp->http->status == 206) { @@ -3988,6 +4009,7 @@ int strclean(const char *string, const char *substring) } #endif /* def FEATURE_FORCE_LOAD */ + /********************************************************************* * * Function : parse_header_time @@ -4037,6 +4059,7 @@ static jb_err parse_header_time(const char *header_time, time_t *result) } + /********************************************************************* * * Function : get_destination_from_headers @@ -4119,6 +4142,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