LCOV - code coverage report
Current view: top level - fuzz - loaders.c (source / functions) Hit Total Coverage
Test: trace.lcov_info_final Lines: 218 448 48.7 %
Date: 2021-02-22 04:51:02 Functions: 10 16 62.5 %

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

Generated by: LCOV version 1.14