LCOV - code coverage report
Current view: top level - fuzz - loadcfg.c (source / functions) Hit Total Coverage
Test: trace.lcov_info_final Lines: 342 696 49.1 %
Date: 2021-02-22 04:51:02 Functions: 6 8 75.0 %

          Line data    Source code
       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         3239141416U /* "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           0 : static void unload_configfile (void * data)
     220             : {
     221           0 :    struct configuration_spec * config = (struct configuration_spec *)data;
     222           0 :    struct forward_spec *cur_fwd = config->forward;
     223             :    int i;
     224             : 
     225             : #ifdef FEATURE_ACL
     226           0 :    struct access_control_list *cur_acl = config->acl;
     227             : 
     228           0 :    while (cur_acl != NULL)
     229             :    {
     230           0 :       struct access_control_list * next_acl = cur_acl->next;
     231           0 :       free(cur_acl);
     232           0 :       cur_acl = next_acl;
     233             :    }
     234           0 :    config->acl = NULL;
     235             : #endif /* def FEATURE_ACL */
     236             : 
     237           0 :    while (cur_fwd != NULL)
     238             :    {
     239           0 :       struct forward_spec * next_fwd = cur_fwd->next;
     240             : 
     241           0 :       unload_forward_spec(cur_fwd);
     242             : 
     243           0 :       cur_fwd = next_fwd;
     244             :    }
     245           0 :    config->forward = NULL;
     246             : 
     247           0 :    freez(config->confdir);
     248           0 :    freez(config->logdir);
     249           0 :    freez(config->templdir);
     250           0 :    freez(config->hostname);
     251             : #ifdef FEATURE_EXTERNAL_FILTERS
     252           0 :    freez(config->temporary_directory);
     253             : #endif
     254             : 
     255           0 :    for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
     256             :    {
     257           0 :       freez(config->haddr[i]);
     258             :    }
     259           0 :    freez(config->logfile);
     260             : 
     261           0 :    for (i = 0; i < MAX_AF_FILES; i++)
     262             :    {
     263           0 :       freez(config->actions_file_short[i]);
     264           0 :       freez(config->actions_file[i]);
     265           0 :       freez(config->re_filterfile_short[i]);
     266           0 :       freez(config->re_filterfile[i]);
     267             :    }
     268             : 
     269           0 :    list_remove_all(config->ordered_client_headers);
     270             : 
     271           0 :    freez(config->admin_address);
     272           0 :    freez(config->cors_allowed_origin);
     273           0 :    freez(config->proxy_info_url);
     274           0 :    freez(config->proxy_args);
     275           0 :    freez(config->usermanual);
     276           0 :    freez(config->trusted_cgi_referrer);
     277             : 
     278             : #ifdef FEATURE_HTTPS_INSPECTION
     279           0 :    freez(config->ca_password);
     280           0 :    freez(config->ca_directory);
     281           0 :    freez(config->ca_cert_file);
     282           0 :    freez(config->ca_key_file);
     283           0 :    freez(config->certificate_directory);
     284           0 :    freez(config->cipher_list);
     285           0 :    freez(config->trusted_cas_file);
     286             : #endif
     287             : 
     288             : #ifdef FEATURE_TRUST
     289           0 :    freez(config->trustfile);
     290           0 :    list_remove_all(config->trust_info);
     291             : #endif /* def FEATURE_TRUST */
     292             : 
     293             : #ifdef FEATURE_CLIENT_TAGS
     294           0 :    free_client_specific_tags(config->client_tags);
     295             : #endif
     296             : 
     297           0 :    freez(config);
     298           0 : }
     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       12392 : 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       12392 :    last_tag = tag_list;
     347       21686 :    while (last_tag->next != NULL)
     348             :    {
     349        9294 :       last_tag = last_tag->next;
     350             :    }
     351       12392 :    if (last_tag->name == NULL)
     352             :    {
     353             :       /* First entry */
     354        3098 :       new_tag = last_tag;
     355             :    }
     356             :    else
     357             :    {
     358        9294 :       new_tag = zalloc_or_die(sizeof(struct client_tag_spec));
     359             :    }
     360       12392 :    new_tag->name = strdup_or_die(name);
     361       12392 :    new_tag->description = strdup_or_die(description);
     362       12392 :    if (new_tag != last_tag)
     363             :    {
     364        9294 :       last_tag->next = new_tag;
     365             :    }
     366       12392 : }
     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           0 : 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           0 :    next_tag = tag_list;
     387             :    do
     388             :    {
     389           0 :       this_tag = next_tag;
     390           0 :       next_tag = next_tag->next;
     391             : 
     392           0 :       freez(this_tag->name);
     393           0 :       freez(this_tag->description);
     394             : 
     395           0 :       if (this_tag != tag_list)
     396             :       {
     397           0 :          freez(this_tag);
     398             :       }
     399           0 :    } while (next_tag != NULL);
     400           0 : }
     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       65058 : static int parse_numeric_value(const char *name, const char *value)
     421             : {
     422             :    int number;
     423             :    char *endptr;
     424             : 
     425       65058 :    assert(name != NULL);
     426       65058 :    assert(value != NULL);
     427             : 
     428       65058 :    if ((value == NULL) || (*value == '\0'))
     429             :    {
     430           0 :       log_error(LOG_LEVEL_FATAL, "Directive %s used without argument", name);
     431             :    }
     432             : 
     433       65058 :    number = (int)strtol(value, &endptr, 0);
     434       65058 :    if (*endptr != '\0')
     435             :    {
     436           0 :       log_error(LOG_LEVEL_FATAL,
     437             :          "Directive '%s' used with non-numerical value: '%s'", name, value);
     438             :    }
     439             : 
     440       65058 :    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       43372 : static int parse_toggle_state(const char *name, const char *value)
     462             : {
     463             :    int toggle_state;
     464       43372 :    assert(name != NULL);
     465       43372 :    assert(value != NULL);
     466             : 
     467       43372 :    if ((value == NULL) || (*value == '\0'))
     468             :    {
     469           0 :       log_error(LOG_LEVEL_FATAL, "Directive %s used without argument", name);
     470             :    }
     471             : 
     472       43372 :    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       43372 :    if (((toggle_state != 0) && (toggle_state != 1)) || (strlen(value) != 1))
     479             :    {
     480           0 :       log_error(LOG_LEVEL_FATAL,
     481             :          "Directive %s used with invalid argument '%s'. Use either '0' or '1'.",
     482             :          name, value);
     483             :    }
     484             : 
     485       43372 :    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        3098 : 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        3098 :    assert(ordered_header_list != NULL);
     515        3098 :    assert(ordered_headers != NULL);
     516             : 
     517        3098 :    if (ordered_headers == NULL)
     518             :    {
     519           0 :       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        3098 :    max_segments = strlen(ordered_headers) / 2;
     529        3098 :    if (max_segments == 0)
     530             :    {
     531           0 :       max_segments = 1;
     532             :    }
     533        3098 :    vector = malloc_or_die(max_segments * sizeof(char *));
     534             : 
     535        3098 :    original_headers_copy = strdup_or_die(ordered_headers);
     536             : 
     537        3098 :    number_of_headers = ssplit(original_headers_copy, "\t ", vector, max_segments);
     538        3098 :    if (number_of_headers == -1)
     539             :    {
     540           0 :       log_error(LOG_LEVEL_FATAL, "Failed to split ordered headers");
     541             :    }
     542             : 
     543       27882 :    for (i = 0; i < number_of_headers; i++)
     544             :    {
     545       24784 :       if (JB_ERR_OK != enlist(ordered_header_list, vector[i]))
     546             :       {
     547           0 :          log_error(LOG_LEVEL_FATAL,
     548           0 :             "Failed to enlist ordered header: %s", vector[i]);
     549             :       }
     550             :    }
     551             : 
     552        3098 :    freez(vector);
     553        3098 :    freez(original_headers_copy);
     554             : 
     555        3098 :    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        3098 : struct configuration_spec * load_config(void)
     575             : {
     576        3098 :    char *buf = NULL;
     577             :    char *p, *q;
     578        3098 :    FILE *configfp = NULL;
     579        3098 :    struct configuration_spec * config = NULL;
     580             :    struct client_state * fake_csp;
     581             :    struct file_list *fs;
     582        3098 :    unsigned long linenum = 0;
     583             :    int i;
     584        3098 :    char *logfile          = NULL;
     585             : #ifdef FEATURE_HTTPS_INSPECTION
     586        3098 :    char *ca_cert_file     = NULL;
     587        3098 :    char *ca_key_file      = NULL;
     588        3098 :    char *ca_directory     = NULL;
     589        3098 :    char *trusted_cas_file = NULL;
     590        3098 :    char *certificate_directory = NULL;
     591             : #endif
     592             : 
     593        3098 :    if (!check_file_changed(current_configfile, configfile, &fs))
     594             :    {
     595             :       /* No need to load */
     596           0 :       return ((struct configuration_spec *)current_configfile->f);
     597             :    }
     598        3098 :    if (NULL == fs)
     599             :    {
     600           0 :       log_error(LOG_LEVEL_FATAL,
     601             :          "can't check configuration file '%s':  %E", configfile);
     602           0 :       return NULL;
     603             :    }
     604             : 
     605        3098 :    if (NULL != current_configfile)
     606             :    {
     607           0 :       log_error(LOG_LEVEL_INFO, "Reloading configuration file '%s'", configfile);
     608             :    }
     609             : 
     610             : #ifdef FEATURE_TOGGLE
     611        3098 :    global_toggle_state = 1;
     612             : #endif /* def FEATURE_TOGGLE */
     613             : 
     614        3098 :    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        3098 :    config->config_file_list = fs;
     626             : 
     627             :    /*
     628             :     * Set to defaults
     629             :     */
     630        3098 :    config->multi_threaded            = 1;
     631        3098 :    config->buffer_limit              = 4096 * 1024;
     632        3098 :    config->receive_buffer_size       = BUFFER_SIZE;
     633        3098 :    config->usermanual                = strdup_or_die(USER_MANUAL_URL);
     634        3098 :    config->proxy_args                = strdup_or_die("");
     635        3098 :    config->forwarded_connect_retries = 0;
     636             : #ifdef FEATURE_HTTPS_INSPECTION
     637        3098 :    config->ca_password               = strdup("");
     638        3098 :    ca_cert_file                      = strdup("cacert.crt");
     639        3098 :    ca_key_file                       = strdup("cakey.pem");
     640        3098 :    ca_directory                      = strdup("./CA");
     641        3098 :    trusted_cas_file                  = strdup("trustedCAs.pem");
     642        3098 :    certificate_directory             = strdup("./certs");
     643             : #endif
     644             : 
     645             : #ifdef FEATURE_CLIENT_TAGS
     646        3098 :    config->client_tag_lifetime       = 60;
     647             : #endif
     648        3098 :    config->trust_x_forwarded_for     = 0;
     649             : #if defined(FEATURE_ACCEPT_FILTER) && defined(SO_ACCEPTFILTER)
     650             :    config->enable_accept_filter      = 0;
     651             : #endif
     652        3098 :    config->listen_backlog            = DEFAULT_LISTEN_BACKLOG;
     653        3098 :    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        3098 :    config->max_client_connections    = 128;
     660        3098 :    config->socket_timeout            = 300; /* XXX: Should be a macro. */
     661             : #ifdef FEATURE_CONNECTION_KEEP_ALIVE
     662        3098 :    config->default_server_timeout    = 0;
     663        3098 :    config->keep_alive_timeout        = DEFAULT_KEEP_ALIVE_TIMEOUT;
     664        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
     665        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
     666             : #endif
     667        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_CGI_TOGGLE;
     668        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
     669        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
     670        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
     671        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS;
     672             : #ifdef FEATURE_COMPRESSION
     673        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_COMPRESSION;
     674             :    /*
     675             :     * XXX: Run some benchmarks to see if there are better default values.
     676             :     */
     677        3098 :    config->compression_level         = 1;
     678             : #endif
     679        3098 :    config->feature_flags            &= ~RUNTIME_FEATURE_TOLERATE_PIPELINING;
     680        3098 :    config->cors_allowed_origin       = NULL;
     681             : 
     682        3098 :    configfp = fopen(configfile, "r");
     683        3098 :    if (NULL == configfp)
     684             :    {
     685           0 :       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      176586 :    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      173488 :       strlcpy(tmp, buf, sizeof(tmp));
     704             : 
     705             :       /* Copy command (i.e. up to space or tab) into cmd */
     706      173488 :       p = buf;
     707      173488 :       q = cmd;
     708     2518674 :       while (*p && (*p != ' ') && (*p != '\t'))
     709             :       {
     710     2345186 :          *q++ = *p++;
     711             :       }
     712      173488 :       *q = '\0';
     713             : 
     714             :       /* Skip over the whitespace in buf */
     715      467798 :       while (*p && ((*p == ' ') || (*p == '\t')))
     716             :       {
     717      294310 :          p++;
     718             :       }
     719             : 
     720             :       /* Copy the argument into arg */
     721      173488 :       if (strlcpy(arg, p, sizeof(arg)) >= sizeof(arg))
     722             :       {
     723           0 :          log_error(LOG_LEVEL_FATAL, "Config line too long: %s", buf);
     724             :       }
     725             : 
     726             :       /* Should never happen, but check this anyway */
     727      173488 :       if (*cmd == '\0')
     728             :       {
     729           0 :          freez(buf);
     730           0 :          continue;
     731             :       }
     732             : 
     733             :       /* Make sure the command field is lower case */
     734     2518674 :       for (p = cmd; *p; p++)
     735             :       {
     736     2345186 :          if (privoxy_isupper(*p))
     737             :          {
     738           0 :             *p = (char)privoxy_tolower(*p);
     739             :          }
     740             :       }
     741             : 
     742      173488 :       directive_hash = hash_string(cmd);
     743      173488 :       switch (directive_hash)
     744             :       {
     745             : /* *************************************************************************
     746             :  * actionsfile actions-file-name
     747             :  * In confdir by default
     748             :  * *************************************************************************/
     749        6196 :          case hash_actions_file :
     750        6196 :             i = 0;
     751        9294 :             while ((i < MAX_AF_FILES) && (NULL != config->actions_file[i]))
     752             :             {
     753        3098 :                i++;
     754             :             }
     755             : 
     756        6196 :             if (i >= MAX_AF_FILES)
     757             :             {
     758           0 :                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        6196 :             config->actions_file_short[i] = strdup_or_die(arg);
     763        6196 :             config->actions_file[i] = make_path(config->confdir, arg);
     764             : 
     765        6196 :             break;
     766             : /* *************************************************************************
     767             :  * accept-intercepted-requests
     768             :  * *************************************************************************/
     769        3098 :          case hash_accept_intercepted_requests:
     770        3098 :             if (parse_toggle_state(cmd, arg) == 1)
     771             :             {
     772        3098 :                config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
     773             :             }
     774             :             else
     775             :             {
     776           0 :                config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
     777             :             }
     778        3098 :             break;
     779             : 
     780             : /* *************************************************************************
     781             :  * admin-address email-address
     782             :  * *************************************************************************/
     783           0 :          case hash_admin_address :
     784           0 :             freez(config->admin_address);
     785           0 :             config->admin_address = strdup_or_die(arg);
     786           0 :             break;
     787             : 
     788             : /* *************************************************************************
     789             :  * allow-cgi-request-crunching
     790             :  * *************************************************************************/
     791        3098 :          case hash_allow_cgi_request_crunching:
     792        3098 :             if (parse_toggle_state(cmd, arg) == 1)
     793             :             {
     794           0 :                config->feature_flags |= RUNTIME_FEATURE_CGI_CRUNCHING;
     795             :             }
     796             :             else
     797             :             {
     798        3098 :                config->feature_flags &= ~RUNTIME_FEATURE_CGI_CRUNCHING;
     799             :             }
     800        3098 :             break;
     801             : 
     802             : /* *************************************************************************
     803             :  * buffer-limit n
     804             :  * *************************************************************************/
     805        3098 :          case hash_buffer_limit :
     806        3098 :             config->buffer_limit = (size_t)(1024 * parse_numeric_value(cmd, arg));
     807        3098 :             break;
     808             : 
     809             : /* *************************************************************************
     810             :  * client-header-order header-1 header-2 ... header-n
     811             :  * *************************************************************************/
     812        3098 :          case hash_client_header_order:
     813        3098 :             list_remove_all(config->ordered_client_headers);
     814        3098 :             parse_client_header_order(config->ordered_client_headers, arg);
     815        3098 :             break;
     816             : 
     817             : /* *************************************************************************
     818             :  * client-specific-tag tag-name description
     819             :  * *************************************************************************/
     820             : #ifdef FEATURE_CLIENT_TAGS
     821       12392 :          case hash_client_specific_tag:
     822             :             {
     823             :                char *name;
     824             :                char *description;
     825             : 
     826       12392 :                name = arg;
     827       12392 :                description = strstr(arg, " ");
     828       12392 :                if (description == NULL)
     829             :                {
     830           0 :                   log_error(LOG_LEVEL_FATAL,
     831             :                      "client-specific-tag '%s' lacks a description.", name);
     832             :                }
     833       12392 :                *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       12392 :                if (strlen(name) > CLIENT_TAG_LENGTH_MAX)
     840             :                {
     841           0 :                   log_error(LOG_LEVEL_FATAL,
     842             :                      "client-specific-tag '%s' is longer than %d characters.",
     843             :                      name, CLIENT_TAG_LENGTH_MAX);
     844             :                }
     845       12392 :                description++;
     846       12392 :                register_tag(config->client_tags, name, description);
     847             :             }
     848       12392 :             break;
     849             : #endif /* def FEATURE_CLIENT_TAGS */
     850             : 
     851             : /* *************************************************************************
     852             :  * client-tag-lifetime ttl
     853             :  * *************************************************************************/
     854             : #ifdef FEATURE_CLIENT_TAGS
     855        3098 :          case hash_client_tag_lifetime:
     856             :          {
     857        3098 :             int ttl = parse_numeric_value(cmd, arg);
     858        3098 :             if (0 <= ttl)
     859             :             {
     860        3098 :                config->client_tag_lifetime = (unsigned)ttl;
     861             :             }
     862             :             else
     863             :             {
     864           0 :                log_error(LOG_LEVEL_FATAL,
     865             :                   "client-tag-lifetime can't be negative.");
     866             :             }
     867        3098 :             break;
     868             :          }
     869             : #endif /* def FEATURE_CLIENT_TAGS */
     870             : 
     871             : /* *************************************************************************
     872             :  * confdir directory-name
     873             :  * *************************************************************************/
     874        3098 :          case hash_confdir :
     875        3098 :             freez(config->confdir);
     876        3098 :             config->confdir = make_path(NULL, arg);
     877        3098 :             break;
     878             : 
     879             : /* *************************************************************************
     880             :  * compression-level 0-9
     881             :  * *************************************************************************/
     882             : #ifdef FEATURE_COMPRESSION
     883        3098 :          case hash_compression_level :
     884             :          {
     885        3098 :             int compression_level = parse_numeric_value(cmd, arg);
     886        3098 :             if (-1 <= compression_level && compression_level <= 9)
     887             :             {
     888        3098 :                config->compression_level = compression_level;
     889             :             }
     890             :             else
     891             :             {
     892           0 :                log_error(LOG_LEVEL_FATAL,
     893             :                   "Invalid compression-level value: %s", arg);
     894             :             }
     895        3098 :             break;
     896             :          }
     897             : #endif
     898             : 
     899             : /* *************************************************************************
     900             :  * connection-sharing (0|1)
     901             :  * *************************************************************************/
     902             : #ifdef FEATURE_CONNECTION_SHARING
     903        3098 :          case hash_connection_sharing :
     904        3098 :             if (parse_toggle_state(cmd, arg) == 1)
     905             :             {
     906           0 :                config->feature_flags |= RUNTIME_FEATURE_CONNECTION_SHARING;
     907             :             }
     908             :             else
     909             :             {
     910        3098 :                config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
     911             :             }
     912        3098 :             break;
     913             : #endif
     914             : 
     915             : /* *************************************************************************
     916             :  * cors-allowed-origin http://www.example.org
     917             :  * *************************************************************************/
     918        3098 :          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        3098 :             freez(config->cors_allowed_origin);
     924        3098 :             config->cors_allowed_origin = strdup_or_die(arg);
     925        3098 :             break;
     926             : 
     927             : /* *************************************************************************
     928             :  * debug n
     929             :  * Specifies debug level, multiple values are ORed together.
     930             :  * *************************************************************************/
     931       49568 :          case hash_debug :
     932       49568 :             config->debug |= parse_numeric_value(cmd, arg);
     933       49568 :             break;
     934             : 
     935             : /* *************************************************************************
     936             :  * default-server-timeout timeout
     937             :  * *************************************************************************/
     938             : #ifdef FEATURE_CONNECTION_KEEP_ALIVE
     939           0 :          case hash_default_server_timeout :
     940             :          {
     941           0 :             int timeout = parse_numeric_value(cmd, arg);
     942           0 :             if (0 <= timeout)
     943             :             {
     944           0 :                config->default_server_timeout = (unsigned int)timeout;
     945             :             }
     946             :             else
     947             :             {
     948           0 :                log_error(LOG_LEVEL_FATAL,
     949             :                   "Invalid default-server-timeout value: %s", arg);
     950             :             }
     951           0 :             break;
     952             :          }
     953             : #endif
     954             : 
     955             : /* *************************************************************************
     956             :  * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
     957             :  * *************************************************************************/
     958             : #ifdef FEATURE_ACL
     959           0 :          case hash_deny_access:
     960           0 :             strlcpy(tmp, arg, sizeof(tmp));
     961           0 :             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
     962             : 
     963           0 :             if ((vec_count != 1) && (vec_count != 2))
     964             :             {
     965           0 :                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
     966             :                      "deny-access directive in configuration file.");
     967           0 :                string_append(&config->proxy_args,
     968             :                   "<br>\nWARNING: Wrong number of parameters for "
     969             :                   "deny-access directive in configuration file.<br><br>\n");
     970           0 :                break;
     971             :             }
     972             : 
     973             :             /* allocate a new node */
     974           0 :             cur_acl = zalloc_or_die(sizeof(*cur_acl));
     975           0 :             cur_acl->action = ACL_DENY;
     976             : 
     977           0 :             if (acl_addr(vec[0], cur_acl->src) < 0)
     978             :             {
     979           0 :                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
     980             :                   "for deny-access directive in configuration file: \"%s\"", vec[0]);
     981           0 :                string_append(&config->proxy_args,
     982             :                   "<br>\nWARNING: Invalid source address, port or netmask "
     983             :                   "for deny-access directive in configuration file: \"");
     984           0 :                string_append(&config->proxy_args,
     985           0 :                   vec[0]);
     986           0 :                string_append(&config->proxy_args,
     987             :                   "\"<br><br>\n");
     988           0 :                freez(cur_acl);
     989           0 :                break;
     990             :             }
     991           0 :             if (vec_count == 2)
     992             :             {
     993           0 :                if (acl_addr(vec[1], cur_acl->dst) < 0)
     994             :                {
     995           0 :                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
     996             :                      "for deny-access directive in configuration file: \"%s\"", vec[1]);
     997           0 :                   string_append(&config->proxy_args,
     998             :                      "<br>\nWARNING: Invalid destination address, port or netmask "
     999             :                      "for deny-access directive in configuration file: \"");
    1000           0 :                   string_append(&config->proxy_args,
    1001           0 :                      vec[1]);
    1002           0 :                   string_append(&config->proxy_args,
    1003             :                      "\"<br><br>\n");
    1004           0 :                   freez(cur_acl);
    1005           0 :                   break;
    1006             :                }
    1007             :             }
    1008             : #ifdef HAVE_RFC2553
    1009             :             else
    1010             :             {
    1011           0 :                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           0 :             cur_acl->next  = config->acl;
    1025           0 :             config->acl = cur_acl;
    1026             : 
    1027           0 :             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        3098 :          case hash_enable_edit_actions:
    1044        3098 :             if (parse_toggle_state(cmd, arg) == 1)
    1045             :             {
    1046        3098 :                config->feature_flags |= RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
    1047             :             }
    1048             :             else
    1049             :             {
    1050           0 :                config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
    1051             :             }
    1052        3098 :             break;
    1053             : #endif /* def FEATURE_CGI_EDIT_ACTIONS */
    1054             : 
    1055             : /* *************************************************************************
    1056             :  * enable-compression 0|1
    1057             :  * *************************************************************************/
    1058             : #ifdef FEATURE_COMPRESSION
    1059        3098 :          case hash_enable_compression:
    1060        3098 :             if (parse_toggle_state(cmd, arg) == 1)
    1061             :             {
    1062        3098 :                config->feature_flags |= RUNTIME_FEATURE_COMPRESSION;
    1063             :             }
    1064             :             else
    1065             :             {
    1066           0 :                config->feature_flags &= ~RUNTIME_FEATURE_COMPRESSION;
    1067             :             }
    1068        3098 :             break;
    1069             : #endif /* def FEATURE_COMPRESSION */
    1070             : 
    1071             : /* *************************************************************************
    1072             :  * enable-proxy-authentication-forwarding 0|1
    1073             :  * *************************************************************************/
    1074        3098 :          case hash_enable_proxy_authentication_forwarding:
    1075        3098 :             if (parse_toggle_state(cmd, arg) == 1)
    1076             :             {
    1077        3098 :                config->feature_flags |= RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS;
    1078             :             }
    1079             :             else
    1080             :             {
    1081           0 :                config->feature_flags &= ~RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS;
    1082             :             }
    1083        3098 :             break;
    1084             : 
    1085             : /* *************************************************************************
    1086             :  * enable-remote-toggle 0|1
    1087             :  * *************************************************************************/
    1088             : #ifdef FEATURE_TOGGLE
    1089        3098 :          case hash_enable_remote_toggle:
    1090        3098 :             if (parse_toggle_state(cmd, arg) == 1)
    1091             :             {
    1092        3098 :                config->feature_flags |= RUNTIME_FEATURE_CGI_TOGGLE;
    1093             :             }
    1094             :             else
    1095             :             {
    1096           0 :                config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE;
    1097             :             }
    1098        3098 :             break;
    1099             : #endif /* def FEATURE_TOGGLE */
    1100             : 
    1101             : /* *************************************************************************
    1102             :  * enable-remote-http-toggle 0|1
    1103             :  * *************************************************************************/
    1104        3098 :          case hash_enable_remote_http_toggle:
    1105        3098 :             if (parse_toggle_state(cmd, arg) == 1)
    1106             :             {
    1107        3098 :                config->feature_flags |= RUNTIME_FEATURE_HTTP_TOGGLE;
    1108             :             }
    1109             :             else
    1110             :             {
    1111           0 :                config->feature_flags &= ~RUNTIME_FEATURE_HTTP_TOGGLE;
    1112             :             }
    1113        3098 :             break;
    1114             : 
    1115             : /* *************************************************************************
    1116             :  * enforce-blocks 0|1
    1117             :  * *************************************************************************/
    1118        3098 :          case hash_enforce_blocks:
    1119             : #ifdef FEATURE_FORCE_LOAD
    1120        3098 :             if (parse_toggle_state(cmd, arg) == 1)
    1121             :             {
    1122           0 :                config->feature_flags |= RUNTIME_FEATURE_ENFORCE_BLOCKS;
    1123             :             }
    1124             :             else
    1125             :             {
    1126        3098 :                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        3098 :             break;
    1133             : 
    1134             : /* *************************************************************************
    1135             :  * filterfile file-name
    1136             :  * In confdir by default.
    1137             :  * *************************************************************************/
    1138        6196 :          case hash_filterfile :
    1139        6196 :             i = 0;
    1140        9294 :             while ((i < MAX_AF_FILES) && (NULL != config->re_filterfile[i]))
    1141             :             {
    1142        3098 :                i++;
    1143             :             }
    1144             : 
    1145        6196 :             if (i >= MAX_AF_FILES)
    1146             :             {
    1147           0 :                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        6196 :             config->re_filterfile_short[i] = strdup_or_die(arg);
    1152        6196 :             config->re_filterfile[i] = make_path(config->confdir, arg);
    1153             : 
    1154        6196 :             break;
    1155             : 
    1156             : /* *************************************************************************
    1157             :  * forward url-pattern (.|http-proxy-host[:port])
    1158             :  * *************************************************************************/
    1159           0 :          case hash_forward:
    1160           0 :             strlcpy(tmp, arg, sizeof(tmp));
    1161           0 :             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
    1162             : 
    1163           0 :             if (vec_count != 2)
    1164             :             {
    1165           0 :                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward "
    1166             :                      "directive in configuration file.");
    1167           0 :                string_append(&config->proxy_args,
    1168             :                   "<br>\nWARNING: Wrong number of parameters for "
    1169             :                   "forward directive in configuration file.");
    1170           0 :                break;
    1171             :             }
    1172             : 
    1173             :             /* allocate a new node */
    1174           0 :             cur_fwd = zalloc_or_die(sizeof(*cur_fwd));
    1175           0 :             cur_fwd->type = SOCKS_NONE;
    1176             : 
    1177             :             /* Save the URL pattern */
    1178           0 :             if (create_pattern_spec(cur_fwd->url, vec[0]))
    1179             :             {
    1180           0 :                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward "
    1181             :                      "directive in configuration file.");
    1182           0 :                string_append(&config->proxy_args,
    1183             :                   "<br>\nWARNING: Bad URL specifier for "
    1184             :                   "forward directive in configuration file.");
    1185           0 :                freez(cur_fwd);
    1186           0 :                break;
    1187             :             }
    1188             : 
    1189             :             /* Parse the parent HTTP proxy host:port */
    1190           0 :             p = vec[1];
    1191             : 
    1192           0 :             if (strcmp(p, ".") != 0)
    1193             :             {
    1194           0 :                cur_fwd->forward_port = 8000;
    1195           0 :                parse_forwarder_address(p,
    1196             :                   &cur_fwd->forward_host, &cur_fwd->forward_port,
    1197             :                   NULL, NULL);
    1198             :             }
    1199             : 
    1200             :             /* Add to list. */
    1201           0 :             cur_fwd->next = config->forward;
    1202           0 :             config->forward = cur_fwd;
    1203             : 
    1204           0 :             break;
    1205             : 
    1206             : /* *************************************************************************
    1207             :  * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port])
    1208             :  * *************************************************************************/
    1209           0 :          case hash_forward_socks4:
    1210           0 :             strlcpy(tmp, arg, sizeof(tmp));
    1211           0 :             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
    1212             : 
    1213           0 :             if (vec_count != 3)
    1214             :             {
    1215           0 :                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
    1216             :                      "forward-socks4 directive in configuration file.");
    1217           0 :                string_append(&config->proxy_args,
    1218             :                   "<br>\nWARNING: Wrong number of parameters for "
    1219             :                   "forward-socks4 directive in configuration file.");
    1220           0 :                break;
    1221             :             }
    1222             : 
    1223             :             /* allocate a new node */
    1224           0 :             cur_fwd = zalloc_or_die(sizeof(*cur_fwd));
    1225           0 :             cur_fwd->type = SOCKS_4;
    1226             : 
    1227             :             /* Save the URL pattern */
    1228           0 :             if (create_pattern_spec(cur_fwd->url, vec[0]))
    1229             :             {
    1230           0 :                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 "
    1231             :                      "directive in configuration file.");
    1232           0 :                string_append(&config->proxy_args,
    1233             :                   "<br>\nWARNING: Bad URL specifier for "
    1234             :                   "forward-socks4 directive in configuration file.");
    1235           0 :                freez(cur_fwd);
    1236           0 :                break;
    1237             :             }
    1238             : 
    1239             :             /* Parse the SOCKS proxy host[:port] */
    1240           0 :             p = vec[1];
    1241             : 
    1242             :             /* XXX: This check looks like a bug. */
    1243           0 :             if (strcmp(p, ".") != 0)
    1244             :             {
    1245           0 :                cur_fwd->gateway_port = 1080;
    1246           0 :                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           0 :             p = vec[2];
    1253             : 
    1254           0 :             if (strcmp(p, ".") != 0)
    1255             :             {
    1256           0 :                cur_fwd->forward_port = 8000;
    1257           0 :                parse_forwarder_address(p,
    1258             :                   &cur_fwd->forward_host, &cur_fwd->forward_port,
    1259             :                   NULL, NULL);
    1260             :             }
    1261             : 
    1262             :             /* Add to list. */
    1263           0 :             cur_fwd->next = config->forward;
    1264           0 :             config->forward = cur_fwd;
    1265             : 
    1266           0 :             break;
    1267             : 
    1268             : /* *************************************************************************
    1269             :  * forward-socks4a url-pattern socks-proxy[:port] (.|http-proxy[:port])
    1270             :  * *************************************************************************/
    1271           0 :          case hash_forward_socks4a:
    1272             :          case hash_forward_socks5:
    1273             :          case hash_forward_socks5t:
    1274           0 :             strlcpy(tmp, arg, sizeof(tmp));
    1275           0 :             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
    1276             : 
    1277           0 :             if (vec_count != 3)
    1278             :             {
    1279           0 :                log_error(LOG_LEVEL_ERROR,
    1280             :                   "Wrong number of parameters for %s in configuration file.",
    1281             :                   cmd);
    1282           0 :                string_append(&config->proxy_args,
    1283             :                   "<br>\nWARNING: Wrong number of parameters for ");
    1284           0 :                string_append(&config->proxy_args, cmd);
    1285           0 :                string_append(&config->proxy_args,
    1286             :                   "directive in configuration file.");
    1287           0 :                break;
    1288             :             }
    1289             : 
    1290             :             /* allocate a new node */
    1291           0 :             cur_fwd = zalloc_or_die(sizeof(*cur_fwd));
    1292             : 
    1293           0 :             if (directive_hash == hash_forward_socks4a)
    1294             :             {
    1295           0 :                cur_fwd->type = SOCKS_4A;
    1296             :             }
    1297           0 :             else if (directive_hash == hash_forward_socks5)
    1298             :             {
    1299           0 :                cur_fwd->type = SOCKS_5;
    1300             :             }
    1301             :             else
    1302             :             {
    1303           0 :                assert(directive_hash == hash_forward_socks5t);
    1304           0 :                cur_fwd->type = SOCKS_5T;
    1305             :             }
    1306             : 
    1307             :             /* Save the URL pattern */
    1308           0 :             if (create_pattern_spec(cur_fwd->url, vec[0]))
    1309             :             {
    1310           0 :                log_error(LOG_LEVEL_ERROR,
    1311             :                   "Bad URL specifier for %s in configuration file.",
    1312             :                   cmd);
    1313           0 :                string_append(&config->proxy_args,
    1314             :                   "<br>\nWARNING: Bad URL specifier for ");
    1315           0 :                string_append(&config->proxy_args, cmd);
    1316           0 :                string_append(&config->proxy_args,
    1317             :                   "directive in configuration file.");
    1318           0 :                freez(cur_fwd);
    1319           0 :                break;
    1320             :             }
    1321             : 
    1322             :             /* Parse the SOCKS proxy [user:pass@]host[:port] */
    1323           0 :             p = vec[1];
    1324             : 
    1325           0 :             cur_fwd->gateway_port = 1080;
    1326           0 :             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           0 :             p = vec[2];
    1332             : 
    1333           0 :             if (strcmp(p, ".") != 0)
    1334             :             {
    1335           0 :                cur_fwd->forward_port = 8000;
    1336           0 :                parse_forwarder_address(p,
    1337             :                   &cur_fwd->forward_host, &cur_fwd->forward_port,
    1338             :                   NULL, NULL);
    1339             :             }
    1340             : 
    1341             :             /* Add to list. */
    1342           0 :             cur_fwd->next = config->forward;
    1343           0 :             config->forward = cur_fwd;
    1344             : 
    1345           0 :             break;
    1346             : 
    1347             : /* *************************************************************************
    1348             :  * forwarded-connect-retries n
    1349             :  * *************************************************************************/
    1350        3098 :          case hash_forwarded_connect_retries :
    1351        3098 :             config->forwarded_connect_retries = parse_numeric_value(cmd, arg);
    1352        3098 :             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           0 :          case hash_handle_as_empty_returns_ok:
    1364           0 :             if (parse_toggle_state(cmd, arg) == 1)
    1365             :             {
    1366           0 :                config->feature_flags |= RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
    1367             :             }
    1368             :             else
    1369             :             {
    1370           0 :                config->feature_flags &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
    1371             :             }
    1372           0 :             break;
    1373             : 
    1374             : /* *************************************************************************
    1375             :  * hostname hostname-to-show-on-cgi-pages
    1376             :  * *************************************************************************/
    1377           0 :          case hash_hostname :
    1378           0 :             freez(config->hostname);
    1379           0 :             config->hostname = strdup_or_die(arg);
    1380           0 :             break;
    1381             : 
    1382             : /* *************************************************************************
    1383             :  * keep-alive-timeout timeout
    1384             :  * *************************************************************************/
    1385             : #ifdef FEATURE_CONNECTION_KEEP_ALIVE
    1386           0 :          case hash_keep_alive_timeout :
    1387             :          {
    1388           0 :             int timeout = parse_numeric_value(cmd, arg);
    1389           0 :             if (0 < timeout)
    1390             :             {
    1391           0 :                config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
    1392           0 :                config->keep_alive_timeout = (unsigned int)timeout;
    1393             :             }
    1394             :             else
    1395             :             {
    1396           0 :                config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
    1397             :             }
    1398           0 :             break;
    1399             :          }
    1400             : #endif
    1401             : 
    1402             : /* *************************************************************************
    1403             :  * listen-address [ip][:port]
    1404             :  * *************************************************************************/
    1405        3098 :          case hash_listen_address :
    1406        3098 :             i = 0;
    1407        3098 :             while ((i < MAX_LISTENING_SOCKETS) && (NULL != config->haddr[i]))
    1408             :             {
    1409           0 :                i++;
    1410             :             }
    1411             : 
    1412        3098 :             if (i >= MAX_LISTENING_SOCKETS)
    1413             :             {
    1414           0 :                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        3098 :             config->haddr[i] = strdup_or_die(arg);
    1419        3098 :             break;
    1420             : 
    1421             : /* *************************************************************************
    1422             :  * listen-backlog n
    1423             :  * *************************************************************************/
    1424           0 :          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           0 :             config->listen_backlog = parse_numeric_value(cmd, arg);
    1431           0 :             break;
    1432             : 
    1433             : /* *************************************************************************
    1434             :  * logdir directory-name
    1435             :  * *************************************************************************/
    1436        3098 :          case hash_logdir :
    1437        3098 :             freez(config->logdir);
    1438        3098 :             config->logdir = make_path(NULL, arg);
    1439        3098 :             break;
    1440             : 
    1441             : /* *************************************************************************
    1442             :  * logfile log-file-name
    1443             :  * In logdir by default
    1444             :  * *************************************************************************/
    1445           0 :          case hash_logfile :
    1446           0 :             if (daemon_mode)
    1447             :             {
    1448           0 :                logfile = make_path(config->logdir, arg);
    1449           0 :                if (NULL == logfile)
    1450             :                {
    1451           0 :                   log_error(LOG_LEVEL_FATAL, "Out of memory while creating logfile path");
    1452             :                }
    1453             :             }
    1454           0 :             break;
    1455             : 
    1456             : /* *************************************************************************
    1457             :  * max-client-connections number
    1458             :  * *************************************************************************/
    1459           0 :          case hash_max_client_connections :
    1460             :          {
    1461           0 :             int max_client_connections = parse_numeric_value(cmd, arg);
    1462             : 
    1463             : #if !defined(_WIN32) && !defined(HAVE_POLL)
    1464             :             /*
    1465             :              * Reject values below 1 for obvious reasons and values above
    1466             :              * FD_SETSIZE/2 because Privoxy needs two sockets to serve
    1467             :              * client connections that need forwarding.
    1468             :              *
    1469             :              * We ignore the fact that the first three file descriptors
    1470             :              * are usually set to /dev/null, one is used for logging
    1471             :              * and yet another file descriptor is required to load
    1472             :              * config files.
    1473             :              */
    1474             :             if ((max_client_connections < 1) || (FD_SETSIZE/2 < max_client_connections))
    1475             :             {
    1476             :                log_error(LOG_LEVEL_FATAL, "max-client-connections value %d"
    1477             :                   " is invalid. Value needs to be above 1 and below %d"
    1478             :                   " (FD_SETSIZE/2).", max_client_connections, FD_SETSIZE/2);
    1479             :             }
    1480             : #else
    1481             :             /*
    1482             :              * The Windows libc uses FD_SETSIZE for an array used
    1483             :              * by select(), but has no problems with file descriptors
    1484             :              * above the limit as long as no more than FD_SETSIZE are
    1485             :              * passed to select().
    1486             :              * https://msdn.microsoft.com/en-us/library/windows/desktop/ms739169%28v=vs.85%29.aspx
    1487             :              *
    1488             :              * On platforms were we use poll() we don't have to enforce
    1489             :              * an upper connection limit either.
    1490             :              */
    1491           0 :             if (max_client_connections < 1)
    1492             :             {
    1493           0 :                log_error(LOG_LEVEL_FATAL, "max-client-connections value"
    1494             :                   " has to be a number above 1. %d is invalid.",
    1495             :                   max_client_connections);
    1496             :             }
    1497             : #endif
    1498           0 :             config->max_client_connections = max_client_connections;
    1499           0 :             break;
    1500             :          }
    1501             : 
    1502             : /* *************************************************************************
    1503             :  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
    1504             :  * *************************************************************************/
    1505             : #ifdef FEATURE_ACL
    1506        3098 :          case hash_permit_access:
    1507        3098 :             strlcpy(tmp, arg, sizeof(tmp));
    1508        3098 :             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
    1509             : 
    1510        3098 :             if ((vec_count != 1) && (vec_count != 2))
    1511             :             {
    1512           0 :                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
    1513             :                      "permit-access directive in configuration file.");
    1514           0 :                string_append(&config->proxy_args,
    1515             :                   "<br>\nWARNING: Wrong number of parameters for "
    1516             :                   "permit-access directive in configuration file.<br><br>\n");
    1517             : 
    1518           0 :                break;
    1519             :             }
    1520             : 
    1521             :             /* allocate a new node */
    1522        3098 :             cur_acl = zalloc_or_die(sizeof(*cur_acl));
    1523        3098 :             cur_acl->action = ACL_PERMIT;
    1524             : 
    1525        3098 :             if (acl_addr(vec[0], cur_acl->src) < 0)
    1526             :             {
    1527           0 :                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
    1528             :                   "for permit-access directive in configuration file: \"%s\"", vec[0]);
    1529           0 :                string_append(&config->proxy_args,
    1530             :                   "<br>\nWARNING: Invalid source address, port or netmask for "
    1531             :                   "permit-access directive in configuration file: \"");
    1532           0 :                string_append(&config->proxy_args,
    1533           0 :                   vec[0]);
    1534           0 :                string_append(&config->proxy_args,
    1535             :                   "\"<br><br>\n");
    1536           0 :                freez(cur_acl);
    1537           0 :                break;
    1538             :             }
    1539        3098 :             if (vec_count == 2)
    1540             :             {
    1541           0 :                if (acl_addr(vec[1], cur_acl->dst) < 0)
    1542             :                {
    1543           0 :                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
    1544             :                      "for permit-access directive in configuration file: \"%s\"", vec[1]);
    1545           0 :                   string_append(&config->proxy_args,
    1546             :                      "<br>\nWARNING: Invalid destination address, port or netmask for "
    1547             :                      "permit-access directive in configuration file: \"");
    1548           0 :                   string_append(&config->proxy_args,
    1549           0 :                      vec[1]);
    1550           0 :                   string_append(&config->proxy_args,
    1551             :                      "\"<br><br>\n");
    1552           0 :                   freez(cur_acl);
    1553           0 :                   break;
    1554             :                }
    1555             :             }
    1556             : #ifdef HAVE_RFC2553
    1557             :             else
    1558             :             {
    1559        3098 :                cur_acl->wildcard_dst = 1;
    1560             :             }
    1561             : #endif /* def HAVE_RFC2553 */
    1562             : 
    1563             :             /*
    1564             :              * Add it to the list.  Note we reverse the list to get the
    1565             :              * behaviour the user expects.  With both the ACL and
    1566             :              * actions file, the last match wins.  However, the internal
    1567             :              * implementations are different:  The actions file is stored
    1568             :              * in the same order as the file, and scanned completely.
    1569             :              * With the ACL, we reverse the order as we load it, then
    1570             :              * when we scan it we stop as soon as we get a match.
    1571             :              */
    1572        3098 :             cur_acl->next  = config->acl;
    1573        3098 :             config->acl = cur_acl;
    1574             : 
    1575        3098 :             break;
    1576             : #endif /* def FEATURE_ACL */
    1577             : 
    1578             : /* *************************************************************************
    1579             :  * proxy-info-url url
    1580             :  * *************************************************************************/
    1581           0 :          case hash_proxy_info_url :
    1582           0 :             freez(config->proxy_info_url);
    1583           0 :             config->proxy_info_url = strdup_or_die(arg);
    1584           0 :             break;
    1585             : 
    1586             : 
    1587             : /* *************************************************************************
    1588             :  * receive-buffer-size n
    1589             :  * *************************************************************************/
    1590           0 :          case hash_receive_buffer_size :
    1591           0 :             config->receive_buffer_size = (size_t)parse_numeric_value(cmd, arg);
    1592           0 :             if (config->receive_buffer_size < BUFFER_SIZE)
    1593             :             {
    1594           0 :                log_error(LOG_LEVEL_INFO,
    1595             :                   "receive-buffer-size %lu seems low and may cause problems."
    1596             :                   "Consider setting it to at least %d.",
    1597             :                   config->receive_buffer_size, BUFFER_SIZE);
    1598             :             }
    1599           0 :             break;
    1600             : 
    1601             : /* *************************************************************************
    1602             :  * single-threaded 0|1
    1603             :  * *************************************************************************/
    1604        3098 :          case hash_single_threaded :
    1605        3098 :             config->multi_threaded =  0 == parse_toggle_state(cmd, arg);
    1606        3098 :             break;
    1607             : 
    1608             : /* *************************************************************************
    1609             :  * socket-timeout numer_of_seconds
    1610             :  * *************************************************************************/
    1611        3098 :          case hash_socket_timeout :
    1612             :          {
    1613        3098 :             int socket_timeout = parse_numeric_value(cmd, arg);
    1614        3098 :             if (0 <= socket_timeout)
    1615             :             {
    1616        3098 :                config->socket_timeout = socket_timeout;
    1617             :             }
    1618             :             else
    1619             :             {
    1620           0 :                log_error(LOG_LEVEL_FATAL, "Invalid socket-timeout: '%s'", arg);
    1621             :             }
    1622        3098 :             break;
    1623             :          }
    1624             : 
    1625             : /* *************************************************************************
    1626             :  * split-large-cgi-forms
    1627             :  * *************************************************************************/
    1628        3098 :          case hash_split_large_cgi_forms :
    1629        3098 :             if (parse_toggle_state(cmd, arg) == 1)
    1630             :             {
    1631           0 :                config->feature_flags |= RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
    1632             :             }
    1633             :             else
    1634             :             {
    1635        3098 :                config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
    1636             :             }
    1637        3098 :             break;
    1638             : 
    1639             : /* *************************************************************************
    1640             :  * templdir directory-name
    1641             :  * *************************************************************************/
    1642           0 :          case hash_templdir :
    1643           0 :             freez(config->templdir);
    1644           0 :             config->templdir = make_path(NULL, arg);
    1645           0 :             break;
    1646             : 
    1647             : #ifdef FEATURE_EXTERNAL_FILTERS
    1648             : /* *************************************************************************
    1649             :  * temporary-directory directory-name
    1650             :  * *************************************************************************/
    1651        3098 :          case hash_temporary_directory :
    1652        3098 :             freez(config->temporary_directory);
    1653        3098 :             config->temporary_directory = make_path(NULL, arg);
    1654        3098 :             break;
    1655             : #endif
    1656             : 
    1657             : /* *************************************************************************
    1658             :  * tolerate-pipelining (0|1)
    1659             :  * *************************************************************************/
    1660        3098 :          case hash_tolerate_pipelining :
    1661        3098 :             if (parse_toggle_state(cmd, arg) == 1)
    1662             :             {
    1663        3098 :                config->feature_flags |= RUNTIME_FEATURE_TOLERATE_PIPELINING;
    1664             :             }
    1665             :             else
    1666             :             {
    1667           0 :                config->feature_flags &= ~RUNTIME_FEATURE_TOLERATE_PIPELINING;
    1668             :             }
    1669        3098 :             break;
    1670             : 
    1671             : /* *************************************************************************
    1672             :  * toggle (0|1)
    1673             :  * *************************************************************************/
    1674             : #ifdef FEATURE_TOGGLE
    1675        3098 :          case hash_toggle :
    1676        3098 :             global_toggle_state = parse_toggle_state(cmd, arg);
    1677        3098 :             break;
    1678             : #endif /* def FEATURE_TOGGLE */
    1679             : 
    1680             : /* *************************************************************************
    1681             :  * trust-info-url url
    1682             :  * *************************************************************************/
    1683             : #ifdef FEATURE_TRUST
    1684           0 :          case hash_trust_info_url :
    1685           0 :             enlist(config->trust_info, arg);
    1686           0 :             break;
    1687             : #endif /* def FEATURE_TRUST */
    1688             : 
    1689             : /* *************************************************************************
    1690             :  * trust-x-forwarded-for (0|1)
    1691             :  * *************************************************************************/
    1692        3098 :          case hash_trust_x_forwarded_for :
    1693        3098 :             config->trust_x_forwarded_for = parse_toggle_state(cmd, arg);
    1694        3098 :             break;
    1695             : 
    1696             : /* *************************************************************************
    1697             :  * trusted-cgi-referrer http://www.example.org/some/path.html
    1698             :  * *************************************************************************/
    1699        3098 :          case hash_trusted_cgi_referrer :
    1700             :             /*
    1701             :              * We don't validate the specified referrer as
    1702             :              * it's only used for string comparison.
    1703             :              */
    1704        3098 :             freez(config->trusted_cgi_referrer);
    1705        3098 :             config->trusted_cgi_referrer = strdup_or_die(arg);
    1706        3098 :             break;
    1707             : 
    1708             : /* *************************************************************************
    1709             :  * trustfile filename
    1710             :  * (In confdir by default.)
    1711             :  * *************************************************************************/
    1712             : #ifdef FEATURE_TRUST
    1713           0 :          case hash_trustfile :
    1714           0 :             freez(config->trustfile);
    1715           0 :             config->trustfile = make_path(config->confdir, arg);
    1716           0 :             break;
    1717             : #endif /* def FEATURE_TRUST */
    1718             : 
    1719             : /* *************************************************************************
    1720             :  * usermanual url
    1721             :  * *************************************************************************/
    1722           0 :          case hash_usermanual :
    1723             :             /*
    1724             :              * XXX: If this isn't the first config directive, the
    1725             :              * show-status page links to the website documentation
    1726             :              * for the directives that were already parsed. Lame.
    1727             :              */
    1728           0 :             freez(config->usermanual);
    1729           0 :             config->usermanual = strdup_or_die(arg);
    1730           0 :             break;
    1731             : 
    1732             : #ifdef FEATURE_HTTPS_INSPECTION
    1733             : /* *************************************************************************
    1734             :  * ca private key file password
    1735             :  * *************************************************************************/
    1736           0 :          case hash_ca_password:
    1737           0 :             freez(config->ca_password);
    1738           0 :             config->ca_password = strdup(arg);
    1739           0 :             break;
    1740             : 
    1741             : /* *************************************************************************
    1742             :  * ca-directory directory
    1743             :  * *************************************************************************/
    1744        3098 :          case hash_ca_directory:
    1745        3098 :             freez(ca_directory);
    1746        3098 :             ca_directory = make_path(NULL, arg);
    1747             : 
    1748        3098 :             if (NULL == ca_directory)
    1749             :             {
    1750           0 :                log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca dir path");
    1751             :             }
    1752             : 
    1753        3098 :             break;
    1754             : 
    1755             : /* *************************************************************************
    1756             :  * ca cert file ca-cert-file
    1757             :  * In ca dir by default
    1758             :  * *************************************************************************/
    1759        3098 :          case hash_ca_cert_file:
    1760        3098 :             freez(ca_cert_file);
    1761        3098 :             ca_cert_file = make_path(config->ca_directory, arg);
    1762             : 
    1763        3098 :             if (NULL == ca_cert_file)
    1764             :             {
    1765           0 :                log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca certificate file path");
    1766             :             }
    1767             : 
    1768        3098 :             break;
    1769             : 
    1770             : /* *************************************************************************
    1771             :  * ca key file ca-key-file
    1772             :  * In ca dir by default
    1773             :  * *************************************************************************/
    1774        3098 :          case hash_ca_key_file:
    1775        3098 :             freez(ca_key_file);
    1776        3098 :             ca_key_file = make_path(config->ca_directory, arg);
    1777             : 
    1778        3098 :             if (NULL == ca_key_file)
    1779             :             {
    1780           0 :                log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca key file path");
    1781             :             }
    1782             : 
    1783        3098 :             break;
    1784             : 
    1785             : /* *************************************************************************
    1786             :  * certificate-directory directory
    1787             :  * *************************************************************************/
    1788        3098 :          case hash_certificate_directory:
    1789        3098 :             freez(certificate_directory);
    1790        3098 :             certificate_directory = make_path(NULL, arg);
    1791             : 
    1792        3098 :             if (NULL == certificate_directory)
    1793             :             {
    1794           0 :                log_error(LOG_LEVEL_FATAL,
    1795             :                   "Out of memory while creating certificate directory path");
    1796             :             }
    1797             : 
    1798        3098 :             break;
    1799             : 
    1800             : /* *************************************************************************
    1801             :  * cipher-list list-of-ciphers
    1802             :  * *************************************************************************/
    1803           0 :          case hash_cipher_list:
    1804           0 :             freez(config->cipher_list);
    1805           0 :             config->cipher_list = strdup_or_die(arg);
    1806             : 
    1807           0 :             break;
    1808             : 
    1809             : /* *************************************************************************
    1810             :  * trusted CAs file name trusted-cas-file
    1811             :  * *************************************************************************/
    1812        3098 :          case hash_trusted_cas_file:
    1813        3098 :             freez(trusted_cas_file);
    1814        3098 :             trusted_cas_file = make_path(config->ca_directory, arg);
    1815             : 
    1816        3098 :             if (NULL == trusted_cas_file)
    1817             :             {
    1818           0 :                log_error(LOG_LEVEL_FATAL, "Out of memory while creating trusted CAs file path");
    1819             :             }
    1820             : 
    1821        3098 :             break;
    1822             : #endif
    1823             : 
    1824             : /* *************************************************************************
    1825             :  * Win32 Console options:
    1826             :  * *************************************************************************/
    1827             : 
    1828             : /* *************************************************************************
    1829             :  * hide-console
    1830             :  * *************************************************************************/
    1831             : #ifdef _WIN_CONSOLE
    1832             :          case hash_hide_console :
    1833             :             hideConsole = 1;
    1834             :             break;
    1835             : #endif /*def _WIN_CONSOLE*/
    1836             : 
    1837             : 
    1838             : /* *************************************************************************
    1839             :  * Win32 GUI options:
    1840             :  * *************************************************************************/
    1841             : 
    1842             : #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
    1843             : /* *************************************************************************
    1844             :  * activity-animation (0|1)
    1845             :  * *************************************************************************/
    1846             :          case hash_activity_animation :
    1847             :             g_bShowActivityAnimation = parse_toggle_state(cmd, arg);
    1848             :             break;
    1849             : 
    1850             : /* *************************************************************************
    1851             :  *  close-button-minimizes (0|1)
    1852             :  * *************************************************************************/
    1853             :          case hash_close_button_minimizes :
    1854             :             g_bCloseHidesWindow = parse_toggle_state(cmd, arg);
    1855             :             break;
    1856             : 
    1857             : /* *************************************************************************
    1858             :  * log-buffer-size (0|1)
    1859             :  * *************************************************************************/
    1860             :          case hash_log_buffer_size :
    1861             :             g_bLimitBufferSize = parse_toggle_state(cmd, arg);
    1862             :             break;
    1863             : 
    1864             : /* *************************************************************************
    1865             :  * log-font-name fontname
    1866             :  * *************************************************************************/
    1867             :          case hash_log_font_name :
    1868             :             if (strlcpy(g_szFontFaceName, arg,
    1869             :                    sizeof(g_szFontFaceName)) >= sizeof(g_szFontFaceName))
    1870             :             {
    1871             :                log_error(LOG_LEVEL_FATAL,
    1872             :                   "log-font-name argument '%s' is longer than %u characters.",
    1873             :                   arg, sizeof(g_szFontFaceName)-1);
    1874             :             }
    1875             :             break;
    1876             : 
    1877             : /* *************************************************************************
    1878             :  * log-font-size n
    1879             :  * *************************************************************************/
    1880             :          case hash_log_font_size :
    1881             :             g_nFontSize = parse_numeric_value(cmd, arg);
    1882             :             break;
    1883             : 
    1884             : /* *************************************************************************
    1885             :  * log-highlight-messages (0|1)
    1886             :  * *************************************************************************/
    1887             :          case hash_log_highlight_messages :
    1888             :             g_bHighlightMessages = parse_toggle_state(cmd, arg);
    1889             :             break;
    1890             : 
    1891             : /* *************************************************************************
    1892             :  * log-max-lines n
    1893             :  * *************************************************************************/
    1894             :          case hash_log_max_lines :
    1895             :             g_nMaxBufferLines = parse_numeric_value(cmd, arg);
    1896             :             break;
    1897             : 
    1898             : /* *************************************************************************
    1899             :  * log-messages (0|1)
    1900             :  * *************************************************************************/
    1901             :          case hash_log_messages :
    1902             :             g_bLogMessages = parse_toggle_state(cmd, arg);
    1903             :             break;
    1904             : 
    1905             : /* *************************************************************************
    1906             :  * show-on-task-bar (0|1)
    1907             :  * *************************************************************************/
    1908             :          case hash_show_on_task_bar :
    1909             :             g_bShowOnTaskBar = parse_toggle_state(cmd, arg);
    1910             :             break;
    1911             : 
    1912             : #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
    1913             : 
    1914             : 
    1915             : /* *************************************************************************
    1916             :  * Warnings about unsupported features
    1917             :  * *************************************************************************/
    1918             : #ifndef FEATURE_ACL
    1919             :          case hash_deny_access:
    1920             : #endif /* ndef FEATURE_ACL */
    1921             : #ifndef FEATURE_CGI_EDIT_ACTIONS
    1922             :          case hash_enable_edit_actions:
    1923             : #endif /* ndef FEATURE_CGI_EDIT_ACTIONS */
    1924             : #ifndef FEATURE_TOGGLE
    1925             :          case hash_enable_remote_toggle:
    1926             : #endif /* ndef FEATURE_TOGGLE */
    1927             : #ifndef FEATURE_ACL
    1928             :          case hash_permit_access:
    1929             : #endif /* ndef FEATURE_ACL */
    1930             : #ifndef FEATURE_TOGGLE
    1931             :          case hash_toggle :
    1932             : #endif /* ndef FEATURE_TOGGLE */
    1933             : #ifndef FEATURE_TRUST
    1934             :          case hash_trustfile :
    1935             :          case hash_trust_info_url :
    1936             : #endif /* ndef FEATURE_TRUST */
    1937             : 
    1938             : #ifndef _WIN_CONSOLE
    1939           0 :          case hash_hide_console :
    1940             : #endif /* ndef _WIN_CONSOLE */
    1941             : 
    1942             : #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
    1943             :          case hash_activity_animation :
    1944             :          case hash_close_button_minimizes :
    1945             :          case hash_log_buffer_size :
    1946             :          case hash_log_font_name :
    1947             :          case hash_log_font_size :
    1948             :          case hash_log_highlight_messages :
    1949             :          case hash_log_max_lines :
    1950             :          case hash_log_messages :
    1951             :          case hash_show_on_task_bar :
    1952             : #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
    1953             :             /* These warnings are annoying - so hide them. -- Jon */
    1954             :             /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */
    1955           0 :             break;
    1956             : 
    1957             : /* *************************************************************************/
    1958           0 :          default :
    1959             : /* *************************************************************************/
    1960             :             /*
    1961             :              * I decided that I liked this better as a warning than an
    1962             :              * error.  To change back to an error, just change log level
    1963             :              * to LOG_LEVEL_FATAL.
    1964             :              */
    1965           0 :             log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive "
    1966             :                "'%s' (%uU) in line %lu in configuration file (%s).",
    1967             :                buf, directive_hash, linenum, configfile);
    1968           0 :             string_append(&config->proxy_args,
    1969             :                " <strong class='warning'>Warning: Ignoring unrecognized directive:</strong>");
    1970           0 :             break;
    1971             : 
    1972             : /* *************************************************************************/
    1973             :       } /* end switch(hash_string(cmd)) */
    1974             : 
    1975             :       /* Save the argument for the show-status page. */
    1976      173488 :       savearg(cmd, arg, config);
    1977      173488 :       freez(buf);
    1978             :    } /* end while (read_config_line(...)) */
    1979             : 
    1980        3098 :    fclose(configfp);
    1981             : 
    1982        3098 :    set_debug_level(config->debug);
    1983             : 
    1984        3098 :    freez(config->logfile);
    1985             : 
    1986        3098 :    if (daemon_mode)
    1987             :    {
    1988           0 :       if (NULL != logfile)
    1989             :       {
    1990           0 :          config->logfile = logfile;
    1991           0 :          init_error_log(Argv[0], config->logfile);
    1992             :       }
    1993             :       else
    1994             :       {
    1995           0 :          disable_logging();
    1996             :       }
    1997             :    }
    1998             : 
    1999             : #ifdef FEATURE_HTTPS_INSPECTION
    2000             :    /*
    2001             :     * Setting SSL parameters from loaded values into structures
    2002             :     */
    2003        3098 :    freez(config->ca_directory);
    2004        3098 :    config->ca_directory = make_path(NULL, ca_directory);
    2005        3098 :    freez(ca_directory);
    2006             : 
    2007        3098 :    freez(config->ca_cert_file);
    2008        3098 :    config->ca_cert_file = make_path(config->ca_directory, ca_cert_file);
    2009        3098 :    freez(ca_cert_file);
    2010             : 
    2011        3098 :    freez(config->ca_key_file);
    2012        3098 :    config->ca_key_file  = make_path(config->ca_directory, ca_key_file);
    2013        3098 :    freez(ca_key_file);
    2014             : 
    2015        3098 :    freez(config->trusted_cas_file);
    2016        3098 :    config->trusted_cas_file = make_path(config->ca_directory, trusted_cas_file);
    2017        3098 :    freez(trusted_cas_file);
    2018             : 
    2019        3098 :    freez(config->certificate_directory);
    2020        3098 :    config->certificate_directory = make_path(NULL, certificate_directory);
    2021        3098 :    freez(certificate_directory);
    2022             : #endif
    2023             : #ifdef FEATURE_CONNECTION_KEEP_ALIVE
    2024        3098 :    if (config->default_server_timeout > config->keep_alive_timeout)
    2025             :    {
    2026           0 :       log_error(LOG_LEVEL_ERROR,
    2027             :          "Reducing the default-server-timeout from %d to the keep-alive-timeout %d.",
    2028             :          config->default_server_timeout, config->keep_alive_timeout);
    2029           0 :       config->default_server_timeout = config->keep_alive_timeout;
    2030             :    }
    2031             : #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
    2032             : 
    2033             : #ifdef FEATURE_CONNECTION_SHARING
    2034        3098 :    if (config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
    2035             :    {
    2036           0 :       if (!config->multi_threaded)
    2037             :       {
    2038             :          /*
    2039             :           * While we could use keep-alive without multiple threads
    2040             :           * if we didn't bother with enforcing the connection timeout,
    2041             :           * that might make Tor users sad, even though they shouldn't
    2042             :           * enable the single-threaded option anyway.
    2043             :           *
    2044             :           * XXX: We could still use Proxy-Connection: keep-alive.
    2045             :           */
    2046           0 :          config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
    2047           0 :          log_error(LOG_LEVEL_ERROR,
    2048             :             "Config option single-threaded disables connection keep-alive.");
    2049             :       }
    2050             :    }
    2051        3098 :    else if ((config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
    2052             :    {
    2053           0 :       log_error(LOG_LEVEL_ERROR, "Config option connection-sharing "
    2054             :          "has no effect if keep-alive-timeout isn't set.");
    2055           0 :       config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
    2056             :    }
    2057             : #endif /* def FEATURE_CONNECTION_SHARING */
    2058             : 
    2059        3098 :    if (NULL == config->proxy_args)
    2060             :    {
    2061           0 :       log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args");
    2062             :    }
    2063             : 
    2064        3098 :    if (config->re_filterfile[0])
    2065             :    {
    2066        3098 :       add_loader(load_re_filterfiles, config);
    2067             :    }
    2068             : 
    2069        3098 :    if (config->actions_file[0])
    2070             :    {
    2071        3098 :       add_loader(load_action_files, config);
    2072             :    }
    2073             : 
    2074             : #ifdef FEATURE_TRUST
    2075        3098 :    if (config->trustfile)
    2076             :    {
    2077           0 :       add_loader(load_trustfile, config);
    2078             :    }
    2079             : #endif /* def FEATURE_TRUST */
    2080             : 
    2081        3098 :    if (NULL == config->haddr[0])
    2082             :    {
    2083           0 :       config->haddr[0] = strdup_or_die(HADDR_DEFAULT);
    2084             :    }
    2085             : 
    2086        6196 :    for (i = 0; i < MAX_LISTENING_SOCKETS && NULL != config->haddr[i]; i++)
    2087             :    {
    2088        3098 :       if ((*config->haddr[i] == '[')
    2089           0 :          && (NULL != (p = strchr(config->haddr[i], ']')))
    2090           0 :          && (p[1] == ':')
    2091           0 :          && (0 < (config->hport[i] = atoi(p + 2))))
    2092             :       {
    2093           0 :          *p = '\0';
    2094           0 :          memmove((void *)config->haddr[i], config->haddr[i] + 1,
    2095           0 :             (size_t)(p - config->haddr[i]));
    2096             :       }
    2097        3098 :       else if (NULL != (p = strchr(config->haddr[i], ':'))
    2098        3098 :          && (0 < (config->hport[i] = atoi(p + 1))))
    2099             :       {
    2100        3098 :          *p = '\0';
    2101             :       }
    2102             :       else
    2103             :       {
    2104           0 :          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr[i]);
    2105             :          /* Never get here - LOG_LEVEL_FATAL causes program exit */
    2106             :       }
    2107        3098 :       if (*config->haddr[i] == '\0')
    2108             :       {
    2109             :          /*
    2110             :           * Only the port specified. We stored it in config->hport[i]
    2111             :           * and don't need its text representation anymore.
    2112             :           * Use config->hport[i] == 0 to iterate listening addresses since
    2113             :           * now.
    2114             :           */
    2115           0 :          freez(config->haddr[i]);
    2116             :       }
    2117             :    }
    2118             : 
    2119             :    /*
    2120             :     * Want to run all the loaders once now.
    2121             :     *
    2122             :     * Need to set up a fake csp, so they can get to the config.
    2123             :     */
    2124        3098 :    fake_csp = zalloc_or_die(sizeof(*fake_csp));
    2125        3098 :    fake_csp->config = config;
    2126             : 
    2127        3098 :    if (run_loader(fake_csp))
    2128             :    {
    2129           0 :       freez(fake_csp);
    2130           0 :       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
    2131             :       /* Never get here - LOG_LEVEL_FATAL causes program exit */
    2132             :    }
    2133        3098 :    freez(fake_csp);
    2134             : 
    2135             : /* FIXME: this is a kludge for win32 */
    2136             : #if defined(_WIN32) && !defined (_WIN_CONSOLE)
    2137             : 
    2138             :    g_default_actions_file = config->actions_file[1]; /* FIXME Hope this is default.action */
    2139             :    g_user_actions_file  = config->actions_file[2];  /* FIXME Hope this is user.action */
    2140             :    g_default_filterfile = config->re_filterfile[0]; /* FIXME Hope this is default.filter */
    2141             :    g_user_filterfile    = config->re_filterfile[1]; /* FIXME Hope this is user.filter */
    2142             : 
    2143             : #ifdef FEATURE_TRUST
    2144             :    g_trustfile        = config->trustfile;
    2145             : #endif /* def FEATURE_TRUST */
    2146             : 
    2147             : 
    2148             : #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
    2149             : /* FIXME: end kludge */
    2150             : 
    2151             : 
    2152        3098 :    if (current_configfile == NULL)
    2153             :    {
    2154        3098 :       config->need_bind = 1;
    2155             :    }
    2156             :    else
    2157             :    {
    2158           0 :       struct configuration_spec * oldcfg = (struct configuration_spec *)
    2159           0 :                                            current_configfile->f;
    2160             :       /*
    2161             :        * Check if config->haddr[i],hport[i] == oldcfg->haddr[i],hport[i]
    2162             :        */
    2163           0 :       config->need_bind = 0;
    2164             : 
    2165           0 :       for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
    2166             :       {
    2167           0 :          if (config->hport[i] != oldcfg->hport[i])
    2168             :          {
    2169           0 :             config->need_bind = 1;
    2170             :          }
    2171           0 :          else if (config->haddr[i] == NULL)
    2172             :          {
    2173           0 :             if (oldcfg->haddr[i] != NULL)
    2174             :             {
    2175           0 :                config->need_bind = 1;
    2176             :             }
    2177             :          }
    2178           0 :          else if (oldcfg->haddr[i] == NULL)
    2179             :          {
    2180           0 :             config->need_bind = 1;
    2181             :          }
    2182           0 :          else if (0 != strcmp(config->haddr[i], oldcfg->haddr[i]))
    2183             :          {
    2184           0 :             config->need_bind = 1;
    2185             :          }
    2186             :       }
    2187             : 
    2188           0 :       current_configfile->unloader = unload_configfile;
    2189             :    }
    2190             : 
    2191        3098 :    fs->next = files->next;
    2192        3098 :    files->next = fs;
    2193             : 
    2194        3098 :    current_configfile = fs;
    2195             : 
    2196        3098 :    return (config);
    2197             : }
    2198             : 
    2199             : 
    2200             : /*********************************************************************
    2201             :  *
    2202             :  * Function    :  savearg
    2203             :  *
    2204             :  * Description :  Called from `load_config'.  It saves each non-empty
    2205             :  *                and non-comment line from config into
    2206             :  *                config->proxy_args.  This is used to create the
    2207             :  *                show-status page.  On error, frees
    2208             :  *                config->proxy_args and sets it to NULL
    2209             :  *
    2210             :  * Parameters  :
    2211             :  *          1  :  command = config setting that was found
    2212             :  *          2  :  argument = the setting's argument (if any)
    2213             :  *          3  :  config = Configuration to save into.
    2214             :  *
    2215             :  * Returns     :  N/A
    2216             :  *
    2217             :  *********************************************************************/
    2218      173488 : static void savearg(char *command, char *argument, struct configuration_spec * config)
    2219             : {
    2220             :    char * buf;
    2221             :    char * s;
    2222             : 
    2223      173488 :    assert(command);
    2224      173488 :    assert(argument);
    2225             : 
    2226             :    /*
    2227             :     * Add config option name embedded in
    2228             :     * link to its section in the user-manual
    2229             :     */
    2230      173488 :    buf = strdup_or_die("\n<a href=\"");
    2231      346976 :    if (!strncmpic(config->usermanual, "file://", 7) ||
    2232      173488 :        !strncmpic(config->usermanual, "http", 4))
    2233             :    {
    2234      173488 :       string_append(&buf, config->usermanual);
    2235             :    }
    2236             :    else
    2237             :    {
    2238           0 :       string_append(&buf, "http://" CGI_SITE_2_HOST "/user-manual/");
    2239             :    }
    2240      173488 :    string_append(&buf, CONFIG_HELP_PREFIX);
    2241      173488 :    string_join  (&buf, string_toupper(command));
    2242      173488 :    string_append(&buf, "\">");
    2243      173488 :    string_append(&buf, command);
    2244      173488 :    string_append(&buf, "</a> ");
    2245             : 
    2246      173488 :    if (NULL == buf)
    2247             :    {
    2248           0 :       freez(config->proxy_args);
    2249           0 :       return;
    2250             :    }
    2251             : 
    2252      173488 :    if ((NULL != argument) && ('\0' != *argument))
    2253             :    {
    2254      173488 :       s = html_encode(argument);
    2255      173488 :       if (NULL == s)
    2256             :       {
    2257           0 :          freez(buf);
    2258           0 :          freez(config->proxy_args);
    2259           0 :          return;
    2260             :       }
    2261             : 
    2262      173488 :       if (strncmpic(argument, "http://", 7) == 0)
    2263             :       {
    2264           0 :          string_append(&buf, "<a href=\"");
    2265           0 :          string_append(&buf, s);
    2266           0 :          string_append(&buf, "\">");
    2267           0 :          string_join  (&buf, s);
    2268           0 :          string_append(&buf, "</a>");
    2269             :       }
    2270             :       else
    2271             :       {
    2272      173488 :          string_join  (&buf, s);
    2273             :       }
    2274             :    }
    2275             : 
    2276      173488 :    string_append(&buf, "<br>");
    2277      173488 :    string_join(&config->proxy_args, buf);
    2278             : }
    2279             : 
    2280             : 
    2281             : /*
    2282             :   Local Variables:
    2283             :   tab-width: 3
    2284             :   end:
    2285             : */

Generated by: LCOV version 1.14