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