Changed to include many of the new actions.
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.12 2001/05/31 17:32:31 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/loaders.c,v $
5  *
6  * Purpose     :  Functions to load and unload the various
7  *                configuration files.  Also contains code to manage
8  *                the list of active loaders, and to automatically 
9  *                unload files that are no longer in use.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
12  *                IJBSWA team.  http://ijbswa.sourceforge.net
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and 
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it 
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: loaders.c,v $
38  *    Revision 1.12  2001/05/31 17:32:31  oes
39  *
40  *     - Enhanced domain part globbing with infix and prefix asterisk
41  *       matching and optional unanchored operation
42  *
43  *    Revision 1.11  2001/05/29 23:25:24  oes
44  *
45  *     - load_config_line() and load_permissions_file() now use chomp()
46  *
47  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
48  *    Unified blocklist/imagelist/permissionslist.
49  *    File format is still under discussion, but the internal changes
50  *    are (mostly) done.
51  *
52  *    Also modified interceptor behaviour:
53  *    - We now intercept all URLs beginning with one of the following
54  *      prefixes (and *only* these prefixes):
55  *        * http://i.j.b/
56  *        * http://ijbswa.sf.net/config/
57  *        * http://ijbswa.sourceforge.net/config/
58  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
59  *    - Internal changes so that intercepted and fast redirect pages
60  *      are not replaced with an image.
61  *    - Interceptors now have the option to send a binary page direct
62  *      to the client. (i.e. ijb-send-banner uses this)
63  *    - Implemented show-url-info interceptor.  (Which is why I needed
64  *      the above interceptors changes - a typical URL is
65  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
66  *      The previous mechanism would not have intercepted that, and
67  *      if it had been intercepted then it then it would have replaced
68  *      it with an image.)
69  *
70  *    Revision 1.9  2001/05/26 17:12:07  jongfoster
71  *    Fatal errors loading configuration files now give better error messages.
72  *
73  *    Revision 1.8  2001/05/26 00:55:20  jongfoster
74  *    Removing duplicated code.  load_forwardfile() now uses create_url_spec()
75  *
76  *    Revision 1.7  2001/05/26 00:28:36  jongfoster
77  *    Automatic reloading of config file.
78  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
79  *    Most of the global variables have been moved to a new
80  *    struct configuration_spec, accessed through csp->config->globalname
81  *    Most of the globals remaining are used by the Win32 GUI.
82  *
83  *    Revision 1.6  2001/05/23 12:27:33  oes
84  *
85  *    Fixed ugly indentation of my last changes
86  *
87  *    Revision 1.5  2001/05/23 10:39:05  oes
88  *    - Added support for escaping the comment character
89  *      in config files by a backslash
90  *    - Added support for line continuation in config
91  *      files
92  *    - Fixed a buffer overflow bug with long config lines
93  *
94  *    Revision 1.4  2001/05/22 18:56:28  oes
95  *    CRLF -> LF
96  *
97  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
98  *    Version 2.9.4 checkin.
99  *    - Merged popupfile and cookiefile, and added control over PCRS
100  *      filtering, in new "permissionsfile".
101  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
102  *      file error you now get a message box (in the Win32 GUI) rather
103  *      than the program exiting with no explanation.
104  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
105  *      skipping.
106  *    - Removed tabs from "config"
107  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
108  *    - Bumped up version number.
109  *
110  *    Revision 1.2  2001/05/17 23:01:01  oes
111  *     - Cleaned CRLF's from the sources and related files
112  *
113  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
114  *    Initial import of version 2.9.3 source tree
115  *
116  *
117  *********************************************************************/
118 \f
119
120 #include "config.h"
121
122 #include <stdio.h>
123 #include <stdlib.h>
124 #include <sys/types.h>
125 #include <string.h>
126 #include <malloc.h>
127 #include <errno.h>
128 #include <sys/stat.h>
129 #include <ctype.h>
130
131 #ifndef _WIN32
132 #include <unistd.h>
133 #endif
134
135 #include "project.h"
136 #include "list.h"
137 #include "loaders.h"
138 #include "encode.h"
139 #include "filters.h"
140 #include "parsers.h"
141 #include "jcc.h"
142 #include "ssplit.h"
143 #include "miscutil.h"
144 #include "errlog.h"
145 #include "gateway.h"
146 #include "actions.h"
147
148 #ifndef SPLIT_PROXY_ARGS
149 /* For strsav */
150 #include "showargs.h"
151 #endif /* ndef SPLIT_PROXY_ARGS */
152
153 const char loaders_h_rcs[] = LOADERS_H_VERSION;
154
155 /* Fix a problem with Solaris.  There should be no effect on other
156  * platforms.
157  * Solaris's isspace() is a macro which uses it's argument directly
158  * as an array index.  Therefore we need to make sure that high-bit
159  * characters generate +ve values, and ideally we also want to make
160  * the argument match the declared parameter type of "int".
161  */
162 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
163
164
165 /*
166  * Currently active files.
167  * These are also entered in the main linked list of files.
168  */
169 static struct file_list *current_forwardfile    = NULL;
170
171 #ifdef ACL_FILES
172 static struct file_list *current_aclfile        = NULL;
173 #endif /* def ACL_FILES */
174
175 #ifdef TRUST_FILES
176 static struct file_list *current_trustfile      = NULL;
177 #endif /* def TRUST_FILES */
178
179 #ifdef PCRS
180 static struct file_list *current_re_filterfile  = NULL;
181 #endif /* def PCRS */
182
183
184 /*********************************************************************
185  *
186  * Function    :  sweep
187  *
188  * Description :  Basically a mark and sweep garbage collector, it is run
189  *                (by the parent thread) every once in a while to reclaim memory.
190  *
191  * It uses a mark and sweep strategy:
192  *   1) mark all files as inactive
193  *
194  *   2) check with each client:
195  *       if it is active,   mark its files as active
196  *       if it is inactive, free its resources
197  *
198  *   3) free the resources of all of the files that
199  *      are still marked as inactive (and are obsolete).
200  *
201  *   N.B. files that are not obsolete don't have an unloader defined.
202  *
203  * Parameters  :  None
204  *
205  * Returns     :  N/A
206  *
207  *********************************************************************/
208 void sweep(void)
209 {
210    struct file_list *fl, *nfl;
211    struct client_state *csp, *ncsp;
212
213    /* clear all of the file's active flags */
214    for ( fl = files->next; NULL != fl; fl = fl->next )
215    {
216       fl->active = 0;
217    }
218
219    for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
220    {
221       if (ncsp->active)
222       {
223          /* mark this client's files as active */
224
225          /*
226           * Always have a configuration file.
227           * (Also note the slightly non-standard extra
228           * indirection here.)
229           */
230          ncsp->config->config_file_list->active = 1;
231
232          if (ncsp->actions_list)     /* actions files */
233          {
234             ncsp->actions_list->active = 1;
235          }
236
237          if (ncsp->flist)     /* forward files */
238          {
239             ncsp->flist->active = 1;
240          }
241
242 #ifdef ACL_FILES
243          if (ncsp->alist)     /* acl files */
244          {
245             ncsp->alist->active = 1;
246          }
247 #endif /* def ACL_FILES */
248
249 #ifdef PCRS
250          if (ncsp->rlist)     /* perl re files */
251          {
252             ncsp->rlist->active = 1;
253          }
254 #endif /* def PCRS */
255
256 #ifdef TRUST_FILES
257          if (ncsp->tlist)     /* trust files */
258          {
259             ncsp->tlist->active = 1;
260          }
261 #endif /* def TRUST_FILES */
262
263       }
264       else
265       {
266          /* this client one is not active, release its resources */
267          csp->next = ncsp->next;
268
269          freez(ncsp->ip_addr_str);
270 #ifdef TRUST_FILES
271          freez(ncsp->referrer);
272 #endif /* def TRUST_FILES */
273          freez(ncsp->x_forwarded);
274          freez(ncsp->iob->buf);
275
276          free_http_request(ncsp->http);
277
278          destroy_list(ncsp->headers);
279          destroy_list(ncsp->cookie_list);
280
281          free_current_action(ncsp->action);
282
283 #ifdef STATISTICS
284          urls_read++;
285          if (ncsp->rejected)
286          {
287             urls_rejected++;
288          }
289 #endif /* def STATISTICS */
290
291          freez(ncsp);
292       }
293    }
294
295    for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
296    {
297       if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
298       {
299          fl->next = nfl->next;
300
301          (nfl->unloader)(nfl->f);
302
303 #ifndef SPLIT_PROXY_ARGS
304          freez(nfl->proxy_args);
305 #endif /* ndef SPLIT_PROXY_ARGS */
306
307          freez(nfl->filename);
308
309          freez(nfl);
310       }
311    }
312
313 }
314
315
316 /*********************************************************************
317  *
318  * Function    :  create_url_spec
319  *
320  * Description :  Creates a "url_spec" structure from a string.
321  *                When finished, free with unload_url().
322  *
323  * Parameters  :
324  *          1  :  url = Target url_spec to be filled in.  Must be
325  *                      zeroed out before the call (e.g. using zalloc).
326  *          2  :  buf = Source pattern, null terminated.  NOTE: The
327  *                      contents of this buffer are destroyed by this
328  *                      function.  If this function succeeds, the
329  *                      buffer is copied to url->spec.  If this
330  *                      function fails, the contents of the buffer
331  *                      are lost forever.
332  *
333  * Returns     :  0 => Ok, everything else is an error.
334  *
335  *********************************************************************/
336 int create_url_spec(struct url_spec * url, char * buf)
337 {
338    char *p;
339    struct url_spec tmp_url[1];
340
341    /* paranoia - should never happen. */
342    if ((url == NULL) || (buf == NULL))
343    {
344       return 1;
345    }
346
347    /* save a copy of the orignal specification */
348    if ((url->spec = strdup(buf)) == NULL)
349    {
350       return 1;
351    }
352
353    if ((p = strchr(buf, '/')))
354    {
355       if (NULL == (url->path = strdup(p)))
356       {
357          freez(url->spec);
358          return 1;
359       }
360       url->pathlen = strlen(url->path);
361       *p = '\0';
362    }
363    else
364    {
365       url->path    = NULL;
366       url->pathlen = 0;
367    }
368 #ifdef REGEX
369    if (url->path)
370    {
371       int errcode;
372       char rebuf[BUFSIZ];
373
374       if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
375       {
376          freez(url->spec);
377          freez(url->path);
378          return 1;
379       }
380
381       sprintf(rebuf, "^(%s)", url->path);
382
383       errcode = regcomp(url->preg, rebuf,
384             (REG_EXTENDED|REG_NOSUB|REG_ICASE));
385       if (errcode)
386       {
387          size_t errlen =
388             regerror(errcode,
389                url->preg, buf, sizeof(buf));
390
391          buf[errlen] = '\0';
392
393          log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
394                  url->spec, buf);
395
396          freez(url->spec);
397          freez(url->path);
398          freez(url->preg);
399
400          return 1;
401       }
402    }
403 #endif
404    if ((p = strchr(buf, ':')) == NULL)
405    {
406       url->port = 0;
407    }
408    else
409    {
410       *p++ = '\0';
411       url->port = atoi(p);
412    }
413
414    if ((url->domain = strdup(buf)) == NULL)
415    {
416       freez(url->spec);
417       freez(url->path);
418 #ifdef REGEX
419       freez(url->preg);
420 #endif /* def REGEX */
421       return 1;
422    }
423
424    /* split domain into components */
425
426    *tmp_url = dsplit(url->domain);
427    url->dbuf = tmp_url->dbuf;
428    url->dcnt = tmp_url->dcnt;
429    url->dvec = tmp_url->dvec;
430    url->unanchored = tmp_url->unanchored;
431
432    return 0; /* OK */
433 }
434
435
436 /*********************************************************************
437  *
438  * Function    :  free_url
439  *
440  * Description :  Called from the "unloaders".  Freez the url
441  *                structure elements.
442  *
443  * Parameters  :
444  *          1  :  url = pointer to a url_spec structure.
445  *
446  * Returns     :  N/A
447  *
448  *********************************************************************/
449 void free_url(struct url_spec *url)
450 {
451    if (url == NULL) return;
452
453    freez(url->spec);
454    freez(url->domain);
455    freez(url->dbuf);
456    freez(url->dvec);
457    freez(url->path);
458 #ifdef REGEX
459    if (url->preg)
460    {
461       regfree(url->preg);
462       freez(url->preg);
463    }
464 #endif
465
466 }
467
468
469 #ifdef ACL_FILES
470 /*********************************************************************
471  *
472  * Function    :  unload_aclfile
473  *
474  * Description :  Unloads an aclfile.
475  *
476  * Parameters  :
477  *          1  :  f = the data structure associated with the aclfile.
478  *
479  * Returns     :  N/A
480  *
481  *********************************************************************/
482 static void unload_aclfile(void *f)
483 {
484    struct access_control_list *b = (struct access_control_list *)f;
485    if (b == NULL) return;
486
487    unload_aclfile(b->next);
488
489    freez(b);
490
491 }
492 #endif /* def ACL_FILES */
493
494
495 #ifdef TRUST_FILES
496 /*********************************************************************
497  *
498  * Function    :  unload_trustfile
499  *
500  * Description :  Unloads a trustfile.
501  *
502  * Parameters  :
503  *          1  :  f = the data structure associated with the trustfile.
504  *
505  * Returns     :  N/A
506  *
507  *********************************************************************/
508 static void unload_trustfile(void *f)
509 {
510    struct block_spec *b = (struct block_spec *)f;
511    if (b == NULL) return;
512
513    unload_trustfile(b->next);
514
515    free_url(b->url);
516
517    freez(b);
518
519 }
520 #endif /* def TRUST_FILES */
521
522
523 /*********************************************************************
524  *
525  * Function    :  unload_forwardfile
526  *
527  * Description :  Unloads a forwardfile.
528  *
529  * Parameters  :
530  *          1  :  f = the data structure associated with the forwardfile.
531  *
532  * Returns     :  N/A
533  *
534  *********************************************************************/
535 static void unload_forwardfile(void *f)
536 {
537    struct forward_spec *b = (struct forward_spec *)f;
538    if (b == NULL) return;
539
540    unload_forwardfile(b->next);
541
542    free_url(b->url);
543
544    freez(b->gw->gateway_host);
545    freez(b->gw->forward_host);
546
547    freez(b);
548
549 }
550
551
552 #ifdef PCRS
553 /*********************************************************************
554  *
555  * Function    :  unload_re_filterfile
556  *
557  * Description :  Unload the re_filter list.
558  *
559  * Parameters  :
560  *          1  :  f = the data structure associated with the filterfile.
561  *
562  * Returns     :  N/A
563  *
564  *********************************************************************/
565 static void unload_re_filterfile(void *f)
566 {
567    pcrs_job *joblist;
568    struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
569
570    if (b == NULL) return;
571
572    destroy_list(b->patterns);
573
574    joblist = b->joblist;
575    while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
576
577    freez(b);
578
579 }
580 #endif /* def PCRS */
581
582
583 /*********************************************************************
584  *
585  * Function    :  check_file_changed
586  *
587  * Description :  Helper function to check if a file needs reloading.
588  *                If "current" is still current, return it.  Otherwise
589  *                allocates a new (zeroed) "struct file_list", fills 
590  *                in the disk file name and timestamp, and returns it.
591  *
592  * Parameters  :
593  *          1  :  current = The file_list currently being used - will
594  *                          be checked to see if it is out of date. 
595  *                          May be NULL (which is treated as out of
596  *                          date).
597  *          2  :  filename = Name of file to check.
598  *          3  :  newfl    = New file list. [Output only]
599  *                           This will be set to NULL, OR a struct
600  *                           file_list newly allocated on the
601  *                           heap, with the filename and lastmodified
602  *                           fields filled, standard header giving file
603  *                           name in proxy_args, and all others zeroed.
604  *                           (proxy_args is only filled in if !defined
605  *                           SPLIT_PROXY_ARGS and !suppress_blocklists).
606  *
607  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
608  *                If file changed: 1 and sets newfl != NULL
609  *                On error: 1 and sets newfl == NULL
610  *
611  *********************************************************************/
612 int check_file_changed(const struct file_list * current,
613                        const char * filename,
614                        struct file_list ** newfl)
615 {
616    struct file_list *fs;
617    struct stat statbuf[1];
618
619    *newfl = NULL;
620
621    if (stat(filename, statbuf) < 0)
622    {
623       /* Error, probably file not found. */
624       return 1;
625    }
626
627    if (current
628        && (current->lastmodified == statbuf->st_mtime)
629        && (0 == strcmp(current->filename, filename)))
630    {
631       return 0;
632    }
633
634    fs = (struct file_list *)zalloc(sizeof(struct file_list));
635
636    if (fs == NULL)
637    {
638       /* Out of memory error */
639       return 1;
640    }
641
642    fs->filename = strdup(filename);
643    fs->lastmodified = statbuf->st_mtime;
644
645    if (fs->filename == NULL)
646    {
647       /* Out of memory error */
648       freez (fs);
649       return 1;
650    }
651
652 #ifndef SPLIT_PROXY_ARGS
653    if (!suppress_blocklists)
654    {
655       char * p = html_encode(filename);
656       if (p)
657       {
658          fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
659          fs->proxy_args = strsav(fs->proxy_args, p);
660          fs->proxy_args = strsav(fs->proxy_args, 
661             "' contains the following patterns</h2>\n");
662          freez(p);
663       }
664       fs->proxy_args = strsav(fs->proxy_args, "<pre>");
665    }
666 #endif /* ndef SPLIT_PROXY_ARGS */
667
668    *newfl = fs;
669    return 1;
670 }
671
672
673 /*********************************************************************
674  *
675  * Function    :  read_config_line
676  *
677  * Description :  Read a single non-empty line from a file and return
678  *                it.  Trims comments, leading and trailing whitespace
679  *                and respects escaping of newline and comment char.
680  *                Also writes the file to fs->proxy_args.
681  *
682  * Parameters  :
683  *          1  :  buf = Buffer to use.
684  *          2  :  buflen = Size of buffer in bytes.
685  *          3  :  fp = File to read from
686  *          4  :  fs = File will be written to fs->proxy_args.  May
687  *                be NULL to disable this feature.
688  *
689  * Returns     :  NULL on EOF or error
690  *                Otherwise, returns buf.
691  *
692  *********************************************************************/
693 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
694 {
695    char *p, *q;
696    char linebuf[BUFSIZ];
697    int contflag = 0;
698
699    *buf = '\0';
700
701    while (fgets(linebuf, sizeof(linebuf), fp))
702    {
703 #ifndef SPLIT_PROXY_ARGS
704       if (fs && !suppress_blocklists)
705       {
706          char *html_line = html_encode(linebuf);
707          if (html_line != NULL)
708          {
709             fs->proxy_args = strsav(fs->proxy_args, html_line);
710             freez(html_line);
711          }
712          fs->proxy_args = strsav(fs->proxy_args, "<br>");
713       }
714 #endif /* ndef SPLIT_PROXY_ARGS */
715
716       /* Trim off newline */
717       if ((p = strpbrk(linebuf, "\r\n")) != NULL)
718       {
719          *p = '\0';
720       }
721
722       /* Line continuation? Trim escape and set flag. */
723       if ((p != linebuf) && (*--p == '\\'))
724       {
725          contflag = 1;
726          *p = '\0';
727       }
728
729       /* If there's a comment char.. */
730       if ((p = strpbrk(linebuf, "#")) != NULL)
731       {
732          /* ..and it's escaped, left-shift the line over the escape. */
733          if ((p != linebuf) && (*(p-1) == '\\'))
734          {
735             q = p-1;
736             while ((*q++ = *p++) != '\0') /* nop */;
737          }
738          /* Else, chop off the rest of the line */
739          else
740          {
741             *p = '\0';
742          }
743       }
744       
745       /* Remove leading and trailing whitespace */
746       chomp(linebuf);
747
748       if (*linebuf)
749       {
750          strncat(buf, linebuf, buflen - strlen(buf));
751          if (contflag)
752          {
753             contflag = 0;
754             continue;
755          }
756          else
757          {
758             return buf;
759          }
760       }
761    }
762    /* EOF */
763    return NULL;
764
765 }
766
767
768 #ifdef ACL_FILES
769 /*********************************************************************
770  *
771  * Function    :  load_aclfile
772  *
773  * Description :  Read and parse an aclfile and add to files list.
774  *
775  * Parameters  :
776  *          1  :  csp = Current client state (buffers, headers, etc...)
777  *
778  * Returns     :  0 => Ok, everything else is an error.
779  *
780  *********************************************************************/
781 int load_aclfile(struct client_state *csp)
782 {
783    FILE *fp;
784    char buf[BUFSIZ], *v[3], *p;
785    int i;
786    struct access_control_list *a, *bl;
787    struct file_list *fs;
788
789    if (!check_file_changed(current_aclfile, csp->config->aclfile, &fs))
790    {
791       /* No need to load */
792       if (csp)
793       {
794          csp->alist = current_aclfile;
795       }
796       return(0);
797    }
798    if (!fs)
799    {
800       goto load_aclfile_error;
801    }
802
803    fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
804    if (bl == NULL)
805    {
806       freez(fs->filename);
807       freez(fs);
808       goto load_aclfile_error;
809    }
810
811    fp = fopen(csp->config->aclfile, "r");
812
813    if (fp == NULL)
814    {
815       goto load_aclfile_error;
816    }
817
818    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
819    {
820       i = ssplit(buf, " \t", v, SZ(v), 1, 1);
821
822       /* allocate a new node */
823       a = (struct access_control_list *) zalloc(sizeof(*a));
824
825       if (a == NULL)
826       {
827          fclose(fp);
828          freez(fs->f);
829          freez(fs->filename);
830          freez(fs);
831          goto load_aclfile_error;
832       }
833
834       /* add it to the list */
835       a->next  = bl->next;
836       bl->next = a;
837
838       switch (i)
839       {
840          case 3:
841             if (acl_addr(v[2], a->dst) < 0)
842             {
843                goto load_aclfile_error;
844             }
845             /* no break */
846
847          case 2:
848             if (acl_addr(v[1], a->src) < 0)
849             {
850                goto load_aclfile_error;
851             }
852
853             p = v[0];
854             if (strcmpic(p, "permit") == 0)
855             {
856                a->action = ACL_PERMIT;
857                break;
858             }
859
860             if (strcmpic(p, "deny") == 0)
861             {
862                a->action = ACL_DENY;
863                break;
864             }
865             /* no break */
866
867          default:
868             goto load_aclfile_error;
869       }
870    }
871
872    fclose(fp);
873
874 #ifndef SPLIT_PROXY_ARGS
875    if (!suppress_blocklists)
876    {
877       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
878    }
879 #endif /* ndef SPLIT_PROXY_ARGS */
880
881    if (current_aclfile)
882    {
883       current_aclfile->unloader = unload_aclfile;
884    }
885
886    fs->next = files->next;
887    files->next = fs;
888    current_aclfile = fs;
889
890    if (csp)
891    {
892       csp->alist = fs;
893    }
894
895    return(0);
896
897 load_aclfile_error:
898    log_error(LOG_LEVEL_FATAL, "can't load access control list %s: %E",
899              csp->config->aclfile);
900    return(-1);
901
902 }
903 #endif /* def ACL_FILES */
904
905
906 #ifdef TRUST_FILES
907 /*********************************************************************
908  *
909  * Function    :  load_trustfile
910  *
911  * Description :  Read and parse a trustfile and add to files list.
912  *
913  * Parameters  :
914  *          1  :  csp = Current client state (buffers, headers, etc...)
915  *
916  * Returns     :  0 => Ok, everything else is an error.
917  *
918  *********************************************************************/
919 int load_trustfile(struct client_state *csp)
920 {
921    FILE *fp;
922
923    struct block_spec *b, *bl;
924    struct url_spec **tl;
925
926    char  buf[BUFSIZ], *p, *q;
927    int reject, trusted;
928    struct file_list *fs;
929
930    if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
931    {
932       /* No need to load */
933       if (csp)
934       {
935          csp->tlist = current_trustfile;
936       }
937       return(0);
938    }
939    if (!fs)
940    {
941       goto load_trustfile_error;
942    }
943
944    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
945    if (bl == NULL)
946    {
947       goto load_trustfile_error;
948    }
949
950    if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
951    {
952       goto load_trustfile_error;
953    }
954
955    tl = csp->config->trust_list;
956
957    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
958    {
959       trusted = 0;
960       reject  = 1;
961
962       if (*buf == '+')
963       {
964          trusted = 1;
965          *buf = '~';
966       }
967
968       if (*buf == '~')
969       {
970          reject = 0;
971          p = buf;
972          q = p+1;
973          while ((*p++ = *q++))
974          {
975             /* nop */
976          }
977       }
978
979       /* skip blank lines */
980       if (*buf == '\0')
981       {
982          continue;
983       }
984
985       /* allocate a new node */
986       if ((b = zalloc(sizeof(*b))) == NULL)
987       {
988          fclose(fp);
989          goto load_trustfile_error;
990       }
991
992       /* add it to the list */
993       b->next  = bl->next;
994       bl->next = b;
995
996       b->reject = reject;
997
998       /* Save the URL pattern */
999       if (create_url_spec(b->url, buf))
1000       {
1001          fclose(fp);
1002          goto load_trustfile_error;
1003       }
1004
1005       /*
1006        * save a pointer to URL's spec in the list of trusted URL's, too
1007        */
1008       if (trusted)
1009       {
1010          *tl++ = b->url;
1011       }
1012    }
1013
1014    *tl = NULL;
1015
1016    fclose(fp);
1017
1018 #ifndef SPLIT_PROXY_ARGS
1019    if (!suppress_blocklists)
1020    {
1021       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1022    }
1023 #endif /* ndef SPLIT_PROXY_ARGS */
1024
1025    /* the old one is now obsolete */
1026    if (current_trustfile)
1027    {
1028       current_trustfile->unloader = unload_trustfile;
1029    }
1030
1031    fs->next    = files->next;
1032    files->next = fs;
1033    current_trustfile = fs;
1034
1035    if (csp)
1036    {
1037       csp->tlist = fs;
1038    }
1039
1040    return(0);
1041
1042 load_trustfile_error:
1043    log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1044              csp->config->trustfile);
1045    return(-1);
1046
1047 }
1048 #endif /* def TRUST_FILES */
1049
1050
1051 /*********************************************************************
1052  *
1053  * Function    :  load_forwardfile
1054  *
1055  * Description :  Read and parse a forwardfile and add to files list.
1056  *
1057  * Parameters  :
1058  *          1  :  csp = Current client state (buffers, headers, etc...)
1059  *
1060  * Returns     :  0 => Ok, everything else is an error.
1061  *
1062  *********************************************************************/
1063 int load_forwardfile(struct client_state *csp)
1064 {
1065    FILE *fp;
1066
1067    struct forward_spec *b, *bl;
1068    char buf[BUFSIZ];
1069    char *p, *tmp;
1070    char *vec[4];
1071    int n;
1072    struct file_list *fs;
1073    const struct gateway *gw;
1074
1075    if (!check_file_changed(current_forwardfile, csp->config->forwardfile, &fs))
1076    {
1077       /* No need to load */
1078       if (csp)
1079       {
1080          csp->flist = current_forwardfile;
1081       }
1082       return(0);
1083    }
1084    if (!fs)
1085    {
1086       goto load_forwardfile_error;
1087    }
1088
1089    fs->f = bl = (struct forward_spec  *)zalloc(sizeof(*bl));
1090
1091    if ((fs == NULL) || (bl == NULL))
1092    {
1093       goto load_forwardfile_error;
1094    }
1095
1096    if ((fp = fopen(csp->config->forwardfile, "r")) == NULL)
1097    {
1098       goto load_forwardfile_error;
1099    }
1100
1101    tmp = NULL;
1102
1103    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1104    {
1105       freez(tmp);
1106
1107       tmp = strdup(buf);
1108
1109       n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1110
1111       if (n != 4)
1112       {
1113          log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1114          continue;
1115       }
1116
1117       strcpy(buf, vec[0]);
1118
1119       /* skip lines containing only ~ */
1120       if (*buf == '\0')
1121       {
1122          continue;
1123       }
1124
1125       /* allocate a new node */
1126       if (((b = zalloc(sizeof(*b))) == NULL)
1127       )
1128       {
1129          fclose(fp);
1130          goto load_forwardfile_error;
1131       }
1132
1133       /* add it to the list */
1134       b->next  = bl->next;
1135       bl->next = b;
1136
1137       /* Save the URL pattern */
1138       if (create_url_spec(b->url, buf))
1139       {
1140          fclose(fp);
1141          goto load_forwardfile_error;
1142       }
1143
1144       /* now parse the gateway specs */
1145
1146       p = vec[2];
1147
1148       for (gw = gateways; gw->name; gw++)
1149       {
1150          if (strcmp(gw->name, p) == 0)
1151          {
1152             break;
1153          }
1154       }
1155
1156       if (gw->name == NULL)
1157       {
1158          goto load_forwardfile_error;
1159       }
1160
1161       /* save this as the gateway type */
1162       *b->gw = *gw;
1163
1164       /* now parse the gateway host[:port] spec */
1165       p = vec[3];
1166
1167       if (strcmp(p, ".") != 0)
1168       {
1169          b->gw->gateway_host = strdup(p);
1170
1171          if ((p = strchr(b->gw->gateway_host, ':')))
1172          {
1173             *p++ = '\0';
1174             b->gw->gateway_port = atoi(p);
1175          }
1176
1177          if (b->gw->gateway_port <= 0)
1178          {
1179             goto load_forwardfile_error;
1180          }
1181       }
1182
1183       /* now parse the forwarding spec */
1184       p = vec[1];
1185
1186       if (strcmp(p, ".") != 0)
1187       {
1188          b->gw->forward_host = strdup(p);
1189
1190          if ((p = strchr(b->gw->forward_host, ':')))
1191          {
1192             *p++ = '\0';
1193             b->gw->forward_port = atoi(p);
1194          }
1195
1196          if (b->gw->forward_port <= 0)
1197          {
1198             b->gw->forward_port = 8000;
1199          }
1200       }
1201    }
1202
1203    freez(tmp);
1204
1205    fclose(fp);
1206
1207 #ifndef SPLIT_PROXY_ARGS
1208    if (!suppress_blocklists)
1209    {
1210       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1211    }
1212 #endif /* ndef SPLIT_PROXY_ARGS */
1213
1214    /* the old one is now obsolete */
1215    if (current_forwardfile)
1216    {
1217       current_forwardfile->unloader = unload_forwardfile;
1218    }
1219
1220    fs->next    = files->next;
1221    files->next = fs;
1222    current_forwardfile = fs;
1223
1224    if (csp)
1225    {
1226       csp->flist = fs;
1227    }
1228
1229    return(0);
1230
1231 load_forwardfile_error:
1232    log_error(LOG_LEVEL_FATAL, "can't load forwardfile '%s': %E",
1233              csp->config->forwardfile);
1234    return(-1);
1235
1236 }
1237
1238
1239 #ifdef PCRS
1240 /*********************************************************************
1241  *
1242  * Function    :  load_re_filterfile
1243  *
1244  * Description :  Load the re_filterfile. Each non-comment, non-empty
1245  *                line is instantly added to the joblist, which is
1246  *                a chained list of pcrs_job structs.
1247  *
1248  * Parameters  :
1249  *          1  :  csp = Current client state (buffers, headers, etc...)
1250  *
1251  * Returns     :  0 => Ok, everything else is an error.
1252  *
1253  *********************************************************************/
1254 int load_re_filterfile(struct client_state *csp)
1255 {
1256    FILE *fp;
1257
1258    struct re_filterfile_spec *bl;
1259    struct file_list *fs;
1260
1261    char  buf[BUFSIZ];
1262    int error;
1263    pcrs_job *dummy;
1264
1265    if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1266    {
1267       /* No need to load */
1268       if (csp)
1269       {
1270          csp->rlist = current_re_filterfile;
1271       }
1272       return(0);
1273    }
1274    if (!fs)
1275    {
1276       goto load_re_filterfile_error;
1277    }
1278
1279    fs->f = bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
1280    if (bl == NULL)
1281    {
1282       goto load_re_filterfile_error;
1283    }
1284
1285    /* Open the file or fail */
1286    if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1287    {
1288       goto load_re_filterfile_error;
1289    }
1290
1291    /* Read line by line */
1292    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1293    {
1294       enlist( bl->patterns, buf );
1295
1296       /* We have a meaningful line -> make it a job */
1297       if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1298       {
1299          log_error(LOG_LEVEL_RE_FILTER, 
1300                "Adding re_filter job %s failed with error %d.", buf, error);
1301          continue;
1302       }
1303       else
1304       {
1305          dummy->next = bl->joblist;
1306          bl->joblist = dummy;
1307          log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1308       }
1309    }
1310
1311    fclose(fp);
1312
1313 #ifndef SPLIT_PROXY_ARGS
1314    if (!suppress_blocklists)
1315    {
1316       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1317    }
1318 #endif /* ndef SPLIT_PROXY_ARGS */
1319
1320    /* the old one is now obsolete */
1321    if ( NULL != current_re_filterfile )
1322    {
1323       current_re_filterfile->unloader = unload_re_filterfile;
1324    }
1325
1326    fs->next    = files->next;
1327    files->next = fs;
1328    current_re_filterfile = fs;
1329
1330    if (csp)
1331    {
1332       csp->rlist = fs;
1333    }
1334
1335    return( 0 );
1336
1337 load_re_filterfile_error:
1338    log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E", 
1339              csp->config->re_filterfile);
1340    return(-1);
1341
1342 }
1343 #endif /* def PCRS */
1344
1345
1346 /*********************************************************************
1347  *
1348  * Function    :  add_loader
1349  *
1350  * Description :  Called from `load_config'.  Called once for each input
1351  *                file found in config.
1352  *
1353  * Parameters  :
1354  *          1  :  loader = pointer to a function that can parse and load
1355  *                the appropriate config file.
1356  *          2  :  config = The configuration_spec to add the loader to.
1357  *
1358  * Returns     :  N/A
1359  *
1360  *********************************************************************/
1361 void add_loader(int (*loader)(struct client_state *), 
1362                 struct configuration_spec * config)
1363 {
1364    int i;
1365
1366    for (i=0; i < NLOADERS; i++)
1367    {
1368       if (config->loaders[i] == NULL)
1369       {
1370          config->loaders[i] = loader;
1371          break;
1372       }
1373    }
1374
1375 }
1376
1377
1378 /*********************************************************************
1379  *
1380  * Function    :  run_loader
1381  *
1382  * Description :  Called from `load_config' and `listen_loop'.  This
1383  *                function keeps the "csp" current with any file mods
1384  *                since the last loop.  If a file is unchanged, the
1385  *                loader functions do NOT reload the file.
1386  *
1387  * Parameters  :
1388  *          1  :  csp = Current client state (buffers, headers, etc...)
1389  *                      Must be non-null.  Reads: "csp->config"
1390  *                      Writes: various data members.
1391  *
1392  * Returns     :  0 => Ok, everything else is an error.
1393  *
1394  *********************************************************************/
1395 int run_loader(struct client_state *csp)
1396 {
1397    int ret = 0;
1398    int i;
1399
1400    for (i=0; i < NLOADERS; i++)
1401    {
1402       if (csp->config->loaders[i] == NULL)
1403       {
1404          break;
1405       }
1406       ret |= (csp->config->loaders[i])(csp);
1407    }
1408    return(ret);
1409
1410 }
1411
1412
1413 /*
1414   Local Variables:
1415   tab-width: 3
1416   end:
1417 */