Add comments for (relatively) new features bitmasks.
[privoxy.git] / loadcfg.c
1 const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.105 2009/09/06 14:15:46 fabiankeil 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-2009 the
12  *                Privoxy team. http://www.privoxy.org/
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  *********************************************************************/
37
38
39 #include "config.h"
40
41 #include <stdio.h>
42 #include <sys/types.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <signal.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <ctype.h>
49 #include <assert.h>
50
51 #ifdef _WIN32
52
53 # ifndef STRICT
54 #  define STRICT
55 # endif
56 # include <windows.h>
57
58 # include "win32.h"
59 # ifndef _WIN_CONSOLE
60 #  include "w32log.h"
61 # endif /* ndef _WIN_CONSOLE */
62
63 #else /* ifndef _WIN32 */
64
65 #ifndef __OS2__
66 # include <unistd.h>
67 # include <sys/wait.h>
68 #endif
69 # include <sys/time.h>
70 # include <sys/stat.h>
71 # include <signal.h>
72
73 #endif
74
75 #include "loadcfg.h"
76 #include "list.h"
77 #include "jcc.h"
78 #include "filters.h"
79 #include "loaders.h"
80 #include "miscutil.h"
81 #include "errlog.h"
82 #include "ssplit.h"
83 #include "encode.h"
84 #include "urlmatch.h"
85 #include "cgi.h"
86 #include "gateway.h"
87
88 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
89
90 /*
91  * Fix a problem with Solaris.  There should be no effect on other
92  * platforms.
93  * Solaris's isspace() is a macro which uses it's argument directly
94  * as an array index.  Therefore we need to make sure that high-bit
95  * characters generate +ve values, and ideally we also want to make
96  * the argument match the declared parameter type of "int".
97  */
98 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
99 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
100
101 #ifdef FEATURE_TOGGLE
102 /* Privoxy is enabled by default. */
103 int global_toggle_state = 1;
104 #endif /* def FEATURE_TOGGLE */
105
106 /* The filename of the configfile */
107 const char *configfile  = NULL;
108
109 /*
110  * CGI functions will later need access to the invocation args,
111  * so we will make argc and argv global.
112  */
113 int Argc = 0;
114 char * const * Argv = NULL;
115
116 static struct file_list *current_configfile = NULL;
117
118
119 /*
120  * This takes the "cryptic" hash of each keyword and aliases them to
121  * something a little more readable.  This also makes changing the
122  * hash values easier if they should change or the hash algorthm changes.
123  * Use the included "hash" program to find out what the hash will be
124  * for any string supplied on the command line.  (Or just put it in the
125  * config file and read the number from the error message in the log).
126  *
127  * Please keep this list sorted alphabetically (but with the Windows
128  * console and GUI specific options last).
129  */
130
131 #define hash_actions_file                1196306641ul /* "actionsfile" */
132 #define hash_accept_intercepted_requests 1513024973ul /* "accept-intercepted-requests" */
133 #define hash_admin_address               4112573064ul /* "admin-address" */
134 #define hash_allow_cgi_request_crunching  258915987ul /* "allow-cgi-request-crunching" */
135 #define hash_buffer_limit                1881726070ul /* "buffer-limit */
136 #define hash_confdir                        1978389ul /* "confdir" */
137 #define hash_connection_sharing          1348841265ul /* "connection-sharing" */
138 #define hash_debug                            78263ul /* "debug" */
139 #define hash_deny_access                 1227333715ul /* "deny-access" */
140 #define hash_enable_edit_actions         2517097536ul /* "enable-edit-actions" */
141 #define hash_enable_remote_toggle        2979744683ul /* "enable-remote-toggle" */
142 #define hash_enable_remote_http_toggle    110543988ul /* "enable-remote-http-toggle" */
143 #define hash_enforce_blocks              1862427469ul /* "enforce-blocks" */
144 #define hash_filterfile                   250887266ul /* "filterfile" */
145 #define hash_forward                        2029845ul /* "forward" */
146 #define hash_forward_socks4              3963965521ul /* "forward-socks4" */
147 #define hash_forward_socks4a             2639958518ul /* "forward-socks4a" */
148 #define hash_forward_socks5              3963965522ul /* "forward-socks5" */
149 #define hash_forwarded_connect_retries    101465292ul /* "forwarded-connect-retries" */
150 #define hash_hostname                      10308071ul /* "hostname" */
151 #define hash_keep_alive_timeout          3878599515ul /* "keep-alive-timeout" */
152 #define hash_listen_address              1255650842ul /* "listen-address" */
153 #define hash_logdir                          422889ul /* "logdir" */
154 #define hash_logfile                        2114766ul /* "logfile" */
155 #define hash_max_client_connections      3595884446ul /* "max-client-connections" */
156 #define hash_permit_access               3587953268ul /* "permit-access" */
157 #define hash_proxy_info_url              3903079059ul /* "proxy-info-url" */
158 #define hash_single_threaded             4250084780ul /* "single-threaded" */
159 #define hash_socket_timeout              1809001761ul /* "socket-timeout" */
160 #define hash_split_large_cgi_forms        671658948ul /* "split-large-cgi-forms" */
161 #define hash_suppress_blocklists         1948693308ul /* "suppress-blocklists" */
162 #define hash_templdir                      11067889ul /* "templdir" */
163 #define hash_toggle                          447966ul /* "toggle" */
164 #define hash_trust_info_url               430331967ul /* "trust-info-url" */
165 #define hash_trustfile                     56494766ul /* "trustfile" */
166 #define hash_usermanual                  1416668518ul /* "user-manual" */
167 #define hash_activity_animation          1817904738ul /* "activity-animation" */
168 #define hash_close_button_minimizes      3651284693ul /* "close-button-minimizes" */
169 #define hash_hide_console                2048809870ul /* "hide-console" */
170 #define hash_log_buffer_size             2918070425ul /* "log-buffer-size" */
171 #define hash_log_font_name               2866730124ul /* "log-font-name" */
172 #define hash_log_font_size               2866731014ul /* "log-font-size" */
173 #define hash_log_highlight_messages      4032101240ul /* "log-highlight-messages" */
174 #define hash_log_max_lines               2868344173ul /* "log-max-lines" */
175 #define hash_log_messages                2291744899ul /* "log-messages" */
176 #define hash_show_on_task_bar             215410365ul /* "show-on-task-bar" */
177
178
179 static void savearg(char *command, char *argument, struct configuration_spec * config);
180
181 /*********************************************************************
182  *
183  * Function    :  unload_configfile
184  *
185  * Description :  Free the config structure and all components.
186  *
187  * Parameters  :
188  *          1  :  data: struct configuration_spec to unload
189  *
190  * Returns     :  N/A
191  *
192  *********************************************************************/
193 static void unload_configfile (void * data)
194 {
195    struct configuration_spec * config = (struct configuration_spec *)data;
196    struct forward_spec *cur_fwd = config->forward;
197    int i;
198
199 #ifdef FEATURE_ACL
200    struct access_control_list *cur_acl = config->acl;
201
202    while (cur_acl != NULL)
203    {
204       struct access_control_list * next_acl = cur_acl->next;
205       free(cur_acl);
206       cur_acl = next_acl;
207    }
208    config->acl = NULL;
209 #endif /* def FEATURE_ACL */
210
211    while (cur_fwd != NULL)
212    {
213       struct forward_spec * next_fwd = cur_fwd->next;
214       free_url_spec(cur_fwd->url);
215
216       freez(cur_fwd->gateway_host);
217       freez(cur_fwd->forward_host);
218       free(cur_fwd);
219       cur_fwd = next_fwd;
220    }
221    config->forward = NULL;
222
223    freez(config->confdir);
224    freez(config->logdir);
225    freez(config->templdir);
226    freez(config->hostname);
227
228    freez(config->haddr);
229    freez(config->logfile);
230
231    for (i = 0; i < MAX_AF_FILES; i++)
232    {
233       freez(config->actions_file_short[i]);
234       freez(config->actions_file[i]);
235       freez(config->re_filterfile_short[i]);
236       freez(config->re_filterfile[i]);
237    }
238
239    freez(config->admin_address);
240    freez(config->proxy_info_url);
241    freez(config->proxy_args);
242    freez(config->usermanual);
243
244 #ifdef FEATURE_TRUST
245    freez(config->trustfile);
246    list_remove_all(config->trust_info);
247 #endif /* def FEATURE_TRUST */
248
249    for (i = 0; i < MAX_AF_FILES; i++)
250    {
251       freez(config->re_filterfile[i]);
252    }
253
254    freez(config);
255 }
256
257
258 #ifdef FEATURE_GRACEFUL_TERMINATION
259 /*********************************************************************
260  *
261  * Function    :  unload_current_config_file
262  *
263  * Description :  Unloads current config file - reset to state at
264  *                beginning of program.
265  *
266  * Parameters  :  None
267  *
268  * Returns     :  N/A
269  *
270  *********************************************************************/
271 void unload_current_config_file(void)
272 {
273    if (current_configfile)
274    {
275       current_configfile->unloader = unload_configfile;
276       current_configfile = NULL;
277    }
278 }
279 #endif
280
281
282 /*********************************************************************
283  *
284  * Function    :  load_config
285  *
286  * Description :  Load the config file and all parameters.
287  *
288  *                XXX: more than thousand lines long
289  *                and thus in serious need of refactoring.
290  *
291  * Parameters  :  None
292  *
293  * Returns     :  The configuration_spec, or NULL on error.
294  *
295  *********************************************************************/
296 struct configuration_spec * load_config(void)
297 {
298    char buf[BUFFER_SIZE];
299    char *p, *q;
300    FILE *configfp = NULL;
301    struct configuration_spec * config = NULL;
302    struct client_state * fake_csp;
303    struct file_list *fs;
304    unsigned long linenum = 0;
305    int i;
306    char *logfile = NULL;
307
308    if (!check_file_changed(current_configfile, configfile, &fs))
309    {
310       /* No need to load */
311       return ((struct configuration_spec *)current_configfile->f);
312    }
313    if (NULL == fs)
314    {
315       log_error(LOG_LEVEL_FATAL,
316          "can't check configuration file '%s':  %E", configfile);
317       return NULL;
318    }
319
320    if (NULL != current_configfile)
321    {
322       log_error(LOG_LEVEL_INFO, "Reloading configuration file '%s'", configfile);
323    }
324
325 #ifdef FEATURE_TOGGLE
326    global_toggle_state = 1;
327 #endif /* def FEATURE_TOGGLE */
328
329    fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
330
331    if (NULL == config)
332    {
333       freez(fs->filename);
334       freez(fs);
335       log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
336       return NULL;
337    }
338
339    /*
340     * This is backwards from how it's usually done.
341     * Following the usual pattern, "fs" would be stored in a member
342     * variable in "csp", and then we'd access "config" from "fs->f",
343     * using a cast.  However, "config" is used so often that a
344     * cast each time would be very ugly, and the extra indirection
345     * would waste CPU cycles.  Therefore we store "config" in
346     * "csp->config", and "fs" in "csp->config->config_file_list".
347     */
348    config->config_file_list = fs;
349
350    /*
351     * Set to defaults
352     */
353    config->multi_threaded            = 1;
354    config->buffer_limit              = 4096 * 1024;
355    config->usermanual                = strdup(USER_MANUAL_URL);
356    config->proxy_args                = strdup("");
357    config->forwarded_connect_retries = 0;
358    config->max_client_connections    = 0;
359    config->socket_timeout            = 300; /* XXX: Should be a macro. */
360 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
361    config->keep_alive_timeout        = DEFAULT_KEEP_ALIVE_TIMEOUT;
362    config->feature_flags            &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
363    config->feature_flags            &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
364 #endif
365    config->feature_flags            &= ~RUNTIME_FEATURE_CGI_TOGGLE;
366    config->feature_flags            &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
367    config->feature_flags            &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
368
369    configfp = fopen(configfile, "r");
370    if (NULL == configfp)
371    {
372       log_error(LOG_LEVEL_FATAL,
373          "can't open configuration file '%s':  %E", configfile);
374       /* Never get here - LOG_LEVEL_FATAL causes program exit */
375    }
376
377    while (read_config_line(buf, sizeof(buf), configfp, &linenum) != NULL)
378    {
379       char cmd[BUFFER_SIZE];
380       char arg[BUFFER_SIZE];
381       char tmp[BUFFER_SIZE];
382 #ifdef FEATURE_ACL
383       struct access_control_list *cur_acl;
384 #endif /* def FEATURE_ACL */
385       struct forward_spec *cur_fwd;
386       int vec_count;
387       char *vec[3];
388       unsigned long directive_hash;
389
390       strlcpy(tmp, buf, sizeof(tmp));
391
392       /* Copy command (i.e. up to space or tab) into cmd */
393       p = buf;
394       q = cmd;
395       while (*p && (*p != ' ') && (*p != '\t'))
396       {
397          *q++ = *p++;
398       }
399       *q = '\0';
400
401       /* Skip over the whitespace in buf */
402       while (*p && ((*p == ' ') || (*p == '\t')))
403       {
404          p++;
405       }
406
407       /* Copy the argument into arg */
408       strlcpy(arg, p, sizeof(arg));
409
410       /* Should never happen, but check this anyway */
411       if (*cmd == '\0')
412       {
413          continue;
414       }
415
416       /* Make sure the command field is lower case */
417       for (p = cmd; *p; p++)
418       {
419          if (ijb_isupper(*p))
420          {
421             *p = (char)ijb_tolower(*p);
422          }
423       }
424
425       directive_hash = hash_string(cmd);
426       switch (directive_hash)
427       {
428 /* *************************************************************************
429  * actionsfile actions-file-name
430  * In confdir by default
431  * *************************************************************************/
432          case hash_actions_file :
433             i = 0;
434             while ((i < MAX_AF_FILES) && (NULL != config->actions_file[i]))
435             {
436                i++;
437             }
438
439             if (i >= MAX_AF_FILES)
440             {
441                log_error(LOG_LEVEL_FATAL, "Too many 'actionsfile' directives in config file - limit is %d.\n"
442                   "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).",
443                   MAX_AF_FILES);
444             }
445             config->actions_file_short[i] = strdup(arg);
446             config->actions_file[i] = make_path(config->confdir, arg);
447
448             break;
449 /* *************************************************************************
450  * accept-intercepted-requests
451  * *************************************************************************/
452          case hash_accept_intercepted_requests:
453             if ((*arg != '\0') && (0 != atoi(arg)))
454             {
455                config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
456             }
457             else
458             {
459                config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
460             }
461             break;
462
463 /* *************************************************************************
464  * admin-address email-address
465  * *************************************************************************/
466          case hash_admin_address :
467             freez(config->admin_address);
468             config->admin_address = strdup(arg);
469             break;
470
471 /* *************************************************************************
472  * allow-cgi-request-crunching
473  * *************************************************************************/
474          case hash_allow_cgi_request_crunching:
475             if ((*arg != '\0') && (0 != atoi(arg)))
476             {
477                config->feature_flags |= RUNTIME_FEATURE_CGI_CRUNCHING;
478             }
479             else
480             {
481                config->feature_flags &= ~RUNTIME_FEATURE_CGI_CRUNCHING;
482             }
483             break;
484
485 /* *************************************************************************
486  * buffer-limit n
487  * *************************************************************************/
488          case hash_buffer_limit :
489             config->buffer_limit = (size_t)(1024 * atoi(arg));
490             break;
491
492 /* *************************************************************************
493  * confdir directory-name
494  * *************************************************************************/
495          case hash_confdir :
496             freez(config->confdir);
497             config->confdir = make_path( NULL, arg);
498             break;
499
500 /* *************************************************************************
501  * connection-sharing (0|1)
502  * *************************************************************************/
503 #ifdef FEATURE_CONNECTION_SHARING
504          case hash_connection_sharing :
505             if ((*arg != '\0') && (0 != atoi(arg)))
506             {
507                config->feature_flags |= RUNTIME_FEATURE_CONNECTION_SHARING;
508             }
509             else
510             {
511                config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
512             }
513             break;
514 #endif
515
516 /* *************************************************************************
517  * debug n
518  * Specifies debug level, multiple values are ORed together.
519  * *************************************************************************/
520          case hash_debug :
521             config->debug |= atoi(arg);
522             break;
523
524 /* *************************************************************************
525  * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
526  * *************************************************************************/
527 #ifdef FEATURE_ACL
528          case hash_deny_access:
529             strlcpy(tmp, arg, sizeof(tmp));
530             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
531
532             if ((vec_count != 1) && (vec_count != 2))
533             {
534                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
535                      "deny-access directive in configuration file.");
536                string_append(&config->proxy_args,
537                   "<br>\nWARNING: Wrong number of parameters for "
538                   "deny-access directive in configuration file.<br><br>\n");
539                break;
540             }
541
542             /* allocate a new node */
543             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
544
545             if (cur_acl == NULL)
546             {
547                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
548                /* Never get here - LOG_LEVEL_FATAL causes program exit */
549                break;
550             }
551             cur_acl->action = ACL_DENY;
552
553             if (acl_addr(vec[0], cur_acl->src) < 0)
554             {
555                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
556                   "for deny-access directive in configuration file: \"%s\"", vec[0]);
557                string_append(&config->proxy_args,
558                   "<br>\nWARNING: Invalid source address, port or netmask "
559                   "for deny-access directive in configuration file: \"");
560                string_append(&config->proxy_args,
561                   vec[0]);
562                string_append(&config->proxy_args,
563                   "\"<br><br>\n");
564                freez(cur_acl);
565                break;
566             }
567             if (vec_count == 2)
568             {
569                if (acl_addr(vec[1], cur_acl->dst) < 0)
570                {
571                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
572                      "for deny-access directive in configuration file: \"%s\"", vec[1]);
573                   string_append(&config->proxy_args,
574                      "<br>\nWARNING: Invalid destination address, port or netmask "
575                      "for deny-access directive in configuration file: \"");
576                   string_append(&config->proxy_args,
577                      vec[1]);
578                   string_append(&config->proxy_args,
579                      "\"<br><br>\n");
580                   freez(cur_acl);
581                   break;
582                }
583             }
584 #ifdef HAVE_RFC2553
585             else
586             {
587                cur_acl->wildcard_dst = 1;
588             }
589 #endif /* def HAVE_RFC2553 */
590
591             /*
592              * Add it to the list.  Note we reverse the list to get the
593              * behaviour the user expects.  With both the ACL and
594              * actions file, the last match wins.  However, the internal
595              * implementations are different:  The actions file is stored
596              * in the same order as the file, and scanned completely.
597              * With the ACL, we reverse the order as we load it, then
598              * when we scan it we stop as soon as we get a match.
599              */
600             cur_acl->next  = config->acl;
601             config->acl = cur_acl;
602
603             break;
604 #endif /* def FEATURE_ACL */
605
606 /* *************************************************************************
607  * enable-edit-actions 0|1
608  * *************************************************************************/
609 #ifdef FEATURE_CGI_EDIT_ACTIONS
610          case hash_enable_edit_actions:
611             if ((*arg != '\0') && (0 != atoi(arg)))
612             {
613                config->feature_flags |= RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
614             }
615             else
616             {
617                config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
618             }
619             break;
620 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
621
622 /* *************************************************************************
623  * enable-remote-toggle 0|1
624  * *************************************************************************/
625 #ifdef FEATURE_TOGGLE
626          case hash_enable_remote_toggle:
627             if ((*arg != '\0') && (0 != atoi(arg)))
628             {
629                config->feature_flags |= RUNTIME_FEATURE_CGI_TOGGLE;
630             }
631             else
632             {
633                config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE;
634             }
635             break;
636 #endif /* def FEATURE_TOGGLE */
637
638 /* *************************************************************************
639  * enable-remote-http-toggle 0|1
640  * *************************************************************************/
641          case hash_enable_remote_http_toggle:
642             if ((*arg != '\0') && (0 != atoi(arg)))
643             {
644                config->feature_flags |= RUNTIME_FEATURE_HTTP_TOGGLE;
645             }
646             else
647             {
648                config->feature_flags &= ~RUNTIME_FEATURE_HTTP_TOGGLE;
649             }
650             break;
651
652 /* *************************************************************************
653  * enforce-blocks 0|1
654  * *************************************************************************/
655          case hash_enforce_blocks:
656 #ifdef FEATURE_FORCE_LOAD
657             if ((*arg != '\0') && (0 != atoi(arg)))
658             {
659                config->feature_flags |= RUNTIME_FEATURE_ENFORCE_BLOCKS;
660             }
661             else
662             {
663                config->feature_flags &= ~RUNTIME_FEATURE_ENFORCE_BLOCKS;
664             }
665 #else
666             log_error(LOG_LEVEL_ERROR, "Ignoring directive 'enforce-blocks'. "
667                "FEATURE_FORCE_LOAD is disabled, blocks will always be enforced.");
668 #endif /* def FEATURE_FORCE_LOAD */
669             break;
670
671 /* *************************************************************************
672  * filterfile file-name
673  * In confdir by default.
674  * *************************************************************************/
675          case hash_filterfile :
676             i = 0;
677             while ((i < MAX_AF_FILES) && (NULL != config->re_filterfile[i]))
678             {
679                i++;
680             }
681
682             if (i >= MAX_AF_FILES)
683             {
684                log_error(LOG_LEVEL_FATAL, "Too many 'filterfile' directives in config file - limit is %d.\n"
685                   "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).",
686                   MAX_AF_FILES);
687             }
688             config->re_filterfile_short[i] = strdup(arg);
689             config->re_filterfile[i] = make_path(config->confdir, arg);
690
691             break;
692
693 /* *************************************************************************
694  * forward url-pattern (.|http-proxy-host[:port])
695  * *************************************************************************/
696          case hash_forward:
697             strlcpy(tmp, arg, sizeof(tmp));
698             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
699
700             if (vec_count != 2)
701             {
702                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward "
703                      "directive in configuration file.");
704                string_append(&config->proxy_args,
705                   "<br>\nWARNING: Wrong number of parameters for "
706                   "forward directive in configuration file.");
707                break;
708             }
709
710             /* allocate a new node */
711             cur_fwd = zalloc(sizeof(*cur_fwd));
712             if (cur_fwd == NULL)
713             {
714                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
715                /* Never get here - LOG_LEVEL_FATAL causes program exit */
716                break;
717             }
718
719             cur_fwd->type = SOCKS_NONE;
720
721             /* Save the URL pattern */
722             if (create_url_spec(cur_fwd->url, vec[0]))
723             {
724                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward "
725                      "directive in configuration file.");
726                string_append(&config->proxy_args,
727                   "<br>\nWARNING: Bad URL specifier for "
728                   "forward directive in configuration file.");
729                break;
730             }
731
732             /* Parse the parent HTTP proxy host:port */
733             p = vec[1];
734
735             if (strcmp(p, ".") != 0)
736             {
737                cur_fwd->forward_port = 8000;
738                parse_forwarder_address(p, &cur_fwd->forward_host,
739                   &cur_fwd->forward_port);
740             }
741
742             /* Add to list. */
743             cur_fwd->next = config->forward;
744             config->forward = cur_fwd;
745
746             break;
747
748 /* *************************************************************************
749  * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port])
750  * *************************************************************************/
751          case hash_forward_socks4:
752             strlcpy(tmp, arg, sizeof(tmp));
753             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
754
755             if (vec_count != 3)
756             {
757                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
758                      "forward-socks4 directive in configuration file.");
759                string_append(&config->proxy_args,
760                   "<br>\nWARNING: Wrong number of parameters for "
761                   "forward-socks4 directive in configuration file.");
762                break;
763             }
764
765             /* allocate a new node */
766             cur_fwd = zalloc(sizeof(*cur_fwd));
767             if (cur_fwd == NULL)
768             {
769                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
770                /* Never get here - LOG_LEVEL_FATAL causes program exit */
771                break;
772             }
773
774             cur_fwd->type = SOCKS_4;
775
776             /* Save the URL pattern */
777             if (create_url_spec(cur_fwd->url, vec[0]))
778             {
779                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 "
780                      "directive in configuration file.");
781                string_append(&config->proxy_args,
782                   "<br>\nWARNING: Bad URL specifier for "
783                   "forward-socks4 directive in configuration file.");
784                break;
785             }
786
787             /* Parse the SOCKS proxy host[:port] */
788             p = vec[1];
789
790             /* XXX: This check looks like a bug. */
791             if (strcmp(p, ".") != 0)
792             {
793                cur_fwd->gateway_port = 1080;
794                parse_forwarder_address(p, &cur_fwd->gateway_host,
795                   &cur_fwd->gateway_port);
796             }
797
798             /* Parse the parent HTTP proxy host[:port] */
799             p = vec[2];
800
801             if (strcmp(p, ".") != 0)
802             {
803                cur_fwd->forward_port = 8000;
804                parse_forwarder_address(p, &cur_fwd->forward_host,
805                   &cur_fwd->forward_port);
806             }
807
808             /* Add to list. */
809             cur_fwd->next = config->forward;
810             config->forward = cur_fwd;
811
812             break;
813
814 /* *************************************************************************
815  * forward-socks4a url-pattern socks-proxy[:port] (.|http-proxy[:port])
816  * *************************************************************************/
817          case hash_forward_socks4a:
818          case hash_forward_socks5:
819             strlcpy(tmp, arg, sizeof(tmp));
820             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
821
822             if (vec_count != 3)
823             {
824                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
825                      "forward-socks4a directive in configuration file.");
826                string_append(&config->proxy_args,
827                   "<br>\nWARNING: Wrong number of parameters for "
828                   "forward-socks4a directive in configuration file.");
829                break;
830             }
831
832             /* allocate a new node */
833             cur_fwd = zalloc(sizeof(*cur_fwd));
834             if (cur_fwd == NULL)
835             {
836                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
837                /* Never get here - LOG_LEVEL_FATAL causes program exit */
838                break;
839             }
840
841             if (directive_hash == hash_forward_socks4a)
842             {
843                cur_fwd->type = SOCKS_4A;
844             }
845             else
846             {
847                cur_fwd->type = SOCKS_5;
848             }
849
850             /* Save the URL pattern */
851             if (create_url_spec(cur_fwd->url, vec[0]))
852             {
853                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4a "
854                      "directive in configuration file.");
855                string_append(&config->proxy_args,
856                   "<br>\nWARNING: Bad URL specifier for "
857                   "forward-socks4a directive in configuration file.");
858                break;
859             }
860
861             /* Parse the SOCKS proxy host[:port] */
862             p = vec[1];
863
864             cur_fwd->gateway_port = 1080;
865             parse_forwarder_address(p, &cur_fwd->gateway_host,
866                &cur_fwd->gateway_port);
867
868             /* Parse the parent HTTP proxy host[:port] */
869             p = vec[2];
870
871             if (strcmp(p, ".") != 0)
872             {
873                cur_fwd->forward_port = 8000;
874                parse_forwarder_address(p, &cur_fwd->forward_host,
875                   &cur_fwd->forward_port);
876             }
877
878             /* Add to list. */
879             cur_fwd->next = config->forward;
880             config->forward = cur_fwd;
881
882             break;
883
884 /* *************************************************************************
885  * forwarded-connect-retries n
886  * *************************************************************************/
887          case hash_forwarded_connect_retries :
888             config->forwarded_connect_retries = atoi(arg);
889             break;
890
891 /* *************************************************************************
892  * hostname hostname-to-show-on-cgi-pages
893  * *************************************************************************/
894          case hash_hostname :
895             freez(config->hostname);
896             config->hostname = strdup(arg);
897             if (NULL == config->hostname)
898             {
899                log_error(LOG_LEVEL_FATAL, "Out of memory saving hostname.");
900             }
901             break;
902
903 /* *************************************************************************
904  * keep-alive-timeout timeout
905  * *************************************************************************/
906 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
907          case hash_keep_alive_timeout :
908             if (*arg != '\0')
909             {
910                int timeout = atoi(arg);
911                if (0 < timeout)
912                {
913                   config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
914                   config->keep_alive_timeout = (unsigned int)timeout;
915                }
916                else
917                {
918                   config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
919                }
920             }
921             break;
922 #endif
923
924 /* *************************************************************************
925  * listen-address [ip][:port]
926  * *************************************************************************/
927          case hash_listen_address :
928             freez(config->haddr);
929             config->haddr = strdup(arg);
930             break;
931
932 /* *************************************************************************
933  * logdir directory-name
934  * *************************************************************************/
935          case hash_logdir :
936             freez(config->logdir);
937             config->logdir = make_path(NULL, arg);
938             break;
939
940 /* *************************************************************************
941  * logfile log-file-name
942  * In logdir by default
943  * *************************************************************************/
944          case hash_logfile :
945             if (!no_daemon)
946             {
947                logfile = make_path(config->logdir, arg);
948                if (NULL == logfile)
949                {
950                   log_error(LOG_LEVEL_FATAL, "Out of memory while creating logfile path");
951                }
952             }
953             break;
954
955 /* *************************************************************************
956  * max-client-connections number
957  * *************************************************************************/
958          case hash_max_client_connections :
959             if (*arg != '\0')
960             {
961                int max_client_connections = atoi(arg);
962                if (0 <= max_client_connections)
963                {
964                   config->max_client_connections = max_client_connections;
965                }
966             }
967             break;
968
969 /* *************************************************************************
970  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
971  * *************************************************************************/
972 #ifdef FEATURE_ACL
973          case hash_permit_access:
974             strlcpy(tmp, arg, sizeof(tmp));
975             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
976
977             if ((vec_count != 1) && (vec_count != 2))
978             {
979                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
980                      "permit-access directive in configuration file.");
981                string_append(&config->proxy_args,
982                   "<br>\nWARNING: Wrong number of parameters for "
983                   "permit-access directive in configuration file.<br><br>\n");
984
985                break;
986             }
987
988             /* allocate a new node */
989             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
990
991             if (cur_acl == NULL)
992             {
993                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
994                /* Never get here - LOG_LEVEL_FATAL causes program exit */
995                break;
996             }
997             cur_acl->action = ACL_PERMIT;
998
999             if (acl_addr(vec[0], cur_acl->src) < 0)
1000             {
1001                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
1002                   "for permit-access directive in configuration file: \"%s\"", vec[0]);
1003                string_append(&config->proxy_args,
1004                   "<br>\nWARNING: Invalid source address, port or netmask for "
1005                   "permit-access directive in configuration file: \"");
1006                string_append(&config->proxy_args,
1007                   vec[0]);
1008                string_append(&config->proxy_args,
1009                   "\"<br><br>\n");
1010                freez(cur_acl);
1011                break;
1012             }
1013             if (vec_count == 2)
1014             {
1015                if (acl_addr(vec[1], cur_acl->dst) < 0)
1016                {
1017                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
1018                      "for permit-access directive in configuration file: \"%s\"", vec[1]);
1019                   string_append(&config->proxy_args,
1020                      "<br>\nWARNING: Invalid destination address, port or netmask for "
1021                      "permit-access directive in configuration file: \"");
1022                   string_append(&config->proxy_args,
1023                      vec[1]);
1024                   string_append(&config->proxy_args,
1025                      "\"<br><br>\n");
1026                   freez(cur_acl);
1027                   break;
1028                }
1029             }
1030 #ifdef HAVE_RFC2553
1031             else
1032             {
1033                cur_acl->wildcard_dst = 1;
1034             }
1035 #endif /* def HAVE_RFC2553 */
1036
1037             /*
1038              * Add it to the list.  Note we reverse the list to get the
1039              * behaviour the user expects.  With both the ACL and
1040              * actions file, the last match wins.  However, the internal
1041              * implementations are different:  The actions file is stored
1042              * in the same order as the file, and scanned completely.
1043              * With the ACL, we reverse the order as we load it, then
1044              * when we scan it we stop as soon as we get a match.
1045              */
1046             cur_acl->next  = config->acl;
1047             config->acl = cur_acl;
1048
1049             break;
1050 #endif /* def FEATURE_ACL */
1051
1052 /* *************************************************************************
1053  * proxy-info-url url
1054  * *************************************************************************/
1055          case hash_proxy_info_url :
1056             freez(config->proxy_info_url);
1057             config->proxy_info_url = strdup(arg);
1058             break;
1059
1060 /* *************************************************************************
1061  * single-threaded
1062  * *************************************************************************/
1063          case hash_single_threaded :
1064             config->multi_threaded = 0;
1065             break;
1066
1067 /* *************************************************************************
1068  * socket-timeout numer_of_seconds
1069  * *************************************************************************/
1070          case hash_socket_timeout :
1071             if (*arg != '\0')
1072             {
1073                int socket_timeout = atoi(arg);
1074                if (0 < socket_timeout)
1075                {
1076                   config->socket_timeout = socket_timeout;
1077                }
1078                else
1079                {
1080                   log_error(LOG_LEVEL_FATAL,
1081                      "Invalid socket-timeout: '%s'", arg);
1082                }
1083             }
1084             break;
1085
1086 /* *************************************************************************
1087  * split-large-cgi-forms
1088  * *************************************************************************/
1089          case hash_split_large_cgi_forms :
1090             if ((*arg != '\0') && (0 != atoi(arg)))
1091             {
1092                config->feature_flags |= RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1093             }
1094             else
1095             {
1096                config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1097             }
1098             break;
1099
1100 /* *************************************************************************
1101  * templdir directory-name
1102  * *************************************************************************/
1103          case hash_templdir :
1104             freez(config->templdir);
1105             config->templdir = make_path(NULL, arg);
1106             break;
1107
1108 /* *************************************************************************
1109  * toggle (0|1)
1110  * *************************************************************************/
1111 #ifdef FEATURE_TOGGLE
1112          case hash_toggle :
1113             global_toggle_state = atoi(arg);
1114             break;
1115 #endif /* def FEATURE_TOGGLE */
1116
1117 /* *************************************************************************
1118  * trust-info-url url
1119  * *************************************************************************/
1120 #ifdef FEATURE_TRUST
1121          case hash_trust_info_url :
1122             enlist(config->trust_info, arg);
1123             break;
1124 #endif /* def FEATURE_TRUST */
1125
1126 /* *************************************************************************
1127  * trustfile filename
1128  * (In confdir by default.)
1129  * *************************************************************************/
1130 #ifdef FEATURE_TRUST
1131          case hash_trustfile :
1132             freez(config->trustfile);
1133             config->trustfile = make_path(config->confdir, arg);
1134             break;
1135 #endif /* def FEATURE_TRUST */
1136
1137 /* *************************************************************************
1138  * usermanual url
1139  * *************************************************************************/
1140          case hash_usermanual :
1141             /*
1142              * XXX: If this isn't the first config directive, the
1143              * show-status page links to the website documentation
1144              * for the directives that were already parsed. Lame.
1145              */
1146             freez(config->usermanual);
1147             config->usermanual = strdup(arg);
1148             break;
1149
1150 /* *************************************************************************
1151  * Win32 Console options:
1152  * *************************************************************************/
1153
1154 /* *************************************************************************
1155  * hide-console
1156  * *************************************************************************/
1157 #ifdef _WIN_CONSOLE
1158          case hash_hide_console :
1159             hideConsole = 1;
1160             break;
1161 #endif /*def _WIN_CONSOLE*/
1162
1163
1164 /* *************************************************************************
1165  * Win32 GUI options:
1166  * *************************************************************************/
1167
1168 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
1169 /* *************************************************************************
1170  * activity-animation (0|1)
1171  * *************************************************************************/
1172          case hash_activity_animation :
1173             g_bShowActivityAnimation = atoi(arg);
1174             break;
1175
1176 /* *************************************************************************
1177  *  close-button-minimizes (0|1)
1178  * *************************************************************************/
1179          case hash_close_button_minimizes :
1180             g_bCloseHidesWindow = atoi(arg);
1181             break;
1182
1183 /* *************************************************************************
1184  * log-buffer-size (0|1)
1185  * *************************************************************************/
1186          case hash_log_buffer_size :
1187             g_bLimitBufferSize = atoi(arg);
1188             break;
1189
1190 /* *************************************************************************
1191  * log-font-name fontname
1192  * *************************************************************************/
1193          case hash_log_font_name :
1194             if (strlcpy(g_szFontFaceName, arg,
1195                    sizeof(g_szFontFaceName)) >= sizeof(g_szFontFaceName))
1196             {
1197                log_error(LOG_LEVEL_FATAL,
1198                   "log-font-name argument '%s' is longer than %u characters.",
1199                   arg, sizeof(g_szFontFaceName)-1);
1200             }
1201             break;
1202
1203 /* *************************************************************************
1204  * log-font-size n
1205  * *************************************************************************/
1206          case hash_log_font_size :
1207             g_nFontSize = atoi(arg);
1208             break;
1209
1210 /* *************************************************************************
1211  * log-highlight-messages (0|1)
1212  * *************************************************************************/
1213          case hash_log_highlight_messages :
1214             g_bHighlightMessages = atoi(arg);
1215             break;
1216
1217 /* *************************************************************************
1218  * log-max-lines n
1219  * *************************************************************************/
1220          case hash_log_max_lines :
1221             g_nMaxBufferLines = atoi(arg);
1222             break;
1223
1224 /* *************************************************************************
1225  * log-messages (0|1)
1226  * *************************************************************************/
1227          case hash_log_messages :
1228             g_bLogMessages = atoi(arg);
1229             break;
1230
1231 /* *************************************************************************
1232  * show-on-task-bar (0|1)
1233  * *************************************************************************/
1234          case hash_show_on_task_bar :
1235             g_bShowOnTaskBar = atoi(arg);
1236             break;
1237
1238 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
1239
1240
1241 /* *************************************************************************
1242  * Warnings about unsupported features
1243  * *************************************************************************/
1244 #ifndef FEATURE_ACL
1245          case hash_deny_access:
1246 #endif /* ndef FEATURE_ACL */
1247 #ifndef FEATURE_CGI_EDIT_ACTIONS
1248          case hash_enable_edit_actions:
1249 #endif /* ndef FEATURE_CGI_EDIT_ACTIONS */
1250 #ifndef FEATURE_TOGGLE
1251          case hash_enable_remote_toggle:
1252 #endif /* ndef FEATURE_TOGGLE */
1253 #ifndef FEATURE_ACL
1254          case hash_permit_access:
1255 #endif /* ndef FEATURE_ACL */
1256 #ifndef FEATURE_TOGGLE
1257          case hash_toggle :
1258 #endif /* ndef FEATURE_TOGGLE */
1259 #ifndef FEATURE_TRUST
1260          case hash_trustfile :
1261          case hash_trust_info_url :
1262 #endif /* ndef FEATURE_TRUST */
1263
1264 #ifndef _WIN_CONSOLE
1265          case hash_hide_console :
1266 #endif /* ndef _WIN_CONSOLE */
1267
1268 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
1269          case hash_activity_animation :
1270          case hash_close_button_minimizes :
1271          case hash_log_buffer_size :
1272          case hash_log_font_name :
1273          case hash_log_font_size :
1274          case hash_log_highlight_messages :
1275          case hash_log_max_lines :
1276          case hash_log_messages :
1277          case hash_show_on_task_bar :
1278 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
1279             /* These warnings are annoying - so hide them. -- Jon */
1280             /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */
1281             break;
1282
1283 /* *************************************************************************/
1284          default :
1285 /* *************************************************************************/
1286             /*
1287              * I decided that I liked this better as a warning than an
1288              * error.  To change back to an error, just change log level
1289              * to LOG_LEVEL_FATAL.
1290              */
1291             log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive '%s' (%luul) in line %lu "
1292                   "in configuration file (%s).",  buf, directive_hash, linenum, configfile);
1293             string_append(&config->proxy_args,
1294                " <strong class='warning'>Warning: Ignoring unrecognized directive:</strong>");
1295             break;
1296
1297 /* *************************************************************************/
1298       } /* end switch( hash_string(cmd) ) */
1299
1300       /* Save the argument for the show-status page. */
1301       savearg(cmd, arg, config);
1302
1303    } /* end while ( read_config_line(...) ) */
1304
1305    fclose(configfp);
1306
1307    set_debug_level(config->debug);
1308
1309    freez(config->logfile);
1310
1311    if (!no_daemon)
1312    {
1313       if (NULL != logfile)
1314       {
1315          config->logfile = logfile;
1316          init_error_log(Argv[0], config->logfile);
1317       }
1318       else
1319       {
1320          disable_logging();
1321       }
1322    }
1323
1324 #ifdef FEATURE_CONNECTION_SHARING
1325    if (config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
1326    {
1327       if (config->multi_threaded)
1328       {
1329          set_keep_alive_timeout(config->keep_alive_timeout);
1330       }
1331       else
1332       {
1333          /*
1334           * While we could use keep-alive without multiple threads
1335           * if we didn't bother with enforcing the connection timeout,
1336           * that might make Tor users sad, even though they shouldn't
1337           * enable the single-threaded option anyway.
1338           *
1339           * XXX: We could still use Proxy-Connection: keep-alive.
1340           */
1341          config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
1342          log_error(LOG_LEVEL_ERROR,
1343             "Config option single-threaded disables connection keep-alive.");
1344       }
1345    }
1346    else if ((config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
1347    {
1348       log_error(LOG_LEVEL_ERROR, "Config option connection-sharing "
1349          "has no effect if keep-alive-timeout isn't set.");
1350       config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
1351    }
1352 #endif /* def FEATURE_CONNECTION_SHARING */
1353
1354    if (NULL == config->proxy_args)
1355    {
1356       log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args");
1357    }
1358
1359    if (config->actions_file[0])
1360    {
1361       add_loader(load_action_files, config);
1362    }
1363
1364    if (config->re_filterfile[0])
1365    {
1366       add_loader(load_re_filterfiles, config);
1367    }
1368
1369 #ifdef FEATURE_TRUST
1370    if (config->trustfile)
1371    {
1372       add_loader(load_trustfile, config);
1373    }
1374 #endif /* def FEATURE_TRUST */
1375
1376    if ( NULL == config->haddr )
1377    {
1378       config->haddr = strdup( HADDR_DEFAULT );
1379    }
1380
1381    if ( NULL != config->haddr )
1382    {
1383       if ((*config->haddr == '[')
1384          && (NULL != (p = strchr(config->haddr, ']')))
1385          && (p[1] == ':')
1386          && (0 < (config->hport = atoi(p + 2))))
1387       {
1388          *p = '\0';
1389          memmove((void *)config->haddr, config->haddr + 1,
1390             (size_t)(p - config->haddr));
1391       }
1392       else if (NULL != (p = strchr(config->haddr, ':'))
1393          && (0 < (config->hport = atoi(p + 1))))
1394       {
1395          *p = '\0';
1396       }
1397       else
1398       {
1399          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
1400          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1401       }
1402       if (*config->haddr == '\0')
1403       {
1404          /*
1405           * Only the port specified. We stored it in config->hport
1406           * and don't need its text representation anymore.
1407           */
1408          freez(config->haddr);
1409       }
1410    }
1411
1412    /*
1413     * Want to run all the loaders once now.
1414     *
1415     * Need to set up a fake csp, so they can get to the config.
1416     */
1417    fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp));
1418    fake_csp->config = config;
1419
1420    if (run_loader(fake_csp))
1421    {
1422       freez(fake_csp);
1423       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
1424       /* Never get here - LOG_LEVEL_FATAL causes program exit */
1425    }
1426    freez(fake_csp);
1427
1428 /* FIXME: this is a kludge for win32 */
1429 #if defined(_WIN32) && !defined (_WIN_CONSOLE)
1430
1431    g_default_actions_file = config->actions_file[1]; /* FIXME Hope this is default.action */
1432    g_user_actions_file = config->actions_file[2]; /* FIXME Hope this is user.action */
1433    g_re_filterfile    = config->re_filterfile[0]; /* FIXME Hope this is default.filter */
1434
1435 #ifdef FEATURE_TRUST
1436    g_trustfile        = config->trustfile;
1437 #endif /* def FEATURE_TRUST */
1438
1439
1440 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
1441 /* FIXME: end kludge */
1442
1443
1444    config->need_bind = 1;
1445
1446    if (current_configfile)
1447    {
1448       struct configuration_spec * oldcfg = (struct configuration_spec *)
1449                                            current_configfile->f;
1450       /*
1451        * Check if config->haddr,hport == oldcfg->haddr,hport
1452        *
1453        * The following could be written more compactly as a single,
1454        * (unreadably long) if statement.
1455        */
1456       config->need_bind = 0;
1457       if (config->hport != oldcfg->hport)
1458       {
1459          config->need_bind = 1;
1460       }
1461       else if (config->haddr == NULL)
1462       {
1463          if (oldcfg->haddr != NULL)
1464          {
1465             config->need_bind = 1;
1466          }
1467       }
1468       else if (oldcfg->haddr == NULL)
1469       {
1470          config->need_bind = 1;
1471       }
1472       else if (0 != strcmp(config->haddr, oldcfg->haddr))
1473       {
1474          config->need_bind = 1;
1475       }
1476
1477       current_configfile->unloader = unload_configfile;
1478    }
1479
1480    fs->next = files->next;
1481    files->next = fs;
1482
1483    current_configfile = fs;
1484
1485    return (config);
1486 }
1487
1488
1489 /*********************************************************************
1490  *
1491  * Function    :  savearg
1492  *
1493  * Description :  Called from `load_config'.  It saves each non-empty
1494  *                and non-comment line from config into
1495  *                config->proxy_args.  This is used to create the
1496  *                show-proxy-args page.  On error, frees
1497  *                config->proxy_args and sets it to NULL
1498  *
1499  * Parameters  :
1500  *          1  :  command = config setting that was found
1501  *          2  :  argument = the setting's argument (if any)
1502  *          3  :  config = Configuration to save into.
1503  *
1504  * Returns     :  N/A
1505  *
1506  *********************************************************************/
1507 static void savearg(char *command, char *argument, struct configuration_spec * config)
1508 {
1509    char * buf;
1510    char * s;
1511
1512    assert(command);
1513    assert(argument);
1514
1515    /*
1516     * Add config option name embedded in
1517     * link to its section in the user-manual
1518     */
1519    buf = strdup("\n<a href=\"");
1520    if (!strncmpic(config->usermanual, "file://", 7) ||
1521        !strncmpic(config->usermanual, "http", 4))
1522    {
1523       string_append(&buf, config->usermanual);
1524    }
1525    else
1526    {
1527       string_append(&buf, "http://" CGI_SITE_2_HOST "/user-manual/");
1528    }
1529    string_append(&buf, CONFIG_HELP_PREFIX);
1530    string_join  (&buf, string_toupper(command));
1531    string_append(&buf, "\">");
1532    string_append(&buf, command);
1533    string_append(&buf, "</a> ");
1534
1535    if (NULL == buf)
1536    {
1537       freez(config->proxy_args);
1538       return;
1539    }
1540
1541    if ( (NULL != argument) && ('\0' != *argument) )
1542    {
1543       s = html_encode(argument);
1544       if (NULL == s)
1545       {
1546          freez(buf);
1547          freez(config->proxy_args);
1548          return;
1549       }
1550
1551       if (strncmpic(argument, "http://", 7) == 0)
1552       {
1553          string_append(&buf, "<a href=\"");
1554          string_append(&buf, s);
1555          string_append(&buf, "\">");
1556          string_join  (&buf, s);
1557          string_append(&buf, "</a>");
1558       }
1559       else
1560       {
1561          string_join  (&buf, s);
1562       }
1563    }
1564
1565    string_append(&buf, "<br>");
1566    string_join(&config->proxy_args, buf);
1567 }
1568
1569
1570 /*
1571   Local Variables:
1572   tab-width: 3
1573   end:
1574 */