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