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