X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=loadcfg.c;h=7cf580157e245c5e008704f61845181e9c1a8afb;hp=5ced6c90a7dc19e9b179016bc9eded6bcf649281;hb=97dcdede1c96c857ea36b5f5a9873c302d021a7d;hpb=9969c79b899259b1cc496528b4f775d7fa68c151 diff --git a/loadcfg.c b/loadcfg.c index 5ced6c90..7cf58015 100644 --- a/loadcfg.c +++ b/loadcfg.c @@ -1,4 +1,4 @@ -const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.109 2010/01/10 13:53:48 ler762 Exp $"; +const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.152 2016/05/08 10:46:55 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loadcfg.c,v $ @@ -8,7 +8,7 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.109 2010/01/10 13:53:48 ler762 Ex * routine to load the configuration and the global * variables it writes to. * - * Copyright : Written by and Copyright (C) 2001-2009 the + * Copyright : Written by and Copyright (C) 2001-2016 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -72,6 +72,7 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.109 2010/01/10 13:53:48 ler762 Ex #endif +#include "project.h" #include "loadcfg.h" #include "list.h" #include "jcc.h" @@ -84,20 +85,12 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.109 2010/01/10 13:53:48 ler762 Ex #include "urlmatch.h" #include "cgi.h" #include "gateway.h" +#ifdef FEATURE_CLIENT_TAGS +#include "client-tags.h" +#endif const char loadcfg_h_rcs[] = LOADCFG_H_VERSION; -/* - * Fix a problem with Solaris. There should be no effect on other - * platforms. - * Solaris's isspace() is a macro which uses it's argument directly - * as an array index. Therefore we need to make sure that high-bit - * characters generate +ve values, and ideally we also want to make - * the argument match the declared parameter type of "int". - */ -#define ijb_isupper(__X) isupper((int)(unsigned char)(__X)) -#define ijb_tolower(__X) tolower((int)(unsigned char)(__X)) - #ifdef FEATURE_TOGGLE /* Privoxy is enabled by default. */ int global_toggle_state = 1; @@ -128,57 +121,70 @@ static struct file_list *current_configfile = NULL; * console and GUI specific options last). */ -#define hash_actions_file 1196306641ul /* "actionsfile" */ -#define hash_accept_intercepted_requests 1513024973ul /* "accept-intercepted-requests" */ -#define hash_admin_address 4112573064ul /* "admin-address" */ -#define hash_allow_cgi_request_crunching 258915987ul /* "allow-cgi-request-crunching" */ -#define hash_buffer_limit 1881726070ul /* "buffer-limit */ -#define hash_confdir 1978389ul /* "confdir" */ -#define hash_connection_sharing 1348841265ul /* "connection-sharing" */ -#define hash_debug 78263ul /* "debug" */ -#define hash_default_server_timeout 2530089913ul /* "default-server-timeout" */ -#define hash_deny_access 1227333715ul /* "deny-access" */ -#define hash_enable_edit_actions 2517097536ul /* "enable-edit-actions" */ -#define hash_enable_remote_toggle 2979744683ul /* "enable-remote-toggle" */ -#define hash_enable_remote_http_toggle 110543988ul /* "enable-remote-http-toggle" */ -#define hash_enforce_blocks 1862427469ul /* "enforce-blocks" */ -#define hash_filterfile 250887266ul /* "filterfile" */ -#define hash_forward 2029845ul /* "forward" */ -#define hash_forward_socks4 3963965521ul /* "forward-socks4" */ -#define hash_forward_socks4a 2639958518ul /* "forward-socks4a" */ -#define hash_forward_socks5 3963965522ul /* "forward-socks5" */ -#define hash_forwarded_connect_retries 101465292ul /* "forwarded-connect-retries" */ -#define hash_handle_as_empty_returns_ok 1444873247ul /* "handle-as-empty-doc-returns-ok" */ -#define hash_hostname 10308071ul /* "hostname" */ -#define hash_keep_alive_timeout 3878599515ul /* "keep-alive-timeout" */ -#define hash_listen_address 1255650842ul /* "listen-address" */ -#define hash_logdir 422889ul /* "logdir" */ -#define hash_logfile 2114766ul /* "logfile" */ -#define hash_max_client_connections 3595884446ul /* "max-client-connections" */ -#define hash_permit_access 3587953268ul /* "permit-access" */ -#define hash_proxy_info_url 3903079059ul /* "proxy-info-url" */ -#define hash_single_threaded 4250084780ul /* "single-threaded" */ -#define hash_socket_timeout 1809001761ul /* "socket-timeout" */ -#define hash_split_large_cgi_forms 671658948ul /* "split-large-cgi-forms" */ -#define hash_suppress_blocklists 1948693308ul /* "suppress-blocklists" */ -#define hash_templdir 11067889ul /* "templdir" */ -#define hash_toggle 447966ul /* "toggle" */ -#define hash_trust_info_url 430331967ul /* "trust-info-url" */ -#define hash_trustfile 56494766ul /* "trustfile" */ -#define hash_usermanual 1416668518ul /* "user-manual" */ -#define hash_activity_animation 1817904738ul /* "activity-animation" */ -#define hash_close_button_minimizes 3651284693ul /* "close-button-minimizes" */ -#define hash_hide_console 2048809870ul /* "hide-console" */ -#define hash_log_buffer_size 2918070425ul /* "log-buffer-size" */ -#define hash_log_font_name 2866730124ul /* "log-font-name" */ -#define hash_log_font_size 2866731014ul /* "log-font-size" */ -#define hash_log_highlight_messages 4032101240ul /* "log-highlight-messages" */ -#define hash_log_max_lines 2868344173ul /* "log-max-lines" */ -#define hash_log_messages 2291744899ul /* "log-messages" */ -#define hash_show_on_task_bar 215410365ul /* "show-on-task-bar" */ +#define hash_actions_file 1196306641U /* "actionsfile" */ +#define hash_accept_intercepted_requests 1513024973U /* "accept-intercepted-requests" */ +#define hash_admin_address 4112573064U /* "admin-address" */ +#define hash_allow_cgi_request_crunching 258915987U /* "allow-cgi-request-crunching" */ +#define hash_buffer_limit 1881726070U /* "buffer-limit */ +#define hash_client_header_order 2701453514U /* "client-header-order" */ +#define hash_client_specific_tag 3353703383U /* "client-specific-tag" */ +#define hash_client_tag_lifetime 647957580U /* "client-tag-lifetime" */ +#define hash_compression_level 2464423563U /* "compression-level" */ +#define hash_confdir 1978389U /* "confdir" */ +#define hash_connection_sharing 1348841265U /* "connection-sharing" */ +#define hash_debug 78263U /* "debug" */ +#define hash_default_server_timeout 2530089913U /* "default-server-timeout" */ +#define hash_deny_access 1227333715U /* "deny-access" */ +#define hash_enable_edit_actions 2517097536U /* "enable-edit-actions" */ +#define hash_enable_compression 3943696946U /* "enable-compression" */ +#define hash_enable_proxy_authentication_forwarding 4040610791U /* enable-proxy-authentication-forwarding */ +#define hash_enable_remote_toggle 2979744683U /* "enable-remote-toggle" */ +#define hash_enable_remote_http_toggle 110543988U /* "enable-remote-http-toggle" */ +#define hash_enforce_blocks 1862427469U /* "enforce-blocks" */ +#define hash_filterfile 250887266U /* "filterfile" */ +#define hash_forward 2029845U /* "forward" */ +#define hash_forward_socks4 3963965521U /* "forward-socks4" */ +#define hash_forward_socks4a 2639958518U /* "forward-socks4a" */ +#define hash_forward_socks5 3963965522U /* "forward-socks5" */ +#define hash_forward_socks5t 2639958542U /* "forward-socks5t" */ +#define hash_forwarded_connect_retries 101465292U /* "forwarded-connect-retries" */ +#define hash_handle_as_empty_returns_ok 1444873247U /* "handle-as-empty-doc-returns-ok" */ +#define hash_hostname 10308071U /* "hostname" */ +#define hash_keep_alive_timeout 3878599515U /* "keep-alive-timeout" */ +#define hash_listen_address 1255650842U /* "listen-address" */ +#define hash_logdir 422889U /* "logdir" */ +#define hash_logfile 2114766U /* "logfile" */ +#define hash_max_client_connections 3595884446U /* "max-client-connections" */ +#define hash_permit_access 3587953268U /* "permit-access" */ +#define hash_proxy_info_url 3903079059U /* "proxy-info-url" */ +#define hash_single_threaded 4250084780U /* "single-threaded" */ +#define hash_socket_timeout 1809001761U /* "socket-timeout" */ +#define hash_split_large_cgi_forms 671658948U /* "split-large-cgi-forms" */ +#define hash_suppress_blocklists 1948693308U /* "suppress-blocklists" */ +#define hash_templdir 11067889U /* "templdir" */ +#define hash_temporary_directory 1824125181U /* "temporary-directory" */ +#define hash_tolerate_pipelining 1360286620U /* "tolerate-pipelining" */ +#define hash_toggle 447966U /* "toggle" */ +#define hash_trust_info_url 430331967U /* "trust-info-url" */ +#define hash_trust_x_forwarded_for 2971537414U /* "trust-x-forwarded-for" */ +#define hash_trustfile 56494766U /* "trustfile" */ +#define hash_usermanual 1416668518U /* "user-manual" */ +#define hash_activity_animation 1817904738U /* "activity-animation" */ +#define hash_close_button_minimizes 3651284693U /* "close-button-minimizes" */ +#define hash_hide_console 2048809870U /* "hide-console" */ +#define hash_log_buffer_size 2918070425U /* "log-buffer-size" */ +#define hash_log_font_name 2866730124U /* "log-font-name" */ +#define hash_log_font_size 2866731014U /* "log-font-size" */ +#define hash_log_highlight_messages 4032101240U /* "log-highlight-messages" */ +#define hash_log_max_lines 2868344173U /* "log-max-lines" */ +#define hash_log_messages 2291744899U /* "log-messages" */ +#define hash_show_on_task_bar 215410365U /* "show-on-task-bar" */ static void savearg(char *command, char *argument, struct configuration_spec * config); +#ifdef FEATURE_CLIENT_TAGS +static void free_client_specific_tags(struct client_tag_spec *tag_list); +#endif /********************************************************************* * @@ -213,7 +219,7 @@ static void unload_configfile (void * data) while (cur_fwd != NULL) { struct forward_spec * next_fwd = cur_fwd->next; - free_url_spec(cur_fwd->url); + free_pattern_spec(cur_fwd->url); freez(cur_fwd->gateway_host); freez(cur_fwd->forward_host); @@ -226,8 +232,14 @@ static void unload_configfile (void * data) freez(config->logdir); freez(config->templdir); freez(config->hostname); +#ifdef FEATURE_EXTERNAL_FILTERS + freez(config->temporary_directory); +#endif - freez(config->haddr); + for (i = 0; i < MAX_LISTENING_SOCKETS; i++) + { + freez(config->haddr[i]); + } freez(config->logfile); for (i = 0; i < MAX_AF_FILES; i++) @@ -238,6 +250,8 @@ static void unload_configfile (void * data) freez(config->re_filterfile[i]); } + list_remove_all(config->ordered_client_headers); + freez(config->admin_address); freez(config->proxy_info_url); freez(config->proxy_args); @@ -248,6 +262,10 @@ static void unload_configfile (void * data) list_remove_all(config->trust_info); #endif /* def FEATURE_TRUST */ +#ifdef FEATURE_CLIENT_TAGS + free_client_specific_tags(config->client_tags); +#endif + freez(config); } @@ -276,6 +294,241 @@ void unload_current_config_file(void) #endif +#ifdef FEATURE_CLIENT_TAGS +/********************************************************************* + * + * Function : register_tag + * + * Description : Registers a client-specific-tag and its description + * + * Parameters : + * 1 : config: The tag list + * 2 : name: The name of the client-specific-tag + * 3 : description: The human-readable description for the tag + * + * Returns : N/A + * + *********************************************************************/ +static void register_tag(struct client_tag_spec *tag_list, + const char *name, const char *description) +{ + struct client_tag_spec *new_tag; + struct client_tag_spec *last_tag; + + last_tag = tag_list; + while (last_tag->next != NULL) + { + last_tag = last_tag->next; + } + if (last_tag->name == NULL) + { + /* First entry */ + new_tag = last_tag; + } + else + { + new_tag = zalloc_or_die(sizeof(struct client_tag_spec)); + } + new_tag->name = strdup_or_die(name); + new_tag->description = strdup_or_die(description); + if (new_tag != last_tag) + { + last_tag->next = new_tag; + } +} + + +/********************************************************************* + * + * Function : free_client_specific_tags + * + * Description : Frees client-specific tags and their descriptions + * + * Parameters : + * 1 : tag_list: The tag list to free + * + * Returns : N/A + * + *********************************************************************/ +static void free_client_specific_tags(struct client_tag_spec *tag_list) +{ + struct client_tag_spec *this_tag; + struct client_tag_spec *next_tag; + + next_tag = tag_list; + do + { + this_tag = next_tag; + next_tag = next_tag->next; + + freez(this_tag->name); + freez(this_tag->description); + + if (this_tag != tag_list) + { + freez(this_tag); + } + } while (next_tag != NULL); +} +#endif /* def FEATURE_CLIENT_TAGS */ + + +/********************************************************************* + * + * Function : parse_numeric_value + * + * Description : Parse the value of a directive that can only have + * a single numeric value. Terminates with a fatal error + * if the value is NULL or not numeric. + * + * Parameters : + * 1 : name: The name of the directive. Used for log messages. + * 2 : value: The value to parse + * + * + * Returns : The numerical value as integer + * + *********************************************************************/ +static int parse_numeric_value(const char *name, const char *value) +{ + int number; + char *endptr; + + assert(name != NULL); + assert(value != NULL); + + if ((value == NULL) || (*value == '\0')) + { + log_error(LOG_LEVEL_FATAL, "Directive %s used without argument", name); + } + + number = (int)strtol(value, &endptr, 0); + if (*endptr != '\0') + { + log_error(LOG_LEVEL_FATAL, + "Directive '%s' used with non-numerical value: '%s'", name, value); + } + + return number; + +} + + +/********************************************************************* + * + * Function : parse_toggle_value + * + * Description : Parse the value of a directive that can only be + * enabled or disabled. Terminates with a fatal error + * if the value is NULL or something other than 0 or 1. + * + * Parameters : + * 1 : name: The name of the directive. Used for log messages. + * 2 : value: The value to parse + * + * + * Returns : The numerical toggle state + * + *********************************************************************/ +static int parse_toggle_state(const char *name, const char *value) +{ + int toggle_state; + assert(name != NULL); + assert(value != NULL); + + if ((value == NULL) || (*value == '\0')) + { + log_error(LOG_LEVEL_FATAL, "Directive %s used without argument", name); + } + + toggle_state = atoi(value); + + /* + * Also check the length as atoi() doesn't mind + * garbage after a valid integer, but we do. + */ + if (((toggle_state != 0) && (toggle_state != 1)) || (strlen(value) != 1)) + { + log_error(LOG_LEVEL_FATAL, + "Directive %s used with invalid argument '%s'. Use either '0' or '1'.", + name, value); + } + + return toggle_state; + +} + + +/********************************************************************* + * + * Function : parse_client_header_order + * + * Description : Parse the value of the header-order directive + * + * Parameters : + * 1 : ordered_header_list: List to insert the ordered + * headers into. + * 2 : ordered_headers: The ordered header names separated + * by spaces or tabs. + * + * + * Returns : N/A + * + *********************************************************************/ +static void parse_client_header_order(struct list *ordered_header_list, const char *ordered_headers) +{ + char *original_headers_copy; + char **vector; + size_t max_segments; + int number_of_headers; + int i; + + assert(ordered_header_list != NULL); + assert(ordered_headers != NULL); + + if (ordered_headers == NULL) + { + log_error(LOG_LEVEL_FATAL, "header-order used without argument"); + } + + /* + * XXX: This estimate is guaranteed to be high enough as we + * let ssplit() ignore empty fields, but also a bit wasteful. + * The same hack is used in get_last_url() so it looks like + * a real solution is needed. + */ + max_segments = strlen(ordered_headers) / 2; + if (max_segments == 0) + { + max_segments = 1; + } + vector = malloc_or_die(max_segments * sizeof(char *)); + + original_headers_copy = strdup_or_die(ordered_headers); + + number_of_headers = ssplit(original_headers_copy, "\t ", vector, max_segments); + if (number_of_headers == -1) + { + log_error(LOG_LEVEL_FATAL, "Failed to split ordered headers"); + } + + for (i = 0; i < number_of_headers; i++) + { + if (JB_ERR_OK != enlist(ordered_header_list, vector[i])) + { + log_error(LOG_LEVEL_FATAL, + "Failed to enlist ordered header: %s", vector[i]); + } + } + + freez(vector); + freez(original_headers_copy); + + return; + +} + + /********************************************************************* * * Function : load_config @@ -292,7 +545,7 @@ void unload_current_config_file(void) *********************************************************************/ struct configuration_spec * load_config(void) { - char buf[BUFFER_SIZE]; + char *buf = NULL; char *p, *q; FILE *configfp = NULL; struct configuration_spec * config = NULL; @@ -323,15 +576,7 @@ struct configuration_spec * load_config(void) global_toggle_state = 1; #endif /* def FEATURE_TOGGLE */ - fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config)); - - if (NULL == config) - { - freez(fs->filename); - freez(fs); - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); - return NULL; - } + fs->f = config = zalloc_or_die(sizeof(*config)); /* * This is backwards from how it's usually done. @@ -352,7 +597,16 @@ struct configuration_spec * load_config(void) config->usermanual = strdup(USER_MANUAL_URL); config->proxy_args = strdup(""); config->forwarded_connect_retries = 0; - config->max_client_connections = 0; +#ifdef FEATURE_CLIENT_TAGS + config->client_tag_lifetime = 60; +#endif + config->trust_x_forwarded_for = 0; + /* + * 128 client sockets ought to be enough for everybody who can't + * be bothered to read the documentation to figure out how to + * increase the limit. + */ + config->max_client_connections = 128; config->socket_timeout = 300; /* XXX: Should be a macro. */ #ifdef FEATURE_CONNECTION_KEEP_ALIVE config->default_server_timeout = 0; @@ -364,6 +618,15 @@ struct configuration_spec * load_config(void) config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS; config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS; config->feature_flags &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK; + config->feature_flags &= ~RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS; +#ifdef FEATURE_COMPRESSION + config->feature_flags &= ~RUNTIME_FEATURE_COMPRESSION; + /* + * XXX: Run some benchmarks to see if there are better default values. + */ + config->compression_level = 1; +#endif + config->feature_flags &= ~RUNTIME_FEATURE_TOLERATE_PIPELINING; configfp = fopen(configfile, "r"); if (NULL == configfp) @@ -373,7 +636,7 @@ struct configuration_spec * load_config(void) /* Never get here - LOG_LEVEL_FATAL causes program exit */ } - while (read_config_line(buf, sizeof(buf), configfp, &linenum) != NULL) + while (read_config_line(configfp, &linenum, &buf) != NULL) { char cmd[BUFFER_SIZE]; char arg[BUFFER_SIZE]; @@ -384,7 +647,7 @@ struct configuration_spec * load_config(void) struct forward_spec *cur_fwd; int vec_count; char *vec[3]; - unsigned long directive_hash; + unsigned int directive_hash; strlcpy(tmp, buf, sizeof(tmp)); @@ -404,20 +667,24 @@ struct configuration_spec * load_config(void) } /* Copy the argument into arg */ - strlcpy(arg, p, sizeof(arg)); + if (strlcpy(arg, p, sizeof(arg)) >= sizeof(arg)) + { + log_error(LOG_LEVEL_FATAL, "Config line too long: %s", buf); + } /* Should never happen, but check this anyway */ if (*cmd == '\0') { + freez(buf); continue; } /* Make sure the command field is lower case */ for (p = cmd; *p; p++) { - if (ijb_isupper(*p)) + if (privoxy_isupper(*p)) { - *p = (char)ijb_tolower(*p); + *p = (char)privoxy_tolower(*p); } } @@ -449,7 +716,7 @@ struct configuration_spec * load_config(void) * accept-intercepted-requests * *************************************************************************/ case hash_accept_intercepted_requests: - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS; } @@ -471,7 +738,7 @@ struct configuration_spec * load_config(void) * allow-cgi-request-crunching * *************************************************************************/ case hash_allow_cgi_request_crunching: - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_CGI_CRUNCHING; } @@ -485,23 +752,105 @@ struct configuration_spec * load_config(void) * buffer-limit n * *************************************************************************/ case hash_buffer_limit : - config->buffer_limit = (size_t)(1024 * atoi(arg)); + config->buffer_limit = (size_t)(1024 * parse_numeric_value(cmd, arg)); + break; + +/* ************************************************************************* + * client-header-order header-1 header-2 ... header-n + * *************************************************************************/ + case hash_client_header_order: + list_remove_all(config->ordered_client_headers); + parse_client_header_order(config->ordered_client_headers, arg); break; +/* ************************************************************************* + * client-specific-tag tag-name description + * *************************************************************************/ +#ifdef FEATURE_CLIENT_TAGS + case hash_client_specific_tag: + { + char *name; + char *description; + + name = arg; + description = strstr(arg, " "); + if (description == NULL) + { + log_error(LOG_LEVEL_FATAL, + "client-specific-tag '%s' lacks a description.", name); + } + *description = '\0'; + /* + * The length is limited because we don't want truncated + * HTML caused by the cgi interface using static buffer + * sizes. + */ + if (strlen(name) > CLIENT_TAG_LENGTH_MAX) + { + log_error(LOG_LEVEL_FATAL, + "client-specific-tag '%s' is longer than %d characters.", + name, CLIENT_TAG_LENGTH_MAX); + } + description++; + register_tag(config->client_tags, name, description); + } + break; +#endif /* def FEATURE_CLIENT_TAGS */ + +/* ************************************************************************* + * client-tag-lifetime ttl + * *************************************************************************/ +#ifdef FEATURE_CLIENT_TAGS + case hash_client_tag_lifetime: + { + int ttl = parse_numeric_value(cmd, arg); + if (0 <= ttl) + { + config->client_tag_lifetime = (unsigned)ttl; + } + else + { + log_error(LOG_LEVEL_FATAL, + "client-tag-lifetime can't be negative."); + } + break; + } +#endif /* def FEATURE_CLIENT_TAGS */ + /* ************************************************************************* * confdir directory-name * *************************************************************************/ case hash_confdir : freez(config->confdir); - config->confdir = make_path( NULL, arg); + config->confdir = make_path(NULL, arg); + break; + +/* ************************************************************************* + * compression-level 0-9 + * *************************************************************************/ +#ifdef FEATURE_COMPRESSION + case hash_compression_level : + { + int compression_level = parse_numeric_value(cmd, arg); + if (-1 <= compression_level && compression_level <= 9) + { + config->compression_level = compression_level; + } + else + { + log_error(LOG_LEVEL_FATAL, + "Invalid compression-level value: %s", arg); + } break; + } +#endif /* ************************************************************************* * connection-sharing (0|1) * *************************************************************************/ #ifdef FEATURE_CONNECTION_SHARING case hash_connection_sharing : - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_CONNECTION_SHARING; } @@ -517,7 +866,7 @@ struct configuration_spec * load_config(void) * Specifies debug level, multiple values are ORed together. * *************************************************************************/ case hash_debug : - config->debug |= atoi(arg); + config->debug |= parse_numeric_value(cmd, arg); break; /* ************************************************************************* @@ -525,20 +874,19 @@ struct configuration_spec * load_config(void) * *************************************************************************/ #ifdef FEATURE_CONNECTION_KEEP_ALIVE case hash_default_server_timeout : - if (*arg != '\0') + { + int timeout = parse_numeric_value(cmd, arg); + if (0 <= timeout) { - int timeout = atoi(arg); - if (0 < timeout) - { - config->default_server_timeout = (unsigned int)timeout; - } - else - { - log_error(LOG_LEVEL_FATAL, - "Invalid default-server-timeout value: %s", arg); - } + config->default_server_timeout = (unsigned int)timeout; + } + else + { + log_error(LOG_LEVEL_FATAL, + "Invalid default-server-timeout value: %s", arg); } break; + } #endif /* ************************************************************************* @@ -547,7 +895,7 @@ struct configuration_spec * load_config(void) #ifdef FEATURE_ACL case hash_deny_access: strlcpy(tmp, arg, sizeof(tmp)); - vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1); + vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if ((vec_count != 1) && (vec_count != 2)) { @@ -560,14 +908,7 @@ struct configuration_spec * load_config(void) } /* allocate a new node */ - cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl)); - - if (cur_acl == NULL) - { - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); - /* Never get here - LOG_LEVEL_FATAL causes program exit */ - break; - } + cur_acl = zalloc_or_die(sizeof(*cur_acl)); cur_acl->action = ACL_DENY; if (acl_addr(vec[0], cur_acl->src) < 0) @@ -628,7 +969,7 @@ struct configuration_spec * load_config(void) * *************************************************************************/ #ifdef FEATURE_CGI_EDIT_ACTIONS case hash_enable_edit_actions: - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_CGI_EDIT_ACTIONS; } @@ -639,12 +980,42 @@ struct configuration_spec * load_config(void) break; #endif /* def FEATURE_CGI_EDIT_ACTIONS */ +/* ************************************************************************* + * enable-compression 0|1 + * *************************************************************************/ +#ifdef FEATURE_COMPRESSION + case hash_enable_compression: + if (parse_toggle_state(cmd, arg) == 1) + { + config->feature_flags |= RUNTIME_FEATURE_COMPRESSION; + } + else + { + config->feature_flags &= ~RUNTIME_FEATURE_COMPRESSION; + } + break; +#endif /* def FEATURE_COMPRESSION */ + +/* ************************************************************************* + * enable-proxy-authentication-forwarding 0|1 + * *************************************************************************/ + case hash_enable_proxy_authentication_forwarding: + if (parse_toggle_state(cmd, arg) == 1) + { + config->feature_flags |= RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS; + } + else + { + config->feature_flags &= ~RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS; + } + break; + /* ************************************************************************* * enable-remote-toggle 0|1 * *************************************************************************/ #ifdef FEATURE_TOGGLE case hash_enable_remote_toggle: - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_CGI_TOGGLE; } @@ -659,7 +1030,7 @@ struct configuration_spec * load_config(void) * enable-remote-http-toggle 0|1 * *************************************************************************/ case hash_enable_remote_http_toggle: - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_HTTP_TOGGLE; } @@ -674,7 +1045,7 @@ struct configuration_spec * load_config(void) * *************************************************************************/ case hash_enforce_blocks: #ifdef FEATURE_FORCE_LOAD - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_ENFORCE_BLOCKS; } @@ -715,7 +1086,7 @@ struct configuration_spec * load_config(void) * *************************************************************************/ case hash_forward: strlcpy(tmp, arg, sizeof(tmp)); - vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1); + vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if (vec_count != 2) { @@ -728,24 +1099,18 @@ struct configuration_spec * load_config(void) } /* allocate a new node */ - cur_fwd = zalloc(sizeof(*cur_fwd)); - if (cur_fwd == NULL) - { - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); - /* Never get here - LOG_LEVEL_FATAL causes program exit */ - break; - } - + cur_fwd = zalloc_or_die(sizeof(*cur_fwd)); cur_fwd->type = SOCKS_NONE; /* Save the URL pattern */ - if (create_url_spec(cur_fwd->url, vec[0])) + if (create_pattern_spec(cur_fwd->url, vec[0])) { log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward " "directive in configuration file."); string_append(&config->proxy_args, "
\nWARNING: Bad URL specifier for " "forward directive in configuration file."); + freez(cur_fwd); break; } @@ -770,7 +1135,7 @@ struct configuration_spec * load_config(void) * *************************************************************************/ case hash_forward_socks4: strlcpy(tmp, arg, sizeof(tmp)); - vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1); + vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if (vec_count != 3) { @@ -783,24 +1148,18 @@ struct configuration_spec * load_config(void) } /* allocate a new node */ - cur_fwd = zalloc(sizeof(*cur_fwd)); - if (cur_fwd == NULL) - { - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); - /* Never get here - LOG_LEVEL_FATAL causes program exit */ - break; - } - + cur_fwd = zalloc_or_die(sizeof(*cur_fwd)); cur_fwd->type = SOCKS_4; /* Save the URL pattern */ - if (create_url_spec(cur_fwd->url, vec[0])) + if (create_pattern_spec(cur_fwd->url, vec[0])) { log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 " "directive in configuration file."); string_append(&config->proxy_args, "
\nWARNING: Bad URL specifier for " "forward-socks4 directive in configuration file."); + freez(cur_fwd); break; } @@ -836,45 +1195,52 @@ struct configuration_spec * load_config(void) * *************************************************************************/ case hash_forward_socks4a: case hash_forward_socks5: + case hash_forward_socks5t: strlcpy(tmp, arg, sizeof(tmp)); - vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1); + vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if (vec_count != 3) { - log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " - "forward-socks4a directive in configuration file."); + log_error(LOG_LEVEL_ERROR, + "Wrong number of parameters for %s in configuration file.", + cmd); string_append(&config->proxy_args, - "
\nWARNING: Wrong number of parameters for " - "forward-socks4a directive in configuration file."); + "
\nWARNING: Wrong number of parameters for "); + string_append(&config->proxy_args, cmd); + string_append(&config->proxy_args, + "directive in configuration file."); break; } /* allocate a new node */ - cur_fwd = zalloc(sizeof(*cur_fwd)); - if (cur_fwd == NULL) - { - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); - /* Never get here - LOG_LEVEL_FATAL causes program exit */ - break; - } + cur_fwd = zalloc_or_die(sizeof(*cur_fwd)); if (directive_hash == hash_forward_socks4a) { cur_fwd->type = SOCKS_4A; } - else + else if (directive_hash == hash_forward_socks5) { cur_fwd->type = SOCKS_5; } + else + { + assert(directive_hash == hash_forward_socks5t); + cur_fwd->type = SOCKS_5T; + } /* Save the URL pattern */ - if (create_url_spec(cur_fwd->url, vec[0])) + if (create_pattern_spec(cur_fwd->url, vec[0])) { - log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4a " - "directive in configuration file."); + log_error(LOG_LEVEL_ERROR, + "Bad URL specifier for %s in configuration file.", + cmd); string_append(&config->proxy_args, - "
\nWARNING: Bad URL specifier for " - "forward-socks4a directive in configuration file."); + "
\nWARNING: Bad URL specifier for "); + string_append(&config->proxy_args, cmd); + string_append(&config->proxy_args, + "directive in configuration file."); + freez(cur_fwd); break; } @@ -905,7 +1271,7 @@ struct configuration_spec * load_config(void) * forwarded-connect-retries n * *************************************************************************/ case hash_forwarded_connect_retries : - config->forwarded_connect_retries = atoi(arg); + config->forwarded_connect_retries = parse_numeric_value(cmd, arg); break; /* ************************************************************************* @@ -918,7 +1284,7 @@ struct configuration_spec * load_config(void) * to the browser for blocked pages. ***************************************************************************/ case hash_handle_as_empty_returns_ok: - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK; } @@ -945,28 +1311,42 @@ struct configuration_spec * load_config(void) * *************************************************************************/ #ifdef FEATURE_CONNECTION_KEEP_ALIVE case hash_keep_alive_timeout : - if (*arg != '\0') + { + int timeout = parse_numeric_value(cmd, arg); + if (0 < timeout) { - int timeout = atoi(arg); - if (0 < timeout) - { - config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; - config->keep_alive_timeout = (unsigned int)timeout; - } - else - { - config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; - } + config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; + config->keep_alive_timeout = (unsigned int)timeout; + } + else + { + config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; } break; + } #endif /* ************************************************************************* * listen-address [ip][:port] * *************************************************************************/ case hash_listen_address : - freez(config->haddr); - config->haddr = strdup(arg); + i = 0; + while ((i < MAX_LISTENING_SOCKETS) && (NULL != config->haddr[i])) + { + i++; + } + + if (i >= MAX_LISTENING_SOCKETS) + { + log_error(LOG_LEVEL_FATAL, "Too many 'listen-address' directives in config file - limit is %d.\n" + "(You can increase this limit by changing MAX_LISTENING_SOCKETS in project.h and recompiling).", + MAX_LISTENING_SOCKETS); + } + config->haddr[i] = strdup(arg); + if (NULL == config->haddr[i]) + { + log_error(LOG_LEVEL_FATAL, "Out of memory while copying listening address"); + } break; /* ************************************************************************* @@ -996,15 +1376,46 @@ struct configuration_spec * load_config(void) * max-client-connections number * *************************************************************************/ case hash_max_client_connections : - if (*arg != '\0') + { + int max_client_connections = parse_numeric_value(cmd, arg); + +#ifndef _WIN32 + /* + * Reject values below 1 for obvious reasons and values above + * FD_SETSIZE/2 because Privoxy needs two sockets to serve + * client connections that need forwarding. + * + * We ignore the fact that the first three file descriptors + * are usually set to /dev/null, one is used for logging + * and yet another file descriptor is required to load + * config files. + */ + if ((max_client_connections < 1) || (FD_SETSIZE/2 < max_client_connections)) { - int max_client_connections = atoi(arg); - if (0 <= max_client_connections) - { - config->max_client_connections = max_client_connections; - } + log_error(LOG_LEVEL_FATAL, "max-client-connections value %d" + " is invalid. Value needs to be above 1 and below %d" + " (FD_SETSIZE/2).", max_client_connections, FD_SETSIZE/2); + } +#else + /* + * The Windows libc uses FD_SETSIZE for an array used + * by select(), but has no problems with file descriptors + * above the limit as long as no more than FD_SETSIZE are + * passed to select(). + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms739169%28v=vs.85%29.aspx + * + * XXX: Do OS/2, Amiga etc. belong here as well? + */ + if (max_client_connections < 1) + { + log_error(LOG_LEVEL_FATAL, "max-client-connections value" + " has to be a number above 1. %d is invalid.", + max_client_connections); } +#endif + config->max_client_connections = max_client_connections; break; + } /* ************************************************************************* * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]] @@ -1012,7 +1423,7 @@ struct configuration_spec * load_config(void) #ifdef FEATURE_ACL case hash_permit_access: strlcpy(tmp, arg, sizeof(tmp)); - vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1); + vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if ((vec_count != 1) && (vec_count != 2)) { @@ -1026,14 +1437,7 @@ struct configuration_spec * load_config(void) } /* allocate a new node */ - cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl)); - - if (cur_acl == NULL) - { - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); - /* Never get here - LOG_LEVEL_FATAL causes program exit */ - break; - } + cur_acl = zalloc_or_die(sizeof(*cur_acl)); cur_acl->action = ACL_PERMIT; if (acl_addr(vec[0], cur_acl->src) < 0) @@ -1098,36 +1502,34 @@ struct configuration_spec * load_config(void) break; /* ************************************************************************* - * single-threaded + * single-threaded 0|1 * *************************************************************************/ case hash_single_threaded : - config->multi_threaded = 0; + config->multi_threaded = 0 == parse_toggle_state(cmd, arg); break; /* ************************************************************************* * socket-timeout numer_of_seconds * *************************************************************************/ case hash_socket_timeout : - if (*arg != '\0') + { + int socket_timeout = parse_numeric_value(cmd, arg); + if (0 <= socket_timeout) { - int socket_timeout = atoi(arg); - if (0 < socket_timeout) - { - config->socket_timeout = socket_timeout; - } - else - { - log_error(LOG_LEVEL_FATAL, - "Invalid socket-timeout: '%s'", arg); - } + config->socket_timeout = socket_timeout; + } + else + { + log_error(LOG_LEVEL_FATAL, "Invalid socket-timeout: '%s'", arg); } break; + } /* ************************************************************************* * split-large-cgi-forms * *************************************************************************/ case hash_split_large_cgi_forms : - if ((*arg != '\0') && (0 != atoi(arg))) + if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_SPLIT_LARGE_FORMS; } @@ -1145,12 +1547,36 @@ struct configuration_spec * load_config(void) config->templdir = make_path(NULL, arg); break; +#ifdef FEATURE_EXTERNAL_FILTERS +/* ************************************************************************* + * temporary-directory directory-name + * *************************************************************************/ + case hash_temporary_directory : + freez(config->temporary_directory); + config->temporary_directory = make_path(NULL, arg); + break; +#endif + +/* ************************************************************************* + * tolerate-pipelining (0|1) + * *************************************************************************/ + case hash_tolerate_pipelining : + if (parse_toggle_state(cmd, arg) == 1) + { + config->feature_flags |= RUNTIME_FEATURE_TOLERATE_PIPELINING; + } + else + { + config->feature_flags &= ~RUNTIME_FEATURE_TOLERATE_PIPELINING; + } + break; + /* ************************************************************************* * toggle (0|1) * *************************************************************************/ #ifdef FEATURE_TOGGLE case hash_toggle : - global_toggle_state = atoi(arg); + global_toggle_state = parse_toggle_state(cmd, arg); break; #endif /* def FEATURE_TOGGLE */ @@ -1163,6 +1589,13 @@ struct configuration_spec * load_config(void) break; #endif /* def FEATURE_TRUST */ +/* ************************************************************************* + * trust-x-forwarded-for (0|1) + * *************************************************************************/ + case hash_trust_x_forwarded_for : + config->trust_x_forwarded_for = parse_toggle_state(cmd, arg); + break; + /* ************************************************************************* * trustfile filename * (In confdir by default.) @@ -1210,21 +1643,21 @@ struct configuration_spec * load_config(void) * activity-animation (0|1) * *************************************************************************/ case hash_activity_animation : - g_bShowActivityAnimation = atoi(arg); + g_bShowActivityAnimation = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * close-button-minimizes (0|1) * *************************************************************************/ case hash_close_button_minimizes : - g_bCloseHidesWindow = atoi(arg); + g_bCloseHidesWindow = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * log-buffer-size (0|1) * *************************************************************************/ case hash_log_buffer_size : - g_bLimitBufferSize = atoi(arg); + g_bLimitBufferSize = parse_toggle_state(cmd, arg); break; /* ************************************************************************* @@ -1244,35 +1677,35 @@ struct configuration_spec * load_config(void) * log-font-size n * *************************************************************************/ case hash_log_font_size : - g_nFontSize = atoi(arg); + g_nFontSize = parse_numeric_value(cmd, arg); break; /* ************************************************************************* * log-highlight-messages (0|1) * *************************************************************************/ case hash_log_highlight_messages : - g_bHighlightMessages = atoi(arg); + g_bHighlightMessages = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * log-max-lines n * *************************************************************************/ case hash_log_max_lines : - g_nMaxBufferLines = atoi(arg); + g_nMaxBufferLines = parse_numeric_value(cmd, arg); break; /* ************************************************************************* * log-messages (0|1) * *************************************************************************/ case hash_log_messages : - g_bLogMessages = atoi(arg); + g_bLogMessages = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * show-on-task-bar (0|1) * *************************************************************************/ case hash_show_on_task_bar : - g_bShowOnTaskBar = atoi(arg); + g_bShowOnTaskBar = parse_toggle_state(cmd, arg); break; #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */ @@ -1328,19 +1761,20 @@ struct configuration_spec * load_config(void) * error. To change back to an error, just change log level * to LOG_LEVEL_FATAL. */ - log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive '%s' (%luul) in line %lu " - "in configuration file (%s).", buf, directive_hash, linenum, configfile); + log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive " + "'%s' (%uU) in line %lu in configuration file (%s).", + buf, directive_hash, linenum, configfile); string_append(&config->proxy_args, " Warning: Ignoring unrecognized directive:"); break; /* *************************************************************************/ - } /* end switch( hash_string(cmd) ) */ + } /* end switch(hash_string(cmd)) */ /* Save the argument for the show-status page. */ savearg(cmd, arg, config); - - } /* end while ( read_config_line(...) ) */ + freez(buf); + } /* end while (read_config_line(...)) */ fclose(configfp); @@ -1406,14 +1840,14 @@ struct configuration_spec * load_config(void) log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args"); } - if (config->actions_file[0]) + if (config->re_filterfile[0]) { - add_loader(load_action_files, config); + add_loader(load_re_filterfiles, config); } - if (config->re_filterfile[0]) + if (config->actions_file[0]) { - add_loader(load_re_filterfiles, config); + add_loader(load_action_files, config); } #ifdef FEATURE_TRUST @@ -1423,39 +1857,45 @@ struct configuration_spec * load_config(void) } #endif /* def FEATURE_TRUST */ - if ( NULL == config->haddr ) + if (NULL == config->haddr[0]) { - config->haddr = strdup( HADDR_DEFAULT ); + config->haddr[0] = strdup(HADDR_DEFAULT); + if (NULL == config->haddr[0]) + { + log_error(LOG_LEVEL_FATAL, "Out of memory while copying default listening address"); + } } - if ( NULL != config->haddr ) + for (i = 0; i < MAX_LISTENING_SOCKETS && NULL != config->haddr[i]; i++) { - if ((*config->haddr == '[') - && (NULL != (p = strchr(config->haddr, ']'))) + if ((*config->haddr[i] == '[') + && (NULL != (p = strchr(config->haddr[i], ']'))) && (p[1] == ':') - && (0 < (config->hport = atoi(p + 2)))) + && (0 < (config->hport[i] = atoi(p + 2)))) { *p = '\0'; - memmove((void *)config->haddr, config->haddr + 1, - (size_t)(p - config->haddr)); + memmove((void *)config->haddr[i], config->haddr[i] + 1, + (size_t)(p - config->haddr[i])); } - else if (NULL != (p = strchr(config->haddr, ':')) - && (0 < (config->hport = atoi(p + 1)))) + else if (NULL != (p = strchr(config->haddr[i], ':')) + && (0 < (config->hport[i] = atoi(p + 1)))) { *p = '\0'; } else { - log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr); + log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr[i]); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } - if (*config->haddr == '\0') + if (*config->haddr[i] == '\0') { /* - * Only the port specified. We stored it in config->hport + * Only the port specified. We stored it in config->hport[i] * and don't need its text representation anymore. + * Use config->hport[i] == 0 to iterate listening addresses since + * now. */ - freez(config->haddr); + freez(config->haddr[i]); } } @@ -1464,7 +1904,7 @@ struct configuration_spec * load_config(void) * * Need to set up a fake csp, so they can get to the config. */ - fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp)); + fake_csp = zalloc_or_die(sizeof(*fake_csp)); fake_csp->config = config; if (run_loader(fake_csp)) @@ -1479,8 +1919,9 @@ struct configuration_spec * load_config(void) #if defined(_WIN32) && !defined (_WIN_CONSOLE) g_default_actions_file = config->actions_file[1]; /* FIXME Hope this is default.action */ - g_user_actions_file = config->actions_file[2]; /* FIXME Hope this is user.action */ - g_re_filterfile = config->re_filterfile[0]; /* FIXME Hope this is default.filter */ + g_user_actions_file = config->actions_file[2]; /* FIXME Hope this is user.action */ + g_default_filterfile = config->re_filterfile[0]; /* FIXME Hope this is default.filter */ + g_user_filterfile = config->re_filterfile[1]; /* FIXME Hope this is user.filter */ #ifdef FEATURE_TRUST g_trustfile = config->trustfile; @@ -1498,30 +1939,34 @@ struct configuration_spec * load_config(void) struct configuration_spec * oldcfg = (struct configuration_spec *) current_configfile->f; /* - * Check if config->haddr,hport == oldcfg->haddr,hport + * Check if config->haddr[i],hport[i] == oldcfg->haddr[i],hport[i] * * The following could be written more compactly as a single, * (unreadably long) if statement. */ config->need_bind = 0; - if (config->hport != oldcfg->hport) - { - config->need_bind = 1; - } - else if (config->haddr == NULL) + + for (i = 0; i < MAX_LISTENING_SOCKETS; i++) { - if (oldcfg->haddr != NULL) + if (config->hport[i] != oldcfg->hport[i]) + { + config->need_bind = 1; + } + else if (config->haddr[i] == NULL) + { + if (oldcfg->haddr[i] != NULL) + { + config->need_bind = 1; + } + } + else if (oldcfg->haddr[i] == NULL) + { + config->need_bind = 1; + } + else if (0 != strcmp(config->haddr[i], oldcfg->haddr[i])) { config->need_bind = 1; } - } - else if (oldcfg->haddr == NULL) - { - config->need_bind = 1; - } - else if (0 != strcmp(config->haddr, oldcfg->haddr)) - { - config->need_bind = 1; } current_configfile->unloader = unload_configfile; @@ -1588,7 +2033,7 @@ static void savearg(char *command, char *argument, struct configuration_spec * c return; } - if ( (NULL != argument) && ('\0' != *argument) ) + if ((NULL != argument) && ('\0' != *argument)) { s = html_encode(argument); if (NULL == s)