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