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