Help clang understand that we aren't dereferencing
[privoxy.git] / filters.c
1 const char filters_rcs[] = "$Id: filters.c,v 1.111 2008/12/04 18:13:46 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/filters.c,v $
5  *
6  * Purpose     :  Declares functions to parse/crunch headers and pages.
7  *                Functions declared include:
8  *                   `acl_addr', `add_stats', `block_acl', `block_imageurl',
9  *                   `block_url', `url_actions', `domain_split',
10  *                   `filter_popups', `forward_url', 'redirect_url',
11  *                   `ij_untrusted_url', `intercept_url', `pcrs_filter_respose',
12  *                   `ijb_send_banner', `trust_url', `gif_deanimate_response',
13  *                   `execute_single_pcrs_command', `rewrite_url',
14  *                   `get_last_url'
15  *
16  * Copyright   :  Written by and Copyright (C) 2001, 2004-2008 the SourceForge
17  *                Privoxy team. http://www.privoxy.org/
18  *
19  *                Based on the Internet Junkbuster originally written
20  *                by and Copyright (C) 1997 Anonymous Coders and
21  *                Junkbusters Corporation.  http://www.junkbusters.com
22  *
23  *                This program is free software; you can redistribute it
24  *                and/or modify it under the terms of the GNU General
25  *                Public License as published by the Free Software
26  *                Foundation; either version 2 of the License, or (at
27  *                your option) any later version.
28  *
29  *                This program is distributed in the hope that it will
30  *                be useful, but WITHOUT ANY WARRANTY; without even the
31  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
32  *                PARTICULAR PURPOSE.  See the GNU General Public
33  *                License for more details.
34  *
35  *                The GNU General Public License should be included with
36  *                this file.  If not, you can view it at
37  *                http://www.gnu.org/copyleft/gpl.html
38  *                or write to the Free Software Foundation, Inc., 59
39  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
40  *
41  * Revisions   :
42  *    $Log: filters.c,v $
43  *    Revision 1.111  2008/12/04 18:13:46  fabiankeil
44  *    Fix a cparser warning.
45  *
46  *    Revision 1.110  2008/11/10 16:40:25  fabiankeil
47  *    Fix a gcc44 warning.
48  *
49  *    Revision 1.109  2008/11/08 15:48:41  fabiankeil
50  *    Mention actual values when complaining about
51  *    the chunk size exceeding the buffer size.
52  *
53  *    Revision 1.108  2008/05/21 15:35:08  fabiankeil
54  *    - Mark csp as immutable for block_acl().
55  *    - Remove an obsolete complaint about filter_popups().
56  *
57  *    Revision 1.107  2008/05/04 17:52:56  fabiankeil
58  *    Adjust parse_http_url() call to new prototype.
59  *
60  *    Revision 1.106  2008/05/03 16:40:44  fabiankeil
61  *    Change content_filters_enabled()'s parameter from
62  *    csp->action to action so it can be also used in the
63  *    CGI code. Don't bother checking if there are filters
64  *    loaded, as that's somewhat besides the point.
65  *
66  *    Revision 1.105  2008/03/28 15:13:39  fabiankeil
67  *    Remove inspect-jpegs action.
68  *
69  *    Revision 1.104  2008/03/27 18:27:24  fabiankeil
70  *    Remove kill-popups action.
71  *
72  *    Revision 1.103  2008/03/06 16:33:45  fabiankeil
73  *    If limit-connect isn't used, don't limit CONNECT requests to port 443.
74  *
75  *    Revision 1.102  2008/03/01 14:00:44  fabiankeil
76  *    Let the block action take the reason for the block
77  *    as argument and show it on the "blocked" page.
78  *
79  *    Revision 1.101  2008/02/23 16:57:12  fabiankeil
80  *    Rename url_actions() to get_url_actions() and let it
81  *    use the standard parameter ordering.
82  *
83  *    Revision 1.100  2008/02/23 16:33:43  fabiankeil
84  *    Let forward_url() use the standard parameter ordering
85  *    and mark its second parameter immutable.
86  *
87  *    Revision 1.99  2008/02/03 13:57:58  fabiankeil
88  *    Add SOCKS5 support for forward-override{}.
89  *
90  *    Revision 1.98  2008/01/04 17:43:45  fabiankeil
91  *    Improve the warning messages that get logged if the action files
92  *    "enable" filters but no filters of that type have been loaded.
93  *
94  *    Revision 1.97  2007/11/30 15:37:03  fabiankeil
95  *    Use freez instead of free.
96  *
97  *    Revision 1.96  2007/10/19 16:53:28  fabiankeil
98  *    Add helper function to check if any content filters are enabled.
99  *
100  *    Revision 1.95  2007/10/17 19:31:20  fabiankeil
101  *    Omitting the zero chunk that ends the chunk transfer encoding seems
102  *    to be the new black. Log the problem and continue filtering anyway.
103  *
104  *    Revision 1.94  2007/09/29 13:20:20  fabiankeil
105  *    Remove two redundant and one useless log messages.
106  *
107  *    Revision 1.93  2007/09/29 10:21:16  fabiankeil
108  *    - Move get_filter_function() from jcc.c to filters.c
109  *      so the filter functions can be static.
110  *    - Don't bother filtering body-less responses.
111  *
112  *    Revision 1.92  2007/09/28 16:38:55  fabiankeil
113  *    - Execute content filters through execute_content_filter().
114  *    - Add prepare_for_filtering() so filter functions don't have to
115  *      care about de-chunking and decompression. As a side effect this enables
116  *      decompression for gif_deanimate_response() and jpeg_inspect_response().
117  *    - Change remove_chunked_transfer_coding()'s return type to jb_err.
118  *      Some clowns feel like chunking empty responses in which case
119  *      (size == 0) is valid but previously would be interpreted as error.
120  *
121  *    Revision 1.91  2007/09/02 15:31:20  fabiankeil
122  *    Move match_portlist() from filter.c to urlmatch.c.
123  *    It's used for url matching, not for filtering.
124  *
125  *    Revision 1.90  2007/09/02 12:44:17  fabiankeil
126  *    Remove newline at the end of a log_error() message.
127  *
128  *    Revision 1.89  2007/08/05 13:42:23  fabiankeil
129  *    #1763173 from Stefan Huehner: declare some more functions static.
130  *
131  *    Revision 1.88  2007/06/01 16:41:11  fabiankeil
132  *    Add forward-override{} to change the forwarding settings through
133  *    action sections. This is mainly interesting to forward different
134  *    clients differently (for example based on User-Agent or request
135  *    origin).
136  *
137  *    Revision 1.87  2007/04/30 15:53:10  fabiankeil
138  *    Make sure filters with dynamic jobs actually use them.
139  *
140  *    Revision 1.86  2007/04/30 15:03:28  fabiankeil
141  *    - Introduce dynamic pcrs jobs that can resolve variables.
142  *    - Don't run redirect functions more than once,
143  *      unless they are activated more than once.
144  *
145  *    Revision 1.85  2007/03/21 12:24:47  fabiankeil
146  *    - Log the content size after decompression in decompress_iob()
147  *      instead of pcrs_filter_response().
148  *
149  *    Revision 1.84  2007/03/20 15:16:34  fabiankeil
150  *    Use dedicated header filter actions instead of abusing "filter".
151  *    Replace "filter-client-headers" and "filter-client-headers"
152  *    with "server-header-filter" and "client-header-filter".
153  *
154  *    Revision 1.83  2007/03/17 15:20:05  fabiankeil
155  *    New config option: enforce-blocks.
156  *
157  *    Revision 1.82  2007/03/13 11:28:43  fabiankeil
158  *    - Fix port handling in acl_addr() and use a temporary acl spec
159  *      copy so error messages don't contain a truncated version.
160  *    - Log size of iob before and after decompression.
161  *
162  *    Revision 1.81  2007/03/05 14:40:53  fabiankeil
163  *    - Cosmetical changes for LOG_LEVEL_RE_FILTER messages.
164  *    - Hide the "Go there anyway" link for blocked CONNECT
165  *      requests where going there anyway doesn't work anyway.
166  *
167  *    Revision 1.80  2007/02/07 10:55:20  fabiankeil
168  *    - Save the reason for generating http_responses.
169  *    - Block (+block) with status code 403 instead of 404.
170  *    - Use a different kludge to remember a failed decompression.
171  *
172  *    Revision 1.79  2007/01/31 16:21:38  fabiankeil
173  *    Search for Max-Forwards headers case-insensitive,
174  *    don't generate the "501 unsupported" message for invalid
175  *    Max-Forwards values and don't increase negative ones.
176  *
177  *    Revision 1.78  2007/01/28 13:41:18  fabiankeil
178  *    - Add HEAD support to finish_http_response.
179  *    - Add error favicon to internal HTML error messages.
180  *
181  *    Revision 1.77  2007/01/12 15:36:44  fabiankeil
182  *    Mark *csp as immutable for is_untrusted_url()
183  *    and is_imageurl(). Closes FR 1237736.
184  *
185  *    Revision 1.76  2007/01/01 19:36:37  fabiankeil
186  *    Integrate a modified version of Wil Mahan's
187  *    zlib patch (PR #895531).
188  *
189  *    Revision 1.75  2006/12/29 18:30:46  fabiankeil
190  *    Fixed gcc43 conversion warnings,
191  *    changed sprintf calls to snprintf.
192  *
193  *    Revision 1.74  2006/12/24 17:37:38  fabiankeil
194  *    Adjust comment in pcrs_filter_response()
195  *    to recent pcrs changes. Hohoho.
196  *
197  *    Revision 1.73  2006/12/23 16:01:02  fabiankeil
198  *    Don't crash if pcre returns an error code
199  *    that pcrs didn't expect. Fixes BR 1621173.
200  *
201  *    Revision 1.72  2006/12/22 18:52:53  fabiankeil
202  *    Modified is_untrusted_url to complain in case of
203  *    write errors and to give a reason when adding new
204  *    entries to the trustfile. Closes FR 1097611.
205  *
206  *    Revision 1.71  2006/12/22 14:24:52  fabiankeil
207  *    Skip empty filter files in pcrs_filter_response,
208  *    but don't ignore the ones that come afterwards.
209  *    Fixes parts of BR 1619208.
210  *
211  *    Revision 1.70  2006/12/09 13:33:15  fabiankeil
212  *    Added some sanity checks for get_last_url().
213  *    Fixed possible segfault caused by my last commit.
214  *
215  *    Revision 1.69  2006/12/08 12:39:13  fabiankeil
216  *    Let get_last_url() catch https URLs as well.
217  *
218  *    Revision 1.68  2006/12/05 14:45:48  fabiankeil
219  *    Make sure get_last_url() behaves like advertised
220  *    and fast-redirects{} can be combined with redirect{}.
221  *
222  *    Revision 1.67  2006/11/28 15:19:43  fabiankeil
223  *    Implemented +redirect{s@foo@bar@} to generate
224  *    a redirect based on a rewritten version of the
225  *    original URL.
226  *
227  *    Revision 1.66  2006/09/23 13:26:38  roro
228  *    Replace TABs by spaces in source code.
229  *
230  *    Revision 1.65  2006/09/21 12:54:43  fabiankeil
231  *    Fix +redirect{}. Didn't work with -fast-redirects.
232  *
233  *    Revision 1.64  2006/08/31 10:55:49  fabiankeil
234  *    Block requests for untrusted URLs with status
235  *    code 403 instead of 200.
236  *
237  *    Revision 1.63  2006/08/31 10:11:28  fabiankeil
238  *    Don't free p which is still in use and will be later
239  *    freed by free_map(). Don't claim the referrer is unknown
240  *    when the client didn't set one.
241  *
242  *    Revision 1.62  2006/08/14 00:27:47  david__schmidt
243  *    Feature request 595948: Re-Filter logging in single line
244  *
245  *    Revision 1.61  2006/08/03 02:46:41  david__schmidt
246  *    Incorporate Fabian Keil's patch work:\rhttp://www.fabiankeil.de/sourcecode/privoxy/
247  *
248  *    Revision 1.60  2006/07/18 14:48:46  david__schmidt
249  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
250  *    with what was really the latest development (the v_3_0_branch branch)
251  *
252  *    Revision 1.58.2.9  2006/01/29 23:10:56  david__schmidt
253  *    Multiple filter file support
254  *
255  *    Revision 1.58.2.8  2005/05/07 21:50:55  david__schmidt
256  *    A few memory leaks plugged (mostly on error paths)
257  *
258  *    Revision 1.58.2.7  2004/10/03 12:53:32  david__schmidt
259  *    Add the ability to check jpeg images for invalid
260  *    lengths of comment blocks.  Defensive strategy
261  *    against the exploit:
262  *       Microsoft Security Bulletin MS04-028
263  *       Buffer Overrun in JPEG Processing (GDI+) Could
264  *       Allow Code Execution (833987)
265  *    Enabled with +inspect-jpegs in actions files.
266  *
267  *    Revision 1.58.2.6  2003/12/06 22:18:27  gliptak
268  *    Correcting compile problem with FEATURE_IMAGE_BLOCKING
269  *
270  *    Revision 1.58.2.5  2003/11/11 13:10:31  oes
271  *    Fixed bug #839859: "See why" link URL now gets url-encoded.
272  *
273  *    Revision 1.58.2.4  2003/02/28 12:52:45  oes
274  *    Fixed a typo
275  *
276  *    Revision 1.58.2.3  2002/09/25 14:51:51  oes
277  *    Added basic support for OPTIONS and TRACE HTTP methods:
278  *    New function direct_response which handles OPTIONS and
279  *    TRACE requests whose Max-Forwards header field is zero.
280  *
281  *    Revision 1.58.2.2  2002/08/01 17:18:28  oes
282  *    Fixed BR 537651 / SR 579724 (MSIE image detect improper for IE/Mac)
283  *
284  *    Revision 1.58.2.1  2002/07/26 15:18:53  oes
285  *    - Bugfix: Executing a filters without jobs no longer results in
286  *      turing off *all* filters.
287  *    - Security fix: Malicious web servers can't cause a seg fault
288  *      through bogus chunk sizes anymore
289  *
290  *    Revision 1.58  2002/04/24 02:11:17  oes
291  *    Jon's multiple AF patch: url_actions now evaluates rules
292  *    from all AFs.
293  *
294  *    Revision 1.57  2002/04/08 20:38:34  swa
295  *    fixed JB spelling
296  *
297  *    Revision 1.56  2002/04/05 15:51:24  oes
298  *     - bugfix: error-pages now get correct request protocol
299  *     - fix for invalid HTML in trust info
300  *
301  *    Revision 1.55  2002/04/02 16:13:51  oes
302  *    Fix: No "Go there anyway" for SSL
303  *
304  *    Revision 1.54  2002/04/02 14:55:56  oes
305  *    Bugfix: is_untrusted_url() now depends on FEATURE_TRUST, not FEATURE_COOKIE_JAR
306  *
307  *    Revision 1.53  2002/03/26 22:29:54  swa
308  *    we have a new homepage!
309  *
310  *    Revision 1.52  2002/03/24 16:35:57  jongfoster
311  *    Removing logo
312  *
313  *    Revision 1.51  2002/03/24 15:23:33  jongfoster
314  *    Name changes
315  *
316  *    Revision 1.50  2002/03/24 13:25:43  swa
317  *    name change related issues
318  *
319  *    Revision 1.49  2002/03/16 20:29:14  oes
320  *    Cosmetics
321  *
322  *    Revision 1.48  2002/03/13 20:25:34  oes
323  *    Better logging for content filters
324  *
325  *    Revision 1.47  2002/03/13 00:30:52  jongfoster
326  *    Killing warnings
327  *    Added option of always sending redirect for imageblock,
328  *    currently disabled with #if 0.
329  *
330  *    Revision 1.46  2002/03/12 01:42:49  oes
331  *    Introduced modular filters
332  *
333  *    Revision 1.45  2002/03/08 16:47:50  oes
334  *    Added choice beween GIF and PNG built-in images
335  *
336  *    Revision 1.44  2002/03/07 03:49:31  oes
337  *     - Fixed compiler warnings etc
338  *     - Changed built-in images from GIF to PNG
339  *       (with regard to Unisys patent issue)
340  *     - Added a 4x4 pattern PNG which is less intrusive
341  *       than the logo but also clearly marks the deleted banners
342  *
343  *    Revision 1.43  2002/01/22 23:51:59  jongfoster
344  *    Replacing strsav() with the safer string_append().
345  *
346  *    Adding missing html_encode() to error message generators.  Where encoded
347  *    and unencoded versions of a string were provided, removing the unencoded
348  *    one.
349  *
350  *    Revision 1.42  2002/01/17 21:00:32  jongfoster
351  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
352  *
353  *    Using a single, simple url_match(pattern,url) function - rather than
354  *    the 3-line match routine which was repeated all over the place.
355  *
356  *    Renaming free_url to free_url_spec, since it frees a struct url_spec.
357  *
358  *    Using parse_http_url() to parse URLs without faking a HTTP
359  *    request line for parse_http_request().
360  *
361  *    Revision 1.41  2001/11/13 00:14:07  jongfoster
362  *    Fixing stupid bug now I've figured out what || means.
363  *    (It always returns 0 or 1, not one of it's paramaters.)
364  *
365  *    Revision 1.40  2001/10/26 17:37:55  oes
366  *    - Re-enabled Netscape 200/404 bug workaround in block_url():
367  *      - Removed OS/2 special case
368  *      - Made block_url() independant from sed() having been run
369  *    - Made trust_url independant from sed() having been run
370  *    - Made is_imageurl independant from sed() having been run.
371  *      It now checks User-Agent: and Accept: by itself.
372  *
373  *
374  *    Revision 1.39  2001/10/25 03:40:48  david__schmidt
375  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
376  *    threads to call select() simultaneously.  So, it's time to do a real, live,
377  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
378  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
379  *
380  *    Revision 1.38  2001/10/23 21:32:33  jongfoster
381  *    Adding error-checking to selected functions
382  *
383  *    Revision 1.37  2001/10/22 15:33:56  david__schmidt
384  *    Special-cased OS/2 out of the Netscape-abort-on-404-in-js problem in
385  *    filters.c.  Added a FIXME in front of the offending code.  I'll gladly
386  *    put in a better/more robust fix for all parties if one is presented...
387  *    It seems that just returning 200 instead of 404 would pretty much fix
388  *    it for everyone, but I don't know all the history of the problem.
389  *
390  *    Revision 1.36  2001/10/10 16:44:16  oes
391  *    Added match_portlist function
392  *
393  *    Revision 1.35  2001/10/07 15:41:23  oes
394  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
395  *
396  *    New function remove_chunked_transfer_coding that strips chunked
397  *      transfer coding to plain and is called by pcrs_filter_response
398  *      and gif_deanimate_response if neccessary
399  *
400  *    Improved handling of zero-change re_filter runs
401  *
402  *    pcrs_filter_response and gif_deanimate_response now remove
403  *      chunked transfer codeing before processing the body.
404  *
405  *    Revision 1.34  2001/09/20 15:49:36  steudten
406  *
407  *    Fix BUG: Change int size to size_t size in pcrs_filter_response().
408  *    See cgi.c fill_template().
409  *
410  *    Revision 1.33  2001/09/16 17:05:14  jongfoster
411  *    Removing unused #include showarg.h
412  *
413  *    Revision 1.32  2001/09/16 13:21:27  jongfoster
414  *    Changes to use new list functions.
415  *
416  *    Revision 1.31  2001/09/16 11:38:02  jongfoster
417  *    Splitting fill_template() into 2 functions:
418  *    template_load() loads the file
419  *    template_fill() performs the PCRS regexps.
420  *    This is because the CGI edit interface has a "table row"
421  *    template which is used many times in the page - this
422  *    change means it's only loaded from disk once.
423  *
424  *    Revision 1.30  2001/09/16 11:00:10  jongfoster
425  *    New function alloc_http_response, for symmetry with free_http_response
426  *
427  *    Revision 1.29  2001/09/13 23:32:40  jongfoster
428  *    Moving image data to cgi.c rather than cgi.h
429  *    Fixing a GPF under Win32 (and any other OS that protects global
430  *    constants from being written to).
431  *
432  *    Revision 1.28  2001/09/10 10:18:51  oes
433  *    Silenced compiler warnings
434  *
435  *    Revision 1.27  2001/08/05 16:06:20  jongfoster
436  *    Modifiying "struct map" so that there are now separate header and
437  *    "map_entry" structures.  This means that functions which modify a
438  *    map no longer need to return a pointer to the modified map.
439  *    Also, it no longer reverses the order of the entries (which may be
440  *    important with some advanced template substitutions).
441  *
442  *    Revision 1.26  2001/07/30 22:08:36  jongfoster
443  *    Tidying up #defines:
444  *    - All feature #defines are now of the form FEATURE_xxx
445  *    - Permanently turned off WIN_GUI_EDIT
446  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
447  *
448  *    Revision 1.25  2001/07/26 10:09:46  oes
449  *    Made browser detection a little less naive
450  *
451  *    Revision 1.24  2001/07/25 17:22:51  oes
452  *    Added workaround for Netscape bug that prevents display of page when loading a component fails.
453  *
454  *    Revision 1.23  2001/07/23 13:40:12  oes
455  *    Fixed bug that caused document body to be dropped when pcrs joblist was empty.
456  *
457  *    Revision 1.22  2001/07/18 12:29:34  oes
458  *    - Made gif_deanimate_response respect
459  *      csp->action->string[ACTION_STRING_DEANIMATE]
460  *    - Logging cosmetics
461  *
462  *    Revision 1.21  2001/07/13 13:59:53  oes
463  *     - Introduced gif_deanimate_response which shares the
464  *       generic content modification interface of pcrs_filter_response
465  *       and acts as a wrapper to deanimate.c:gif_deanimate()
466  *     - Renamed re_process_buffer to pcrs_filter_response
467  *     - pcrs_filter_response now returns NULL on failiure
468  *     - Removed all #ifdef PCRS
469  *
470  *    Revision 1.20  2001/07/01 17:01:04  oes
471  *    Added comments and missing return statement in is_untrusted_url()
472  *
473  *    Revision 1.19  2001/06/29 21:45:41  oes
474  *    Indentation, CRLF->LF, Tab-> Space
475  *
476  *    Revision 1.18  2001/06/29 13:27:38  oes
477  *    - Cleaned up, renamed and reorderd functions
478  *      and improved comments
479  *
480  *    - block_url:
481  *      - Ported to CGI platform. Now delivers
482  *        http_response or NULL
483  *      - Unified HTML and GIF generation (moved image detection
484  *        and GIF generation here from jcc.c:chat())
485  *      - Fixed HTTP status to:
486  *       -  403 (Forbidden) for the "blocked" HTML message
487  *       -  200 (OK) for GIF answers
488  *       -  302 (Redirect) for redirect to GIF
489  *
490  *    - trust_url:
491  *      - Ported to CGI platform. Now delivers
492  *        http_response or NULL
493  *      - Separated detection of untrusted URL into
494  *        (bool)is_untrusted_url
495  *      - Added enforcement of untrusted requests
496  *
497  *    - Moved redirect_url() from cgi.c to here
498  *      and ported it to the CGI platform
499  *
500  *    - Removed logentry from cancelled commit
501  *
502  *    Revision 1.17  2001/06/09 10:55:28  jongfoster
503  *    Changing BUFSIZ ==> BUFFER_SIZE
504  *
505  *    Revision 1.16  2001/06/07 23:10:26  jongfoster
506  *    Allowing unanchored domain patterns to back off and retry
507  *    if they partially match.  Optimized right-anchored patterns.
508  *    Moving ACL and forward files into config file.
509  *    Replacing struct gateway with struct forward_spec
510  *
511  *    Revision 1.15  2001/06/03 19:12:00  oes
512  *    extracted-CGI relevant stuff
513  *
514  *    Revision 1.14  2001/06/01 10:30:55  oes
515  *    Added optional left-anchoring to domaincmp
516  *
517  *    Revision 1.13  2001/05/31 21:21:30  jongfoster
518  *    Permissionsfile / actions file changes:
519  *    - Changed "permission" to "action" throughout
520  *    - changes to file format to allow string parameters
521  *    - Moved helper functions to actions.c
522  *
523  *    Revision 1.12  2001/05/31 17:35:20  oes
524  *
525  *     - Enhanced domain part globbing with infix and prefix asterisk
526  *       matching and optional unanchored operation
527  *
528  *    Revision 1.11  2001/05/29 11:53:23  oes
529  *    "See why" link added to "blocked" page
530  *
531  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
532  *    Unified blocklist/imagelist/permissionslist.
533  *    File format is still under discussion, but the internal changes
534  *    are (mostly) done.
535  *
536  *    Also modified interceptor behaviour:
537  *    - We now intercept all URLs beginning with one of the following
538  *      prefixes (and *only* these prefixes):
539  *        * http://i.j.b/
540  *        * http://ijbswa.sf.net/config/
541  *        * http://ijbswa.sourceforge.net/config/
542  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
543  *    - Internal changes so that intercepted and fast redirect pages
544  *      are not replaced with an image.
545  *    - Interceptors now have the option to send a binary page direct
546  *      to the client. (i.e. ijb-send-banner uses this)
547  *    - Implemented show-url-info interceptor.  (Which is why I needed
548  *      the above interceptors changes - a typical URL is
549  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
550  *      The previous mechanism would not have intercepted that, and
551  *      if it had been intercepted then it then it would have replaced
552  *      it with an image.)
553  *
554  *    Revision 1.9  2001/05/27 22:17:04  oes
555  *
556  *    - re_process_buffer no longer writes the modified buffer
557  *      to the client, which was very ugly. It now returns the
558  *      buffer, which it is then written by chat.
559  *
560  *    - content_length now adjusts the Content-Length: header
561  *      for modified documents rather than crunch()ing it.
562  *      (Length info in csp->content_length, which is 0 for
563  *      unmodified documents)
564  *
565  *    - For this to work, sed() is called twice when filtering.
566  *
567  *    Revision 1.8  2001/05/26 17:13:28  jongfoster
568  *    Filled in a function comment.
569  *
570  *    Revision 1.7  2001/05/26 15:26:15  jongfoster
571  *    ACL feature now provides more security by immediately dropping
572  *    connections from untrusted hosts.
573  *
574  *    Revision 1.6  2001/05/26 00:28:36  jongfoster
575  *    Automatic reloading of config file.
576  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
577  *    Most of the global variables have been moved to a new
578  *    struct configuration_spec, accessed through csp->config->globalname
579  *    Most of the globals remaining are used by the Win32 GUI.
580  *
581  *    Revision 1.5  2001/05/25 22:34:30  jongfoster
582  *    Hard tabs->Spaces
583  *
584  *    Revision 1.4  2001/05/22 18:46:04  oes
585  *
586  *    - Enabled filtering banners by size rather than URL
587  *      by adding patterns that replace all standard banner
588  *      sizes with the "Junkbuster" gif to the re_filterfile
589  *
590  *    - Enabled filtering WebBugs by providing a pattern
591  *      which kills all 1x1 images
592  *
593  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
594  *      which is selected by the (nonstandard and therefore
595  *      capital) letter 'U' in the option string.
596  *      It causes the quantifiers to be ungreedy by default.
597  *      Appending a ? turns back to greedy (!).
598  *
599  *    - Added a new interceptor ijb-send-banner, which
600  *      sends back the "Junkbuster" gif. Without imagelist or
601  *      MSIE detection support, or if tinygif = 1, or the
602  *      URL isn't recognized as an imageurl, a lame HTML
603  *      explanation is sent instead.
604  *
605  *    - Added new feature, which permits blocking remote
606  *      script redirects and firing back a local redirect
607  *      to the browser.
608  *      The feature is conditionally compiled, i.e. it
609  *      can be disabled with --disable-fast-redirects,
610  *      plus it must be activated by a "fast-redirects"
611  *      line in the config file, has its own log level
612  *      and of course wants to be displayed by show-proxy-args
613  *      Note: Boy, all the #ifdefs in 1001 locations and
614  *      all the fumbling with configure.in and acconfig.h
615  *      were *way* more work than the feature itself :-(
616  *
617  *    - Because a generic redirect template was needed for
618  *      this, tinygif = 3 now uses the same.
619  *
620  *    - Moved GIFs, and other static HTTP response templates
621  *      to project.h
622  *
623  *    - Some minor fixes
624  *
625  *    - Removed some >400 CRs again (Jon, you really worked
626  *      a lot! ;-)
627  *
628  *    Revision 1.3  2001/05/20 16:44:47  jongfoster
629  *    Removing last hardcoded Junkbusters.com URLs.
630  *
631  *    Revision 1.2  2001/05/20 01:21:20  jongfoster
632  *    Version 2.9.4 checkin.
633  *    - Merged popupfile and cookiefile, and added control over PCRS
634  *      filtering, in new "permissionsfile".
635  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
636  *      file error you now get a message box (in the Win32 GUI) rather
637  *      than the program exiting with no explanation.
638  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
639  *      skipping.
640  *    - Removed tabs from "config"
641  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
642  *    - Bumped up version number.
643  *
644  *    Revision 1.1.1.1  2001/05/15 13:58:52  oes
645  *    Initial import of version 2.9.3 source tree
646  *
647  *
648  *********************************************************************/
649 \f
650
651 #include "config.h"
652
653 #include <stdio.h>
654 #include <sys/types.h>
655 #include <stdlib.h>
656 #include <ctype.h>
657 #include <string.h>
658 #include <assert.h>
659
660 #ifndef _WIN32
661 #ifndef __OS2__
662 #include <unistd.h>
663 #endif /* ndef __OS2__ */
664 #include <netinet/in.h>
665 #else
666 #include <winsock2.h>
667 #endif /* ndef _WIN32 */
668
669 #ifdef __OS2__
670 #include <utils.h>
671 #endif /* def __OS2__ */
672
673 #include "project.h"
674 #include "filters.h"
675 #include "encode.h"
676 #include "parsers.h"
677 #include "ssplit.h"
678 #include "errlog.h"
679 #include "jbsockets.h"
680 #include "miscutil.h"
681 #include "actions.h"
682 #include "cgi.h"
683 #include "list.h"
684 #include "deanimate.h"
685 #include "urlmatch.h"
686 #include "loaders.h"
687
688 #ifdef _WIN32
689 #include "win32.h"
690 #endif
691
692 const char filters_h_rcs[] = FILTERS_H_VERSION;
693
694 /* Fix a problem with Solaris.  There should be no effect on other
695  * platforms.
696  * Solaris's isspace() is a macro which uses it's argument directly
697  * as an array index.  Therefore we need to make sure that high-bit
698  * characters generate +ve values, and ideally we also want to make
699  * the argument match the declared parameter type of "int".
700  */
701 #define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
702
703 static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size);
704 static jb_err prepare_for_filtering(struct client_state *csp);
705
706 #ifdef FEATURE_ACL
707 /*********************************************************************
708  *
709  * Function    :  block_acl
710  *
711  * Description :  Block this request?
712  *                Decide yes or no based on ACL file.
713  *
714  * Parameters  :
715  *          1  :  dst = The proxy or gateway address this is going to.
716  *                      Or NULL to check all possible targets.
717  *          2  :  csp = Current client state (buffers, headers, etc...)
718  *                      Also includes the client IP address.
719  *
720  * Returns     : 0 = FALSE (don't block) and 1 = TRUE (do block)
721  *
722  *********************************************************************/
723 int block_acl(const struct access_control_addr *dst, const struct client_state *csp)
724 {
725    struct access_control_list *acl = csp->config->acl;
726
727    /* if not using an access control list, then permit the connection */
728    if (acl == NULL)
729    {
730       return(0);
731    }
732
733    /* search the list */
734    while (acl != NULL)
735    {
736       if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
737       {
738          if (dst == NULL)
739          {
740             /* Just want to check if they have any access */
741             if (acl->action == ACL_PERMIT)
742             {
743                return(0);
744             }
745          }
746          else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
747            && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
748          {
749             if (acl->action == ACL_PERMIT)
750             {
751                return(0);
752             }
753             else
754             {
755                return(1);
756             }
757          }
758       }
759       acl = acl->next;
760    }
761
762    return(1);
763
764 }
765
766
767 /*********************************************************************
768  *
769  * Function    :  acl_addr
770  *
771  * Description :  Called from `load_config' to parse an ACL address.
772  *
773  * Parameters  :
774  *          1  :  aspec = String specifying ACL address.
775  *          2  :  aca = struct access_control_addr to fill in.
776  *
777  * Returns     :  0 => Ok, everything else is an error.
778  *
779  *********************************************************************/
780 int acl_addr(const char *aspec, struct access_control_addr *aca)
781 {
782    int i, masklength;
783    long port;
784    char *p;
785    char *acl_spec = NULL;
786
787    masklength = 32;
788    port       =  0;
789
790    /*
791     * Use a temporary acl spec copy so we can log
792     * the unmodified original in case of parse errors.
793     */
794    acl_spec = strdup(aspec);
795    if (acl_spec == NULL)
796    {
797       /* XXX: This will be logged as parse error. */
798       return(-1);
799    }
800
801    if ((p = strchr(acl_spec, '/')) != NULL)
802    {
803       *p++ = '\0';
804       if (ijb_isdigit(*p) == 0)
805       {
806          freez(acl_spec);
807          return(-1);
808       }
809       masklength = atoi(p);
810    }
811
812    if ((masklength < 0) || (masklength > 32))
813    {
814       freez(acl_spec);
815       return(-1);
816    }
817
818    if ((p = strchr(acl_spec, ':')) != NULL)
819    {
820       char *endptr;
821
822       *p++ = '\0';
823       port = strtol(p, &endptr, 10);
824
825       if (port <= 0 || port > 65535 || *endptr != '\0')
826       {
827          freez(acl_spec);
828          return(-1);
829       }
830    }
831
832    aca->port = (unsigned long)port;
833
834    aca->addr = ntohl(resolve_hostname_to_ip(acl_spec));
835    freez(acl_spec);
836
837    if (aca->addr == INADDR_NONE)
838    {
839       /* XXX: This will be logged as parse error. */
840       return(-1);
841    }
842
843    /* build the netmask */
844    aca->mask = 0;
845    for (i=1; i <= masklength ; i++)
846    {
847       aca->mask |= (1U << (32 - i));
848    }
849
850    /* now mask off the host portion of the ip address
851     * (i.e. save on the network portion of the address).
852     */
853    aca->addr = aca->addr & aca->mask;
854
855    return(0);
856
857 }
858 #endif /* def FEATURE_ACL */
859
860
861 /*********************************************************************
862  *
863  * Function    :  connect_port_is_forbidden
864  *
865  * Description :  Check to see if CONNECT requests to the destination
866  *                port of this request are forbidden. The check is
867  *                independend of the actual request method.
868  *
869  * Parameters  :
870  *          1  :  csp = Current client state (buffers, headers, etc...)
871  *
872  * Returns     :  True if yes, false otherwise.
873  *
874  *********************************************************************/
875 int connect_port_is_forbidden(const struct client_state *csp)
876 {
877    return ((csp->action->flags & ACTION_LIMIT_CONNECT) &&
878      !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT],
879         csp->http->port));
880 }
881
882
883 /*********************************************************************
884  *
885  * Function    :  block_url
886  *
887  * Description :  Called from `chat'.  Check to see if we need to block this.
888  *
889  * Parameters  :
890  *          1  :  csp = Current client state (buffers, headers, etc...)
891  *
892  * Returns     :  NULL => unblocked, else HTTP block response
893  *
894  *********************************************************************/
895 struct http_response *block_url(struct client_state *csp)
896 {
897    struct http_response *rsp;
898    const char *new_content_type = NULL;
899
900    /*
901     * If it's not blocked, don't block it ;-)
902     */
903    if ((csp->action->flags & ACTION_BLOCK) == 0)
904    {
905       return NULL;
906    }
907    if (csp->action->flags & ACTION_REDIRECT)
908    {
909       log_error(LOG_LEVEL_ERROR, "redirect{} overruled by block.");     
910    }
911    /*
912     * Else, prepare a response
913     */
914    if (NULL == (rsp = alloc_http_response()))
915    {
916       return cgi_error_memory();
917    }
918
919    /*
920     * If it's an image-url, send back an image or redirect
921     * as specified by the relevant +image action
922     */
923 #ifdef FEATURE_IMAGE_BLOCKING
924    if (((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0)
925         && is_imageurl(csp))
926    {
927       char *p;
928       /* determine HOW images should be blocked */
929       p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER];
930
931       if(csp->action->flags & ACTION_HANDLE_AS_EMPTY_DOCUMENT)
932       {
933          log_error(LOG_LEVEL_ERROR, "handle-as-empty-document overruled by handle-as-image.");
934       }
935 #if 1 /* Two alternative strategies, use this one for now: */
936
937       /* and handle accordingly: */
938       if ((p == NULL) || (0 == strcmpic(p, "pattern")))
939       {
940          rsp->status = strdup("403 Request blocked by Privoxy");
941          if (rsp->status == NULL)
942          {
943             free_http_response(rsp);
944             return cgi_error_memory();
945          }
946          rsp->body = bindup(image_pattern_data, image_pattern_length);
947          if (rsp->body == NULL)
948          {
949             free_http_response(rsp);
950             return cgi_error_memory();
951          }
952          rsp->content_length = image_pattern_length;
953
954          if (enlist_unique_header(rsp->headers, "Content-Type", BUILTIN_IMAGE_MIMETYPE))
955          {
956             free_http_response(rsp);
957             return cgi_error_memory();
958          }
959       }
960
961       else if (0 == strcmpic(p, "blank"))
962       {
963          rsp->status = strdup("403 Request blocked by Privoxy");
964          if (rsp->status == NULL)
965          {
966             free_http_response(rsp);
967             return cgi_error_memory();
968          }
969          rsp->body = bindup(image_blank_data, image_blank_length);
970          if (rsp->body == NULL)
971          {
972             free_http_response(rsp);
973             return cgi_error_memory();
974          }
975          rsp->content_length = image_blank_length;
976
977          if (enlist_unique_header(rsp->headers, "Content-Type", BUILTIN_IMAGE_MIMETYPE))
978          {
979             free_http_response(rsp);
980             return cgi_error_memory();
981          }
982       }
983
984       else
985       {
986          rsp->status = strdup("302 Local Redirect from Privoxy");
987          if (rsp->status == NULL)
988          {
989             free_http_response(rsp);
990             return cgi_error_memory();
991          }
992
993          if (enlist_unique_header(rsp->headers, "Location", p))
994          {
995             free_http_response(rsp);
996             return cgi_error_memory();
997          }
998       }
999
1000 #else /* Following code is disabled for now */
1001
1002       /* and handle accordingly: */
1003       if ((p == NULL) || (0 == strcmpic(p, "pattern")))
1004       {
1005          p = CGI_PREFIX "send-banner?type=pattern";
1006       }
1007       else if (0 == strcmpic(p, "blank"))
1008       {
1009          p = CGI_PREFIX "send-banner?type=blank";
1010       }
1011       rsp->status = strdup("302 Local Redirect from Privoxy");
1012       if (rsp->status == NULL)
1013       {
1014          free_http_response(rsp);
1015          return cgi_error_memory();
1016       }
1017
1018       if (enlist_unique_header(rsp->headers, "Location", p))
1019       {
1020          free_http_response(rsp);
1021          return cgi_error_memory();
1022       }
1023 #endif /* Preceeding code is disabled for now */
1024    }
1025    else if(csp->action->flags & ACTION_HANDLE_AS_EMPTY_DOCUMENT)
1026    {
1027      /*
1028       *  Send empty document.               
1029       */
1030       new_content_type = csp->action->string[ACTION_STRING_CONTENT_TYPE];
1031
1032       freez(rsp->body);
1033       rsp->body = strdup(" ");
1034       rsp->content_length = 1;
1035
1036       rsp->status = strdup("403 Request blocked by Privoxy");
1037       if (rsp->status == NULL)
1038       {
1039          free_http_response(rsp);
1040          return cgi_error_memory();
1041       }
1042       if (new_content_type != 0)
1043       {
1044          log_error(LOG_LEVEL_HEADER, "Overwriting Content-Type with %s", new_content_type);
1045          if (enlist_unique_header(rsp->headers, "Content-Type", new_content_type))
1046          {
1047             free_http_response(rsp);
1048             return cgi_error_memory();
1049          }
1050       }
1051    }
1052    else
1053 #endif /* def FEATURE_IMAGE_BLOCKING */
1054
1055    /*
1056     * Else, generate an HTML "blocked" message:
1057     */
1058    {
1059       jb_err err;
1060       struct map * exports;
1061       char *p;
1062
1063       /*
1064        * Workaround for stupid Netscape bug which prevents
1065        * pages from being displayed if loading a referenced
1066        * JavaScript or style sheet fails. So make it appear
1067        * as if it succeeded.
1068        */
1069       if ( NULL != (p = get_header_value(csp->headers, "User-Agent:"))
1070            && !strncmpic(p, "mozilla", 7) /* Catch Netscape but */
1071            && !strstr(p, "Gecko")         /* save Mozilla, */
1072            && !strstr(p, "compatible")    /* MSIE */
1073            && !strstr(p, "Opera"))        /* and Opera. */
1074       {
1075          rsp->status = strdup("200 Request for blocked URL");
1076       }
1077       else
1078       {
1079          rsp->status = strdup("403 Request for blocked URL");
1080       }
1081
1082       if (rsp->status == NULL)
1083       {
1084          free_http_response(rsp);
1085          return cgi_error_memory();
1086       }
1087
1088       exports = default_exports(csp, NULL);
1089       if (exports == NULL)
1090       {
1091          free_http_response(rsp);
1092          return cgi_error_memory();
1093       }
1094
1095 #ifdef FEATURE_FORCE_LOAD
1096       err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1);
1097       /*
1098        * Export the force conditional block killer if
1099        *
1100        * - Privoxy was compiled without FEATURE_FORCE_LOAD, or
1101        * - Privoxy is configured to enforce blocks, or
1102        * - it's a CONNECT request and enforcing wouldn't work anyway.
1103        */
1104       if ((csp->config->feature_flags & RUNTIME_FEATURE_ENFORCE_BLOCKS)
1105        || (0 == strcmpic(csp->http->gpc, "connect")))
1106 #endif /* ndef FEATURE_FORCE_LOAD */
1107       {
1108          err = map_block_killer(exports, "force-support");
1109       }
1110
1111       if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1);
1112       if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0);
1113       if (!err) err = map(exports, "path", 1, html_encode(csp->http->path), 0);
1114       if (!err) err = map(exports, "path-ue", 1, url_encode(csp->http->path), 0);
1115       if (!err)
1116       {
1117          const char *block_reason;
1118          if (csp->action->string[ACTION_STRING_BLOCK] != NULL)
1119          {
1120             block_reason = csp->action->string[ACTION_STRING_BLOCK];
1121          }
1122          else
1123          {
1124             assert(connect_port_is_forbidden(csp));
1125             block_reason = "Forbidden CONNECT port.";
1126          }
1127          err = map(exports, "block-reason", 1, html_encode(block_reason), 0);
1128       }
1129       if (err)
1130       {
1131          free_map(exports);
1132          free_http_response(rsp);
1133          return cgi_error_memory();
1134       }
1135
1136       err = template_fill_for_cgi(csp, "blocked", exports, rsp);
1137       if (err)
1138       {
1139          free_http_response(rsp);
1140          return cgi_error_memory();
1141       }
1142    }
1143    rsp->reason = RSP_REASON_BLOCKED;
1144
1145    return finish_http_response(csp, rsp);
1146
1147 }
1148
1149
1150 #ifdef FEATURE_TRUST
1151 /*********************************************************************
1152  *
1153  * Function    :  trust_url FIXME: I should be called distrust_url
1154  *
1155  * Description :  Calls is_untrusted_url to determine if the URL is trusted
1156  *                and if not, returns a HTTP 403 response with a reject message.
1157  *
1158  * Parameters  :
1159  *          1  :  csp = Current client state (buffers, headers, etc...)
1160  *
1161  * Returns     :  NULL => trusted, else http_response.
1162  *
1163  *********************************************************************/
1164 struct http_response *trust_url(struct client_state *csp)
1165 {
1166    struct http_response *rsp;
1167    struct map * exports;
1168    char buf[BUFFER_SIZE];
1169    char *p;
1170    struct url_spec **tl;
1171    struct url_spec *t;
1172    jb_err err;
1173
1174    /*
1175     * Don't bother to work on trusted URLs
1176     */
1177    if (!is_untrusted_url(csp))
1178    {
1179       return NULL;
1180    }
1181
1182    /*
1183     * Else, prepare a response:
1184     */
1185    if (NULL == (rsp = alloc_http_response()))
1186    {
1187       return cgi_error_memory();
1188    }
1189
1190    rsp->status = strdup("403 Request blocked by Privoxy");
1191    exports = default_exports(csp, NULL);
1192    if (exports == NULL || rsp->status == NULL)
1193    {
1194       free_http_response(rsp);
1195       return cgi_error_memory();
1196    }
1197
1198    /*
1199     * Export the protocol, host, port, and referrer information
1200     */
1201    err = map(exports, "hostport", 1, csp->http->hostport, 1);
1202    if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); 
1203    if (!err) err = map(exports, "path", 1, csp->http->path, 1);
1204
1205    if (NULL != (p = get_header_value(csp->headers, "Referer:")))
1206    {
1207       if (!err) err = map(exports, "referrer", 1, html_encode(p), 0);
1208    }
1209    else
1210    {
1211       if (!err) err = map(exports, "referrer", 1, "none set", 1);
1212    }
1213
1214    if (err)
1215    {
1216       free_map(exports);
1217       free_http_response(rsp);
1218       return cgi_error_memory();
1219    }
1220
1221    /*
1222     * Export the trust list
1223     */
1224    p = strdup("");
1225    for (tl = csp->config->trust_list; (t = *tl) != NULL ; tl++)
1226    {
1227       snprintf(buf, sizeof(buf), "<li>%s</li>\n", t->spec);
1228       string_append(&p, buf);
1229    }
1230    err = map(exports, "trusted-referrers", 1, p, 0);
1231
1232    if (err)
1233    {
1234       free_map(exports);
1235       free_http_response(rsp);
1236       return cgi_error_memory();
1237    }
1238
1239    /*
1240     * Export the trust info, if available
1241     */
1242    if (csp->config->trust_info->first)
1243    {
1244       struct list_entry *l;
1245
1246       p = strdup("");
1247       for (l = csp->config->trust_info->first; l ; l = l->next)
1248       {
1249          snprintf(buf, sizeof(buf), "<li> <a href=\"%s\">%s</a><br>\n", l->str, l->str);
1250          string_append(&p, buf);
1251       }
1252       err = map(exports, "trust-info", 1, p, 0);
1253    }
1254    else
1255    {
1256       err = map_block_killer(exports, "have-trust-info");
1257    }
1258
1259    if (err)
1260    {
1261       free_map(exports);
1262       free_http_response(rsp);
1263       return cgi_error_memory();
1264    }
1265
1266    /*
1267     * Export the force conditional block killer if
1268     *
1269     * - Privoxy was compiled without FEATURE_FORCE_LOAD, or
1270     * - Privoxy is configured to enforce blocks, or
1271     * - it's a CONNECT request and enforcing wouldn't work anyway.
1272     */
1273 #ifdef FEATURE_FORCE_LOAD
1274    if ((csp->config->feature_flags & RUNTIME_FEATURE_ENFORCE_BLOCKS)
1275     || (0 == strcmpic(csp->http->gpc, "connect")))
1276    {
1277       err = map_block_killer(exports, "force-support");
1278    }
1279    else
1280    {
1281       err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1);
1282    }
1283 #else /* ifndef FEATURE_FORCE_LOAD */
1284    err = map_block_killer(exports, "force-support");
1285 #endif /* ndef FEATURE_FORCE_LOAD */
1286
1287    if (err)
1288    {
1289       free_map(exports);
1290       free_http_response(rsp);
1291       return cgi_error_memory();
1292    }
1293
1294    /*
1295     * Build the response
1296     */
1297    err = template_fill_for_cgi(csp, "untrusted", exports, rsp);
1298    if (err)
1299    {
1300       free_http_response(rsp);
1301       return cgi_error_memory();
1302    }
1303    rsp->reason = RSP_REASON_UNTRUSTED;
1304
1305    return finish_http_response(csp, rsp);
1306 }
1307 #endif /* def FEATURE_TRUST */
1308
1309
1310 /*********************************************************************
1311  *
1312  * Function    :  compile_dynamic_pcrs_job_list
1313  *
1314  * Description :  Compiles a dynamic pcrs job list (one with variables
1315  *                resolved at request time)
1316  *
1317  * Parameters  :
1318  *          1  :  csp = Current client state (buffers, headers, etc...)
1319  *          2  :  b = The filter list to compile
1320  *
1321  * Returns     :  NULL in case of errors, otherwise the
1322  *                pcrs job list.  
1323  *
1324  *********************************************************************/
1325 pcrs_job *compile_dynamic_pcrs_job_list(const struct client_state *csp, const struct re_filterfile_spec *b)
1326 {
1327    struct list_entry *pattern;
1328    pcrs_job *job_list = NULL;
1329    pcrs_job *dummy = NULL;
1330    pcrs_job *lastjob = NULL;
1331    int error = 0;
1332
1333    const struct pcrs_variable variables[] =
1334    {
1335       {"url",    csp->http->url,   1},
1336       {"path",   csp->http->path,  1},
1337       {"host",   csp->http->host,  1},
1338       {"origin", csp->ip_addr_str, 1},
1339       {NULL,     NULL,             1}
1340    };
1341
1342    for (pattern = b->patterns->first; pattern != NULL; pattern = pattern->next)
1343    {
1344       assert(pattern->str != NULL);
1345
1346       dummy = pcrs_compile_dynamic_command(pattern->str, variables, &error);
1347       if (NULL == dummy)
1348       {
1349          assert(error < 0);
1350          log_error(LOG_LEVEL_ERROR,
1351             "Adding filter job \'%s\' to dynamic filter %s failed: %s",
1352             pattern->str, b->name, pcrs_strerror(error));
1353          continue;
1354       }
1355       else
1356       {
1357          if (error == PCRS_WARN_TRUNCATION)
1358          {
1359             log_error(LOG_LEVEL_ERROR,
1360                "At least one of the variables in \'%s\' had to "
1361                "be truncated before compilation", pattern->str);
1362          }
1363          if (job_list == NULL)
1364          {
1365             job_list = dummy;
1366          }
1367          else
1368          {
1369             lastjob->next = dummy;
1370          }
1371          lastjob = dummy;
1372       }
1373    }
1374
1375    return job_list;
1376 }
1377
1378
1379 /*********************************************************************
1380  *
1381  * Function    :  rewrite_url
1382  *
1383  * Description :  Rewrites a URL with a single pcrs command
1384  *                and returns the result if it differs from the
1385  *                original and isn't obviously invalid.
1386  *
1387  * Parameters  :
1388  *          1  :  old_url = URL to rewrite.
1389  *          2  :  pcrs_command = pcrs command formatted as string (s@foo@bar@)
1390  *
1391  *
1392  * Returns     :  NULL if the pcrs_command didn't change the url, or 
1393  *                the result of the modification.
1394  *
1395  *********************************************************************/
1396 char *rewrite_url(char *old_url, const char *pcrs_command)
1397 {
1398    char *new_url = NULL;
1399    int hits;
1400
1401    assert(old_url);
1402    assert(pcrs_command);
1403
1404    new_url = pcrs_execute_single_command(old_url, pcrs_command, &hits);
1405
1406    if (hits == 0)
1407    {
1408       log_error(LOG_LEVEL_REDIRECTS,
1409          "pcrs command \"%s\" didn't change \"%s\".",
1410          pcrs_command, old_url);
1411       freez(new_url);
1412    }
1413    else if (hits < 0)
1414    {
1415       log_error(LOG_LEVEL_REDIRECTS,
1416          "executing pcrs command \"%s\" to rewrite %s failed: %s",
1417          pcrs_command, old_url, pcrs_strerror(hits));
1418       freez(new_url);
1419    }
1420    else if (strncmpic(new_url, "http://", 7) && strncmpic(new_url, "https://", 8))
1421    {
1422       log_error(LOG_LEVEL_ERROR,
1423          "pcrs command \"%s\" changed \"%s\" to \"%s\" (%u hi%s), "
1424          "but the result doesn't look like a valid URL and will be ignored.",
1425          pcrs_command, old_url, new_url, hits, (hits == 1) ? "t" : "ts");
1426       freez(new_url);
1427    }
1428    else
1429    {
1430       log_error(LOG_LEVEL_REDIRECTS,
1431          "pcrs command \"%s\" changed \"%s\" to \"%s\" (%u hi%s).",
1432          pcrs_command, old_url, new_url, hits, (hits == 1) ? "t" : "ts");
1433    }
1434
1435    return new_url;
1436
1437 }
1438
1439
1440 #ifdef FEATURE_FAST_REDIRECTS
1441 /*********************************************************************
1442  *
1443  * Function    :  get_last_url
1444  *
1445  * Description :  Search for the last URL inside a string.
1446  *                If the string already is a URL, it will
1447  *                be the first URL found.
1448  *
1449  * Parameters  :
1450  *          1  :  subject = the string to check
1451  *          2  :  redirect_mode = +fast-redirect{} mode 
1452  *
1453  * Returns     :  NULL if no URL was found, or
1454  *                the last URL found.
1455  *
1456  *********************************************************************/
1457 char *get_last_url(char *subject, const char *redirect_mode)
1458 {
1459    char *new_url = NULL;
1460    char *tmp;
1461
1462    assert(subject);
1463    assert(redirect_mode);
1464
1465    subject = strdup(subject);
1466    if (subject == NULL)
1467    {
1468       log_error(LOG_LEVEL_ERROR, "Out of memory while searching for redirects.");
1469       return NULL;
1470    }
1471
1472    if (0 == strcmpic(redirect_mode, "check-decoded-url"))
1473    {  
1474       log_error(LOG_LEVEL_REDIRECTS, "Decoding \"%s\" if necessary.", subject);
1475       new_url = url_decode(subject);
1476       if (new_url != NULL)
1477       {
1478          freez(subject);
1479          subject = new_url;
1480       }
1481       else
1482       {
1483          log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", subject);
1484       }
1485    }
1486
1487    log_error(LOG_LEVEL_REDIRECTS, "Checking \"%s\" for redirects.", subject);
1488
1489    /*
1490     * Find the last URL encoded in the request
1491     */
1492    tmp = subject;
1493    while ((tmp = strstr(tmp, "http://")) != NULL)
1494    {
1495       new_url = tmp++;
1496    }
1497    tmp = (new_url != NULL) ? new_url : subject;
1498    while ((tmp = strstr(tmp, "https://")) != NULL)
1499    {
1500       new_url = tmp++;
1501    }
1502
1503    if ((new_url != NULL)
1504       && (  (new_url != subject)
1505          || (0 == strncmpic(subject, "http://", 7))
1506          || (0 == strncmpic(subject, "https://", 8))
1507          ))
1508    {
1509       /*
1510        * Return new URL if we found a redirect 
1511        * or if the subject already was a URL.
1512        *
1513        * The second case makes sure that we can
1514        * chain get_last_url after another redirection check
1515        * (like rewrite_url) without losing earlier redirects.
1516        */
1517       new_url = strdup(new_url);
1518       freez(subject);
1519       return new_url;
1520    }
1521
1522    freez(subject);
1523    return NULL;
1524
1525 }
1526 #endif /* def FEATURE_FAST_REDIRECTS */
1527
1528
1529 /*********************************************************************
1530  *
1531  * Function    :  redirect_url
1532  *
1533  * Description :  Checks if Privoxy should answer the request with
1534  *                a HTTP redirect and generates the redirect if
1535  *                necessary.
1536  *
1537  * Parameters  :
1538  *          1  :  csp = Current client state (buffers, headers, etc...)
1539  *
1540  * Returns     :  NULL if the request can pass, HTTP redirect otherwise.
1541  *
1542  *********************************************************************/
1543 struct http_response *redirect_url(struct client_state *csp)
1544 {
1545    struct http_response *rsp;
1546 #ifdef FEATURE_FAST_REDIRECTS
1547    /*
1548     * XXX: Do we still need FEATURE_FAST_REDIRECTS
1549     * as compile-time option? The user can easily disable
1550     * it in his action file.
1551     */
1552    char * redirect_mode;
1553 #endif /* def FEATURE_FAST_REDIRECTS */
1554    char *old_url = NULL;
1555    char *new_url = NULL;
1556    char *redirection_string;
1557
1558    if ((csp->action->flags & ACTION_REDIRECT))
1559    {
1560       redirection_string = csp->action->string[ACTION_STRING_REDIRECT];
1561
1562       /*
1563        * If the redirection string begins with 's',
1564        * assume it's a pcrs command, otherwise treat it as
1565        * properly formatted URL and use it for the redirection
1566        * directly.
1567        *
1568        * According to RFC 2616 section 14.30 the URL
1569        * has to be absolute and if the user tries:
1570        * +redirect{shit/this/will/be/parsed/as/pcrs_command.html}
1571        * she would get undefined results anyway.
1572        *
1573        */
1574
1575       if (*redirection_string == 's')
1576       {
1577          old_url = csp->http->url;
1578          new_url = rewrite_url(old_url, redirection_string);
1579       }
1580       else
1581       {
1582          log_error(LOG_LEVEL_REDIRECTS,
1583             "No pcrs command recognized, assuming that \"%s\" is already properly formatted.",
1584             redirection_string);
1585          new_url = strdup(redirection_string);
1586       }
1587    }
1588
1589 #ifdef FEATURE_FAST_REDIRECTS
1590    if ((csp->action->flags & ACTION_FAST_REDIRECTS))
1591    {
1592       redirect_mode = csp->action->string[ACTION_STRING_FAST_REDIRECTS];
1593
1594       /*
1595        * If it exists, use the previously rewritten URL as input
1596        * otherwise just use the old path.
1597        */
1598       old_url = (new_url != NULL) ? new_url : strdup(csp->http->path);
1599       new_url = get_last_url(old_url, redirect_mode);
1600       freez(old_url);
1601    }
1602
1603    /*
1604     * Disable redirect checkers, so that they
1605     * will be only run more than once if the user
1606     * also enables them through tags.
1607     *
1608     * From a performance point of view
1609     * it doesn't matter, but the duplicated
1610     * log messages are annoying.
1611     */
1612    csp->action->flags &= ~ACTION_FAST_REDIRECTS;
1613 #endif /* def FEATURE_FAST_REDIRECTS */
1614    csp->action->flags &= ~ACTION_REDIRECT;
1615
1616    /* Did any redirect action trigger? */   
1617    if (new_url)
1618    {
1619       if (0 == strcmpic(new_url, csp->http->url))
1620       {
1621          log_error(LOG_LEVEL_ERROR,
1622             "New URL \"%s\" and old URL \"%s\" are the same. Redirection loop prevented.",
1623             csp->http->url, new_url);
1624             freez(new_url);
1625       }
1626       else
1627       {
1628          log_error(LOG_LEVEL_REDIRECTS, "New URL is: %s", new_url);
1629
1630          if (NULL == (rsp = alloc_http_response()))
1631          {
1632             freez(new_url);
1633             return cgi_error_memory();
1634          }
1635
1636          if ( enlist_unique_header(rsp->headers, "Location", new_url)
1637            || (NULL == (rsp->status = strdup("302 Local Redirect from Privoxy"))) )
1638          {
1639             freez(new_url);
1640             free_http_response(rsp);
1641             return cgi_error_memory();
1642          }
1643          rsp->reason = RSP_REASON_REDIRECTED;
1644          freez(new_url);
1645
1646          return finish_http_response(csp, rsp);
1647       }
1648    }
1649
1650    /* Only reached if no redirect is required */
1651    return NULL;
1652
1653 }
1654
1655
1656 #ifdef FEATURE_IMAGE_BLOCKING
1657 /*********************************************************************
1658  *
1659  * Function    :  is_imageurl
1660  *
1661  * Description :  Given a URL, decide whether it is an image or not,
1662  *                using either the info from a previous +image action
1663  *                or, #ifdef FEATURE_IMAGE_DETECT_MSIE, and the browser
1664  *                is MSIE and not on a Mac, tell from the browser's accept
1665  *                header.
1666  *
1667  * Parameters  :
1668  *          1  :  csp = Current client state (buffers, headers, etc...)
1669  *
1670  * Returns     :  True (nonzero) if URL is an image, false (0)
1671  *                otherwise
1672  *
1673  *********************************************************************/
1674 int is_imageurl(const struct client_state *csp)
1675 {
1676 #ifdef FEATURE_IMAGE_DETECT_MSIE
1677    char *tmp;
1678
1679    tmp = get_header_value(csp->headers, "User-Agent:");
1680    if (tmp && strstr(tmp, "MSIE") && !strstr(tmp, "Mac_"))
1681    {
1682       tmp = get_header_value(csp->headers, "Accept:");
1683       if (tmp && strstr(tmp, "image/gif"))
1684       {
1685          /* Client will accept HTML.  If this seems counterintuitive,
1686           * blame Microsoft.
1687           */
1688          return(0);
1689       }
1690       else
1691       {
1692          return(1);
1693       }
1694    }
1695 #endif /* def FEATURE_IMAGE_DETECT_MSIE */
1696
1697    return ((csp->action->flags & ACTION_IMAGE) != 0);
1698
1699 }
1700 #endif /* def FEATURE_IMAGE_BLOCKING */
1701
1702
1703 #ifdef FEATURE_TRUST
1704 /*********************************************************************
1705  *
1706  * Function    :  is_untrusted_url
1707  *
1708  * Description :  Should we "distrust" this URL (and block it)?
1709  *
1710  *                Yes if it matches a line in the trustfile, or if the
1711  *                    referrer matches a line starting with "+" in the
1712  *                    trustfile.
1713  *                No  otherwise.
1714  *
1715  * Parameters  :
1716  *          1  :  csp = Current client state (buffers, headers, etc...)
1717  *
1718  * Returns     :  0 => trusted, 1 => untrusted
1719  *
1720  *********************************************************************/
1721 int is_untrusted_url(const struct client_state *csp)
1722 {
1723    struct file_list *fl;
1724    struct block_spec *b;
1725    struct url_spec **trusted_url;
1726    struct http_request rhttp[1];
1727    const char * referer;
1728    jb_err err;
1729
1730    /*
1731     * If we don't have a trustlist, we trust everybody
1732     */
1733    if (((fl = csp->tlist) == NULL) || ((b  = fl->f) == NULL))
1734    {
1735       return 0;
1736    }
1737
1738    memset(rhttp, '\0', sizeof(*rhttp));
1739
1740    /*
1741     * Do we trust the request URL itself?
1742     */
1743    for (b = b->next; b ; b = b->next)
1744    {
1745       if (url_match(b->url, csp->http))
1746       {
1747          return b->reject;
1748       }
1749    }
1750
1751    if (NULL == (referer = get_header_value(csp->headers, "Referer:")))
1752    {
1753       /* no referrer was supplied */
1754       return 1;
1755    }
1756
1757
1758    /*
1759     * If not, do we maybe trust its referrer?
1760     */
1761    err = parse_http_url(referer, rhttp, REQUIRE_PROTOCOL);
1762    if (err)
1763    {
1764       return 1;
1765    }
1766
1767    for (trusted_url = csp->config->trust_list; *trusted_url != NULL; trusted_url++)
1768    {
1769       if (url_match(*trusted_url, rhttp))
1770       {
1771          /* if the URL's referrer is from a trusted referrer, then
1772           * add the target spec to the trustfile as an unblocked
1773           * domain and return 0 (which means it's OK).
1774           */
1775
1776          FILE *fp;
1777
1778          if (NULL != (fp = fopen(csp->config->trustfile, "a")))
1779          {
1780             char * path;
1781             char * path_end;
1782             char * new_entry = strdup("~");
1783
1784             string_append(&new_entry, csp->http->hostport);
1785
1786             path = csp->http->path;
1787             if ( (path[0] == '/')
1788               && (path[1] == '~')
1789               && ((path_end = strchr(path + 2, '/')) != NULL))
1790             {
1791                /* since this path points into a user's home space
1792                 * be sure to include this spec in the trustfile.
1793                 */
1794                int path_len = path_end - path; /* save offset */
1795                path = strdup(path); /* Copy string */
1796                if (path != NULL)
1797                {
1798                   path_end = path + path_len; /* regenerate ptr to new buffer */
1799                   *(path_end + 1) = '\0'; /* Truncate path after '/' */
1800                }
1801                string_join(&new_entry, path);
1802             }
1803
1804             /*
1805              * Give a reason for generating this entry.
1806              */
1807             string_append(&new_entry, " # Trusted referrer was: ");
1808             string_append(&new_entry, referer);
1809
1810             if (new_entry != NULL)
1811             {
1812                if (-1 == fprintf(fp, "%s\n", new_entry))
1813                {
1814                   log_error(LOG_LEVEL_ERROR, "Failed to append \'%s\' to trustfile \'%s\': %E",
1815                      new_entry, csp->config->trustfile);
1816                }
1817                freez(new_entry);
1818             }
1819             else
1820             {
1821                /* FIXME: No way to handle out-of memory, so mostly ignoring it */
1822                log_error(LOG_LEVEL_ERROR, "Out of memory adding pattern to trust file");
1823             }
1824
1825             fclose(fp);
1826          }
1827          else
1828          {
1829             log_error(LOG_LEVEL_ERROR, "Failed to append new entry for \'%s\' to trustfile \'%s\': %E",
1830                csp->http->hostport, csp->config->trustfile);
1831          }
1832          return 0;
1833       }
1834    }
1835
1836    return 1;
1837 }
1838 #endif /* def FEATURE_TRUST */
1839
1840
1841 /*********************************************************************
1842  *
1843  * Function    :  pcrs_filter_response
1844  *
1845  * Description :  Execute all text substitutions from all applying
1846  *                +filter actions on the text buffer that's been
1847  *                accumulated in csp->iob->buf.
1848  *
1849  * Parameters  :
1850  *          1  :  csp = Current client state (buffers, headers, etc...)
1851  *
1852  * Returns     :  a pointer to the (newly allocated) modified buffer.
1853  *                or NULL if there were no hits or something went wrong
1854  *
1855  *********************************************************************/
1856 static char *pcrs_filter_response(struct client_state *csp)
1857 {
1858    int hits=0;
1859    size_t size, prev_size;
1860
1861    char *old = NULL;
1862    char *new = NULL;
1863    pcrs_job *job;
1864
1865    struct file_list *fl;
1866    struct re_filterfile_spec *b;
1867    struct list_entry *filtername;
1868
1869    int i, found_filters = 0;
1870
1871    /* 
1872     * Sanity first
1873     */
1874    if (csp->iob->cur >= csp->iob->eod)
1875    {
1876       return(NULL);
1877    }
1878
1879    /*
1880     * Need to check the set of re_filterfiles...
1881     */
1882    for (i = 0; i < MAX_AF_FILES; i++)
1883    {
1884       fl = csp->rlist[i];
1885       if (NULL != fl)
1886       {
1887          if (NULL != fl->f)
1888          {
1889            found_filters = 1;
1890            break;
1891          }
1892       }
1893    }
1894
1895    if (0 == found_filters)
1896    {
1897       log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
1898          "content filtering enabled, but no content filters available.");
1899       return(NULL);
1900    }
1901
1902    size = (size_t)(csp->iob->eod - csp->iob->cur);
1903    old = csp->iob->cur;
1904
1905    for (i = 0; i < MAX_AF_FILES; i++)
1906    {
1907      fl = csp->rlist[i];
1908      if ((NULL == fl) || (NULL == fl->f))
1909      {
1910         /*
1911          * Either there are no filter files
1912          * left, or this filter file just
1913          * contains no valid filters.
1914          *
1915          * Continue to be sure we don't miss
1916          * valid filter files that are chained
1917          * after empty or invalid ones.
1918          */
1919         continue;
1920      }
1921    /*
1922     * For all applying +filter actions, look if a filter by that
1923     * name exists and if yes, execute it's pcrs_joblist on the
1924     * buffer.
1925     */
1926    for (b = fl->f; b; b = b->next)
1927    {
1928       if (b->type != FT_CONTENT_FILTER)
1929       {
1930          /* Skip header filters */
1931          continue;
1932       }
1933
1934       for (filtername = csp->action->multi[ACTION_MULTI_FILTER]->first;
1935            filtername ; filtername = filtername->next)
1936       {
1937          if (strcmp(b->name, filtername->str) == 0)
1938          {
1939             int current_hits = 0; /* Number of hits caused by this filter */
1940             int job_number   = 0; /* Which job we're currently executing  */
1941             int job_hits     = 0; /* How many hits the current job caused */
1942             pcrs_job *joblist = b->joblist;
1943
1944             if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
1945
1946             if (NULL == joblist)
1947             {
1948                log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
1949                continue;
1950             }
1951
1952             prev_size = size;
1953             /* Apply all jobs from the joblist */
1954             for (job = joblist; NULL != job; job = job->next)
1955             {
1956                job_number++;
1957                job_hits = pcrs_execute(job, old, size, &new, &size);
1958
1959                if (job_hits >= 0)
1960                {
1961                   /*
1962                    * That went well. Continue filtering
1963                    * and use the result of this job as
1964                    * input for the next one.
1965                    */
1966                   current_hits += job_hits;
1967                   if (old != csp->iob->cur)
1968                   {
1969                      freez(old);
1970                   }
1971                   old = new;
1972                }
1973                else
1974                {
1975                   /*
1976                    * This job caused an unexpected error. Inform the user
1977                    * and skip the rest of the jobs in this filter. We could
1978                    * continue with the next job, but usually the jobs
1979                    * depend on each other or are similar enough to
1980                    * fail for the same reason.
1981                    *
1982                    * At the moment our pcrs expects the error codes of pcre 3.4,
1983                    * but newer pcre versions can return additional error codes.
1984                    * As a result pcrs_strerror()'s error message might be
1985                    * "Unknown error ...", therefore we print the numerical value
1986                    * as well.
1987                    *
1988                    * XXX: Is this important enough for LOG_LEVEL_ERROR or
1989                    * should we use LOG_LEVEL_RE_FILTER instead?
1990                    */
1991                   log_error(LOG_LEVEL_ERROR, "Skipped filter \'%s\' after job number %u: %s (%d)",
1992                      b->name, job_number, pcrs_strerror(job_hits), job_hits);
1993                   break;
1994                }
1995             }
1996
1997             if (b->dynamic) pcrs_free_joblist(joblist);
1998
1999             log_error(LOG_LEVEL_RE_FILTER,
2000                "filtering %s%s (size %d) with \'%s\' produced %d hits (new size %d).",
2001                csp->http->hostport, csp->http->path, prev_size, b->name, current_hits, size);
2002
2003             hits += current_hits;
2004          }
2005       }
2006    }
2007    }
2008
2009    /*
2010     * If there were no hits, destroy our copy and let
2011     * chat() use the original in csp->iob
2012     */
2013    if (!hits)
2014    {
2015       freez(new);
2016       return(NULL);
2017    }
2018
2019    csp->flags |= CSP_FLAG_MODIFIED;
2020    csp->content_length = size;
2021    IOB_RESET(csp);
2022
2023    return(new);
2024
2025 }
2026
2027
2028 /*********************************************************************
2029  *
2030  * Function    :  gif_deanimate_response
2031  *
2032  * Description :  Deanimate the GIF image that has been accumulated in
2033  *                csp->iob->buf, set csp->content_length to the modified
2034  *                size and raise the CSP_FLAG_MODIFIED flag.
2035  *
2036  * Parameters  :
2037  *          1  :  csp = Current client state (buffers, headers, etc...)
2038  *
2039  * Returns     :  a pointer to the (newly allocated) modified buffer.
2040  *                or NULL in case something went wrong.
2041  *
2042  *********************************************************************/
2043 static char *gif_deanimate_response(struct client_state *csp)
2044 {
2045    struct binbuffer *in, *out;
2046    char *p;
2047    size_t size;
2048
2049    size = (size_t)(csp->iob->eod - csp->iob->cur);
2050
2051    if (  (NULL == (in =  (struct binbuffer *)zalloc(sizeof *in )))
2052       || (NULL == (out = (struct binbuffer *)zalloc(sizeof *out))) )
2053    {
2054       log_error(LOG_LEVEL_DEANIMATE, "failed! (no mem)");
2055       return NULL;
2056    }
2057
2058    in->buffer = csp->iob->cur;
2059    in->size = size;
2060
2061    if (gif_deanimate(in, out, strncmp("last", csp->action->string[ACTION_STRING_DEANIMATE], 4)))
2062    {
2063       log_error(LOG_LEVEL_DEANIMATE, "failed! (gif parsing)");
2064       freez(in);
2065       buf_free(out);
2066       return(NULL);
2067    }
2068    else
2069    {
2070       if ((int)size == out->offset)
2071       {
2072          log_error(LOG_LEVEL_DEANIMATE, "GIF not changed.");
2073       }
2074       else
2075       {
2076          log_error(LOG_LEVEL_DEANIMATE, "Success! GIF shrunk from %d bytes to %d.", size, out->offset);
2077       }
2078       csp->content_length = out->offset;
2079       csp->flags |= CSP_FLAG_MODIFIED;
2080       p = out->buffer;
2081       freez(in);
2082       freez(out);
2083       return(p);
2084    }
2085
2086 }
2087
2088
2089 /*********************************************************************
2090  *
2091  * Function    :  get_filter_function
2092  *
2093  * Description :  Decides which content filter function has
2094  *                to be applied (if any).
2095  *
2096  * Parameters  :
2097  *          1  :  csp = Current client state (buffers, headers, etc...)
2098  *
2099  * Returns     :  The content filter function to run, or
2100  *                NULL if no content filter is active
2101  *
2102  *********************************************************************/
2103 filter_function_ptr get_filter_function(struct client_state *csp)
2104 {
2105    filter_function_ptr filter_function = NULL;
2106
2107    /*
2108     * Are we enabling text mode by force?
2109     */
2110    if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
2111    {
2112       /*
2113        * Do we really have to?
2114        */
2115       if (csp->content_type & CT_TEXT)
2116       {
2117          log_error(LOG_LEVEL_HEADER, "Text mode is already enabled.");   
2118       }
2119       else
2120       {
2121          csp->content_type |= CT_TEXT;
2122          log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!");   
2123       }
2124    }
2125
2126    if (!(csp->content_type & CT_DECLARED))
2127    {
2128       /*
2129        * The server didn't bother to declare a MIME-Type.
2130        * Assume it's text that can be filtered.
2131        *
2132        * This also regulary happens with 304 responses,
2133        * therefore logging anything here would cause
2134        * too much noise.
2135        */
2136       csp->content_type |= CT_TEXT;
2137    }
2138
2139    /*
2140     * Choose the applying filter function based on
2141     * the content type and action settings.
2142     */
2143    if ((csp->content_type & CT_TEXT) &&
2144        (csp->rlist != NULL) &&
2145        (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER])))
2146    {
2147       filter_function = pcrs_filter_response;
2148    }
2149    else if ((csp->content_type & CT_GIF)  &&
2150             (csp->action->flags & ACTION_DEANIMATE))
2151    {
2152       filter_function = gif_deanimate_response;
2153    }
2154
2155    return filter_function;
2156 }
2157
2158
2159 /*********************************************************************
2160  *
2161  * Function    :  remove_chunked_transfer_coding
2162  *
2163  * Description :  In-situ remove the "chunked" transfer coding as defined
2164  *                in rfc2616 from a buffer.
2165  *
2166  * Parameters  :
2167  *          1  :  buffer = Pointer to the text buffer
2168  *          2  :  size =  In: Number of bytes to be processed,
2169  *                       Out: Number of bytes after de-chunking.
2170  *                       (undefined in case of errors)
2171  *
2172  * Returns     :  JB_ERR_OK for success,
2173  *                JB_ERR_PARSE otherwise
2174  *
2175  *********************************************************************/
2176 static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size)
2177 {
2178    size_t newsize = 0;
2179    unsigned int chunksize = 0;
2180    char *from_p, *to_p;
2181
2182    assert(buffer);
2183    from_p = to_p = buffer;
2184
2185    if (sscanf(buffer, "%x", &chunksize) != 1)
2186    {
2187       log_error(LOG_LEVEL_ERROR, "Invalid first chunksize while stripping \"chunked\" transfer coding");
2188       return JB_ERR_PARSE;
2189    }
2190
2191    while (chunksize > 0U)
2192    {
2193       if (NULL == (from_p = strstr(from_p, "\r\n")))
2194       {
2195          log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding");
2196          return JB_ERR_PARSE;
2197       }
2198
2199       if ((newsize += chunksize) >= *size)
2200       {
2201          log_error(LOG_LEVEL_ERROR,
2202             "Chunk size %d exceeds buffer size %d in  \"chunked\" transfer coding",
2203             chunksize, *size);
2204          return JB_ERR_PARSE;
2205       }
2206       from_p += 2;
2207
2208       memmove(to_p, from_p, (size_t) chunksize);
2209       to_p = buffer + newsize;
2210       from_p += chunksize + 2;
2211
2212       if (sscanf(from_p, "%x", &chunksize) != 1)
2213       {
2214          log_error(LOG_LEVEL_INFO, "Invalid \"chunked\" transfer encoding detected and ignored.");
2215          break;
2216       }
2217    }
2218    
2219    /* XXX: Should get its own loglevel. */
2220    log_error(LOG_LEVEL_RE_FILTER, "De-chunking successful. Shrunk from %d to %d", *size, newsize);
2221
2222    *size = newsize;
2223
2224    return JB_ERR_OK;
2225
2226 }
2227
2228
2229 /*********************************************************************
2230  *
2231  * Function    :  prepare_for_filtering
2232  *
2233  * Description :  If necessary, de-chunks and decompresses
2234  *                the content so it can get filterd.
2235  *
2236  * Parameters  :
2237  *          1  :  csp = Current client state (buffers, headers, etc...)
2238  *
2239  * Returns     :  JB_ERR_OK for success,
2240  *                JB_ERR_PARSE otherwise
2241  *
2242  *********************************************************************/
2243 static jb_err prepare_for_filtering(struct client_state *csp)
2244 {
2245    jb_err err = JB_ERR_OK;
2246
2247    /*
2248     * If the body has a "chunked" transfer-encoding,
2249     * get rid of it, adjusting size and iob->eod
2250     */
2251    if (csp->flags & CSP_FLAG_CHUNKED)
2252    {
2253       size_t size = (size_t)(csp->iob->eod - csp->iob->cur);
2254
2255       log_error(LOG_LEVEL_RE_FILTER, "Need to de-chunk first");
2256       err = remove_chunked_transfer_coding(csp->iob->cur, &size);
2257       if (JB_ERR_OK == err)
2258       {
2259          csp->iob->eod = csp->iob->cur + size;
2260          csp->flags |= CSP_FLAG_MODIFIED;
2261       }
2262       else
2263       {
2264          return JB_ERR_PARSE;
2265       }
2266    }
2267
2268 #ifdef FEATURE_ZLIB
2269    /*
2270     * If the body has a supported transfer-encoding,
2271     * decompress it, adjusting size and iob->eod.
2272     */
2273    if (csp->content_type & (CT_GZIP|CT_DEFLATE))
2274    {
2275       if (0 == csp->iob->eod - csp->iob->cur)
2276       {
2277          /* Nothing left after de-chunking. */
2278          return JB_ERR_OK;
2279       }
2280
2281       err = decompress_iob(csp);
2282
2283       if (JB_ERR_OK == err)
2284       {
2285          csp->flags |= CSP_FLAG_MODIFIED;
2286          csp->content_type &= ~CT_TABOO;
2287       }
2288       else
2289       {
2290          /*
2291           * Unset CT_GZIP and CT_DEFLATE to remember not
2292           * to modify the Content-Encoding header later.
2293           */
2294          csp->content_type &= ~CT_GZIP;
2295          csp->content_type &= ~CT_DEFLATE;
2296       }
2297    }
2298 #endif
2299
2300    return err;
2301 }
2302
2303
2304 /*********************************************************************
2305  *
2306  * Function    :  execute_content_filter
2307  *
2308  * Description :  Executes a given content filter.
2309  *
2310  * Parameters  :
2311  *          1  :  csp = Current client state (buffers, headers, etc...)
2312  *          2  :  content_filter = The filter function to execute
2313  *
2314  * Returns     :  Pointer to the modified buffer, or
2315  *                NULL if filtering failed or wasn't necessary.
2316  *
2317  *********************************************************************/
2318 char *execute_content_filter(struct client_state *csp, filter_function_ptr content_filter)
2319 {
2320    if (0 == csp->iob->eod - csp->iob->cur)
2321    {
2322       /*
2323        * No content (probably status code 301, 302 ...),
2324        * no filtering necessary.
2325        */
2326       return NULL;
2327    }
2328
2329    if (JB_ERR_OK != prepare_for_filtering(csp))
2330    {
2331       /*
2332        * failed to de-chunk or decompress.
2333        */
2334       return NULL;
2335    }
2336
2337    if (0 == csp->iob->eod - csp->iob->cur)
2338    {
2339       /*
2340        * Clown alarm: chunked and/or compressed nothing delivered.
2341        */
2342       return NULL;
2343    }
2344
2345    return ((*content_filter)(csp));
2346 }
2347
2348
2349 /*********************************************************************
2350  *
2351  * Function    :  get_url_actions
2352  *
2353  * Description :  Gets the actions for this URL.
2354  *
2355  * Parameters  :
2356  *          1  :  csp = Current client state (buffers, headers, etc...)
2357  *          2  :  http = http_request request for blocked URLs
2358  *
2359  * Returns     :  N/A
2360  *
2361  *********************************************************************/
2362 void get_url_actions(struct client_state *csp, struct http_request *http)
2363 {
2364    struct file_list *fl;
2365    struct url_actions *b;
2366    int i;
2367
2368    init_current_action(csp->action);
2369
2370    for (i = 0; i < MAX_AF_FILES; i++)
2371    {
2372       if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL))
2373       {
2374          return;
2375       }
2376
2377       apply_url_actions(csp->action, http, b);
2378    }
2379
2380    return;
2381 }
2382
2383
2384 /*********************************************************************
2385  *
2386  * Function    :  apply_url_actions
2387  *
2388  * Description :  Applies a list of URL actions.
2389  *
2390  * Parameters  :
2391  *          1  :  action = Destination.
2392  *          2  :  http = Current URL
2393  *          3  :  b = list of URL actions to apply
2394  *
2395  * Returns     :  N/A
2396  *
2397  *********************************************************************/
2398 void apply_url_actions(struct current_action_spec *action,
2399                        struct http_request *http,
2400                        struct url_actions *b)
2401 {
2402    if (b == NULL)
2403    {
2404       /* Should never happen */
2405       return;
2406    }
2407
2408    for (b = b->next; NULL != b; b = b->next)
2409    {
2410       if (url_match(b->url, http))
2411       {
2412          merge_current_action(action, b->action);
2413       }
2414    }
2415 }
2416
2417
2418 /*********************************************************************
2419  *
2420  * Function    :  get_forward_override_settings
2421  *
2422  * Description :  Returns forward settings as specified with the
2423  *                forward-override{} action. forward-override accepts
2424  *                forward lines similar to the one used in the
2425  *                configuration file, but without the URL pattern.
2426  *
2427  *                For example:
2428  *
2429  *                   forward / .
2430  *
2431  *                in the configuration file can be replaced with
2432  *                the action section:
2433  *
2434  *                 {+forward-override{forward .}}
2435  *                 /
2436  *
2437  * Parameters  :
2438  *          1  :  csp = Current client state (buffers, headers, etc...)
2439  *
2440  * Returns     :  Pointer to forwarding structure in case of success.
2441  *                Invalid syntax is fatal.
2442  *
2443  *********************************************************************/
2444 const static struct forward_spec *get_forward_override_settings(struct client_state *csp)
2445 {
2446    const char *forward_override_line = csp->action->string[ACTION_STRING_FORWARD_OVERRIDE];
2447    char forward_settings[BUFFER_SIZE];
2448    char *http_parent = NULL;
2449    /* variable names were chosen for consistency reasons. */
2450    struct forward_spec *fwd = NULL;
2451    int vec_count;
2452    char *vec[3];
2453
2454    assert(csp->action->flags & ACTION_FORWARD_OVERRIDE);
2455    /* Should be enforced by load_one_actions_file() */
2456    assert(strlen(forward_override_line) < sizeof(forward_settings) - 1);
2457
2458    /* Create a copy ssplit can modify */
2459    strlcpy(forward_settings, forward_override_line, sizeof(forward_settings));
2460
2461    if (NULL != csp->fwd)
2462    {
2463       /*
2464        * XXX: Currently necessary to prevent memory
2465        * leaks when the show-url-info cgi page is visited.
2466        */
2467       unload_forward_spec(csp->fwd);
2468    }
2469
2470    /*
2471     * allocate a new forward node, valid only for
2472     * the lifetime of this request. Save its location
2473     * in csp as well, so sweep() can free it later on.
2474     */
2475    fwd = csp->fwd = zalloc(sizeof(*fwd));
2476    if (NULL == fwd)
2477    {
2478       log_error(LOG_LEVEL_FATAL,
2479          "can't allocate memory for forward-override{%s}", forward_override_line);
2480       /* Never get here - LOG_LEVEL_FATAL causes program exit */
2481       return NULL;
2482    }
2483
2484    vec_count = ssplit(forward_settings, " \t", vec, SZ(vec), 1, 1);
2485    if ((vec_count == 2) && !strcasecmp(vec[0], "forward"))
2486    {
2487       fwd->type = SOCKS_NONE;
2488
2489       /* Parse the parent HTTP proxy host:port */
2490       http_parent = vec[1];
2491
2492    }
2493    else if (vec_count == 3)
2494    {
2495       char *socks_proxy = NULL;
2496
2497       if  (!strcasecmp(vec[0], "forward-socks4"))
2498       {
2499          fwd->type = SOCKS_4;
2500          socks_proxy = vec[1];
2501       }
2502       else if (!strcasecmp(vec[0], "forward-socks4a"))
2503       {
2504          fwd->type = SOCKS_4A;
2505          socks_proxy = vec[1];
2506       }
2507       else if (!strcasecmp(vec[0], "forward-socks5"))
2508       {
2509          fwd->type = SOCKS_5;
2510          socks_proxy = vec[1];
2511       }
2512
2513       if (NULL != socks_proxy)
2514       {
2515          /* Parse the SOCKS proxy host[:port] */
2516          fwd->gateway_host = strdup(socks_proxy);
2517
2518          if (NULL != (socks_proxy = strchr(fwd->gateway_host, ':')))
2519          {
2520             *socks_proxy++ = '\0';
2521             fwd->gateway_port = strtol(socks_proxy, NULL, 0);
2522          }
2523
2524          if (fwd->gateway_port <= 0)
2525          {
2526             fwd->gateway_port = 1080;
2527          }
2528
2529          http_parent = vec[2];
2530       }
2531    }
2532
2533    if (NULL == http_parent)
2534    {
2535       log_error(LOG_LEVEL_FATAL,
2536          "Invalid forward-override syntax in: %s", forward_override_line);
2537       /* Never get here - LOG_LEVEL_FATAL causes program exit */
2538    }
2539
2540    /* Parse http forwarding settings */
2541    if (strcmp(http_parent, ".") != 0)
2542    {
2543       fwd->forward_host = strdup(http_parent);
2544
2545       if (NULL != (http_parent = strchr(fwd->forward_host, ':')))
2546       {
2547          *http_parent++ = '\0';
2548          fwd->forward_port = strtol(http_parent, NULL, 0);
2549       }
2550
2551       if (fwd->forward_port <= 0)
2552       {
2553          fwd->forward_port = 8000;
2554       }
2555    }
2556
2557    assert (NULL != fwd);
2558
2559    log_error(LOG_LEVEL_CONNECT,
2560       "Overriding forwarding settings based on \'%s\'", forward_override_line);
2561
2562    return fwd;
2563 }
2564
2565
2566 /*********************************************************************
2567  *
2568  * Function    :  forward_url
2569  *
2570  * Description :  Should we forward this to another proxy?
2571  *
2572  * Parameters  :
2573  *          1  :  csp = Current client state (buffers, headers, etc...)
2574  *          2  :  http = http_request request for current URL
2575  *
2576  * Returns     :  Pointer to forwarding information.
2577  *
2578  *********************************************************************/
2579 const struct forward_spec *forward_url(struct client_state *csp,
2580                                        const struct http_request *http)
2581 {
2582    static const struct forward_spec fwd_default[1] = { FORWARD_SPEC_INITIALIZER };
2583    struct forward_spec *fwd = csp->config->forward;
2584
2585    if (csp->action->flags & ACTION_FORWARD_OVERRIDE)
2586    {
2587       return get_forward_override_settings(csp);
2588    }
2589
2590    if (fwd == NULL)
2591    {
2592       return fwd_default;
2593    }
2594
2595    while (fwd != NULL)
2596    {
2597       if (url_match(fwd->url, http))
2598       {
2599          return fwd;
2600       }
2601       fwd = fwd->next;
2602    }
2603
2604    return fwd_default;
2605 }
2606
2607
2608 /*********************************************************************
2609  *
2610  * Function    :  direct_response 
2611  *
2612  * Description :  Check if Max-Forwards == 0 for an OPTIONS or TRACE
2613  *                request and if so, return a HTTP 501 to the client.
2614  *
2615  *                FIXME: I have a stupid name and I should handle the
2616  *                requests properly. Still, what we do here is rfc-
2617  *                compliant, whereas ignoring or forwarding are not.
2618  *
2619  * Parameters  :  
2620  *          1  :  csp = Current client state (buffers, headers, etc...)
2621  *
2622  * Returns     :  http_response if , NULL if nonmatch or handler fail
2623  *
2624  *********************************************************************/
2625 struct http_response *direct_response(struct client_state *csp)
2626 {
2627    struct http_response *rsp;
2628    struct list_entry *p;
2629
2630    if ((0 == strcmpic(csp->http->gpc, "trace"))
2631       || (0 == strcmpic(csp->http->gpc, "options")))
2632    {
2633       for (p = csp->headers->first; (p != NULL) ; p = p->next)
2634       {
2635          if (!strncmpic("Max-Forwards:", p->str, 13))
2636          {
2637             unsigned int max_forwards;
2638
2639             /*
2640              * If it's a Max-Forwards value of zero,
2641              * we have to intercept the request.
2642              */
2643             if (1 == sscanf(p->str+12, ": %u", &max_forwards) && max_forwards == 0)
2644             {
2645                /*
2646                 * FIXME: We could handle at least TRACE here,
2647                 * but that would require a verbatim copy of
2648                 * the request which we don't have anymore
2649                 */
2650                 log_error(LOG_LEVEL_HEADER,
2651                   "Detected header \'%s\' in OPTIONS or TRACE request. Returning 501.",
2652                   p->str);
2653
2654                /* Get mem for response or fail*/
2655                if (NULL == (rsp = alloc_http_response()))
2656                {
2657                   return cgi_error_memory();
2658                }
2659             
2660                if (NULL == (rsp->status = strdup("501 Not Implemented")))
2661                {
2662                   free_http_response(rsp);
2663                   return cgi_error_memory();
2664                }
2665
2666                rsp->is_static = 1;
2667                rsp->reason = RSP_REASON_UNSUPPORTED;
2668
2669                return(finish_http_response(csp, rsp));
2670             }
2671          }
2672       }
2673    }
2674    return NULL;
2675 }
2676
2677
2678 /*********************************************************************
2679  *
2680  * Function    :  content_filters_enabled
2681  *
2682  * Description :  Checks whether there are any content filters
2683  *                enabled for the current request.
2684  *
2685  * Parameters  :  
2686  *          1  :  action = Action spec to check.
2687  *
2688  * Returns     :  TRUE for yes, FALSE otherwise
2689  *
2690  *********************************************************************/
2691 int content_filters_enabled(const struct current_action_spec *action)
2692 {
2693    return ((action->flags & ACTION_DEANIMATE) ||
2694       !list_is_empty(action->multi[ACTION_MULTI_FILTER]));
2695 }
2696
2697 /*
2698   Local Variables:
2699   tab-width: 3
2700   end:
2701 */