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