Add a --fuzz option
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.105 2016/05/25 10:50:55 fabiankeil 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-2014 the
12  *                Privoxy team. http://www.privoxy.org/
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  *********************************************************************/
37
38
39 #include "config.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <sys/types.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <sys/stat.h>
47 #include <ctype.h>
48 #include <assert.h>
49
50 #if !defined(_WIN32) && !defined(__OS2__)
51 #include <unistd.h>
52 #endif
53
54 #include "project.h"
55 #include "list.h"
56 #include "loaders.h"
57 #include "filters.h"
58 #include "parsers.h"
59 #include "jcc.h"
60 #include "miscutil.h"
61 #include "errlog.h"
62 #include "actions.h"
63 #include "urlmatch.h"
64 #include "encode.h"
65
66 const char loaders_h_rcs[] = LOADERS_H_VERSION;
67
68 /*
69  * Currently active files.
70  * These are also entered in the main linked list of files.
71  */
72
73 #ifdef FEATURE_TRUST
74 static struct file_list *current_trustfile      = NULL;
75 #endif /* def FEATURE_TRUST */
76
77 #ifndef FUZZ
78 static int load_one_re_filterfile(struct client_state *csp, int fileid);
79 #endif
80
81 static struct file_list *current_re_filterfile[MAX_AF_FILES]  = {
82    NULL, NULL, NULL, NULL, NULL,
83    NULL, NULL, NULL, NULL, NULL
84 };
85
86
87 /*********************************************************************
88  *
89  * Function    :  sweep
90  *
91  * Description :  Basically a mark and sweep garbage collector, it is run
92  *                (by the parent thread) every once in a while to reclaim memory.
93  *
94  * It uses a mark and sweep strategy:
95  *   1) mark all files as inactive
96  *
97  *   2) check with each client:
98  *       if it is active,   mark its files as active
99  *       if it is inactive, free its resources
100  *
101  *   3) free the resources of all of the files that
102  *      are still marked as inactive (and are obsolete).
103  *
104  *   N.B. files that are not obsolete don't have an unloader defined.
105  *
106  * Parameters  :  None
107  *
108  * Returns     :  The number of threads that are still active.
109  *
110  *********************************************************************/
111 unsigned int sweep(void)
112 {
113    struct file_list *fl, *nfl;
114    struct client_state *csp;
115    struct client_states *last_active, *client_list;
116    int i;
117    unsigned int active_threads = 0;
118
119    /* clear all of the file's active flags */
120    for (fl = files->next; NULL != fl; fl = fl->next)
121    {
122       fl->active = 0;
123    }
124
125    last_active = clients;
126    client_list = clients->next;
127
128    while (NULL != client_list)
129    {
130       csp = &client_list->csp;
131       if (csp->flags & CSP_FLAG_ACTIVE)
132       {
133          /* Mark this client's files as active */
134
135          /*
136           * Always have a configuration file.
137           * (Also note the slightly non-standard extra
138           * indirection here.)
139           */
140          csp->config->config_file_list->active = 1;
141
142          /*
143           * Actions files
144           */
145          for (i = 0; i < MAX_AF_FILES; i++)
146          {
147             if (csp->actions_list[i])
148             {
149                csp->actions_list[i]->active = 1;
150             }
151          }
152
153          /*
154           * Filter files
155           */
156          for (i = 0; i < MAX_AF_FILES; i++)
157          {
158             if (csp->rlist[i])
159             {
160                csp->rlist[i]->active = 1;
161             }
162          }
163
164          /*
165           * Trust file
166           */
167 #ifdef FEATURE_TRUST
168          if (csp->tlist)
169          {
170             csp->tlist->active = 1;
171          }
172 #endif /* def FEATURE_TRUST */
173
174          active_threads++;
175
176          last_active = client_list;
177          client_list = client_list->next;
178       }
179       else
180       /*
181        * This client is not active. Free its resources.
182        */
183       {
184          last_active->next = client_list->next;
185
186          freez(csp->ip_addr_str);
187 #ifdef FEATURE_CLIENT_TAGS
188          freez(csp->client_address);
189 #endif
190          freez(csp->listen_addr_str);
191          freez(csp->client_iob->buf);
192          freez(csp->iob->buf);
193          freez(csp->error_message);
194
195          if (csp->action->flags & ACTION_FORWARD_OVERRIDE &&
196              NULL != csp->fwd)
197          {
198             unload_forward_spec(csp->fwd);
199          }
200          free_http_request(csp->http);
201
202          destroy_list(csp->headers);
203          destroy_list(csp->tags);
204
205          free_current_action(csp->action);
206
207 #ifdef FEATURE_STATISTICS
208          urls_read++;
209          if (csp->flags & CSP_FLAG_REJECTED)
210          {
211             urls_rejected++;
212          }
213 #endif /* def FEATURE_STATISTICS */
214
215          freez(client_list);
216
217          client_list = last_active->next;
218       }
219    }
220
221    nfl = files;
222    fl = files->next;
223
224    while (fl != NULL)
225    {
226       if ((0 == fl->active) && (NULL != fl->unloader))
227       {
228          nfl->next = fl->next;
229
230          (fl->unloader)(fl->f);
231
232          freez(fl->filename);
233          freez(fl);
234
235          fl = nfl->next;
236       }
237       else
238       {
239          nfl = fl;
240          fl = fl->next;
241       }
242    }
243
244    return active_threads;
245
246 }
247
248
249 /*********************************************************************
250  *
251  * Function    :  check_file_changed
252  *
253  * Description :  Helper function to check if a file needs reloading.
254  *                If "current" is still current, return it.  Otherwise
255  *                allocates a new (zeroed) "struct file_list", fills
256  *                in the disk file name and timestamp, and returns it.
257  *
258  * Parameters  :
259  *          1  :  current = The file_list currently being used - will
260  *                          be checked to see if it is out of date.
261  *                          May be NULL (which is treated as out of
262  *                          date).
263  *          2  :  filename = Name of file to check.
264  *          3  :  newfl    = New file list. [Output only]
265  *                           This will be set to NULL, OR a struct
266  *                           file_list newly allocated on the
267  *                           heap, with the filename and lastmodified
268  *                           fields filled, and all others zeroed.
269  *
270  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
271  *                If file changed: 1 and sets newfl != NULL
272  *                On error: 1 and sets newfl == NULL
273  *
274  *********************************************************************/
275 int check_file_changed(const struct file_list * current,
276                        const char * filename,
277                        struct file_list ** newfl)
278 {
279    struct file_list *fs;
280    struct stat statbuf[1];
281
282    *newfl = NULL;
283
284    if (stat(filename, statbuf) < 0)
285    {
286       /* Error, probably file not found. */
287       return 1;
288    }
289
290    if (current
291        && (current->lastmodified == statbuf->st_mtime)
292        && (0 == strcmp(current->filename, filename)))
293    {
294       return 0;
295    }
296
297    fs = zalloc_or_die(sizeof(struct file_list));
298    fs->filename = strdup_or_die(filename);
299    fs->lastmodified = statbuf->st_mtime;
300
301    if (fs->filename == NULL)
302    {
303       /* Out of memory error */
304       freez (fs);
305       return 1;
306    }
307    *newfl = fs;
308    return 1;
309 }
310
311
312 /*********************************************************************
313  *
314  * Function    :  simple_read_line
315  *
316  * Description :  Read a single line from a file and return it.
317  *                This is basically a version of fgets() that malloc()s
318  *                it's own line buffer.  Note that the buffer will
319  *                always be a multiple of BUFFER_SIZE bytes long.
320  *                Therefore if you are going to keep the string for
321  *                an extended period of time, you should probably
322  *                strdup() it and free() the original, to save memory.
323  *
324  *
325  * Parameters  :
326  *          1  :  dest = destination for newly malloc'd pointer to
327  *                line data.  Will be set to NULL on error.
328  *          2  :  fp = File to read from
329  *          3  :  newline = Standard for newlines in the file.
330  *                Will be unchanged if it's value on input is not
331  *                NEWLINE_UNKNOWN.
332  *                On output, may be changed from NEWLINE_UNKNOWN to
333  *                actual convention in file.
334  *
335  * Returns     :  JB_ERR_OK     on success
336  *                JB_ERR_MEMORY on out-of-memory
337  *                JB_ERR_FILE   on EOF.
338  *
339  *********************************************************************/
340 jb_err simple_read_line(FILE *fp, char **dest, int *newline)
341 {
342    size_t len = 0;
343    size_t buflen = BUFFER_SIZE;
344    char * buf;
345    char * p;
346    int ch;
347    int realnewline = NEWLINE_UNKNOWN;
348
349    if (NULL == (buf = malloc(buflen)))
350    {
351       return JB_ERR_MEMORY;
352    }
353
354    p = buf;
355
356 /*
357  * Character codes.  If you have a weird compiler and the following are
358  * incorrect, you also need to fix NEWLINE() in loaders.h
359  */
360 #define CHAR_CR '\r' /* ASCII 13 */
361 #define CHAR_LF '\n' /* ASCII 10 */
362
363    for (;;)
364    {
365       ch = getc(fp);
366
367       if (ch == EOF)
368       {
369          if (len > 0)
370          {
371             *p = '\0';
372             *dest = buf;
373             return JB_ERR_OK;
374          }
375          else
376          {
377             free(buf);
378             *dest = NULL;
379             return JB_ERR_FILE;
380          }
381       }
382       else if (ch == CHAR_CR)
383       {
384          ch = getc(fp);
385          if (ch == CHAR_LF)
386          {
387             if (*newline == NEWLINE_UNKNOWN)
388             {
389                *newline = NEWLINE_DOS;
390             }
391          }
392          else
393          {
394             if (ch != EOF)
395             {
396                ungetc(ch, fp);
397             }
398             if (*newline == NEWLINE_UNKNOWN)
399             {
400                *newline = NEWLINE_MAC;
401             }
402          }
403          *p = '\0';
404          *dest = buf;
405          if (*newline == NEWLINE_UNKNOWN)
406          {
407             *newline = realnewline;
408          }
409          return JB_ERR_OK;
410       }
411       else if (ch == CHAR_LF)
412       {
413          *p = '\0';
414          *dest = buf;
415          if (*newline == NEWLINE_UNKNOWN)
416          {
417             *newline = NEWLINE_UNIX;
418          }
419          return JB_ERR_OK;
420       }
421       else if (ch == 0)
422       {
423          /* XXX: Why do we allow this anyway? */
424          *p = '\0';
425          *dest = buf;
426          return JB_ERR_OK;
427       }
428
429       *p++ = (char)ch;
430
431       if (++len >= buflen)
432       {
433          buflen += BUFFER_SIZE;
434          if (NULL == (p = realloc(buf, buflen)))
435          {
436             free(buf);
437             return JB_ERR_MEMORY;
438          }
439          buf = p;
440          p = buf + len;
441       }
442    }
443 }
444
445
446 /*********************************************************************
447  *
448  * Function    :  edit_read_line
449  *
450  * Description :  Read a single non-empty line from a file and return
451  *                it.  Trims comments, leading and trailing whitespace
452  *                and respects escaping of newline and comment char.
453  *                Provides the line in 2 alternative forms: raw and
454  *                preprocessed.
455  *                - raw is the raw data read from the file.  If the
456  *                  line is not modified, then this should be written
457  *                  to the new file.
458  *                - prefix is any comments and blank lines that were
459  *                  read from the file.  If the line is modified, then
460  *                  this should be written out to the file followed
461  *                  by the modified data.  (If this string is non-empty
462  *                  then it will have a newline at the end).
463  *                - data is the actual data that will be parsed
464  *                  further by appropriate routines.
465  *                On EOF, the 3 strings will all be set to NULL and
466  *                0 will be returned.
467  *
468  * Parameters  :
469  *          1  :  fp = File to read from
470  *          2  :  raw_out = destination for newly malloc'd pointer to
471  *                raw line data.  May be NULL if you don't want it.
472  *          3  :  prefix_out = destination for newly malloc'd pointer to
473  *                comments.  May be NULL if you don't want it.
474  *          4  :  data_out = destination for newly malloc'd pointer to
475  *                line data with comments and leading/trailing spaces
476  *                removed, and line continuation performed.  May be
477  *                NULL if you don't want it.
478  *          5  :  newline = Standard for newlines in the file.
479  *                On input, set to value to use or NEWLINE_UNKNOWN.
480  *                On output, may be changed from NEWLINE_UNKNOWN to
481  *                actual convention in file.  May be NULL if you
482  *                don't want it.
483  *          6  :  line_number = Line number in file.  In "lines" as
484  *                reported by a text editor, not lines containing data.
485  *
486  * Returns     :  JB_ERR_OK     on success
487  *                JB_ERR_MEMORY on out-of-memory
488  *                JB_ERR_FILE   on EOF.
489  *
490  *********************************************************************/
491 jb_err edit_read_line(FILE *fp,
492                       char **raw_out,
493                       char **prefix_out,
494                       char **data_out,
495                       int *newline,
496                       unsigned long *line_number)
497 {
498    char *p;          /* Temporary pointer   */
499    char *linebuf;    /* Line read from file */
500    char *linestart;  /* Start of linebuf, usually first non-whitespace char */
501    int contflag = 0; /* Nonzero for line continuation - i.e. line ends '\' */
502    int is_empty = 1; /* Flag if not got any data yet */
503    char *raw    = NULL; /* String to be stored in raw_out    */
504    char *prefix = NULL; /* String to be stored in prefix_out */
505    char *data   = NULL; /* String to be stored in data_out   */
506    int scrapnewline;    /* Used for (*newline) if newline==NULL */
507    jb_err rval = JB_ERR_OK;
508
509    assert(fp);
510    assert(raw_out || data_out);
511    assert(newline == NULL
512        || *newline == NEWLINE_UNKNOWN
513        || *newline == NEWLINE_UNIX
514        || *newline == NEWLINE_DOS
515        || *newline == NEWLINE_MAC);
516
517    if (newline == NULL)
518    {
519       scrapnewline = NEWLINE_UNKNOWN;
520       newline = &scrapnewline;
521    }
522
523    /* Set output parameters to NULL */
524    if (raw_out)
525    {
526       *raw_out    = NULL;
527    }
528    if (prefix_out)
529    {
530       *prefix_out = NULL;
531    }
532    if (data_out)
533    {
534       *data_out   = NULL;
535    }
536
537    /* Set string variables to new, empty strings. */
538
539    if (raw_out)
540    {
541       raw = strdup_or_die("");
542    }
543    if (prefix_out)
544    {
545       prefix = strdup_or_die("");
546    }
547    if (data_out)
548    {
549       data = strdup_or_die("");
550    }
551
552    /* Main loop.  Loop while we need more data & it's not EOF. */
553
554    while ((contflag || is_empty)
555        && (JB_ERR_OK == (rval = simple_read_line(fp, &linebuf, newline))))
556    {
557       if (line_number)
558       {
559          (*line_number)++;
560       }
561       if (raw)
562       {
563          string_append(&raw,linebuf);
564          if (string_append(&raw,NEWLINE(*newline)))
565          {
566             freez(prefix);
567             freez(data);
568             free(linebuf);
569             return JB_ERR_MEMORY;
570          }
571       }
572
573       /* Line continuation? Trim escape and set flag. */
574       p = linebuf + strlen(linebuf) - 1;
575       contflag = ((*linebuf != '\0') && (*p == '\\'));
576       if (contflag)
577       {
578          *p = '\0';
579       }
580
581       /* Trim leading spaces if we're at the start of the line */
582       linestart = linebuf;
583       assert(NULL != data);
584       if (*data == '\0')
585       {
586          /* Trim leading spaces */
587          while (*linestart && isspace((int)(unsigned char)*linestart))
588          {
589             linestart++;
590          }
591       }
592
593       /* Handle comment characters. */
594       p = linestart;
595       while ((p = strchr(p, '#')) != NULL)
596       {
597          /* Found a comment char.. */
598          if ((p != linebuf) && (*(p-1) == '\\'))
599          {
600             /* ..and it's escaped, left-shift the line over the escape. */
601             char *q = p - 1;
602             while ((*q = *(q + 1)) != '\0')
603             {
604                q++;
605             }
606             /* Now scan from just after the "#". */
607          }
608          else
609          {
610             /* Real comment.  Save it... */
611             if (p == linestart)
612             {
613                /* Special case:  Line only contains a comment, so all the
614                 * previous whitespace is considered part of the comment.
615                 * Undo the whitespace skipping, if any.
616                 */
617                linestart = linebuf;
618                p = linestart;
619             }
620             if (prefix)
621             {
622                string_append(&prefix,p);
623                if (string_append(&prefix, NEWLINE(*newline)))
624                {
625                   freez(raw);
626                   freez(data);
627                   free(linebuf);
628                   return JB_ERR_MEMORY;
629                }
630             }
631
632             /* ... and chop off the rest of the line */
633             *p = '\0';
634          }
635       } /* END while (there's a # character) */
636
637       /* Write to the buffer */
638       if (*linestart)
639       {
640          is_empty = 0;
641          if (string_append(&data, linestart))
642          {
643             freez(raw);
644             freez(prefix);
645             free(linebuf);
646             return JB_ERR_MEMORY;
647          }
648       }
649
650       free(linebuf);
651    } /* END while(we need more data) */
652
653    /* Handle simple_read_line() errors - ignore EOF */
654    if ((rval != JB_ERR_OK) && (rval != JB_ERR_FILE))
655    {
656       freez(raw);
657       freez(prefix);
658       freez(data);
659       return rval;
660    }
661
662    if (raw ? (*raw == '\0') : is_empty)
663    {
664       /* EOF and no data there.  (Definition of "data" depends on whether
665        * the caller cares about "raw" or just "data").
666        */
667
668       freez(raw);
669       freez(prefix);
670       freez(data);
671
672       return JB_ERR_FILE;
673    }
674    else
675    {
676       /* Got at least some data */
677
678       /* Remove trailing whitespace */
679       chomp(data);
680
681       if (raw_out)
682       {
683          *raw_out    = raw;
684       }
685       else
686       {
687          freez(raw);
688       }
689       if (prefix_out)
690       {
691          *prefix_out = prefix;
692       }
693       else
694       {
695          freez(prefix);
696       }
697       if (data_out)
698       {
699          *data_out   = data;
700       }
701       else
702       {
703          freez(data);
704       }
705       return JB_ERR_OK;
706    }
707 }
708
709
710 /*********************************************************************
711  *
712  * Function    :  read_config_line
713  *
714  * Description :  Read a single non-empty line from a file and return
715  *                it.  Trims comments, leading and trailing whitespace
716  *                and respects escaping of newline and comment char.
717  *
718  * Parameters  :
719  *          1  :  fp = File to read from
720  *          2  :  linenum = linenumber in file
721  *          3  :  buf = Pointer to a pointer to set to the data buffer.
722  *
723  * Returns     :  NULL on EOF or error
724  *                Otherwise, returns buf.
725  *
726  *********************************************************************/
727 char *read_config_line(FILE *fp, unsigned long *linenum, char **buf)
728 {
729    jb_err err;
730    err = edit_read_line(fp, NULL, NULL, buf, NULL, linenum);
731    if (err)
732    {
733       if (err == JB_ERR_MEMORY)
734       {
735          log_error(LOG_LEVEL_FATAL, "Out of memory loading a config file");
736       }
737       *buf = NULL;
738    }
739    return *buf;
740 }
741
742
743 #ifdef FEATURE_TRUST
744 /*********************************************************************
745  *
746  * Function    :  unload_trustfile
747  *
748  * Description :  Unloads a trustfile.
749  *
750  * Parameters  :
751  *          1  :  f = the data structure associated with the trustfile.
752  *
753  * Returns     :  N/A
754  *
755  *********************************************************************/
756 static void unload_trustfile(void *f)
757 {
758    struct block_spec *cur = (struct block_spec *)f;
759    struct block_spec *next;
760
761    while (cur != NULL)
762    {
763       next = cur->next;
764
765       free_pattern_spec(cur->url);
766       free(cur);
767
768       cur = next;
769    }
770
771 }
772
773
774 #ifdef FEATURE_GRACEFUL_TERMINATION
775 /*********************************************************************
776  *
777  * Function    :  unload_current_trust_file
778  *
779  * Description :  Unloads current trust file - reset to state at
780  *                beginning of program.
781  *
782  * Parameters  :  None
783  *
784  * Returns     :  N/A
785  *
786  *********************************************************************/
787 void unload_current_trust_file(void)
788 {
789    if (current_trustfile)
790    {
791       current_trustfile->unloader = unload_trustfile;
792       current_trustfile = NULL;
793    }
794 }
795 #endif /* FEATURE_GRACEFUL_TERMINATION */
796
797
798 /*********************************************************************
799  *
800  * Function    :  load_trustfile
801  *
802  * Description :  Read and parse a trustfile and add to files list.
803  *
804  * Parameters  :
805  *          1  :  csp = Current client state (buffers, headers, etc...)
806  *
807  * Returns     :  0 => Ok, everything else is an error.
808  *
809  *********************************************************************/
810 int load_trustfile(struct client_state *csp)
811 {
812    FILE *fp;
813
814    struct block_spec *b, *bl;
815    struct pattern_spec **tl;
816
817    char *buf = NULL;
818    int reject, trusted;
819    struct file_list *fs;
820    unsigned long linenum = 0;
821    int trusted_referrers = 0;
822
823    if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
824    {
825       /* No need to load */
826       csp->tlist = current_trustfile;
827       return(0);
828    }
829    if (!fs)
830    {
831       goto load_trustfile_error;
832    }
833
834    fs->f = bl = zalloc_or_die(sizeof(*bl));
835
836    if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
837    {
838       goto load_trustfile_error;
839    }
840    log_error(LOG_LEVEL_INFO, "Loading trust file: %s", csp->config->trustfile);
841
842    tl = csp->config->trust_list;
843
844    while (read_config_line(fp, &linenum, &buf) != NULL)
845    {
846       trusted = 0;
847       reject  = 1;
848
849       if (*buf == '+')
850       {
851          trusted = 1;
852          *buf = '~';
853       }
854
855       if (*buf == '~')
856       {
857          char *p;
858          char *q;
859
860          reject = 0;
861          p = buf;
862          q = p+1;
863          while ((*p++ = *q++) != '\0')
864          {
865             /* nop */
866          }
867       }
868
869       /* skip blank lines */
870       if (*buf == '\0')
871       {
872          freez(buf);
873          continue;
874       }
875
876       /* allocate a new node */
877       b = zalloc_or_die(sizeof(*b));
878
879       /* add it to the list */
880       b->next  = bl->next;
881       bl->next = b;
882
883       b->reject = reject;
884
885       /* Save the URL pattern */
886       if (create_pattern_spec(b->url, buf))
887       {
888          fclose(fp);
889          goto load_trustfile_error;
890       }
891
892       /*
893        * save a pointer to URL's spec in the list of trusted URL's, too
894        */
895       if (trusted)
896       {
897          if (++trusted_referrers < MAX_TRUSTED_REFERRERS)
898          {
899             *tl++ = b->url;
900          }
901       }
902       freez(buf);
903    }
904
905    if (trusted_referrers >= MAX_TRUSTED_REFERRERS)
906    {
907       /*
908        * FIXME: ... after Privoxy 3.0.4 is out.
909        */
910        log_error(LOG_LEVEL_ERROR, "Too many trusted referrers. Current limit is %d, you are using %d.\n"
911           "  Additional trusted referrers are treated like ordinary trusted URLs.\n"
912           "  (You can increase this limit by changing MAX_TRUSTED_REFERRERS in project.h and recompiling).",
913           MAX_TRUSTED_REFERRERS, trusted_referrers);
914    }
915
916    *tl = NULL;
917
918    fclose(fp);
919
920    /* the old one is now obsolete */
921    if (current_trustfile)
922    {
923       current_trustfile->unloader = unload_trustfile;
924    }
925
926    fs->next    = files->next;
927    files->next = fs;
928    current_trustfile = fs;
929    csp->tlist = fs;
930
931    return(0);
932
933 load_trustfile_error:
934    log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
935       csp->config->trustfile);
936    freez(buf);
937    return(-1);
938
939 }
940 #endif /* def FEATURE_TRUST */
941
942
943 /*********************************************************************
944  *
945  * Function    :  unload_re_filterfile
946  *
947  * Description :  Unload the re_filter list by freeing all chained
948  *                re_filterfile specs and their data.
949  *
950  * Parameters  :
951  *          1  :  f = the data structure associated with the filterfile.
952  *
953  * Returns     :  N/A
954  *
955  *********************************************************************/
956 static void unload_re_filterfile(void *f)
957 {
958    struct re_filterfile_spec *a, *b = (struct re_filterfile_spec *)f;
959
960    while (b != NULL)
961    {
962       a = b->next;
963
964       destroy_list(b->patterns);
965       pcrs_free_joblist(b->joblist);
966       freez(b->name);
967       freez(b->description);
968       freez(b);
969
970       b = a;
971    }
972
973    return;
974 }
975
976 /*********************************************************************
977  *
978  * Function    :  unload_forward_spec
979  *
980  * Description :  Unload the forward spec settings by freeing all
981  *                memory referenced by members and the memory for
982  *                the spec itself.
983  *
984  * Parameters  :
985  *          1  :  fwd = the forward spec.
986  *
987  * Returns     :  N/A
988  *
989  *********************************************************************/
990 void unload_forward_spec(struct forward_spec *fwd)
991 {
992    free_pattern_spec(fwd->url);
993    freez(fwd->gateway_host);
994    freez(fwd->forward_host);
995    free(fwd);
996
997    return;
998 }
999
1000
1001 #ifdef FEATURE_GRACEFUL_TERMINATION
1002 /*********************************************************************
1003  *
1004  * Function    :  unload_current_re_filterfile
1005  *
1006  * Description :  Unloads current re_filter file - reset to state at
1007  *                beginning of program.
1008  *
1009  * Parameters  :  None
1010  *
1011  * Returns     :  N/A
1012  *
1013  *********************************************************************/
1014 void unload_current_re_filterfile(void)
1015 {
1016    int i;
1017
1018    for (i = 0; i < MAX_AF_FILES; i++)
1019    {
1020       if (current_re_filterfile[i])
1021       {
1022          current_re_filterfile[i]->unloader = unload_re_filterfile;
1023          current_re_filterfile[i] = NULL;
1024       }
1025    }
1026 }
1027 #endif
1028
1029
1030 /*********************************************************************
1031  *
1032  * Function    :  load_re_filterfiles
1033  *
1034  * Description :  Loads all the filterfiles.
1035  *                Generate a chained list of re_filterfile_spec's from
1036  *                the "FILTER: " blocks, compiling all their substitutions
1037  *                into chained lists of pcrs_job structs.
1038  *
1039  * Parameters  :
1040  *          1  :  csp = Current client state (buffers, headers, etc...)
1041  *
1042  * Returns     :  0 => Ok, everything else is an error.
1043  *
1044  *********************************************************************/
1045 int load_re_filterfiles(struct client_state *csp)
1046 {
1047    int i;
1048    int result;
1049
1050    for (i = 0; i < MAX_AF_FILES; i++)
1051    {
1052       if (csp->config->re_filterfile[i])
1053       {
1054          result = load_one_re_filterfile(csp, i);
1055          if (result)
1056          {
1057             return result;
1058          }
1059       }
1060       else if (current_re_filterfile[i])
1061       {
1062          current_re_filterfile[i]->unloader = unload_re_filterfile;
1063          current_re_filterfile[i] = NULL;
1064       }
1065    }
1066
1067    return 0;
1068 }
1069
1070
1071 /*********************************************************************
1072  *
1073  * Function    :  load_one_re_filterfile
1074  *
1075  * Description :  Load a re_filterfile.
1076  *                Generate a chained list of re_filterfile_spec's from
1077  *                the "FILTER: " blocks, compiling all their substitutions
1078  *                into chained lists of pcrs_job structs.
1079  *
1080  * Parameters  :
1081  *          1  :  csp = Current client state (buffers, headers, etc...)
1082  *
1083  * Returns     :  0 => Ok, everything else is an error.
1084  *
1085  *********************************************************************/
1086 int load_one_re_filterfile(struct client_state *csp, int fileid)
1087 {
1088    FILE *fp;
1089
1090    struct re_filterfile_spec *new_bl, *bl = NULL;
1091    struct file_list *fs;
1092
1093    char *buf = NULL;
1094    int error;
1095    unsigned long linenum = 0;
1096    pcrs_job *dummy, *lastjob = NULL;
1097
1098    /*
1099     * No need to reload if unchanged
1100     */
1101    if (!check_file_changed(current_re_filterfile[fileid], csp->config->re_filterfile[fileid], &fs))
1102    {
1103       csp->rlist[fileid] = current_re_filterfile[fileid];
1104       return(0);
1105    }
1106    if (!fs)
1107    {
1108       goto load_re_filterfile_error;
1109    }
1110
1111    /*
1112     * Open the file or fail
1113     */
1114    if ((fp = fopen(csp->config->re_filterfile[fileid], "r")) == NULL)
1115    {
1116       goto load_re_filterfile_error;
1117    }
1118
1119    log_error(LOG_LEVEL_INFO, "Loading filter file: %s", csp->config->re_filterfile[fileid]);
1120
1121    /*
1122     * Read line by line
1123     */
1124    while (read_config_line(fp, &linenum, &buf) != NULL)
1125    {
1126       enum filter_type new_filter = FT_INVALID_FILTER;
1127
1128       if (strncmp(buf, "FILTER:", 7) == 0)
1129       {
1130          new_filter = FT_CONTENT_FILTER;
1131       }
1132       else if (strncmp(buf, "SERVER-HEADER-FILTER:", 21) == 0)
1133       {
1134          new_filter = FT_SERVER_HEADER_FILTER;
1135       }
1136       else if (strncmp(buf, "CLIENT-HEADER-FILTER:", 21) == 0)
1137       {
1138          new_filter = FT_CLIENT_HEADER_FILTER;
1139       }
1140       else if (strncmp(buf, "CLIENT-HEADER-TAGGER:", 21) == 0)
1141       {
1142          new_filter = FT_CLIENT_HEADER_TAGGER;
1143       }
1144       else if (strncmp(buf, "SERVER-HEADER-TAGGER:", 21) == 0)
1145       {
1146          new_filter = FT_SERVER_HEADER_TAGGER;
1147       }
1148 #ifdef FEATURE_EXTERNAL_FILTERS
1149       else if (strncmp(buf, "EXTERNAL-FILTER:", 16) == 0)
1150       {
1151          new_filter = FT_EXTERNAL_CONTENT_FILTER;
1152       }
1153 #endif
1154
1155       /*
1156        * If this is the head of a new filter block, make it a
1157        * re_filterfile spec of its own and chain it to the list:
1158        */
1159       if (new_filter != FT_INVALID_FILTER)
1160       {
1161          new_bl = zalloc_or_die(sizeof(*bl));
1162          if (new_filter == FT_CONTENT_FILTER)
1163          {
1164             new_bl->name = chomp(buf + 7);
1165          }
1166 #ifdef FEATURE_EXTERNAL_FILTERS
1167          else if (new_filter == FT_EXTERNAL_CONTENT_FILTER)
1168          {
1169             new_bl->name = chomp(buf + 16);
1170          }
1171 #endif
1172          else
1173          {
1174             new_bl->name = chomp(buf + 21);
1175          }
1176          new_bl->type = new_filter;
1177
1178          /*
1179           * If a filter description is available,
1180           * encode it to HTML and save it.
1181           */
1182          if (NULL != (new_bl->description = strpbrk(new_bl->name, " \t")))
1183          {
1184             *new_bl->description++ = '\0';
1185             new_bl->description = html_encode(chomp(new_bl->description));
1186             if (NULL == new_bl->description)
1187             {
1188                new_bl->description = strdup_or_die("Out of memory while "
1189                   "encoding filter description to HTML");
1190             }
1191          }
1192          else
1193          {
1194             new_bl->description = strdup_or_die("No description available");
1195          }
1196
1197          new_bl->name = strdup_or_die(chomp(new_bl->name));
1198
1199          /*
1200           * If this is the first filter block, chain it
1201           * to the file_list rather than its (nonexistant)
1202           * predecessor
1203           */
1204          if (fs->f == NULL)
1205          {
1206             fs->f = new_bl;
1207          }
1208          else
1209          {
1210             assert(NULL != bl);
1211             bl->next = new_bl;
1212          }
1213          bl = new_bl;
1214
1215          log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description);
1216
1217          freez(buf);
1218          continue;
1219       }
1220
1221 #ifdef FEATURE_EXTERNAL_FILTERS
1222       if ((bl != NULL) && (bl->type == FT_EXTERNAL_CONTENT_FILTER))
1223       {
1224          /* Save the code as "pattern", but do not compile anything. */
1225          if (bl->patterns->first != NULL)
1226          {
1227             log_error(LOG_LEVEL_FATAL, "External filter '%s' contains several jobss. "
1228                "Did you forget to escape a line break?",
1229                bl->name);
1230          }
1231          error = enlist(bl->patterns, buf);
1232          if (JB_ERR_MEMORY == error)
1233          {
1234             log_error(LOG_LEVEL_FATAL,
1235                "Out of memory while enlisting external filter code \'%s\' for filter %s.",
1236                buf, bl->name);
1237          }
1238          freez(buf);
1239          continue;
1240       }
1241 #endif
1242       if (bl != NULL)
1243       {
1244          /*
1245           * Save the expression, make it a pcrs_job
1246           * and chain it into the current filter's joblist
1247           */
1248          error = enlist(bl->patterns, buf);
1249          if (JB_ERR_MEMORY == error)
1250          {
1251             log_error(LOG_LEVEL_FATAL,
1252                "Out of memory while enlisting re_filter job \'%s\' for filter %s.", buf, bl->name);
1253          }
1254          assert(JB_ERR_OK == error);
1255
1256          if (pcrs_job_is_dynamic(buf))
1257          {
1258             /*
1259              * Dynamic pattern that might contain variables
1260              * and has to be recompiled for every request
1261              */
1262             if (bl->joblist != NULL)
1263             {
1264                 pcrs_free_joblist(bl->joblist);
1265                 bl->joblist = NULL;
1266             }
1267             bl->dynamic = 1;
1268             log_error(LOG_LEVEL_RE_FILTER,
1269                "Adding dynamic re_filter job \'%s\' to filter %s succeeded.", buf, bl->name);
1270             freez(buf);
1271             continue;
1272          }
1273          else if (bl->dynamic)
1274          {
1275             /*
1276              * A previous job was dynamic and as we
1277              * recompile the whole filter anyway, it
1278              * makes no sense to compile this job now.
1279              */
1280             log_error(LOG_LEVEL_RE_FILTER,
1281                "Adding static re_filter job \'%s\' to dynamic filter %s succeeded.", buf, bl->name);
1282             freez(buf);
1283             continue;
1284          }
1285
1286          if ((dummy = pcrs_compile_command(buf, &error)) == NULL)
1287          {
1288             log_error(LOG_LEVEL_ERROR,
1289                "Adding re_filter job \'%s\' to filter %s failed: %s",
1290                buf, bl->name, pcrs_strerror(error));
1291             freez(buf);
1292             continue;
1293          }
1294          else
1295          {
1296             if (bl->joblist == NULL)
1297             {
1298                bl->joblist = dummy;
1299             }
1300             else if (NULL != lastjob)
1301             {
1302                lastjob->next = dummy;
1303             }
1304             lastjob = dummy;
1305             log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job \'%s\' to filter %s succeeded.", buf, bl->name);
1306          }
1307       }
1308       else
1309       {
1310          log_error(LOG_LEVEL_ERROR, "Ignoring job %s outside filter block in %s, line %d",
1311             buf, csp->config->re_filterfile[fileid], linenum);
1312       }
1313       freez(buf);
1314    }
1315
1316    fclose(fp);
1317
1318    /*
1319     * Schedule the now-obsolete old data for unloading
1320     */
1321    if (NULL != current_re_filterfile[fileid])
1322    {
1323       current_re_filterfile[fileid]->unloader = unload_re_filterfile;
1324    }
1325
1326    /*
1327     * Chain this file into the global list of loaded files
1328     */
1329    fs->next    = files->next;
1330    files->next = fs;
1331    current_re_filterfile[fileid] = fs;
1332    csp->rlist[fileid] = fs;
1333
1334    return(0);
1335
1336 load_re_filterfile_error:
1337    log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1338              csp->config->re_filterfile[fileid]);
1339    return(-1);
1340
1341 }
1342
1343
1344 /*********************************************************************
1345  *
1346  * Function    :  add_loader
1347  *
1348  * Description :  Called from `load_config'.  Called once for each input
1349  *                file found in config.
1350  *
1351  * Parameters  :
1352  *          1  :  loader = pointer to a function that can parse and load
1353  *                the appropriate config file.
1354  *          2  :  config = The configuration_spec to add the loader to.
1355  *
1356  * Returns     :  N/A
1357  *
1358  *********************************************************************/
1359 void add_loader(int (*loader)(struct client_state *),
1360                 struct configuration_spec * config)
1361 {
1362    int i;
1363
1364    for (i = 0; i < NLOADERS; i++)
1365    {
1366       if (config->loaders[i] == NULL)
1367       {
1368          config->loaders[i] = loader;
1369          break;
1370       }
1371    }
1372
1373 }
1374
1375
1376 /*********************************************************************
1377  *
1378  * Function    :  run_loader
1379  *
1380  * Description :  Called from `load_config' and `listen_loop'.  This
1381  *                function keeps the "csp" current with any file mods
1382  *                since the last loop.  If a file is unchanged, the
1383  *                loader functions do NOT reload the file.
1384  *
1385  * Parameters  :
1386  *          1  :  csp = Current client state (buffers, headers, etc...)
1387  *                      Must be non-null.  Reads: "csp->config"
1388  *                      Writes: various data members.
1389  *
1390  * Returns     :  0 => Ok, everything else is an error.
1391  *
1392  *********************************************************************/
1393 int run_loader(struct client_state *csp)
1394 {
1395    int ret = 0;
1396    int i;
1397
1398    for (i = 0; i < NLOADERS; i++)
1399    {
1400       if (csp->config->loaders[i] == NULL)
1401       {
1402          break;
1403       }
1404       ret |= (csp->config->loaders[i])(csp);
1405    }
1406    return(ret);
1407
1408 }
1409
1410 /*********************************************************************
1411  *
1412  * Function    :  file_has_been_modified
1413  *
1414  * Description :  Helper function to check if a file has been changed
1415  *
1416  * Parameters  :
1417  *          1  : filename = The name of the file to check
1418  *          2  : last_known_modification = The time of the last known
1419  *                                         modification
1420  *
1421  * Returns     :  TRUE if the file has been changed,
1422  *                FALSE otherwise.
1423  *
1424  *********************************************************************/
1425 static int file_has_been_modified(const char *filename, time_t last_know_modification)
1426 {
1427    struct stat statbuf[1];
1428
1429    if (stat(filename, statbuf) < 0)
1430    {
1431       /* Error, probably file not found which counts as change. */
1432       return 1;
1433    }
1434
1435    return (last_know_modification != statbuf->st_mtime);
1436 }
1437
1438
1439 /*********************************************************************
1440  *
1441  * Function    :  any_loaded_file_changed
1442  *
1443  * Description :  Helper function to check if any loaded file has been
1444  *                changed since the time it has been loaded.
1445  *
1446  *                XXX: Should we cache the return value for x seconds?
1447  *
1448  * Parameters  :
1449  *          1  : files_to_check = List of files to check
1450  *
1451  * Returns     : TRUE if any file has been changed,
1452  *               FALSE otherwise.
1453  *
1454  *********************************************************************/
1455 int any_loaded_file_changed(const struct client_state *csp)
1456 {
1457    const struct file_list *file_to_check = csp->config->config_file_list;
1458    int i;
1459
1460    if (file_has_been_modified(file_to_check->filename, file_to_check->lastmodified))
1461    {
1462       return TRUE;
1463    }
1464
1465    for (i = 0; i < MAX_AF_FILES; i++)
1466    {
1467       if (csp->actions_list[i])
1468       {
1469          file_to_check = csp->actions_list[i];
1470          if (file_has_been_modified(file_to_check->filename, file_to_check->lastmodified))
1471          {
1472             return TRUE;
1473          }
1474       }
1475    }
1476
1477    for (i = 0; i < MAX_AF_FILES; i++)
1478    {
1479       if (csp->rlist[i])
1480       {
1481          file_to_check = csp->rlist[i];
1482          if (file_has_been_modified(file_to_check->filename, file_to_check->lastmodified))
1483          {
1484             return TRUE;
1485          }
1486       }
1487    }
1488
1489 #ifdef FEATURE_TRUST
1490    if (csp->tlist)
1491    {
1492       if (file_has_been_modified(csp->tlist->filename, csp->tlist->lastmodified))
1493       {
1494          return TRUE;
1495       }
1496    }
1497 #endif /* def FEATURE_TRUST */
1498
1499    return FALSE;
1500 }
1501
1502
1503 /*
1504   Local Variables:
1505   tab-width: 3
1506   end:
1507 */