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