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