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