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