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