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