Added descriptions to the filters so users will know what they select in the cgi...
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.42 2002/03/13 00:27:05 jongfoster 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 the SourceForge
12  *                IJBSWA team.  http://ijbswa.sourceforge.net
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  * Revisions   :
37  *    $Log: loaders.c,v $
38  *    Revision 1.42  2002/03/13 00:27:05  jongfoster
39  *    Killing warnings
40  *
41  *    Revision 1.41  2002/03/12 01:42:50  oes
42  *    Introduced modular filters
43  *
44  *    Revision 1.40  2002/03/08 17:46:04  jongfoster
45  *    Fixing int/size_t warnings
46  *
47  *    Revision 1.39  2002/03/07 03:46:17  oes
48  *    Fixed compiler warnings
49  *
50  *    Revision 1.38  2002/03/06 22:54:35  jongfoster
51  *    Automated function-comment nitpicking.
52  *
53  *    Revision 1.37  2002/03/03 15:07:49  oes
54  *    Re-enabled automatic config reloading
55  *
56  *    Revision 1.36  2002/01/22 23:46:18  jongfoster
57  *    Moving edit_read_line() and simple_read_line() to loaders.c, and
58  *    extending them to support reading MS-DOS, Mac and UNIX style files
59  *    on all platforms.
60  *
61  *    Modifying read_config_line() (without changing it's prototype) to
62  *    be a trivial wrapper for edit_read_line().  This means that we have
63  *    one function to read a line and handle comments, which is common
64  *    between the initialization code and the edit interface.
65  *
66  *    Revision 1.35  2002/01/17 21:03:08  jongfoster
67  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
68  *
69  *    Renaming free_url to free_url_spec, since it frees a struct url_spec.
70  *
71  *    Revision 1.34  2001/12/30 14:07:32  steudten
72  *    - Add signal handling (unix)
73  *    - Add SIGHUP handler (unix)
74  *    - Add creation of pidfile (unix)
75  *    - Add action 'top' in rc file (RH)
76  *    - Add entry 'SIGNALS' to manpage
77  *    - Add exit message to logfile (unix)
78  *
79  *    Revision 1.33  2001/11/13 00:16:38  jongfoster
80  *    Replacing references to malloc.h with the standard stdlib.h
81  *    (See ANSI or K&R 2nd Ed)
82  *
83  *    Revision 1.32  2001/11/07 00:02:13  steudten
84  *    Add line number in error output for lineparsing for
85  *    actionsfile and configfile.
86  *    Special handling for CLF added.
87  *
88  *    Revision 1.31  2001/10/26 17:39:01  oes
89  *    Removed csp->referrer
90  *    Moved ijb_isspace and ijb_tolower to project.h
91  *
92  *    Revision 1.30  2001/10/25 03:40:48  david__schmidt
93  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
94  *    threads to call select() simultaneously.  So, it's time to do a real, live,
95  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
96  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
97  *
98  *    Revision 1.29  2001/10/23 21:38:53  jongfoster
99  *    Adding error-checking to create_url_spec()
100  *
101  *    Revision 1.28  2001/10/07 15:40:39  oes
102  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
103  *
104  *    Revision 1.27  2001/09/22 16:36:59  jongfoster
105  *    Removing unused parameter fs from read_config_line()
106  *
107  *    Revision 1.26  2001/09/22 14:05:22  jongfoster
108  *    Bugfix: Multiple escaped "#" characters in a configuration
109  *    file are now permitted.
110  *    Also removing 3 unused headers.
111  *
112  *    Revision 1.25  2001/09/13 22:44:03  jongfoster
113  *    Adding {} to an if statement
114  *
115  *    Revision 1.24  2001/07/30 22:08:36  jongfoster
116  *    Tidying up #defines:
117  *    - All feature #defines are now of the form FEATURE_xxx
118  *    - Permanently turned off WIN_GUI_EDIT
119  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
120  *
121  *    Revision 1.23  2001/07/20 15:51:54  oes
122  *    Fixed indentation of prepocessor commands
123  *
124  *    Revision 1.22  2001/07/20 15:16:17  haroon
125  *    - per Guy's suggestion, added a while loop in sweep() to catch not just
126  *      the last inactive CSP but all other consecutive inactive CSPs after that
127  *      as well
128  *
129  *    Revision 1.21  2001/07/18 17:26:24  oes
130  *    Changed to conform to new pcrs interface
131  *
132  *    Revision 1.20  2001/07/17 13:07:01  oes
133  *    Fixed segv when last line in config files
134  *     lacked a terminating (\r)\n
135  *
136  *    Revision 1.19  2001/07/13 14:01:54  oes
137  *    Removed all #ifdef PCRS
138  *
139  *    Revision 1.18  2001/06/29 21:45:41  oes
140  *    Indentation, CRLF->LF, Tab-> Space
141  *
142  *    Revision 1.17  2001/06/29 13:31:51  oes
143  *    Various adaptions
144  *
145  *    Revision 1.16  2001/06/09 10:55:28  jongfoster
146  *    Changing BUFSIZ ==> BUFFER_SIZE
147  *
148  *    Revision 1.15  2001/06/07 23:14:14  jongfoster
149  *    Removing ACL and forward file loaders - these
150  *    files have been merged into the config file.
151  *    Cosmetic: Moving unloader funcs next to their
152  *    respective loader funcs
153  *
154  *    Revision 1.14  2001/06/01 03:27:04  oes
155  *    Fixed line continuation problem
156  *
157  *    Revision 1.13  2001/05/31 21:28:49  jongfoster
158  *    Removed all permissionsfile code - it's now called the actions
159  *    file, and (almost) all the code is in actions.c
160  *
161  *    Revision 1.12  2001/05/31 17:32:31  oes
162  *
163  *     - Enhanced domain part globbing with infix and prefix asterisk
164  *       matching and optional unanchored operation
165  *
166  *    Revision 1.11  2001/05/29 23:25:24  oes
167  *
168  *     - load_config_line() and load_permissions_file() now use chomp()
169  *
170  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
171  *    Unified blocklist/imagelist/permissionslist.
172  *    File format is still under discussion, but the internal changes
173  *    are (mostly) done.
174  *
175  *    Also modified interceptor behaviour:
176  *    - We now intercept all URLs beginning with one of the following
177  *      prefixes (and *only* these prefixes):
178  *        * http://i.j.b/
179  *        * http://ijbswa.sf.net/config/
180  *        * http://ijbswa.sourceforge.net/config/
181  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
182  *    - Internal changes so that intercepted and fast redirect pages
183  *      are not replaced with an image.
184  *    - Interceptors now have the option to send a binary page direct
185  *      to the client. (i.e. ijb-send-banner uses this)
186  *    - Implemented show-url-info interceptor.  (Which is why I needed
187  *      the above interceptors changes - a typical URL is
188  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
189  *      The previous mechanism would not have intercepted that, and
190  *      if it had been intercepted then it then it would have replaced
191  *      it with an image.)
192  *
193  *    Revision 1.9  2001/05/26 17:12:07  jongfoster
194  *    Fatal errors loading configuration files now give better error messages.
195  *
196  *    Revision 1.8  2001/05/26 00:55:20  jongfoster
197  *    Removing duplicated code.  load_forwardfile() now uses create_url_spec()
198  *
199  *    Revision 1.7  2001/05/26 00:28:36  jongfoster
200  *    Automatic reloading of config file.
201  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
202  *    Most of the global variables have been moved to a new
203  *    struct configuration_spec, accessed through csp->config->globalname
204  *    Most of the globals remaining are used by the Win32 GUI.
205  *
206  *    Revision 1.6  2001/05/23 12:27:33  oes
207  *
208  *    Fixed ugly indentation of my last changes
209  *
210  *    Revision 1.5  2001/05/23 10:39:05  oes
211  *    - Added support for escaping the comment character
212  *      in config files by a backslash
213  *    - Added support for line continuation in config
214  *      files
215  *    - Fixed a buffer overflow bug with long config lines
216  *
217  *    Revision 1.4  2001/05/22 18:56:28  oes
218  *    CRLF -> LF
219  *
220  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
221  *    Version 2.9.4 checkin.
222  *    - Merged popupfile and cookiefile, and added control over PCRS
223  *      filtering, in new "permissionsfile".
224  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
225  *      file error you now get a message box (in the Win32 GUI) rather
226  *      than the program exiting with no explanation.
227  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
228  *      skipping.
229  *    - Removed tabs from "config"
230  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
231  *    - Bumped up version number.
232  *
233  *    Revision 1.2  2001/05/17 23:01:01  oes
234  *     - Cleaned CRLF's from the sources and related files
235  *
236  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
237  *    Initial import of version 2.9.3 source tree
238  *
239  *
240  *********************************************************************/
241 \f
242
243 #include "config.h"
244
245 #include <stdio.h>
246 #include <stdlib.h>
247 #include <sys/types.h>
248 #include <string.h>
249 #include <errno.h>
250 #include <sys/stat.h>
251 #include <ctype.h>
252 #include <assert.h>
253
254 #if !defined(_WIN32) && !defined(__OS2__)
255 #include <unistd.h>
256 #endif
257
258 #include "project.h"
259 #include "list.h"
260 #include "loaders.h"
261 #include "filters.h"
262 #include "parsers.h"
263 #include "jcc.h"
264 #include "miscutil.h"
265 #include "errlog.h"
266 #include "actions.h"
267 #include "urlmatch.h"
268
269 const char loaders_h_rcs[] = LOADERS_H_VERSION;
270
271 /*
272  * Currently active files.
273  * These are also entered in the main linked list of files.
274  */
275
276 #ifdef FEATURE_TRUST
277 static struct file_list *current_trustfile      = NULL;
278 #endif /* def FEATURE_TRUST */
279
280 static struct file_list *current_re_filterfile  = NULL;
281
282
283
284 /*********************************************************************
285  *
286  * Function    :  sweep
287  *
288  * Description :  Basically a mark and sweep garbage collector, it is run
289  *                (by the parent thread) every once in a while to reclaim memory.
290  *
291  * It uses a mark and sweep strategy:
292  *   1) mark all files as inactive
293  *
294  *   2) check with each client:
295  *       if it is active,   mark its files as active
296  *       if it is inactive, free its resources
297  *
298  *   3) free the resources of all of the files that
299  *      are still marked as inactive (and are obsolete).
300  *
301  *   N.B. files that are not obsolete don't have an unloader defined.
302  *
303  * Parameters  :  None
304  *
305  * Returns     :  N/A
306  *
307  *********************************************************************/
308 void sweep(void)
309 {
310    struct file_list *fl, *nfl;
311    struct client_state *csp, *ncsp;
312
313    /* clear all of the file's active flags */
314    for ( fl = files->next; NULL != fl; fl = fl->next )
315    {
316       fl->active = 0;
317    }
318
319    for (csp = clients; csp && (NULL != (ncsp = csp->next)) ; csp = csp->next)
320    {
321       if (ncsp->flags & CSP_FLAG_ACTIVE)
322       {
323          /* mark this client's files as active */
324
325          /*
326           * Always have a configuration file.
327           * (Also note the slightly non-standard extra
328           * indirection here.)
329           */
330          ncsp->config->config_file_list->active = 1;
331
332          if (ncsp->actions_list)     /* actions files */
333          {
334             ncsp->actions_list->active = 1;
335          }
336
337          if (ncsp->rlist)     /* pcrsjob files */
338          {
339             ncsp->rlist->active = 1;
340          }
341
342 #ifdef FEATURE_TRUST
343          if (ncsp->tlist)     /* trust files */
344          {
345             ncsp->tlist->active = 1;
346          }
347 #endif /* def FEATURE_TRUST */
348
349       }
350       else
351       /*
352        * this client is not active, release its resources
353        * and the ones of all inactive clients that might
354        * follow it
355        */
356       {
357          while (!(ncsp->flags & CSP_FLAG_ACTIVE))
358          {
359             csp->next = ncsp->next;
360
361             freez(ncsp->ip_addr_str);
362             freez(ncsp->my_ip_addr_str);
363             freez(ncsp->my_hostname);
364             freez(ncsp->x_forwarded);
365             freez(ncsp->iob->buf);
366
367             free_http_request(ncsp->http);
368
369             destroy_list(ncsp->headers);
370             destroy_list(ncsp->cookie_list);
371
372             free_current_action(ncsp->action);
373
374 #ifdef FEATURE_STATISTICS
375             urls_read++;
376             if (ncsp->flags & CSP_FLAG_REJECTED)
377             {
378                urls_rejected++;
379             }
380 #endif /* def FEATURE_STATISTICS */
381
382             freez(ncsp);
383
384             /* are there any more in sequence after it? */
385             if( (ncsp = csp->next) == NULL)
386                break;
387          }
388       }
389    }
390
391    for (fl = files; fl && ((nfl = fl->next) != NULL) ; fl = fl->next)
392    {
393       if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
394       {
395          fl->next = nfl->next;
396
397          (nfl->unloader)(nfl->f);
398
399          freez(nfl->filename);
400
401          freez(nfl);
402       }
403    }
404
405 }
406
407
408 /*********************************************************************
409  *
410  * Function    :  check_file_changed
411  *
412  * Description :  Helper function to check if a file needs reloading.
413  *                If "current" is still current, return it.  Otherwise
414  *                allocates a new (zeroed) "struct file_list", fills
415  *                in the disk file name and timestamp, and returns it.
416  *
417  * Parameters  :
418  *          1  :  current = The file_list currently being used - will
419  *                          be checked to see if it is out of date.
420  *                          May be NULL (which is treated as out of
421  *                          date).
422  *          2  :  filename = Name of file to check.
423  *          3  :  newfl    = New file list. [Output only]
424  *                           This will be set to NULL, OR a struct
425  *                           file_list newly allocated on the
426  *                           heap, with the filename and lastmodified
427  *                           fields filled, and all others zeroed.
428  *
429  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
430  *                If file changed: 1 and sets newfl != NULL
431  *                On error: 1 and sets newfl == NULL
432  *
433  *********************************************************************/
434 int check_file_changed(const struct file_list * current,
435                        const char * filename,
436                        struct file_list ** newfl)
437 {
438    struct file_list *fs;
439    struct stat statbuf[1];
440
441    *newfl = NULL;
442
443    if (stat(filename, statbuf) < 0)
444    {
445       /* Error, probably file not found. */
446       return 1;
447    }
448
449    if (current
450        && (current->lastmodified == statbuf->st_mtime)
451        && (0 == strcmp(current->filename, filename)))
452    {
453       return 0;
454    }
455
456    fs = (struct file_list *)zalloc(sizeof(struct file_list));
457    if (fs == NULL)
458    {
459       /* Out of memory error */
460       return 1;
461    }
462
463    fs->filename = strdup(filename);
464    fs->lastmodified = statbuf->st_mtime;
465
466    if (fs->filename == NULL)
467    {
468       /* Out of memory error */
469       freez (fs);
470       return 1;
471    }
472    *newfl = fs;
473    return 1;
474 }
475
476
477 /*********************************************************************
478  *
479  * Function    :  simple_read_line
480  *
481  * Description :  Read a single line from a file and return it.
482  *                This is basically a version of fgets() that malloc()s
483  *                it's own line buffer.  Note that the buffer will
484  *                always be a multiple of BUFFER_SIZE bytes long.
485  *                Therefore if you are going to keep the string for
486  *                an extended period of time, you should probably
487  *                strdup() it and free() the original, to save memory.
488  *
489  *
490  * Parameters  :
491  *          1  :  dest = destination for newly malloc'd pointer to
492  *                line data.  Will be set to NULL on error.
493  *          2  :  fp = File to read from
494  *          3  :  newline = Standard for newlines in the file.
495  *                Will be unchanged if it's value on input is not
496  *                NEWLINE_UNKNOWN.
497  *                On output, may be changed from NEWLINE_UNKNOWN to
498  *                actual convention in file.
499  *
500  * Returns     :  JB_ERR_OK     on success
501  *                JB_ERR_MEMORY on out-of-memory
502  *                JB_ERR_FILE   on EOF.
503  *
504  *********************************************************************/
505 jb_err simple_read_line(FILE *fp, char **dest, int *newline)
506 {
507    size_t len = 0;
508    size_t buflen = BUFFER_SIZE;
509    char * buf;
510    char * p;
511    int ch;
512    int realnewline = NEWLINE_UNKNOWN;
513
514    if (NULL == (buf = malloc(buflen)))
515    {
516       return JB_ERR_MEMORY;
517    }
518
519    p = buf;
520
521 /*
522  * Character codes.  If you have a wierd compiler and the following are
523  * incorrect, you also need to fix NEWLINE() in loaders.h
524  */
525 #define CHAR_CR '\r' /* ASCII 13 */
526 #define CHAR_LF '\n' /* ASCII 10 */
527
528    for (;;)
529    {
530       ch = fgetc(fp);
531       if (ch == EOF)
532       {
533          if (len > 0)
534          {
535             *p = '\0';
536             *dest = buf;
537             return JB_ERR_OK;
538          }
539          else
540          {
541             free(buf);
542             *dest = NULL;
543             return JB_ERR_FILE;
544          }
545       }
546       else if (ch == CHAR_CR)
547       {
548          ch = getc(fp);
549          if (ch == CHAR_LF)
550          {
551             if (*newline == NEWLINE_UNKNOWN)
552             {
553                *newline = NEWLINE_DOS;
554             }
555          }
556          else
557          {
558             if (ch != EOF)
559             {
560                ungetc(ch, fp);
561             }
562             if (*newline == NEWLINE_UNKNOWN)
563             {
564                *newline = NEWLINE_MAC;
565             }
566          }
567          *p = '\0';
568          *dest = buf;
569          if (*newline == NEWLINE_UNKNOWN)
570          {
571             *newline = realnewline;
572          }
573          return JB_ERR_OK;
574       }
575       else if (ch == CHAR_LF)
576       {
577          *p = '\0';
578          *dest = buf;
579          if (*newline == NEWLINE_UNKNOWN)
580          {
581             *newline = NEWLINE_UNIX;
582          }
583          return JB_ERR_OK;
584       }
585       else if (ch == 0)
586       {
587          *p = '\0';
588          *dest = buf;
589          return JB_ERR_OK;
590       }
591
592       *p++ = ch;
593
594       if (++len >= buflen)
595       {
596          buflen += BUFFER_SIZE;
597          if (NULL == (p = realloc(buf, buflen)));
598          {
599             free(buf);
600             return JB_ERR_MEMORY;
601          }
602          buf = p;
603          p = buf + len;
604       }
605    }
606 }
607
608
609 /*********************************************************************
610  *
611  * Function    :  edit_read_line
612  *
613  * Description :  Read a single non-empty line from a file and return
614  *                it.  Trims comments, leading and trailing whitespace
615  *                and respects escaping of newline and comment char.
616  *                Provides the line in 2 alternative forms: raw and
617  *                preprocessed.
618  *                - raw is the raw data read from the file.  If the
619  *                  line is not modified, then this should be written
620  *                  to the new file.
621  *                - prefix is any comments and blank lines that were
622  *                  read from the file.  If the line is modified, then
623  *                  this should be written out to the file followed
624  *                  by the modified data.  (If this string is non-empty
625  *                  then it will have a newline at the end).
626  *                - data is the actual data that will be parsed
627  *                  further by appropriate routines.
628  *                On EOF, the 3 strings will all be set to NULL and
629  *                0 will be returned.
630  *
631  * Parameters  :
632  *          1  :  fp = File to read from
633  *          2  :  raw_out = destination for newly malloc'd pointer to
634  *                raw line data.  May be NULL if you don't want it.
635  *          3  :  prefix_out = destination for newly malloc'd pointer to
636  *                comments.  May be NULL if you don't want it.
637  *          4  :  data_out = destination for newly malloc'd pointer to
638  *                line data with comments and leading/trailing spaces
639  *                removed, and line continuation performed.  May be
640  *                NULL if you don't want it.
641  *          5  :  newline = Standard for newlines in the file.
642  *                On input, set to value to use or NEWLINE_UNKNOWN.
643  *                On output, may be changed from NEWLINE_UNKNOWN to
644  *                actual convention in file.  May be NULL if you
645  *                don't want it.
646  *          6  :  line_number = Line number in file.  In "lines" as
647  *                reported by a text editor, not lines containing data.
648  *
649  * Returns     :  JB_ERR_OK     on success
650  *                JB_ERR_MEMORY on out-of-memory
651  *                JB_ERR_FILE   on EOF.
652  *
653  *********************************************************************/
654 jb_err edit_read_line(FILE *fp,
655                       char **raw_out,
656                       char **prefix_out,
657                       char **data_out,
658                       int *newline,
659                       unsigned long *line_number)
660 {
661    char *p;          /* Temporary pointer   */
662    char *linebuf;    /* Line read from file */
663    char *linestart;  /* Start of linebuf, usually first non-whitespace char */
664    int contflag = 0; /* Nonzero for line continuation - i.e. line ends '\' */
665    int is_empty = 1; /* Flag if not got any data yet */
666    char *raw    = NULL; /* String to be stored in raw_out    */
667    char *prefix = NULL; /* String to be stored in prefix_out */
668    char *data   = NULL; /* String to be stored in data_out   */
669    int scrapnewline;    /* Used for (*newline) if newline==NULL */
670    jb_err rval = JB_ERR_OK;
671
672    assert(fp);
673    assert(raw_out || data_out);
674    assert(newline == NULL
675        || *newline == NEWLINE_UNKNOWN
676        || *newline == NEWLINE_UNIX
677        || *newline == NEWLINE_DOS
678        || *newline == NEWLINE_MAC);
679
680    if (newline == NULL)
681    {
682       scrapnewline = NEWLINE_UNKNOWN;
683       newline = &scrapnewline;
684    }
685
686    /* Set output parameters to NULL */
687    if (raw_out)
688    {
689       *raw_out    = NULL;
690    }
691    if (prefix_out)
692    {
693       *prefix_out = NULL;
694    }
695    if (data_out)
696    {
697       *data_out   = NULL;
698    }
699
700    /* Set string variables to new, empty strings. */
701
702    if (raw_out)
703    {
704       if ((raw = malloc(1)) == NULL)
705       {
706          return JB_ERR_MEMORY;
707       }
708       *raw = '\0';
709    }
710    if (prefix_out)
711    {
712       if ((prefix = malloc(1)) == NULL)
713       {
714          freez(raw);
715          return JB_ERR_MEMORY;
716       }
717       *prefix = '\0';
718    }
719    if (data_out)
720    {
721       if ((data = malloc(1)) == NULL)
722       {
723          freez(raw);
724          freez(prefix);
725          return JB_ERR_MEMORY;
726       }
727       *data = '\0';
728    }
729
730    /* Main loop.  Loop while we need more data & it's not EOF. */
731
732    while ( (contflag || is_empty)
733         && (JB_ERR_OK == (rval = simple_read_line(fp, &linebuf, newline))))
734    {
735       if (line_number)
736       {
737          (*line_number)++;
738       }
739       if (raw)
740       {
741          string_append(&raw,linebuf);
742          if (string_append(&raw,NEWLINE(*newline)))
743          {
744             freez(prefix);
745             freez(data);
746             free(linebuf);
747             return JB_ERR_MEMORY;
748          }
749       }
750
751       /* Line continuation? Trim escape and set flag. */
752       p = linebuf + strlen(linebuf) - 1;
753       contflag = ((*linebuf != '\0') && (*p == '\\'));
754       if (contflag)
755       {
756          *p = '\0';
757       }
758
759       /* Trim leading spaces if we're at the start of the line */
760       linestart = linebuf;
761       if (*data == '\0')
762       {
763          /* Trim leading spaces */
764          while (*linestart && isspace((int)(unsigned char)*linestart))
765          {
766             linestart++;
767          }
768       }
769
770       /* Handle comment characters. */
771       p = linestart;
772       while ((p = strchr(p, '#')) != NULL)
773       {
774          /* Found a comment char.. */
775          if ((p != linebuf) && (*(p-1) == '\\'))
776          {
777             /* ..and it's escaped, left-shift the line over the escape. */
778             char *q = p - 1;
779             while ((*q = *(q + 1)) != '\0')
780             {
781                q++;
782             }
783             /* Now scan from just after the "#". */
784          }
785          else
786          {
787             /* Real comment.  Save it... */
788             if (p == linestart)
789             {
790                /* Special case:  Line only contains a comment, so all the
791                 * previous whitespace is considered part of the comment.
792                 * Undo the whitespace skipping, if any.
793                 */
794                linestart = linebuf;
795                p = linestart;
796             }
797             if (prefix)
798             {
799                string_append(&prefix,p);
800                if (string_append(&prefix, NEWLINE(*newline)))
801                {
802                   freez(raw);
803                   freez(data);
804                   free(linebuf);
805                   return JB_ERR_MEMORY;
806                }
807             }
808
809             /* ... and chop off the rest of the line */
810             *p = '\0';
811          }
812       } /* END while (there's a # character) */
813
814       /* Write to the buffer */
815       if (*linestart)
816       {
817          is_empty = 0;
818          if (data)
819          {
820             if (string_append(&data, linestart))
821             {
822                freez(raw);
823                freez(prefix);
824                free(linebuf);
825                return JB_ERR_MEMORY;
826             }
827          }
828       }
829
830       free(linebuf);
831    } /* END while(we need more data) */
832
833    /* Handle simple_read_line() errors - ignore EOF */
834    if ((rval != JB_ERR_OK) && (rval != JB_ERR_FILE))
835    {
836       freez(raw);
837       freez(prefix);
838       freez(data);
839       return rval;
840    }
841
842    if (raw ? (*raw == '\0') : is_empty)
843    {
844       /* EOF and no data there.  (Definition of "data" depends on whether
845        * the caller cares about "raw" or just "data").
846        */
847
848       free(raw);
849       free(prefix);
850       free(data);
851
852       return JB_ERR_FILE;
853    }
854    else
855    {
856       /* Got at least some data */
857
858       /* Remove trailing whitespace */
859       chomp(data);
860
861       if (raw_out)
862       {
863          *raw_out    = raw;
864       }
865       else
866       {
867          free(raw);
868       }
869       if (prefix_out)
870       {
871          *prefix_out = prefix;
872       }
873       else
874       {
875          free(prefix);
876       }
877       if (data_out)
878       {
879          *data_out   = data;
880       }
881       else
882       {
883          free(data);
884       }
885       return JB_ERR_OK;
886    }
887 }
888
889
890 /*********************************************************************
891  *
892  * Function    :  read_config_line
893  *
894  * Description :  Read a single non-empty line from a file and return
895  *                it.  Trims comments, leading and trailing whitespace
896  *                and respects escaping of newline and comment char.
897  *
898  * Parameters  :
899  *          1  :  buf = Buffer to use.
900  *          2  :  buflen = Size of buffer in bytes.
901  *          3  :  fp = File to read from
902  *          4  :  linenum = linenumber in file
903  *
904  * Returns     :  NULL on EOF or error
905  *                Otherwise, returns buf.
906  *
907  *********************************************************************/
908 char *read_config_line(char *buf, size_t buflen, FILE *fp, unsigned long *linenum)
909 {
910    jb_err err;
911    char *buf2 = NULL;
912    err = edit_read_line(fp, NULL, NULL, &buf2, NULL, linenum);
913    if (err)
914    {
915       if (err == JB_ERR_MEMORY)
916       {
917          log_error(LOG_LEVEL_FATAL, "Out of memory loading a config file");
918       }
919       return NULL;
920    }
921    else
922    {
923       assert(buf2);
924       assert(strlen(buf2) + 1U < buflen);
925       strncpy(buf, buf2, buflen - 1);
926       free(buf2);
927       buf[buflen - 1] = '\0';
928       return buf;
929    }
930 }
931
932
933 #ifdef FEATURE_TRUST
934 /*********************************************************************
935  *
936  * Function    :  unload_trustfile
937  *
938  * Description :  Unloads a trustfile.
939  *
940  * Parameters  :
941  *          1  :  f = the data structure associated with the trustfile.
942  *
943  * Returns     :  N/A
944  *
945  *********************************************************************/
946 static void unload_trustfile(void *f)
947 {
948    struct block_spec *b = (struct block_spec *)f;
949    if (b == NULL) return;
950
951    unload_trustfile(b->next); /* Stack is cheap, isn't it? */
952
953    free_url_spec(b->url);
954
955    freez(b);
956
957 }
958
959
960 /*********************************************************************
961  *
962  * Function    :  load_trustfile
963  *
964  * Description :  Read and parse a trustfile and add to files list.
965  *
966  * Parameters  :
967  *          1  :  csp = Current client state (buffers, headers, etc...)
968  *
969  * Returns     :  0 => Ok, everything else is an error.
970  *
971  *********************************************************************/
972 int load_trustfile(struct client_state *csp)
973 {
974    FILE *fp;
975
976    struct block_spec *b, *bl;
977    struct url_spec **tl;
978
979    char  buf[BUFFER_SIZE], *p, *q;
980    int reject, trusted;
981    struct file_list *fs;
982    unsigned long linenum = 0;
983
984    if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
985    {
986       /* No need to load */
987       if (csp)
988       {
989          csp->tlist = current_trustfile;
990       }
991       return(0);
992    }
993    if (!fs)
994    {
995       goto load_trustfile_error;
996    }
997
998    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
999    if (bl == NULL)
1000    {
1001       goto load_trustfile_error;
1002    }
1003
1004    if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
1005    {
1006       goto load_trustfile_error;
1007    }
1008
1009    tl = csp->config->trust_list;
1010
1011    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1012    {
1013       trusted = 0;
1014       reject  = 1;
1015
1016       if (*buf == '+')
1017       {
1018          trusted = 1;
1019          *buf = '~';
1020       }
1021
1022       if (*buf == '~')
1023       {
1024          reject = 0;
1025          p = buf;
1026          q = p+1;
1027          while ((*p++ = *q++) != '\0')
1028          {
1029             /* nop */
1030          }
1031       }
1032
1033       /* skip blank lines */
1034       if (*buf == '\0')
1035       {
1036          continue;
1037       }
1038
1039       /* allocate a new node */
1040       if ((b = zalloc(sizeof(*b))) == NULL)
1041       {
1042          fclose(fp);
1043          goto load_trustfile_error;
1044       }
1045
1046       /* add it to the list */
1047       b->next  = bl->next;
1048       bl->next = b;
1049
1050       b->reject = reject;
1051
1052       /* Save the URL pattern */
1053       if (create_url_spec(b->url, buf))
1054       {
1055          fclose(fp);
1056          goto load_trustfile_error;
1057       }
1058
1059       /*
1060        * save a pointer to URL's spec in the list of trusted URL's, too
1061        */
1062       if (trusted)
1063       {
1064          *tl++ = b->url;
1065          /* FIXME BUFFER OVERFLOW if >=64 entries */
1066       }
1067    }
1068
1069    *tl = NULL;
1070
1071    fclose(fp);
1072
1073    /* the old one is now obsolete */
1074    if (current_trustfile)
1075    {
1076       current_trustfile->unloader = unload_trustfile;
1077    }
1078
1079    fs->next    = files->next;
1080    files->next = fs;
1081    current_trustfile = fs;
1082
1083    if (csp)
1084    {
1085       csp->tlist = fs;
1086    }
1087
1088    return(0);
1089
1090 load_trustfile_error:
1091    log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1092              csp->config->trustfile);
1093    return(-1);
1094
1095 }
1096 #endif /* def FEATURE_TRUST */
1097
1098
1099 /*********************************************************************
1100  *
1101  * Function    :  unload_re_filterfile
1102  *
1103  * Description :  Unload the re_filter list by freeing all chained
1104  *                re_filterfile specs and their data.
1105  *
1106  * Parameters  :
1107  *          1  :  f = the data structure associated with the filterfile.
1108  *
1109  * Returns     :  N/A
1110  *
1111  *********************************************************************/
1112 static void unload_re_filterfile(void *f)
1113 {
1114    struct re_filterfile_spec *a, *b = (struct re_filterfile_spec *)f;
1115
1116    while (b != NULL)
1117    {
1118       a = b->next;
1119
1120       destroy_list(b->patterns);
1121       pcrs_free_joblist(b->joblist);
1122       freez(b->name);
1123       freez(b->description);
1124       freez(b);
1125
1126       b = a;
1127    }
1128
1129    return;
1130 }
1131
1132
1133 /*********************************************************************
1134  *
1135  * Function    :  load_re_filterfile
1136  *
1137  * Description :  Load the re_filterfile. 
1138  *                Generate a chained list of re_filterfile_spec's from
1139  *                the "FILTER: " blocks, compiling all their substitutions
1140  *                into chained lists of pcrs_job structs.
1141  *
1142  * Parameters  :
1143  *          1  :  csp = Current client state (buffers, headers, etc...)
1144  *
1145  * Returns     :  0 => Ok, everything else is an error.
1146  *
1147  *********************************************************************/
1148 int load_re_filterfile(struct client_state *csp)
1149 {
1150    FILE *fp;
1151
1152    struct re_filterfile_spec *new_bl, *bl = NULL;
1153    struct file_list *fs;
1154
1155    char  buf[BUFFER_SIZE];
1156    int error;
1157    unsigned long linenum = 0;
1158    pcrs_job *dummy;
1159
1160    /*
1161     * No need to reload if unchanged
1162     */
1163    if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1164    {
1165       if (csp)
1166       {
1167          csp->rlist = current_re_filterfile;
1168       }
1169       return(0);
1170    }
1171    if (!fs)
1172    {
1173       goto load_re_filterfile_error;
1174    }
1175
1176    /* 
1177     * Open the file or fail
1178     */
1179    if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1180    {
1181       goto load_re_filterfile_error;
1182    }
1183
1184    /* 
1185     * Read line by line
1186     */
1187    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1188    {
1189       /*
1190        * If this is the head of a new filter block, make it a
1191        * re_filterfile spec of its own and chain it to the list:
1192        */
1193       if (strncmp(buf, "FILTER:", 7) == 0)
1194       {
1195          new_bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
1196          if (new_bl == NULL)
1197          {
1198             goto load_re_filterfile_error;
1199          }
1200
1201          new_bl->name = chomp(buf + 7);
1202
1203          if (NULL != (new_bl->description = strchr(new_bl->name, ' ')))
1204          {
1205             *new_bl->description++ = '\0';
1206             new_bl->description = strdup(chomp(new_bl->description));
1207          }
1208          else
1209          {
1210             new_bl->description = strdup("No description available for this filter");
1211          }
1212
1213          new_bl->name = strdup(chomp(new_bl->name));
1214          
1215          /*
1216           * If this is the first filter block, chain it
1217           * to the file_list rather than its (nonexistant)
1218           * predecessor
1219           */
1220          if (fs->f == NULL)
1221          {
1222             fs->f = new_bl;
1223          }
1224          else
1225          {
1226             bl->next = new_bl;
1227          }
1228          bl = new_bl;
1229
1230          log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description);
1231
1232          continue;
1233       }
1234
1235       /* 
1236        * Else, save the expression, make it a pcrs_job
1237        * and chain it into the current filter's joblist 
1238        */
1239       if (bl != NULL)
1240       {
1241          enlist(bl->patterns, buf);
1242
1243          if ((dummy = pcrs_compile_command(buf, &error)) == NULL)
1244          {
1245             log_error(LOG_LEVEL_RE_FILTER,
1246                       "Adding re_filter job %s to filter %s failed with error %d.", buf, bl->name, error);
1247             continue;
1248          }
1249          else
1250          {
1251             dummy->next = bl->joblist;
1252             bl->joblist = dummy;
1253             log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s to filter %s succeeded.", buf, bl->name);
1254          }
1255       }
1256       else
1257       {
1258          log_error(LOG_LEVEL_ERROR, "Ignoring job %s outside filter block in %s, line %d", buf, csp->config->re_filterfile, linenum);
1259       }
1260    }
1261
1262    fclose(fp);
1263
1264    /* 
1265     * Schedule the now-obsolete old data for unloading
1266     */
1267    if ( NULL != current_re_filterfile )
1268    {
1269       current_re_filterfile->unloader = unload_re_filterfile;
1270    }
1271
1272    /*
1273     * Chain this file into the global list of loaded files
1274     */
1275    fs->next    = files->next;
1276    files->next = fs;
1277    current_re_filterfile = fs;
1278
1279    if (csp)
1280    {
1281       csp->rlist = fs;
1282    }
1283
1284    return( 0 );
1285
1286 load_re_filterfile_error:
1287    log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1288              csp->config->re_filterfile);
1289    return(-1);
1290
1291 }
1292
1293
1294 /*********************************************************************
1295  *
1296  * Function    :  add_loader
1297  *
1298  * Description :  Called from `load_config'.  Called once for each input
1299  *                file found in config.
1300  *
1301  * Parameters  :
1302  *          1  :  loader = pointer to a function that can parse and load
1303  *                the appropriate config file.
1304  *          2  :  config = The configuration_spec to add the loader to.
1305  *
1306  * Returns     :  N/A
1307  *
1308  *********************************************************************/
1309 void add_loader(int (*loader)(struct client_state *),
1310                 struct configuration_spec * config)
1311 {
1312    int i;
1313
1314    for (i=0; i < NLOADERS; i++)
1315    {
1316       if (config->loaders[i] == NULL)
1317       {
1318          config->loaders[i] = loader;
1319          break;
1320       }
1321    }
1322
1323 }
1324
1325
1326 /*********************************************************************
1327  *
1328  * Function    :  run_loader
1329  *
1330  * Description :  Called from `load_config' and `listen_loop'.  This
1331  *                function keeps the "csp" current with any file mods
1332  *                since the last loop.  If a file is unchanged, the
1333  *                loader functions do NOT reload the file.
1334  *
1335  * Parameters  :
1336  *          1  :  csp = Current client state (buffers, headers, etc...)
1337  *                      Must be non-null.  Reads: "csp->config"
1338  *                      Writes: various data members.
1339  *
1340  * Returns     :  0 => Ok, everything else is an error.
1341  *
1342  *********************************************************************/
1343 int run_loader(struct client_state *csp)
1344 {
1345    int ret = 0;
1346    int i;
1347
1348    for (i=0; i < NLOADERS; i++)
1349    {
1350       if (csp->config->loaders[i] == NULL)
1351       {
1352          break;
1353       }
1354       ret |= (csp->config->loaders[i])(csp);
1355    }
1356    return(ret);
1357
1358 }
1359
1360
1361 /*
1362   Local Variables:
1363   tab-width: 3
1364   end:
1365 */