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