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