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