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