c1bac6f63b32c497b591fba3699096eb778cb117
[privoxy.git] / cgi.c
1 const char cgi_rcs[] = "$Id: cgi.c,v 1.1 2001/06/03 11:03:48 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
5  *
6  * Purpose     :  Declares functions to intercept request, generate
7  *                html or gif answers, and to compose HTTP resonses.
8  *                
9  *                Functions declared include:
10  * 
11  *
12  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
13  *                IJBSWA team.  http://ijbswa.sourceforge.net
14  *
15  *                Based on the Internet Junkbuster originally written
16  *                by and Copyright (C) 1997 Anonymous Coders and 
17  *                Junkbusters Corporation.  http://www.junkbusters.com
18  *
19  *                This program is free software; you can redistribute it 
20  *                and/or modify it under the terms of the GNU General
21  *                Public License as published by the Free Software
22  *                Foundation; either version 2 of the License, or (at
23  *                your option) any later version.
24  *
25  *                This program is distributed in the hope that it will
26  *                be useful, but WITHOUT ANY WARRANTY; without even the
27  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
28  *                PARTICULAR PURPOSE.  See the GNU General Public
29  *                License for more details.
30  *
31  *                The GNU General Public License should be included with
32  *                this file.  If not, you can view it at
33  *                http://www.gnu.org/copyleft/gpl.html
34  *                or write to the Free Software Foundation, Inc., 59
35  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  *
37  * Revisions   :
38  *    $Log: cgi.c,v $
39  *    Revision 1.1  2001/06/03 11:03:48  oes
40  *    Makefile/in
41  *
42  *    introduced cgi.c
43  *
44  *    actions.c:
45  *
46  *    adapted to new enlist_unique arg format
47  *
48  *    conf loadcfg.c
49  *
50  *    introduced confdir option
51  *
52  *    filters.c filtrers.h
53  *
54  *     extracted-CGI relevant stuff
55  *
56  *    jbsockets.c
57  *
58  *     filled comment
59  *
60  *    jcc.c
61  *
62  *     support for new cgi mechansim
63  *
64  *    list.c list.h
65  *
66  *    functions for new list type: "map"
67  *    extended enlist_unique
68  *
69  *    miscutil.c .h
70  *    introduced bindup()
71  *
72  *    parsers.c parsers.h
73  *
74  *    deleted const struct interceptors
75  *
76  *    pcrs.c
77  *    added FIXME
78  *
79  *    project.h
80  *
81  *    added struct map
82  *    added struct http_response
83  *    changes struct interceptors to struct cgi_dispatcher
84  *    moved HTML stuff to cgi.h
85  *
86  *    re_filterfile:
87  *
88  *    changed
89  *
90  *    showargs.c
91  *    NO TIME LEFT
92  *
93  *
94  *
95  **********************************************************************/
96 \f
97
98 #include "config.h"
99
100 #include <stdio.h>
101 #include <sys/types.h>
102 #include <stdlib.h>
103 #include <ctype.h>
104 #include <string.h>
105
106 #include "project.h"
107 #include "cgi.h"
108 #include "list.h"
109 #include "pcrs.h"
110 #include "encode.h"
111 #include "ssplit.h"
112 #include "jcc.h"
113 #include "filters.h"
114 #include "actions.h"
115 #include "errlog.h"
116 #include "miscutil.h"
117 #include "showargs.h"
118
119
120 const struct cgi_dispatcher cgi_dispatchers[] = {
121    { "show-status", 
122          11, cgi_show_status,  
123          "Show information about the version and configuration" }, 
124 /* { "show-url-info",
125          13, cgi_show_url_info, 
126          "Show which actions apply to a URL and why"  },*/
127    { "send-banner",
128          11, cgi_send_banner, 
129          "HIDE Send the transparent or \"Junkbuster\" gif" },
130 #ifdef TRUST_FILES
131 /* { "untrusted-url",
132          15, ij_untrusted_url,
133               "HIDE Show why a URL was not trusted" }, */
134 #endif /* def TRUST_FILES */
135    { "",
136          0, cgi_default,
137          "HIDE Send a page linking to all unhidden CGIs" },
138    { NULL, 0, NULL, NULL }
139 };
140
141
142 /*********************************************************************
143  * 
144  * Function    :  dispatch_cgi
145  *
146  * Description :  Checks if a request URL has either the magical hostname
147  *                i.j.b or matches HOME_PAGE_URL/config/. If so, it parses
148  *                the (rest of the) path as a cgi name plus query string,
149  *                prepares a map that maps CGI parameter names to their values,
150  *                initializes the http_response struct, and calls the 
151  *                relevant CGI handler function.
152  *
153  * Parameters  :
154  *          1  :  csp = Current client state (buffers, headers, etc...)
155  *
156  * Returns     :  http_response if match, NULL if nonmatch or handler fail
157  *
158  *********************************************************************/
159 struct http_response *cgi_dispatch(struct client_state *csp)
160 {
161    char *argstring = NULL;
162    const struct cgi_dispatcher *d;
163    struct map *param_list;
164    struct http_response *response;
165
166    /*
167     * Should we intercept ?
168     */
169
170    /* Either the host matches CGI_PREFIX_HOST ..*/
171    if (0 == strcmpic(csp->http->host, CGI_PREFIX_HOST))
172    {
173       /* ..then the path will all be for us */
174       argstring = csp->http->path;
175    }
176    /* Or it's the host part of HOME_PAGE_URL ? */
177    else if (   (0 == strcmpic(csp->http->host, *&HOME_PAGE_URL + 7 ))
178             && (0 == strncmpic(csp->http->path,"/config", 7))
179             && ((csp->http->path[7] == '/') || (csp->http->path[7] == '\0')))
180    {
181       /* then it's everything following "/config" */
182       argstring = csp->http->path + 7;
183    }
184    else
185    {
186       return NULL;
187    }
188
189    /* 
190     * We have intercepted it.
191     */
192
193    /* Get mem for response */
194    if (NULL == ( response = zalloc(sizeof(*response))))
195    {
196       return NULL;
197    }
198
199    /* remove any leading slash */
200    if (*argstring == '/')
201    {
202       argstring++;
203    }
204
205    log_error(LOG_LEVEL_GPC, "%s%s cgi call", csp->http->hostport, csp->http->path);
206    log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", 
207                             csp->ip_addr_str, csp->http->cmd); 
208
209    for (d = cgi_dispatchers; d->handler; d++)
210    {
211       if (strncmp(argstring, d->name, d->name_length) == 0)
212       {
213          param_list = parse_cgi(argstring + d->name_length);
214          if ((d->handler)(csp, response, param_list))
215               {
216                  freez(response);
217               }
218
219               free_map(param_list);
220               return(response);
221       }
222    }
223
224    freez(response);
225    return(NULL);
226
227 }
228
229
230 /*********************************************************************
231  *
232  * Function    :  parse_cgi
233  *
234  * Description :  Parse a URL-encoded argument string into name/value
235  *                pairs and store them in a struct map list.
236  *
237  * Parameters  :
238  *          1  :  string = string to be parsed 
239  *
240  * Returns     :  poniter to param list, or NULL if failiure
241  *
242  *********************************************************************/
243 struct map *parse_cgi(char *argstring)
244 {
245    char *tmp, *p;
246    char *vector[BUFSIZ];
247    int pairs, i;
248    struct map *cgi_params = NULL;
249
250    if(*argstring == '?') argstring++;
251    tmp = strdup(argstring);
252
253    pairs = ssplit(tmp, "&", vector, SZ(vector), 1, 1);
254
255    for (i = 0; i < pairs; i++)
256    {
257       if ((NULL != (p = strchr(vector[i], '='))) && (*(p+1) != '\0'))
258       {
259          *p = '\0';
260          cgi_params = map(cgi_params, url_decode(vector[i]), 0, url_decode(++p), 0);
261       }
262    }
263
264    free(tmp);
265    return(cgi_params);
266
267 }
268
269
270 /*********************************************************************
271  *
272  * Function    :  make_http_response
273  *
274  * Description :  Fill in the missing headers in an http response,
275  *                and flatten the headers to an http head.
276  *
277  * Parameters  :
278  *          1  :  rsp = pointer to http_response to be processed
279  *
280  * Returns     :  length of http head, or 0 on failiure
281  *
282  *********************************************************************/
283 int make_http_response(struct http_response *rsp)
284 {
285   char buf[BUFSIZ];
286
287   /* Fill in the HTTP Status */
288   sprintf(buf, "HTTP/1.0 %s", rsp->status ? rsp->status : "200 OK");
289   enlist_first(rsp->headers, buf);
290
291   /* Set the Content-Length */
292   if (rsp->content_length == 0)
293   {
294      rsp->content_length = rsp->body ? strlen(rsp->body) : 0;
295   }
296
297
298   sprintf(buf, "Content-Length: %d", rsp->content_length);
299   enlist(rsp->headers, buf);
300
301   /* Fill in the default headers FIXME: Are these correct? sequence OK? check rfc! */
302   enlist_unique(rsp->headers, "Pragma: no-cache", 7);
303   enlist_unique(rsp->headers, "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT", 14);
304   enlist_unique(rsp->headers, "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT", 8);
305   enlist_unique(rsp->headers, "Content-Type: text/html", 13);
306   enlist(rsp->headers, "");
307   
308
309   /* Write the head */
310   if (NULL == (rsp->head = list_to_text(rsp->headers)))
311   {
312     free_http_response(rsp);
313     return(0);
314   }
315  
316   return(strlen(rsp->head));
317 }
318   
319
320 /*********************************************************************
321  *
322  * Function    :  free_http_response
323  *
324  * Description :  Free the memory occupied by an http_response
325  *                and its depandant structures.
326  *
327  * Parameters  :
328  *          1  :  rsp = pointer to http_response to be freed
329  *
330  * Returns     :  N/A
331  *
332  *********************************************************************/
333 void free_http_response(struct http_response *rsp)
334 {
335    if(rsp)
336    {
337       freez(rsp->status);
338       freez(rsp->head);
339       freez(rsp->body);
340       destroy_list(rsp->headers);
341    }
342 }
343
344
345 /*********************************************************************
346  *
347  * Function    :  fill_template
348  *
349  * Description :  CGI support function that loads a given HTML
350  *                template from the confdir, and fills it in
351  *                by replacing @name@ with value using pcrs,
352  *                for each item in the output map.
353  *
354  * Parameters  :
355  *           1 :  csp = Current client state (buffers, headers, etc...)
356  *           3 :  template = name of the HTML template to be used
357  *           2 :  answers = map with fill in symbol -> name pairs
358  *                FIXME: needs better name!
359  *
360  * Returns     :  char * with filled out form, or NULL if failiure
361  *
362  *********************************************************************/
363 char *fill_template(struct client_state *csp, char *template, struct map *answers)
364 {
365    struct map *m;
366    pcrs_job *job, *joblist = NULL;
367    char buf[BUFSIZ];
368    char *new, *old = NULL;
369    int error, size;
370    FILE *fp;
371
372    /*
373     * Open template file or fail
374     */
375    snprintf(buf, BUFSIZ, "%s/templates/%s", csp->config->confdir, template);
376
377    if(NULL == (fp = fopen(buf, "r")))
378         {
379            log_error(LOG_LEVEL_ERROR, "error loading template %s: %E", buf);
380       return NULL;
381         }
382         
383    /* 
384     * Assemble pcrs joblist from answers map
385     */
386    for (m = answers; m; m = m->next)
387         {
388            int error;
389
390            snprintf(buf, BUFSIZ, "s°@%s@°%s°ig", m->name, m->value);
391
392            if(NULL == (job = pcrs_make_job(buf, &error)))
393                 {
394                   log_error(LOG_LEVEL_ERROR, "Adding template fill job %s failed with error %d",
395                                                 buf, error);
396                   while ( NULL != (joblist = pcrs_free_job(joblist)) ) {};
397                   return NULL;
398                 }
399                 else
400                 {
401                    job->next = joblist;
402                         joblist = job;
403                 }
404         }
405
406    /* 
407     * Read the file, ignoring comments
408     */
409         while (fgets(buf, BUFSIZ, fp))
410         {
411       /* skip lines starting with '#' */
412            if(*buf == '#') continue;
413         
414       old = strsav(old, buf);
415         }
416         fclose(fp);
417
418    /*
419     * Execute the jobs
420     */
421         size = strlen(old) + 1;
422    new = old;
423
424    for (job = joblist; NULL != job; job = job->next)
425    {
426            pcrs_exec_substitution(job, old, size, &new, &size);
427       if (old != buf) free(old);
428       old=new;
429         }
430
431    /*
432     * Free the jobs & return
433     */
434    while ( NULL != (joblist = pcrs_free_job(joblist)) ) {};
435    return(new);
436
437 }
438
439
440 /*********************************************************************
441  *
442  * Function    :  dump_map
443  *
444  * Description :  HTML-dump a map for debugging
445  *
446  * Parameters  :
447  *          1  :  map = map to dump
448  *
449  * Returns     :  string with HTML
450  *
451  *********************************************************************/
452 char *dump_map(struct map *map)
453 {
454    struct map *p = map;
455    char *ret = NULL;
456
457
458    ret = strsav(ret, "<table>\n");
459
460    while (p)
461    {
462       ret = strsav(ret, "<tr><td><b>");
463       ret = strsav(ret, p->name);
464       ret = strsav(ret, "</b></td><td>");
465       ret = strsav(ret, p->value);
466       ret = strsav(ret, "</td></tr>\n");
467       p = p->next;
468    }
469
470    ret = strsav(ret, "</table>\n");
471    return(ret);
472 }
473
474
475 /*********************************************************************
476  *
477  * Function    :  cgi_default
478  *
479  * Description :  CGI function that is called if no action was given
480  *                lists menu of available unhidden CGIs.
481  *               
482  * Parameters  :
483  *           1 :  csp = Current client state (buffers, headers, etc...)
484  *           2 :  rsp = http_response data structure for output
485  *           3 :  parameters = map of cgi parameters
486  *
487  * Returns     :  0
488  *
489  *********************************************************************/
490 int cgi_default(struct client_state *csp, struct http_response *rsp,
491                 struct map *parameters)
492 {
493    char *p, *tmp = NULL;
494    char buf[BUFSIZ];
495    const struct cgi_dispatcher *d;
496         struct map *exports = NULL;
497
498    /* List available unhidden CGI's and export as "other-cgis" */
499    for (d = cgi_dispatchers; d->handler; d++)
500    {
501       if (strncmp(d->description, "HIDE", 4))
502            {
503          snprintf(buf, BUFSIZ, "<li><a href=%s/config/%s>%s</a></li>",
504                                   HOME_PAGE_URL, d->name, d->description);
505          tmp = strsav(tmp, buf);
506       }
507         }
508         exports = map(exports, "other-cgis", 1, tmp, 0);
509
510    /* If there were other parameters, export a dump as "cgi-parameters" */
511    if(parameters)
512         {
513       p = dump_map(parameters);
514            tmp = strsav(tmp, "<p>What made you think this cgi takes options?\n
515                          Anyway, here they are, in case you're interested:</p>\n");
516                 tmp = strsav(tmp, p);
517                 exports = map(exports, "cgi-parameters", 1, tmp, 0);
518       free(p);
519         }
520         else
521         {
522            exports = map(exports, "cgi-parameters", 1, "", 1);
523         }
524
525    rsp->body = fill_template(csp, "default", exports);
526
527    free_map(exports);
528    return(0);
529
530 }
531
532
533 /*********************************************************************
534  *
535  * Function    :  cgi_send_banner
536  *
537  * Description :  CGI function that returns a banner. 
538  *
539  * Parameters  :
540  *           1 :  csp = Current client state (buffers, headers, etc...)
541  *           2 :  rsp = http_response data structure for output
542  *           3 :  parameters = map of cgi parameters
543  *
544  * CGI Parameters :
545  *           type : Selects the type of banner between "trans" and "jb".
546  *                  Defaults to "jb" if absent or != "trans".
547  *
548  * Returns     :  0
549  *
550  *********************************************************************/
551 int cgi_send_banner(struct client_state *csp, struct http_response *rsp,
552                     struct map *parameters)
553 {
554    if(strcmp(lookup(parameters, "type"), "trans"))
555    {
556      rsp->body = bindup(CJBGIF, sizeof(CJBGIF));
557      rsp->content_length = sizeof(CJBGIF);
558    }
559    else
560    {
561      rsp->body = bindup(CBLANKGIF, sizeof(CBLANKGIF));
562      rsp->content_length = sizeof(CBLANKGIF);
563    }   
564
565    enlist(rsp->headers, "Content-Type: image/gif");
566
567    return(0);
568 }
569
570
571 #ifdef FAST_REDIRECTS
572 /*********************************************************************
573  *
574  * Function    :  redirect_url
575  *
576  * Description :  Checks for redirection URLs and returns a HTTP redirect
577  *                to the destination URL.
578  *
579  * Parameters  :
580  *          1  :  http = http_request request, check `basename's of blocklist
581  *          2  :  csp = Current client state (buffers, headers, etc...)
582  *
583  * Returns     :  NULL if URL was clean, HTTP redirect otherwise.
584  *
585  *********************************************************************/
586 char *redirect_url(struct http_request *http, struct client_state *csp)
587 {
588    char *p, *q;
589
590    p = q = csp->http->path;
591    log_error(LOG_LEVEL_REDIRECTS, "checking path: %s", p);
592
593    /* find the last URL encoded in the request */
594    while (p = strstr(p, "http://"))
595    {
596       q = p++;
597    }
598
599    /* if there was any, generate and return a HTTP redirect */
600    if (q != csp->http->path)
601    {
602       log_error(LOG_LEVEL_REDIRECTS, "redirecting to: %s", q);
603
604       p = (char *)malloc(strlen(HTTP_REDIRECT_TEMPLATE) + strlen(q));
605       sprintf(p, HTTP_REDIRECT_TEMPLATE, q);
606       return(p);
607    }
608    else
609    {
610       return(NULL);
611    }
612
613 }
614 #endif /* def FAST_REDIRECTS */
615
616
617
618 /*********************************************************************
619  *
620  * Function    :  cgi_show_status
621  *
622  * Description :  CGI function that returns a a web page describing the
623  *                current status of IJB.
624  *
625  * Parameters  :
626  *           1 :  csp = Current client state (buffers, headers, etc...)
627  *           2 :  rsp = http_response data structure for output
628  *           3 :  parameters = map of cgi parameters
629  *
630  * CGI Parameters :
631  *           type : Selects the type of banner between "trans" and "jb".
632  *                  Defaults to "jb" if absent or != "trans".
633  *
634  * Returns     :  0
635  *
636  *********************************************************************/
637 int cgi_show_status(struct client_state *csp, struct http_response *rsp,
638                     struct map *parameters)
639 {
640    char *s = NULL;
641    const struct gateway *g;
642    int i;
643
644    struct map *exports = NULL;
645
646 #ifdef SPLIT_PROXY_ARGS
647    FILE * fp;
648    char buf[BUFSIZ];
649    char * p;
650    const char * filename = NULL;
651    char * file_description = NULL;
652
653
654    p = lookup(parameters, "file");
655    switch (*p)
656    {
657    case 'p':
658       if (csp->actions_list)
659       {
660          filename = csp->actions_list->filename;
661          file_description = "Actions List";
662       }
663       break;
664    case 'f':
665       if (csp->flist)
666       {
667          filename = csp->flist->filename;
668          file_description = "Forward List";
669       }
670       break;
671
672 #ifdef ACL_FILES
673    case 'a':
674       if (csp->alist)
675       {
676          filename = csp->alist->filename;
677          file_description = "Access Control List";
678       }
679       break;
680 #endif /* def ACL_FILES */
681
682 #ifdef PCRS
683    case 'r':
684       if (csp->rlist)
685       {
686          filename = csp->rlist->filename;
687          file_description = "Regex Filter List";
688       }
689       break;
690 #endif /* def PCRS */
691
692 #ifdef TRUST_FILES
693    case 't':
694       if (csp->tlist)
695       {
696          filename = csp->tlist->filename;
697          file_description = "Trust List";
698       }
699       break;
700 #endif /* def TRUST_FILES */
701    }
702
703    if (NULL != filename)
704    {
705            exports = map(exports, "filename", 1, file_description, 1);
706       exports = map(exports, "filepath", 1, html_encode(filename), 0);
707
708       if ((fp = fopen(filename, "r")) == NULL)
709       {
710          exports = map(exports, "content", 1, "</pre><h1>ERROR OPENING FILE!</h1><pre>", 1);
711       }
712       else
713       {
714          while (fgets(buf, sizeof(buf), fp))
715          {
716             p = html_encode(buf);
717             if (p)
718             {
719                s = strsav(s, p);
720                freez(p);
721                s = strsav(s, "<br>");
722             }
723          }
724          fclose(fp);
725          exports = map(exports, "contents", 1, s, 0);
726      }
727          rsp->body = fill_template(csp, "show-status-file", exports);;
728          free_map(exports);
729          return(0);
730
731    }
732
733 #endif /* def SPLIT_PROXY_ARGS */
734
735    exports = map(exports, "redirect-url", 1, REDIRECT_URL, 1);
736    exports = map(exports, "version", 1, VERSION, 1);
737    exports = map(exports, "home-page", 1, HOME_PAGE_URL, 1);
738    exports = map(exports, "invocation-args", 1, csp->config->proxy_args_header, 1);
739    exports = map(exports, "gateways", 1, csp->config->proxy_args_gateways, 1);
740    exports = map(exports, "gateway-protocols", 1, s, 0);
741
742
743 #ifdef STATISTICS
744    exports = map(exports, "statistics", 1, add_stats(NULL), 0);
745 #else
746    exports = map(exports, "statistics", 1, "", 1);
747 #endif /* ndef STATISTICS */
748
749 #ifdef SPLIT_PROXY_ARGS
750    if (csp->actions_list)
751    {
752       exports = map(exports, "actions-filename", 1,  csp->actions_list->filename, 1);
753         }
754    else
755         {
756            exports = map(exports, "actions-filename", 1, "None specified", 1);
757         }
758
759    if (csp->flist)
760    {
761       exports = map(exports, "forward-filename", 1,  csp->flist->filename, 1);
762         }
763    else
764         {
765            exports = map(exports, "forward-filename", 1, "None specified", 1);
766         }
767
768 #ifdef ACL_FILES
769    if (csp->alist)
770    {
771       exports = map(exports, "acl-filename", 1,  csp->alist->filename, 1);
772         }
773    else
774         {
775            exports = map(exports, "acl-filename", 1, "None specified", 1);
776         }
777 #else
778    exports = map(exports, "acl-killer-start.*acl-killer-end", 1, "", 1);
779 #endif /* ndef ACL_FILES */
780
781 #ifdef PCRS
782    if (csp->rlist)
783    {
784       exports = map(exports, "re-filter-filename", 1,  csp->rlist->filename, 1);
785         }
786    else
787         {
788            exports = map(exports, "re-filter-filename", 1, "None specified", 1);
789         }
790 #else
791    exports = map(exports, "re-filter-killer-start.*re-filter-killer-end", 1, "", 1);
792 #endif /* ndef PCRS */
793
794 #ifdef TRUST_FILES
795    if (csp->tlist)
796    {
797       exports = map(exports, "trust-filename", 1,  csp->tlist->filename, 1);
798         }
799    else
800         {
801            exports = map(exports, "trust-filename", 1, "None specified", 1);
802         }
803 #else
804    exports = map(exports, "acl-killer-start.*acl-killer-end", 1, "", 1);
805 #endif /* ndef TRUST_FILES */
806
807    exports = map(exports, ".list", 1, "" , 1);
808
809 #else /* ifndef SPLIT_PROXY_ARGS */
810    exports = map(exports, "magic-eliminator-start.*magic-eliminator-end", 1, "", 1);
811
812    if (csp->clist)
813    {
814       map(exports, "clist", 1, csp->clist->proxy_args , 1);
815    }
816
817    if (csp->flist)
818    {
819       map(exports, "flist", 1, csp->flist->proxy_args , 1);
820         }
821
822 #ifdef ACL_FILES
823    if (csp->alist)
824    {
825       map(exports, "alist", 1, csp->alist->proxy_args , 1);
826         }
827 #endif /* def ACL_FILES */
828
829 #ifdef PCRS
830    if (csp->rlist)
831    {
832       map(exports, "rlist", 1, csp->rlist->proxy_args , 1);
833         }
834 #endif /* def PCRS */
835
836 #ifdef TRUST_FILES
837     if (csp->tlist)
838    {
839       map(exports, "tlist", 1, csp->tlist->proxy_args , 1);
840         }
841 #endif /* def TRUST_FILES */
842
843 #endif /* ndef SPLIT_PROXY_ARGS */
844
845         s = end_proxy_args(csp->config);
846    exports = map(exports, "rcs-and-defines", 1, s , 0);
847
848
849    rsp->body = fill_template(csp, "show-status", exports);
850    free_map(exports);
851    return(0);
852
853 }
854
855  
856  /*********************************************************************
857  *
858  * Function    :  cgi_show_url_info
859  *
860  * Description :  (please fill me in)
861  *
862  * Parameters  :
863  *          1  :  http = http_request request for crunched URL
864  *          2  :  csp = Current client state (buffers, headers, etc...)
865  *
866  * Returns     :  ???FIXME
867  *
868  *********************************************************************/
869 char *cgi_show_url_info(struct http_request *http, struct client_state *csp)
870 {
871    char * query_string = strchr(http->path, '?');
872    char * host = NULL;
873    
874    if (query_string != NULL)
875    {
876       query_string = url_decode(query_string + 1);
877       if (strncmpic(query_string, "url=", 4) == 0)
878       {
879          host = strdup(query_string + 4);
880       }
881       freez(query_string);
882    }
883    if (host != NULL)
884    {
885       char * result;
886       char * path;
887       char * s;
888       int port = 80;
889       struct file_list *fl;
890       struct url_actions *b;
891       struct url_spec url[1];
892       struct current_action_spec action[1];
893
894       init_current_action(action);
895
896       result = (char *)malloc(sizeof(C_URL_INFO_HEADER) + 2 * strlen(host));
897       sprintf(result, C_URL_INFO_HEADER, host, host);
898
899       s = current_action_to_text(action);
900       result = strsav(result, "<h3>Defaults:</h3>\n<p><b>{");
901       result = strsav(result, s);
902       result = strsav(result, " }</b></p>\n<h3>Patterns affecting the URL:</h3>\n<p>\n");
903       freez(s);
904
905       s = strchr(host, '/');
906       if (s != NULL)
907       {
908          path = strdup(s);
909          *s = '\0';
910       }
911       else
912       {
913          path = strdup("");
914       }
915       s = strchr(host, ':');
916       if (s != NULL)
917       {
918          *s++ = '\0';
919          port = atoi(s);
920       }
921
922       if (((fl = csp->actions_list) == NULL) || ((b = fl->f) == NULL))
923       {
924          freez(host);
925          freez(path);
926          result = strsav(result, C_URL_INFO_FOOTER);
927          return result;
928       }
929
930       *url = dsplit(host);
931
932       /* if splitting the domain fails, punt */
933       if (url->dbuf == NULL)
934       {
935          freez(host);
936          freez(path);
937          result = strsav(result, C_URL_INFO_FOOTER);
938          return result;
939       }
940
941       for (b = b->next; NULL != b; b = b->next)
942       {
943          if ((b->url->port == 0) || (b->url->port == port))
944          {
945             if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
946             {
947                if ((b->url->path == NULL) ||
948 #ifdef REGEX
949                   (regexec(b->url->preg, path, 0, NULL, 0) == 0)
950 #else
951                   (strncmp(b->url->path, path, b->url->pathlen) == 0)
952 #endif
953                )
954                {
955                   s = actions_to_text(b->action);
956                   result = strsav(result, "<b>{");
957                   result = strsav(result, s);
958                   result = strsav(result, " }</b><br>\n<code>");
959                   result = strsav(result, b->url->spec);
960                   result = strsav(result, "</code><br>\n<br>\n");
961                   freez(s);
962
963                   merge_current_action(action, b->action);
964                }
965             }
966          }
967       }
968
969       freez(url->dbuf);
970       freez(url->dvec);
971
972       freez(host);
973       freez(path);
974
975       s = current_action_to_text(action);
976       result = strsav(result, "</p>\n<h2>Final Results:</h2>\n<p><b>{");
977       result = strsav(result, s);
978       result = strsav(result, " }</b><br>\n<br>\n");
979       freez(s);
980
981       free_current_action(action);
982
983       result = strsav(result, C_URL_INFO_FOOTER);
984       return result;
985    }
986    else
987    {
988       return strdup(C_URL_INFO_FORM);
989    }
990 }
991
992
993
994 #ifdef TRUST_FILES
995 /*********************************************************************
996  *
997  * Function    :  ij_untrusted_url
998  *
999  * Description :  This "crunch"es "http:/any.thing/ij-untrusted-url" and
1000  *                returns a web page describing why it was untrusted.
1001  *
1002  * Parameters  :
1003  *          1  :  http = http_request request for crunched URL
1004  *          2  :  csp = Current client state (buffers, headers, etc...)
1005  *
1006  * Returns     :  A string that contains why this was untrusted.
1007  *
1008  *********************************************************************/
1009 char *ij_untrusted_url(struct http_request *http, struct client_state *csp)
1010 {
1011    int n;
1012    char *hostport, *path, *refer, *p, *v[9];
1013    char buf[BUFSIZ];
1014    struct url_spec **tl, *t;
1015
1016
1017    static const char format[] =
1018       "HTTP/1.0 200 OK\r\n"
1019       "Pragma: no-cache\n"
1020       "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1021       "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
1022       "Content-Type: text/html\n\n"
1023       "<html>\n"
1024       "<head>\n"
1025       "<title>Internet Junkbuster: Request for untrusted URL</title>\n"
1026       "</head>\n"
1027       BODY
1028       "<center><h1>"
1029       BANNER
1030       "</h1></center>"
1031       "The " BANNER " Proxy "
1032       "<A href=\"" HOME_PAGE_URL "\">"
1033       "(" HOME_PAGE_URL ") </A>"
1034       "intercepted the request for %s%s\n"
1035       "because the URL is not trusted.\n"
1036       "<br><br>\n";
1037
1038    if ((n = ssplit(http->path, "?+", v, SZ(v), 0, 0)) == 4)
1039    {
1040       hostport = url_decode(v[1]);
1041       path     = url_decode(v[2]);
1042       refer    = url_decode(v[3]);
1043    }
1044    else
1045    {
1046       hostport = strdup("undefined_host");
1047       path     = strdup("/undefined_path");
1048       refer    = strdup("undefined");
1049    }
1050
1051    n  = sizeof(format);
1052    n += strlen(hostport);
1053    n += strlen(path    );
1054
1055    if ((p = (char *)malloc(n)))
1056    {
1057       sprintf(p, format, hostport, path);
1058    }
1059
1060    strsav(p, "The referrer in this request was <strong>");
1061    strsav(p, refer);
1062    strsav(p, "</strong><br>\n");
1063
1064    freez(hostport);
1065    freez(path    );
1066    freez(refer   );
1067
1068    p = strsav(p, "<h3>The following referrers are trusted</h3>\n");
1069
1070    for (tl = csp->config->trust_list; (t = *tl) ; tl++)
1071    {
1072       sprintf(buf, "%s<br>\n", t->spec);
1073       p = strsav(p, buf);
1074    }
1075
1076    if (csp->config->trust_info->next)
1077    {
1078       struct list *l;
1079
1080       strcpy(buf,
1081          "<p>"
1082          "You can learn more about what this means "
1083          "and what you may be able to do about it by "
1084          "reading the following documents:<br>\n"
1085          "<ol>\n"
1086       );
1087
1088       p = strsav(p, buf);
1089
1090       for (l = csp->config->trust_info->next; l ; l = l->next)
1091       {
1092          sprintf(buf,
1093             "<li> <a href=%s>%s</a><br>\n",
1094                l->str, l->str);
1095          p = strsav(p, buf);
1096       }
1097
1098       p = strsav(p, "</ol>\n");
1099    }
1100
1101    p = strsav(p, "</body>\n" "</html>\n");
1102
1103    return(p);
1104
1105 }
1106 #endif /* def TRUST_FILES */
1107
1108
1109 #ifdef STATISTICS
1110 /*********************************************************************
1111  *
1112  * Function    :  add_stats
1113  *
1114  * Description :  Statistics function of JB.  Called by `show_proxy_args'.
1115  *
1116  * Parameters  :
1117  *          1  :  s = string that holds the proxy args description page
1118  *
1119  * Returns     :  A pointer to the descriptive status web page.
1120  *
1121  *********************************************************************/
1122 char *add_stats(char *s)
1123 {
1124    /*
1125     * Output details of the number of requests rejected and
1126     * accepted. This is switchable in the junkbuster config.
1127     * Does nothing if this option is not enabled.
1128     */
1129
1130    float perc_rej;   /* Percentage of http requests rejected */
1131    char out_str[81];
1132    int local_urls_read     = urls_read;
1133    int local_urls_rejected = urls_rejected;
1134
1135    /*
1136     * Need to alter the stats not to include the fetch of this
1137     * page.
1138     *
1139     * Can't do following thread safely! doh!
1140     *
1141     * urls_read--;
1142     * urls_rejected--; * This will be incremented subsequently *
1143     */
1144
1145    s = strsav(s,"<h2>Statistics for this " BANNER ":</h2>\n");
1146
1147    if (local_urls_read == 0)
1148    {
1149
1150       s = strsav(s,"No activity so far!\n");
1151
1152    }
1153    else
1154    {
1155
1156       perc_rej = (float)local_urls_rejected * 100.0F /
1157             (float)local_urls_read;
1158
1159       sprintf(out_str,
1160          "%d requests received, %d filtered "
1161          "(%6.2f %%).",
1162          local_urls_read, 
1163          local_urls_rejected, perc_rej);
1164
1165       s = strsav(s,out_str);
1166    }
1167
1168    return(s);
1169 }
1170 #endif /* def STATISTICS */
1171
1172 /*
1173   Local Variables:
1174   tab-width: 3
1175   end:
1176 */