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