- Add signal handling (unix)
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.33 2001/11/13 00:16:38 jongfoster Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/loaders.c,v $
5  *
6  * Purpose     :  Functions to load and unload the various
7  *                configuration files.  Also contains code to manage
8  *                the list of active loaders, and to automatically
9  *                unload files that are no longer in use.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
12  *                IJBSWA team.  http://ijbswa.sourceforge.net
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: loaders.c,v $
38  *    Revision 1.33  2001/11/13 00:16:38  jongfoster
39  *    Replacing references to malloc.h with the standard stdlib.h
40  *    (See ANSI or K&R 2nd Ed)
41  *
42  *    Revision 1.32  2001/11/07 00:02:13  steudten
43  *    Add line number in error output for lineparsing for
44  *    actionsfile and configfile.
45  *    Special handling for CLF added.
46  *
47  *    Revision 1.31  2001/10/26 17:39:01  oes
48  *    Removed csp->referrer
49  *    Moved ijb_isspace and ijb_tolower to project.h
50  *
51  *    Revision 1.30  2001/10/25 03:40:48  david__schmidt
52  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
53  *    threads to call select() simultaneously.  So, it's time to do a real, live,
54  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
55  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
56  *
57  *    Revision 1.29  2001/10/23 21:38:53  jongfoster
58  *    Adding error-checking to create_url_spec()
59  *
60  *    Revision 1.28  2001/10/07 15:40:39  oes
61  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
62  *
63  *    Revision 1.27  2001/09/22 16:36:59  jongfoster
64  *    Removing unused parameter fs from read_config_line()
65  *
66  *    Revision 1.26  2001/09/22 14:05:22  jongfoster
67  *    Bugfix: Multiple escaped "#" characters in a configuration
68  *    file are now permitted.
69  *    Also removing 3 unused headers.
70  *
71  *    Revision 1.25  2001/09/13 22:44:03  jongfoster
72  *    Adding {} to an if statement
73  *
74  *    Revision 1.24  2001/07/30 22:08:36  jongfoster
75  *    Tidying up #defines:
76  *    - All feature #defines are now of the form FEATURE_xxx
77  *    - Permanently turned off WIN_GUI_EDIT
78  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
79  *
80  *    Revision 1.23  2001/07/20 15:51:54  oes
81  *    Fixed indentation of prepocessor commands
82  *
83  *    Revision 1.22  2001/07/20 15:16:17  haroon
84  *    - per Guy's suggestion, added a while loop in sweep() to catch not just
85  *      the last inactive CSP but all other consecutive inactive CSPs after that
86  *      as well
87  *
88  *    Revision 1.21  2001/07/18 17:26:24  oes
89  *    Changed to conform to new pcrs interface
90  *
91  *    Revision 1.20  2001/07/17 13:07:01  oes
92  *    Fixed segv when last line in config files
93  *     lacked a terminating (\r)\n
94  *
95  *    Revision 1.19  2001/07/13 14:01:54  oes
96  *    Removed all #ifdef PCRS
97  *
98  *    Revision 1.18  2001/06/29 21:45:41  oes
99  *    Indentation, CRLF->LF, Tab-> Space
100  *
101  *    Revision 1.17  2001/06/29 13:31:51  oes
102  *    Various adaptions
103  *
104  *    Revision 1.16  2001/06/09 10:55:28  jongfoster
105  *    Changing BUFSIZ ==> BUFFER_SIZE
106  *
107  *    Revision 1.15  2001/06/07 23:14:14  jongfoster
108  *    Removing ACL and forward file loaders - these
109  *    files have been merged into the config file.
110  *    Cosmetic: Moving unloader funcs next to their
111  *    respective loader funcs
112  *
113  *    Revision 1.14  2001/06/01 03:27:04  oes
114  *    Fixed line continuation problem
115  *
116  *    Revision 1.13  2001/05/31 21:28:49  jongfoster
117  *    Removed all permissionsfile code - it's now called the actions
118  *    file, and (almost) all the code is in actions.c
119  *
120  *    Revision 1.12  2001/05/31 17:32:31  oes
121  *
122  *     - Enhanced domain part globbing with infix and prefix asterisk
123  *       matching and optional unanchored operation
124  *
125  *    Revision 1.11  2001/05/29 23:25:24  oes
126  *
127  *     - load_config_line() and load_permissions_file() now use chomp()
128  *
129  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
130  *    Unified blocklist/imagelist/permissionslist.
131  *    File format is still under discussion, but the internal changes
132  *    are (mostly) done.
133  *
134  *    Also modified interceptor behaviour:
135  *    - We now intercept all URLs beginning with one of the following
136  *      prefixes (and *only* these prefixes):
137  *        * http://i.j.b/
138  *        * http://ijbswa.sf.net/config/
139  *        * http://ijbswa.sourceforge.net/config/
140  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
141  *    - Internal changes so that intercepted and fast redirect pages
142  *      are not replaced with an image.
143  *    - Interceptors now have the option to send a binary page direct
144  *      to the client. (i.e. ijb-send-banner uses this)
145  *    - Implemented show-url-info interceptor.  (Which is why I needed
146  *      the above interceptors changes - a typical URL is
147  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
148  *      The previous mechanism would not have intercepted that, and
149  *      if it had been intercepted then it then it would have replaced
150  *      it with an image.)
151  *
152  *    Revision 1.9  2001/05/26 17:12:07  jongfoster
153  *    Fatal errors loading configuration files now give better error messages.
154  *
155  *    Revision 1.8  2001/05/26 00:55:20  jongfoster
156  *    Removing duplicated code.  load_forwardfile() now uses create_url_spec()
157  *
158  *    Revision 1.7  2001/05/26 00:28:36  jongfoster
159  *    Automatic reloading of config file.
160  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
161  *    Most of the global variables have been moved to a new
162  *    struct configuration_spec, accessed through csp->config->globalname
163  *    Most of the globals remaining are used by the Win32 GUI.
164  *
165  *    Revision 1.6  2001/05/23 12:27:33  oes
166  *
167  *    Fixed ugly indentation of my last changes
168  *
169  *    Revision 1.5  2001/05/23 10:39:05  oes
170  *    - Added support for escaping the comment character
171  *      in config files by a backslash
172  *    - Added support for line continuation in config
173  *      files
174  *    - Fixed a buffer overflow bug with long config lines
175  *
176  *    Revision 1.4  2001/05/22 18:56:28  oes
177  *    CRLF -> LF
178  *
179  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
180  *    Version 2.9.4 checkin.
181  *    - Merged popupfile and cookiefile, and added control over PCRS
182  *      filtering, in new "permissionsfile".
183  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
184  *      file error you now get a message box (in the Win32 GUI) rather
185  *      than the program exiting with no explanation.
186  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
187  *      skipping.
188  *    - Removed tabs from "config"
189  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
190  *    - Bumped up version number.
191  *
192  *    Revision 1.2  2001/05/17 23:01:01  oes
193  *     - Cleaned CRLF's from the sources and related files
194  *
195  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
196  *    Initial import of version 2.9.3 source tree
197  *
198  *
199  *********************************************************************/
200 \f
201
202 #include "config.h"
203
204 #include <stdio.h>
205 #include <stdlib.h>
206 #include <sys/types.h>
207 #include <string.h>
208 #include <errno.h>
209 #include <sys/stat.h>
210 #include <ctype.h>
211 #include <assert.h>
212
213 #if !defined(_WIN32) && !defined(__OS2__)
214 #include <unistd.h>
215 #endif
216
217 #include "project.h"
218 #include "list.h"
219 #include "loaders.h"
220 #include "filters.h"
221 #include "parsers.h"
222 #include "jcc.h"
223 #include "miscutil.h"
224 #include "errlog.h"
225 #include "actions.h"
226
227 const char loaders_h_rcs[] = LOADERS_H_VERSION;
228
229 /*
230  * Currently active files.
231  * These are also entered in the main linked list of files.
232  */
233
234 #ifdef FEATURE_TRUST
235 static struct file_list *current_trustfile      = NULL;
236 #endif /* def FEATURE_TRUST */
237
238 static struct file_list *current_re_filterfile  = NULL;
239
240
241
242 /*********************************************************************
243  *
244  * Function    :  sweep
245  *
246  * Description :  Basically a mark and sweep garbage collector, it is run
247  *                (by the parent thread) every once in a while to reclaim memory.
248  *
249  * It uses a mark and sweep strategy:
250  *   1) mark all files as inactive
251  *
252  *   2) check with each client:
253  *       if it is active,   mark its files as active
254  *       if it is inactive, free its resources
255  *
256  *   3) free the resources of all of the files that
257  *      are still marked as inactive (and are obsolete).
258  *
259  *   N.B. files that are not obsolete don't have an unloader defined.
260  *
261  * Parameters  :  None
262  *
263  * Returns     :  N/A
264  *
265  *********************************************************************/
266 void sweep(void)
267 {
268    struct file_list *fl, *nfl;
269    struct client_state *csp, *ncsp;
270
271    /* clear all of the file's active flags */
272    for ( fl = files->next; NULL != fl; fl = fl->next )
273    {
274       fl->active = 0;
275    }
276
277    for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
278    {
279       if (ncsp->flags & CSP_FLAG_ACTIVE)
280       {
281          /* mark this client's files as active */
282
283          /*
284           * Always have a configuration file.
285           * (Also note the slightly non-standard extra
286           * indirection here.)
287           */
288          ncsp->config->config_file_list->active = 1;
289
290          if (ncsp->actions_list)     /* actions files */
291          {
292             ncsp->actions_list->active = 1;
293          }
294
295          if (ncsp->rlist)     /* pcrsjob files */
296          {
297             ncsp->rlist->active = 1;
298          }
299
300 #ifdef FEATURE_TRUST
301          if (ncsp->tlist)     /* trust files */
302          {
303             ncsp->tlist->active = 1;
304          }
305 #endif /* def FEATURE_TRUST */
306
307       }
308       else
309       /*
310        * this client is not active, release its resources
311        * and the ones of all inactive clients that might
312        * follow it
313        */
314       {
315          while (!(ncsp->flags & CSP_FLAG_ACTIVE))
316          {
317             csp->next = ncsp->next;
318
319             freez(ncsp->ip_addr_str);
320             freez(ncsp->my_ip_addr_str);
321             freez(ncsp->my_hostname);
322             freez(ncsp->x_forwarded);
323             freez(ncsp->iob->buf);
324
325             free_http_request(ncsp->http);
326
327             destroy_list(ncsp->headers);
328             destroy_list(ncsp->cookie_list);
329
330             free_current_action(ncsp->action);
331
332 #ifdef FEATURE_STATISTICS
333             urls_read++;
334             if (ncsp->flags & CSP_FLAG_REJECTED)
335             {
336                urls_rejected++;
337             }
338 #endif /* def FEATURE_STATISTICS */
339
340             freez(ncsp);
341
342             /* are there any more in sequence after it? */
343             if( !(ncsp = csp->next) )
344                break;
345          }
346       }
347    }
348
349    for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
350    {
351       if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
352       {
353          fl->next = nfl->next;
354
355          (nfl->unloader)(nfl->f);
356
357          freez(nfl->filename);
358
359          freez(nfl);
360       }
361    }
362
363 }
364
365
366 /*********************************************************************
367  *
368  * Function    :  create_url_spec
369  *
370  * Description :  Creates a "url_spec" structure from a string.
371  *                When finished, free with unload_url().
372  *
373  * Parameters  :
374  *          1  :  url = Target url_spec to be filled in.  Must be
375  *                      zeroed out before the call (e.g. using zalloc).
376  *          2  :  buf = Source pattern, null terminated.  NOTE: The
377  *                      contents of this buffer are destroyed by this
378  *                      function.  If this function succeeds, the
379  *                      buffer is copied to url->spec.  If this
380  *                      function fails, the contents of the buffer
381  *                      are lost forever.
382  *
383  * Returns     :  JB_ERR_OK - Success
384  *                JB_ERR_MEMORY - Out of memory
385  *                JB_ERR_PARSE - Cannot parse regex (Detailed message
386  *                               written to system log)
387  *
388  *********************************************************************/
389 jb_err create_url_spec(struct url_spec * url, char * buf)
390 {
391    char *p;
392    struct url_spec tmp_url[1];
393
394    assert(url);
395    assert(buf);
396
397    /* save a copy of the orignal specification */
398    if ((url->spec = strdup(buf)) == NULL)
399    {
400       return JB_ERR_MEMORY;
401    }
402
403    if ((p = strchr(buf, '/')))
404    {
405       if (NULL == (url->path = strdup(p)))
406       {
407          freez(url->spec);
408          return JB_ERR_MEMORY;
409       }
410       url->pathlen = strlen(url->path);
411       *p = '\0';
412    }
413    else
414    {
415       url->path    = NULL;
416       url->pathlen = 0;
417    }
418 #ifdef REGEX
419    if (url->path)
420    {
421       int errcode;
422       char rebuf[BUFFER_SIZE];
423
424       if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
425       {
426          freez(url->spec);
427          freez(url->path);
428          return JB_ERR_MEMORY;
429       }
430
431       sprintf(rebuf, "^(%s)", url->path);
432
433       errcode = regcomp(url->preg, rebuf,
434             (REG_EXTENDED|REG_NOSUB|REG_ICASE));
435       if (errcode)
436       {
437          size_t errlen = regerror(errcode,
438             url->preg, rebuf, sizeof(rebuf));
439
440          if (errlen > (sizeof(rebuf) - (size_t)1))
441          {
442             errlen = sizeof(rebuf) - (size_t)1;
443          }
444          rebuf[errlen] = '\0';
445
446          log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
447             url->spec, rebuf);
448
449          freez(url->spec);
450          freez(url->path);
451          freez(url->preg);
452
453          return JB_ERR_PARSE;
454       }
455    }
456 #endif
457    if ((p = strchr(buf, ':')) == NULL)
458    {
459       url->port = 0;
460    }
461    else
462    {
463       *p++ = '\0';
464       url->port = atoi(p);
465    }
466
467    if ((url->domain = strdup(buf)) == NULL)
468    {
469       freez(url->spec);
470       freez(url->path);
471 #ifdef REGEX
472       freez(url->preg);
473 #endif /* def REGEX */
474       return JB_ERR_MEMORY;
475    }
476
477    /* split domain into components */
478
479    *tmp_url = dsplit(url->domain);
480    if (tmp_url->dbuf == NULL)
481    {
482       freez(url->spec);
483       freez(url->path);
484       freez(url->domain);
485 #ifdef REGEX
486       freez(url->preg);
487 #endif /* def REGEX */
488       return JB_ERR_MEMORY;
489    }
490
491    url->dbuf = tmp_url->dbuf;
492    url->dcnt = tmp_url->dcnt;
493    url->dvec = tmp_url->dvec;
494    url->unanchored = tmp_url->unanchored;
495
496    return JB_ERR_OK;
497
498 }
499
500
501 /*********************************************************************
502  *
503  * Function    :  free_url
504  *
505  * Description :  Called from the "unloaders".  Freez the url
506  *                structure elements.
507  *
508  * Parameters  :
509  *          1  :  url = pointer to a url_spec structure.
510  *
511  * Returns     :  N/A
512  *
513  *********************************************************************/
514 void free_url(struct url_spec *url)
515 {
516    if (url == NULL) return;
517
518    freez(url->spec);
519    freez(url->domain);
520    freez(url->dbuf);
521    freez(url->dvec);
522    freez(url->path);
523 #ifdef REGEX
524    if (url->preg)
525    {
526       regfree(url->preg);
527       freez(url->preg);
528    }
529 #endif
530
531 }
532
533
534 /*********************************************************************
535  *
536  * Function    :  check_file_changed
537  *
538  * Description :  Helper function to check if a file needs reloading.
539  *                If "current" is still current, return it.  Otherwise
540  *                allocates a new (zeroed) "struct file_list", fills
541  *                in the disk file name and timestamp, and returns it.
542  *
543  * Parameters  :
544  *          1  :  current = The file_list currently being used - will
545  *                          be checked to see if it is out of date.
546  *                          May be NULL (which is treated as out of
547  *                          date).
548  *          2  :  filename = Name of file to check.
549  *          3  :  newfl    = New file list. [Output only]
550  *                           This will be set to NULL, OR a struct
551  *                           file_list newly allocated on the
552  *                           heap, with the filename and lastmodified
553  *                           fields filled, and all others zeroed.
554  *
555  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
556  *                If file changed: 1 and sets newfl != NULL
557  *                On error: 1 and sets newfl == NULL
558  *
559  *********************************************************************/
560 int check_file_changed(const struct file_list * current,
561                        const char * filename,
562                        struct file_list ** newfl)
563 {
564    struct file_list *fs;
565    struct stat statbuf[1];
566
567    *newfl = NULL;
568
569    if (stat(filename, statbuf) < 0)
570    {
571       /* Error, probably file not found. */
572       return 1;
573    }
574
575    if (current
576        && (current->lastmodified == statbuf->st_mtime)
577        && (0 == strcmp(current->filename, filename)))
578    {
579        /* force reload of configfile and all the logs */
580        if ( !MustReload ) return 0;
581    }
582
583    fs = (struct file_list *)zalloc(sizeof(struct file_list));
584    if (fs == NULL)
585    {
586       /* Out of memory error */
587       return 1;
588    }
589
590    fs->filename = strdup(filename);
591    fs->lastmodified = statbuf->st_mtime;
592
593    if (fs->filename == NULL)
594    {
595       /* Out of memory error */
596       freez (fs);
597       return 1;
598    }
599    *newfl = fs;
600    return 1;
601 }
602
603
604 /*********************************************************************
605  *
606  * Function    :  read_config_line
607  *
608  * Description :  Read a single non-empty line from a file and return
609  *                it.  Trims comments, leading and trailing whitespace
610  *                and respects escaping of newline and comment char.
611  *
612  * Parameters  :
613  *          1  :  buf = Buffer to use.
614  *          2  :  buflen = Size of buffer in bytes.
615  *          3  :  fp = File to read from
616  *          4  :  linenum = linenumber in file
617  *
618  * Returns     :  NULL on EOF or error
619  *                Otherwise, returns buf.
620  *
621  *********************************************************************/
622 char *read_config_line(char *buf, int buflen, FILE *fp, unsigned long *linenum)
623 {
624    char *p;
625    char *src;
626    char *dest;
627    char linebuf[BUFFER_SIZE];
628    int contflag = 0;
629
630    *buf = '\0';
631
632    while (fgets(linebuf, sizeof(linebuf), fp))
633    {
634        (*linenum)++;
635       /* Trim off newline */
636       if ((p = strpbrk(linebuf, "\r\n")) != NULL)
637       {
638          *p = '\0';
639       }
640       else
641       {
642          p = linebuf + strlen(linebuf);
643       }
644
645       /* Line continuation? Trim escape and set flag. */
646       if ((p != linebuf) && (*--p == '\\'))
647       {
648          contflag = 1;
649          *p = '\0';
650       }
651
652       /* If there's a comment char.. */
653       p = linebuf;
654       while ((p = strchr(p, '#')) != NULL)
655       {
656          /* ..and it's escaped, left-shift the line over the escape. */
657          if ((p != linebuf) && (*(p-1) == '\\'))
658          {
659             src = p;
660             dest = p - 1;
661             while ((*dest++ = *src++) != '\0')
662             {
663                /* nop */
664             }
665             /* Now scan from just after the "#". */
666          }
667          /* Else, chop off the rest of the line */
668          else
669          {
670             *p = '\0';
671          }
672       }
673
674       /* Write to the buffer */
675       if (*linebuf)
676       {
677          strncat(buf, linebuf, buflen - strlen(buf));
678       }
679
680       /* Continue? */
681       if (contflag)
682       {
683          contflag = 0;
684          continue;
685       }
686
687       /* Remove leading and trailing whitespace */
688       chomp(buf);
689
690       if (*buf)
691       {
692          return buf;
693       }
694    }
695
696    /* EOF */
697    return NULL;
698
699 }
700
701
702 #ifdef FEATURE_TRUST
703 /*********************************************************************
704  *
705  * Function    :  unload_trustfile
706  *
707  * Description :  Unloads a trustfile.
708  *
709  * Parameters  :
710  *          1  :  f = the data structure associated with the trustfile.
711  *
712  * Returns     :  N/A
713  *
714  *********************************************************************/
715 static void unload_trustfile(void *f)
716 {
717    struct block_spec *b = (struct block_spec *)f;
718    if (b == NULL) return;
719
720    unload_trustfile(b->next); /* Stack is cheap, isn't it? */
721
722    free_url(b->url);
723
724    freez(b);
725
726 }
727
728
729 /*********************************************************************
730  *
731  * Function    :  load_trustfile
732  *
733  * Description :  Read and parse a trustfile and add to files list.
734  *
735  * Parameters  :
736  *          1  :  csp = Current client state (buffers, headers, etc...)
737  *
738  * Returns     :  0 => Ok, everything else is an error.
739  *
740  *********************************************************************/
741 int load_trustfile(struct client_state *csp)
742 {
743    FILE *fp;
744
745    struct block_spec *b, *bl;
746    struct url_spec **tl;
747
748    char  buf[BUFFER_SIZE], *p, *q;
749    int reject, trusted;
750    struct file_list *fs;
751    unsigned long linenum = 0;
752
753    if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
754    {
755       /* No need to load */
756       if (csp)
757       {
758          csp->tlist = current_trustfile;
759       }
760       return(0);
761    }
762    if (!fs)
763    {
764       goto load_trustfile_error;
765    }
766
767    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
768    if (bl == NULL)
769    {
770       goto load_trustfile_error;
771    }
772
773    if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
774    {
775       goto load_trustfile_error;
776    }
777
778    tl = csp->config->trust_list;
779
780    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
781    {
782       trusted = 0;
783       reject  = 1;
784
785       if (*buf == '+')
786       {
787          trusted = 1;
788          *buf = '~';
789       }
790
791       if (*buf == '~')
792       {
793          reject = 0;
794          p = buf;
795          q = p+1;
796          while ((*p++ = *q++))
797          {
798             /* nop */
799          }
800       }
801
802       /* skip blank lines */
803       if (*buf == '\0')
804       {
805          continue;
806       }
807
808       /* allocate a new node */
809       if ((b = zalloc(sizeof(*b))) == NULL)
810       {
811          fclose(fp);
812          goto load_trustfile_error;
813       }
814
815       /* add it to the list */
816       b->next  = bl->next;
817       bl->next = b;
818
819       b->reject = reject;
820
821       /* Save the URL pattern */
822       if (create_url_spec(b->url, buf))
823       {
824          fclose(fp);
825          goto load_trustfile_error;
826       }
827
828       /*
829        * save a pointer to URL's spec in the list of trusted URL's, too
830        */
831       if (trusted)
832       {
833          *tl++ = b->url;
834       }
835    }
836
837    *tl = NULL;
838
839    fclose(fp);
840
841    /* the old one is now obsolete */
842    if (current_trustfile)
843    {
844       current_trustfile->unloader = unload_trustfile;
845    }
846
847    fs->next    = files->next;
848    files->next = fs;
849    current_trustfile = fs;
850
851    if (csp)
852    {
853       csp->tlist = fs;
854    }
855
856    return(0);
857
858 load_trustfile_error:
859    log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
860              csp->config->trustfile);
861    return(-1);
862
863 }
864 #endif /* def FEATURE_TRUST */
865
866
867 /*********************************************************************
868  *
869  * Function    :  unload_re_filterfile
870  *
871  * Description :  Unload the re_filter list.
872  *
873  * Parameters  :
874  *          1  :  f = the data structure associated with the filterfile.
875  *
876  * Returns     :  N/A
877  *
878  *********************************************************************/
879 static void unload_re_filterfile(void *f)
880 {
881    struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
882
883    if (b == NULL)
884    {
885       return;
886    }
887
888    destroy_list(b->patterns);
889    pcrs_free_joblist(b->joblist);
890    freez(b);
891
892    return;
893 }
894
895 /*********************************************************************
896  *
897  * Function    :  load_re_filterfile
898  *
899  * Description :  Load the re_filterfile. Each non-comment, non-empty
900  *                line is instantly added to the joblist, which is
901  *                a chained list of pcrs_job structs.
902  *
903  * Parameters  :
904  *          1  :  csp = Current client state (buffers, headers, etc...)
905  *
906  * Returns     :  0 => Ok, everything else is an error.
907  *
908  *********************************************************************/
909 int load_re_filterfile(struct client_state *csp)
910 {
911    FILE *fp;
912
913    struct re_filterfile_spec *bl;
914    struct file_list *fs;
915
916    char  buf[BUFFER_SIZE];
917    int error;
918    unsigned long linenum = 0;
919    pcrs_job *dummy;
920
921    if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
922    {
923       /* No need to load */
924       if (csp)
925       {
926          csp->rlist = current_re_filterfile;
927       }
928       return(0);
929    }
930    if (!fs)
931    {
932       goto load_re_filterfile_error;
933    }
934
935    fs->f = bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
936    if (bl == NULL)
937    {
938       goto load_re_filterfile_error;
939    }
940
941    /* Open the file or fail */
942    if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
943    {
944       goto load_re_filterfile_error;
945    }
946
947    /* Read line by line */
948    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
949    {
950       enlist( bl->patterns, buf );
951
952       /* We have a meaningful line -> make it a job */
953       if ((dummy = pcrs_compile_command(buf, &error)) == NULL)
954       {
955          log_error(LOG_LEVEL_RE_FILTER,
956                "Adding re_filter job %s failed with error %d.", buf, error);
957          continue;
958       }
959       else
960       {
961          dummy->next = bl->joblist;
962          bl->joblist = dummy;
963          log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
964       }
965    }
966
967    fclose(fp);
968
969    /* the old one is now obsolete */
970    if ( NULL != current_re_filterfile )
971    {
972       current_re_filterfile->unloader = unload_re_filterfile;
973    }
974
975    fs->next    = files->next;
976    files->next = fs;
977    current_re_filterfile = fs;
978
979    if (csp)
980    {
981       csp->rlist = fs;
982    }
983
984    return( 0 );
985
986 load_re_filterfile_error:
987    log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
988              csp->config->re_filterfile);
989    return(-1);
990
991 }
992
993
994 /*********************************************************************
995  *
996  * Function    :  add_loader
997  *
998  * Description :  Called from `load_config'.  Called once for each input
999  *                file found in config.
1000  *
1001  * Parameters  :
1002  *          1  :  loader = pointer to a function that can parse and load
1003  *                the appropriate config file.
1004  *          2  :  config = The configuration_spec to add the loader to.
1005  *
1006  * Returns     :  N/A
1007  *
1008  *********************************************************************/
1009 void add_loader(int (*loader)(struct client_state *),
1010                 struct configuration_spec * config)
1011 {
1012    int i;
1013
1014    for (i=0; i < NLOADERS; i++)
1015    {
1016       if (config->loaders[i] == NULL)
1017       {
1018          config->loaders[i] = loader;
1019          break;
1020       }
1021    }
1022
1023 }
1024
1025
1026 /*********************************************************************
1027  *
1028  * Function    :  run_loader
1029  *
1030  * Description :  Called from `load_config' and `listen_loop'.  This
1031  *                function keeps the "csp" current with any file mods
1032  *                since the last loop.  If a file is unchanged, the
1033  *                loader functions do NOT reload the file.
1034  *
1035  * Parameters  :
1036  *          1  :  csp = Current client state (buffers, headers, etc...)
1037  *                      Must be non-null.  Reads: "csp->config"
1038  *                      Writes: various data members.
1039  *
1040  * Returns     :  0 => Ok, everything else is an error.
1041  *
1042  *********************************************************************/
1043 int run_loader(struct client_state *csp)
1044 {
1045    int ret = 0;
1046    int i;
1047
1048    for (i=0; i < NLOADERS; i++)
1049    {
1050       if (csp->config->loaders[i] == NULL)
1051       {
1052          break;
1053       }
1054       ret |= (csp->config->loaders[i])(csp);
1055    }
1056    return(ret);
1057
1058 }
1059
1060
1061 /*
1062   Local Variables:
1063   tab-width: 3
1064   end:
1065 */