X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=loadcfg.c;h=e8cdffee19e217f218ba2b4aaff6336263006899;hp=c0417aee72dde279224aaf79b78cff383d75dd48;hb=777f23fd554b0811d16bc2323ced6fe9dc0cff72;hpb=d68b67d85e08f5cb0d5d915c38aa6a5481e10219 diff --git a/loadcfg.c b/loadcfg.c index c0417aee..e8cdffee 100644 --- a/loadcfg.c +++ b/loadcfg.c @@ -1,4 +1,4 @@ -const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.104 2009/07/19 10:07:46 fabiankeil Exp $"; +const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.144 2015/12/27 12:50:42 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loadcfg.c,v $ @@ -8,7 +8,7 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.104 2009/07/19 10:07:46 fabiankei * 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.104 2009/07/19 10:07:46 fabiankei #endif +#include "project.h" #include "loadcfg.h" #include "list.h" #include "jcc.h" @@ -87,17 +88,6 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.104 2009/07/19 10:07:46 fabiankei 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; @@ -111,7 +101,7 @@ const char *configfile = NULL; * so we will make argc and argv global. */ int Argc = 0; -const char **Argv = NULL; +char * const * Argv = NULL; static struct file_list *current_configfile = NULL; @@ -128,52 +118,61 @@ 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_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_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_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_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); @@ -211,7 +210,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); @@ -224,8 +223,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++) @@ -236,6 +241,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); @@ -246,11 +253,6 @@ static void unload_configfile (void * data) list_remove_all(config->trust_info); #endif /* def FEATURE_TRUST */ - for (i = 0; i < MAX_AF_FILES; i++) - { - freez(config->re_filterfile[i]); - } - freez(config); } @@ -279,6 +281,162 @@ void unload_current_config_file(void) #endif +/********************************************************************* + * + * 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 @@ -295,7 +453,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; @@ -355,9 +513,15 @@ 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; + /* + * 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; config->keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT; config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING; @@ -365,6 +529,16 @@ struct configuration_spec * load_config(void) config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE; 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) @@ -374,7 +548,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]; @@ -385,7 +559,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)); @@ -405,20 +579,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); } } @@ -450,7 +628,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; } @@ -472,7 +650,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; } @@ -486,7 +664,15 @@ 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; /* ************************************************************************* @@ -494,15 +680,35 @@ struct configuration_spec * load_config(void) * *************************************************************************/ 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; } @@ -518,16 +724,36 @@ 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; +/* ************************************************************************* + * default-server-timeout timeout + * *************************************************************************/ +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + case hash_default_server_timeout : + { + int timeout = parse_numeric_value(cmd, arg); + if (0 <= timeout) + { + config->default_server_timeout = (unsigned int)timeout; + } + else + { + log_error(LOG_LEVEL_FATAL, + "Invalid default-server-timeout value: %s", arg); + } + break; + } +#endif + /* ************************************************************************* * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]] * *************************************************************************/ #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)) { @@ -608,7 +834,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; } @@ -619,12 +845,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; } @@ -639,7 +895,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; } @@ -654,7 +910,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; } @@ -695,7 +951,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) { @@ -719,13 +975,14 @@ struct configuration_spec * load_config(void) 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; } @@ -750,7 +1007,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) { @@ -774,13 +1031,14 @@ struct configuration_spec * load_config(void) 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; } @@ -816,16 +1074,20 @@ 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; } @@ -842,19 +1104,28 @@ struct configuration_spec * load_config(void) { 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; } @@ -885,7 +1156,27 @@ 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; + +/* ************************************************************************* + * handle-as-empty-doc-returns-ok 0|1 + * + * Workaround for firefox hanging on blocked javascript pages. + * Block with the "+handle-as-empty-document" flag and set the + * "handle-as-empty-doc-returns-ok" run-time config flag so that + * Privoxy returns a 200/OK status instead of a 403/Forbidden status + * to the browser for blocked pages. + ***************************************************************************/ + case hash_handle_as_empty_returns_ok: + if (parse_toggle_state(cmd, arg) == 1) + { + config->feature_flags |= RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK; + } + else + { + config->feature_flags &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK; + } break; /* ************************************************************************* @@ -905,28 +1196,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; /* ************************************************************************* @@ -942,7 +1247,7 @@ struct configuration_spec * load_config(void) * In logdir by default * *************************************************************************/ case hash_logfile : - if (!no_daemon) + if (daemon_mode) { logfile = make_path(config->logdir, arg); if (NULL == logfile) @@ -956,15 +1261,15 @@ 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); + if (0 <= max_client_connections) { - int max_client_connections = atoi(arg); - if (0 <= max_client_connections) - { - config->max_client_connections = max_client_connections; - } + /* XXX: log error */ + config->max_client_connections = max_client_connections; } break; + } /* ************************************************************************* * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]] @@ -972,7 +1277,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)) { @@ -1058,36 +1363,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; } @@ -1105,12 +1408,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 */ @@ -1170,21 +1497,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; /* ************************************************************************* @@ -1204,35 +1531,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) */ @@ -1288,19 +1615,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); @@ -1308,7 +1636,7 @@ struct configuration_spec * load_config(void) freez(config->logfile); - if (!no_daemon) + if (daemon_mode) { if (NULL != logfile) { @@ -1321,6 +1649,16 @@ struct configuration_spec * load_config(void) } } +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + if (config->default_server_timeout > config->keep_alive_timeout) + { + log_error(LOG_LEVEL_ERROR, + "Reducing the default-server-timeout from %d to the keep-alive-timeout %d.", + config->default_server_timeout, config->keep_alive_timeout); + config->default_server_timeout = config->keep_alive_timeout; + } +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + #ifdef FEATURE_CONNECTION_SHARING if (config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) { @@ -1356,14 +1694,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 @@ -1373,39 +1711,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]); } } @@ -1429,8 +1773,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; @@ -1448,30 +1793,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; @@ -1538,7 +1887,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)