Removing obsolete settings.
[privoxy.git] / filters.c
1 const char filters_rcs[] = "$Id: filters.c,v 1.12 2001/05/31 17:35:20 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/filters.c,v $
5  *
6  * Purpose     :  Declares functions to parse/crunch headers and pages.
7  *                Functions declared include:
8  *                   `acl_addr', `add_stats', `block_acl', `block_imageurl',
9  *                   `block_url', `url_actions', `domaincmp', `dsplit',
10  *                   `filter_popups', `forward_url', 'redirect_url',
11  *                   `ij_untrusted_url', `intercept_url', `re_process_buffer',
12  *                   `show_proxy_args', 'ijb_send_banner', and `trust_url'
13  *
14  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
15  *                IJBSWA team.  http://ijbswa.sourceforge.net
16  *
17  *                Based on the Internet Junkbuster originally written
18  *                by and Copyright (C) 1997 Anonymous Coders and 
19  *                Junkbusters Corporation.  http://www.junkbusters.com
20  *
21  *                This program is free software; you can redistribute it 
22  *                and/or modify it under the terms of the GNU General
23  *                Public License as published by the Free Software
24  *                Foundation; either version 2 of the License, or (at
25  *                your option) any later version.
26  *
27  *                This program is distributed in the hope that it will
28  *                be useful, but WITHOUT ANY WARRANTY; without even the
29  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
30  *                PARTICULAR PURPOSE.  See the GNU General Public
31  *                License for more details.
32  *
33  *                The GNU General Public License should be included with
34  *                this file.  If not, you can view it at
35  *                http://www.gnu.org/copyleft/gpl.html
36  *                or write to the Free Software Foundation, Inc., 59
37  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
38  *
39  * Revisions   :
40  *    $Log: filters.c,v $
41  *    Revision 1.12  2001/05/31 17:35:20  oes
42  *
43  *     - Enhanced domain part globbing with infix and prefix asterisk
44  *       matching and optional unanchored operation
45  *
46  *    Revision 1.11  2001/05/29 11:53:23  oes
47  *    "See why" link added to "blocked" page
48  *
49  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
50  *    Unified blocklist/imagelist/permissionslist.
51  *    File format is still under discussion, but the internal changes
52  *    are (mostly) done.
53  *
54  *    Also modified interceptor behaviour:
55  *    - We now intercept all URLs beginning with one of the following
56  *      prefixes (and *only* these prefixes):
57  *        * http://i.j.b/
58  *        * http://ijbswa.sf.net/config/
59  *        * http://ijbswa.sourceforge.net/config/
60  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
61  *    - Internal changes so that intercepted and fast redirect pages
62  *      are not replaced with an image.
63  *    - Interceptors now have the option to send a binary page direct
64  *      to the client. (i.e. ijb-send-banner uses this)
65  *    - Implemented show-url-info interceptor.  (Which is why I needed
66  *      the above interceptors changes - a typical URL is
67  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
68  *      The previous mechanism would not have intercepted that, and
69  *      if it had been intercepted then it then it would have replaced
70  *      it with an image.)
71  *
72  *    Revision 1.9  2001/05/27 22:17:04  oes
73  *
74  *    - re_process_buffer no longer writes the modified buffer
75  *      to the client, which was very ugly. It now returns the
76  *      buffer, which it is then written by chat.
77  *
78  *    - content_length now adjusts the Content-Length: header
79  *      for modified documents rather than crunch()ing it.
80  *      (Length info in csp->content_length, which is 0 for
81  *      unmodified documents)
82  *
83  *    - For this to work, sed() is called twice when filtering.
84  *
85  *    Revision 1.8  2001/05/26 17:13:28  jongfoster
86  *    Filled in a function comment.
87  *
88  *    Revision 1.7  2001/05/26 15:26:15  jongfoster
89  *    ACL feature now provides more security by immediately dropping
90  *    connections from untrusted hosts.
91  *
92  *    Revision 1.6  2001/05/26 00:28:36  jongfoster
93  *    Automatic reloading of config file.
94  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
95  *    Most of the global variables have been moved to a new
96  *    struct configuration_spec, accessed through csp->config->globalname
97  *    Most of the globals remaining are used by the Win32 GUI.
98  *
99  *    Revision 1.5  2001/05/25 22:34:30  jongfoster
100  *    Hard tabs->Spaces
101  *
102  *    Revision 1.4  2001/05/22 18:46:04  oes
103  *
104  *    - Enabled filtering banners by size rather than URL
105  *      by adding patterns that replace all standard banner
106  *      sizes with the "Junkbuster" gif to the re_filterfile
107  *
108  *    - Enabled filtering WebBugs by providing a pattern
109  *      which kills all 1x1 images
110  *
111  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
112  *      which is selected by the (nonstandard and therefore
113  *      capital) letter 'U' in the option string.
114  *      It causes the quantifiers to be ungreedy by default.
115  *      Appending a ? turns back to greedy (!).
116  *
117  *    - Added a new interceptor ijb-send-banner, which
118  *      sends back the "Junkbuster" gif. Without imagelist or
119  *      MSIE detection support, or if tinygif = 1, or the
120  *      URL isn't recognized as an imageurl, a lame HTML
121  *      explanation is sent instead.
122  *
123  *    - Added new feature, which permits blocking remote
124  *      script redirects and firing back a local redirect
125  *      to the browser.
126  *      The feature is conditionally compiled, i.e. it
127  *      can be disabled with --disable-fast-redirects,
128  *      plus it must be activated by a "fast-redirects"
129  *      line in the config file, has its own log level
130  *      and of course wants to be displayed by show-proxy-args
131  *      Note: Boy, all the #ifdefs in 1001 locations and
132  *      all the fumbling with configure.in and acconfig.h
133  *      were *way* more work than the feature itself :-(
134  *
135  *    - Because a generic redirect template was needed for
136  *      this, tinygif = 3 now uses the same.
137  *
138  *    - Moved GIFs, and other static HTTP response templates
139  *      to project.h
140  *
141  *    - Some minor fixes
142  *
143  *    - Removed some >400 CRs again (Jon, you really worked
144  *      a lot! ;-)
145  *
146  *    Revision 1.3  2001/05/20 16:44:47  jongfoster
147  *    Removing last hardcoded JunkBusters.com URLs.
148  *
149  *    Revision 1.2  2001/05/20 01:21:20  jongfoster
150  *    Version 2.9.4 checkin.
151  *    - Merged popupfile and cookiefile, and added control over PCRS
152  *      filtering, in new "permissionsfile".
153  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
154  *      file error you now get a message box (in the Win32 GUI) rather
155  *      than the program exiting with no explanation.
156  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
157  *      skipping.
158  *    - Removed tabs from "config"
159  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
160  *    - Bumped up version number.
161  *
162  *    Revision 1.1.1.1  2001/05/15 13:58:52  oes
163  *    Initial import of version 2.9.3 source tree
164  *
165  *
166  *********************************************************************/
167 \f
168
169 #include "config.h"
170
171 #include <stdio.h>
172 #include <sys/types.h>
173 #include <stdlib.h>
174 #include <ctype.h>
175 #include <string.h>
176
177 #ifndef _WIN32
178 #include <unistd.h>
179 #include <netinet/in.h>
180 #else
181 #include <winsock2.h>
182 #endif
183
184 #include "project.h"
185 #include "filters.h"
186 #include "encode.h"
187 #include "jcc.h"
188 #include "showargs.h"
189 #include "parsers.h"
190 #include "ssplit.h"
191 #include "gateway.h"
192 #include "jbsockets.h"
193 #include "errlog.h"
194 #include "jbsockets.h"
195 #include "miscutil.h"
196 #include "actions.h"
197
198 #ifdef _WIN32
199 #include "win32.h"
200 #endif
201
202 const char filters_h_rcs[] = FILTERS_H_VERSION;
203
204 /* Fix a problem with Solaris.  There should be no effect on other
205  * platforms.
206  * Solaris's isspace() is a macro which uses it's argument directly
207  * as an array index.  Therefore we need to make sure that high-bit
208  * characters generate +ve values, and ideally we also want to make
209  * the argument match the declared parameter type of "int".
210  */
211 #define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
212
213
214 static const char CBLOCK[] = 
215 #ifdef AMIGA 
216        "HTTP/1.0 403 Request for blocked URL\n" 
217 #else /* ifndef AMIGA */
218        "HTTP/1.0 202 Request for blocked URL\n"
219 #endif /* ndef AMIGA */
220        "Pragma: no-cache\n"
221        "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
222        "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
223        "Content-Type: text/html\n\n"
224        "<html>\n"
225        "<head>\n"
226        "<title>Internet Junkbuster: Request for blocked URL</title>\n"
227        "</head>\n"
228        WHITEBG
229        "<center><h1>"
230        BANNER
231        "</h1></center>\n"
232       "<p align=center>Your request for <b>%s%s</b>\n"
233       "was blocked.<br><a href=\"http://i.j.b/show-url-info?url=%s%s\">See why</a>"
234 #ifdef FORCE_LOAD
235        " or <a href=\"http://%s" FORCE_PREFIX "%s\">"
236        "go there anyway.</a>"
237 #endif /* def FORCE_LOAD */
238       "</p>\n"
239       "</body>\n"
240       "</html>\n";
241
242 #ifdef TRUST_FILES
243 static const char CTRUST[] =
244 #ifdef AMIGA 
245        "HTTP/1.0 403 Request for untrusted URL\n"
246 #else /* ifndef AMIGA */
247        "HTTP/1.0 202 Request for untrusted URL\n"
248 #endif /* ndef AMIGA */
249        "Pragma: no-cache\n"
250        "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
251        "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
252        "Content-Type: text/html\n\n"
253        "<html>\n"
254        "<head>\n"
255        "<title>Internet Junkbuster: Request for untrusted URL</title>\n"
256        "</head>\n"
257        WHITEBG
258        "<center>"
259        "<a href=http://i.j.b/ij-untrusted-url?%s+%s+%s>"
260        BANNER
261        "</a>"
262        "</center>"
263        "</body>\n"
264        "</html>\n";
265 #endif /* def TRUST_FILES */
266
267
268 #ifdef ACL_FILES
269 /*********************************************************************
270  *
271  * Function    :  block_acl
272  *
273  * Description :  Block this request?
274  *                Decide yes or no based on ACL file.
275  *
276  * Parameters  :
277  *          1  :  dst = The proxy or gateway address this is going to.
278  *                      Or NULL to check all possible targets.
279  *          2  :  csp = Current client state (buffers, headers, etc...)
280  *                      Also includes the client IP address.
281  *
282  * Returns     : 0 = FALSE (don't block) and 1 = TRUE (do block)
283  *
284  *********************************************************************/
285 int block_acl(struct access_control_addr *dst,
286               struct client_state *csp)
287 {
288    struct file_list *fl;
289    struct access_control_list *a, *acl;
290
291    /* if not using an access control list, then permit the connection */
292    if (((fl = csp->alist) == NULL) || 
293        ((acl = (struct access_control_list *) fl->f) == NULL))
294    {
295       return(0);
296    }
297
298    /* search the list */
299    for (a = acl->next ; a ; a = a->next)
300    {
301       if ((csp->ip_addr_long & a->src->mask) == a->src->addr)
302       {
303          if (dst == NULL)
304          {
305             /* Just want to check if they have any access */
306             if (a->action == ACL_PERMIT)
307             {
308                return(0);
309             }
310          }
311          else if ( ((dst->addr & a->dst->mask) == a->dst->addr)
312            && ((dst->port == a->dst->port) || (a->dst->port == 0)))
313          {
314             if (a->action == ACL_PERMIT)
315             {
316                return(0);
317             }
318             else
319             {
320                return(1);
321             }
322          }
323       }
324    }
325
326    return(1);
327
328 }
329
330
331 /*********************************************************************
332  *
333  * Function    :  acl_addr
334  *
335  * Description :  Called from `load_aclfile' to parse an ACL address.
336  *
337  * Parameters  :
338  *          1  :  aspec = String specifying ACL address.
339  *          2  :  aca = struct access_control_addr to fill in.
340  *
341  * Returns     :  0 => Ok, everything else is an error.
342  *
343  *********************************************************************/
344 int acl_addr(char *aspec, struct access_control_addr *aca)
345 {
346    int i, masklength, port;
347    char *p;
348
349    masklength = 32;
350    port       =  0;
351
352    if ((p = strchr(aspec, '/')))
353    {
354       *p++ = '\0';
355
356       if (ijb_isdigit(*p) == 0)
357       {
358          return(-1);
359       }
360       masklength = atoi(p);
361    }
362
363    if ((masklength < 0) || (masklength > 32))
364    {
365       return(-1);
366    }
367
368    if ((p = strchr(aspec, ':')))
369    {
370       *p++ = '\0';
371
372       if (ijb_isdigit(*p) == 0)
373       {
374          return(-1);
375       }
376       port = atoi(p);
377    }
378
379    aca->port = port;
380
381    aca->addr = ntohl(resolve_hostname_to_ip(aspec));
382
383    if (aca->addr == -1)
384    {
385       log_error(LOG_LEVEL_ERROR, "can't resolve address for %s", aspec);
386       return(-1);
387    }
388
389    /* build the netmask */
390    aca->mask = 0;
391    for (i=1; i <= masklength ; i++)
392    {
393       aca->mask |= (1 << (32 - i));
394    }
395
396    /* now mask off the host portion of the ip address
397     * (i.e. save on the network portion of the address).
398     */
399    aca->addr = aca->addr & aca->mask;
400
401    return(0);
402
403 }
404 #endif /* def ACL_FILES */
405
406
407 /*********************************************************************
408  *
409  * Function    :  block_url
410  *
411  * Description :  Called from `chat'.  Check to see if we need to block this.
412  *
413  * Parameters  :
414  *          1  :  http = http_request request to "check" for blocked
415  *          2  :  csp = Current client state (buffers, headers, etc...)
416  *
417  * Returns     :  NULL => unblocked, else string to HTML block description.
418  *
419  *********************************************************************/
420 char *block_url(struct http_request *http, struct client_state *csp)
421 {
422    char *p;
423    int n;
424    int factor = 2;
425
426    if ((csp->action->flags & ACTION_BLOCK) == 0)
427    {
428       return(NULL);
429    }
430    else
431    {
432 #ifdef FORCE_LOAD
433       factor++;
434 #endif /* def FORCE_LOAD */
435
436       n  = strlen(CBLOCK);
437       n += factor * strlen(http->hostport);
438       n += factor * strlen(http->path);
439
440       p = (char *)malloc(n);
441
442 #ifdef FORCE_LOAD
443       sprintf(p, CBLOCK, http->hostport, http->path, http->hostport, http->path,
444               http->hostport, http->path);
445 #else
446       sprintf(p, CBLOCK, http->hostport, http->path, http->hostport, http->path);
447 #endif /* def FORCE_LOAD */
448
449       return(p);
450    }
451 }
452
453
454 #ifdef IMAGE_BLOCKING
455 /*********************************************************************
456  *
457  * Function    :  block_imageurl
458  *
459  * Description :  Given a URL which is blocked, decide whether to 
460  *                send the "blocked" image or HTML.
461  *
462  * Parameters  :
463  *          1  :  http = URL to check.
464  *          2  :  csp = Current client state (buffers, headers, etc...)
465  *
466  * Returns     :  True (nonzero) if URL is in image list, false (0)
467  *                otherwise
468  *
469  *********************************************************************/
470 int block_imageurl(struct http_request *http, struct client_state *csp)
471 {
472 #ifdef DETECT_MSIE_IMAGES
473    if ((csp->accept_types 
474        & (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE|ACCEPT_TYPE_MSIE_HTML))
475        == (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE))
476    {
477       return 1;
478    }
479    else if ((csp->accept_types 
480        & (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE|ACCEPT_TYPE_MSIE_HTML))
481        == (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_HTML))
482    {
483       return 0;
484    }
485 #endif
486
487    return ((csp->action->flags & ACTION_IMAGE) != 0);
488 }
489 #endif /* def IMAGE_BLOCKING */
490
491
492 #ifdef PCRS
493 /*********************************************************************
494  *
495  * Function    :  re_process_buffer
496  *
497  * Description :  Apply all jobs from the joblist (aka. Perl regexp's) to
498  *                the text buffer that's been accumulated in csp->iob->buf
499  *                and set csp->content_length to the modified size.
500  *
501  * Parameters  :
502  *          1  :  csp = Current client state (buffers, headers, etc...)
503  *
504  * Returns     :  a pointer to the (newly allocated) modified buffer.
505  *                
506  *
507  *********************************************************************/
508 char *re_process_buffer(struct client_state *csp)
509 {
510    int hits=0;
511    int size = csp->iob->eod - csp->iob->cur;
512    char *old=csp->iob->cur, *new = NULL;
513    pcrs_job *job, *joblist;
514
515    struct file_list *fl;
516    struct re_filterfile_spec *b;
517
518    /* Sanity first ;-) */
519    if (size <= 0)
520    {
521       return(strdup(""));
522    }
523
524    if ( ( NULL == (fl = csp->rlist) ) || ( NULL == (b = fl->f) ) )
525    {
526       log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering.");
527       return(strdup(""));
528    }
529
530    joblist = b->joblist;
531
532
533    log_error(LOG_LEVEL_RE_FILTER, "re_filtering %s%s (size %d) ...",
534               csp->http->hostport, csp->http->path, size);
535
536    /* Apply all jobs from the joblist */
537    for (job = joblist; NULL != job; job = job->next)
538    {
539       hits += pcrs_exec_substitution(job, old, size, &new, &size);
540       if (old != csp->iob->cur) free(old);
541       old=new;
542    }
543
544    log_error(LOG_LEVEL_RE_FILTER, " produced %d hits (new size %d).", hits, size);
545
546    csp->content_length = size;
547
548    /* fwiw, reset the iob */
549    IOB_RESET(csp);
550    return(new);
551
552 }
553 #endif /* def PCRS */
554
555
556 #ifdef TRUST_FILES
557 /*********************************************************************
558  *
559  * Function    :  trust_url
560  *
561  * Description :  Should we "trust" this URL?  See "trustfile" line in config.
562  *
563  * Parameters  :
564  *          1  :  http = http_request request for requested URL
565  *          2  :  csp = Current client state (buffers, headers, etc...)
566  *
567  * Returns     :  NULL => trusted, else string to HTML "untrusted" description.
568  *
569  *********************************************************************/
570 char *trust_url(struct http_request *http, struct client_state *csp)
571 {
572    struct file_list *fl;
573    struct block_spec *b;
574    struct url_spec url[1], **tl, *t;
575    char *p, *h;
576    char *hostport, *path, *refer;
577    struct http_request rhttp[1];
578    int n;
579
580    if (((fl = csp->tlist) == NULL) || ((b  = fl->f) == NULL))
581    {
582       return(NULL);
583    }
584
585    *url = dsplit(http->host);
586
587    /* if splitting the domain fails, punt */
588    if (url->dbuf == NULL) return(NULL);
589
590    memset(rhttp, '\0', sizeof(*rhttp));
591
592    for (b = b->next; b ; b = b->next)
593    {
594       if ((b->url->port == 0) || (b->url->port == http->port))
595       {
596          if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
597          {
598             if ((b->url->path == NULL) ||
599 #ifdef REGEX
600                (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
601 #else
602                (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
603 #endif
604             )
605             {
606                freez(url->dbuf);
607                freez(url->dvec);
608
609                if (b->reject == 0) return(NULL);
610
611                hostport = url_encode(http->hostport);
612                path     = url_encode(http->path);
613
614                if (csp->referrer)
615                {
616                   refer = url_encode(csp->referrer);
617                }
618                else
619                {
620                   refer = url_encode("undefined");
621                }
622
623                n  = strlen(CTRUST);
624                n += strlen(hostport);
625                n += strlen(path);
626                n += strlen(refer);
627
628                p = (char *)malloc(n);
629
630                sprintf(p, CTRUST, hostport, path, refer);
631
632                freez(hostport);
633                freez(path);
634                freez(refer);
635
636                return(p);
637             }
638          }
639       }
640    }
641
642    freez(url->dbuf);
643    freez(url->dvec);
644
645    if ((csp->referrer == NULL)|| (strlen(csp->referrer) <= 9))
646    {
647       /* no referrer was supplied */
648       goto trust_url_not_trusted;
649    }
650
651    /* forge a URL from the referrer so we can use
652     * convert_url() to parse it into its components.
653     */
654
655    p = NULL;
656    p = strsav(p, "GET ");
657    p = strsav(p, csp->referrer + 9);   /* skip over "Referer: " */
658    p = strsav(p, " HTTP/1.0");
659
660    parse_http_request(p, rhttp, csp);
661
662    if (rhttp->cmd == NULL)
663    {
664       freez(p);
665       goto trust_url_not_trusted;
666    }
667
668    freez(p);
669
670    *url = dsplit(rhttp->host);
671
672    /* if splitting the domain fails, punt */
673    if (url->dbuf == NULL) goto trust_url_not_trusted;
674
675    for (tl = csp->config->trust_list; (t = *tl) ; tl++)
676    {
677       if ((t->port == 0) || (t->port == rhttp->port))
678       {
679          if ((t->domain[0] == '\0') || domaincmp(t, url) == 0)
680          {
681             if ((t->path == NULL) ||
682 #ifdef REGEX
683                (regexec(t->preg, rhttp->path, 0, NULL, 0) == 0)
684 #else
685                (strncmp(t->path, rhttp->path, t->pathlen) == 0)
686 #endif
687             )
688             {
689                /* if the URL's referrer is from a trusted referrer, then
690                 * add the target spec to the trustfile as an unblocked
691                 * domain and return NULL (which means it's OK).
692                 */
693
694                FILE *fp;
695
696                freez(url->dbuf);
697                freez(url->dvec);
698
699                if ((fp = fopen(csp->config->trustfile, "a")))
700                {
701                   h = NULL;
702
703                   h = strsav(h, "~");
704                   h = strsav(h, http->hostport);
705
706                   p = http->path;
707                   if ((*p++ == '/')
708                   && (*p++ == '~'))
709                   {
710                   /* since this path points into a user's home space
711                    * be sure to include this spec in the trustfile.
712                    */
713                      if ((p = strchr(p, '/')))
714                      {
715                         *p = '\0';
716                         h = strsav(h, http->path);
717                         h = strsav(h, "/");
718                      }
719                   }
720
721                   free_http_request(rhttp);
722
723                   fprintf(fp, "%s\n", h);
724                   freez(h);
725                   fclose(fp);
726                }
727                return(NULL);
728             }
729          }
730       }
731    }
732
733 trust_url_not_trusted:
734    free_http_request(rhttp);
735
736    hostport = url_encode(http->hostport);
737    path     = url_encode(http->path);
738
739    if (csp->referrer)
740    {
741       refer = url_encode(csp->referrer);
742    }
743    else
744    {
745       refer = url_encode("undefined");
746    }
747
748    n  = strlen(CTRUST);
749    n += strlen(hostport);
750    n += strlen(path);
751    n += strlen(refer);
752
753    p = (char *)malloc(n);
754    sprintf(p, CTRUST, hostport, path, refer);
755
756    freez(hostport);
757    freez(path);
758    freez(refer);
759
760    return(p);
761
762 }
763 #endif /* def TRUST_FILES */
764
765
766 static const char C_HOME_PAGE[] =
767    "HTTP/1.0 200 OK\n"
768    "Pragma: no-cache\n"
769    "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\n"
770    "Content-Type: text/html\n\n"
771    "<html>\n"
772    "<head>\n"
773    "<title>Internet Junkbuster: Information</title>\n"
774    "</head>\n"
775    BODY
776    "<h1><center>"
777    BANNER
778    "</h1></center>\n"
779    "<p><a href=\"" HOME_PAGE_URL "\">JunkBuster web site</a></p>\n"
780    "<p><a href=\"http://i.j.b/show-proxy-arg\">Proxy configuration</a></p>\n"
781    "<p><a href=\"http://i.j.b/show-url-info\">Look up a URL</a></p>\n"
782    "</body>\n"
783    "</html>\n";
784
785
786 /*********************************************************************
787  *
788  * Function    :  intercept_url
789  *
790  * Description :  checks the URL `basename' against a list of URLs to
791  *                snarf. If it matches, it calls the associated function
792  *                which returns an HTML page to send back to the client.
793  *                Right now, we snarf:
794  *                      "show-proxy-args", and
795  *                      "ij-untrusted-url" (optional w/TRUST_FILES)
796  *
797  * Parameters  :
798  *          1  :  http = http_request request, check `basename's of blocklist
799  *          2  :  csp = Current client state (buffers, headers, etc...)
800  *
801  * Returns     :  1 if it intercepts & handles the request.
802  *
803  *********************************************************************/
804 int intercept_url(struct http_request *http, struct client_state *csp)
805 {
806    char *basename = NULL;
807    const struct interceptors *v;
808
809    if (0 == strcmpic(http->host,"i.j.b"))
810    {
811       /*
812        * Catch http://i.j.b/...
813        */
814       basename = http->path;
815    }
816    else if ( ( (0 == strcmpic(http->host,"ijbswa.sourceforge.net"))
817             || (0 == strcmpic(http->host,"ijbswa.sf.net")) )
818             && (0 == strncmpic(http->path,"/config", 7))
819             && ((http->path[7] == '/') || (http->path[7] == '\0')))
820    {
821       /*
822        * Catch http://ijbswa.sourceforge.net/config/...
823        * and   http://ijbswa.sf.net/config/...
824        */
825       basename = http->path + 7;
826    }
827
828    if (!basename)
829    {
830       /* Don't want to intercept */
831       return(0);
832    }
833
834    /* We have intercepted it. */
835
836    /* remove any leading slash */
837    if (*basename == '/')
838    {
839       basename++;
840    }
841
842    log_error(LOG_LEVEL_GPC, "%s%s intercepted!", http->hostport, http->path);
843    log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", 
844                             csp->ip_addr_str, http->cmd); 
845
846    for (v = intercept_patterns; v->str; v++)
847    {
848       if (strncmp(basename, v->str, v->len) == 0)
849       {
850          char * p = ((v->interceptor)(http, csp));
851
852          if (p != NULL)
853          {
854             /* Send HTML redirection result */
855             write_socket(csp->cfd, p, strlen(p));
856
857             freez(p);
858          }
859          return(1);
860       }
861    }
862
863    write_socket(csp->cfd, C_HOME_PAGE, strlen(C_HOME_PAGE));
864
865    return(1);
866 }
867
868 #ifdef FAST_REDIRECTS
869 /*********************************************************************
870  *
871  * Function    :  redirect_url
872  *
873  * Description :  Checks for redirection URLs and returns a HTTP redirect
874  *                to the destination URL.
875  *
876  * Parameters  :
877  *          1  :  http = http_request request, check `basename's of blocklist
878  *          2  :  csp = Current client state (buffers, headers, etc...)
879  *
880  * Returns     :  NULL if URL was clean, HTTP redirect otherwise.
881  *
882  *********************************************************************/
883 char *redirect_url(struct http_request *http, struct client_state *csp)
884 {
885    char *p, *q;
886
887    p = q = csp->http->path;
888    log_error(LOG_LEVEL_REDIRECTS, "checking path: %s", p);
889
890    /* find the last URL encoded in the request */
891    while (p = strstr(p, "http://"))
892    {
893       q = p++;
894    }
895
896    /* if there was any, generate and return a HTTP redirect */
897    if (q != csp->http->path)
898    {
899       log_error(LOG_LEVEL_REDIRECTS, "redirecting to: %s", q);
900
901       p = (char *)malloc(strlen(HTTP_REDIRECT_TEMPLATE) + strlen(q));
902       sprintf(p, HTTP_REDIRECT_TEMPLATE, q);
903       return(p);
904    }
905    else
906    {
907       return(NULL);
908    }
909
910 }
911 #endif /* def FAST_REDIRECTS */
912
913 /*********************************************************************
914  *
915  * Function    :  url_actions
916  *
917  * Description :  Gets the actions for this URL.
918  *
919  * Parameters  :
920  *          1  :  http = http_request request for blocked URLs
921  *          2  :  csp = Current client state (buffers, headers, etc...)
922  *
923  * Returns     :  N/A
924  *
925  *********************************************************************/
926 void url_actions(struct http_request *http, 
927                  struct client_state *csp)
928 {
929    struct file_list *fl;
930    struct url_actions *b;
931
932    init_current_action(csp->action);
933
934    if (((fl = csp->actions_list) == NULL) || ((b = fl->f) == NULL))
935    {
936       return;
937    }
938
939    apply_url_actions(csp->action, http, b);
940 }
941
942
943 /*********************************************************************
944  *
945  * Function    :  apply_url_actions
946  *
947  * Description :  Applies a list of URL actions.
948  *
949  * Parameters  :
950  *          1  :  action = Destination.
951  *          2  :  http = Current URL
952  *          3  :  b = list of URL actions to apply
953  *
954  * Returns     :  N/A
955  *
956  *********************************************************************/
957 void apply_url_actions(struct current_action_spec *action, 
958                        struct http_request *http, 
959                        struct url_actions *b)
960 {
961    struct url_spec url[1];
962
963    if (b == NULL)
964    {
965       /* Should never happen */
966       return;
967    }
968
969    *url = dsplit(http->host);
970
971    /* if splitting the domain fails, punt */
972    if (url->dbuf == NULL)
973    {
974       return;
975    }
976
977    for (b = b->next; NULL != b; b = b->next)
978    {
979       if ((b->url->port == 0) || (b->url->port == http->port))
980       {
981          if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
982          {
983             if ((b->url->path == NULL) ||
984 #ifdef REGEX
985                (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
986 #else
987                (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
988 #endif
989             )
990             {
991                merge_current_action(action, b->action);
992             }
993          }
994       }
995    }
996
997    freez(url->dbuf);
998    freez(url->dvec);
999 }
1000
1001
1002 /*********************************************************************
1003  *
1004  * Function    :  forward_url
1005  *
1006  * Description :  Should we forward this to another proxy?
1007  *
1008  * Parameters  :
1009  *          1  :  http = http_request request for current URL
1010  *          2  :  csp = Current client state (buffers, headers, etc...)
1011  *
1012  * Returns     :  Return gw_default for no forward match,
1013  *                else a gateway pointer to a specific forwarding proxy.
1014  *
1015  *********************************************************************/
1016 const struct gateway *forward_url(struct http_request *http, struct client_state *csp)
1017 {
1018    struct file_list *fl;
1019    struct forward_spec *b;
1020    struct url_spec url[1];
1021
1022    if (((fl = csp->flist) == NULL) || ((b = fl->f) == NULL))
1023    {
1024       return(gw_default);
1025    }
1026
1027    *url = dsplit(http->host);
1028
1029    /* if splitting the domain fails, punt */
1030    if (url->dbuf == NULL) return(gw_default);
1031
1032    for (b = b->next; b ; b = b->next)
1033    {
1034       if ((b->url->port == 0) || (b->url->port == http->port))
1035       {
1036          if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
1037          {
1038             if ((b->url->path == NULL) ||
1039 #ifdef REGEX
1040                (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
1041 #else
1042                (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
1043 #endif
1044             )
1045             {
1046                freez(url->dbuf);
1047                freez(url->dvec);
1048                return(b->gw);
1049             }
1050          }
1051       }
1052    }
1053
1054    freez(url->dbuf);
1055    freez(url->dvec);
1056    return(gw_default);
1057
1058 }
1059
1060
1061 /*********************************************************************
1062  *
1063  * Function    :  dsplit
1064  *
1065  * Description :  Takes a domain and returns a pointer to a url_spec
1066  *                structure populated with dbuf, dcnt and dvec.  The
1067  *                other fields in the structure that is returned are zero.
1068  *
1069  * Parameters  :
1070  *          1  :  domain = a URL address
1071  *
1072  * Returns     :  url_spec structure populated with dbuf, dcnt and dvec.
1073  *
1074  *********************************************************************/
1075 struct url_spec dsplit(char *domain)
1076 {
1077    struct url_spec ret[1];
1078    char *v[BUFSIZ];
1079    int size;
1080    char *p;
1081
1082    memset(ret, '\0', sizeof(*ret));
1083
1084    ret->unanchored = (domain[strlen(domain) - 1] == '.');
1085
1086    ret->dbuf = strdup(domain);
1087
1088    /* map to lower case */
1089    for (p = ret->dbuf; *p ; p++) *p = tolower(*p);
1090
1091    /* split the domain name into components */
1092    ret->dcnt = ssplit(ret->dbuf, ".", v, SZ(v), 1, 1);
1093
1094    if (ret->dcnt <= 0)
1095    {
1096       memset(ret, '\0', sizeof(ret));
1097       return(*ret);
1098    }
1099
1100    /* save a copy of the pointers in dvec */
1101    size = ret->dcnt * sizeof(*ret->dvec);
1102
1103    if ((ret->dvec = (char **)malloc(size)))
1104    {
1105       memcpy(ret->dvec, v, size);
1106    }
1107
1108
1109    return(*ret);
1110
1111 }
1112
1113
1114 /*********************************************************************
1115  *
1116  * Function    :  domaincmp
1117  *
1118  * Description :  Compare domain names.
1119  *                domaincmp("a.b.c",  "a.b.c")  => 0 (MATCH)
1120  *                domaincmp("a*.b.c", "a.b.c")  => 0 (MATCH)
1121  *                domaincmp("a*.b.c", "abc.b.c")  => 0 (MATCH)
1122  *                domaincmp("a*c.b.c","abbc.b.c")  => 0 (MATCH)
1123  *                domaincmp("*a.b.c", "dabc.b.c")  => 0 (MATCH)
1124  *                domaincmp("b.c"   , "a.b.c")  => 0 (MATCH)
1125  *                domaincmp("a.b"   , "a.b.c")  => 1 (DIFF)
1126  *                domaincmp("a.b."  , "a.b.c")  => 0 (MATCH)
1127  *                domaincmp(""      , "a.b.c")  => 0 (MATCH)
1128  *                
1129  * FIXME: I need a definition!
1130  *
1131  * Parameters  :
1132  *          1  :  pattern = a domain that may contain a '*' as a wildcard.
1133  *          2  :  fqdn = domain name against which the patterns are compared.
1134  *
1135  * Returns     :  0 => domains are equivalent, else no match.
1136  *
1137  *********************************************************************/
1138 int domaincmp(struct url_spec *pattern, struct url_spec *fqdn)
1139 {
1140    char **pv, **fv;  /* vectors  */
1141    int    pn,   fn;  /* counters */
1142    char  *p,   *f;   /* chars    */
1143
1144    pv = pattern->dvec;
1145    fv = fqdn->dvec;
1146    fn = pn = 0;
1147
1148    while (fn < fqdn->dcnt && pn < pattern->dcnt)
1149    {
1150       p = pv[pn];
1151       f = fv[fn];
1152
1153       if (trivimatch(p, f))
1154       {
1155          if(pn)
1156          {
1157             return 1;
1158          }
1159       }
1160       else
1161       {
1162          pn++;
1163       }
1164       fn++;
1165    }
1166
1167    return ((pn < pattern->dcnt) || ((fn < fqdn->dcnt) && !pattern->unanchored));
1168
1169    return(0);
1170
1171 }
1172
1173
1174 /* intercept functions */
1175
1176 /*********************************************************************
1177  *
1178  * Function    :  show_proxy_args
1179  *
1180  * Description :  This "crunch"es "http:/any.thing/show-proxy-args" and
1181  *                returns a web page describing the current status of IJB.
1182  *
1183  * Parameters  :
1184  *          1  :  http = ignored
1185  *          2  :  csp = Current client state (buffers, headers, etc...)
1186  *
1187  * Returns     :  A string that contains the current status of IJB.
1188  *
1189  *********************************************************************/
1190 char *show_proxy_args(struct http_request *http, struct client_state *csp)
1191 {
1192    char *s = NULL;
1193
1194 #ifdef SPLIT_PROXY_ARGS
1195    FILE * fp;
1196    char buf[BUFSIZ];
1197    char * p;
1198    const char * filename = NULL;
1199    const char * file_description = NULL;
1200    char * query_string = strrchr(http->path, '?');
1201    char which_file = '\0';
1202
1203
1204    if (query_string != NULL)
1205    {
1206       /* first char past the last '?' (maybe '\0')*/
1207       which_file = query_string[1];
1208    }
1209    switch (which_file)
1210    {
1211    case 'p':
1212       if (csp->actions_list)
1213       {
1214          filename = csp->actions_list->filename;
1215          file_description = "Actions List";
1216       }
1217       break;
1218    case 'f':
1219       if (csp->flist)
1220       {
1221          filename = csp->flist->filename;
1222          file_description = "Forward List";
1223       }
1224       break;
1225
1226 #ifdef ACL_FILES
1227    case 'a':
1228       if (csp->alist)
1229       {
1230          filename = csp->alist->filename;
1231          file_description = "Access Control List";
1232       }
1233       break;
1234 #endif /* def ACL_FILES */
1235
1236 #ifdef PCRS
1237    case 'r':
1238       if (csp->rlist)
1239       {
1240          filename = csp->rlist->filename;
1241          file_description = "RE Filter List";
1242       }
1243       break;
1244 #endif /* def PCRS */
1245
1246 #ifdef TRUST_FILES
1247    case 't':
1248       if (csp->tlist)
1249       {
1250          filename = csp->tlist->filename;
1251          file_description = "Trust List";
1252       }
1253       break;
1254 #endif /* def TRUST_FILES */
1255    }
1256
1257    if (filename)
1258    {
1259       /* Display specified file */
1260       /* FIXME: Add HTTP headers so this isn't cached */
1261       s = strsav(s,
1262          "HTTP/1.0 200 OK\n"
1263          "Server: IJ/" VERSION "\n"
1264          "Content-type: text/html\n"
1265          "Pragma: no-cache\n"
1266          "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1267          "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
1268          "\n"
1269
1270          "<html>"
1271          "<head>"
1272          "<title>Internet Junkbuster Proxy Status - ");
1273       s = strsav(s, file_description);
1274       s = strsav(s, 
1275          "</title>"
1276          "</head>\n"
1277          "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
1278          "<center>\n"
1279          "<h1>" BANNER "\n");
1280       s = strsav(s, file_description);
1281       s = strsav(s, 
1282          "</h1></center>\n"
1283          "<p><a href=\"show-proxy-args\">Back to proxy status</a></p>\n"
1284          "<h2>");
1285       s = strsav(s, file_description);
1286       s = strsav(s,
1287          "</h2>\n"
1288          "Contents of file &quot;<code>");
1289       p = html_encode(filename);
1290       s = strsav(s, p);
1291       freez(p);
1292       s = strsav(s,
1293          "</code>&quot;:<br>\n"
1294          "</p>\n"
1295          "<pre>");
1296       
1297       if ((fp = fopen(filename, "r")) == NULL)
1298       {
1299          s = strsav(s, "</pre><h1>ERROR OPENING FILE!</h1><pre>");
1300       }
1301       else
1302       {
1303          while (fgets(buf, sizeof(buf), fp))
1304          {
1305             p = html_encode(buf);
1306             if (p)
1307             {
1308                s = strsav(s, p);
1309                freez(p);
1310                s = strsav(s, "<br>");
1311             }
1312          }
1313          fclose(fp);
1314       }
1315
1316       s = strsav(s,
1317          "</pre>\n"
1318          "<br>\n"
1319          "<p><a href=\"show-proxy-args\">Back to proxy status</a></p>\n"
1320          "<br>\n"
1321          "<small><small><p>\n"
1322          "The " BANNER " Proxy - \n"
1323          "<a href=\"" HOME_PAGE_URL "\">" HOME_PAGE_URL "</a>\n"
1324          "</small></small>"
1325          "</body></html>\n");
1326       return(s);
1327    }
1328 #endif /* def SPLIT_PROXY_ARGS */
1329    
1330    s = strsav(s, csp->config->proxy_args_header);
1331    s = strsav(s, csp->config->proxy_args_invocation);
1332 #ifdef STATISTICS
1333    s = add_stats(s);
1334 #endif /* def STATISTICS */
1335    s = strsav(s, csp->config->proxy_args_gateways);
1336
1337 #ifdef SPLIT_PROXY_ARGS
1338    s = strsav(s, 
1339       "<h2>The following files are in use:</h2>\n"
1340       "<p>(Click a filename to view it)</p>\n"
1341       "<ul>\n");
1342
1343    if (csp->actions_list)
1344    {
1345       s = strsav(s, "<li>Actions List: <a href=\"show-proxy-args?permit\"><code>");
1346       s = strsav(s, csp->actions_list->filename);
1347       s = strsav(s, "</code></a></li>\n");
1348    }
1349
1350    if (csp->flist)
1351    {
1352       s = strsav(s, "<li>Forward List: <a href=\"show-proxy-args?forward\"><code>");
1353       s = strsav(s, csp->flist->filename);
1354       s = strsav(s, "</code></a></li>\n");
1355    }
1356
1357 #ifdef ACL_FILES
1358    if (csp->alist)
1359    {
1360       s = strsav(s, "<li>Access Control List: <a href=\"show-proxy-args?acl\"><code>");
1361       s = strsav(s, csp->alist->filename);
1362       s = strsav(s, "</code></a></li>\n");
1363    }
1364 #endif /* def ACL_FILES */
1365
1366 #ifdef PCRS
1367    if (csp->rlist)
1368    {
1369       s = strsav(s, "<li>RE Filter List: <a href=\"show-proxy-args?re\"><code>");
1370       s = strsav(s, csp->rlist->filename);
1371       s = strsav(s, "</code></a></li>\n");
1372    }
1373 #endif /* def PCRS */
1374
1375 #ifdef TRUST_FILES
1376    if (csp->tlist)
1377    {
1378       s = strsav(s, "<li>Trust List: <a href=\"show-proxy-args?trust\"><code>");
1379       s = strsav(s, csp->tlist->filename);
1380       s = strsav(s, "</code></a></li>\n");
1381    }
1382 #endif /* def TRUST_FILES */
1383
1384    s = strsav(s, "</ul>");
1385
1386 #else /* ifndef SPLIT_PROXY_ARGS */
1387    if (csp->clist)
1388    {
1389       s = strsav(s, csp->clist->proxy_args);
1390    }
1391
1392    if (csp->flist)
1393    {
1394       s = strsav(s, csp->flist->proxy_args);
1395    }
1396
1397 #ifdef ACL_FILES
1398    if (csp->alist)
1399    {
1400       s = strsav(s, csp->alist->proxy_args);
1401    }
1402 #endif /* def ACL_FILES */
1403
1404 #ifdef PCRS
1405    if (csp->rlist)
1406    {
1407       s = strsav(s, csp->rlist->proxy_args);
1408    }
1409 #endif /* def PCRS */
1410
1411 #ifdef TRUST_FILES
1412    if (csp->tlist)
1413    {
1414       s = strsav(s, csp->tlist->proxy_args);
1415    }
1416 #endif /* def TRUST_FILES */
1417
1418 #endif /* ndef SPLIT_PROXY_ARGS */
1419
1420    s = strsav(s, csp->config->proxy_args_trailer);
1421
1422    return(s);
1423
1424 }
1425
1426
1427 static const char C_URL_INFO_HEADER[] =
1428    "HTTP/1.0 200 OK\n"
1429    "Pragma: no-cache\n"
1430    "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
1431    "Content-Type: text/html\n\n"
1432    "<html>\n"
1433    "<head>\n"
1434    "<title>Internet Junkbuster: URL Info</title>\n"
1435    "</head>\n"
1436    BODY
1437    "<h1><center>"
1438    BANNER
1439    "</h1></center>\n"
1440    "<p>Information for: <a href=\"http://%s\">http://%s</a></p>\n";
1441 static const char C_URL_INFO_FOOTER[] =
1442    "\n</p>\n"
1443    "</body>\n"
1444    "</html>\n";
1445
1446 static const char C_URL_INFO_FORM[] =
1447    "HTTP/1.0 200 OK\n"
1448    "Pragma: no-cache\n"
1449    "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
1450    "Content-Type: text/html\n\n"
1451    "<html>\n"
1452    "<head>\n"
1453    "<title>Internet Junkbuster: URL Info</title>\n"
1454    "</head>\n"
1455    BODY
1456    "<h1><center>"
1457    BANNER
1458    "</h1></center>\n"
1459    "<form method=\"GET\" action=\"http://i.j.b/show-url-info\">\n"
1460    "<p>Please enter a URL, without the leading &quot;http://&quot;:</p>"
1461    "<p><input type=\"text\" name=\"url\" size=\"80\">"
1462    "<input type=\"submit\" value=\"Info\"></p>\n"
1463    "</form>\n"
1464    "</body>\n"
1465    "</html>\n";
1466
1467
1468  /*********************************************************************
1469  *
1470  * Function    :  ijb_show_url_info
1471  *
1472  * Description :  (please fill me in)
1473  *
1474  * Parameters  :
1475  *          1  :  http = http_request request for crunched URL
1476  *          2  :  csp = Current client state (buffers, headers, etc...)
1477  *
1478  * Returns     :  ???FIXME
1479  *
1480  *********************************************************************/
1481 char *ijb_show_url_info(struct http_request *http, struct client_state *csp)
1482 {
1483    char * query_string = strchr(http->path, '?');
1484    char * host = NULL;
1485    
1486    if (query_string != NULL)
1487    {
1488       query_string = url_decode(query_string + 1);
1489       if (strncmpic(query_string, "url=", 4) == 0)
1490       {
1491          host = strdup(query_string + 4);
1492       }
1493       freez(query_string);
1494    }
1495    if (host != NULL)
1496    {
1497       char * result;
1498       char * path;
1499       char * s;
1500       int port = 80;
1501       struct file_list *fl;
1502       struct url_actions *b;
1503       struct url_spec url[1];
1504       struct current_action_spec action[1];
1505
1506       init_current_action(action);
1507
1508       result = (char *)malloc(sizeof(C_URL_INFO_HEADER) + 2 * strlen(host));
1509       sprintf(result, C_URL_INFO_HEADER, host, host);
1510
1511       s = current_action_to_text(action);
1512       result = strsav(result, "<h3>Defaults:</h3>\n<p><b>{");
1513       result = strsav(result, s);
1514       result = strsav(result, " }</b></p>\n<h3>Patterns affecting the URL:</h3>\n<p>\n");
1515       freez(s);
1516
1517       s = strchr(host, '/');
1518       if (s != NULL)
1519       {
1520          path = strdup(s);
1521          *s = '\0';
1522       }
1523       else
1524       {
1525          path = strdup("");
1526       }
1527       s = strchr(host, ':');
1528       if (s != NULL)
1529       {
1530          *s++ = '\0';
1531          port = atoi(s);
1532       }
1533
1534       if (((fl = csp->actions_list) == NULL) || ((b = fl->f) == NULL))
1535       {
1536          freez(host);
1537          freez(path);
1538          result = strsav(result, C_URL_INFO_FOOTER);
1539          return result;
1540       }
1541
1542       *url = dsplit(host);
1543
1544       /* if splitting the domain fails, punt */
1545       if (url->dbuf == NULL)
1546       {
1547          freez(host);
1548          freez(path);
1549          result = strsav(result, C_URL_INFO_FOOTER);
1550          return result;
1551       }
1552
1553       for (b = b->next; NULL != b; b = b->next)
1554       {
1555          if ((b->url->port == 0) || (b->url->port == port))
1556          {
1557             if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
1558             {
1559                if ((b->url->path == NULL) ||
1560 #ifdef REGEX
1561                   (regexec(b->url->preg, path, 0, NULL, 0) == 0)
1562 #else
1563                   (strncmp(b->url->path, path, b->url->pathlen) == 0)
1564 #endif
1565                )
1566                {
1567                   s = actions_to_text(b->action);
1568                   result = strsav(result, "<b>{");
1569                   result = strsav(result, s);
1570                   result = strsav(result, " }</b><br>\n<code>");
1571                   result = strsav(result, b->url->spec);
1572                   result = strsav(result, "</code><br>\n<br>\n");
1573                   freez(s);
1574
1575                   merge_current_action(action, b->action);
1576                }
1577             }
1578          }
1579       }
1580
1581       freez(url->dbuf);
1582       freez(url->dvec);
1583
1584       freez(host);
1585       freez(path);
1586
1587       s = current_action_to_text(action);
1588       result = strsav(result, "</p>\n<h2>Final Results:</h2>\n<p><b>{");
1589       result = strsav(result, s);
1590       result = strsav(result, " }</b><br>\n<br>\n");
1591       freez(s);
1592
1593       free_current_action(action);
1594
1595       result = strsav(result, C_URL_INFO_FOOTER);
1596       return result;
1597    }
1598    else
1599    {
1600       return strdup(C_URL_INFO_FORM);
1601    }
1602 }
1603
1604
1605 /*********************************************************************
1606  *
1607  * Function    :  ijb_send_banner
1608  *
1609  * Description :  This "crunch"es "http://i.j.b/ijb-send-banner and
1610  *                sends the image.
1611  *
1612  * Parameters  :
1613  *          1  :  http = http_request request for crunched URL
1614  *          2  :  csp = Current client state (buffers, headers, etc...)
1615  *
1616  * Returns     :  NULL, indicating that it has already sent the data.
1617  *
1618  *********************************************************************/
1619 char *ijb_send_banner(struct http_request *http, struct client_state *csp)
1620 {
1621    write_socket(csp->cfd, JBGIF, sizeof(JBGIF)-1);
1622    
1623    return(NULL);
1624 }
1625
1626 #ifdef TRUST_FILES
1627 /*********************************************************************
1628  *
1629  * Function    :  ij_untrusted_url
1630  *
1631  * Description :  This "crunch"es "http:/any.thing/ij-untrusted-url" and
1632  *                returns a web page describing why it was untrusted.
1633  *
1634  * Parameters  :
1635  *          1  :  http = http_request request for crunched URL
1636  *          2  :  csp = Current client state (buffers, headers, etc...)
1637  *
1638  * Returns     :  A string that contains why this was untrusted.
1639  *
1640  *********************************************************************/
1641 char *ij_untrusted_url(struct http_request *http, struct client_state *csp)
1642 {
1643    int n;
1644    char *hostport, *path, *refer, *p, *v[9];
1645    char buf[BUFSIZ];
1646    struct url_spec **tl, *t;
1647
1648
1649    static const char format[] =
1650       "HTTP/1.0 200 OK\r\n"
1651       "Pragma: no-cache\n"
1652       "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1653       "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
1654       "Content-Type: text/html\n\n"
1655       "<html>\n"
1656       "<head>\n"
1657       "<title>Internet Junkbuster: Request for untrusted URL</title>\n"
1658       "</head>\n"
1659       BODY
1660       "<center><h1>"
1661       BANNER
1662       "</h1></center>"
1663       "The " BANNER " Proxy "
1664       "<A href=\"" HOME_PAGE_URL "\">"
1665       "(" HOME_PAGE_URL ") </A>"
1666       "intercepted the request for %s%s\n"
1667       "because the URL is not trusted.\n"
1668       "<br><br>\n";
1669
1670    if ((n = ssplit(http->path, "?+", v, SZ(v), 0, 0)) == 4)
1671    {
1672       hostport = url_decode(v[1]);
1673       path     = url_decode(v[2]);
1674       refer    = url_decode(v[3]);
1675    }
1676    else
1677    {
1678       hostport = strdup("undefined_host");
1679       path     = strdup("/undefined_path");
1680       refer    = strdup("undefined");
1681    }
1682
1683    n  = sizeof(format);
1684    n += strlen(hostport);
1685    n += strlen(path    );
1686
1687    if ((p = (char *)malloc(n)))
1688    {
1689       sprintf(p, format, hostport, path);
1690    }
1691
1692    strsav(p, "The referrer in this request was <strong>");
1693    strsav(p, refer);
1694    strsav(p, "</strong><br>\n");
1695
1696    freez(hostport);
1697    freez(path    );
1698    freez(refer   );
1699
1700    p = strsav(p, "<h3>The following referrers are trusted</h3>\n");
1701
1702    for (tl = csp->config->trust_list; (t = *tl) ; tl++)
1703    {
1704       sprintf(buf, "%s<br>\n", t->spec);
1705       p = strsav(p, buf);
1706    }
1707
1708    if (csp->config->trust_info->next)
1709    {
1710       struct list *l;
1711
1712       strcpy(buf,
1713          "<p>"
1714          "You can learn more about what this means "
1715          "and what you may be able to do about it by "
1716          "reading the following documents:<br>\n"
1717          "<ol>\n"
1718       );
1719
1720       p = strsav(p, buf);
1721
1722       for (l = csp->config->trust_info->next; l ; l = l->next)
1723       {
1724          sprintf(buf,
1725             "<li> <a href=%s>%s</a><br>\n",
1726                l->str, l->str);
1727          p = strsav(p, buf);
1728       }
1729
1730       p = strsav(p, "</ol>\n");
1731    }
1732
1733    p = strsav(p, "</body>\n" "</html>\n");
1734
1735    return(p);
1736
1737 }
1738 #endif /* def TRUST_FILES */
1739
1740
1741 #ifdef STATISTICS
1742 /*********************************************************************
1743  *
1744  * Function    :  add_stats
1745  *
1746  * Description :  Statistics function of JB.  Called by `show_proxy_args'.
1747  *
1748  * Parameters  :
1749  *          1  :  s = string that holds the proxy args description page
1750  *
1751  * Returns     :  A pointer to the descriptive status web page.
1752  *
1753  *********************************************************************/
1754 char *add_stats(char *s)
1755 {
1756    /*
1757     * Output details of the number of requests rejected and
1758     * accepted. This is switchable in the junkbuster config.
1759     * Does nothing if this option is not enabled.
1760     */
1761
1762    float perc_rej;   /* Percentage of http requests rejected */
1763    char out_str[81];
1764    int local_urls_read     = urls_read;
1765    int local_urls_rejected = urls_rejected;
1766
1767    /*
1768     * Need to alter the stats not to include the fetch of this
1769     * page.
1770     *
1771     * Can't do following thread safely! doh!
1772     *
1773     * urls_read--;
1774     * urls_rejected--; * This will be incremented subsequently *
1775     */
1776
1777    s = strsav(s,"<h2>Statistics for this " BANNER ":</h2>\n");
1778
1779    if (local_urls_read == 0)
1780    {
1781
1782       s = strsav(s,"No activity so far!\n");
1783
1784    }
1785    else
1786    {
1787
1788       perc_rej = (float)local_urls_rejected * 100.0F /
1789             (float)local_urls_read;
1790
1791       sprintf(out_str,
1792          "%d requests received, %d filtered "
1793          "(%6.2f %%).",
1794          local_urls_read, 
1795          local_urls_rejected, perc_rej);
1796
1797       s = strsav(s,out_str);
1798    }
1799
1800    return(s);
1801 }
1802 #endif /* def STATISTICS */
1803
1804
1805 /*
1806   Local Variables:
1807   tab-width: 3
1808   end:
1809 */