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