privoxy-regression-test: When get_cgi_page_or_else() fails, include the URL of the...
[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 (max_client_connections < 1)
1464             {
1465                log_error(LOG_LEVEL_FATAL, "max-client-connections value"
1466                   " has to be a number above 1. %d is invalid.",
1467                   max_client_connections);
1468             }
1469
1470             config->max_client_connections = max_client_connections;
1471             break;
1472          }
1473
1474 /* *************************************************************************
1475  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
1476  * *************************************************************************/
1477 #ifdef FEATURE_ACL
1478          case hash_permit_access:
1479             strlcpy(tmp, arg, sizeof(tmp));
1480             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
1481
1482             if ((vec_count != 1) && (vec_count != 2))
1483             {
1484                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
1485                      "permit-access directive in configuration file.");
1486                string_append(&config->proxy_args,
1487                   "<br>\nWARNING: Wrong number of parameters for "
1488                   "permit-access directive in configuration file.<br><br>\n");
1489
1490                break;
1491             }
1492
1493             /* allocate a new node */
1494             cur_acl = zalloc_or_die(sizeof(*cur_acl));
1495             cur_acl->action = ACL_PERMIT;
1496
1497             if (acl_addr(vec[0], cur_acl->src) < 0)
1498             {
1499                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
1500                   "for permit-access directive in configuration file: \"%s\"", vec[0]);
1501                string_append(&config->proxy_args,
1502                   "<br>\nWARNING: Invalid source address, port or netmask for "
1503                   "permit-access directive in configuration file: \"");
1504                string_append(&config->proxy_args,
1505                   vec[0]);
1506                string_append(&config->proxy_args,
1507                   "\"<br><br>\n");
1508                freez(cur_acl);
1509                break;
1510             }
1511             if (vec_count == 2)
1512             {
1513                if (acl_addr(vec[1], cur_acl->dst) < 0)
1514                {
1515                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
1516                      "for permit-access directive in configuration file: \"%s\"", vec[1]);
1517                   string_append(&config->proxy_args,
1518                      "<br>\nWARNING: Invalid destination address, port or netmask for "
1519                      "permit-access directive in configuration file: \"");
1520                   string_append(&config->proxy_args,
1521                      vec[1]);
1522                   string_append(&config->proxy_args,
1523                      "\"<br><br>\n");
1524                   freez(cur_acl);
1525                   break;
1526                }
1527             }
1528 #ifdef HAVE_RFC2553
1529             else
1530             {
1531                cur_acl->wildcard_dst = 1;
1532             }
1533 #endif /* def HAVE_RFC2553 */
1534
1535             /*
1536              * Add it to the list.  Note we reverse the list to get the
1537              * behaviour the user expects.  With both the ACL and
1538              * actions file, the last match wins.  However, the internal
1539              * implementations are different:  The actions file is stored
1540              * in the same order as the file, and scanned completely.
1541              * With the ACL, we reverse the order as we load it, then
1542              * when we scan it we stop as soon as we get a match.
1543              */
1544             cur_acl->next  = config->acl;
1545             config->acl = cur_acl;
1546
1547             break;
1548 #endif /* def FEATURE_ACL */
1549
1550 /* *************************************************************************
1551  * proxy-info-url url
1552  * *************************************************************************/
1553          case hash_proxy_info_url :
1554             freez(config->proxy_info_url);
1555             config->proxy_info_url = strdup_or_die(arg);
1556             break;
1557
1558
1559 /* *************************************************************************
1560  * receive-buffer-size n
1561  * *************************************************************************/
1562          case hash_receive_buffer_size :
1563             config->receive_buffer_size = (size_t)parse_numeric_value(cmd, arg);
1564             if (config->receive_buffer_size < BUFFER_SIZE)
1565             {
1566                log_error(LOG_LEVEL_INFO,
1567                   "receive-buffer-size %lu seems low and may cause problems."
1568                   "Consider setting it to at least %d.",
1569                   config->receive_buffer_size, BUFFER_SIZE);
1570             }
1571             break;
1572
1573 /* *************************************************************************
1574  * single-threaded 0|1
1575  * *************************************************************************/
1576          case hash_single_threaded :
1577             config->multi_threaded =  0 == parse_toggle_state(cmd, arg);
1578             break;
1579
1580 /* *************************************************************************
1581  * socket-timeout numer_of_seconds
1582  * *************************************************************************/
1583          case hash_socket_timeout :
1584          {
1585             int socket_timeout = parse_numeric_value(cmd, arg);
1586             if (0 <= socket_timeout)
1587             {
1588                config->socket_timeout = socket_timeout;
1589             }
1590             else
1591             {
1592                log_error(LOG_LEVEL_FATAL, "Invalid socket-timeout: '%s'", arg);
1593             }
1594             break;
1595          }
1596
1597 /* *************************************************************************
1598  * split-large-cgi-forms
1599  * *************************************************************************/
1600          case hash_split_large_cgi_forms :
1601             if (parse_toggle_state(cmd, arg) == 1)
1602             {
1603                config->feature_flags |= RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1604             }
1605             else
1606             {
1607                config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1608             }
1609             break;
1610
1611 /* *************************************************************************
1612  * templdir directory-name
1613  * *************************************************************************/
1614          case hash_templdir :
1615             freez(config->templdir);
1616             config->templdir = make_path(NULL, arg);
1617             break;
1618
1619 #ifdef FEATURE_EXTERNAL_FILTERS
1620 /* *************************************************************************
1621  * temporary-directory directory-name
1622  * *************************************************************************/
1623          case hash_temporary_directory :
1624             freez(config->temporary_directory);
1625             config->temporary_directory = make_path(NULL, arg);
1626             break;
1627 #endif
1628
1629 /* *************************************************************************
1630  * tolerate-pipelining (0|1)
1631  * *************************************************************************/
1632          case hash_tolerate_pipelining :
1633             if (parse_toggle_state(cmd, arg) == 1)
1634             {
1635                config->feature_flags |= RUNTIME_FEATURE_TOLERATE_PIPELINING;
1636             }
1637             else
1638             {
1639                config->feature_flags &= ~RUNTIME_FEATURE_TOLERATE_PIPELINING;
1640             }
1641             break;
1642
1643 /* *************************************************************************
1644  * toggle (0|1)
1645  * *************************************************************************/
1646 #ifdef FEATURE_TOGGLE
1647          case hash_toggle :
1648             global_toggle_state = parse_toggle_state(cmd, arg);
1649             break;
1650 #endif /* def FEATURE_TOGGLE */
1651
1652 /* *************************************************************************
1653  * trust-info-url url
1654  * *************************************************************************/
1655 #ifdef FEATURE_TRUST
1656          case hash_trust_info_url :
1657             enlist(config->trust_info, arg);
1658             break;
1659 #endif /* def FEATURE_TRUST */
1660
1661 /* *************************************************************************
1662  * trust-x-forwarded-for (0|1)
1663  * *************************************************************************/
1664          case hash_trust_x_forwarded_for :
1665             config->trust_x_forwarded_for = parse_toggle_state(cmd, arg);
1666             break;
1667
1668 /* *************************************************************************
1669  * trusted-cgi-referrer http://www.example.org/some/path.html
1670  * *************************************************************************/
1671          case hash_trusted_cgi_referrer :
1672             /*
1673              * We don't validate the specified referrer as
1674              * it's only used for string comparison.
1675              */
1676             freez(config->trusted_cgi_referrer);
1677             config->trusted_cgi_referrer = strdup_or_die(arg);
1678             break;
1679
1680 /* *************************************************************************
1681  * trustfile filename
1682  * (In confdir by default.)
1683  * *************************************************************************/
1684 #ifdef FEATURE_TRUST
1685          case hash_trustfile :
1686             freez(config->trustfile);
1687             config->trustfile = make_path(config->confdir, arg);
1688             break;
1689 #endif /* def FEATURE_TRUST */
1690
1691 /* *************************************************************************
1692  * usermanual url
1693  * *************************************************************************/
1694          case hash_usermanual :
1695             /*
1696              * XXX: If this isn't the first config directive, the
1697              * show-status page links to the website documentation
1698              * for the directives that were already parsed. Lame.
1699              */
1700             freez(config->usermanual);
1701             config->usermanual = strdup_or_die(arg);
1702             break;
1703
1704 #ifdef FEATURE_HTTPS_INSPECTION
1705 /* *************************************************************************
1706  * ca private key file password
1707  * *************************************************************************/
1708          case hash_ca_password:
1709             freez(config->ca_password);
1710             config->ca_password = strdup(arg);
1711             break;
1712
1713 /* *************************************************************************
1714  * ca-directory directory
1715  * *************************************************************************/
1716          case hash_ca_directory:
1717             freez(ca_directory);
1718             ca_directory = make_path(NULL, arg);
1719
1720             if (NULL == ca_directory)
1721             {
1722                log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca dir path");
1723             }
1724
1725             break;
1726
1727 /* *************************************************************************
1728  * ca cert file ca-cert-file
1729  * In ca dir by default
1730  * *************************************************************************/
1731          case hash_ca_cert_file:
1732             freez(ca_cert_file);
1733             ca_cert_file = make_path(config->ca_directory, arg);
1734
1735             if (NULL == ca_cert_file)
1736             {
1737                log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca certificate file path");
1738             }
1739
1740             break;
1741
1742 /* *************************************************************************
1743  * ca key file ca-key-file
1744  * In ca dir by default
1745  * *************************************************************************/
1746          case hash_ca_key_file:
1747             freez(ca_key_file);
1748             ca_key_file = make_path(config->ca_directory, arg);
1749
1750             if (NULL == ca_key_file)
1751             {
1752                log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca key file path");
1753             }
1754
1755             break;
1756
1757 /* *************************************************************************
1758  * certificate-directory directory
1759  * *************************************************************************/
1760          case hash_certificate_directory:
1761             freez(certificate_directory);
1762             certificate_directory = make_path(NULL, arg);
1763
1764             if (NULL == certificate_directory)
1765             {
1766                log_error(LOG_LEVEL_FATAL,
1767                   "Out of memory while creating certificate directory path");
1768             }
1769
1770             break;
1771
1772 /* *************************************************************************
1773  * cipher-list list-of-ciphers
1774  * *************************************************************************/
1775          case hash_cipher_list:
1776             freez(config->cipher_list);
1777             config->cipher_list = strdup_or_die(arg);
1778
1779             break;
1780
1781 /* *************************************************************************
1782  * trusted CAs file name trusted-cas-file
1783  * *************************************************************************/
1784          case hash_trusted_cas_file:
1785             freez(trusted_cas_file);
1786             trusted_cas_file = make_path(config->ca_directory, arg);
1787
1788             if (NULL == trusted_cas_file)
1789             {
1790                log_error(LOG_LEVEL_FATAL, "Out of memory while creating trusted CAs file path");
1791             }
1792
1793             break;
1794 #endif
1795
1796 /* *************************************************************************
1797  * Win32 Console options:
1798  * *************************************************************************/
1799
1800 /* *************************************************************************
1801  * hide-console
1802  * *************************************************************************/
1803 #ifdef _WIN_CONSOLE
1804          case hash_hide_console :
1805             hideConsole = 1;
1806             break;
1807 #endif /*def _WIN_CONSOLE*/
1808
1809
1810 /* *************************************************************************
1811  * Win32 GUI options:
1812  * *************************************************************************/
1813
1814 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
1815 /* *************************************************************************
1816  * activity-animation (0|1)
1817  * *************************************************************************/
1818          case hash_activity_animation :
1819             g_bShowActivityAnimation = parse_toggle_state(cmd, arg);
1820             break;
1821
1822 /* *************************************************************************
1823  *  close-button-minimizes (0|1)
1824  * *************************************************************************/
1825          case hash_close_button_minimizes :
1826             g_bCloseHidesWindow = parse_toggle_state(cmd, arg);
1827             break;
1828
1829 /* *************************************************************************
1830  * log-buffer-size (0|1)
1831  * *************************************************************************/
1832          case hash_log_buffer_size :
1833             g_bLimitBufferSize = parse_toggle_state(cmd, arg);
1834             break;
1835
1836 /* *************************************************************************
1837  * log-font-name fontname
1838  * *************************************************************************/
1839          case hash_log_font_name :
1840             if (strlcpy(g_szFontFaceName, arg,
1841                    sizeof(g_szFontFaceName)) >= sizeof(g_szFontFaceName))
1842             {
1843                log_error(LOG_LEVEL_FATAL,
1844                   "log-font-name argument '%s' is longer than %u characters.",
1845                   arg, sizeof(g_szFontFaceName)-1);
1846             }
1847             break;
1848
1849 /* *************************************************************************
1850  * log-font-size n
1851  * *************************************************************************/
1852          case hash_log_font_size :
1853             g_nFontSize = parse_numeric_value(cmd, arg);
1854             break;
1855
1856 /* *************************************************************************
1857  * log-highlight-messages (0|1)
1858  * *************************************************************************/
1859          case hash_log_highlight_messages :
1860             g_bHighlightMessages = parse_toggle_state(cmd, arg);
1861             break;
1862
1863 /* *************************************************************************
1864  * log-max-lines n
1865  * *************************************************************************/
1866          case hash_log_max_lines :
1867             g_nMaxBufferLines = parse_numeric_value(cmd, arg);
1868             break;
1869
1870 /* *************************************************************************
1871  * log-messages (0|1)
1872  * *************************************************************************/
1873          case hash_log_messages :
1874             g_bLogMessages = parse_toggle_state(cmd, arg);
1875             break;
1876
1877 /* *************************************************************************
1878  * show-on-task-bar (0|1)
1879  * *************************************************************************/
1880          case hash_show_on_task_bar :
1881             g_bShowOnTaskBar = parse_toggle_state(cmd, arg);
1882             break;
1883
1884 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
1885
1886
1887 /* *************************************************************************
1888  * Warnings about unsupported features
1889  * *************************************************************************/
1890 #ifndef FEATURE_ACL
1891          case hash_deny_access:
1892 #endif /* ndef FEATURE_ACL */
1893 #ifndef FEATURE_CGI_EDIT_ACTIONS
1894          case hash_enable_edit_actions:
1895 #endif /* ndef FEATURE_CGI_EDIT_ACTIONS */
1896 #ifndef FEATURE_TOGGLE
1897          case hash_enable_remote_toggle:
1898 #endif /* ndef FEATURE_TOGGLE */
1899 #ifndef FEATURE_ACL
1900          case hash_permit_access:
1901 #endif /* ndef FEATURE_ACL */
1902 #ifndef FEATURE_TOGGLE
1903          case hash_toggle :
1904 #endif /* ndef FEATURE_TOGGLE */
1905 #ifndef FEATURE_TRUST
1906          case hash_trustfile :
1907          case hash_trust_info_url :
1908 #endif /* ndef FEATURE_TRUST */
1909
1910 #ifndef _WIN_CONSOLE
1911          case hash_hide_console :
1912 #endif /* ndef _WIN_CONSOLE */
1913
1914 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
1915          case hash_activity_animation :
1916          case hash_close_button_minimizes :
1917          case hash_log_buffer_size :
1918          case hash_log_font_name :
1919          case hash_log_font_size :
1920          case hash_log_highlight_messages :
1921          case hash_log_max_lines :
1922          case hash_log_messages :
1923          case hash_show_on_task_bar :
1924 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
1925             /* These warnings are annoying - so hide them. -- Jon */
1926             /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */
1927             break;
1928
1929 /* *************************************************************************/
1930          default :
1931 /* *************************************************************************/
1932             /*
1933              * I decided that I liked this better as a warning than an
1934              * error.  To change back to an error, just change log level
1935              * to LOG_LEVEL_FATAL.
1936              */
1937             log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive "
1938                "'%s' (%uU) in line %lu in configuration file (%s).",
1939                buf, directive_hash, linenum, configfile);
1940             string_append(&config->proxy_args,
1941                " <strong class='warning'>Warning: Ignoring unrecognized directive:</strong>");
1942             break;
1943
1944 /* *************************************************************************/
1945       } /* end switch(hash_string(cmd)) */
1946
1947       /* Save the argument for the show-status page. */
1948       savearg(cmd, arg, config);
1949       freez(buf);
1950    } /* end while (read_config_line(...)) */
1951
1952    fclose(configfp);
1953
1954    set_debug_level(config->debug);
1955
1956    freez(config->logfile);
1957
1958    if (daemon_mode)
1959    {
1960       if (NULL != logfile)
1961       {
1962          config->logfile = logfile;
1963          init_error_log(Argv[0], config->logfile);
1964       }
1965       else
1966       {
1967          disable_logging();
1968       }
1969    }
1970
1971 #ifdef FEATURE_HTTPS_INSPECTION
1972    /*
1973     * Setting SSL parameters from loaded values into structures
1974     */
1975    freez(config->ca_directory);
1976    config->ca_directory = make_path(NULL, ca_directory);
1977    freez(ca_directory);
1978
1979    freez(config->ca_cert_file);
1980    config->ca_cert_file = make_path(config->ca_directory, ca_cert_file);
1981    freez(ca_cert_file);
1982
1983    freez(config->ca_key_file);
1984    config->ca_key_file  = make_path(config->ca_directory, ca_key_file);
1985    freez(ca_key_file);
1986
1987    freez(config->trusted_cas_file);
1988    config->trusted_cas_file = make_path(config->ca_directory, trusted_cas_file);
1989    freez(trusted_cas_file);
1990
1991    freez(config->certificate_directory);
1992    config->certificate_directory = make_path(NULL, certificate_directory);
1993    freez(certificate_directory);
1994 #endif
1995 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1996    if (config->default_server_timeout > config->keep_alive_timeout)
1997    {
1998       log_error(LOG_LEVEL_ERROR,
1999          "Reducing the default-server-timeout from %d to the keep-alive-timeout %d.",
2000          config->default_server_timeout, config->keep_alive_timeout);
2001       config->default_server_timeout = config->keep_alive_timeout;
2002    }
2003 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
2004
2005 #ifdef FEATURE_CONNECTION_SHARING
2006    if (config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
2007    {
2008       if (!config->multi_threaded)
2009       {
2010          /*
2011           * While we could use keep-alive without multiple threads
2012           * if we didn't bother with enforcing the connection timeout,
2013           * that might make Tor users sad, even though they shouldn't
2014           * enable the single-threaded option anyway.
2015           *
2016           * XXX: We could still use Proxy-Connection: keep-alive.
2017           */
2018          config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
2019          log_error(LOG_LEVEL_ERROR,
2020             "Config option single-threaded disables connection keep-alive.");
2021       }
2022    }
2023    else if ((config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
2024    {
2025       log_error(LOG_LEVEL_ERROR, "Config option connection-sharing "
2026          "has no effect if keep-alive-timeout isn't set.");
2027       config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
2028    }
2029 #endif /* def FEATURE_CONNECTION_SHARING */
2030
2031    if (NULL == config->proxy_args)
2032    {
2033       log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args");
2034    }
2035
2036    if (config->re_filterfile[0])
2037    {
2038       add_loader(load_re_filterfiles, config);
2039    }
2040
2041    if (config->actions_file[0])
2042    {
2043       add_loader(load_action_files, config);
2044    }
2045
2046 #ifdef FEATURE_TRUST
2047    if (config->trustfile)
2048    {
2049       add_loader(load_trustfile, config);
2050    }
2051 #endif /* def FEATURE_TRUST */
2052
2053    if (NULL == config->haddr[0])
2054    {
2055       config->haddr[0] = strdup_or_die(HADDR_DEFAULT);
2056    }
2057
2058    for (i = 0; i < MAX_LISTENING_SOCKETS && NULL != config->haddr[i]; i++)
2059    {
2060       if ((*config->haddr[i] == '[')
2061          && (NULL != (p = strchr(config->haddr[i], ']')))
2062          && (p[1] == ':')
2063          && (0 < (config->hport[i] = atoi(p + 2))))
2064       {
2065          *p = '\0';
2066          memmove((void *)config->haddr[i], config->haddr[i] + 1,
2067             (size_t)(p - config->haddr[i]));
2068       }
2069       else if (NULL != (p = strchr(config->haddr[i], ':'))
2070          && (0 < (config->hport[i] = atoi(p + 1))))
2071       {
2072          *p = '\0';
2073       }
2074       else
2075       {
2076          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr[i]);
2077          /* Never get here - LOG_LEVEL_FATAL causes program exit */
2078       }
2079       if (*config->haddr[i] == '\0')
2080       {
2081          /*
2082           * Only the port specified. We stored it in config->hport[i]
2083           * and don't need its text representation anymore.
2084           * Use config->hport[i] == 0 to iterate listening addresses since
2085           * now.
2086           */
2087          freez(config->haddr[i]);
2088       }
2089    }
2090
2091    /*
2092     * Want to run all the loaders once now.
2093     *
2094     * Need to set up a fake csp, so they can get to the config.
2095     */
2096    fake_csp = zalloc_or_die(sizeof(*fake_csp));
2097    fake_csp->config = config;
2098
2099    if (run_loader(fake_csp))
2100    {
2101       freez(fake_csp);
2102       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
2103       /* Never get here - LOG_LEVEL_FATAL causes program exit */
2104    }
2105    freez(fake_csp);
2106
2107 /* FIXME: this is a kludge for win32 */
2108 #if defined(_WIN32) && !defined (_WIN_CONSOLE)
2109
2110    g_default_actions_file = config->actions_file[1]; /* FIXME Hope this is default.action */
2111    g_user_actions_file  = config->actions_file[2];  /* FIXME Hope this is user.action */
2112    g_default_filterfile = config->re_filterfile[0]; /* FIXME Hope this is default.filter */
2113    g_user_filterfile    = config->re_filterfile[1]; /* FIXME Hope this is user.filter */
2114
2115 #ifdef FEATURE_TRUST
2116    g_trustfile        = config->trustfile;
2117 #endif /* def FEATURE_TRUST */
2118
2119
2120 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
2121 /* FIXME: end kludge */
2122
2123
2124    if (current_configfile == NULL)
2125    {
2126       config->need_bind = 1;
2127    }
2128    else
2129    {
2130       struct configuration_spec * oldcfg = (struct configuration_spec *)
2131                                            current_configfile->f;
2132       /*
2133        * Check if config->haddr[i],hport[i] == oldcfg->haddr[i],hport[i]
2134        */
2135       config->need_bind = 0;
2136
2137       for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
2138       {
2139          if (config->hport[i] != oldcfg->hport[i])
2140          {
2141             config->need_bind = 1;
2142          }
2143          else if (config->haddr[i] == NULL)
2144          {
2145             if (oldcfg->haddr[i] != NULL)
2146             {
2147                config->need_bind = 1;
2148             }
2149          }
2150          else if (oldcfg->haddr[i] == NULL)
2151          {
2152             config->need_bind = 1;
2153          }
2154          else if (0 != strcmp(config->haddr[i], oldcfg->haddr[i]))
2155          {
2156             config->need_bind = 1;
2157          }
2158       }
2159
2160       current_configfile->unloader = unload_configfile;
2161    }
2162
2163    fs->next = files->next;
2164    files->next = fs;
2165
2166    current_configfile = fs;
2167
2168    return (config);
2169 }
2170
2171
2172 /*********************************************************************
2173  *
2174  * Function    :  savearg
2175  *
2176  * Description :  Called from `load_config'.  It saves each non-empty
2177  *                and non-comment line from config into
2178  *                config->proxy_args.  This is used to create the
2179  *                show-status page.  On error, frees
2180  *                config->proxy_args and sets it to NULL
2181  *
2182  * Parameters  :
2183  *          1  :  command = config setting that was found
2184  *          2  :  argument = the setting's argument (if any)
2185  *          3  :  config = Configuration to save into.
2186  *
2187  * Returns     :  N/A
2188  *
2189  *********************************************************************/
2190 static void savearg(char *command, char *argument, struct configuration_spec * config)
2191 {
2192    char * buf;
2193    char * s;
2194
2195    assert(command);
2196    assert(argument);
2197
2198    /*
2199     * Add config option name embedded in
2200     * link to its section in the user-manual
2201     */
2202    buf = strdup_or_die("\n<a href=\"");
2203    if (!strncmpic(config->usermanual, "file://", 7) ||
2204        !strncmpic(config->usermanual, "http", 4))
2205    {
2206       string_append(&buf, config->usermanual);
2207    }
2208    else
2209    {
2210       string_append(&buf, "http://" CGI_SITE_2_HOST "/user-manual/");
2211    }
2212    string_append(&buf, CONFIG_HELP_PREFIX);
2213    string_join  (&buf, string_toupper(command));
2214    string_append(&buf, "\">");
2215    string_append(&buf, command);
2216    string_append(&buf, "</a> ");
2217
2218    if (NULL == buf)
2219    {
2220       freez(config->proxy_args);
2221       return;
2222    }
2223
2224    if ((NULL != argument) && ('\0' != *argument))
2225    {
2226       s = html_encode(argument);
2227       if (NULL == s)
2228       {
2229          freez(buf);
2230          freez(config->proxy_args);
2231          return;
2232       }
2233
2234       if (strncmpic(argument, "http://", 7) == 0)
2235       {
2236          string_append(&buf, "<a href=\"");
2237          string_append(&buf, s);
2238          string_append(&buf, "\">");
2239          string_join  (&buf, s);
2240          string_append(&buf, "</a>");
2241       }
2242       else
2243       {
2244          string_join  (&buf, s);
2245       }
2246    }
2247
2248    string_append(&buf, "<br>");
2249    string_join(&config->proxy_args, buf);
2250 }
2251
2252
2253 /*
2254   Local Variables:
2255   tab-width: 3
2256   end:
2257 */