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