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