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