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