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