=== modified file 'compat/xstrto.cc' --- compat/xstrto.cc 2012-10-04 11:10:17 +0000 +++ compat/xstrto.cc 2013-01-04 18:08:03 +0000 @@ -59,8 +59,14 @@ char *my_end; errno = 0; - v = strtoul(s, &my_end, 0); - + + long l = strtol(s, &my_end, 0); + + v = l; + + if (l < 0) + return false; + if (my_end == s) return false; if (end != NULL) @@ -85,8 +91,14 @@ bool ret; ret = xstrtoul(s, end, &v, min, max); + if (value != NULL) *value = v; + + if(v != (unsigned long) *value) { + return false; + } + return ret; } === modified file 'src/HelperChildConfig.cc' --- src/HelperChildConfig.cc 2012-08-31 16:57:39 +0000 +++ src/HelperChildConfig.cc 2013-01-04 21:19:42 +0000 @@ -3,6 +3,7 @@ #include "Debug.h" #include "HelperChildConfig.h" #include "globals.h" +#include "Parsing.h" #include @@ -49,24 +50,27 @@ self_destruct(); /* starts with a bare number for the max... back-compatible */ - n_max = atoi(token); + n_max = xatoui(token); - if (n_max < 1) + if (n_max < 1) { + debugs(0, DBG_CRITICAL, "ERROR: The maximum number of processes cannot be less than 1."); self_destruct(); + } /* Parse extension options */ for (; (token = strtok(NULL, w_space)) ;) { if (strncmp(token, "startup=", 8) == 0) { - n_startup = atoi(token + 8); + n_startup = xatoui(token + 8); } else if (strncmp(token, "idle=", 5) == 0) { - n_idle = atoi(token + 5); + n_idle = xatoui(token + 5); if (n_idle < 1) { debugs(0, DBG_CRITICAL, "WARNING OVERIDE: Using idle=0 for helpers causes request failures. Overiding to use idle=1 instead."); n_idle = 1; } } else if (strncmp(token, "concurrency=", 12) == 0) { - concurrency = atoi(token + 12); + concurrency = xatoui(token + 12); } else { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Undefined option: " << token << "."); self_destruct(); } } === modified file 'src/Parsing.cc' --- src/Parsing.cc 2012-12-29 02:52:50 +0000 +++ src/Parsing.cc 2013-01-04 19:29:08 +0000 @@ -34,6 +34,8 @@ #include "cache_cf.h" #include "compat/strtoll.h" #include "Parsing.h" +#include "globals.h" +#include "Debug.h" /* * These functions is the same as atoi/l/f, except that they check for errors @@ -45,8 +47,15 @@ char *end; double ret = strtod(token, &end); - if (ret == 0 && end == token) - self_destruct(); + if (ret == 0 && end == token) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: No digits were found in the input value '" << token << "'."); + self_destruct(); + } + + if (*end) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The input value '" << token << "' contains unexpected characters."); + self_destruct(); + } return ret; } @@ -54,19 +63,66 @@ int xatoi(const char *token) { - return xatol(token); + long long input; + int ret; + + input = xatoll(token, 10); + ret = (int) input; + + if (input != (long long) ret) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' is larger than the type 'int'."); + self_destruct(); + } + + return ret; +} + +unsigned int +xatoui(const char *token) +{ + int ret = xatoi(token); + if(ret < 0) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The input value '" << token << "' cannot be less than 0."); + self_destruct(); + } + + return ret; } long xatol(const char *token) { + long long input; + long ret; + + input = xatoll(token, 10); + ret = (long) input; + + if (input != (long long) ret) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The input value '" << token << "' is larger than the type 'long'."); + self_destruct(); + } + + return ret; +} + +long long +xatoll(const char *token, int base) +{ char *end; - long ret = strtol(token, &end, 10); - - if (end == token || *end) - self_destruct(); - - return ret; + long long ret = strtoll(token, &end, base); + + if (end == token) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: No digits were found in the input value '" << token << "'."); + self_destruct(); + } + + if (*end) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The input value '" << token << "'contains unexpected characters."); + self_destruct(); + } + + return ret; } unsigned short @@ -74,8 +130,15 @@ { long port = xatol(token); - if (port & ~0xFFFF) - self_destruct(); + if(port < 0) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "'cannot be less than 0."); + self_destruct(); + } + + if (port & ~0xFFFF) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "'is larger than the type 'short'."); + self_destruct(); + } return port; } @@ -84,32 +147,77 @@ GetInteger64(void) { char *token = strtok(NULL, w_space); - int64_t i; + int64_t ret; + long long input; if (token == NULL) self_destruct(); - i = strtoll(token, NULL, 10); - - return i; + input = xatoll(token, 10); + ret = (int64_t) input; + + if (input != (long long) ret) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' is larger than the type 'int64_t'."); + self_destruct(); + } + + return ret; } +/* + * This function is different from others (e.g., GetInteger64, GetShort) + * because it supports octal and hexadecimal numbers + */ int GetInteger(void) { char *token = strtok(NULL, w_space); int i; - + + long long ret; + if (token == NULL) self_destruct(); - // %i honors 0 and 0x prefixes, which are important for things like umask - if (sscanf(token, "%i", &i) != 1) + ret = xatoll(token, 0); + + i = (int) ret; + if(ret != (long long) i) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' is larger than the type 'int'."); self_destruct(); - + } + return i; } +/* + * This function is similar as GetInteger() but the token might contain + * the percentage symbol (%) and we check whether the value is in the range + * of [0, 100] + * So, we accept two types of input: 1. XX% or 2. XX , 0<=XX<=100 + */ +int +GetPercentage(void) +{ + int p; + char *token = strtok(NULL, w_space); + + //if there is a % in the end of the digits, we remove it and go on. + char* end = &token[strlen(token)-1]; + if(*end == '%') { + *end = '\0'; + } + + p = xatoi(token); + + if(p < 0 || p > 100) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' is out of range -- a percentage should be within [0, 100]."); + self_destruct(); + } + + return p; +} + unsigned short GetShort(void) { @@ -193,6 +301,8 @@ return false; } else if ((port = strtol(token, &tmp, 10)), !*tmp) { /* port */ + port = xatos(token); + } else { host = token; port = 0; === modified file 'src/Parsing.h' --- src/Parsing.h 2012-09-21 14:57:30 +0000 +++ src/Parsing.h 2013-01-04 19:33:12 +0000 @@ -38,7 +38,9 @@ double xatof(const char *token); int xatoi(const char *token); +unsigned int xatoui(const char *token); long xatol(const char *token); +long long xatoll(const char *token, int base); unsigned short xatos(const char *token); /** @@ -52,6 +54,11 @@ */ int GetInteger(void); +/** + * Parse a percentage value, e.g., 20% + */ +int GetPercentage(void); + unsigned short GetShort(void); // on success, returns true and sets *p (if any) to the end of the integer === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2012-12-27 18:15:38 +0000 +++ src/cache_cf.cc 2013-01-04 21:29:00 +0000 @@ -1017,6 +1017,13 @@ self_destruct(); *tptr = static_cast(m * d); + + if (static_cast(*tptr) * 2 != m * d * 2) { + debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" << + d << " " << token << ": integer overflow (time_msec_t)."); + self_destruct(); + } + } static uint64_t @@ -1097,8 +1104,11 @@ *bptr = static_cast(m * d / u); - if (static_cast(*bptr) * 2 != m * d / u * 2) + if (static_cast(*bptr) * 2 != m * d / u * 2) { + debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" << + d << " " << token << ": integer overflow (int64_t)."); self_destruct(); + } } static void @@ -1141,8 +1151,11 @@ *bptr = static_cast(m * d / u); - if (static_cast(*bptr) * 2 != m * d / u * 2) + if (static_cast(*bptr) * 2 != m * d / u * 2) { + debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" << + d << " " << token << ": integer overflow (size_t)."); self_destruct(); + } } #if !USE_DNSHELPER @@ -1184,10 +1197,13 @@ return; } - *bptr = static_cast(m * d / u); + *bptr = static_cast(m * d / u); - if (static_cast(*bptr) * 2 != m * d / u * 2) + if (static_cast(*bptr) * 2 != m * d / u * 2) { + debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" << + d << " " << token << ": integer overflow (ssize_t)."); self_destruct(); + } } #endif @@ -2266,7 +2282,7 @@ safe_free(p->sslkey); p->sslkey = xstrdup(token + 7); } else if (strncmp(token, "sslversion=", 11) == 0) { - p->sslversion = atoi(token + 11); + p->sslversion = xatoi(token + 11); } else if (strncmp(token, "ssloptions=", 11) == 0) { safe_free(p->ssloptions); p->ssloptions = xstrdup(token + 11); @@ -2597,10 +2613,20 @@ if (token == NULL) self_destruct(); - if (!strcasecmp(token, "on") || !strcasecmp(token, "enable")) - *var = 1; - else - *var = 0; + if (!strcasecmp(token, "on")) { + *var = 1; + } else if (!strcasecmp(token, "enable")) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' and 'disable' will be deprecated in future releases. Please update to use value 'on' and 'off'."); + *var = 1; + } else if (!strcasecmp(token, "off")) { + *var = 0; + } else if (!strcasecmp(token, "disable")) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' and 'disable' will be deprecated in future releases. Please update to use value 'on' and 'off'."); + *var = 0; + } else { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Boolean options can only be 'on' or 'off'."); + self_destruct(); + } } #define free_onoff free_int @@ -2628,12 +2654,22 @@ if (token == NULL) self_destruct(); - if (!strcasecmp(token, "on") || !strcasecmp(token, "enable")) - *var = 1; - else if (!strcasecmp(token, "warn")) + if (!strcasecmp(token, "on")) { + *var = 1; + } else if (!strcasecmp(token, "enable")) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' and 'disable' will be deprecated in future releases. Please update to use value 'on' and 'off'."); + *var = 1; + } else if (!strcasecmp(token, "warn")) { *var = -1; - else - *var = 0; + } else if (!strcasecmp(token, "off")) { + *var = 0; + } else if (!strcasecmp(token, "disable")) { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' and 'disable' will be deprecated in future releases. Please update to use value 'on' and 'off'."); + *var = 0; + } else { + debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Tristate options can only be 'on', 'off', or 'warn'."); + self_destruct(); + } } #define free_tristate free_int @@ -2757,7 +2793,7 @@ min = (time_t) (i * 60); /* convert minutes to seconds */ - i = GetInteger(); /* token: pct */ + i = GetPercentage(); /* token: pct */ pct = (double) i / 100.0; @@ -2782,7 +2818,7 @@ } else if (!strcmp(token, "store-stale")) { store_stale = 1; } else if (!strncmp(token, "max-stale=", 10)) { - max_stale = atoi(token + 10); + max_stale = xatoi(token + 10); #if USE_HTTP_VIOLATIONS } else if (!strcmp(token, "override-expire")) @@ -3223,8 +3259,10 @@ *var = URI_WHITESPACE_ENCODE; else if (!strcasecmp(token, "chop")) *var = URI_WHITESPACE_CHOP; - else + else { + debugs(0, DBG_PARSE_NOTE(2), "ERROR: Invalid option '" << token << "': 'uri_whitespace' accepts 'strip', 'deny', 'allow', 'encode', and 'chop'."); self_destruct(); + } } static void @@ -3334,9 +3372,11 @@ Config.onoff.memory_cache_disk = 0; } else if (strcmp(token, "never") == 0) { Config.onoff.memory_cache_first = 0; - Config.onoff.memory_cache_disk = 0; - } else + Config.onoff.memory_cache_disk = 0; + } else { + debugs(0, DBG_PARSE_NOTE(2), "ERROR: Invalid option '" << token << "': 'memory_cache_mode' accepts 'always', 'disk', 'network', and 'never'."); self_destruct(); + } } static void @@ -3475,6 +3515,7 @@ } else if ((port = strtol(token, &junk, 10)), !*junk) { /* port */ + port = xatos(token); debugs(3, 3, s->protocol << "_port: found Listen on Port: " << port); } else { debugs(3, DBG_CRITICAL, s->protocol << "_port: missing Port: " << token); @@ -3639,16 +3680,16 @@ } else if (strncmp(token, "tcpkeepalive=", 13) == 0) { char *t = token + 13; s->tcp_keepalive.enabled = 1; - s->tcp_keepalive.idle = atoi(t); + s->tcp_keepalive.idle = xatoui(t); t = strchr(t, ','); if (t) { ++t; - s->tcp_keepalive.interval = atoi(t); + s->tcp_keepalive.interval = xatoui(t); t = strchr(t, ','); } if (t) { ++t; - s->tcp_keepalive.timeout = atoi(t); + s->tcp_keepalive.timeout = xatoui(t); // t = strchr(t, ','); // not really needed, left in as documentation } #if USE_SSL @@ -3705,6 +3746,7 @@ parseBytesOptionValue(&s->dynamicCertMemCacheSize, B_BYTES_STR, token + 28); #endif } else { + debugs(0, DBG_PARSE_NOTE(2), "ERROR: Undefined option: " << token << "."); self_destruct(); } } === modified file 'src/wccp2.cc' --- src/wccp2.cc 2012-12-23 18:43:09 +0000 +++ src/wccp2.cc 2013-01-04 22:05:47 +0000 @@ -2249,7 +2249,7 @@ { int i = 0; int p; - char *tmp, *tmp2, *port, *end; + char *tmp, *tmp2, *port; if (!options) { return; @@ -2261,7 +2261,7 @@ port = strsep(&tmp2, ","); while (port && i < WCCP2_NUMPORTS) { - p = strtol(port, &end, 0); + p = xatoi(port); if (p < 1 || p > 65535) { fatalf("parse_wccp2_service_ports: port value '%s' isn't valid (1..65535)\n", port);