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