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