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