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