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