- Cleaned CRLF's from the sources and related files
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.1.1.1 2001/05/15 13:58:59 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/loaders.c,v $
5  *
6  * Purpose     :  Functions to load and unload the various
7  *                configuration files.  Also contains code to manage
8  *                the list of active loaders, and to automatically 
9  *                unload files that are no longer in use.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
12  *                IJBSWA team.  http://ijbswa.sourceforge.net
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and 
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it 
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: loaders.c,v $
38  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
39  *    Initial import of version 2.9.3 source tree
40  *
41  *
42  *********************************************************************/
43 \f
44
45 #include "config.h"
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <sys/types.h>
50 #include <string.h>
51 #include <malloc.h>
52 #include <errno.h>
53 #include <sys/stat.h>
54 #include <ctype.h>
55
56 #ifndef _WIN32
57 #include <unistd.h>
58 #endif
59
60 #include "project.h"
61 #include "loaders.h"
62 #include "encode.h"
63 #include "filters.h"
64 #include "parsers.h"
65 #include "jcc.h"
66 #include "ssplit.h"
67 #include "miscutil.h"
68 #include "errlog.h"
69 #include "gateway.h"
70
71 #ifndef SPLIT_PROXY_ARGS
72 /* For strsav */
73 #include "showargs.h"
74 #endif /* ndef SPLIT_PROXY_ARGS */
75
76 const char loaders_h_rcs[] = LOADERS_H_VERSION;
77
78 /* Fix a problem with Solaris.  There should be no effect on other
79  * platforms.
80  * Solaris's isspace() is a macro which uses it's argument directly
81  * as an array index.  Therefore we need to make sure that high-bit
82  * characters generate +ve values, and ideally we also want to make
83  * the argument match the declared parameter type of "int".
84  */
85 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
86
87
88 #define NLOADERS 8
89 static int (*loaders[NLOADERS])(struct client_state *);
90
91
92 /*
93  * Currently active files.
94  * These are also entered in the main linked list of files.
95  */
96 static struct file_list *current_blockfile      = NULL;
97 static struct file_list *current_cookiefile     = NULL;
98 static struct file_list *current_forwardfile    = NULL;
99
100 #ifdef ACL_FILES
101 static struct file_list *current_aclfile        = NULL;
102 #endif /* def ACL_FILES */
103
104 #ifdef USE_IMAGE_LIST
105 static struct file_list *current_imagefile      = NULL;
106 #endif /* def USE_IMAGE_LIST */
107
108 #ifdef KILLPOPUPS
109 static struct file_list * current_popupfile     = NULL;
110 #endif /* def KILLPOPUPS */
111
112 #ifdef TRUST_FILES
113 static struct file_list *current_trustfile      = NULL;
114 #endif /* def TRUST_FILES */
115
116 #ifdef PCRS
117 static struct file_list *current_re_filterfile  = NULL;
118 #endif /* def PCRS */
119
120
121 /*********************************************************************
122  *
123  * Function    :  sweep
124  *
125  * Description :  Basically a mark and sweep garbage collector, it is run
126  *                (by the parent thread) every once in a while to reclaim memory.
127  *
128  * It uses a mark and sweep strategy:
129  *   1) mark all files as inactive
130  *
131  *   2) check with each client:
132  *       if it is active,   mark its files as active
133  *       if it is inactive, free its resources
134  *
135  *   3) free the resources of all of the files that
136  *      are still marked as inactive (and are obsolete).
137  *
138  *   N.B. files that are not obsolete don't have an unloader defined.
139  *
140  * Parameters  :  None
141  *
142  * Returns     :  N/A
143  *
144  *********************************************************************/
145 void sweep(void)
146 {
147    struct file_list *fl, *nfl;
148    struct client_state *csp, *ncsp;
149
150    /* clear all of the file's active flags */
151    for ( fl = files->next; NULL != fl; fl = fl->next )
152    {
153       fl->active = 0;
154    }
155
156    for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
157    {
158       if (ncsp->active)
159       {
160          /* mark this client's files as active */
161
162          if (ncsp->blist)     /* block files */
163          {
164             ncsp->blist->active = 1;
165          }
166
167          if (ncsp->clist)     /* cookie files */
168          {
169             ncsp->clist->active = 1;
170          }
171
172          /* FIXME: These were left out of the "10" release.  Should they be here? */
173          if (ncsp->flist)     /* forward files */
174          {
175             ncsp->flist->active = 1;
176          }
177
178 #ifdef ACL_FILES
179          if (ncsp->alist)     /* acl files */
180          {
181             ncsp->alist->active = 1;
182          }
183 #endif /* def ACL_FILES */
184
185 #ifdef USE_IMAGE_LIST
186          if (ncsp->ilist)     /* image files */
187          {
188             ncsp->ilist->active = 1;
189          }
190 #endif /* def USE_IMAGE_LIST */
191
192 #ifdef KILLPOPUPS
193          if (ncsp->plist)     /* killpopup files */
194          {
195             ncsp->plist->active = 1;
196          }
197 #endif /* def KILLPOPUPS */
198
199 #ifdef PCRS
200          if (ncsp->rlist)     /* perl re files */
201          {
202             ncsp->rlist->active = 1;
203          }
204 #endif /* def PCRS */
205
206 #ifdef TRUST_FILES
207          if (ncsp->tlist)     /* trust files */
208          {
209             ncsp->tlist->active = 1;
210          }
211 #endif /* def TRUST_FILES */
212
213       }
214       else
215       {
216          /* this client one is not active, release its resources */
217          csp->next = ncsp->next;
218
219          freez(ncsp->ip_addr_str);
220          freez(ncsp->referrer);
221          freez(ncsp->x_forwarded);
222          freez(ncsp->ip_addr_str);
223          freez(ncsp->iob->buf);
224
225          free_http_request(ncsp->http);
226
227          destroy_list(ncsp->headers);
228          destroy_list(ncsp->cookie_list);
229
230 #ifdef STATISTICS
231          urls_read++;
232          if (ncsp->rejected)
233          {
234             urls_rejected++;
235          }
236 #endif /* def STATISTICS */
237
238          freez(ncsp);
239       }
240    }
241
242    for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
243    {
244       if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
245       {
246          fl->next = nfl->next;
247
248          (nfl->unloader)(nfl->f);
249
250 #ifndef SPLIT_PROXY_ARGS
251          freez(nfl->proxy_args);
252 #endif /* ndef SPLIT_PROXY_ARGS */
253
254          freez(nfl->filename);
255
256          freez(nfl);
257       }
258    }
259
260 }
261
262
263 /*********************************************************************
264  *
265  * Function    :  unload_url
266  *
267  * Description :  Called from the "unloaders".  Freez the url
268  *                structure elements.
269  *
270  * Parameters  :
271  *          1  :  url = pointer to a url_spec structure.
272  *
273  * Returns     :  N/A
274  *
275  *********************************************************************/
276 static void unload_url(struct url_spec *url)
277 {
278    if (url == NULL) return;
279
280    freez(url->spec);
281    freez(url->domain);
282    freez(url->dbuf);
283    freez(url->dvec);
284    freez(url->path);
285 #ifdef REGEX
286    if (url->preg)
287    {
288       regfree(url->preg);
289       freez(url->preg);
290    }
291 #endif
292
293 }
294
295
296 #ifdef ACL_FILES
297 /*********************************************************************
298  *
299  * Function    :  unload_aclfile
300  *
301  * Description :  Unloads an aclfile.
302  *
303  * Parameters  :
304  *          1  :  f = the data structure associated with the aclfile.
305  *
306  * Returns     :  N/A
307  *
308  *********************************************************************/
309 static void unload_aclfile(void *f)
310 {
311    struct access_control_list *b = (struct access_control_list *)f;
312    if (b == NULL) return;
313
314    unload_aclfile(b->next);
315
316    freez(b);
317
318 }
319 #endif /* def ACL_FILES */
320
321 /*********************************************************************
322  *
323  * Function    :  unload_blockfile
324  *
325  * Description :  Unloads a blockfile.
326  *
327  * Parameters  :
328  *          1  :  f = the data structure associated with the blockfile.
329  *
330  * Returns     :  N/A
331  *
332  *********************************************************************/
333 static void unload_blockfile(void *f)
334 {
335    struct block_spec *b = (struct block_spec *)f;
336    if (b == NULL) return;
337
338    unload_blockfile(b->next);
339
340    unload_url(b->url);
341
342    freez(b);
343
344 }
345
346
347 #ifdef USE_IMAGE_LIST
348 /*********************************************************************
349  *
350  * Function    :  unload_imagefile
351  *
352  * Description :  Unloads an imagefile.
353  *
354  * Parameters  :
355  *          1  :  f = the data structure associated with the imagefile.
356  *
357  * Returns     :  N/A
358  *
359  *********************************************************************/
360 static void unload_imagefile(void *f)
361 {
362    struct block_spec *b = (struct block_spec *)f;
363    if (b == NULL) return;
364
365    unload_imagefile(b->next);
366
367    unload_url(b->url);
368
369    freez(b);
370
371 }
372 #endif /* def USE_IMAGE_LIST */
373
374
375 /*********************************************************************
376  *
377  * Function    :  unload_cookiefile
378  *
379  * Description :  Unloads a cookiefile.
380  *
381  * Parameters  :
382  *          1  :  f = the data structure associated with the cookiefile.
383  *
384  * Returns     :  N/A
385  *
386  *********************************************************************/
387 static void unload_cookiefile(void *f)
388 {
389    struct cookie_spec *b = (struct cookie_spec *)f;
390    if (b == NULL) return;
391
392    unload_cookiefile(b->next);
393
394    unload_url(b->url);
395
396    freez(b);
397
398 }
399
400
401 #ifdef TRUST_FILES
402 /*********************************************************************
403  *
404  * Function    :  unload_trustfile
405  *
406  * Description :  Unloads a trustfile.
407  *
408  * Parameters  :
409  *          1  :  f = the data structure associated with the trustfile.
410  *
411  * Returns     :  N/A
412  *
413  *********************************************************************/
414 static void unload_trustfile(void *f)
415 {
416    struct block_spec *b = (struct block_spec *)f;
417    if (b == NULL) return;
418
419    unload_trustfile(b->next);
420
421    unload_url(b->url);
422
423    freez(b);
424
425 }
426 #endif /* def TRUST_FILES */
427
428
429 /*********************************************************************
430  *
431  * Function    :  unload_forwardfile
432  *
433  * Description :  Unloads a forwardfile.
434  *
435  * Parameters  :
436  *          1  :  f = the data structure associated with the forwardfile.
437  *
438  * Returns     :  N/A
439  *
440  *********************************************************************/
441 static void unload_forwardfile(void *f)
442 {
443    struct forward_spec *b = (struct forward_spec *)f;
444    if (b == NULL) return;
445
446    unload_forwardfile(b->next);
447
448    unload_url(b->url);
449
450    freez(b->gw->gateway_host);
451    freez(b->gw->forward_host);
452
453    freez(b);
454
455 }
456
457
458 #ifdef PCRS
459 /*********************************************************************
460  *
461  * Function    :  unload_re_filterfile
462  *
463  * Description :  Unload the re_filter list.
464  *
465  * Parameters  :
466  *          1  :  f = the data structure associated with the filterfile.
467  *
468  * Returns     :  N/A
469  *
470  *********************************************************************/
471 static void unload_re_filterfile(void *f)
472 {
473    pcrs_job *joblist;
474    struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
475
476    if (b == NULL) return;
477
478    destroy_list(b->patterns);
479
480    joblist = b->joblist;
481    while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
482
483    freez(b);
484
485 }
486 #endif /* def PCRS */
487
488
489 #ifdef KILLPOPUPS
490 /*********************************************************************
491  *
492  * Function    :  unload_popupfile
493  *
494  * Description :  Free the lists of blocked, and allowed popup sites.
495  *
496  * Parameters  :
497  *          1  :  csp = Current client state (buffers, headers, etc...)
498  *
499  * Returns     :  N/A
500  *
501  *********************************************************************/
502 static void unload_popupfile(void * b)
503 {
504    struct popup_settings * data = (struct popup_settings *) b;
505    struct popup_blocklist * cur = NULL;
506    struct popup_blocklist * temp= NULL;
507
508    /* Free the blocked list. */
509    cur = data->blocked;
510    while (cur != NULL)
511    {
512       temp = cur->next;
513       freez (cur->host_name);
514       free  (cur);
515       cur  = temp;
516    }
517    data->blocked = NULL;
518
519    /* Free the allowed list. */
520    cur = data->allowed;
521    while (cur != NULL)
522    {
523       temp = cur->next;
524       freez (cur->host_name);
525       free  (cur);
526       cur  = temp;
527    }
528    data->allowed = NULL;
529
530 }
531 #endif /* def KILLPOPUPS */
532
533
534 /*********************************************************************
535  *
536  * Function    :  check_file_changed
537  *
538  * Description :  Helper function to check if a file needs reloading.
539  *                If "current" is still current, return it.  Otherwise
540  *                allocates a new (zeroed) "struct file_list", fills 
541  *                in the disk file name and timestamp, and returns it.
542  *
543  * Parameters  :
544  *          1  :  current = The file_list currently being used - will
545  *                          be checked to see if it is out of date. 
546  *                          May be NULL (which is treated as out of
547  *                          date).
548  *          2  :  filename = Name of file to check.
549  *          3  :  newfl    = New file list. [Output only]
550  *                           This will be set to NULL, OR a struct
551  *                           file_list newly allocated on the
552  *                           heap, with the filename and lastmodified
553  *                           fields filled, standard header giving file
554  *                           name in proxy_args, and all others zeroed.
555  *                           (proxy_args is only filled in if
556  *                           SPLIT_PROXY_ARGS and !suppress_blocklists).
557  *
558  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
559  *                If file changed: 1 and sets newfl != NULL
560  *                On error: 1 and sets newfl == NULL
561  *
562  *********************************************************************/
563 static int check_file_changed(const struct file_list * current,
564                               const char * filename,
565                               struct file_list ** newfl)
566 {
567    struct file_list *fs;
568    struct stat statbuf[1];
569
570    *newfl = NULL;
571
572    if (stat(filename, statbuf) < 0)
573    {
574       /* Error, probably file not found. */
575       return 1;
576    }
577
578    if (current
579        && (current->lastmodified == statbuf->st_mtime)
580        && (0 == strcmp(current->filename, filename)))
581    {
582       return 0;
583    }
584
585    fs = (struct file_list *)zalloc(sizeof(struct file_list));
586
587    if (fs == NULL)
588    {
589       /* Out of memory error */
590       return 1;
591    }
592
593    fs->filename = strdup(filename);
594    fs->lastmodified = statbuf->st_mtime;
595
596    if (fs->filename == NULL)
597    {
598       /* Out of memory error */
599       freez (fs);
600       return 1;
601    }
602
603 #ifndef SPLIT_PROXY_ARGS
604    if (!suppress_blocklists)
605    {
606       char * p = html_encode(filename);
607       if (p)
608       {
609          fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
610          fs->proxy_args = strsav(fs->proxy_args, p);
611          fs->proxy_args = strsav(fs->proxy_args, 
612             "' contains the following patterns</h2>\n");
613          freez(p);
614       }
615       fs->proxy_args = strsav(fs->proxy_args, "<pre>");
616    }
617 #endif /* ndef SPLIT_PROXY_ARGS */
618
619    *newfl = fs;
620    return 1;
621 }
622
623
624 /*********************************************************************
625  *
626  * Function    :  read_config_line
627  *
628  * Description :  Read a single non-empty line from a file and return
629  *                it.  Trims comments, leading and trailing whitespace.
630  *                Also wites the file to fs->proxy_args.
631  *
632  * Parameters  :
633  *          1  :  buf = Buffer to use.
634  *          2  :  buflen = Size of buffer in bytes.
635  *          3  :  fp = File to read from
636  *          4  :  fs = File will be written to fs->proxy_args.  May
637  *                be NULL to disable this feature.
638  *
639  * Returns     :  NULL on EOF or error
640  *                Otherwise, returns buf.
641  *
642  *********************************************************************/
643 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
644 {
645    char *p, *q;
646    char linebuf[BUFSIZ];
647
648    while (fgets(linebuf, sizeof(linebuf), fp))
649    {
650 #ifndef SPLIT_PROXY_ARGS
651       if (fs && !suppress_blocklists)
652       {
653          char *html_line = html_encode(linebuf);
654          if (html_line != NULL)
655          {
656             fs->proxy_args = strsav(fs->proxy_args, html_line);
657             freez(html_line);
658          }
659          fs->proxy_args = strsav(fs->proxy_args, "<br>");
660       }
661 #endif /* ndef SPLIT_PROXY_ARGS */
662
663       /* Trim off newline and any comment */
664       if ((p = strpbrk(linebuf, "\r\n#")) != NULL)
665       {
666          *p = '\0';
667       }
668       
669       /* Trim leading whitespace */
670       p = linebuf;
671       while (*p && ijb_isspace(*p))
672       {
673          *p++;
674       }
675
676       if (*p)
677       {
678          /* There is something other than whitespace on the line. */
679
680          /* Move the data to the start of buf */
681          if (p != linebuf)
682          {
683             /* strcpy that can cope with overlap. */
684             q = linebuf;
685             while ((*q++ = *p++) != '\0')
686             {
687                /* Do nothing */
688             }
689          }
690
691          /* Trim trailing whitespace */
692          p = linebuf + strlen(linebuf) - 1;
693
694          /*
695           * Note: the (p >= retval) below is paranoia, it's not really needed.
696           * When p == retval then ijb_isspace(*p) will be false and we'll drop
697           * out of the loop.
698           */
699          while ((p >= linebuf) && ijb_isspace(*p))
700          {
701             p--;
702          }
703          p[1] = '\0';
704
705          /* More paranoia.  This if statement is always true. */
706          if (*linebuf)
707          {
708             strcpy(buf, linebuf);
709             return buf;
710          }
711       }
712    }
713
714    /* EOF */
715    return NULL;
716 }
717
718
719 #ifdef ACL_FILES
720 /*********************************************************************
721  *
722  * Function    :  load_aclfile
723  *
724  * Description :  Read and parse an aclfile and add to files list.
725  *
726  * Parameters  :
727  *          1  :  csp = Current client state (buffers, headers, etc...)
728  *
729  * Returns     :  0 => Ok, everything else is an error.
730  *
731  *********************************************************************/
732 int load_aclfile(struct client_state *csp)
733 {
734    FILE *fp;
735    char buf[BUFSIZ], *v[3], *p;
736    int i;
737    struct access_control_list *a, *bl;
738    struct file_list *fs;
739
740    if (!check_file_changed(current_aclfile, aclfile, &fs))
741    {
742       /* No need to load */
743       if (csp)
744       {
745          csp->alist = current_aclfile;
746       }
747       return(0);
748    }
749    if (!fs)
750    {
751       goto load_aclfile_error;
752    }
753
754    fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
755    if (bl == NULL)
756    {
757       freez(fs->filename);
758       freez(fs);
759       goto load_aclfile_error;
760    }
761
762    fp = fopen(aclfile, "r");
763
764    if (fp == NULL)
765    {
766       goto load_aclfile_error;
767    }
768
769    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
770    {
771       i = ssplit(buf, " \t", v, SZ(v), 1, 1);
772
773       /* allocate a new node */
774       a = (struct access_control_list *) zalloc(sizeof(*a));
775
776       if (a == NULL)
777       {
778          fclose(fp);
779          freez(fs->f);
780          freez(fs->filename);
781          freez(fs);
782          goto load_aclfile_error;
783       }
784
785       /* add it to the list */
786       a->next  = bl->next;
787       bl->next = a;
788
789       switch (i)
790       {
791          case 3:
792             if (acl_addr(v[2], a->dst) < 0)
793             {
794                goto load_aclfile_error;
795             }
796             /* no break */
797
798          case 2:
799             if (acl_addr(v[1], a->src) < 0)
800             {
801                goto load_aclfile_error;
802             }
803
804             p = v[0];
805             if (strcmpic(p, "permit") == 0)
806             {
807                a->action = ACL_PERMIT;
808                break;
809             }
810
811             if (strcmpic(p, "deny") == 0)
812             {
813                a->action = ACL_DENY;
814                break;
815             }
816             /* no break */
817
818          default:
819             goto load_aclfile_error;
820       }
821    }
822
823    fclose(fp);
824
825 #ifndef SPLIT_PROXY_ARGS
826    if (!suppress_blocklists)
827    {
828       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
829    }
830 #endif /* ndef SPLIT_PROXY_ARGS */
831
832    if (current_aclfile)
833    {
834       current_aclfile->unloader = unload_aclfile;
835    }
836
837    fs->next = files->next;
838    files->next = fs;
839    current_aclfile = fs;
840
841    if (csp)
842    {
843       csp->alist = fs;
844    }
845
846    return(0);
847
848 load_aclfile_error:
849    log_error(LOG_LEVEL_ERROR, "can't load access control list %s: %E", aclfile);
850    return(-1);
851
852 }
853 #endif /* def ACL_FILES */
854
855
856 /*********************************************************************
857  *
858  * Function    :  load_blockfile
859  *
860  * Description :  Read and parse a blockfile and add to files list.
861  *
862  * Parameters  :
863  *          1  :  csp = Current client state (buffers, headers, etc...)
864  *
865  * Returns     :  0 => Ok, everything else is an error.
866  *
867  *********************************************************************/
868 int load_blockfile(struct client_state *csp)
869 {
870    FILE *fp;
871
872    struct block_spec *b, *bl;
873    char  buf[BUFSIZ], *p, *q;
874    int port, reject;
875    struct file_list *fs;
876    struct url_spec url[1];
877
878    if (!check_file_changed(current_blockfile, blockfile, &fs))
879    {
880       /* No need to load */
881       if (csp)
882       {
883          csp->blist = current_blockfile;
884       }
885       return(0);
886    }
887    if (!fs)
888    {
889       goto load_blockfile_error;
890    }
891
892    fs->f = bl = (struct block_spec *) zalloc(sizeof(*bl));
893    if (bl == NULL)
894    {
895       goto load_blockfile_error;
896    }
897
898    if ((fp = fopen(blockfile, "r")) == NULL)
899    {
900       goto load_blockfile_error;
901    }
902
903    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
904    {
905       reject = 1;
906
907       if (*buf == '~')
908       {
909          reject = 0;
910          p = buf;
911          q = p+1;
912          while ((*p++ = *q++))
913          {
914             /* nop */
915          }
916       }
917
918       /* skip lines containing only ~ */
919       if (*buf == '\0')
920       {
921          continue;
922       }
923
924       /* allocate a new node */
925       if (((b = zalloc(sizeof(*b))) == NULL)
926 #ifdef REGEX
927           || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
928 #endif
929       )
930       {
931          fclose(fp);
932          goto load_blockfile_error;
933       }
934
935       /* add it to the list */
936       b->next  = bl->next;
937       bl->next = b;
938
939       /* save a copy of the orignal specification */
940       if ((b->url->spec = strdup(buf)) == NULL)
941       {
942          fclose(fp);
943          goto load_blockfile_error;
944       }
945
946       b->reject = reject;
947
948       if ((p = strchr(buf, '/')))
949       {
950          b->url->path    = strdup(p);
951          b->url->pathlen = strlen(b->url->path);
952          *p = '\0';
953       }
954       else
955       {
956          b->url->path    = NULL;
957          b->url->pathlen = 0;
958       }
959 #ifdef REGEX
960       if (b->url->path)
961       {
962          int errcode;
963          char rebuf[BUFSIZ];
964
965          sprintf(rebuf, "^(%s)", b->url->path);
966
967          errcode = regcomp(b->url->preg, rebuf,
968                (REG_EXTENDED|REG_NOSUB|REG_ICASE));
969
970          if (errcode)
971          {
972             size_t errlen =
973                regerror(errcode,
974                   b->url->preg, buf, sizeof(buf));
975
976             buf[errlen] = '\0';
977
978             log_error(LOG_LEVEL_ERROR, "error compiling %s: %s\n",
979                     b->url->spec, buf);
980             fclose(fp);
981             goto load_blockfile_error;
982          }
983       }
984       else
985       {
986          freez(b->url->preg);
987       }
988 #endif
989       if ((p = strchr(buf, ':')) == NULL)
990       {
991          port = 0;
992       }
993       else
994       {
995          *p++ = '\0';
996          port = atoi(p);
997       }
998
999       b->url->port = port;
1000
1001       if ((b->url->domain = strdup(buf)) == NULL)
1002       {
1003          fclose(fp);
1004          goto load_blockfile_error;
1005       }
1006
1007       /* split domain into components */
1008       *url = dsplit(b->url->domain);
1009       b->url->dbuf = url->dbuf;
1010       b->url->dcnt = url->dcnt;
1011       b->url->dvec = url->dvec;
1012    }
1013
1014    fclose(fp);
1015
1016 #ifndef SPLIT_PROXY_ARGS
1017    if (!suppress_blocklists)
1018    {
1019       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1020    }
1021 #endif /* ndef SPLIT_PROXY_ARGS */
1022
1023    /* the old one is now obsolete */
1024    if (current_blockfile)
1025    {
1026       current_blockfile->unloader = unload_blockfile;
1027    }
1028
1029    fs->next    = files->next;
1030    files->next = fs;
1031    current_blockfile = fs;
1032
1033    if (csp)
1034    {
1035       csp->blist = fs;
1036    }
1037
1038    return(0);
1039
1040 load_blockfile_error:
1041    log_error(LOG_LEVEL_ERROR, "can't load blockfile '%s': %E", blockfile);
1042    return(-1);
1043
1044 }
1045
1046
1047 #ifdef USE_IMAGE_LIST
1048 /*********************************************************************
1049  *
1050  * Function    :  load_imagefile
1051  *
1052  * Description :  Read and parse an imagefile and add to files list.
1053  *
1054  * Parameters  :
1055  *          1  :  csp = Current client state (buffers, headers, etc...)
1056  *
1057  * Returns     :  0 => Ok, everything else is an error.
1058  *
1059  *********************************************************************/
1060 int load_imagefile(struct client_state *csp)
1061 {
1062    FILE *fp;
1063
1064    struct block_spec *b, *bl;
1065    char  buf[BUFSIZ], *p, *q;
1066    int port, reject;
1067    struct file_list *fs;
1068    struct url_spec url[1];
1069
1070    if (!check_file_changed(current_imagefile, imagefile, &fs))
1071    {
1072       /* No need to load */
1073       if (csp)
1074       {
1075          csp->ilist = current_imagefile;
1076       }
1077       return(0);
1078    }
1079    if (!fs)
1080    {
1081       goto load_imagefile_error;
1082    }
1083
1084    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1085    if (bl == NULL)
1086    {
1087       goto load_imagefile_error;
1088    }
1089
1090    if ((fp = fopen(imagefile, "r")) == NULL)
1091    {
1092       goto load_imagefile_error;
1093    }
1094
1095    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1096    {
1097       reject = 1;
1098
1099       if (*buf == '~')
1100       {
1101          reject = 0;
1102          p = buf;
1103          q = p+1;
1104          while ((*p++ = *q++))
1105          {
1106             /* nop */
1107          }
1108       }
1109
1110       /* skip lines containing only ~ */
1111       if (*buf == '\0')
1112       {
1113          continue;
1114       }
1115
1116       /* allocate a new node */
1117       if (((b = zalloc(sizeof(*b))) == NULL)
1118 #ifdef REGEX
1119       || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
1120 #endif
1121       )
1122       {
1123          fclose(fp);
1124          goto load_imagefile_error;
1125       }
1126
1127       /* add it to the list */
1128       b->next  = bl->next;
1129       bl->next = b;
1130
1131       /* save a copy of the orignal specification */
1132       if ((b->url->spec = strdup(buf)) == NULL)
1133       {
1134          fclose(fp);
1135          goto load_imagefile_error;
1136       }
1137
1138       b->reject = reject;
1139
1140       if ((p = strchr(buf, '/')))
1141       {
1142          b->url->path    = strdup(p);
1143          b->url->pathlen = strlen(b->url->path);
1144          *p = '\0';
1145       }
1146       else
1147       {
1148          b->url->path    = NULL;
1149          b->url->pathlen = 0;
1150       }
1151 #ifdef REGEX
1152       if (b->url->path)
1153       {
1154          int errcode;
1155          char rebuf[BUFSIZ];
1156
1157          sprintf(rebuf, "^(%s)", b->url->path);
1158
1159          errcode = regcomp(b->url->preg, rebuf,
1160                (REG_EXTENDED|REG_NOSUB|REG_ICASE));
1161
1162          if (errcode)
1163          {
1164             size_t errlen =
1165                regerror(errcode,
1166                   b->url->preg, buf, sizeof(buf));
1167
1168             buf[errlen] = '\0';
1169
1170             log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
1171                     b->url->spec, buf);
1172             fclose(fp);
1173             goto load_imagefile_error;
1174          }
1175       }
1176       else
1177       {
1178          freez(b->url->preg);
1179       }
1180 #endif
1181       if ((p = strchr(buf, ':')) == NULL)
1182       {
1183          port = 0;
1184       }
1185       else
1186       {
1187          *p++ = '\0';
1188          port = atoi(p);
1189       }
1190
1191       b->url->port = port;
1192
1193       if ((b->url->domain = strdup(buf)) == NULL)
1194       {
1195          fclose(fp);
1196          goto load_imagefile_error;
1197       }
1198
1199       /* split domain into components */
1200       *url = dsplit(b->url->domain);
1201       b->url->dbuf = url->dbuf;
1202       b->url->dcnt = url->dcnt;
1203       b->url->dvec = url->dvec;
1204    }
1205 #ifndef SPLIT_PROXY_ARGS
1206    if (!suppress_blocklists)
1207       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1208 #endif /* ndef SPLIT_PROXY_ARGS */
1209
1210    fclose(fp);
1211
1212 #ifndef SPLIT_PROXY_ARGS
1213    if (!suppress_blocklists)
1214    {
1215       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1216    }
1217 #endif /* ndef SPLIT_PROXY_ARGS */
1218
1219    /* the old one is now obsolete */
1220    if (current_imagefile)
1221    {
1222       current_imagefile->unloader = unload_imagefile;
1223    }
1224
1225    fs->next    = files->next;
1226    files->next = fs;
1227    current_imagefile = fs;
1228
1229    if (csp)
1230    {
1231       csp->ilist = fs;
1232    }
1233
1234    return(0);
1235
1236 load_imagefile_error:
1237    log_error(LOG_LEVEL_ERROR, "can't load imagefile '%s': %E", imagefile);
1238    return(-1);
1239
1240 }
1241 #endif /* def USE_IMAGE_LIST */
1242
1243
1244 /*********************************************************************
1245  *
1246  * Function    :  load_cookiefile
1247  *
1248  * Description :  Read and parse a cookiefile and add to files list.
1249  *
1250  * Parameters  :
1251  *          1  :  csp = Current client state (buffers, headers, etc...)
1252  *
1253  * Returns     :  0 => Ok, everything else is an error.
1254  *
1255  *********************************************************************/
1256 int load_cookiefile(struct client_state *csp)
1257 {
1258    FILE *fp;
1259
1260    struct cookie_spec *b, *bl;
1261    char  buf[BUFSIZ], *p, *q;
1262    int port, user_cookie, server_cookie;
1263    struct file_list *fs;
1264    struct url_spec url[1];
1265
1266    if (!check_file_changed(current_cookiefile, cookiefile, &fs))
1267    {
1268       /* No need to load */
1269       if (csp)
1270       {
1271          csp->clist = current_cookiefile;
1272       }
1273       return(0);
1274    }
1275    if (!fs)
1276    {
1277       goto load_cookie_error;
1278    }
1279
1280    fs->f = bl = (struct cookie_spec   *)zalloc(sizeof(*bl));
1281    if (bl == NULL)
1282    {
1283       goto load_cookie_error;
1284    }
1285
1286    if ((fp = fopen(cookiefile, "r")) == NULL)
1287    {
1288       goto load_cookie_error;
1289    }
1290
1291    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1292    {
1293       p = buf;
1294
1295       switch ((int)*p)
1296       {
1297          case '>':
1298             server_cookie = 0;
1299             user_cookie   = 1;
1300             p++;
1301             break;
1302
1303          case '<':
1304             server_cookie = 1;
1305             user_cookie   = 0;
1306             p++;
1307             break;
1308
1309          case '~':
1310             server_cookie = 0;
1311             user_cookie   = 0;
1312             p++;
1313             break;
1314
1315          default:
1316             server_cookie = 1;
1317             user_cookie   = 1;
1318             break;
1319       }
1320
1321       /*
1322        * Elide any of the "special" chars from the
1323        * front of the pattern
1324        */
1325       q = buf;
1326       if (p > q) while ((*q++ = *p++))
1327       {
1328          /* nop */
1329       }
1330
1331       /* skip lines containing only "special" chars */
1332       if (*buf == '\0')
1333       {
1334          continue;
1335       }
1336
1337       /* allocate a new node */
1338       if (((b = zalloc(sizeof(*b))) == NULL)
1339 #ifdef REGEX
1340       || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
1341 #endif
1342       )
1343       {
1344          fclose(fp);
1345          goto load_cookie_error;
1346       }
1347
1348       /* add it to the list */
1349       b->next  = bl->next;
1350       bl->next = b;
1351
1352       /* save a copy of the orignal specification */
1353       if ((b->url->spec = strdup(buf)) == NULL)
1354       {
1355          fclose(fp);
1356          goto load_cookie_error;
1357       }
1358
1359       b->send_user_cookie     = user_cookie;
1360       b->accept_server_cookie = server_cookie;
1361
1362       if ((p = strchr(buf, '/')))
1363       {
1364          b->url->path    = strdup(p);
1365          b->url->pathlen = strlen(b->url->path);
1366          *p = '\0';
1367       }
1368       else
1369       {
1370          b->url->path    = NULL;
1371          b->url->pathlen = 0;
1372       }
1373 #ifdef REGEX
1374       if (b->url->path)
1375       {
1376          int errcode;
1377          char rebuf[BUFSIZ];
1378
1379          sprintf(rebuf, "^(%s)", b->url->path);
1380
1381          errcode = regcomp(b->url->preg, rebuf,
1382                (REG_EXTENDED|REG_NOSUB|REG_ICASE));
1383          if (errcode)
1384          {
1385             size_t errlen =
1386                regerror(errcode,
1387                   b->url->preg, buf, sizeof(buf));
1388
1389             buf[errlen] = '\0';
1390
1391             log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
1392                     b->url->spec, buf);
1393             fclose(fp);
1394             goto load_cookie_error;
1395          }
1396       }
1397       else
1398       {
1399          freez(b->url->preg);
1400       }
1401 #endif
1402       if ((p = strchr(buf, ':')) == NULL)
1403       {
1404          port = 0;
1405       }
1406       else
1407       {
1408          *p++ = '\0';
1409          port = atoi(p);
1410       }
1411
1412       b->url->port = port;
1413
1414       if ((b->url->domain = strdup(buf)) == NULL)
1415       {
1416          fclose(fp);
1417          goto load_cookie_error;
1418       }
1419
1420       /* split domain into components */
1421
1422       *url = dsplit(b->url->domain);
1423       b->url->dbuf = url->dbuf;
1424       b->url->dcnt = url->dcnt;
1425       b->url->dvec = url->dvec;
1426    }
1427
1428    fclose(fp);
1429
1430 #ifndef SPLIT_PROXY_ARGS
1431    if (!suppress_blocklists)
1432    {
1433       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1434    }
1435 #endif /* ndef SPLIT_PROXY_ARGS */
1436
1437    /* the old one is now obsolete */
1438    if (current_cookiefile)
1439    {
1440       current_cookiefile->unloader = unload_cookiefile;
1441    }
1442
1443    fs->next    = files->next;
1444    files->next = fs;
1445    current_cookiefile = fs;
1446
1447    if (csp)
1448    {
1449       csp->clist = fs;
1450    }
1451
1452    return(0);
1453
1454 load_cookie_error:
1455    log_error(LOG_LEVEL_ERROR, "can't load cookiefile '%s': %E", cookiefile);
1456    return(-1);
1457
1458 }
1459
1460
1461 #ifdef TRUST_FILES
1462 /*********************************************************************
1463  *
1464  * Function    :  load_trustfile
1465  *
1466  * Description :  Read and parse a trustfile and add to files list.
1467  *
1468  * Parameters  :
1469  *          1  :  csp = Current client state (buffers, headers, etc...)
1470  *
1471  * Returns     :  0 => Ok, everything else is an error.
1472  *
1473  *********************************************************************/
1474 int load_trustfile(struct client_state *csp)
1475 {
1476    FILE *fp;
1477
1478    struct block_spec *b, *bl;
1479    struct url_spec **tl;
1480
1481    char  buf[BUFSIZ], *p, *q;
1482    int port, reject, trusted;
1483    struct file_list *fs;
1484    struct url_spec url[1];
1485
1486    if (!check_file_changed(current_trustfile, trustfile, &fs))
1487    {
1488       /* No need to load */
1489       if (csp)
1490       {
1491          csp->tlist = current_trustfile;
1492       }
1493       return(0);
1494    }
1495    if (!fs)
1496    {
1497       goto load_trustfile_error;
1498    }
1499
1500    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1501    if (bl == NULL)
1502    {
1503       goto load_trustfile_error;
1504    }
1505
1506    if ((fp = fopen(trustfile, "r")) == NULL)
1507    {
1508       goto load_trustfile_error;
1509    }
1510
1511    tl = trust_list;
1512
1513    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1514    {
1515       trusted = 0;
1516       reject  = 1;
1517
1518       if (*buf == '+')
1519       {
1520          trusted = 1;
1521          *buf = '~';
1522       }
1523
1524       if (*buf == '~')
1525       {
1526          reject = 0;
1527          p = buf;
1528          q = p+1;
1529          while ((*p++ = *q++))
1530          {
1531             /* nop */
1532          }
1533       }
1534
1535       /* skip blank lines */
1536       if (*buf == '\0')
1537       {
1538          continue;
1539       }
1540
1541       /* allocate a new node */
1542       if (((b = zalloc(sizeof(*b))) == NULL)
1543 #ifdef REGEX
1544       || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
1545 #endif
1546       )
1547       {
1548          fclose(fp);
1549          goto load_trustfile_error;
1550       }
1551
1552       /* add it to the list */
1553       b->next  = bl->next;
1554       bl->next = b;
1555
1556       /* save a copy of the orignal specification */
1557       if ((b->url->spec = strdup(buf)) == NULL)
1558       {
1559          fclose(fp);
1560          goto load_trustfile_error;
1561       }
1562
1563       b->reject = reject;
1564
1565       if ((p = strchr(buf, '/')))
1566       {
1567          b->url->path    = strdup(p);
1568          b->url->pathlen = strlen(b->url->path);
1569          *p = '\0';
1570       }
1571       else
1572       {
1573          b->url->path    = NULL;
1574          b->url->pathlen = 0;
1575       }
1576 #ifdef REGEX
1577       if (b->url->path)
1578       {
1579          int errcode;
1580          char rebuf[BUFSIZ];
1581
1582          sprintf(rebuf, "^(%s)", b->url->path);
1583
1584          errcode = regcomp(b->url->preg, rebuf,
1585                (REG_EXTENDED|REG_NOSUB|REG_ICASE));
1586
1587          if (errcode)
1588          {
1589             size_t errlen =
1590                regerror(errcode,
1591                   b->url->preg, buf, sizeof(buf));
1592
1593             buf[errlen] = '\0';
1594
1595             log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
1596                     b->url->spec, buf);
1597             fclose(fp);
1598             goto load_trustfile_error;
1599          }
1600       }
1601       else
1602       {
1603          freez(b->url->preg);
1604       }
1605 #endif
1606       if ((p = strchr(buf, ':')) == NULL)
1607       {
1608          port = 0;
1609       }
1610       else
1611       {
1612          *p++ = '\0';
1613          port = atoi(p);
1614       }
1615
1616       b->url->port = port;
1617
1618       if ((b->url->domain = strdup(buf)) == NULL)
1619       {
1620          fclose(fp);
1621          goto load_trustfile_error;
1622       }
1623
1624       /* split domain into components */
1625       *url = dsplit(b->url->domain);
1626       b->url->dbuf = url->dbuf;
1627       b->url->dcnt = url->dcnt;
1628       b->url->dvec = url->dvec;
1629
1630       /*
1631        * save a pointer to URL's spec in the list of trusted URL's, too
1632        */
1633       if (trusted)
1634       {
1635          *tl++ = b->url;
1636       }
1637    }
1638
1639    *tl = NULL;
1640
1641    fclose(fp);
1642
1643 #ifndef SPLIT_PROXY_ARGS
1644    if (!suppress_blocklists)
1645    {
1646       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1647    }
1648 #endif /* ndef SPLIT_PROXY_ARGS */
1649
1650    /* the old one is now obsolete */
1651    if (current_trustfile)
1652    {
1653       current_trustfile->unloader = unload_trustfile;
1654    }
1655
1656    fs->next    = files->next;
1657    files->next = fs;
1658    current_trustfile = fs;
1659
1660    if (csp)
1661    {
1662       csp->tlist = fs;
1663    }
1664
1665    return(0);
1666
1667 load_trustfile_error:
1668    log_error(LOG_LEVEL_ERROR, "can't load trustfile '%s': %E", trustfile);
1669    return(-1);
1670
1671 }
1672 #endif /* def TRUST_FILES */
1673
1674
1675 /*********************************************************************
1676  *
1677  * Function    :  load_forwardfile
1678  *
1679  * Description :  Read and parse a forwardfile and add to files list.
1680  *
1681  * Parameters  :
1682  *          1  :  csp = Current client state (buffers, headers, etc...)
1683  *
1684  * Returns     :  0 => Ok, everything else is an error.
1685  *
1686  *********************************************************************/
1687 int load_forwardfile(struct client_state *csp)
1688 {
1689    FILE *fp;
1690
1691    struct forward_spec *b, *bl;
1692    char  buf[BUFSIZ], *p, *q, *tmp;
1693    char  *vec[4];
1694    int port, n, reject;
1695    struct file_list *fs;
1696    const struct gateway *gw;
1697    struct url_spec url[1];
1698
1699    if (!check_file_changed(current_forwardfile, forwardfile, &fs))
1700    {
1701       /* No need to load */
1702       if (csp)
1703       {
1704          csp->flist = current_forwardfile;
1705       }
1706       return(0);
1707    }
1708    if (!fs)
1709    {
1710       goto load_forwardfile_error;
1711    }
1712
1713    fs->f = bl = (struct forward_spec  *)zalloc(sizeof(*bl));
1714
1715    if ((fs == NULL) || (bl == NULL))
1716    {
1717       goto load_forwardfile_error;
1718    }
1719
1720    if ((fp = fopen(forwardfile, "r")) == NULL)
1721    {
1722       goto load_forwardfile_error;
1723    }
1724
1725    tmp = NULL;
1726
1727    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1728    {
1729       freez(tmp);
1730
1731       tmp = strdup(buf);
1732
1733       n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1734
1735       if (n != 4)
1736       {
1737          log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1738          continue;
1739       }
1740
1741       strcpy(buf, vec[0]);
1742
1743       reject = 1;
1744
1745       if (*buf == '~')
1746       {
1747          reject = 0;
1748          p = buf;
1749          q = p+1;
1750          while ((*p++ = *q++))
1751          {
1752             /* nop */
1753          }
1754       }
1755
1756       /* skip lines containing only ~ */
1757       if (*buf == '\0')
1758       {
1759          continue;
1760       }
1761
1762       /* allocate a new node */
1763       if (((b = zalloc(sizeof(*b))) == NULL)
1764 #ifdef REGEX
1765       || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
1766 #endif
1767       )
1768       {
1769          fclose(fp);
1770          goto load_forwardfile_error;
1771       }
1772
1773       /* add it to the list */
1774       b->next  = bl->next;
1775       bl->next = b;
1776
1777       /* save a copy of the orignal specification */
1778       if ((b->url->spec = strdup(buf)) == NULL)
1779       {
1780          fclose(fp);
1781          goto load_forwardfile_error;
1782       }
1783
1784       b->reject = reject;
1785
1786       if ((p = strchr(buf, '/')))
1787       {
1788          b->url->path    = strdup(p);
1789          b->url->pathlen = strlen(b->url->path);
1790          *p = '\0';
1791       }
1792       else
1793       {
1794          b->url->path    = NULL;
1795          b->url->pathlen = 0;
1796       }
1797 #ifdef REGEX
1798       if (b->url->path)
1799       {
1800          int errcode;
1801          char rebuf[BUFSIZ];
1802
1803          sprintf(rebuf, "^(%s)", b->url->path);
1804
1805          errcode = regcomp(b->url->preg, rebuf,
1806                (REG_EXTENDED|REG_NOSUB|REG_ICASE));
1807
1808          if (errcode)
1809          {
1810             size_t errlen = regerror(errcode, b->url->preg, buf, sizeof(buf));
1811
1812             buf[errlen] = '\0';
1813
1814             log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
1815                     b->url->spec, buf);
1816             fclose(fp);
1817             goto load_forwardfile_error;
1818          }
1819       }
1820       else
1821       {
1822          freez(b->url->preg);
1823       }
1824 #endif
1825       if ((p = strchr(buf, ':')) == NULL)
1826       {
1827          port = 0;
1828       }
1829       else
1830       {
1831          *p++ = '\0';
1832          port = atoi(p);
1833       }
1834
1835       b->url->port = port;
1836
1837       if ((b->url->domain = strdup(buf)) == NULL)
1838       {
1839          fclose(fp);
1840          goto load_forwardfile_error;
1841       }
1842
1843       /* split domain into components */
1844       *url = dsplit(b->url->domain);
1845       b->url->dbuf = url->dbuf;
1846       b->url->dcnt = url->dcnt;
1847       b->url->dvec = url->dvec;
1848
1849       /* now parse the gateway specs */
1850
1851       p = vec[2];
1852
1853       for (gw = gateways; gw->name; gw++)
1854       {
1855          if (strcmp(gw->name, p) == 0)
1856          {
1857             break;
1858          }
1859       }
1860
1861       if (gw->name == NULL)
1862       {
1863          goto load_forwardfile_error;
1864       }
1865
1866       /* save this as the gateway type */
1867       *b->gw = *gw;
1868
1869       /* now parse the gateway host[:port] spec */
1870       p = vec[3];
1871
1872       if (strcmp(p, ".") != 0)
1873       {
1874          b->gw->gateway_host = strdup(p);
1875
1876          if ((p = strchr(b->gw->gateway_host, ':')))
1877          {
1878             *p++ = '\0';
1879             b->gw->gateway_port = atoi(p);
1880          }
1881
1882          if (b->gw->gateway_port <= 0)
1883          {
1884             goto load_forwardfile_error;
1885          }
1886       }
1887
1888       /* now parse the forwarding spec */
1889       p = vec[1];
1890
1891       if (strcmp(p, ".") != 0)
1892       {
1893          b->gw->forward_host = strdup(p);
1894
1895          if ((p = strchr(b->gw->forward_host, ':')))
1896          {
1897             *p++ = '\0';
1898             b->gw->forward_port = atoi(p);
1899          }
1900
1901          if (b->gw->forward_port <= 0)
1902          {
1903             b->gw->forward_port = 8000;
1904          }
1905       }
1906    }
1907
1908    freez(tmp);
1909
1910    fclose(fp);
1911
1912 #ifndef SPLIT_PROXY_ARGS
1913    if (!suppress_blocklists)
1914    {
1915       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1916    }
1917 #endif /* ndef SPLIT_PROXY_ARGS */
1918
1919    /* the old one is now obsolete */
1920    if (current_forwardfile)
1921    {
1922       current_forwardfile->unloader = unload_forwardfile;
1923    }
1924
1925    fs->next    = files->next;
1926    files->next = fs;
1927    current_forwardfile = fs;
1928
1929    if (csp)
1930    {
1931       csp->flist = fs;
1932    }
1933
1934    return(0);
1935
1936 load_forwardfile_error:
1937    log_error(LOG_LEVEL_ERROR, "can't load forwardfile '%s': %E", forwardfile);
1938    return(-1);
1939
1940 }
1941
1942
1943 #ifdef PCRS
1944 /*********************************************************************
1945  *
1946  * Function    :  load_re_filterfile
1947  *
1948  * Description :  Load the re_filterfile. Each non-comment, non-empty
1949  *                line is instantly added to the joblist, which is
1950  *                a chained list of pcrs_job structs.
1951  *
1952  * Parameters  :
1953  *          1  :  csp = Current client state (buffers, headers, etc...)
1954  *
1955  * Returns     :  0 => Ok, everything else is an error.
1956  *
1957  *********************************************************************/
1958 int load_re_filterfile(struct client_state *csp)
1959 {
1960    FILE *fp;
1961
1962    struct re_filterfile_spec *bl;
1963    struct file_list *fs;
1964
1965    char  buf[BUFSIZ];
1966    int error;
1967    pcrs_job *dummy;
1968
1969 #ifndef SPLIT_PROXY_ARGS
1970    char *p;
1971 #endif /* ndef SPLIT_PROXY_ARGS */
1972    if (!check_file_changed(current_re_filterfile, re_filterfile, &fs))
1973    {
1974       /* No need to load */
1975       if (csp)
1976       {
1977          csp->rlist = current_re_filterfile;
1978       }
1979       return(0);
1980    }
1981    if (!fs)
1982    {
1983       goto load_re_filterfile_error;
1984    }
1985
1986    fs->f = bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
1987    if (bl == NULL)
1988    {
1989       goto load_re_filterfile_error;
1990    }
1991
1992    /* Open the file or fail */
1993    if ((fp = fopen(re_filterfile, "r")) == NULL)
1994    {
1995       goto load_re_filterfile_error;
1996    }
1997
1998    /* Read line by line */
1999    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
2000    {
2001       enlist( bl->patterns, buf );
2002
2003       /* We have a meaningful line -> make it a job */
2004       if ((dummy = pcrs_make_job(buf, &error)) == NULL)
2005       {
2006          log_error(LOG_LEVEL_REF, 
2007                "Adding re_filter job %s failed with error %d.", buf, error);
2008          continue;
2009       }
2010       else
2011       {
2012          dummy->next = bl->joblist;
2013          bl->joblist = dummy;
2014          log_error(LOG_LEVEL_REF, "Adding re_filter job %s succeeded.", buf);
2015       }
2016    }
2017
2018    fclose(fp);
2019
2020 #ifndef SPLIT_PROXY_ARGS
2021    if (!suppress_blocklists)
2022    {
2023       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
2024    }
2025 #endif /* ndef SPLIT_PROXY_ARGS */
2026
2027    /* the old one is now obsolete */
2028    if ( NULL != current_re_filterfile )
2029    {
2030       current_re_filterfile->unloader = unload_re_filterfile;
2031    }
2032
2033    fs->next    = files->next;
2034    files->next = fs;
2035    current_re_filterfile = fs;
2036
2037    if (csp)
2038    {
2039       csp->rlist = fs;
2040    }
2041
2042    return( 0 );
2043
2044 load_re_filterfile_error:
2045    log_error(LOG_LEVEL_ERROR, "can't load re_filterfile '%s': %E", re_filterfile);
2046    return(-1);
2047
2048 }
2049 #endif /* def PCRS */
2050
2051
2052 #ifdef KILLPOPUPS
2053 /*********************************************************************
2054  *
2055  * Function    :  load_popupfile
2056  *
2057  * Description :  Load, and parse the popup blocklist.
2058  *
2059  * Parameters  :
2060  *          1  :  csp = Current client state (buffers, headers, etc...)
2061  *
2062  * Returns     :  0 => success, else there was an error.
2063  *
2064  *********************************************************************/
2065 int load_popupfile(struct client_state *csp)
2066 {
2067    FILE *fp;
2068    char  buf[BUFSIZ], *p, *q;
2069    struct popup_blocklist *entry = NULL;
2070    struct popup_settings * data;
2071    struct file_list *fs;
2072    p = buf;
2073    q = buf;
2074
2075    if (!check_file_changed(current_popupfile, popupfile, &fs))
2076    {
2077       /* No need to load */
2078       if (csp)
2079       {
2080          csp->plist = current_popupfile;
2081       }
2082       return(0);
2083    }
2084    if (!fs)
2085    {
2086       goto load_popupfile_error;
2087    }
2088
2089    fs->f = data = (struct popup_settings  *)zalloc(sizeof(*data));
2090    if (data == NULL)
2091    {
2092       goto load_popupfile_error;
2093    }
2094
2095    if ((fp = fopen(popupfile, "r")) == NULL)
2096    {
2097       goto load_popupfile_error;
2098    }
2099
2100    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
2101    {
2102       entry = (struct popup_blocklist*)zalloc(sizeof(struct popup_blocklist));
2103       if (!entry)
2104       {
2105          fclose( fp );
2106          goto load_popupfile_error;
2107       }
2108
2109       /* Handle allowed hosts. */
2110       if ( *buf == '~' )
2111       {
2112          /* Rememeber: skip the tilde */
2113          entry->host_name = strdup( buf + 1 );
2114          if (!entry->host_name)
2115          {
2116             fclose( fp );
2117             goto load_popupfile_error;
2118          }
2119
2120          entry->next = data->allowed;
2121          data->allowed = entry;
2122       }
2123       else
2124       {
2125          /* Blocked host */
2126          entry->host_name = strdup( buf );
2127          if (!entry->host_name)
2128          {
2129             fclose( fp );
2130             goto load_popupfile_error;
2131          }
2132
2133          entry->next = data->blocked;
2134          data->blocked = entry;
2135       }
2136    }
2137
2138    fclose( fp );
2139
2140 #ifndef SPLIT_PROXY_ARGS
2141    if (!suppress_blocklists)
2142    {
2143       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
2144    }
2145 #endif /* ndef SPLIT_PROXY_ARGS */
2146
2147    /* the old one is now obsolete */
2148    if ( NULL != current_popupfile )
2149    {
2150       current_popupfile->unloader = unload_popupfile;
2151    }
2152
2153    fs->next    = files->next;
2154    files->next = fs;
2155    current_popupfile = fs;
2156
2157    if (csp)
2158    {
2159       csp->plist = fs;
2160    }
2161
2162    return( 0 );
2163
2164 load_popupfile_error:
2165    log_error(LOG_LEVEL_ERROR, "can't load popupfile '%s': %E", popupfile);
2166    return(-1);
2167
2168 }
2169 #endif /* def KILLPOPUPS */
2170
2171
2172
2173 /*********************************************************************
2174  *
2175  * Function    :  add_loader
2176  *
2177  * Description :  Called from `load_config'.  Called once for each input
2178  *                file found in config.
2179  *
2180  * Parameters  :
2181  *          1  :  loader = pointer to a function that can parse and load
2182  *                the appropriate config file.
2183  *
2184  * Returns     :  N/A
2185  *
2186  *********************************************************************/
2187 void add_loader(int (*loader)(struct client_state *))
2188 {
2189    int i;
2190
2191    for (i=0; i < NLOADERS; i++)
2192    {
2193       if (loaders[i] == NULL)
2194       {
2195          loaders[i] = loader;
2196          break;
2197       }
2198    }
2199
2200 }
2201
2202
2203 /*********************************************************************
2204  *
2205  * Function    :  run_loader
2206  *
2207  * Description :  Called from `load_config' and `listen_loop'.  This
2208  *                function keeps the "csp" current with any file mods
2209  *                since the last loop.  If a file is unchanged, the
2210  *                loader functions do NOT reload the file.
2211  *
2212  * Parameters  :
2213  *          1  :  csp = Current client state (buffers, headers, etc...)
2214  *
2215  * Returns     :  0 => Ok, everything else is an error.
2216  *
2217  *********************************************************************/
2218 int run_loader(struct client_state *csp)
2219 {
2220    int ret = 0;
2221    int i;
2222
2223    for (i=0; i < NLOADERS; i++)
2224    {
2225       if (loaders[i] == NULL)
2226       {
2227          break;
2228       }
2229       ret |= (loaders[i])(csp);
2230    }
2231    return(ret);
2232
2233 }
2234
2235
2236 /*********************************************************************
2237  *
2238  * Function    :  remove_all_loaders
2239  *
2240  * Description :  Remove all loaders from the list.
2241  *
2242  * Parameters  :  N/A
2243  *
2244  * Returns     :  N/A
2245  *
2246  *********************************************************************/
2247 void remove_all_loaders(void)
2248 {
2249    memset( loaders, 0, sizeof( loaders ) );
2250 }
2251
2252
2253 /*
2254   Local Variables:
2255   tab-width: 3
2256   end:
2257 */