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