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