first import of project's documentation for the webserver.
[privoxy.git] / loadcfg.c
1 /* vim:ts=3: */
2 const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.15 2001/06/07 23:13:40 jongfoster Exp $";
3 /*********************************************************************
4  *
5  * File        :  $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
6  *
7  * Purpose     :  Loads settings from the configuration file into
8  *                global variables.  This file contains both the 
9  *                routine to load the configuration and the global
10  *                variables it writes to.
11  *
12  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
13  *                IJBSWA team.  http://ijbswa.sourceforge.net
14  *
15  *                Based on the Internet Junkbuster originally written
16  *                by and Copyright (C) 1997 Anonymous Coders and 
17  *                Junkbusters Corporation.  http://www.junkbusters.com
18  *
19  *                This program is free software; you can redistribute it 
20  *                and/or modify it under the terms of the GNU General
21  *                Public License as published by the Free Software
22  *                Foundation; either version 2 of the License, or (at
23  *                your option) any later version.
24  *
25  *                This program is distributed in the hope that it will
26  *                be useful, but WITHOUT ANY WARRANTY; without even the
27  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
28  *                PARTICULAR PURPOSE.  See the GNU General Public
29  *                License for more details.
30  *
31  *                The GNU General Public License should be included with
32  *                this file.  If not, you can view it at
33  *                http://www.gnu.org/copyleft/gpl.html
34  *                or write to the Free Software Foundation, Inc., 59
35  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  *
37  * Revisions   :
38  *    $Log: loadcfg.c,v $
39  *    Revision 1.15  2001/06/07 23:13:40  jongfoster
40  *    Merging ACL and forward files into config file.
41  *    Cosmetic: Sorting config file options alphabetically.
42  *    Cosmetic: Adding brief syntax comments to config file options.
43  *
44  *    Revision 1.14  2001/06/07 14:46:25  joergs
45  *    Missing make_path() added for re_filterfile.
46  *
47  *    Revision 1.13  2001/06/05 22:33:54  jongfoster
48  *
49  *    Fixed minor memory leak.
50  *    Also now uses make_path to prepend the pathnames.
51  *
52  *    Revision 1.12  2001/06/05 20:04:09  jongfoster
53  *    Now uses _snprintf() in place of snprintf() under Win32.
54  *
55  *    Revision 1.11  2001/06/04 18:31:58  swa
56  *    files are now prefixed with either `confdir' or `logdir'.
57  *    `make redhat-dist' replaces both entries confdir and logdir
58  *    with redhat values
59  *
60  *    Revision 1.10  2001/06/03 19:11:54  oes
61  *    introduced confdir option
62  *
63  *    Revision 1.10  2001/06/03 11:03:48  oes
64  *    Makefile/in
65  *
66  *    introduced cgi.c
67  *
68  *    actions.c:
69  *
70  *    adapted to new enlist_unique arg format
71  *
72  *    conf loadcfg.c
73  *
74  *    introduced confdir option
75  *
76  *    filters.c filtrers.h
77  *
78  *     extracted-CGI relevant stuff
79  *
80  *    jbsockets.c
81  *
82  *     filled comment
83  *
84  *    jcc.c
85  *
86  *     support for new cgi mechansim
87  *
88  *    list.c list.h
89  *
90  *    functions for new list type: "map"
91  *    extended enlist_unique
92  *
93  *    miscutil.c .h
94  *    introduced bindup()
95  *
96  *    parsers.c parsers.h
97  *
98  *    deleted const struct interceptors
99  *
100  *    pcrs.c
101  *    added FIXME
102  *
103  *    project.h
104  *
105  *    added struct map
106  *    added struct http_response
107  *    changes struct interceptors to struct cgi_dispatcher
108  *    moved HTML stuff to cgi.h
109  *
110  *    re_filterfile:
111  *
112  *    changed
113  *
114  *    showargs.c
115  *    NO TIME LEFT
116  *
117  *    Revision 1.9  2001/06/01 20:06:24  jongfoster
118  *    Removed support for "tinygif" option - moved to actions file.
119  *
120  *    Revision 1.8  2001/05/31 21:27:13  jongfoster
121  *    Removed many options from the config file and into the
122  *    "actions" file: add_forwarded, suppress_vanilla_wafer,
123  *    wafer, add_header, user_agent, referer, from
124  *    Also globally replaced "permission" with "action".
125  *
126  *    Revision 1.7  2001/05/29 09:50:24  jongfoster
127  *    Unified blocklist/imagelist/permissionslist.
128  *    File format is still under discussion, but the internal changes
129  *    are (mostly) done.
130  *
131  *    Also modified interceptor behaviour:
132  *    - We now intercept all URLs beginning with one of the following
133  *      prefixes (and *only* these prefixes):
134  *        * http://i.j.b/
135  *        * http://ijbswa.sf.net/config/
136  *        * http://ijbswa.sourceforge.net/config/
137  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
138  *    - Internal changes so that intercepted and fast redirect pages
139  *      are not replaced with an image.
140  *    - Interceptors now have the option to send a binary page direct
141  *      to the client. (i.e. ijb-send-banner uses this)
142  *    - Implemented show-url-info interceptor.  (Which is why I needed
143  *      the above interceptors changes - a typical URL is
144  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
145  *      The previous mechanism would not have intercepted that, and
146  *      if it had been intercepted then it then it would have replaced
147  *      it with an image.)
148  *
149  *    Revision 1.6  2001/05/26 00:28:36  jongfoster
150  *    Automatic reloading of config file.
151  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
152  *    Most of the global variables have been moved to a new
153  *    struct configuration_spec, accessed through csp->config->globalname
154  *    Most of the globals remaining are used by the Win32 GUI.
155  *
156  *    Revision 1.5  2001/05/25 22:34:30  jongfoster
157  *    Hard tabs->Spaces
158  *
159  *    Revision 1.4  2001/05/22 18:46:04  oes
160  *
161  *    - Enabled filtering banners by size rather than URL
162  *      by adding patterns that replace all standard banner
163  *      sizes with the "Junkbuster" gif to the re_filterfile
164  *
165  *    - Enabled filtering WebBugs by providing a pattern
166  *      which kills all 1x1 images
167  *
168  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
169  *      which is selected by the (nonstandard and therefore
170  *      capital) letter 'U' in the option string.
171  *      It causes the quantifiers to be ungreedy by default.
172  *      Appending a ? turns back to greedy (!).
173  *
174  *    - Added a new interceptor ijb-send-banner, which
175  *      sends back the "Junkbuster" gif. Without imagelist or
176  *      MSIE detection support, or if tinygif = 1, or the
177  *      URL isn't recognized as an imageurl, a lame HTML
178  *      explanation is sent instead.
179  *
180  *    - Added new feature, which permits blocking remote
181  *      script redirects and firing back a local redirect
182  *      to the browser.
183  *      The feature is conditionally compiled, i.e. it
184  *      can be disabled with --disable-fast-redirects,
185  *      plus it must be activated by a "fast-redirects"
186  *      line in the config file, has its own log level
187  *      and of course wants to be displayed by show-proxy-args
188  *      Note: Boy, all the #ifdefs in 1001 locations and
189  *      all the fumbling with configure.in and acconfig.h
190  *      were *way* more work than the feature itself :-(
191  *
192  *    - Because a generic redirect template was needed for
193  *      this, tinygif = 3 now uses the same.
194  *
195  *    - Moved GIFs, and other static HTTP response templates
196  *      to project.h
197  *
198  *    - Some minor fixes
199  *
200  *    - Removed some >400 CRs again (Jon, you really worked
201  *      a lot! ;-)
202  *
203  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
204  *    Version 2.9.4 checkin.
205  *    - Merged popupfile and cookiefile, and added control over PCRS
206  *      filtering, in new "permissionsfile".
207  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
208  *      file error you now get a message box (in the Win32 GUI) rather
209  *      than the program exiting with no explanation.
210  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
211  *      skipping.
212  *    - Removed tabs from "config"
213  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
214  *    - Bumped up version number.
215  *
216  *    Revision 1.2  2001/05/17 23:01:01  oes
217  *     - Cleaned CRLF's from the sources and related files
218  *
219  *    Revision 1.1.1.1  2001/05/15 13:58:58  oes
220  *    Initial import of version 2.9.3 source tree
221  *
222  *
223  *********************************************************************/
224 \f
225
226 #include "config.h"
227
228 #include <stdio.h>
229 #include <sys/types.h>
230 #include <stdlib.h>
231 #include <string.h>
232 #include <signal.h>
233 #include <fcntl.h>
234 #include <errno.h>
235 #include <ctype.h>
236
237 #ifdef _WIN32
238
239 # include <sys/timeb.h>
240 # include <windows.h>
241 # include <io.h>
242 # include <process.h>
243 # ifdef TOGGLE
244 #  include <time.h>
245 # endif /* def TOGGLE */
246
247 # include "win32.h"
248 # ifndef _WIN_CONSOLE
249 #  include "w32log.h"
250 # endif /* ndef _WIN_CONSOLE */
251
252 /* VC++ has "_snprintf", not "snprintf" */
253 #define snprintf _snprintf
254
255 #else /* ifndef _WIN32 */
256
257 # include <unistd.h>
258 # include <sys/time.h>
259 # include <sys/wait.h>
260 # include <sys/stat.h>
261 # include <signal.h>
262
263 #endif
264
265 #include "loadcfg.h"
266 #include "list.h"
267 #include "jcc.h"
268 #include "filters.h"
269 #include "loaders.h"
270 #include "showargs.h"
271 #include "parsers.h"
272 #include "killpopup.h"
273 #include "miscutil.h"
274 #include "errlog.h"
275 #include "jbsockets.h"
276 #include "gateway.h"
277 #include "ssplit.h"
278
279 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
280
281 /*
282  * Fix a problem with Solaris.  There should be no effect on other
283  * platforms.
284  * Solaris's isspace() is a macro which uses it's argument directly
285  * as an array index.  Therefore we need to make sure that high-bit
286  * characters generate +ve values, and ideally we also want to make
287  * the argument match the declared parameter type of "int".
288  */
289 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
290 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
291
292 #ifdef TOGGLE
293 /* by haroon - indicates if ijb is enabled */
294 int g_bToggleIJB        = 1;   /* JunkBusters is enabled by default. */
295 #endif
296
297 /* The filename of the configfile */
298 const char *configfile  = NULL;
299
300 /*
301  * The load_config function is now going to call `init_proxy_args',
302  * so it will need argc and argv.  So we need to have these
303  * globally available.
304  */
305 int Argc = 0;
306 const char **Argv = NULL;
307
308 static struct file_list *current_configfile = NULL;
309
310
311 /*
312  * This takes the "cryptic" hash of each keyword and aliases them to
313  * something a little more readable.  This also makes changing the
314  * hash values easier if they should change or the hash algorthm changes.
315  * Use the included "hash" program to find out what the hash will be
316  * for any string supplied on the command line.  (Or just put it in the
317  * config file and read the number from the error message in the log).
318  *
319  * Please keep this list sorted alphabetically (but with the Windows
320  * console and GUI specific options last).
321  */
322
323 #define hash_actions_file              3825730796ul /* FIXME "permissionsfile" */
324 #define hash_confdir                      1978389ul /* "confdir" */
325 #define hash_debug                          78263ul /* "debug" */
326 #define hash_deny_access               1227333715ul /* "deny-access" */
327 #define hash_forward                      2029845ul /* "forward" */
328 #define hash_forward_socks4            3963965521ul /* "forward-socks4" */
329 #define hash_forward_socks4a           2639958518ul /* "forward-socks4a" */
330 #define hash_jarfile                      2046641ul /* "jarfile" */
331 #define hash_listen_address            1255650842ul /* "listen-address" */
332 #define hash_logdir                        422889ul /* "logdir" */
333 #define hash_logfile                      2114766ul /* "logfile" */
334 #define hash_permit_access             3587953268ul /* "permit-access" */
335 #define hash_re_filterfile             3877522444ul /* "re_filterfile" */
336 #define hash_single_threaded           4250084780ul /* "single-threaded" */
337 #define hash_suppress_blocklists       1948693308ul /* ??? */
338 #define hash_toggle                        447966ul /* "toggle" */
339 #define hash_trust_info_url             449869467ul /* ??? */
340 #define hash_trustfile                   56494766ul /* "trustfile" */
341
342 #define hash_hide_console              2048809870ul /* "hide-console" */
343
344 #define hash_activity_animation        1817904738ul /* "activity-animation" */
345 #define hash_close_button_minimizes    3651284693ul /* "close-button-minimizes" */
346 #define hash_log_buffer_size           2918070425ul /* "log-buffer-size" */
347 #define hash_log_font_name             2866730124ul /* "log-font-name" */
348 #define hash_log_font_size             2866731014ul /* "log-font-size" */
349 #define hash_log_highlight_messages    4032101240ul /* "log-highlight-messages" */
350 #define hash_log_max_lines             2868344173ul /* "log-max-lines" */
351 #define hash_log_messages              2291744899ul /* "log-messages" */
352 #define hash_show_on_task_bar           215410365ul /* "show-on-task-bar" */
353
354
355 /*********************************************************************
356  *
357  * Function    :  unload_configfile
358  *
359  * Description :  Free the config structure and all components.
360  *
361  * Parameters  :
362  *          1  :  data: struct configuration_spec to unload
363  *
364  * Returns     :  N/A
365  *
366  *********************************************************************/
367 void unload_configfile (void * data)
368 {
369    struct configuration_spec * config = (struct configuration_spec *)data;
370    struct forward_spec *cur_fwd = config->forward;
371 #ifdef ACL_FILES
372    struct access_control_list *cur_acl = config->acl;
373
374    while (cur_acl != NULL)
375    {
376       struct access_control_list * next_acl = cur_acl->next;
377       free(cur_acl);
378       cur_acl = next_acl;
379    }
380    config->acl = NULL;
381 #endif /* def ACL_FILES */
382
383    while (cur_fwd != NULL)
384    {
385       struct forward_spec * next_fwd = cur_fwd->next;
386       free_url(cur_fwd->url);
387
388       freez(cur_fwd->gateway_host);
389       freez(cur_fwd->forward_host);
390       free(cur_fwd);
391       cur_fwd = next_fwd;
392    }
393    config->forward = NULL;
394    
395 #ifdef JAR_FILES
396    if ( NULL != config->jar )
397    {
398       fclose( config->jar );
399       config->jar = NULL;
400    }
401 #endif /* def JAR_FILES */
402
403    freez((char *)config->confdir);
404    freez((char *)config->logdir);
405
406    freez((char *)config->haddr);
407    freez((char *)config->logfile);
408
409    freez((char *)config->actions_file);
410
411 #ifdef JAR_FILES
412    freez((char *)config->jarfile);
413 #endif /* def JAR_FILES */
414
415 #ifndef SPLIT_PROXY_ARGS
416    freez((char *)config->suppress_message);
417 #endif /* ndef SPLIT_PROXY_ARGS */
418
419 #ifdef PCRS
420    freez((char *)config->re_filterfile);
421 #endif /* def PCRS */
422
423 }
424
425
426 /*********************************************************************
427  *
428  * Function    :  load_config
429  *
430  * Description :  Load the config file and all parameters.
431  *
432  * Parameters  :
433  *          1  :  csp = Client state (the config member will be 
434  *                filled in by this function).
435  *
436  * Returns     :  0 => Ok, everything else is an error.
437  *
438  *********************************************************************/
439 struct configuration_spec * load_config(void)
440 {
441    char buf[BUFFER_SIZE];
442    char *p, *q;
443    FILE *configfp = NULL;
444    struct configuration_spec * config = NULL;
445    struct client_state * fake_csp;
446    struct file_list *fs;
447
448    if (!check_file_changed(current_configfile, configfile, &fs))
449    {
450       /* No need to load */
451       return ((struct configuration_spec *)current_configfile->f);
452    }
453    if (!fs)
454    {
455       log_error(LOG_LEVEL_FATAL, "can't check configuration file '%s':  %E",
456                 configfile);
457    }
458
459    log_error(LOG_LEVEL_INFO, "loading configuration file '%s':", configfile);
460
461 #ifdef TOGGLE
462    g_bToggleIJB      = 1;
463 #endif
464
465    fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
466
467    if (config==NULL)
468    {
469       freez(fs->filename);
470       freez(fs);
471       log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
472       /* Never get here - LOG_LEVEL_FATAL causes program exit */
473    }
474
475    /*
476     * This is backwards from how it's usually done.
477     * Following the usual pattern, "fs" would be stored in a member 
478     * variable in "csp", and then we'd access "config" from "fs->f",
479     * using a cast.  However, "config" is used so often that a 
480     * cast each time would be very ugly, and the extra indirection
481     * would waste CPU cycles.  Therefore we store "config" in
482     * "csp->config", and "fs" in "csp->config->config_file_list".
483     */
484    config->config_file_list = fs;
485
486    init_proxy_args(Argc, Argv, config);
487
488    /*
489     * Set to defaults
490     */
491
492    config->multi_threaded    = 1;
493    config->hport             = HADDR_PORT;
494
495    if ((configfp = fopen(configfile, "r")) == NULL)
496    {
497       log_error(LOG_LEVEL_FATAL, "can't open configuration file '%s':  %E",
498               configfile);
499       /* Never get here - LOG_LEVEL_FATAL causes program exit */
500    }
501
502    while (read_config_line(buf, sizeof(buf), configfp, fs) != NULL)
503    {
504       char cmd[BUFFER_SIZE];
505       char arg[BUFFER_SIZE];
506       char tmp[BUFFER_SIZE];
507 #ifdef ACL_FILES
508       struct access_control_list *cur_acl;
509 #endif /* def ACL_FILES */
510       struct forward_spec *cur_fwd;
511       int vec_count;
512       char *vec[3];
513
514       strcpy(tmp, buf);
515
516       /* Copy command (i.e. up to space or tab) into cmd */
517       p = buf;
518       q = cmd;
519       while (*p && (*p != ' ') && (*p != '\t'))
520       {
521          *q++ = *p++;
522       }
523       *q = '\0';
524
525       /* Skip over the whitespace in buf */
526       while (*p && ((*p == ' ') || (*p == '\t')))
527       {
528          p++;
529       }
530
531       /* Copy the argument into arg */
532       strcpy(arg, p);
533
534       /* Should never happen, but check this anyway */
535       if (*cmd == '\0')
536       {
537          continue;
538       }
539
540       /* Make sure the command field is lower case */
541       for (p=cmd; *p; p++)
542       {
543          if (ijb_isupper(*p))
544          {
545             *p = ijb_tolower(*p);
546          }
547       }
548
549       /* Save the argument for show-proxy-args */
550       savearg(cmd, arg, config);
551
552
553       switch( hash_string( cmd ) )
554       {
555 /****************************************************************************
556  * permissionsfile actions-file-name
557  * In confdir by default
558  ****************************************************************************/
559          case hash_actions_file :
560             freez((char *)config->actions_file);
561             config->actions_file = make_path(config->confdir, arg);
562             continue;
563
564 /****************************************************************************
565  * confdir directory-name
566  ****************************************************************************/
567          case hash_confdir :
568             freez((char *)config->confdir);
569             config->confdir = strdup(arg);
570             continue;            
571
572 /****************************************************************************
573  * debug n
574  * Specifies debug level, multiple values are ORed together.
575  ****************************************************************************/
576          case hash_debug :
577             config->debug |= atoi(arg);
578             continue;
579
580 /****************************************************************************
581  * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
582  ****************************************************************************/
583 #ifdef ACL_FILES
584          case hash_deny_access:
585             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
586
587             if ((vec_count != 1) && (vec_count != 2))
588             {
589                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
590                      "deny-access directive in configuration file.");
591                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
592                   "<br>\nWARNING: Wrong number of parameters for "
593                   "deny-access directive in configuration file.<br><br>\n");
594                continue;
595             }
596
597             /* allocate a new node */
598             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
599
600             if (cur_acl == NULL)
601             {
602                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
603                /* Never get here - LOG_LEVEL_FATAL causes program exit */
604                continue;
605             }
606             cur_acl->action = ACL_DENY;
607
608             if (acl_addr(vec[0], cur_acl->src) < 0)
609             {
610                log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access "
611                      "directive in configuration file: \"%s\"", vec[0]);
612                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
613                   "<br>\nWARNING: Invalid source IP for deny-access directive"
614                   " in configuration file: \"");
615                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
616                   vec[0]);
617                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
618                   "\"<br><br>\n");
619                freez(cur_acl);
620                continue;
621             }
622             if (vec_count == 2)
623             {
624                if (acl_addr(vec[1], cur_acl->dst) < 0)
625                {
626                   log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access "
627                         "directive in configuration file: \"%s\"", vec[0]);
628                   config->proxy_args_invocation = strsav( config->proxy_args_invocation,
629                      "<br>\nWARNING: Invalid destination IP for deny-access directive"
630                      " in configuration file: \"");
631                   config->proxy_args_invocation = strsav( config->proxy_args_invocation,
632                      vec[0]);
633                   config->proxy_args_invocation = strsav( config->proxy_args_invocation,
634                      "\"<br><br>\n");
635                   freez(cur_acl);
636                   continue;
637                }
638             }
639
640             /*
641              * Add it to the list.  Note we reverse the list to get the
642              * behaviour the user expects.  With both the ACL and
643              * actions file, the last match wins.  However, the internal
644              * implementations are different:  The actions file is stored
645              * in the same order as the file, and scanned completely.
646              * With the ACL, we reverse the order as we load it, then 
647              * when we scan it we stop as soon as we get a match.
648              */
649             cur_acl->next  = config->acl;
650             config->acl = cur_acl;
651
652             continue;
653 #endif /* def ACL_FILES */
654
655 /****************************************************************************
656  * forward url-pattern (.|http-proxy-host[:port])
657  ****************************************************************************/
658          case hash_forward:
659             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
660
661             if (vec_count != 2)
662             {
663                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward "
664                      "directive in configuration file.");
665                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
666                   "<br>\nWARNING: Wrong number of parameters for "
667                   "forward directive in configuration file.");
668                continue;
669             }
670
671             /* allocate a new node */
672             cur_fwd = zalloc(sizeof(*cur_fwd));
673             if (cur_fwd == NULL)
674             {
675                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
676                /* Never get here - LOG_LEVEL_FATAL causes program exit */
677                continue;
678             }
679
680             cur_fwd->type = SOCKS_NONE;
681
682             /* Save the URL pattern */
683             if (create_url_spec(cur_fwd->url, vec[0]))
684             {
685                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward "
686                      "directive in configuration file.");
687                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
688                   "<br>\nWARNING: Bad URL specifier for "
689                   "forward directive in configuration file.");
690                continue;
691             }
692
693             /* Parse the parent HTTP proxy host:port */
694             p = vec[1];
695
696             if (strcmp(p, ".") != 0)
697             {
698                cur_fwd->forward_host = strdup(p);
699
700                if ((p = strchr(cur_fwd->forward_host, ':')))
701                {
702                   *p++ = '\0';
703                   cur_fwd->forward_port = atoi(p);
704                }
705
706                if (cur_fwd->forward_port <= 0)
707                {
708                   cur_fwd->forward_port = 8000;
709                }
710             }
711
712             /* Add to list. */
713             cur_fwd->next = config->forward;
714             config->forward = cur_fwd;
715
716             continue;
717
718 /****************************************************************************
719  * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port])
720  ****************************************************************************/
721          case hash_forward_socks4:
722             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
723
724             if (vec_count != 3)
725             {
726                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
727                      "forward-socks4 directive in configuration file.");
728                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
729                   "<br>\nWARNING: Wrong number of parameters for "
730                   "forward-socks4 directive in configuration file.");
731                continue;
732             }
733
734             /* allocate a new node */
735             cur_fwd = zalloc(sizeof(*cur_fwd));
736             if (cur_fwd == NULL)
737             {
738                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
739                /* Never get here - LOG_LEVEL_FATAL causes program exit */
740                continue;
741             }
742
743             cur_fwd->type = SOCKS_4;
744
745             /* Save the URL pattern */
746             if (create_url_spec(cur_fwd->url, vec[0]))
747             {
748                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 "
749                      "directive in configuration file.");
750                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
751                   "<br>\nWARNING: Bad URL specifier for "
752                   "forward-socks4 directive in configuration file.");
753                continue;
754             }
755
756             /* Parse the SOCKS proxy host[:port] */
757             p = vec[1];
758
759             if (strcmp(p, ".") != 0)
760             {
761                cur_fwd->gateway_host = strdup(p);
762
763                if ((p = strchr(cur_fwd->gateway_host, ':')))
764                {
765                   *p++ = '\0';
766                   cur_fwd->gateway_port = atoi(p);
767                }
768                if (cur_fwd->gateway_port <= 0)
769                {
770                   cur_fwd->gateway_port = 1080;
771                }
772             }
773
774             /* Parse the parent HTTP proxy host[:port] */
775             p = vec[2];
776
777             if (strcmp(p, ".") != 0)
778             {
779                cur_fwd->forward_host = strdup(p);
780
781                if ((p = strchr(cur_fwd->forward_host, ':')))
782                {
783                   *p++ = '\0';
784                   cur_fwd->forward_port = atoi(p);
785                }
786
787                if (cur_fwd->forward_port <= 0)
788                {
789                   cur_fwd->forward_port = 8000;
790                }
791             }
792
793             /* Add to list. */
794             cur_fwd->next = config->forward;
795             config->forward = cur_fwd;
796             
797             continue;
798
799 /****************************************************************************
800  * forward-socks4a url-pattern socks-proxy[:port] (.|http-proxy[:port])
801  ****************************************************************************/
802          case hash_forward_socks4a:
803             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
804
805             if (vec_count != 3)
806             {
807                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
808                      "forward-socks4a directive in configuration file.");
809                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
810                   "<br>\nWARNING: Wrong number of parameters for "
811                   "forward-socks4a directive in configuration file.");
812                continue;
813             }
814
815             /* allocate a new node */
816             cur_fwd = zalloc(sizeof(*cur_fwd));
817             if (cur_fwd == NULL)
818             {
819                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
820                /* Never get here - LOG_LEVEL_FATAL causes program exit */
821                continue;
822             }
823
824             cur_fwd->type = SOCKS_4A;
825
826             /* Save the URL pattern */
827             if (create_url_spec(cur_fwd->url, vec[0]))
828             {
829                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4a "
830                      "directive in configuration file.");
831                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
832                   "<br>\nWARNING: Bad URL specifier for "
833                   "forward-socks4a directive in configuration file.");
834                continue;
835             }
836
837             /* Parse the SOCKS proxy host[:port] */
838             p = vec[1];
839
840             cur_fwd->gateway_host = strdup(p);
841
842             if ((p = strchr(cur_fwd->gateway_host, ':')))
843             {
844                *p++ = '\0';
845                cur_fwd->gateway_port = atoi(p);
846             }
847             if (cur_fwd->gateway_port <= 0)
848             {
849                cur_fwd->gateway_port = 1080;
850             }
851
852             /* Parse the parent HTTP proxy host[:port] */
853             p = vec[2];
854
855             if (strcmp(p, ".") != 0)
856             {
857                cur_fwd->forward_host = strdup(p);
858
859                if ((p = strchr(cur_fwd->forward_host, ':')))
860                {
861                   *p++ = '\0';
862                   cur_fwd->forward_port = atoi(p);
863                }
864
865                if (cur_fwd->forward_port <= 0)
866                {
867                   cur_fwd->forward_port = 8000;
868                }
869             }
870
871             /* Add to list. */
872             cur_fwd->next = config->forward;
873             config->forward = cur_fwd;
874             
875             continue;
876
877 /****************************************************************************
878  * jarfile jar-file-name
879  * In logdir by default
880  ****************************************************************************/
881 #ifdef JAR_FILES
882          case hash_jarfile :
883             freez((char *)config->jarfile);
884             config->jarfile = make_path(config->logdir, arg);
885             continue;
886 #endif /* def JAR_FILES */
887
888 /****************************************************************************
889  * listen-address [ip][:port]
890  ****************************************************************************/
891          case hash_listen_address :
892             freez((char *)config->haddr);
893             config->haddr = strdup(arg);
894             continue;
895
896 /****************************************************************************
897  * logdir directory-name
898  ****************************************************************************/
899          case hash_logdir :
900             freez((char *)config->logdir);
901             config->logdir = strdup(arg);
902             continue;            
903
904 /****************************************************************************
905  * logfile log-file-name
906  * In logdir by default
907  ****************************************************************************/
908          case hash_logfile :
909             freez((char *)config->logfile);
910             config->logfile = make_path(config->logdir, arg);
911             continue;
912
913 /****************************************************************************
914  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
915  ****************************************************************************/
916 #ifdef ACL_FILES
917          case hash_permit_access:
918             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
919
920             if ((vec_count != 1) && (vec_count != 2))
921             {
922                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
923                      "permit-access directive in configuration file.");
924                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
925                   "<br>\nWARNING: Wrong number of parameters for "
926                   "permit-access directive in configuration file.<br><br>\n");
927
928                continue;
929             }
930
931             /* allocate a new node */
932             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
933
934             if (cur_acl == NULL)
935             {
936                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
937                /* Never get here - LOG_LEVEL_FATAL causes program exit */
938                continue;
939             }
940             cur_acl->action = ACL_PERMIT;
941
942             if (acl_addr(vec[0], cur_acl->src) < 0)
943             {
944                log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access "
945                      "directive in configuration file: \"%s\"", vec[0]);
946                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
947                   "<br>\nWARNING: Invalid source IP for permit-access directive"
948                   " in configuration file: \"");
949                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
950                   vec[0]);
951                config->proxy_args_invocation = strsav( config->proxy_args_invocation,
952                   "\"<br><br>\n");
953                freez(cur_acl);
954                continue;
955             }
956             if (vec_count == 2)
957             {
958                if (acl_addr(vec[1], cur_acl->dst) < 0)
959                {
960                   log_error(LOG_LEVEL_ERROR, "Invalid destination IP for "
961                         "permit-access directive in configuration file: \"%s\"",
962                         vec[0]);
963                   config->proxy_args_invocation = strsav( config->proxy_args_invocation,
964                      "<br>\nWARNING: Invalid destination IP for permit-access directive"
965                      " in configuration file: \"");
966                   config->proxy_args_invocation = strsav( config->proxy_args_invocation,
967                      vec[0]);
968                   config->proxy_args_invocation = strsav( config->proxy_args_invocation,
969                      "\"<br><br>\n");
970                   freez(cur_acl);
971                   continue;
972                }
973             }
974
975             /*
976              * Add it to the list.  Note we reverse the list to get the
977              * behaviour the user expects.  With both the ACL and
978              * actions file, the last match wins.  However, the internal
979              * implementations are different:  The actions file is stored
980              * in the same order as the file, and scanned completely.
981              * With the ACL, we reverse the order as we load it, then 
982              * when we scan it we stop as soon as we get a match.
983              */
984             cur_acl->next  = config->acl;
985             config->acl = cur_acl;
986
987             continue;
988 #endif /* def ACL_FILES */
989
990 /****************************************************************************
991  * re_filterfile file-name
992  * In confdir by default.
993  ****************************************************************************/
994 #ifdef PCRS
995          case hash_re_filterfile :
996             freez((char *)config->re_filterfile);
997             config->re_filterfile = make_path(config->confdir, arg);
998             continue;
999 #endif /* def PCRS */
1000
1001 /****************************************************************************
1002  * single-threaded
1003  ****************************************************************************/
1004          case hash_single_threaded :
1005             config->multi_threaded = 0;
1006             continue;
1007
1008 /****************************************************************************
1009  * FIXME: Document this
1010  ****************************************************************************/
1011 #ifndef SPLIT_PROXY_ARGS
1012          case hash_suppress_blocklists :
1013             if (arg[0] != '\0')
1014             {
1015                config->suppress_message = strdup(arg);
1016             }
1017             else
1018             {
1019                /* There will be NO reference in proxy-args. */
1020                config->suppress_message = NULL;
1021             }
1022
1023             config->suppress_blocklists = 1;
1024             continue;
1025 #endif /* ndef SPLIT_PROXY_ARGS */
1026
1027 /****************************************************************************
1028  * toggle (0|1)
1029  ****************************************************************************/
1030 #ifdef TOGGLE
1031          case hash_toggle :
1032             g_bToggleIJB = atoi(arg);
1033             continue;
1034 #endif /* def TOGGLE */
1035
1036 /****************************************************************************
1037  * FIXME: Please document this!
1038  ****************************************************************************/
1039 #ifdef TRUST_FILES
1040          case hash_trust_info_url :
1041             enlist(config->trust_info, arg);
1042             continue;
1043 #endif /* def TRUST_FILES */
1044
1045 /****************************************************************************
1046  * trustfile filename
1047  * (In confdir by default.)
1048  ****************************************************************************/
1049 #ifdef TRUST_FILES
1050          case hash_trustfile :
1051             freez((char *)config->trustfile);
1052             config->trustfile = make_path(config->confdir, arg);
1053             continue;
1054 #endif /* def TRUST_FILES */
1055
1056
1057 /****************************************************************************
1058  * Win32 Console options:
1059  ****************************************************************************/
1060
1061 /****************************************************************************
1062  * hide-console
1063  ****************************************************************************/
1064 #ifdef _WIN_CONSOLE
1065          case hash_hide_console :
1066             hideConsole = 1;
1067             continue;
1068 #endif /*def _WIN_CONSOLE*/
1069
1070
1071 /****************************************************************************
1072  * Win32 GUI options:
1073  ****************************************************************************/
1074
1075 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
1076 /****************************************************************************
1077  * activity-animation (0|1)
1078  ****************************************************************************/
1079          case hash_activity_animation :
1080             g_bShowActivityAnimation = atoi(arg);
1081             continue;
1082
1083 /****************************************************************************
1084  *  close-button-minimizes (0|1)
1085  ****************************************************************************/
1086          case hash_close_button_minimizes :
1087             g_bCloseHidesWindow = atoi(arg);
1088             continue;
1089
1090 /****************************************************************************
1091  * log-buffer-size (0|1)
1092  ****************************************************************************/
1093          case hash_log_buffer_size :
1094             g_bLimitBufferSize = atoi(arg);
1095             continue;
1096
1097 /****************************************************************************
1098  * log-font-name fontnane
1099  ****************************************************************************/
1100          case hash_log_font_name :
1101             strcpy( g_szFontFaceName, arg );
1102             continue;
1103
1104 /****************************************************************************
1105  * log-font-size n
1106  ****************************************************************************/
1107          case hash_log_font_size :
1108             g_nFontSize = atoi(arg);
1109             continue;
1110
1111 /****************************************************************************
1112  * log-highlight-messages (0|1)
1113  ****************************************************************************/
1114          case hash_log_highlight_messages :
1115             g_bHighlightMessages = atoi(arg);
1116             continue;
1117
1118 /****************************************************************************
1119  * log-max-lines n
1120  ****************************************************************************/
1121          case hash_log_max_lines :
1122             g_nMaxBufferLines = atoi(arg);
1123             continue;
1124
1125 /****************************************************************************
1126  * log-messages (0|1)
1127  ****************************************************************************/
1128          case hash_log_messages :
1129             g_bLogMessages = atoi(arg);
1130             continue;
1131
1132 /****************************************************************************
1133  * show-on-task-bar (0|1)
1134  ****************************************************************************/
1135          case hash_show_on_task_bar :
1136             g_bShowOnTaskBar = atoi(arg);
1137             continue;
1138
1139 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
1140
1141
1142 /****************************************************************************/
1143 /* Warnings about unsupported features                                      */
1144 /****************************************************************************/
1145 #ifndef ACL_FILES
1146          case hash_deny_access:
1147 #endif /* ndef ACL_FILES */
1148 #ifndef JAR_FILES
1149          case hash_jarfile :
1150 #endif /* ndef JAR_FILES */
1151 #ifndef ACL_FILES
1152          case hash_permit_access:
1153 #endif /* ndef ACL_FILES */
1154 #ifndef PCRS
1155          case hash_re_filterfile :
1156 #endif /* ndef PCRS */
1157 #ifdef SPLIT_PROXY_ARGS
1158          case hash_suppress_blocklists :
1159 #endif /* def SPLIT_PROXY_ARGS */
1160 #ifndef TOGGLE
1161          case hash_toggle :
1162 #endif /* ndef TOGGLE */
1163 #ifndef TRUST_FILES
1164          case hash_trustfile :
1165          case hash_trust_info_url :
1166 #endif /* ndef TRUST_FILES */
1167
1168 #ifndef _WIN_CONSOLE
1169          case hash_hide_console :
1170 #endif /* ndef _WIN_CONSOLE */
1171
1172 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
1173          case hash_activity_animation :
1174          case hash_close_button_minimizes :
1175          case hash_log_buffer_size :
1176          case hash_log_font_name :
1177          case hash_log_font_size :
1178          case hash_log_highlight_messages :
1179          case hash_log_max_lines :
1180          case hash_log_messages :
1181          case hash_show_on_task_bar :
1182 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
1183             /* These warnings are annoying - so hide them. -- Jon */
1184             /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */
1185             continue;
1186
1187 /****************************************************************************/
1188          default :
1189 /****************************************************************************/
1190             /*
1191              * I decided that I liked this better as a warning than an
1192              * error.  To change back to an error, just change log level
1193              * to LOG_LEVEL_FATAL.
1194              */
1195             log_error(LOG_LEVEL_ERROR, "Unrecognized directive (%luul) in "
1196                   "configuration file: \"%s\"", hash_string( cmd ), buf);
1197             config->proxy_args_invocation = strsav( config->proxy_args_invocation, "<br>\nWARNING: unrecognized directive : ");
1198             config->proxy_args_invocation = strsav( config->proxy_args_invocation, buf);
1199             config->proxy_args_invocation = strsav( config->proxy_args_invocation, "<br><br>\n");
1200             continue;
1201
1202 /****************************************************************************/
1203       } /* end switch( hash_string(cmd) ) */
1204    } /* end while ( read_config_line(...) ) */
1205
1206    fclose(configfp);
1207
1208    init_error_log(Argv[0], config->logfile, config->debug);
1209
1210    if (config->actions_file)
1211    {
1212       add_loader(load_actions_file, config);
1213    }
1214
1215 #ifdef PCRS
1216    if (config->re_filterfile)
1217    {
1218       add_loader(load_re_filterfile, config);
1219    }
1220 #endif /* def PCRS */
1221
1222 #ifdef TRUST_FILES
1223    if (config->trustfile)
1224    {
1225       add_loader(load_trustfile, config);
1226    }
1227 #endif
1228
1229 #ifdef JAR_FILES
1230    if ( NULL != config->jarfile )
1231    {
1232       if ( NULL == (config->jar = fopen(config->jarfile, "a")) )
1233       {
1234          log_error(LOG_LEVEL_FATAL, "can't open jarfile '%s': %E", config->jarfile);
1235          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1236       }
1237       setbuf(config->jar, NULL);
1238    }
1239 #endif /* def JAR_FILES */
1240
1241    if ( NULL == config->haddr )
1242    {
1243       config->haddr = strdup( HADDR_DEFAULT );
1244    }
1245
1246    if ( NULL != config->haddr )
1247    {
1248       if ((p = strchr(config->haddr, ':')))
1249       {
1250          *p++ = '\0';
1251          if (*p)
1252          {
1253             config->hport = atoi(p);
1254          }
1255       }
1256
1257       if (config->hport <= 0)
1258       {
1259          *--p = ':';
1260          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
1261          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1262       }
1263       if (*config->haddr == '\0')
1264       {
1265          config->haddr = NULL;
1266       }
1267    }
1268
1269    /*
1270     * Want to run all the loaders once now.
1271     *
1272     * Need to set up a fake csp, so they can get to the config.
1273     */
1274    fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp));
1275    fake_csp->config = config;
1276
1277    if (run_loader(fake_csp))
1278    {
1279       freez(fake_csp);
1280       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
1281       /* Never get here - LOG_LEVEL_FATAL causes program exit */
1282    }
1283    freez(fake_csp);
1284
1285 #ifndef SPLIT_PROXY_ARGS
1286    if (!suppress_blocklists)
1287    {
1288       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1289    }
1290 #endif /* ndef SPLIT_PROXY_ARGS */
1291
1292 /* FIXME: this is a kludge for win32 */
1293 #if defined(_WIN32) && !defined (_WIN_CONSOLE)
1294
1295    g_actions_file     = config->actions_file;
1296 #ifdef PCRS
1297    g_re_filterfile    = config->re_filterfile;
1298 #endif
1299 #ifdef TRUST_FILES
1300    g_trustfile        = config->trustfile;
1301 #endif
1302    
1303
1304 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
1305 /* FIXME: end kludge */
1306
1307
1308    config->need_bind = 1;
1309
1310    if (current_configfile)
1311    {
1312       struct configuration_spec * oldcfg = (struct configuration_spec *)
1313                                            current_configfile->f;
1314       /*
1315        * Check if config->haddr,hport == oldcfg->haddr,hport
1316        *
1317        * The following could be written more compactly as a single,
1318        * (unreadably long) if statement.
1319        */
1320       config->need_bind = 0;
1321       if (config->hport != oldcfg->hport)
1322       {
1323          config->need_bind = 1;
1324       }
1325       else if (config->haddr == NULL)
1326       {
1327          if (oldcfg->haddr != NULL)
1328          {
1329             config->need_bind = 1;
1330          }
1331       }
1332       else if (oldcfg->haddr == NULL)
1333       {
1334          config->need_bind = 1;
1335       }
1336       else if (0 != strcmp(config->haddr, oldcfg->haddr))
1337       {
1338          config->need_bind = 1;
1339       }
1340
1341       current_configfile->unloader = unload_configfile;
1342    }
1343
1344    fs->next = files->next;
1345    files->next = fs;
1346
1347    current_configfile = fs;
1348
1349    return (config);
1350 }
1351
1352
1353 /*
1354   Local Variables:
1355   tab-width: 3
1356   end:
1357 */