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