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