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