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