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