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