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