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