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