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