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