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