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