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