Adding myself to the contributors list :-)
[privoxy.git] / jcc.c
1 const char jcc_rcs[] = "$Id: jcc.c,v 1.65 2002/03/03 14:49:11 oes 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  *                IJBSWA team.  http://ijbswa.sourceforge.net
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.65  2002/03/03 14:49:11  oes
37  *    Fixed CLF logging: Now uses client's original HTTP request
38  *
39  *    Revision 1.64  2002/03/03 09:18:03  joergs
40  *    Made jumbjuster work on AmigaOS again.
41  *
42  *    Revision 1.63  2002/03/02 04:14:50  david__schmidt
43  *    Clean up a little CRLF unpleasantness that suddenly appeared
44  *
45  *    Revision 1.62  2002/02/20 23:17:23  jongfoster
46  *    Detecting some out-of memory conditions and exiting with a log message.
47  *
48  *    Revision 1.61  2002/01/17 21:01:52  jongfoster
49  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
50  *
51  *    Revision 1.60  2001/12/30 14:07:32  steudten
52  *    - Add signal handling (unix)
53  *    - Add SIGHUP handler (unix)
54  *    - Add creation of pidfile (unix)
55  *    - Add action 'top' in rc file (RH)
56  *    - Add entry 'SIGNALS' to manpage
57  *    - Add exit message to logfile (unix)
58  *
59  *    Revision 1.59  2001/12/13 14:07:18  oes
60  *    Fixed Bug: 503 error page now sent OK
61  *
62  *    Revision 1.58  2001/11/30 23:37:24  jongfoster
63  *    Renaming the Win32 config file to config.txt - this is almost the
64  *    same as the corresponding UNIX name "config"
65  *
66  *    Revision 1.57  2001/11/16 00:47:43  jongfoster
67  *    Changing the tty-disconnection code to use setsid().
68  *
69  *    Revision 1.56  2001/11/13 20:20:54  jongfoster
70  *    Tabs->spaces, fixing a bug with missing {} around an if()
71  *
72  *    Revision 1.55  2001/11/13 20:14:53  jongfoster
73  *    Patch for FreeBSD setpgrp() as suggested by Alexander Lazic
74  *
75  *    Revision 1.54  2001/11/07 00:03:14  steudten
76  *    Give reliable return value if an error
77  *    occurs not just 0 with new daemon mode.
78  *
79  *    Revision 1.53  2001/11/05 21:41:43  steudten
80  *    Add changes to be a real daemon just for unix os.
81  *    (change cwd to /, detach from controlling tty, set
82  *    process group and session leader to the own process.
83  *    Add DBG() Macro.
84  *    Add some fatal-error log message for failed malloc().
85  *    Add '-d' if compiled with 'configure --with-debug' to
86  *    enable debug output.
87  *
88  *    Revision 1.52  2001/10/26 20:11:20  jongfoster
89  *    Fixing type mismatch
90  *
91  *    Revision 1.51  2001/10/26 17:38:28  oes
92  *    Cosmetics
93  *
94  *    Revision 1.50  2001/10/25 03:40:48  david__schmidt
95  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
96  *    threads to call select() simultaneously.  So, it's time to do a real, live,
97  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
98  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
99  *
100  *    Revision 1.49  2001/10/23 21:41:35  jongfoster
101  *    Added call to initialize the (statically-allocated of course)
102  *    "out of memory" CGI response.
103  *
104  *    Revision 1.48  2001/10/10 19:56:46  jongfoster
105  *    Moving some code that wasn't cookie-related out of an #ifdef
106  *    FEATURE_COOKIE_JAR
107  *
108  *    Revision 1.47  2001/10/10 16:44:36  oes
109  *    Added CONNECT destination port limitation check
110  *
111  *    Revision 1.46  2001/10/08 15:17:41  oes
112  *    Re-enabled SSL forwarding
113  *
114  *    Revision 1.45  2001/10/07 15:42:11  oes
115  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
116  *
117  *    Moved downgrading of the HTTP version from parse_http_request to
118  *      chat(), since we can't decide if it is necessary before we have
119  *      determined the actions for the URL. The HTTP command is now
120  *      *always* re-built so the repairs need no longer be special-cased.
121  *
122  *    filter_popups now gets a csp pointer so it can raise the new
123  *      CSP_FLAG_MODIFIED flag.
124  *
125  *    Bugfix
126  *
127  *    Added configurable size limit for the IOB. If the IOB grows so
128  *      large that the next read would exceed the limit, the header
129  *      is generated, and the header & unfiltered buffer are flushed
130  *      to the client. Chat then continues in non-buffering,
131  *      non-filtering body mode.
132  *
133  *    Revision 1.44  2001/10/02 18:13:57  oes
134  *    Ooops
135  *
136  *    Revision 1.43  2001/10/02 15:32:13  oes
137  *    Moved generation of hdr
138  *
139  *    Revision 1.42  2001/09/21 23:02:02  david__schmidt
140  *    Cleaning up 2 compiler warnings on OS/2.
141  *
142  *    Revision 1.41  2001/09/16 17:05:14  jongfoster
143  *    Removing unused #include showarg.h
144  *
145  *    Revision 1.40  2001/09/16 15:41:45  jongfoster
146  *    Fixing signed/unsigned comparison warning.
147  *
148  *    Revision 1.39  2001/09/16 13:21:27  jongfoster
149  *    Changes to use new list functions.
150  *
151  *    Revision 1.38  2001/09/16 13:01:46  jongfoster
152  *    Removing redundant function call that zeroed zalloc()'d memory.
153  *
154  *    Revision 1.37  2001/09/10 11:12:24  oes
155  *    Deleted unused variable
156  *
157  *    Revision 1.36  2001/09/10 10:56:15  oes
158  *    Silenced compiler warnings
159  *
160  *    Revision 1.35  2001/07/31 14:44:22  oes
161  *    Deleted unused size parameter from filter_popups()
162  *
163  *    Revision 1.34  2001/07/30 22:08:36  jongfoster
164  *    Tidying up #defines:
165  *    - All feature #defines are now of the form FEATURE_xxx
166  *    - Permanently turned off WIN_GUI_EDIT
167  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
168  *
169  *    Revision 1.33  2001/07/29 19:32:00  jongfoster
170  *    Renaming _main() [mingw32 only] to real_main(), for ANSI compliance.
171  *
172  *    Revision 1.32  2001/07/29 18:47:05  jongfoster
173  *    Adding missing #include "loadcfg.h"
174  *
175  *    Revision 1.31  2001/07/29 12:17:48  oes
176  *    Applied pthread fix by Paul Lieverse
177  *
178  *    Revision 1.30  2001/07/25 22:57:13  jongfoster
179  *    __BEOS__ no longer overrides FEATURE_PTHREAD.
180  *    This is because FEATURE_PTHREAD will soon be widely used, so I
181  *    want to keep it simple.
182  *
183  *    Revision 1.29  2001/07/24 12:47:06  oes
184  *    Applied BeOS support update by Eugenia
185  *
186  *    Revision 1.28  2001/07/23 13:26:12  oes
187  *    Fixed bug in popup-killing for the first read that caused binary garbage to be sent between headers and body
188  *
189  *    Revision 1.27  2001/07/19 19:09:47  haroon
190  *    - Added code to take care of the situation where while processing the first
191  *      server response (which includes the server header), after finding the end
192  *      of the headers we were not looking past the end of the headers for
193  *      content modification. I enabled it for filter_popups.
194  *      Someone else should look to see if other similar operations should be
195  *      done to the discarded portion of the buffer.
196  *
197  *      Note 2001/07/20: No, the other content modification mechanisms will process
198  *                       the whole iob later anyway. --oes
199  *
200  *    Revision 1.26  2001/07/18 12:31:36  oes
201  *    cosmetics
202  *
203  *    Revision 1.25  2001/07/15 19:43:49  jongfoster
204  *    Supports POSIX threads.
205  *    Also removed some unused #includes.
206  *
207  *    Revision 1.24  2001/07/13 14:00:40  oes
208  *     - Generic content modification scheme:
209  *       Each feature has its own applicability flag that is set
210  *       from csp->action->flags.
211  *       Replaced the "filtering" int flag , by a function pointer
212  *       "content_filter" to the function that will do the content
213  *       modification. If it is != NULL, the document will be buffered
214  *       and processed through *content_filter, which must set
215  *       csp->content_length and return a modified copy of the body
216  *       or return NULL (on failiure).
217  *     - Changed csp->is_text to the more generic bitmap csp->content_type
218  *       which can currently take the valued CT_TEXT or CT_GIF
219  *     - Reformatting etc
220  *     - Removed all #ifdef PCRS
221  *
222  *    Revision 1.23  2001/07/02 02:28:25  iwanttokeepanon
223  *    Added "#ifdef ACL_FILES" conditional compilation to line 1291 to exclude
224  *    the `block_acl' call.  This prevents a compilation error when the user
225  *    does not wish to use the "ACL" feature.
226  *
227  *    Revision 1.22  2001/06/29 21:45:41  oes
228  *    Indentation, CRLF->LF, Tab-> Space
229  *
230  *    Revision 1.21  2001/06/29 13:29:36  oes
231  *    - Cleaned up, improved comments
232  *    - Unified all possible interceptors (CGI,
233  *      block, trust, fast_redirect) in one
234  *      place, with one (CGI) answer generation
235  *      mechansim. Much clearer now.
236  *    - Removed the GIF image generation, which
237  *      is now done in filters.c:block_url()
238  *    - Made error conditions like domain lookup
239  *      failiure or (various) problems while talking
240  *      to the server use cgi.c:error_response()
241  *      instead of generating HTML/HTTP in chat() (yuck!)
242  *    - Removed logentry from cancelled commit
243  *
244  *    Revision 1.20  2001/06/09 10:55:28  jongfoster
245  *    Changing BUFSIZ ==> BUFFER_SIZE
246  *
247  *    Revision 1.19  2001/06/07 23:12:52  jongfoster
248  *    Replacing function pointer in struct gateway with a directly
249  *    called function forwarded_connect().
250  *    Replacing struct gateway with struct forward_spec
251  *
252  *    Revision 1.18  2001/06/03 19:12:16  oes
253  *    introduced new cgi handling
254  *
255  *    Revision 1.17  2001/06/01 20:07:23  jongfoster
256  *    Now uses action +image-blocker{} rather than config->tinygif
257  *
258  *    Revision 1.16  2001/06/01 18:49:17  jongfoster
259  *    Replaced "list_share" with "list" - the tiny memory gain was not
260  *    worth the extra complexity.
261  *
262  *    Revision 1.15  2001/05/31 21:24:47  jongfoster
263  *    Changed "permission" to "action" throughout.
264  *    Removed DEFAULT_USER_AGENT - it must now be specified manually.
265  *    Moved vanilla wafer check into chat(), since we must now
266  *    decide whether or not to add it based on the URL.
267  *
268  *    Revision 1.14  2001/05/29 20:14:01  joergs
269  *    AmigaOS bugfix: PCRS needs a lot of stack, stacksize for child threads
270  *    increased.
271  *
272  *    Revision 1.13  2001/05/29 09:50:24  jongfoster
273  *    Unified blocklist/imagelist/permissionslist.
274  *    File format is still under discussion, but the internal changes
275  *    are (mostly) done.
276  *
277  *    Also modified interceptor behaviour:
278  *    - We now intercept all URLs beginning with one of the following
279  *      prefixes (and *only* these prefixes):
280  *        * http://i.j.b/
281  *        * http://ijbswa.sf.net/config/
282  *        * http://ijbswa.sourceforge.net/config/
283  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
284  *    - Internal changes so that intercepted and fast redirect pages
285  *      are not replaced with an image.
286  *    - Interceptors now have the option to send a binary page direct
287  *      to the client. (i.e. ijb-send-banner uses this)
288  *    - Implemented show-url-info interceptor.  (Which is why I needed
289  *      the above interceptors changes - a typical URL is
290  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
291  *      The previous mechanism would not have intercepted that, and
292  *      if it had been intercepted then it then it would have replaced
293  *      it with an image.)
294  *
295  *    Revision 1.12  2001/05/27 22:17:04  oes
296  *
297  *    - re_process_buffer no longer writes the modified buffer
298  *      to the client, which was very ugly. It now returns the
299  *      buffer, which it is then written by chat.
300  *
301  *    - content_length now adjusts the Content-Length: header
302  *      for modified documents rather than crunch()ing it.
303  *      (Length info in csp->content_length, which is 0 for
304  *      unmodified documents)
305  *
306  *    - For this to work, sed() is called twice when filtering.
307  *
308  *    Revision 1.11  2001/05/26 17:27:53  jongfoster
309  *    Added support for CLF and fixed LOG_LEVEL_LOG.
310  *    Also did CRLF->LF fix of my previous patch.
311  *
312  *    Revision 1.10  2001/05/26 15:26:15  jongfoster
313  *    ACL feature now provides more security by immediately dropping
314  *    connections from untrusted hosts.
315  *
316  *    Revision 1.9  2001/05/26 00:28:36  jongfoster
317  *    Automatic reloading of config file.
318  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
319  *    Most of the global variables have been moved to a new
320  *    struct configuration_spec, accessed through csp->config->globalname
321  *    Most of the globals remaining are used by the Win32 GUI.
322  *
323  *    Revision 1.8  2001/05/25 22:43:18  jongfoster
324  *    Fixing minor memory leak and buffer overflow.
325  *
326  *    Revision 1.7  2001/05/25 22:34:30  jongfoster
327  *    Hard tabs->Spaces
328  *
329  *    Revision 1.6  2001/05/23 00:13:58  joergs
330  *    AmigaOS support fixed.
331  *
332  *    Revision 1.5  2001/05/22 18:46:04  oes
333  *
334  *    - Enabled filtering banners by size rather than URL
335  *      by adding patterns that replace all standard banner
336  *      sizes with the "Junkbuster" gif to the re_filterfile
337  *
338  *    - Enabled filtering WebBugs by providing a pattern
339  *      which kills all 1x1 images
340  *
341  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
342  *      which is selected by the (nonstandard and therefore
343  *      capital) letter 'U' in the option string.
344  *      It causes the quantifiers to be ungreedy by default.
345  *      Appending a ? turns back to greedy (!).
346  *
347  *    - Added a new interceptor ijb-send-banner, which
348  *      sends back the "Junkbuster" gif. Without imagelist or
349  *      MSIE detection support, or if tinygif = 1, or the
350  *      URL isn't recognized as an imageurl, a lame HTML
351  *      explanation is sent instead.
352  *
353  *    - Added new feature, which permits blocking remote
354  *      script redirects and firing back a local redirect
355  *      to the browser.
356  *      The feature is conditionally compiled, i.e. it
357  *      can be disabled with --disable-fast-redirects,
358  *      plus it must be activated by a "fast-redirects"
359  *      line in the config file, has its own log level
360  *      and of course wants to be displayed by show-proxy-args
361  *      Note: Boy, all the #ifdefs in 1001 locations and
362  *      all the fumbling with configure.in and acconfig.h
363  *      were *way* more work than the feature itself :-(
364  *
365  *    - Because a generic redirect template was needed for
366  *      this, tinygif = 3 now uses the same.
367  *
368  *    - Moved GIFs, and other static HTTP response templates
369  *      to project.h
370  *
371  *    - Some minor fixes
372  *
373  *    - Removed some >400 CRs again (Jon, you really worked
374  *      a lot! ;-)
375  *
376  *    Revision 1.4  2001/05/21 19:34:01  jongfoster
377  *    Made failure to bind() a fatal error.
378  *
379  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
380  *    Version 2.9.4 checkin.
381  *    - Merged popupfile and cookiefile, and added control over PCRS
382  *      filtering, in new "permissionsfile".
383  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
384  *      file error you now get a message box (in the Win32 GUI) rather
385  *      than the program exiting with no explanation.
386  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
387  *      skipping.
388  *    - Removed tabs from "config"
389  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
390  *    - Bumped up version number.
391  *
392  *    Revision 1.2  2001/05/17 22:34:44  oes
393  *     - Added hint on GIF char array generation to jcc.c
394  *     - Cleaned CRLF's from the sources and related files
395  *     - Repaired logging for REF and FRC
396  *
397  *    Revision 1.1.1.1  2001/05/15 13:58:56  oes
398  *    Initial import of version 2.9.3 source tree
399  *
400  *
401  *********************************************************************/
402 \f
403
404 #include "config.h"
405
406 #include <stdio.h>
407 #include <sys/types.h>
408 #include <stdlib.h>
409 #include <string.h>
410 #include <signal.h>
411 #include <fcntl.h>
412 #include <errno.h>
413
414 #ifdef FEATURE_PTHREAD
415 #include <pthread.h>
416 #endif /* def FEATURE_PTHREAD */
417
418 #ifdef _WIN32
419 # ifndef FEATURE_PTHREAD
420 #  include <windows.h>
421 #  include <process.h>
422 # endif /* ndef FEATURE_PTHREAD */
423
424 # include "win32.h"
425 # ifndef _WIN_CONSOLE
426 #  include "w32log.h"
427 # endif /* ndef _WIN_CONSOLE */
428
429 #else /* ifndef _WIN32 */
430
431 # if !defined (__OS2__)
432 # include <unistd.h>
433 # include <sys/wait.h>
434 # endif /* ndef __OS2__ */
435 # include <sys/time.h>
436 # include <sys/stat.h>
437 # include <sys/ioctl.h>
438
439 #ifdef sun
440 #include <sys/termios.h>
441 #endif /* sun */
442
443 # include <signal.h>
444
445 # ifdef __BEOS__
446 #  include <socket.h>  /* BeOS has select() for sockets only. */
447 #  include <OS.h>      /* declarations for threads and stuff. */
448 # endif
449
450 # if defined(__EMX__) || defined(__OS2__)
451 #  include <sys/select.h>  /* OS/2/EMX needs a little help with select */
452 # endif
453 # ifdef __OS2__
454 #define INCL_DOS
455 # include <os2.h>
456 #define bzero(B,N) memset(B,0x00,n)
457 # endif
458
459 # ifndef FD_ZERO
460 #  include <select.h>
461 # endif
462
463 #endif
464
465 #ifdef _DEBUG
466 int ldebug = 0;
467 #endif
468
469 #include "project.h"
470 #include "list.h"
471 #include "jcc.h"
472 #include "filters.h"
473 #include "loaders.h"
474 #include "parsers.h"
475 #include "killpopup.h"
476 #include "miscutil.h"
477 #include "errlog.h"
478 #include "jbsockets.h"
479 #include "gateway.h"
480 #include "actions.h"
481 #include "cgi.h"
482 #include "loadcfg.h"
483 #include "urlmatch.h"
484
485 const char jcc_h_rcs[] = JCC_H_VERSION;
486 const char project_h_rcs[] = PROJECT_H_VERSION;
487
488 struct client_state  clients[1];
489 struct file_list     files[1];
490
491 #ifdef FEATURE_STATISTICS
492 int urls_read     = 0;     /* total nr of urls read inc rejected */
493 int urls_rejected = 0;     /* total nr of urls rejected */
494 #endif /* def FEATURE_STATISTICS */
495
496
497 static void listen_loop(void);
498 static void chat(struct client_state *csp);
499 #ifdef AMIGA
500 void serve(struct client_state *csp);
501 #else /* ifndef AMIGA */
502 static void serve(struct client_state *csp);
503 #endif /* def AMIGA */
504
505 #ifdef __BEOS__
506 static int32 server_thread(void *data);
507 #endif /* def __BEOS__ */
508
509 #ifdef _WIN32
510 #define sleep(N)  Sleep(((N) * 1000))
511 #endif
512
513 #ifdef __OS2__
514 #define sleep(N)  DosSleep(((N) * 100))
515 #endif
516
517 #if defined(unix)
518 const char *basedir;
519 #endif /* defined unix */
520
521 /* The vanilla wafer. */
522 static const char VANILLA_WAFER[] =
523    "NOTICE=TO_WHOM_IT_MAY_CONCERN_"
524    "Do_not_send_me_any_copyrighted_information_other_than_the_"
525    "document_that_I_am_requesting_or_any_of_its_necessary_components._"
526    "In_particular_do_not_send_me_any_cookies_that_"
527    "are_subject_to_a_claim_of_copyright_by_anybody._"
528    "Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_"
529    "(copyright_or_otherwise)_applying_to_any_cookie._";
530
531
532 #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA)
533 /*********************************************************************
534  *
535  * Function    :  SIG_handler 
536  *
537  * Description :  Signal handler for different signals.
538  *                see man kill, signal .. 
539  *
540  * Parameters  :
541  *          1  : signal - the signal cause this function to call 
542  *
543  * Returns     :  - 
544  *
545  *********************************************************************/
546 static void SIG_handler( int signal )
547 {
548    switch( signal )
549    {
550       case SIGHUP:
551          log_error(LOG_LEVEL_INFO, "ignoring HUP signal (%d)", signal);
552          break;
553       case SIGTERM:
554          log_error(LOG_LEVEL_INFO, "exiting by signal %d .. bye", signal);
555          
556 #if defined(unix)
557          deletePidFile();
558 #endif /* unix */
559
560          exit( signal );
561          break;
562
563       default:
564          /* want to exit jb so use FATAL */
565          log_error(LOG_LEVEL_FATAL, "SIG_handler: receive signal %d without handler.", signal);
566    }
567    return;
568 }
569 #endif
570 /*********************************************************************
571  *
572  * Function    :  chat
573  *
574  * Description :  Once a connection to the client has been accepted,
575  *                this function is called (via serve()) to handle the
576  *                main business of the communication.  When this
577  *                function returns, the caller must close the client
578  *                socket handle.
579  *
580  * Parameters  :
581  *          1  :  csp = Current client state (buffers, headers, etc...)
582  *
583  * Returns     :  On success, the number of bytes written are returned (zero
584  *                indicates nothing was written).  On error, -1 is returned,
585  *                and errno is set appropriately.  If count is zero and the
586  *                file descriptor refers to a regular file, 0 will be
587  *                returned without causing any other effect.  For a special
588  *                file, the results are not portable.
589  *
590  *********************************************************************/
591 static void chat(struct client_state *csp)
592 {
593 /*
594  * This next lines are a little ugly, but they simplifies the if statements
595  * below.  Basically if TOGGLE, then we want the if to test if the
596  * CSP_FLAG_TOGGLED_ON flag ist set, else we don't.  And if FEATURE_FORCE_LOAD,
597  * then we want the if to test for CSP_FLAG_FORCED , else we don't
598  */
599 #ifdef FEATURE_TOGGLE
600 #   define IS_TOGGLED_ON_AND (csp->flags & CSP_FLAG_TOGGLED_ON) &&
601 #else /* ifndef FEATURE_TOGGLE */
602 #   define IS_TOGGLED_ON_AND
603 #endif /* ndef FEATURE_TOGGLE */
604 #ifdef FEATURE_FORCE_LOAD
605 #   define IS_NOT_FORCED_AND !(csp->flags & CSP_FLAG_FORCED) &&
606 #else /* ifndef FEATURE_FORCE_LOAD */
607 #   define IS_NOT_FORCED_AND
608 #endif /* def FEATURE_FORCE_LOAD */
609
610 #define IS_ENABLED_AND   IS_TOGGLED_ON_AND IS_NOT_FORCED_AND
611
612    char buf[BUFFER_SIZE];
613    char *hdr, *p, *req;
614    fd_set rfds;
615    int n, maxfd, server_body;
616    int ms_iis5_hack = 0;
617    int byte_count = 0;
618    const struct forward_spec * fwd;
619    struct http_request *http;
620 #ifdef FEATURE_KILL_POPUPS
621    int block_popups;         /* bool, 1==will block popups */
622    int block_popups_now = 0; /* bool, 1==currently blocking popups */
623 #endif /* def FEATURE_KILL_POPUPS */
624
625    int pcrs_filter;        /* bool, 1==will filter through pcrs */
626    int gif_deanimate;      /* bool, 1==will deanimate gifs */
627
628    /* Function that does the content filtering for the current request */
629    char *(*content_filter)() = NULL;
630
631    /* Skeleton for HTTP response, if we should intercept the request */
632    struct http_response *rsp;
633
634    http = csp->http;
635
636    /*
637     * Read the client's request.  Note that since we're not using select() we
638     * could get blocked here if a client connected, then didn't say anything!
639     */
640
641    while (FOREVER)
642    {
643       n = read_socket(csp->cfd, buf, sizeof(buf));
644
645       if (n <= 0) break;      /* error! */
646
647       add_to_iob(csp, buf, n);
648
649       req = get_header(csp);
650
651       if (req == NULL)
652       {
653          break;    /* no HTTP request! */
654       }
655
656       if (*req == '\0')
657       {
658          continue;   /* more to come! */
659       }
660
661 #ifdef FEATURE_FORCE_LOAD
662       /* If this request contains the FORCE_PREFIX,
663        * better get rid of it now and set the force flag --oes
664        */
665
666       if (strstr(req, FORCE_PREFIX))
667       {
668          strclean(req, FORCE_PREFIX);
669          log_error(LOG_LEVEL_FORCE, "Enforcing request \"%s\".\n", req);
670          csp->flags |= CSP_FLAG_FORCED;
671       }
672
673 #endif /* def FEATURE_FORCE_LOAD */
674
675       parse_http_request(req, http, csp);
676       freez(req);
677       break;
678    }
679
680    if (http->cmd == NULL)
681    {
682       strcpy(buf, CHEADER);
683       write_socket(csp->cfd, buf, strlen(buf));
684
685       log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 400 0", csp->ip_addr_str);
686
687       return;
688    }
689
690    /* decide how to route the HTTP request */
691
692    if ((fwd = forward_url(http, csp)) == NULL)
693    {
694       log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!?  This can't happen!");
695       /* Never get here - LOG_LEVEL_FATAL causes program exit */
696    }
697
698    /* build the http request to send to the server
699     * we have to do one of the following:
700     *
701     * create = use the original HTTP request to create a new
702     *          HTTP request that has either the path component
703     *          without the http://domainspec (w/path) or the
704     *          full orininal URL (w/url)
705     *          Note that the path and/or the HTTP version may
706     *          have been altered by now.
707     *
708     * connect = Open a socket to the host:port of the server
709     *           and short-circuit server and client socket.
710     *
711     * pass =  Pass the request unchanged if forwarding a CONNECT
712     *         request to a parent proxy. Note that we'll be sending
713     *         the CFAIL message ourselves if connecting to the parent
714     *         fails, but we won't send a CSUCCEED message if it works,
715     *         since that would result in a double message (ours and the
716     *         parent's). After sending the request to the parent, we simply
717     *         tunnel.
718     *
719     * here's the matrix:
720     *                        SSL
721     *                    0        1
722     *                +--------+--------+
723     *                |        |        |
724     *             0  | create | connect|
725     *                | w/path |        |
726     *  Forwarding    +--------+--------+
727     *                |        |        |
728     *             1  | create | pass   |
729     *                | w/url  |        |
730     *                +--------+--------+
731     *
732     */
733
734    /*
735     * Determine the actions for this URL
736     */
737 #ifdef FEATURE_TOGGLE
738    if (!(csp->flags & CSP_FLAG_TOGGLED_ON))
739    {
740       /* Most compatible set of actions (i.e. none) */
741       init_current_action(csp->action);
742    }
743    else
744 #endif /* ndef FEATURE_TOGGLE */
745    {
746       url_actions(http, csp);
747    }
748
749
750    /*
751     * Check if a CONNECT request is allowable:
752     * In the absence of a +limit-connect action, allow only port 443.
753     * If there is an action, allow whatever matches the specificaton.
754     */
755    if(http->ssl)
756    {
757       if(  ( !(csp->action->flags & ACTION_LIMIT_CONNECT) && csp->http->port != 443)
758            || (csp->action->flags & ACTION_LIMIT_CONNECT
759               && !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT], csp->http->port)) )
760       {
761          strcpy(buf, CFORBIDDEN);
762          write_socket(csp->cfd, buf, strlen(buf));
763
764          log_error(LOG_LEVEL_CONNECT, "Denying suspicious CONNECT request from %s", csp->ip_addr_str);
765          log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 403 0", csp->ip_addr_str);
766
767          return;
768       }
769    }
770
771
772    /*
773     * Downgrade http version from 1.1 to 1.0 if +downgrade
774     * action applies
775     */
776    if ( (http->ssl == 0)
777      && (!strcmpic(http->ver, "HTTP/1.1"))
778      && (csp->action->flags & ACTION_DOWNGRADE))
779    {
780       freez(http->ver);
781       http->ver = strdup("HTTP/1.0");
782
783       if (http->ver == NULL)
784       {
785          log_error(LOG_LEVEL_FATAL, "Out of memory downgrading HTTP version");
786       }
787    }
788
789    /* 
790     * Save a copy of the original request for logging
791     */
792    http->ocmd = strdup(http->cmd);
793
794    if (http->ocmd == NULL)
795    {
796       log_error(LOG_LEVEL_FATAL, "Out of memory copying HTTP request line");
797    }
798
799    /*
800     * (Re)build the HTTP request for non-SSL requests.
801     * If forwarding, use the whole URL, else, use only the path.
802     */
803    if (http->ssl == 0)
804    {
805       freez(http->cmd);
806
807       http->cmd = strdup(http->gpc);
808       string_append(&http->cmd, " ");
809
810       if (fwd->forward_host)
811       {
812          string_append(&http->cmd, http->url);
813       }
814       else
815       {
816          string_append(&http->cmd, http->path);
817       }
818
819       string_append(&http->cmd, " ");
820       string_append(&http->cmd, http->ver);
821
822       if (http->cmd == NULL)
823       {
824          log_error(LOG_LEVEL_FATAL, "Out of memory rewiting SSL command");
825       }
826    }
827    enlist(csp->headers, http->cmd);
828
829
830 #ifdef FEATURE_COOKIE_JAR
831    /*
832     * If we're logging cookies in a cookie jar, and the user has not
833     * supplied any wafers, and the user has not told us to suppress the
834     * vanilla wafer, then send the vanilla wafer.
835     */
836    if ((csp->config->jarfile != NULL)
837        && list_is_empty(csp->action->multi[ACTION_MULTI_WAFER])
838        && ((csp->action->flags & ACTION_VANILLA_WAFER) != 0))
839    {
840       enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER);
841    }
842 #endif /* def FEATURE_COOKIE_JAR */
843
844
845 #ifdef FEATURE_KILL_POPUPS
846    block_popups               = ((csp->action->flags & ACTION_NO_POPUPS) != 0);
847 #endif /* def FEATURE_KILL_POPUPS */
848
849    pcrs_filter                = (csp->rlist != NULL) &&  /* There are expressions to be used */
850                                 ((csp->action->flags & ACTION_FILTER) != 0);
851
852    gif_deanimate              = ((csp->action->flags & ACTION_DEANIMATE) != 0);
853
854    /* grab the rest of the client's headers */
855
856    while (FOREVER)
857    {
858       if ( ( p = get_header(csp) ) && ( *p == '\0' ) )
859       {
860          n = read_socket(csp->cfd, buf, sizeof(buf));
861          if (n <= 0)
862          {
863             log_error(LOG_LEVEL_ERROR, "read from client failed: %E");
864             return;
865          }
866          add_to_iob(csp, buf, n);
867          continue;
868       }
869
870       if (p == NULL) break;
871
872       enlist(csp->headers, p);
873       freez(p);
874    }
875    /*
876     * We have a request. Now, check to see if we need to
877     * intercept it, i.e. If ..
878     */
879
880    if (
881        /* a CGI call was detected and answered */
882        (NULL != (rsp = dispatch_cgi(csp)))
883
884        /* or we are enabled and... */
885        || (IS_ENABLED_AND (
886
887             /* ..the request was blocked */
888           ( NULL != (rsp = block_url(csp)))
889
890           /* ..or untrusted */
891 #ifdef FEATURE_TRUST
892           || ( NULL != (rsp = trust_url(csp)))
893 #endif /* def FEATURE_TRUST */
894
895           /* ..or a fast redirect kicked in */
896 #ifdef FEATURE_FAST_REDIRECTS
897           || (((csp->action->flags & ACTION_FAST_REDIRECTS) != 0) &&
898                 (NULL != (rsp = redirect_url(csp))))
899 #endif /* def FEATURE_FAST_REDIRECTS */
900           ))
901       )
902    {
903       /* Write the answer to the client */
904       if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length)
905            || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
906       {
907          log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
908       }
909
910 #ifdef FEATURE_STATISTICS
911       /* Count as a rejected request */
912       csp->flags |= CSP_FLAG_REJECTED;
913 #endif /* def FEATURE_STATISTICS */
914
915       /* Log (FIXME: All intercept reasons apprear as "crunch" with Status 200) */
916       log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path);
917       log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", csp->ip_addr_str, http->ocmd);
918
919       /* Clean up and return */
920       free_http_response(rsp);
921       return;
922    }
923
924    log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path);
925
926    if (fwd->forward_host)
927    {
928       log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s",
929                fwd->forward_host, fwd->forward_port, http->hostport);
930    }
931    else
932    {
933       log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport);
934    }
935
936    /* here we connect to the server, gateway, or the forwarder */
937
938    csp->sfd = forwarded_connect(fwd, http, csp);
939
940    if (csp->sfd < 0)
941    {
942       log_error(LOG_LEVEL_CONNECT, "connect to: %s failed: %E",
943                 http->hostport);
944
945       if (errno == EINVAL)
946       {
947          rsp = error_response(csp, "no-such-domain", errno);
948
949          log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 404 0",
950                    csp->ip_addr_str, http->ocmd);
951       }
952       else
953       {
954          rsp = error_response(csp, "connect-failed", errno);
955
956          log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
957                    csp->ip_addr_str, http->ocmd);
958       }
959
960
961       /* Write the answer to the client */
962       if(rsp)
963       {
964          if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length)
965           || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
966          {
967             log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
968          }
969       }
970
971       free_http_response(rsp);
972       return;
973    }
974
975    log_error(LOG_LEVEL_CONNECT, "OK");
976
977    hdr = sed(client_patterns, add_client_headers, csp);
978    if (hdr == NULL)
979    {
980       /* FIXME Should handle error properly */
981       log_error(LOG_LEVEL_FATAL, "Out of memory parsing client header");
982    }
983
984    list_remove_all(csp->headers);
985
986    if (fwd->forward_host || (http->ssl == 0))
987    {
988       /* write the client's (modified) header to the server
989        * (along with anything else that may be in the buffer)
990        */
991
992       n = strlen(hdr);
993
994       if ((write_socket(csp->sfd, hdr, n) != n)
995           || (flush_socket(csp->sfd, csp   ) <  0))
996       {
997          log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E",
998                     http->hostport);
999
1000          log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
1001                    csp->ip_addr_str, http->ocmd);
1002
1003          rsp = error_response(csp, "connect-failed", errno);
1004
1005          if(rsp)
1006          {
1007             if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length)
1008              || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
1009             {
1010                log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
1011             }
1012          }
1013
1014          free_http_response(rsp);
1015          freez(hdr);
1016          return;
1017       }
1018    }
1019    else
1020    {
1021       /*
1022        * We're running an SSL tunnel and we're not forwarding,
1023        * so just send the "connect succeeded" message to the
1024        * client, flush the rest, and get out of the way.
1025        */
1026       log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 2\n",
1027                 csp->ip_addr_str, http->ocmd);
1028
1029       if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1) < 0)
1030       {
1031          freez(hdr);
1032          return;
1033       }
1034       IOB_RESET(csp);
1035    }
1036
1037    /* we're finished with the client's header */
1038    freez(hdr);
1039
1040    maxfd = ( csp->cfd > csp->sfd ) ? csp->cfd : csp->sfd;
1041
1042    /* pass data between the client and server
1043     * until one or the other shuts down the connection.
1044     */
1045
1046    server_body = 0;
1047
1048    while (FOREVER)
1049    {
1050       FD_ZERO(&rfds);
1051
1052       FD_SET(csp->cfd, &rfds);
1053       FD_SET(csp->sfd, &rfds);
1054
1055       n = select(maxfd+1, &rfds, NULL, NULL, NULL);
1056
1057       if (n < 0)
1058       {
1059          log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
1060          return;
1061       }
1062
1063       /* this is the body of the browser's request
1064        * just read it and write it.
1065        */
1066
1067       if (FD_ISSET(csp->cfd, &rfds))
1068       {
1069          n = read_socket(csp->cfd, buf, sizeof(buf));
1070
1071          if (n <= 0)
1072          {
1073             break; /* "game over, man" */
1074          }
1075
1076          if (write_socket(csp->sfd, buf, n) != n)
1077          {
1078             log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
1079             return;
1080          }
1081          continue;
1082       }
1083
1084       /*
1085        * The server wants to talk.  It could be the header or the body.
1086        * If `hdr' is null, then it's the header otherwise it's the body.
1087        * FIXME: Does `hdr' really mean `host'? No.
1088        */
1089
1090
1091       if (FD_ISSET(csp->sfd, &rfds))
1092       {
1093          fflush( 0 );
1094          n = read_socket(csp->sfd, buf, sizeof(buf) - 1);
1095
1096          if (n < 0)
1097          {
1098             log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host);
1099
1100             log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
1101                       csp->ip_addr_str, http->ocmd);
1102
1103             rsp = error_response(csp, "connect-failed", errno);
1104
1105             if(rsp)
1106             {
1107                if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length)
1108                 || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
1109                {
1110                   log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
1111                }
1112             }
1113
1114             free_http_response(rsp);
1115             return;
1116          }
1117
1118          /* Add a trailing zero.  This lets filter_popups
1119           * use string operations.
1120           */
1121          buf[n] = '\0';
1122
1123 #ifdef FEATURE_KILL_POPUPS
1124          /* Filter the popups on this read. */
1125          if (block_popups_now)
1126          {
1127             filter_popups(buf, csp);
1128          }
1129 #endif /* def FEATURE_KILL_POPUPS */
1130
1131          /* Normally, this would indicate that we've read
1132           * as much as the server has sent us and we can
1133           * close the client connection.  However, Microsoft
1134           * in its wisdom has released IIS/5 with a bug that
1135           * prevents it from sending the trailing \r\n in
1136           * a 302 redirect header (and possibly other headers).
1137           * To work around this if we've haven't parsed
1138           * a full header we'll append a trailing \r\n
1139           * and see if this now generates a valid one.
1140           *
1141           * This hack shouldn't have any impacts.  If we've
1142           * already transmitted the header or if this is a
1143           * SSL connection, then we won't bother with this
1144           * hack.  So we only work on partially received
1145           * headers.  If we append a \r\n and this still
1146           * doesn't generate a valid header, then we won't
1147           * transmit anything to the client.
1148           */
1149          if (n == 0)
1150          {
1151
1152             if (server_body || http->ssl)
1153             {
1154                /*
1155                 * If we have been buffering up the document,
1156                 * now is the time to apply content modification
1157                 * and send the result to the client.
1158                 */
1159                if (content_filter)
1160                {
1161                   /*
1162                    * If the content filter fails, use the original
1163                    * buffer and length.
1164                    * (see p != NULL ? p : csp->iob->cur below)
1165                    */
1166                   if (NULL == (p = (*content_filter)(csp)))
1167                   {
1168                      csp->content_length = csp->iob->eod - csp->iob->cur;
1169                   }
1170
1171                   hdr = sed(server_patterns, add_server_headers, csp);
1172                   if (hdr == NULL)
1173                   {
1174                      /* FIXME Should handle error properly */
1175                      log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header");
1176                   }
1177
1178                   n = strlen(hdr);
1179
1180                   if ((write_socket(csp->cfd, hdr, n) != n)
1181                       || (write_socket(csp->cfd, p != NULL ? p : csp->iob->cur, csp->content_length) != (int)csp->content_length))
1182                   {
1183                      log_error(LOG_LEVEL_ERROR, "write modified content to client failed: %E");
1184                      return;
1185                   }
1186
1187                   freez(hdr);
1188                   if (NULL != p) {
1189                      freez(p);
1190                   }
1191                }
1192
1193                break; /* "game over, man" */
1194             }
1195
1196             /*
1197              * This is NOT the body, so
1198              * Let's pretend the server just sent us a blank line.
1199              */
1200             n = sprintf(buf, "\r\n");
1201
1202             /*
1203              * Now, let the normal header parsing algorithm below do its
1204              * job.  If it fails, we'll exit instead of continuing.
1205              */
1206
1207             ms_iis5_hack = 1;
1208          }
1209
1210          /*
1211           * If this is an SSL connection or we're in the body
1212           * of the server document, just write it to the client,
1213           * unless we need to buffer the body for later content-filtering
1214           */
1215
1216          if (server_body || http->ssl)
1217          {
1218             if (content_filter)
1219             {
1220                add_to_iob(csp, buf, n);
1221
1222                /*
1223                 * If the buffer limit will be reached on the next read,
1224                 * switch to non-filtering mode, i.e. make & write the
1225                 * header, flush the socket and get out of the way.
1226                 */
1227                if (((size_t)(csp->iob->eod - csp->iob->buf)) + (size_t)BUFFER_SIZE > csp->config->buffer_limit)
1228                {
1229                   log_error(LOG_LEVEL_ERROR, "Buffer size limit reached! Flushing and stepping back.");
1230
1231                   hdr = sed(server_patterns, add_server_headers, csp);
1232                   if (hdr == NULL)
1233                   {
1234                      /* FIXME Should handle error properly */
1235                      log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header");
1236                   }
1237
1238                   n   = strlen(hdr);
1239                   byte_count += n;
1240
1241                   if (((write_socket(csp->cfd, hdr, n) != n)
1242                        || (n = flush_socket(csp->cfd, csp) < 0)))
1243                   {
1244                      log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
1245
1246                      freez(hdr);
1247                      return;
1248                   }
1249
1250                   freez(hdr);
1251                   byte_count += n;
1252
1253                   content_filter = NULL;
1254                   server_body = 1;
1255
1256                }
1257             }
1258             else
1259             {
1260                if (write_socket(csp->cfd, buf, n) != n)
1261                {
1262                   log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
1263                   return;
1264                }
1265             }
1266             byte_count += n;
1267             continue;
1268          }
1269          else
1270          {
1271             /* we're still looking for the end of the
1272              * server's header ... (does that make header
1273              * parsing an "out of body experience" ?
1274              */
1275
1276             /* buffer up the data we just read */
1277             add_to_iob(csp, buf, n);
1278
1279             /* get header lines from the iob */
1280
1281             while ((p = get_header(csp)))
1282             {
1283                if (*p == '\0')
1284                {
1285                   /* see following note */
1286                   break;
1287                }
1288                enlist(csp->headers, p);
1289                freez(p);
1290             }
1291
1292             /* NOTE: there are no "empty" headers so
1293              * if the pointer `p' is not NULL we must
1294              * assume that we reached the end of the
1295              * buffer before we hit the end of the header.
1296              */
1297
1298             if (p)
1299             {
1300                if (ms_iis5_hack)
1301                {
1302                   /* Well, we tried our MS IIS/5
1303                    * hack and it didn't work.
1304                    * The header is incomplete
1305                    * and there isn't anything
1306                    * we can do about it.
1307                    */
1308                   break;
1309                }
1310                else
1311                {
1312                   /* Since we have to wait for
1313                    * more from the server before
1314                    * we can parse the headers
1315                    * we just continue here.
1316                    */
1317                   continue;
1318                }
1319             }
1320
1321             /* we have now received the entire header.
1322              * filter it and send the result to the client
1323              */
1324
1325             hdr = sed(server_patterns, add_server_headers, csp);
1326             if (hdr == NULL)
1327             {
1328                /* FIXME Should handle error properly */
1329                log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header");
1330             }
1331
1332             n   = strlen(hdr);
1333
1334             /* write the server's (modified) header to
1335              * the client (along with anything else that
1336              * may be in the buffer)
1337              */
1338
1339 #ifdef FEATURE_KILL_POPUPS
1340             /* Start blocking popups if appropriate. */
1341
1342             if ((csp->content_type & CT_TEXT) &&  /* It's a text / * MIME-Type */
1343                 !http->ssl    &&                  /* We talk plaintext */
1344                 block_popups)                     /* Policy allows */
1345             {
1346                block_popups_now = 1;
1347                /*
1348                 * Filter the part of the body that came in the same read
1349                 * as the last headers:
1350                 */
1351                filter_popups(csp->iob->cur, csp);
1352             }
1353
1354 #endif /* def FEATURE_KILL_POPUPS */
1355
1356             /* Buffer and pcrs filter this if appropriate. */
1357
1358             if ((csp->content_type & CT_TEXT) &&  /* It's a text / * MIME-Type */
1359                 !http->ssl    &&                  /* We talk plaintext */
1360                 pcrs_filter)                      /* Policy allows */
1361             {
1362                content_filter = pcrs_filter_response;
1363             }
1364
1365             /* Buffer and gif_deanimate this if appropriate. */
1366
1367             if ((csp->content_type & CT_GIF)  &&  /* It's a image/gif MIME-Type */
1368                 !http->ssl    &&                  /* We talk plaintext */
1369                 gif_deanimate)                    /* Policy allows */
1370             {
1371                content_filter = gif_deanimate_response;
1372             }
1373
1374
1375             /*
1376              * Only write if we're not buffering for content modification
1377              */
1378             if (!content_filter && ((write_socket(csp->cfd, hdr, n) != n)
1379                 || (n = flush_socket(csp->cfd, csp) < 0)))
1380             {
1381                log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
1382
1383                /* the write failed, so don't bother
1384                 * mentioning it to the client...
1385                 * it probably can't hear us anyway.
1386                 */
1387                freez(hdr);
1388                return;
1389             }
1390
1391             if(!content_filter) byte_count += n;
1392
1393             /* we're finished with the server's header */
1394
1395             freez(hdr);
1396             server_body = 1;
1397
1398             /* If this was a MS IIS/5 hack then it means
1399              * the server has already closed the
1400              * connection.  Nothing more to read.  Time
1401              * to bail.
1402              */
1403             if (ms_iis5_hack)
1404             {
1405                break;
1406             }
1407          }
1408          continue;
1409       }
1410
1411       return; /* huh? we should never get here */
1412    }
1413
1414    log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %d",
1415              csp->ip_addr_str, http->ocmd, byte_count);
1416 }
1417
1418
1419 /*********************************************************************
1420  *
1421  * Function    :  serve
1422  *
1423  * Description :  This is little more than chat.  We only "serve" to
1424  *                to close any socket that chat may have opened.
1425  *
1426  * Parameters  :
1427  *          1  :  csp = Current client state (buffers, headers, etc...)
1428  *
1429  * Returns     :  N/A
1430  *
1431  *********************************************************************/
1432 #ifdef AMIGA
1433 void serve(struct client_state *csp)
1434 #else /* ifndef AMIGA */
1435 static void serve(struct client_state *csp)
1436 #endif /* def AMIGA */
1437 {
1438    chat(csp);
1439    close_socket(csp->cfd);
1440
1441    if (csp->sfd >= 0)
1442    {
1443       close_socket(csp->sfd);
1444    }
1445
1446    csp->flags &= ~CSP_FLAG_ACTIVE;
1447
1448 }
1449
1450
1451 #ifdef __BEOS__
1452 /*********************************************************************
1453  *
1454  * Function    :  server_thread
1455  *
1456  * Description :  We only exist to call `serve' in a threaded environment.
1457  *
1458  * Parameters  :
1459  *          1  :  data = Current client state (buffers, headers, etc...)
1460  *
1461  * Returns     :  Always 0.
1462  *
1463  *********************************************************************/
1464 static int32 server_thread(void *data)
1465 {
1466    serve((struct client_state *) data);
1467    return 0;
1468
1469 }
1470 #endif
1471
1472
1473 /*********************************************************************
1474  *
1475  * Function    :  main
1476  *
1477  * Description :  Load the config file and start the listen loop.
1478  *                This function is a lot more *sane* with the `load_config'
1479  *                and `listen_loop' functions; although it stills does
1480  *                a *little* too much for my taste.
1481  *
1482  * Parameters  :
1483  *          1  :  argc = Number of parameters (including $0).
1484  *          2  :  argv = Array of (char *)'s to the parameters.
1485  *
1486  * Returns     :  1 if : can't open config file, unrecognized directive,
1487  *                stats requested in multi-thread mode, can't open the
1488  *                log file, can't open the jar file, listen port is invalid,
1489  *                any load fails, and can't bind port.
1490  *
1491  *                Else main never returns, the process must be signaled
1492  *                to terminate execution.  Or, on Windows, use the
1493  *                "File", "Exit" menu option.
1494  *
1495  *********************************************************************/
1496 #ifdef __MINGW32__
1497 int real_main(int argc, const char *argv[])
1498 #else
1499 int main(int argc, const char *argv[])
1500 #endif
1501 {
1502    int argc_pos = 1;
1503
1504    configfile =
1505 #if !defined(_WIN32)
1506    "config"
1507 #else
1508    "config.txt"
1509 #endif
1510       ;
1511
1512 #if !defined(_WIN32) || defined(_WIN_CONSOLE)
1513    if ((argc >= 2) && (strcmp(argv[1], "--help")==0))
1514    {
1515       printf("JunkBuster proxy version " VERSION ".\n\n"
1516          "Usage: %s [configfile]\n\n"
1517          "See " HOME_PAGE_URL " for details.\n"
1518          "This program is distributed under the GNU GPL, version 2 or later.\n",
1519          argv[0]);
1520       exit(2);
1521    }
1522    if ((argc >= 2) && (strcmp(argv[1], "--version")==0))
1523    {
1524       printf(VERSION "\n");
1525       exit(2);
1526    }
1527 #ifdef _DEBUG
1528    if ((argc >= 2) && (strcmp(argv[1], "-d")==0))
1529    {
1530       ldebug++;
1531       argc_pos++;
1532       fprintf(stderr,"debugging enabled..\n");
1533    }
1534 #endif /* _DEBUG */
1535 #endif /* !defined(_WIN32) || defined(_WIN_CONSOLE) */
1536
1537    Argc = argc;
1538    Argv = argv;
1539
1540    if (argc > argc_pos )
1541    {
1542       configfile = argv[argc_pos];
1543    }
1544
1545 #if defined(unix)
1546    if ( *configfile != '/' )
1547    {
1548       char *abs_file;
1549
1550       DBG(1, ("configfile before '%s'\n",configfile) );
1551
1552       /* make config-filename absolute here */
1553       if ( !(basedir = getcwd( NULL, 1024 )))
1554       {
1555          perror("get working dir failed");
1556          exit( 1 );
1557       }
1558       DBG(1, ("working dir '%s'\n",basedir) );
1559       if ( !(abs_file = malloc( strlen( basedir ) + strlen( configfile ) + 5 )))
1560       {
1561          perror("malloc failed");
1562          exit( 1 );
1563       }
1564       strcpy( abs_file, basedir );
1565       strcat( abs_file, "/" );
1566       strcat( abs_file, configfile );
1567       configfile = abs_file;
1568       DBG(1, ("configfile after '%s'\n",configfile) );
1569    }
1570 #endif /* defined unix */
1571
1572
1573    files->next = NULL;
1574
1575 #ifdef AMIGA
1576    InitAmiga();
1577 #elif defined(_WIN32)
1578    InitWin32();
1579 #endif
1580
1581
1582 #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA)
1583 {
1584    int sig;
1585    struct sigaction action;
1586
1587    for ( sig = 1; sig < 16; sig++ )
1588    {
1589       switch( sig )
1590       {
1591          case 9:
1592          case SIGPIPE:
1593          case SIGCHLD:
1594          case SIGHUP:
1595                  continue;
1596       }
1597       if ( signal(sig, SIG_handler)  == SIG_ERR )
1598          log_error(LOG_LEVEL_FATAL, "Can't set signal-handler for signal %d: %E", sig);
1599    }
1600    /* SIG_IGN */
1601    if ( signal(SIGPIPE, SIG_IGN) == SIG_ERR )
1602       log_error(LOG_LEVEL_FATAL, "Can't set SIG_IGN to SIGPIPE: %E");
1603    if ( signal(SIGCHLD, SIG_IGN) == SIG_ERR )
1604       log_error(LOG_LEVEL_FATAL, "Can't set SIG_IGN to SIGCHLD: %E");
1605    /* log file reload */
1606    if (!sigaction(SIGHUP,NULL,&action))
1607    {
1608       action.sa_handler = &SIG_handler;
1609       action.sa_flags   = SA_RESTART;
1610
1611       if ( sigaction(SIGHUP,&action,NULL))
1612          log_error(LOG_LEVEL_FATAL, "Can't set signal-handler for signal SIGHUP: %E");
1613    } 
1614    else
1615    {
1616       perror("sigaction");
1617       log_error(LOG_LEVEL_FATAL, "Can't get sigaction data for signal SIGHUP");
1618    }
1619       
1620 }
1621
1622 #else /* ifdef _WIN32 */
1623 # ifdef _WIN_CONSOLE
1624    /*
1625     * We *are* in a windows console app.
1626     * Print a verbose messages about FAQ's and such
1627     */
1628    printf(win32_blurb);
1629 # endif /* def _WIN_CONSOLE */
1630 #endif /* def _WIN32 */
1631
1632
1633    /* Initialize the CGI subsystem */
1634    cgi_init_error_messages();
1635
1636 #if defined(unix)
1637 {
1638    pid_t pid = 0;
1639 #if 0
1640    int   fd;
1641 #endif
1642
1643    /*
1644     * we make us a real daemon
1645     */
1646 #ifdef _DEBUG
1647    if ( !ldebug)
1648 #endif
1649    pid  = fork();
1650    if ( pid < 0 ) /* error */
1651    {
1652       perror("fork");
1653       exit( 3 );
1654    }
1655    else if ( pid != 0 ) /* parent */
1656    {
1657       int status;
1658       pid_t wpid;
1659       /*
1660        * must check for errors
1661        * child died due to missing files aso
1662        */
1663       sleep( 1 );
1664       wpid = waitpid( pid, &status, WNOHANG );
1665       if ( wpid != 0 )
1666       {
1667          exit( 1 );
1668       }
1669       exit( 0 );
1670    }
1671    /* child */
1672 #if 1
1673    /* Should be more portable, but not as well tested */
1674    setsid();
1675 #else /* !1 */
1676 #ifdef __FreeBSD__
1677    setpgrp(0,0);
1678 #else /* ndef __FreeBSD__ */
1679    setpgrp();
1680 #endif /* ndef __FreeBSD__ */
1681    fd = open("/dev/tty", O_RDONLY);
1682    if ( fd )
1683    {
1684       /* no error check here */
1685       ioctl( fd, TIOCNOTTY,0 );
1686       close ( fd );
1687    }
1688 #endif /* !1 */
1689    /* should close stderr (fd 2) here too, but the test for existence
1690    ** and load config file is done in listen_loop() and puts
1691    ** some messages on stderr there.
1692    */
1693 #ifdef _DEBUG
1694    if ( !ldebug )
1695    {
1696       close( 0 );
1697       close( 1 );
1698    }
1699 #else
1700    close( 0 );
1701    close( 1 );
1702 #endif /* _DEBUG */
1703    chdir("/");
1704
1705    writePidFile();
1706 }
1707 #endif /* defined unix */
1708
1709    DBG(1, ("call listen_loop() \n") );
1710    listen_loop();
1711
1712    /* NOTREACHED */
1713    return(-1);
1714
1715 }
1716
1717
1718 /*********************************************************************
1719  *
1720  * Function    :  listen_loop
1721  *
1722  * Description :  bind the listen port and enter a "FOREVER" listening loop.
1723  *
1724  * Parameters  :  N/A
1725  *
1726  * Returns     :  Never.
1727  *
1728  *********************************************************************/
1729 static void listen_loop(void)
1730 {
1731    struct client_state *csp = NULL;
1732    int bfd;
1733    struct configuration_spec * config;
1734
1735    config = load_config();
1736
1737    log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)",
1738              config->haddr ? config->haddr : "INADDR_ANY", config->hport);
1739
1740    bfd = bind_port(config->haddr, config->hport);
1741
1742    if (bfd < 0)
1743    {
1744       log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E "
1745          "- There may be another junkbuster or some other "
1746          "proxy running on port %d",
1747          (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
1748          config->hport, config->hport
1749       );
1750       /* shouldn't get here */
1751       return;
1752    }
1753
1754    config->need_bind = 0;
1755
1756    while (FOREVER)
1757    {
1758 #if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1759       while (waitpid(-1, NULL, WNOHANG) > 0)
1760       {
1761          /* zombie children */
1762       }
1763 #endif /* !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1764       sweep();
1765
1766       if ( NULL == (csp = (struct client_state *) zalloc(sizeof(*csp))) )
1767       {
1768          log_error(LOG_LEVEL_FATAL, "malloc(%d) for csp failed: %E", sizeof(*csp));
1769          continue;
1770       }
1771
1772       csp->flags |= CSP_FLAG_ACTIVE;
1773       csp->sfd    = -1;
1774
1775       csp->config = config = load_config();
1776
1777       if ( config->need_bind )
1778       {
1779          /*
1780           * Since we were listening to the "old port", we will not see
1781           * a "listen" param change until the next IJB request.  So, at
1782           * least 1 more request must be made for us to find the new
1783           * setting.  I am simply closing the old socket and binding the
1784           * new one.
1785           *
1786           * Which-ever is correct, we will serve 1 more page via the
1787           * old settings.  This should probably be a "show-proxy-args"
1788           * request.  This should not be a so common of an operation
1789           * that this will hurt people's feelings.
1790           */
1791
1792          close_socket(bfd);
1793
1794          log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)",
1795                    config->haddr ? config->haddr : "INADDR_ANY", config->hport);
1796          bfd = bind_port(config->haddr, config->hport);
1797
1798          if (bfd < 0)
1799          {
1800             log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E "
1801                "- There may be another junkbuster or some other "
1802                "proxy running on port %d",
1803                (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
1804                config->hport, config->hport
1805             );
1806             /* shouldn't get here */
1807             return;
1808          }
1809
1810          config->need_bind = 0;
1811       }
1812
1813       log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
1814
1815       if (!accept_connection(csp, bfd))
1816       {
1817          log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
1818
1819 #ifdef AMIGA
1820          if(!childs)
1821          {
1822             exit(1);
1823          }
1824 #endif
1825          freez(csp);
1826          continue;
1827       }
1828       else
1829       {
1830          log_error(LOG_LEVEL_CONNECT, "OK");
1831       }
1832
1833 #ifdef FEATURE_TOGGLE
1834       if (g_bToggleIJB)
1835       {
1836          csp->flags |= CSP_FLAG_TOGGLED_ON;
1837       }
1838 #endif /* def FEATURE_TOGGLE */
1839
1840       if (run_loader(csp))
1841       {
1842          log_error(LOG_LEVEL_FATAL, "a loader failed - must exit");
1843          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1844       }
1845
1846 #ifdef FEATURE_ACL
1847       if (block_acl(NULL,csp))
1848       {
1849          log_error(LOG_LEVEL_CONNECT, "Connection dropped due to ACL");
1850          close_socket(csp->cfd);
1851          freez(csp);
1852          continue;
1853       }
1854 #endif /* def FEATURE_ACL */
1855
1856       /* add it to the list of clients */
1857       csp->next = clients->next;
1858       clients->next = csp;
1859
1860       if (config->multi_threaded)
1861       {
1862          int child_id;
1863
1864 /* this is a switch () statment in the C preprocessor - ugh */
1865 #undef SELECTED_ONE_OPTION
1866
1867 /* Use Pthreads in preference to native code */
1868 #if defined(FEATURE_PTHREAD) && !defined(SELECTED_ONE_OPTION)
1869 #define SELECTED_ONE_OPTION
1870          {
1871             pthread_t the_thread;
1872             pthread_attr_t attrs;
1873
1874             pthread_attr_init(&attrs);
1875             pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
1876             child_id = (pthread_create(&the_thread, &attrs,
1877                (void*)serve, csp) ? -1 : 0);
1878             pthread_attr_destroy(&attrs);
1879          }
1880 #endif
1881
1882 #if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION)
1883 #define SELECTED_ONE_OPTION
1884          child_id = _beginthread(
1885             (void*)serve,
1886             64 * 1024,
1887             csp);
1888 #endif
1889
1890 #if defined(__OS2__) && !defined(SELECTED_ONE_OPTION)
1891 #define SELECTED_ONE_OPTION
1892          child_id = _beginthread(
1893             serve,
1894             NULL,
1895             64 * 1024,
1896             csp);
1897 #endif
1898
1899 #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION)
1900 #define SELECTED_ONE_OPTION
1901          {
1902             thread_id tid = spawn_thread
1903                (server_thread, "server", B_NORMAL_PRIORITY, csp);
1904
1905             if ((tid >= 0) && (resume_thread(tid) == B_OK))
1906             {
1907                child_id = (int) tid;
1908             }
1909             else
1910             {
1911                child_id = -1;
1912             }
1913          }
1914 #endif
1915
1916 #if defined(AMIGA) && !defined(SELECTED_ONE_OPTION)
1917 #define SELECTED_ONE_OPTION
1918          csp->cfd = ReleaseSocket(csp->cfd, -1);
1919          if((child_id = (int)CreateNewProcTags(
1920             NP_Entry, (ULONG)server_thread,
1921             NP_Output, Output(),
1922             NP_CloseOutput, FALSE,
1923             NP_Name, (ULONG)"junkbuster child",
1924             NP_StackSize, 200*1024,
1925             TAG_DONE)))
1926          {
1927             childs++;
1928             ((struct Task *)child_id)->tc_UserData = csp;
1929             Signal((struct Task *)child_id, SIGF_SINGLE);
1930             Wait(SIGF_SINGLE);
1931          }
1932 #endif
1933
1934 #if !defined(SELECTED_ONE_OPTION)
1935          child_id = fork();
1936
1937          /* This block is only needed when using fork().
1938           * When using threads, the server thread was
1939           * created and run by the call to _beginthread().
1940           */
1941          if (child_id == 0)   /* child */
1942          {
1943             serve(csp);
1944             _exit(0);
1945
1946          }
1947          else if (child_id > 0) /* parent */
1948          {
1949             /* in a fork()'d environment, the parent's
1950              * copy of the client socket and the CSP
1951              * are not used.
1952              */
1953
1954 #if !defined(_WIN32) && defined(__CYGWIN__)
1955             wait( NULL );
1956 #endif /* !defined(_WIN32) && defined(__CYGWIN__) */
1957             close_socket(csp->cfd);
1958             csp->flags &= ~CSP_FLAG_ACTIVE;
1959          }
1960 #endif
1961
1962 #undef SELECTED_ONE_OPTION
1963 /* end of cpp switch () */
1964
1965          if (child_id < 0) /* failed */
1966          {
1967             char buf[BUFFER_SIZE];
1968
1969             log_error(LOG_LEVEL_ERROR, "can't fork: %E");
1970
1971             sprintf(buf , "JunkBuster: can't fork: errno = %d", errno);
1972
1973             write_socket(csp->cfd, buf, strlen(buf));
1974             close_socket(csp->cfd);
1975             csp->flags &= ~CSP_FLAG_ACTIVE;
1976             sleep(5);
1977             continue;
1978          }
1979       }
1980       else
1981       {
1982          serve(csp);
1983       }
1984    }
1985    /* NOTREACHED */
1986
1987 }
1988
1989
1990 /*
1991   Local Variables:
1992   tab-width: 3
1993   end:
1994 */