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