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