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