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