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