Updated activity console instrumentation locations
[privoxy.git] / src / jcc.c
1 const char jcc_rcs[] = "$Id: jcc.c,v 2.4 2002/12/28 03:58:19 david__schmidt Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/src/jcc.c,v $
5  *
6  * Purpose     :  Main file.  Contains main() method, main loop, and
7  *                the main connection-handling function.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
10  *                Privoxy team. http://www.privoxy.org/
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  * Revisions   :
35  *    $Log: jcc.c,v $
36  *    Revision 2.4  2002/12/28 03:58:19  david__schmidt
37  *    Initial drop of dashboard instrumentation - enabled with
38  *    --enable-activity-console
39  *
40  *    Revision 2.3  2002/07/18 22:06:12  jongfoster
41  *    Trivial formatting changes
42  *
43  *    Revision 2.2  2002/07/12 04:26:17  agotneja
44  *    Re-factored 'chat()' to become understandable and maintainable as
45  *    a first step in adding Transparent Proxy functionality.
46  *
47  *    Added several new static functions in jcc.c, and moved some data
48  *    parameters up into project.h to allow them to be passed between
49  *    the new functions.
50  *
51  *    Revision 1.91  2002/04/08 20:35:58  swa
52  *    fixed JB spelling
53  *
54  *    Revision 1.90  2002/04/02 14:57:28  oes
55  *    Made sending wafers independent of FEATURE_COOKIE_JAR
56  *
57  *    Revision 1.89  2002/03/31 17:18:59  jongfoster
58  *    Win32 only: Enabling STRICT to fix a VC++ compile warning.
59  *
60  *    Revision 1.88  2002/03/27 14:32:43  david__schmidt
61  *    More compiler warning message maintenance
62  *
63  *    Revision 1.87  2002/03/26 22:29:54  swa
64  *    we have a new homepage!
65  *
66  *    Revision 1.86  2002/03/25 17:04:55  david__schmidt
67  *    Workaround for closing the jarfile before load_config() comes around again
68  *
69  *    Revision 1.85  2002/03/24 15:23:33  jongfoster
70  *    Name changes
71  *
72  *    Revision 1.84  2002/03/24 13:25:43  swa
73  *    name change related issues
74  *
75  *    Revision 1.83  2002/03/16 23:54:06  jongfoster
76  *    Adding graceful termination feature, to help look for memory leaks.
77  *    If you enable this (which, by design, has to be done by hand
78  *    editing config.h) and then go to http://i.j.b/die, then the program
79  *    will exit cleanly after the *next* request.  It should free all the
80  *    memory that was used.
81  *
82  *    Revision 1.82  2002/03/13 00:27:05  jongfoster
83  *    Killing warnings
84  *
85  *    Revision 1.81  2002/03/12 01:42:50  oes
86  *    Introduced modular filters
87  *
88  *    Revision 1.80  2002/03/11 22:07:05  david__schmidt
89  *    OS/2 port maintenance:
90  *    - Fixed EMX build - it had decayed a little
91  *    - Fixed inexplicable crash during FD_ZERO - must be due to a bad macro.
92  *      substituted a memset for now.
93  *
94  *    Revision 1.79  2002/03/09 20:03:52  jongfoster
95  *    - Making various functions return int rather than size_t.
96  *      (Undoing a recent change).  Since size_t is unsigned on
97  *      Windows, functions like read_socket that return -1 on
98  *      error cannot return a size_t.
99  *
100  *      THIS WAS A MAJOR BUG - it caused frequent, unpredictable
101  *      crashes, and also frequently caused JB to jump to 100%
102  *      CPU and stay there.  (Because it thought it had just
103  *      read ((unsigned)-1) == 4Gb of data...)
104  *
105  *    - The signature of write_socket has changed, it now simply
106  *      returns success=0/failure=nonzero.
107  *
108  *    - Trying to get rid of a few warnings --with-debug on
109  *      Windows, I've introduced a new type "jb_socket".  This is
110  *      used for the socket file descriptors.  On Windows, this
111  *      is SOCKET (a typedef for unsigned).  Everywhere else, it's
112  *      an int.  The error value can't be -1 any more, so it's
113  *      now JB_INVALID_SOCKET (which is -1 on UNIX, and in
114  *      Windows it maps to the #define INVALID_SOCKET.)
115  *
116  *    - The signature of bind_port has changed.
117  *
118  *    Revision 1.78  2002/03/08 21:35:04  oes
119  *    Added optional group supplement to --user option. Will now use default group of user if no group given
120  *
121  *    Revision 1.77  2002/03/07 03:52:06  oes
122  *     - Fixed compiler warnings etc
123  *     - Improved handling of failed DNS lookups
124  *
125  *    Revision 1.76  2002/03/06 22:54:35  jongfoster
126  *    Automated function-comment nitpicking.
127  *
128  *    Revision 1.75  2002/03/06 10:02:19  oes
129  *    Fixed stupid bug when --user was not given
130  *
131  *    Revision 1.74  2002/03/06 00:49:31  jongfoster
132  *    Fixing warning on Windows
133  *    Making #ifdefs that refer to the same variable consistently
134  *    use #ifdef unix rather than mixing #ifdef unix & #ifndef OS2
135  *
136  *    Revision 1.73  2002/03/05 23:57:30  hal9
137  *    Stray character 's' on line 1618 was breaking build.
138  *
139  *    Revision 1.72  2002/03/05 21:33:45  david__schmidt
140  *    - Re-enable OS/2 building after new parms were added
141  *    - Fix false out of memory report when resolving CGI templates when no IP
142  *      address is available of failed attempt (a la no such domain)
143  *
144  *    Revision 1.71  2002/03/05 18:13:56  oes
145  *    Added --user option
146  *
147  *    Revision 1.70  2002/03/05 04:52:42  oes
148  *    Deleted non-errlog debugging code
149  *
150  *    Revision 1.69  2002/03/04 23:50:00  jongfoster
151  *    Splitting off bind_port() call into bind_port_helper(), with
152  *    improved logging.
153  *
154  *    Revision 1.68  2002/03/04 20:17:32  oes
155  *    Fixed usage info
156  *
157  *    Revision 1.67  2002/03/04 18:18:57  oes
158  *    - Removed _DEBUG mode
159  *    - Cleand up cmdline parsing
160  *    - Introduced --no-daemon, --pidfile options
161  *    - Cleaned up signal handling:
162  *      - Terminate cleanly on INT, TERM and ABRT
163  *      - Schedule logfile for re-opening on HUP
164  *      - Ignore CHLD and PIPE
165  *      - Leave the rest with their default handlers
166  *      - Uniform handler registration
167  *    - Added usage() function
168  *    - Played styleguide police
169  *
170  *    Revision 1.66  2002/03/03 15:06:55  oes
171  *    Re-enabled automatic config reloading
172  *
173  *    Revision 1.65  2002/03/03 14:49:11  oes
174  *    Fixed CLF logging: Now uses client's original HTTP request
175  *
176  *    Revision 1.64  2002/03/03 09:18:03  joergs
177  *    Made jumbjuster work on AmigaOS again.
178  *
179  *    Revision 1.63  2002/03/02 04:14:50  david__schmidt
180  *    Clean up a little CRLF unpleasantness that suddenly appeared
181  *
182  *    Revision 1.62  2002/02/20 23:17:23  jongfoster
183  *    Detecting some out-of memory conditions and exiting with a log message.
184  *
185  *    Revision 1.61  2002/01/17 21:01:52  jongfoster
186  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
187  *
188  *    Revision 1.60  2001/12/30 14:07:32  steudten
189  *    - Add signal handling (unix)
190  *    - Add SIGHUP handler (unix)
191  *    - Add creation of pidfile (unix)
192  *    - Add action 'top' in rc file (RH)
193  *    - Add entry 'SIGNALS' to manpage
194  *    - Add exit message to logfile (unix)
195  *
196  *    Revision 1.59  2001/12/13 14:07:18  oes
197  *    Fixed Bug: 503 error page now sent OK
198  *
199  *    Revision 1.58  2001/11/30 23:37:24  jongfoster
200  *    Renaming the Win32 config file to config.txt - this is almost the
201  *    same as the corresponding UNIX name "config"
202  *
203  *    Revision 1.57  2001/11/16 00:47:43  jongfoster
204  *    Changing the tty-disconnection code to use setsid().
205  *
206  *    Revision 1.56  2001/11/13 20:20:54  jongfoster
207  *    Tabs->spaces, fixing a bug with missing {} around an if()
208  *
209  *    Revision 1.55  2001/11/13 20:14:53  jongfoster
210  *    Patch for FreeBSD setpgrp() as suggested by Alexander Lazic
211  *
212  *    Revision 1.54  2001/11/07 00:03:14  steudten
213  *    Give reliable return value if an error
214  *    occurs not just 0 with new daemon mode.
215  *
216  *    Revision 1.53  2001/11/05 21:41:43  steudten
217  *    Add changes to be a real daemon just for unix os.
218  *    (change cwd to /, detach from controlling tty, set
219  *    process group and session leader to the own process.
220  *    Add DBG() Macro.
221  *    Add some fatal-error log message for failed malloc().
222  *    Add '-d' if compiled with 'configure --with-debug' to
223  *    enable debug output.
224  *
225  *    Revision 1.52  2001/10/26 20:11:20  jongfoster
226  *    Fixing type mismatch
227  *
228  *    Revision 1.51  2001/10/26 17:38:28  oes
229  *    Cosmetics
230  *
231  *    Revision 1.50  2001/10/25 03:40:48  david__schmidt
232  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
233  *    threads to call select() simultaneously.  So, it's time to do a real, live,
234  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
235  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
236  *
237  *    Revision 1.49  2001/10/23 21:41:35  jongfoster
238  *    Added call to initialize the (statically-allocated of course)
239  *    "out of memory" CGI response.
240  *
241  *    Revision 1.48  2001/10/10 19:56:46  jongfoster
242  *    Moving some code that wasn't cookie-related out of an #ifdef
243  *    FEATURE_COOKIE_JAR
244  *
245  *    Revision 1.47  2001/10/10 16:44:36  oes
246  *    Added CONNECT destination port limitation check
247  *
248  *    Revision 1.46  2001/10/08 15:17:41  oes
249  *    Re-enabled SSL forwarding
250  *
251  *    Revision 1.45  2001/10/07 15:42:11  oes
252  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
253  *
254  *    Moved downgrading of the HTTP version from parse_http_request to
255  *      chat(), since we can't decide if it is necessary before we have
256  *      determined the actions for the URL. The HTTP command is now
257  *      *always* re-built so the repairs need no longer be special-cased.
258  *
259  *    filter_popups now gets a csp pointer so it can raise the new
260  *      CSP_FLAG_MODIFIED flag.
261  *
262  *    Bugfix
263  *
264  *    Added configurable size limit for the IOB. If the IOB grows so
265  *      large that the next read would exceed the limit, the header
266  *      is generated, and the header & unfiltered buffer are flushed
267  *      to the client. Chat then continues in non-buffering,
268  *      non-filtering body mode.
269  *
270  *    Revision 1.44  2001/10/02 18:13:57  oes
271  *    Ooops
272  *
273  *    Revision 1.43  2001/10/02 15:32:13  oes
274  *    Moved generation of hdr
275  *
276  *    Revision 1.42  2001/09/21 23:02:02  david__schmidt
277  *    Cleaning up 2 compiler warnings on OS/2.
278  *
279  *    Revision 1.41  2001/09/16 17:05:14  jongfoster
280  *    Removing unused #include showarg.h
281  *
282  *    Revision 1.40  2001/09/16 15:41:45  jongfoster
283  *    Fixing signed/unsigned comparison warning.
284  *
285  *    Revision 1.39  2001/09/16 13:21:27  jongfoster
286  *    Changes to use new list functions.
287  *
288  *    Revision 1.38  2001/09/16 13:01:46  jongfoster
289  *    Removing redundant function call that zeroed zalloc()'d memory.
290  *
291  *    Revision 1.37  2001/09/10 11:12:24  oes
292  *    Deleted unused variable
293  *
294  *    Revision 1.36  2001/09/10 10:56:15  oes
295  *    Silenced compiler warnings
296  *
297  *    Revision 1.35  2001/07/31 14:44:22  oes
298  *    Deleted unused size parameter from filter_popups()
299  *
300  *    Revision 1.34  2001/07/30 22:08:36  jongfoster
301  *    Tidying up #defines:
302  *    - All feature #defines are now of the form FEATURE_xxx
303  *    - Permanently turned off WIN_GUI_EDIT
304  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
305  *
306  *    Revision 1.33  2001/07/29 19:32:00  jongfoster
307  *    Renaming _main() [mingw32 only] to real_main(), for ANSI compliance.
308  *
309  *    Revision 1.32  2001/07/29 18:47:05  jongfoster
310  *    Adding missing #include "loadcfg.h"
311  *
312  *    Revision 1.31  2001/07/29 12:17:48  oes
313  *    Applied pthread fix by Paul Lieverse
314  *
315  *    Revision 1.30  2001/07/25 22:57:13  jongfoster
316  *    __BEOS__ no longer overrides FEATURE_PTHREAD.
317  *    This is because FEATURE_PTHREAD will soon be widely used, so I
318  *    want to keep it simple.
319  *
320  *    Revision 1.29  2001/07/24 12:47:06  oes
321  *    Applied BeOS support update by Eugenia
322  *
323  *    Revision 1.28  2001/07/23 13:26:12  oes
324  *    Fixed bug in popup-killing for the first read that caused binary garbage to be sent between headers and body
325  *
326  *    Revision 1.27  2001/07/19 19:09:47  haroon
327  *    - Added code to take care of the situation where while processing the first
328  *      server response (which includes the server header), after finding the end
329  *      of the headers we were not looking past the end of the headers for
330  *      content modification. I enabled it for filter_popups.
331  *      Someone else should look to see if other similar operations should be
332  *      done to the discarded portion of the buffer.
333  *
334  *      Note 2001/07/20: No, the other content modification mechanisms will process
335  *                       the whole iob later anyway. --oes
336  *
337  *    Revision 1.26  2001/07/18 12:31:36  oes
338  *    cosmetics
339  *
340  *    Revision 1.25  2001/07/15 19:43:49  jongfoster
341  *    Supports POSIX threads.
342  *    Also removed some unused #includes.
343  *
344  *    Revision 1.24  2001/07/13 14:00:40  oes
345  *     - Generic content modification scheme:
346  *       Each feature has its own applicability flag that is set
347  *       from csp->action->flags.
348  *       Replaced the "filtering" int flag , by a function pointer
349  *       "content_filter" to the function that will do the content
350  *       modification. If it is != NULL, the document will be buffered
351  *       and processed through *content_filter, which must set
352  *       csp->content_length and return a modified copy of the body
353  *       or return NULL (on failiure).
354  *     - Changed csp->is_text to the more generic bitmap csp->content_type
355  *       which can currently take the valued CT_TEXT or CT_GIF
356  *     - Reformatting etc
357  *     - Removed all #ifdef PCRS
358  *
359  *    Revision 1.23  2001/07/02 02:28:25  iwanttokeepanon
360  *    Added "#ifdef ACL_FILES" conditional compilation to line 1291 to exclude
361  *    the `block_acl' call.  This prevents a compilation error when the user
362  *    does not wish to use the "ACL" feature.
363  *
364  *    Revision 1.22  2001/06/29 21:45:41  oes
365  *    Indentation, CRLF->LF, Tab-> Space
366  *
367  *    Revision 1.21  2001/06/29 13:29:36  oes
368  *    - Cleaned up, improved comments
369  *    - Unified all possible interceptors (CGI,
370  *      block, trust, fast_redirect) in one
371  *      place, with one (CGI) answer generation
372  *      mechansim. Much clearer now.
373  *    - Removed the GIF image generation, which
374  *      is now done in filters.c:block_url()
375  *    - Made error conditions like domain lookup
376  *      failiure or (various) problems while talking
377  *      to the server use cgi.c:error_response()
378  *      instead of generating HTML/HTTP in chat() (yuck!)
379  *    - Removed logentry from cancelled commit
380  *
381  *    Revision 1.20  2001/06/09 10:55:28  jongfoster
382  *    Changing BUFSIZ ==> BUFFER_SIZE
383  *
384  *    Revision 1.19  2001/06/07 23:12:52  jongfoster
385  *    Replacing function pointer in struct gateway with a directly
386  *    called function forwarded_connect().
387  *    Replacing struct gateway with struct forward_spec
388  *
389  *    Revision 1.18  2001/06/03 19:12:16  oes
390  *    introduced new cgi handling
391  *
392  *    Revision 1.17  2001/06/01 20:07:23  jongfoster
393  *    Now uses action +image-blocker{} rather than config->tinygif
394  *
395  *    Revision 1.16  2001/06/01 18:49:17  jongfoster
396  *    Replaced "list_share" with "list" - the tiny memory gain was not
397  *    worth the extra complexity.
398  *
399  *    Revision 1.15  2001/05/31 21:24:47  jongfoster
400  *    Changed "permission" to "action" throughout.
401  *    Removed DEFAULT_USER_AGENT - it must now be specified manually.
402  *    Moved vanilla wafer check into chat(), since we must now
403  *    decide whether or not to add it based on the URL.
404  *
405  *    Revision 1.14  2001/05/29 20:14:01  joergs
406  *    AmigaOS bugfix: PCRS needs a lot of stack, stacksize for child threads
407  *    increased.
408  *
409  *    Revision 1.13  2001/05/29 09:50:24  jongfoster
410  *    Unified blocklist/imagelist/permissionslist.
411  *    File format is still under discussion, but the internal changes
412  *    are (mostly) done.
413  *
414  *    Also modified interceptor behaviour:
415  *    - We now intercept all URLs beginning with one of the following
416  *      prefixes (and *only* these prefixes):
417  *        * http://i.j.b/
418  *        * http://ijbswa.sf.net/config/
419  *        * http://ijbswa.sourceforge.net/config/
420  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
421  *    - Internal changes so that intercepted and fast redirect pages
422  *      are not replaced with an image.
423  *    - Interceptors now have the option to send a binary page direct
424  *      to the client. (i.e. ijb-send-banner uses this)
425  *    - Implemented show-url-info interceptor.  (Which is why I needed
426  *      the above interceptors changes - a typical URL is
427  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
428  *      The previous mechanism would not have intercepted that, and
429  *      if it had been intercepted then it then it would have replaced
430  *      it with an image.)
431  *
432  *    Revision 1.12  2001/05/27 22:17:04  oes
433  *
434  *    - re_process_buffer no longer writes the modified buffer
435  *      to the client, which was very ugly. It now returns the
436  *      buffer, which it is then written by chat.
437  *
438  *    - content_length now adjusts the Content-Length: header
439  *      for modified documents rather than crunch()ing it.
440  *      (Length info in csp->content_length, which is 0 for
441  *      unmodified documents)
442  *
443  *    - For this to work, sed() is called twice when filtering.
444  *
445  *    Revision 1.11  2001/05/26 17:27:53  jongfoster
446  *    Added support for CLF and fixed LOG_LEVEL_LOG.
447  *    Also did CRLF->LF fix of my previous patch.
448  *
449  *    Revision 1.10  2001/05/26 15:26:15  jongfoster
450  *    ACL feature now provides more security by immediately dropping
451  *    connections from untrusted hosts.
452  *
453  *    Revision 1.9  2001/05/26 00:28:36  jongfoster
454  *    Automatic reloading of config file.
455  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
456  *    Most of the global variables have been moved to a new
457  *    struct configuration_spec, accessed through csp->config->globalname
458  *    Most of the globals remaining are used by the Win32 GUI.
459  *
460  *    Revision 1.8  2001/05/25 22:43:18  jongfoster
461  *    Fixing minor memory leak and buffer overflow.
462  *
463  *    Revision 1.7  2001/05/25 22:34:30  jongfoster
464  *    Hard tabs->Spaces
465  *
466  *    Revision 1.6  2001/05/23 00:13:58  joergs
467  *    AmigaOS support fixed.
468  *
469  *    Revision 1.5  2001/05/22 18:46:04  oes
470  *
471  *    - Enabled filtering banners by size rather than URL
472  *      by adding patterns that replace all standard banner
473  *      sizes with the "Junkbuster" gif to the re_filterfile
474  *
475  *    - Enabled filtering WebBugs by providing a pattern
476  *      which kills all 1x1 images
477  *
478  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
479  *      which is selected by the (nonstandard and therefore
480  *      capital) letter 'U' in the option string.
481  *      It causes the quantifiers to be ungreedy by default.
482  *      Appending a ? turns back to greedy (!).
483  *
484  *    - Added a new interceptor ijb-send-banner, which
485  *      sends back the "Junkbuster" gif. Without imagelist or
486  *      MSIE detection support, or if tinygif = 1, or the
487  *      URL isn't recognized as an imageurl, a lame HTML
488  *      explanation is sent instead.
489  *
490  *    - Added new feature, which permits blocking remote
491  *      script redirects and firing back a local redirect
492  *      to the browser.
493  *      The feature is conditionally compiled, i.e. it
494  *      can be disabled with --disable-fast-redirects,
495  *      plus it must be activated by a "fast-redirects"
496  *      line in the config file, has its own log level
497  *      and of course wants to be displayed by show-proxy-args
498  *      Note: Boy, all the #ifdefs in 1001 locations and
499  *      all the fumbling with configure.in and acconfig.h
500  *      were *way* more work than the feature itself :-(
501  *
502  *    - Because a generic redirect template was needed for
503  *      this, tinygif = 3 now uses the same.
504  *
505  *    - Moved GIFs, and other static HTTP response templates
506  *      to project.h
507  *
508  *    - Some minor fixes
509  *
510  *    - Removed some >400 CRs again (Jon, you really worked
511  *      a lot! ;-)
512  *
513  *    Revision 1.4  2001/05/21 19:34:01  jongfoster
514  *    Made failure to bind() a fatal error.
515  *
516  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
517  *    Version 2.9.4 checkin.
518  *    - Merged popupfile and cookiefile, and added control over PCRS
519  *      filtering, in new "permissionsfile".
520  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
521  *      file error you now get a message box (in the Win32 GUI) rather
522  *      than the program exiting with no explanation.
523  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
524  *      skipping.
525  *    - Removed tabs from "config"
526  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
527  *    - Bumped up version number.
528  *
529  *    Revision 1.2  2001/05/17 22:34:44  oes
530  *     - Added hint on GIF char array generation to jcc.c
531  *     - Cleaned CRLF's from the sources and related files
532  *     - Repaired logging for REF and FRC
533  *
534  *    Revision 1.1.1.1  2001/05/15 13:58:56  oes
535  *    Initial import of version 2.9.3 source tree
536  *
537  *
538  *********************************************************************/
539 \f
540
541 #include "config.h"
542
543 #include <stdio.h>
544 #include <sys/types.h>
545 #include <stdlib.h>
546 #include <string.h>
547 #include <signal.h>
548 #include <fcntl.h>
549 #include <errno.h>
550
551 #ifdef FEATURE_PTHREAD
552 #include <pthread.h>
553 #endif /* def FEATURE_PTHREAD */
554
555 #ifdef _WIN32
556 # ifndef FEATURE_PTHREAD
557 #  ifndef STRICT
558 #   define STRICT
559 #  endif
560 #  include <windows.h>
561 #  include <process.h>
562 # endif /* ndef FEATURE_PTHREAD */
563
564 # include "win32.h"
565 # ifndef _WIN_CONSOLE
566 #  include "w32log.h"
567 # endif /* ndef _WIN_CONSOLE */
568
569 #else /* ifndef _WIN32 */
570
571 # if !defined (__OS2__)
572 # include <unistd.h>
573 # include <sys/wait.h>
574 # endif /* ndef __OS2__ */
575 # include <sys/time.h>
576 # include <sys/stat.h>
577 # include <sys/ioctl.h>
578
579 #ifdef sun
580 #include <sys/termios.h>
581 #endif /* sun */
582
583 #ifdef unix
584 #include <pwd.h>
585 #include <grp.h>
586 #endif
587
588 # include <signal.h>
589
590 # ifdef __BEOS__
591 #  include <socket.h>  /* BeOS has select() for sockets only. */
592 #  include <OS.h>      /* declarations for threads and stuff. */
593 # endif
594
595 # if defined(__EMX__) || defined(__OS2__)
596 #  include <sys/select.h>  /* OS/2/EMX needs a little help with select */
597 # endif
598 # ifdef __OS2__
599 #define INCL_DOS
600 # include <os2.h>
601 #define bzero(B,N) memset(B,0x00,n)
602 # endif
603
604 # ifndef FD_ZERO
605 #  include <select.h>
606 # endif
607
608 #endif
609
610 #include "project.h"
611 #include "list.h"
612 #include "jcc.h"
613 #include "filters.h"
614 #include "loaders.h"
615 #include "parsers.h"
616 #include "killpopup.h"
617 #include "miscutil.h"
618 #include "errlog.h"
619 #include "jbsockets.h"
620 #include "gateway.h"
621 #include "actions.h"
622 #include "cgi.h"
623 #include "loadcfg.h"
624 #include "urlmatch.h"
625 #ifdef FEATURE_ACTIVITY_CONSOLE
626 #include "stats.h"
627 #endif /* def FEATURE_ACTIVITY_CONSOLE */
628
629 const char jcc_h_rcs[] = JCC_H_VERSION;
630 const char project_h_rcs[] = PROJECT_H_VERSION;
631
632 int no_daemon = 0;
633 struct client_state  clients[1];
634 struct file_list     files[1];
635
636 #ifdef FEATURE_STATISTICS
637 int urls_read     = 0;     /* total nr of urls read inc rejected */
638 int urls_rejected = 0;     /* total nr of urls rejected */
639 #endif /* def FEATURE_STATISTICS */
640
641 #ifdef FEATURE_GRACEFUL_TERMINATION
642 int g_terminate = 0;
643 #endif
644
645 static void listen_loop(void);
646 static void chat(struct client_state *csp);
647 static jb_err relay_server_traffic( struct client_state *csp ) ;
648 static jb_err read_client_headers( struct client_state *csp, struct http_request *http ) ;
649 static jb_err process_client_headers( struct client_state *csp, struct http_request *http ) ;
650 static jb_err intercept_page( struct client_state *csp, struct http_request *http );
651 static jb_err open_forwarding_connection( struct client_state *csp );
652 static jb_err send_client_headers_to_server( struct client_state *csp, struct http_request *http,  char* hdr );
653 static jb_err is_connect_request_allowed( struct client_state *csp ) ;
654
655
656 #ifdef AMIGA
657 void serve(struct client_state *csp);
658 #else /* ifndef AMIGA */
659 static void serve(struct client_state *csp);
660 #endif /* def AMIGA */
661
662 #ifdef __BEOS__
663 static int32 server_thread(void *data);
664 #endif /* def __BEOS__ */
665
666 #ifdef _WIN32
667 #define sleep(N)  Sleep(((N) * 1000))
668 #endif
669
670 #ifdef __OS2__
671 #define sleep(N)  DosSleep(((N) * 100))
672 #endif
673
674 #if defined(unix) || defined(__EMX__)
675 const char *basedir;
676 const char *pidfile = NULL;
677 int received_hup_signal = 0;
678 #endif /* defined unix */
679
680 /* The vanilla wafer. */
681 static const char VANILLA_WAFER[] =
682    "NOTICE=TO_WHOM_IT_MAY_CONCERN_"
683    "Do_not_send_me_any_copyrighted_information_other_than_the_"
684    "document_that_I_am_requesting_or_any_of_its_necessary_components._"
685    "In_particular_do_not_send_me_any_cookies_that_"
686    "are_subject_to_a_claim_of_copyright_by_anybody._"
687    "Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_"
688    "(copyright_or_otherwise)_applying_to_any_cookie._";
689
690 /**
691  * HTTP header sent when doing HTTPS tunnelling ("CONNECT" method).
692  */
693 static const char CSUCCEED[] =
694    "HTTP/1.0 200 Connection established\n"
695    "Proxy-Agent: Privoxy/" VERSION "\r\n\r\n";
696
697
698 /**
699  * HTTP reply sent when the browser sends something unintelligible.
700  */
701 static const char CHEADER[] =
702    "HTTP/1.0 400 Invalid header received from browser\r\n\r\n";
703
704
705 /**
706  * HTTP reply sent when the browser tries to tunnel ("CONNECT") to something
707  * other than a HTTPS port (as defined by +limit-connect).
708  */
709 static const char CFORBIDDEN[] =
710    "HTTP/1.0 403 Connection not allowable\r\nX-Hint: If you read this message interactively, then you know why this happens ,-)\r\n\r\n";
711
712 #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA)
713 /*********************************************************************
714  *
715  * Function    :  sig_handler 
716  *
717  * Description :  Signal handler for different signals.
718  *                Exit gracefully on ABRT, TERM and  INT
719  *                or set a flag that will cause the errlog
720  *                to be reopened by the main thread on HUP.
721  *
722  * Parameters  :
723  *          1  :  the_signal = the signal cause this function to call
724  *
725  * Returns     :  - 
726  *
727  *********************************************************************/
728 static void sig_handler(int the_signal)
729 {
730    switch(the_signal)
731    {
732       case SIGABRT:
733       case SIGTERM:
734       case SIGINT:
735          log_error(LOG_LEVEL_INFO, "exiting by signal %d .. bye", the_signal);
736 #if defined(unix)
737          unlink(pidfile);
738 #endif /* unix */
739          exit(the_signal);
740          break;
741
742       case SIGHUP:
743          received_hup_signal = 1;
744          break;         
745
746       default:
747          /* 
748           * We shouldn't be here, unless we catch signals
749           * in main() that we can't handle here!
750           */
751          log_error(LOG_LEVEL_FATAL, "sig_handler: exiting on unexpected signal %d", the_signal);
752    }
753    return;
754
755 }
756 #endif
757
758
759 /*********************************************************************
760  *
761  * Function    :  chat
762  *
763  * Description :  Once a connection to the client has been accepted,
764  *                this function is called (via serve()) to handle the
765  *                main business of the communication.  When this
766  *                function returns, the caller must close the client
767  *                socket handle.
768  *
769  * Parameters  :
770  *          1  :  csp = Current client state (buffers, headers, etc...)
771  *
772  * Returns     :  void
773  *
774  *********************************************************************/
775 static void chat(struct client_state *csp)
776 {
777
778
779    char buf[BUFFER_SIZE];
780    int len; /* for buffer sizes */
781    char *hdr; 
782    fd_set rfds;
783    int n;
784    jb_socket maxfd;
785    int byte_count = 0;
786    struct http_request *http;
787
788    http = csp->http;
789
790    if (read_client_headers(csp, http ) != JB_ERR_OK )
791       return;
792    
793
794    /* Process the client headers */
795    if (process_client_headers(csp, http) != JB_ERR_OK)
796       return;
797    
798
799    /* Check if this connection request is permitted */
800    if (is_connect_request_allowed(csp) != JB_ERR_OK)
801       return ;
802
803    /*
804     * We have a valid and legit request. Now, check to see if we need to
805     * intercept it.
806     */
807    if (intercept_page(csp, http) != JB_ERR_OK)
808       return;
809   
810    /* 
811     * The page passed the intercept routine, so open a forwarding
812     * connection for conversation
813     */
814    if (open_forwarding_connection(csp) != JB_ERR_OK )
815       return ;
816
817
818
819    hdr = sed(client_patterns, add_client_headers, csp);
820    if (hdr == NULL)
821    {
822       /* FIXME Should handle error properly */
823       log_error(LOG_LEVEL_FATAL, "Out of memory parsing client header");
824    }
825
826    /* FIXME - where should this go, logically ? */
827    list_remove_all(csp->headers);
828
829
830    if (send_client_headers_to_server(csp, http, hdr) != JB_ERR_OK)
831       return ;
832
833
834    /* we're finished with the client's header */
835    freez(hdr);
836
837    maxfd = ( csp->cfd > csp->sfd ) ? csp->cfd : csp->sfd;
838
839    /* pass data between the client and server
840     * until one or the other shuts down the connection.
841     */
842
843    /* Set the flag for reading headers to False */
844    /* This is used in relay_server_traffic */
845    csp->all_headers_read = 0 ;
846
847    for (;;)
848    {
849       jb_err tmp_ret_val = JB_ERR_GENERIC ;
850
851 #ifdef __OS2__
852       /*
853        * FD_ZERO here seems to point to an errant macro which crashes.
854        * So do this by hand for now...
855        */
856       memset(&rfds,0x00,sizeof(fd_set));
857 #else
858       FD_ZERO(&rfds);
859 #endif
860       FD_SET(csp->cfd, &rfds);
861       FD_SET(csp->sfd, &rfds);
862
863       n = select((int)maxfd+1, &rfds, NULL, NULL, NULL);
864
865       if (n < 0)
866       {
867          log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
868          return;
869       }
870
871       /*
872        * This is the body of the browser's request.
873        * Just read it and write it.
874        */
875
876       if (FD_ISSET(csp->cfd, &rfds))
877       {
878          len = read_socket(csp->cfd, buf, sizeof(buf));
879
880          if (len <= 0)
881          {
882             log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %d",
883              csp->ip_addr_str, http->ocmd, byte_count);
884             return ;
885          }
886
887          if (write_socket(csp->sfd, buf, (size_t)len))
888          {
889             log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
890             return;
891          }
892          continue;
893       }
894
895       /*
896        * Check if the server wants to talk, and if so, converse.
897        */
898
899       if (FD_ISSET(csp->sfd, &rfds))
900          tmp_ret_val = relay_server_traffic(csp) ;
901
902
903       if (tmp_ret_val == JB_ERR_OK)
904          continue ;
905       else
906          return; 
907    }
908    /* We should never get here! */
909    log_error(LOG_LEVEL_FATAL, "chat() : logic error in for() loop" ) ;
910 } /* END chat() */
911
912
913 /*********************************************************************
914  *
915  * Function    :  serve
916  *
917  * Description :  This is little more than chat.  We only "serve" to
918  *                to close any socket that chat may have opened.
919  *
920  * Parameters  :
921  *          1  :  csp = Current client state (buffers, headers, etc...)
922  *
923  * Returns     :  N/A
924  *
925  *********************************************************************/
926 #ifdef AMIGA
927 void serve(struct client_state *csp)
928 #else /* ifndef AMIGA */
929 static void serve(struct client_state *csp)
930 #endif /* def AMIGA */
931 {
932    chat(csp);
933    close_socket(csp->cfd);
934
935    if (csp->sfd != JB_INVALID_SOCKET)
936    {
937       close_socket(csp->sfd);
938    }
939
940    csp->flags &= ~CSP_FLAG_ACTIVE;
941
942 }
943
944
945 #ifdef __BEOS__
946 /*********************************************************************
947  *
948  * Function    :  server_thread
949  *
950  * Description :  We only exist to call `serve' in a threaded environment.
951  *
952  * Parameters  :
953  *          1  :  data = Current client state (buffers, headers, etc...)
954  *
955  * Returns     :  Always 0.
956  *
957  *********************************************************************/
958 static int32 server_thread(void *data)
959 {
960    serve((struct client_state *) data);
961    return 0;
962
963 }
964 #endif
965
966
967 /*********************************************************************
968  *
969  * Function    :  usage
970  *
971  * Description :  Print usage info & exit.
972  *
973  * Parameters  :  Pointer to argv[0] for identifying ourselves
974  *
975  * Returns     :  No. ,-)
976  *
977  *********************************************************************/
978 void usage(const char *myname)
979 {
980    printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n"
981            "Usage: %s [--help] [--version] [--no-daemon] [--pidfile pidfile] [--user user[.group]] [configfile]\n"
982            "Aborting.\n", myname);
983  
984    exit(2);
985
986 }
987
988
989 /*********************************************************************
990  *
991  * Function    :  main
992  *
993  * Description :  Load the config file and start the listen loop.
994  *                This function is a lot more *sane* with the `load_config'
995  *                and `listen_loop' functions; although it stills does
996  *                a *little* too much for my taste.
997  *
998  * Parameters  :
999  *          1  :  argc = Number of parameters (including $0).
1000  *          2  :  argv = Array of (char *)'s to the parameters.
1001  *
1002  * Returns     :  1 if : can't open config file, unrecognized directive,
1003  *                stats requested in multi-thread mode, can't open the
1004  *                log file, can't open the jar file, listen port is invalid,
1005  *                any load fails, and can't bind port.
1006  *
1007  *                Else main never returns, the process must be signaled
1008  *                to terminate execution.  Or, on Windows, use the
1009  *                "File", "Exit" menu option.
1010  *
1011  *********************************************************************/
1012 #ifdef __MINGW32__
1013 int real_main(int argc, const char *argv[])
1014 #else
1015 int main(int argc, const char *argv[])
1016 #endif
1017 {
1018    int argc_pos = 0;
1019 #ifdef unix
1020    struct passwd *pw = NULL;
1021    struct group *grp = NULL;
1022    char *p;
1023 #endif
1024
1025    Argc = argc;
1026    Argv = argv;
1027
1028    configfile =
1029 #if !defined(_WIN32)
1030    "config"
1031 #else
1032    "config.txt"
1033 #endif
1034       ;
1035
1036    /*
1037     * Parse the command line arguments
1038     */
1039    while (++argc_pos < argc)
1040    {
1041 #if !defined(_WIN32) || defined(_WIN_CONSOLE)
1042
1043       if (strcmp(argv[argc_pos], "--help") == 0)
1044       {
1045          usage(argv[0]);
1046       }
1047
1048       else if(strcmp(argv[argc_pos], "--version") == 0)
1049       {
1050          printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n");
1051          exit(0);
1052       }
1053
1054       else if (strcmp(argv[argc_pos], "--no-daemon" ) == 0)
1055       {
1056          no_daemon = 1;
1057       }
1058 #if defined(unix)
1059       else if (strcmp(argv[argc_pos], "--pidfile" ) == 0)
1060       {
1061          if (++argc_pos == argc) usage(argv[0]);
1062          pidfile = strdup(argv[argc_pos]);
1063       }
1064
1065       else if (strcmp(argv[argc_pos], "--user" ) == 0)
1066       {
1067          if (++argc_pos == argc) usage(argv[argc_pos]);
1068
1069          if ((NULL != (p = strchr(argv[argc_pos], '.'))) && *(p + 1) != '0')
1070          {
1071             *p++ = '\0';
1072             if (NULL == (grp = getgrnam(p)))
1073             {
1074                log_error(LOG_LEVEL_FATAL, "Group %s not found.", p);
1075             }
1076          }
1077
1078          if (NULL == (pw = getpwnam(argv[argc_pos])))
1079          {
1080             log_error(LOG_LEVEL_FATAL, "User %s not found.", argv[argc_pos]);
1081          }
1082
1083          if (p != NULL) *--p = '\0';
1084       }
1085 #endif /* defined(unix) */
1086       else
1087 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
1088       {
1089          configfile = argv[argc_pos];
1090       }
1091
1092    } /* -END- while (more arguments) */
1093
1094 #if defined(unix)
1095    if ( *configfile != '/' )
1096    {
1097       char *abs_file;
1098
1099       /* make config-filename absolute here */
1100       if ( !(basedir = getcwd( NULL, 1024 )))
1101       {
1102          perror("get working dir failed");
1103          exit( 1 );
1104       }
1105
1106       if ( !(abs_file = malloc( strlen( basedir ) + strlen( configfile ) + 5 )))
1107       {
1108          perror("malloc failed");
1109          exit( 1 );
1110       }
1111       strcpy( abs_file, basedir );
1112       strcat( abs_file, "/" );
1113       strcat( abs_file, configfile );
1114       configfile = abs_file;
1115    }
1116 #endif /* defined unix */
1117
1118
1119    files->next = NULL;
1120
1121 #ifdef AMIGA
1122    InitAmiga();
1123 #elif defined(_WIN32)
1124    InitWin32();
1125 #endif
1126
1127    /*
1128     * Unix signal handling
1129     *
1130     * Catch the abort, interrupt and terminate signals for a graceful exit
1131     * Catch the hangup signal so the errlog can be reopened.
1132     * Ignore the broken pipe and child signals
1133     *  FIXME: Isn't ignoring the default for SIGCHLD anyway and why ignore SIGPIPE? 
1134     */
1135 #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA)
1136 {
1137    int idx;
1138    const int catched_signals[] = { SIGABRT, SIGTERM, SIGINT, SIGHUP, 0 };
1139    const int ignored_signals[] = { SIGPIPE, SIGCHLD, 0 };
1140
1141    for (idx = 0; catched_signals[idx] != 0; idx++)
1142    {
1143       if (signal(catched_signals[idx], sig_handler) == SIG_ERR)
1144       {
1145          log_error(LOG_LEVEL_FATAL, "Can't set signal-handler for signal %d: %E", catched_signals[idx]);
1146       }
1147    }
1148
1149    for (idx = 0; ignored_signals[idx] != 0; idx++)
1150    {
1151       if (signal(ignored_signals[idx], SIG_IGN) == SIG_ERR)
1152       {
1153          log_error(LOG_LEVEL_FATAL, "Can't set ignore-handler for signal %d: %E", ignored_signals[idx]);
1154       }
1155    }
1156
1157 }
1158 #else /* ifdef _WIN32 */
1159 # ifdef _WIN_CONSOLE
1160    /*
1161     * We *are* in a windows console app.
1162     * Print a verbose messages about FAQ's and such
1163     */
1164    printf(win32_blurb);
1165 # endif /* def _WIN_CONSOLE */
1166 #endif /* def _WIN32 */
1167
1168
1169    /* Initialize the CGI subsystem */
1170    cgi_init_error_messages();
1171
1172    /*
1173     * If runnig on unix and without the --nodaemon
1174     * option, become a daemon. I.e. fork, detach
1175     * from tty and get process group leadership
1176     */
1177 #if defined(unix)
1178    {
1179       pid_t pid = 0;
1180 #if 0
1181       int   fd;
1182 #endif
1183
1184       if (!no_daemon)
1185       {
1186          pid  = fork();
1187
1188          if ( pid < 0 ) /* error */
1189          {
1190             perror("fork");
1191             exit( 3 );
1192          }
1193          else if ( pid != 0 ) /* parent */
1194          {
1195             int status;
1196             pid_t wpid;
1197             /*
1198              * must check for errors
1199              * child died due to missing files aso
1200              */
1201             sleep( 1 );
1202             wpid = waitpid( pid, &status, WNOHANG );
1203             if ( wpid != 0 )
1204             {
1205                exit( 1 );
1206             }
1207             exit( 0 );
1208          }
1209          /* child */
1210 #if 1
1211          /* Should be more portable, but not as well tested */
1212          setsid();
1213 #else /* !1 */
1214 #ifdef __FreeBSD__
1215          setpgrp(0,0);
1216 #else /* ndef __FreeBSD__ */
1217          setpgrp();
1218 #endif /* ndef __FreeBSD__ */
1219          fd = open("/dev/tty", O_RDONLY);
1220          if ( fd )
1221          {
1222             /* no error check here */
1223             ioctl( fd, TIOCNOTTY,0 );
1224             close ( fd );
1225          }
1226 #endif /* 1 */
1227          /* FIXME: should close stderr (fd 2) here too, but the test
1228           * for existence
1229           * and load config file is done in listen_loop() and puts
1230           * some messages on stderr there.
1231           */
1232
1233          close( 0 );
1234          close( 1 );
1235          chdir("/");
1236
1237       } /* -END- if (!no_daemon) */
1238
1239       /*
1240        * As soon as we have written the PID file, we can switch
1241        * to the user and group ID indicated by the --user option
1242        */
1243       write_pid_file();
1244    
1245       if (NULL != pw)
1246       {
1247          if (((NULL != grp) && setgid(grp->gr_gid)) || (setgid(pw->pw_gid)))
1248          {
1249             log_error(LOG_LEVEL_FATAL, "Cannot setgid(): Insufficient permissions.");
1250          }
1251          if (setuid(pw->pw_uid))
1252          {
1253             log_error(LOG_LEVEL_FATAL, "Cannot setuid(): Insufficient permissions.");
1254          }
1255       }
1256    }
1257 #endif /* defined unix */
1258
1259    listen_loop();
1260
1261    /* NOTREACHED */
1262    return(-1);
1263
1264 }
1265
1266
1267 /*********************************************************************
1268  *
1269  * Function    :  bind_port_helper
1270  *
1271  * Description :  Bind the listen port.  Handles logging, and aborts
1272  *                on failure.
1273  *
1274  * Parameters  :
1275  *          1  :  config = Privoxy configuration.  Specifies port
1276  *                         to bind to.
1277  *
1278  * Returns     :  Port that was opened.
1279  *
1280  *********************************************************************/
1281 static jb_socket bind_port_helper(struct configuration_spec * config)
1282 {
1283    int result;
1284    jb_socket bfd;
1285
1286    if ( (config->haddr != NULL)
1287      && (config->haddr[0] == '1')
1288      && (config->haddr[1] == '2')
1289      && (config->haddr[2] == '7')
1290      && (config->haddr[3] == '.') )
1291    {
1292       log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only",
1293                 config->hport);
1294    }
1295    else if (config->haddr == NULL)
1296    {
1297       log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
1298                 config->hport);
1299    }
1300    else
1301    {
1302       log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s",
1303                 config->hport, config->haddr);
1304    }
1305
1306    result = bind_port(config->haddr, config->hport, &bfd);
1307
1308    if (result < 0)
1309    {
1310       switch(result)
1311       {
1312          case -3 :
1313             log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
1314                "There may be another Privoxy or some other "
1315                "proxy running on port %d",
1316                (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
1317                       config->hport, config->hport);
1318
1319          case -2 :
1320             log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: " 
1321                "The hostname is not resolvable",
1322                (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
1323
1324          default :
1325             log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E",
1326                (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
1327       }
1328
1329       /* shouldn't get here */
1330       return JB_INVALID_SOCKET;
1331    }
1332
1333    config->need_bind = 0;
1334
1335    return bfd;
1336 }
1337
1338
1339 /*********************************************************************
1340  *
1341  * Function    :  listen_loop
1342  *
1343  * Description :  bind the listen port and enter a "FOREVER" listening loop.
1344  *
1345  * Parameters  :  N/A
1346  *
1347  * Returns     :  Never.
1348  *
1349  *********************************************************************/
1350 static void listen_loop(void)
1351 {
1352    struct client_state *csp = NULL;
1353    jb_socket bfd;
1354    struct configuration_spec * config;
1355
1356    config = load_config();
1357
1358    bfd = bind_port_helper(config);
1359
1360 #ifdef FEATURE_ACTIVITY_CONSOLE
1361    init_stats_config(config);
1362 #endif /* def FEATURE_ACTIVITY_CONSOLE */
1363
1364 #ifdef FEATURE_GRACEFUL_TERMINATION
1365    while (!g_terminate)
1366 #else
1367    for (;;)
1368 #endif
1369    {
1370 #if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1371       while (waitpid(-1, NULL, WNOHANG) > 0)
1372       {
1373          /* zombie children */
1374       }
1375 #endif /* !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1376
1377       /*
1378        * Free data that was used by died threads
1379        */
1380       sweep();
1381
1382 #if defined(unix)
1383       /*
1384        * Re-open the errlog after HUP signal
1385        */
1386       if (received_hup_signal)
1387       {
1388          init_error_log(Argv[0], config->logfile, config->debug);
1389          received_hup_signal = 0;
1390       }
1391 #endif
1392
1393 #ifdef __OS2__
1394 #ifdef FEATURE_COOKIE_JAR
1395       /*
1396        * Need a workaround here: we have to fclose() the jarfile, or we die because it's
1397        * already open.  I think unload_configfile() is not being run, which should do
1398        * this work.  Until that can get resolved, we'll use this workaround.
1399        *
1400        * [Note from Jon: We don't unload_configfile() until all existing threads have
1401        * exited - they're likely to hang aroung transferring data to the browser.]
1402        */
1403        if (csp)
1404          if(csp->config)
1405            if (csp->config->jar)
1406            {
1407              fclose(csp->config->jar);
1408              csp->config->jar = NULL;
1409            }
1410 #endif /* FEATURE_COOKIE_JAR */
1411 #endif /* __OS2__ */
1412
1413       if ( NULL == (csp = (struct client_state *) zalloc(sizeof(*csp))) )
1414       {
1415          log_error(LOG_LEVEL_FATAL, "malloc(%d) for csp failed: %E", sizeof(*csp));
1416          continue;
1417       }
1418
1419       csp->flags |= CSP_FLAG_ACTIVE;
1420       csp->sfd    = JB_INVALID_SOCKET;
1421
1422       csp->config = config = load_config();
1423
1424       if ( config->need_bind )
1425       {
1426          /*
1427           * Since we were listening to the "old port", we will not see
1428           * a "listen" param change until the next IJB request.  So, at
1429           * least 1 more request must be made for us to find the new
1430           * setting.  I am simply closing the old socket and binding the
1431           * new one.
1432           *
1433           * Which-ever is correct, we will serve 1 more page via the
1434           * old settings.  This should probably be a "show-proxy-args"
1435           * request.  This should not be a so common of an operation
1436           * that this will hurt people's feelings.
1437           */
1438
1439          close_socket(bfd);
1440
1441          bfd = bind_port_helper(config);
1442       }
1443
1444       log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
1445
1446       if (!accept_connection(csp, bfd))
1447       {
1448          log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
1449
1450 #ifdef AMIGA
1451          if(!childs)
1452          {
1453             exit(1);
1454          }
1455 #endif
1456          freez(csp);
1457          continue;
1458       }
1459       else
1460       {
1461          log_error(LOG_LEVEL_CONNECT, "OK");
1462       }
1463
1464 #ifdef FEATURE_TOGGLE
1465       if (g_bToggleIJB)
1466       {
1467          csp->flags |= CSP_FLAG_TOGGLED_ON;
1468       }
1469 #endif /* def FEATURE_TOGGLE */
1470
1471 #ifdef FEATURE_ACTIVITY_CONSOLE
1472       update_stats_config(config);
1473 #endif /* def FEATURE_ACTIVITY_CONSOLE */
1474
1475       if (run_loader(csp))
1476       {
1477          log_error(LOG_LEVEL_FATAL, "a loader failed - must exit");
1478          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1479       }
1480
1481 #ifdef FEATURE_ACL
1482       if (block_acl(NULL,csp))
1483       {
1484 #ifdef FEATURE_ACTIVITY_CONSOLE
1485          accumulate_stats(STATS_ACL_RESTRICT,1);
1486 #endif /* def FEATURE_ACTIVITY_CONSOLE */
1487          log_error(LOG_LEVEL_CONNECT, "Connection dropped due to ACL");
1488          close_socket(csp->cfd);
1489          freez(csp);
1490          continue;
1491       }
1492 #endif /* def FEATURE_ACL */
1493
1494       /* add it to the list of clients */
1495       csp->next = clients->next;
1496       clients->next = csp;
1497
1498       if (config->multi_threaded)
1499       {
1500          int child_id;
1501
1502 /* this is a switch () statment in the C preprocessor - ugh */
1503 #undef SELECTED_ONE_OPTION
1504
1505 /* Use Pthreads in preference to native code */
1506 #if defined(FEATURE_PTHREAD) && !defined(SELECTED_ONE_OPTION)
1507 #define SELECTED_ONE_OPTION
1508          {
1509             pthread_t the_thread;
1510             pthread_attr_t attrs;
1511
1512             pthread_attr_init(&attrs);
1513             pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
1514             child_id = (pthread_create(&the_thread, &attrs,
1515                (void*)serve, csp) ? -1 : 0);
1516             pthread_attr_destroy(&attrs);
1517          }
1518 #endif
1519
1520 #if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION)
1521 #define SELECTED_ONE_OPTION
1522          child_id = _beginthread(
1523             (void (*)(void *))serve,
1524             64 * 1024,
1525             csp);
1526 #endif
1527
1528 #if defined(__OS2__) && !defined(SELECTED_ONE_OPTION)
1529 #define SELECTED_ONE_OPTION
1530          child_id = _beginthread(
1531             (void(* _Optlink)(void*))serve,
1532             NULL,
1533             64 * 1024,
1534             csp);
1535 #endif
1536
1537 #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION)
1538 #define SELECTED_ONE_OPTION
1539          {
1540             thread_id tid = spawn_thread
1541                (server_thread, "server", B_NORMAL_PRIORITY, csp);
1542
1543             if ((tid >= 0) && (resume_thread(tid) == B_OK))
1544             {
1545                child_id = (int) tid;
1546             }
1547             else
1548             {
1549                child_id = -1;
1550             }
1551          }
1552 #endif
1553
1554 #if defined(AMIGA) && !defined(SELECTED_ONE_OPTION)
1555 #define SELECTED_ONE_OPTION
1556          csp->cfd = ReleaseSocket(csp->cfd, -1);
1557          if((child_id = (int)CreateNewProcTags(
1558             NP_Entry, (ULONG)server_thread,
1559             NP_Output, Output(),
1560             NP_CloseOutput, FALSE,
1561             NP_Name, (ULONG)"privoxy child",
1562             NP_StackSize, 200*1024,
1563             TAG_DONE)))
1564          {
1565             childs++;
1566             ((struct Task *)child_id)->tc_UserData = csp;
1567             Signal((struct Task *)child_id, SIGF_SINGLE);
1568             Wait(SIGF_SINGLE);
1569          }
1570 #endif
1571
1572 #if !defined(SELECTED_ONE_OPTION)
1573          child_id = fork();
1574
1575          /* This block is only needed when using fork().
1576           * When using threads, the server thread was
1577           * created and run by the call to _beginthread().
1578           */
1579          if (child_id == 0)   /* child */
1580          {
1581             serve(csp);
1582             _exit(0);
1583
1584          }
1585          else if (child_id > 0) /* parent */
1586          {
1587             /* in a fork()'d environment, the parent's
1588              * copy of the client socket and the CSP
1589              * are not used.
1590              */
1591
1592 #if !defined(_WIN32) && defined(__CYGWIN__)
1593             wait( NULL );
1594 #endif /* !defined(_WIN32) && defined(__CYGWIN__) */
1595             close_socket(csp->cfd);
1596             csp->flags &= ~CSP_FLAG_ACTIVE;
1597          }
1598 #endif
1599
1600 #undef SELECTED_ONE_OPTION
1601 /* end of cpp switch () */
1602
1603          if (child_id < 0) /* failed */
1604          {
1605             char buf[BUFFER_SIZE];
1606
1607             log_error(LOG_LEVEL_ERROR, "can't fork: %E");
1608
1609             sprintf(buf , "Privoxy: can't fork: errno = %d", errno);
1610
1611             write_socket(csp->cfd, buf, strlen(buf));
1612             close_socket(csp->cfd);
1613             csp->flags &= ~CSP_FLAG_ACTIVE;
1614             sleep(5);
1615             continue;
1616          }
1617       }
1618       else
1619       {
1620          serve(csp);
1621       }
1622    }
1623
1624    /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */
1625
1626    /* Clean up.  Aim: free all memory (no leaks) */
1627 #ifdef FEATURE_GRACEFUL_TERMINATION
1628
1629    log_error(LOG_LEVEL_ERROR, "Graceful termination requested");
1630
1631    unload_current_config_file();
1632    unload_current_actions_file();
1633    unload_current_re_filterfile();
1634 #ifdef FEATURE_TRUST
1635    unload_current_trust_file();
1636 #endif
1637
1638    if (config->multi_threaded)
1639    {
1640       int i = 60;
1641       do
1642       {
1643          sleep(1);
1644          sweep();
1645       } while ((clients->next != NULL) && (--i > 0));
1646
1647       if (i <= 0)
1648       {
1649          log_error(LOG_LEVEL_ERROR, "Graceful termination failed - still some live clients after 1 minute wait.");
1650       }
1651    }
1652    sweep();
1653    sweep();
1654
1655 #if defined(unix)
1656    free(basedir);
1657 #endif
1658 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
1659    /* Cleanup - remove taskbar icon etc. */
1660    TermLogWindow();
1661 #endif
1662
1663    exit(0);
1664 #endif /* FEATURE_GRACEFUL_TERMINATION */
1665
1666 }
1667
1668 /*********************************************************************
1669  *
1670  * Function    :  relay_server_traffic
1671  *
1672  * Description :  receive traffic from the server and relay it
1673  *                to the client, with some processing
1674  *
1675  * Parameters  :
1676  *          1  :  client_state structure
1677  *                         
1678  *
1679  * Returns     :  JB_ERR_OK if there may be more work
1680  *             :  other values for errors
1681  *
1682  **********************************************************************/
1683
1684 static jb_err relay_server_traffic( struct client_state *csp )
1685 {
1686 #ifdef FEATURE_KILL_POPUPS
1687    int block_popups;         /* bool, 1==will block popups */
1688    int block_popups_now = 0; /* bool, 1==currently blocking popups */
1689 #endif /* def FEATURE_KILL_POPUPS */
1690    
1691    char buf[BUFFER_SIZE];
1692    int len; /* for buffer sizes */
1693    int ms_iis5_hack = 0;
1694    int byte_count = 0;
1695    char *hdr;
1696    char *p;
1697
1698    /* Skeleton for HTTP response, if we should intercept the request */
1699    struct http_response *rsp;
1700
1701    int pcrs_filter;        /* bool, 1==will filter through pcrs */
1702    int gif_deanimate;      /* bool, 1==will deanimate gifs */
1703
1704 #ifdef FEATURE_KILL_POPUPS
1705    block_popups               = ((csp->action->flags & ACTION_NO_POPUPS) != 0);
1706 #endif /* def FEATURE_KILL_POPUPS */
1707
1708    pcrs_filter                = (csp->rlist != NULL) &&  /* There are expressions to be used */
1709                                 (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]));
1710
1711    gif_deanimate              = ((csp->action->flags & ACTION_DEANIMATE) != 0);
1712
1713
1714    fflush (0);
1715    len = read_socket (csp->sfd, buf, sizeof (buf) - 1);
1716
1717    if (len < 0)
1718    {
1719       log_error (LOG_LEVEL_ERROR, "read from: %s failed: %E", csp->http->host);
1720
1721       log_error (LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
1722          csp->ip_addr_str, csp->http->ocmd);
1723
1724       rsp = error_response (csp, "connect-failed", errno);
1725
1726       if (rsp)
1727       {
1728          if (write_socket (csp->cfd, rsp->head, rsp->head_length)
1729             || write_socket (csp->cfd, rsp->body, rsp->content_length))
1730          {
1731             log_error (LOG_LEVEL_ERROR, "write to: %s failed: %E",
1732                        csp->http->host);
1733          }
1734       }
1735
1736       free_http_response (rsp);
1737       return JB_ERR_GENERIC;
1738    }
1739
1740    /* Add a trailing zero.  This lets filter_popups
1741     * use string operations.
1742     */
1743    buf[len] = '\0';
1744
1745 #ifdef FEATURE_KILL_POPUPS
1746    /* Filter the popups on this read. */
1747    if (block_popups_now)
1748    {
1749       filter_popups (buf, csp);
1750    }
1751 #endif /* def FEATURE_KILL_POPUPS */
1752
1753
1754    /* Normally, this would indicate that we've read
1755     * as much as the server has sent us and we can
1756     * close the client connection.  However, Microsoft
1757     * in its wisdom has released IIS/5 with a bug that
1758     * prevents it from sending the trailing \r\n in
1759     * a 302 redirect header (and possibly other headers).
1760     * To work around this if we've haven't parsed
1761     * a full header we'll append a trailing \r\n
1762     * and see if this now generates a valid one.
1763     *
1764     * This hack shouldn't have any impacts.  If we've
1765     * already transmitted the header or if this is a
1766     * SSL connection, then we won't bother with this
1767     * hack.  So we only work on partially received
1768     * headers.  If we append a \r\n and this still
1769     * doesn't generate a valid header, then we won't
1770     * transmit anything to the client.
1771     */
1772    if (len == 0)
1773    {
1774
1775       if (csp->all_headers_read || csp->http->ssl)
1776       {
1777          /*
1778           * If we have been buffering up the document,
1779           * now is the time to apply content modification
1780           * and send the result to the client.
1781           */
1782          if (csp->content_filter)
1783          {
1784             /*
1785              * If the content filter fails, use the original
1786              * buffer and length.
1787              * (see p != NULL ? p : csp->iob->cur below)
1788              */
1789             if (NULL == (p = (*csp->content_filter) (csp)))
1790             {
1791                csp->content_length = csp->iob->eod - csp->iob->cur;
1792             }
1793
1794             hdr = sed (server_patterns, add_server_headers, csp);
1795             if (hdr == NULL)
1796             {
1797                /* FIXME Should handle error properly */
1798                log_error (LOG_LEVEL_FATAL,
1799                   "Out of memory parsing server header");
1800
1801             }
1802
1803             if (write_socket (csp->cfd, hdr, strlen (hdr))
1804                || write_socket (csp->cfd, p != NULL ? p : csp->iob->cur,
1805                           csp->content_length))
1806             {
1807                log_error (LOG_LEVEL_ERROR,
1808                   "write modified content to client failed: %E");
1809                return JB_ERR_GENERIC;
1810             }
1811
1812             freez (hdr);
1813             if (NULL != p)
1814             {
1815                freez (p);
1816             }
1817          }
1818          log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %d",
1819             csp->ip_addr_str, csp->http->ocmd, byte_count);
1820          return JB_ERR_GENERIC;
1821       }
1822
1823       /*
1824        * This is NOT the body, so
1825        * Let's pretend the server just sent us a blank line.
1826        */
1827       len = sprintf (buf, "\r\n");
1828
1829       /*
1830        * Now, let the normal header parsing algorithm below do its
1831        * job.  If it fails, we'll exit instead of continuing.
1832        */
1833
1834       ms_iis5_hack = 1;
1835    }
1836
1837    /*
1838     * If this is an SSL connection or we're in the body
1839     * of the server document, just write it to the client,
1840     * unless we need to buffer the body for later content-filtering
1841     */
1842
1843    if (csp->all_headers_read || csp->http->ssl)
1844    {
1845       if (csp->content_filter)
1846       {
1847          add_to_iob (csp, buf, len);
1848
1849          /*
1850           * If the buffer limit will be reached on the next read,
1851           * switch to non-filtering mode, i.e. make & write the
1852           * header, flush the socket and get out of the way.
1853           */
1854          if (((size_t) (csp->iob->eod - csp->iob->buf)) +
1855               (size_t) BUFFER_SIZE > csp->config->buffer_limit)
1856          {
1857             size_t hdrlen;
1858
1859             log_error (LOG_LEVEL_ERROR,
1860                         "Buffer size limit reached! Flushing and stepping back.");
1861
1862             hdr = sed (server_patterns, add_server_headers, csp);
1863             if (hdr == NULL)
1864             {
1865                /* FIXME Should handle error properly */
1866                log_error (LOG_LEVEL_FATAL,
1867                   "Out of memory parsing server header");
1868             }
1869
1870             hdrlen = strlen (hdr);
1871             byte_count += hdrlen;
1872
1873             if (write_socket (csp->cfd, hdr, hdrlen)
1874                || ((len = flush_socket (csp->cfd, csp)) < 0))
1875             {
1876                log_error (LOG_LEVEL_CONNECT,
1877                   "write header to client failed: %E");
1878
1879                freez (hdr);
1880                return JB_ERR_GENERIC;
1881             }
1882
1883             freez (hdr);
1884             byte_count += len;
1885
1886             csp->content_filter = NULL;
1887             csp->all_headers_read = 1;
1888
1889          }
1890       }
1891       else
1892       {
1893          if (write_socket (csp->cfd, buf, (size_t) len))
1894          {
1895             log_error (LOG_LEVEL_ERROR, "write to client failed: %E");
1896             return JB_ERR_GENERIC;
1897          }
1898       }
1899       byte_count += len;
1900       return JB_ERR_OK ;
1901    }
1902    else
1903    {
1904       /*
1905        * we're still looking for the end of the
1906        * server's header ... (does that make header
1907        * parsing an "out of body experience" ?
1908        */
1909
1910       /* buffer up the data we just read */
1911       add_to_iob (csp, buf, len);
1912
1913       /* get header lines from the iob */
1914
1915       while ((p = get_header (csp)) != NULL)
1916       {
1917          if (*p == '\0')
1918          {
1919             /* see following note */
1920             log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %d",
1921                csp->ip_addr_str, csp->http->ocmd, byte_count);
1922             return JB_ERR_GENERIC;
1923          }
1924          enlist (csp->headers, p);
1925          freez (p);
1926       }
1927
1928       /* NOTE: there are no "empty" headers so
1929        * if the pointer `p' is not NULL we must
1930        * assume that we reached the end of the
1931        * buffer before we hit the end of the header.
1932        */
1933
1934       if (p)
1935       {
1936          if (ms_iis5_hack)
1937          {
1938             /* Well, we tried our MS IIS/5
1939              * hack and it didn't work.
1940              * The header is incomplete
1941              * and there isn't anything
1942              * we can do about it.
1943              */
1944             log_error(LOG_LEVEL_CLF, "Incomplete Server Header: %s - - [%T] \"%s\" 200 %d",
1945                 csp->ip_addr_str, csp->http->ocmd, byte_count);
1946             return JB_ERR_GENERIC;
1947          }
1948          else
1949          {
1950             /* Since we have to wait for
1951              * more from the server before
1952              * we can parse the headers
1953              * we just continue here.
1954              */
1955             return JB_ERR_OK;
1956          }
1957       }      
1958       
1959       /* we have now received the entire header.
1960        * filter it and send the result to the client
1961        */
1962
1963       hdr = sed (server_patterns, add_server_headers, csp);
1964       if (hdr == NULL)
1965       {
1966          /* FIXME Should handle error properly */
1967          log_error (LOG_LEVEL_FATAL, "Out of memory parsing server header");
1968       }
1969
1970   
1971
1972 #ifdef FEATURE_KILL_POPUPS
1973       /* Start blocking popups if appropriate. */
1974
1975       if ((csp->content_type & CT_TEXT) &&   /* It's a text / * MIME-Type */
1976           !csp->http->ssl &&                 /* We talk plaintext */
1977           block_popups)                      /* Policy allows */
1978       {
1979          block_popups_now = 1;
1980          /*
1981           * Filter the part of the body that came in the same read
1982           * as the last headers:
1983           */
1984          filter_popups (csp->iob->cur, csp);
1985       }
1986
1987 #endif /* def FEATURE_KILL_POPUPS */
1988
1989         /* Buffer and pcrs filter this if appropriate. */
1990
1991       if ((csp->content_type & CT_TEXT) &&       /* It's a text / * MIME-Type */
1992           !csp->http->ssl &&                     /* We talk plaintext */
1993           pcrs_filter)                           /* Policy allows */
1994       {
1995          csp->content_filter = pcrs_filter_response;
1996       }
1997
1998       /* Buffer and gif_deanimate this if appropriate. */
1999
2000       if ((csp->content_type & CT_GIF) &&        /* It's a image/gif MIME-Type */
2001           !csp->http->ssl &&                     /* We talk plaintext */
2002           gif_deanimate)                         /* Policy allows */
2003       {
2004          csp->content_filter = gif_deanimate_response;
2005       }
2006       /*
2007        * Only write if we're not buffering for content modification
2008        */
2009       if (!csp->content_filter)
2010       {
2011          /* write the server's (modified) header to
2012           * the client (along with anything else that
2013           * may be in the buffer)
2014           */
2015          if (write_socket (csp->cfd, hdr, strlen (hdr))
2016              || ((len = flush_socket (csp->cfd, csp)) < 0))
2017          {
2018             log_error (LOG_LEVEL_CONNECT,
2019                "write header to client failed: %E");
2020
2021             /* the write failed, so don't bother
2022              * mentioning it to the client...
2023              * it probably can't hear us anyway.
2024              */
2025             freez (hdr);
2026             return JB_ERR_GENERIC;
2027          }
2028
2029          byte_count += len;
2030       }
2031
2032       /* we're finished with the server's header */
2033
2034       freez (hdr);
2035       csp->all_headers_read = 1;
2036
2037       /* If this was a MS IIS/5 hack then it means
2038        * the server has already closed the
2039        * connection.  Nothing more to read.  Time
2040        * to bail.
2041        */
2042       if (ms_iis5_hack)
2043       {
2044          return JB_ERR_GENERIC ;
2045       }
2046    }
2047    return JB_ERR_OK ;
2048 } /* END relay_server_traffic() */
2049
2050
2051 /*********************************************************************
2052  *
2053  * Function    :  read_client_headers
2054  *
2055  * Description :  read all the client headers, and fill in the
2056  *                http* structure
2057  *
2058  * Parameters  :
2059  *          1  :  client_state structure
2060  *          2  :  http_request structure
2061  *                         
2062  *
2063  * Returns     :  JB_ERR_OK  - headers read and parsed ok
2064  *             :  other values - an error occurred.
2065  *********************************************************************/
2066
2067 static jb_err read_client_headers( struct client_state *csp, struct http_request *http )
2068 {
2069
2070    char *p;
2071    char *req;
2072    char buf[BUFFER_SIZE];
2073    int len; /* for buffer sizes */
2074
2075    /*
2076     * Read the client's request.  Note that since we're not using select() we
2077     * could get blocked here if a client connected, then didn't say anything!
2078     *
2079     * This will read all the client headers.
2080     */
2081
2082    req = NULL ;
2083    for (;;)
2084    {
2085       len = read_socket(csp->cfd, buf, sizeof(buf));
2086
2087       if (len <= 0) break;      /* error! */
2088
2089       add_to_iob(csp, buf, len);
2090
2091       req = get_header(csp);
2092
2093       if (req == NULL)
2094       {
2095          break;    /* no HTTP request! */
2096       }
2097
2098       if (*req == '\0')
2099       {
2100          continue;   /* more to come! */
2101       }
2102
2103       /* When we get here we have read one header which is enough */
2104       /* to check whether the connection is allowed */
2105       break; 
2106    }
2107
2108
2109    for(;;) 
2110    {
2111
2112      if ( ( ( p = get_header(csp) ) != NULL) && ( *p == '\0' ) )
2113       {
2114          len = read_socket(csp->cfd, buf, sizeof(buf));
2115          if (len <= 0)
2116          {
2117             log_error(LOG_LEVEL_ERROR, "read from client failed: %E");
2118             return JB_ERR_GENERIC;
2119          }
2120          add_to_iob(csp, buf, len);
2121          continue;
2122       }
2123
2124       if (p == NULL) break;
2125
2126       enlist(csp->headers, p);
2127       freez(p);
2128
2129    }
2130
2131    parse_http_request(req, http, csp);
2132    freez(req);
2133
2134    if (http->cmd == NULL)
2135    {
2136       strcpy(buf, CHEADER);
2137       write_socket(csp->cfd, buf, strlen(buf));
2138
2139       log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 400 0", csp->ip_addr_str);
2140
2141       return JB_ERR_GENERIC;
2142    }
2143
2144    return JB_ERR_OK ;
2145
2146
2147 } /* END read_client_headers */
2148
2149
2150 /*********************************************************************
2151  *
2152  * Function    :  process_client_headers
2153  *
2154  * Description :  Process client headers
2155  * FIXME: Add description of what we do here!
2156  *
2157  * Parameters  :
2158  *          1  :  client_state structure
2159  *          2  :  http_request structure
2160  *                         
2161  *
2162  * Returns     :  JB_ERR_OK  - headers processed ok
2163  *             :  other values - an error occurred.
2164  *********************************************************************/
2165
2166 static jb_err process_client_headers( struct client_state *csp, struct http_request *http )
2167 {
2168
2169
2170 #ifdef FEATURE_FORCE_LOAD
2171       /* If this request contains the FORCE_PREFIX,
2172        * better get rid of it now and set the force flag --oes
2173        * Changed to use the http structure rather than the req field --jaa
2174        */
2175
2176       if (strstr(http->url, FORCE_PREFIX))
2177       {
2178          strclean(http->url, FORCE_PREFIX);
2179          log_error(LOG_LEVEL_FORCE, "Enforcing request \"%s\".\n", http->url);
2180          csp->flags |= CSP_FLAG_FORCED;
2181       }
2182
2183 #endif /* def FEATURE_FORCE_LOAD */
2184
2185
2186    /* decide how to route the HTTP request */
2187
2188    if ((http->fwd = forward_url(http, csp)) == NULL)
2189    {
2190       log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!?  This can't happen!");
2191       /* Never get here - LOG_LEVEL_FATAL causes program exit */
2192    }
2193
2194    /* build the http request to send to the server
2195     * we have to do one of the following:
2196     *
2197     * create = use the original HTTP request to create a new
2198     *          HTTP request that has either the path component
2199     *          without the http://domainspec (w/path) or the
2200     *          full orininal URL (w/url)
2201     *          Note that the path and/or the HTTP version may
2202     *          have been altered by now.
2203     *
2204     * connect = Open a socket to the host:port of the server
2205     *           and short-circuit server and client socket.
2206     *
2207     * pass =  Pass the request unchanged if forwarding a CONNECT
2208     *         request to a parent proxy. Note that we'll be sending
2209     *         the CFAIL message ourselves if connecting to the parent
2210     *         fails, but we won't send a CSUCCEED message if it works,
2211     *         since that would result in a double message (ours and the
2212     *         parent's). After sending the request to the parent, we simply
2213     *         tunnel.
2214     *
2215     * here's the matrix:
2216     *                        SSL
2217     *                    0        1
2218     *                +--------+--------+
2219     *                |        |        |
2220     *             0  | create | connect|
2221     *                | w/path |        |
2222     *  Forwarding    +--------+--------+
2223     *                |        |        |
2224     *             1  | create | pass   |
2225     *                | w/url  |        |
2226     *                +--------+--------+
2227     *
2228     */
2229
2230    /*
2231     * Determine the actions for this URL
2232     */
2233 #ifdef FEATURE_TOGGLE
2234    if (!(csp->flags & CSP_FLAG_TOGGLED_ON))
2235    {
2236       /* Most compatible set of actions (i.e. none) */
2237       init_current_action(csp->action);
2238    }
2239    else
2240 #endif /* ndef FEATURE_TOGGLE */
2241    {
2242       url_actions(http, csp);
2243    }
2244
2245
2246
2247
2248
2249    /*
2250     * Downgrade http version from 1.1 to 1.0 if +downgrade
2251     * action applies
2252     */
2253    if ( (http->ssl == 0)
2254      && (!strcmpic(http->ver, "HTTP/1.1"))
2255      && (csp->action->flags & ACTION_DOWNGRADE))
2256    {
2257       freez(http->ver);
2258       http->ver = strdup("HTTP/1.0");
2259
2260       if (http->ver == NULL)
2261       {
2262          log_error(LOG_LEVEL_FATAL, "Out of memory downgrading HTTP version");
2263       }
2264    }
2265
2266    /* 
2267     * Save a copy of the original request for logging
2268     */
2269    http->ocmd = strdup(http->cmd);
2270
2271    if (http->ocmd == NULL)
2272    {
2273       log_error(LOG_LEVEL_FATAL, "Out of memory copying HTTP request line");
2274    }
2275
2276    /*
2277     * (Re)build the HTTP request for non-SSL requests.
2278     * If forwarding, use the whole URL, else, use only the path.
2279     */
2280    if (http->ssl == 0)
2281    {
2282       freez(http->cmd);
2283
2284       http->cmd = strdup(http->gpc);
2285       string_append(&http->cmd, " ");
2286
2287       if (http->fwd->forward_host)
2288       {
2289          string_append(&http->cmd, http->url);
2290       }
2291       else
2292       {
2293          string_append(&http->cmd, http->path);
2294       }
2295
2296       string_append(&http->cmd, " ");
2297       string_append(&http->cmd, http->ver);
2298
2299       if (http->cmd == NULL)
2300       {
2301          log_error(LOG_LEVEL_FATAL, "Out of memory rewiting SSL command");
2302       }
2303    }
2304    enlist_first(csp->headers, http->cmd);
2305
2306
2307    /*
2308     * If the user has not supplied any wafers, and the user has not
2309     * told us to suppress the vanilla wafer, then send the vanilla wafer.
2310     */
2311    if (list_is_empty(csp->action->multi[ACTION_MULTI_WAFER])
2312        && ((csp->action->flags & ACTION_VANILLA_WAFER) != 0))
2313    {
2314       enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER);
2315    }
2316
2317    return JB_ERR_OK ;
2318 } /* process_client_headers */
2319
2320 /*********************************************************************
2321  *
2322  * Function    :  intercept_page
2323  *
2324  * Description :  Check whether to intercept page
2325  *
2326  * Parameters  :
2327  *          1  :  client_state structure
2328  *          2  :  http_request structure
2329  *                         
2330  *
2331  * Returns     :  JB_ERR_OK  - Do NOT intercept this page
2332  *             :  JB_ERR_INTERCEPT - intercept this page
2333  *             :  all other values - an error occurred.  
2334  *********************************************************************/
2335 static jb_err intercept_page( struct client_state *csp, struct http_request *http )
2336 {
2337
2338    /* Skeleton for HTTP response, if we should intercept the request */
2339    struct http_response *rsp;
2340
2341
2342 /*
2343  * These next lines are a little ugly, but they simplifies the if statements
2344  * below.  Basically if TOGGLE, then we want the if to test if the
2345  * CSP_FLAG_TOGGLED_ON flag ist set, else we don't.  And if FEATURE_FORCE_LOAD,
2346  * then we want the if to test for CSP_FLAG_FORCED , else we don't
2347  */
2348 #ifdef FEATURE_TOGGLE
2349 #   define IS_TOGGLED_ON_AND (csp->flags & CSP_FLAG_TOGGLED_ON) &&
2350 #else /* ifndef FEATURE_TOGGLE */
2351 #   define IS_TOGGLED_ON_AND
2352 #endif /* ndef FEATURE_TOGGLE */
2353 #ifdef FEATURE_FORCE_LOAD
2354 #   define IS_NOT_FORCED_AND !(csp->flags & CSP_FLAG_FORCED) &&
2355 #else /* ifndef FEATURE_FORCE_LOAD */
2356 #   define IS_NOT_FORCED_AND
2357 #endif /* def FEATURE_FORCE_LOAD */
2358
2359 #define IS_ENABLED_AND   IS_TOGGLED_ON_AND IS_NOT_FORCED_AND
2360
2361    if (
2362        /* a CGI call was detected and answered */
2363        (NULL != (rsp = dispatch_cgi(csp)))
2364
2365        /* or we are enabled and... */
2366        || (IS_ENABLED_AND (
2367
2368             /* ..the request was blocked */
2369           ( NULL != (rsp = block_url(csp)))
2370
2371           /* ..or untrusted */
2372 #ifdef FEATURE_TRUST
2373           || ( NULL != (rsp = trust_url(csp)))
2374 #endif /* def FEATURE_TRUST */
2375
2376           /* ..or a fast redirect kicked in */
2377 #ifdef FEATURE_FAST_REDIRECTS
2378           || (((csp->action->flags & ACTION_FAST_REDIRECTS) != 0) &&
2379                 (NULL != (rsp = redirect_url(csp))))
2380 #endif /* def FEATURE_FAST_REDIRECTS */
2381           ))
2382       )
2383    {
2384       /* Write the answer to the client */
2385       if (write_socket(csp->cfd, rsp->head, rsp->head_length)
2386        || write_socket(csp->cfd, rsp->body, rsp->content_length))
2387       {
2388          log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
2389       }
2390
2391 #ifdef FEATURE_STATISTICS
2392       /* Count as a rejected request */
2393       csp->flags |= CSP_FLAG_REJECTED;
2394 #endif /* def FEATURE_STATISTICS */
2395
2396       /* Log (FIXME: All intercept reasons apprear as "crunch" with Status 200) */
2397       log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path);
2398       log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", csp->ip_addr_str, http->ocmd);
2399
2400       /* Clean up and return */
2401       free_http_response(rsp);
2402       return JB_ERR_INTERCEPT;
2403    }
2404
2405    /* When we get here the request doesn't need to be intercepted */
2406    return JB_ERR_OK ;
2407 }
2408
2409 /*********************************************************************
2410  *
2411  * Function    :  open_forwarding_connection
2412  *
2413  * Description :  Check whether to intercept page
2414  *
2415  * Parameters  :
2416  *          1  :  client_state structure
2417  *          2  :  http_request structure
2418  *                         
2419  * Returns     :  JB_ERR_OK  - Connection opened ok
2420  *             :  all other values - an error occurred.  
2421  *********************************************************************/
2422 static jb_err open_forwarding_connection(struct client_state *csp )
2423 {
2424    struct http_response *rsp;
2425    
2426 #ifdef FEATURE_ACTIVITY_CONSOLE
2427    accumulate_stats(STATS_REQUEST, 1);
2428 #endif /* def FEATURE_ACTIVITY_CONSOLE */
2429    log_error(LOG_LEVEL_GPC, "%s%s", csp->http->hostport, csp->http->path);
2430
2431    if (csp->http->fwd->forward_host)
2432    {
2433       log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s",
2434                csp->http->fwd->forward_host, csp->http->fwd->forward_port, 
2435                csp->http->hostport);
2436    }
2437    else
2438    {
2439       log_error(LOG_LEVEL_CONNECT, "to %s", csp->http->hostport);
2440    }
2441
2442    /* here we connect to the server, gateway, or the forwarder */
2443
2444    csp->sfd = forwarded_connect(csp->http->fwd, csp->http, csp);
2445
2446    if (csp->sfd == JB_INVALID_SOCKET)
2447    {
2448       log_error(LOG_LEVEL_CONNECT, "connect to: %s failed: %E",
2449                 csp->http->hostport);
2450
2451       if (errno == EINVAL)
2452       {
2453          rsp = error_response(csp, "no-such-domain", errno);
2454
2455          log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 404 0",
2456                    csp->ip_addr_str, csp->http->ocmd);
2457       }
2458       else
2459       {
2460          rsp = error_response(csp, "connect-failed", errno);
2461
2462          log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
2463                    csp->ip_addr_str, csp->http->ocmd);
2464       }
2465
2466
2467       /* Write the answer to the client */
2468       if(rsp)
2469       {
2470          if (write_socket(csp->cfd, rsp->head, rsp->head_length)
2471           || write_socket(csp->cfd, rsp->body, rsp->content_length))
2472          {
2473             log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", csp->http->host);
2474          }
2475       }
2476
2477       free_http_response(rsp);
2478       return JB_ERR_GENERIC;
2479    }
2480
2481    log_error(LOG_LEVEL_CONNECT, "OK");
2482    return JB_ERR_OK ;
2483
2484 } /* END open_forwarding_connection() */
2485
2486
2487 /*********************************************************************
2488  *
2489  * Function    :  send_client_headers_to_server
2490  *
2491  * Description :  send the client headers (possibly modified) to the server
2492  *
2493  * Parameters  :
2494  *          1  :  client_state structure
2495  *          2  :  http_request structure
2496  *                         
2497  *
2498  * Returns     :  JB_ERR_OK  - headers sent ok
2499  *             :  other values - an error occurred.
2500  *********************************************************************/
2501
2502 static jb_err send_client_headers_to_server( struct client_state *csp, struct http_request *http, char *hdr )
2503 {
2504
2505    struct http_response *rsp;
2506
2507    if (http->fwd->forward_host || (http->ssl == 0))
2508    {
2509       /* write the client's (modified) header to the server
2510        * (along with anything else that may be in the buffer)
2511        */
2512
2513       if (write_socket(csp->sfd, hdr, strlen(hdr))
2514        || (flush_socket(csp->sfd, csp) <  0))
2515       {
2516          log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E",
2517                     http->hostport);
2518
2519          log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
2520                    csp->ip_addr_str, http->ocmd);
2521
2522          rsp = error_response(csp, "connect-failed", errno);
2523
2524          if(rsp)
2525          {
2526             if (write_socket(csp->cfd, rsp->head, rsp->head_length)
2527              || write_socket(csp->cfd, rsp->body, rsp->content_length))
2528             {
2529                log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
2530             }
2531          }
2532
2533          free_http_response(rsp);
2534          return JB_ERR_GENERIC;
2535       }
2536    }
2537    else
2538    {
2539       /*
2540        * We're running an SSL tunnel and we're not forwarding,
2541        * so just send the "connect succeeded" message to the
2542        * client, flush the rest, and get out of the way.
2543        */
2544       log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 2\n",
2545                 csp->ip_addr_str, http->ocmd);
2546
2547       if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1))
2548       {
2549          return JB_ERR_OK;
2550       }
2551       IOB_RESET(csp);
2552    }
2553
2554    return JB_ERR_OK ;
2555 } /* END send_client_headers_to_server */
2556
2557
2558 /*********************************************************************
2559  *
2560  * Function    :  is_connect_request_allowed
2561  *
2562  * Description :  send the client headers (possibly modified) to the server
2563  *
2564  * Parameters  :
2565  *          1  :  client_state structure
2566  *
2567  *                         
2568  *
2569  * Returns     :  JB_ERR_OK  - connect request allowed
2570  *             :  other values - connect request not allowed
2571  *********************************************************************/
2572 static jb_err is_connect_request_allowed( struct client_state *csp )
2573 {
2574    /*
2575     * Check if a CONNECT request is allowable:
2576     * In the absence of a +limit-connect action, allow only port 443.
2577     * If there is an action, allow whatever matches the specificaton.
2578     */
2579
2580    if(csp->http->ssl)
2581    {
2582       if(  ( !(csp->action->flags & ACTION_LIMIT_CONNECT) && csp->http->port != 443)
2583            || (csp->action->flags & ACTION_LIMIT_CONNECT
2584               && !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT], csp->http->port)) )
2585       {
2586          char buf[BUFFER_SIZE];
2587          strcpy(buf, CFORBIDDEN);
2588          write_socket(csp->cfd, buf, strlen(buf));
2589
2590          log_error(LOG_LEVEL_CONNECT, "Denying suspicious CONNECT request from %s", csp->ip_addr_str);
2591          log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 403 0", csp->ip_addr_str);
2592
2593          return JB_ERR_GENERIC;
2594       }
2595    }
2596
2597    return JB_ERR_OK ;
2598 } /* END is_connect_request_allowed */
2599
2600 /*
2601   Local Variables:
2602   tab-width: 3
2603   end:
2604 */