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