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