File squid-2.7.x-bnc796999-bnc794954-CVE-2012-5643-CVE-2013-0188-cachemgr_cgi_dos.diff of Package squid
diff -prNU 30 ../squid-2.7.STABLE5-o/tools/cachemgr.c ./tools/cachemgr.c
--- ../squid-2.7.STABLE5-o/tools/cachemgr.c 2008-06-25 00:55:11.000000000 +0200
+++ ./tools/cachemgr.c 2013-02-06 18:06:02.000000000 +0100
@@ -482,66 +482,69 @@ munge_other_line(const char *buf, cachem
const char *cell = xstrtok(&x, '\t');
while (x && *x == '\t') {
column_span++;
x++;
}
l += snprintf(html + l, sizeof(html) - l, "<%s colspan=\"%d\" align=\"%s\">%s</%s>",
ttag, column_span,
is_header ? "center" : is_number(cell) ? "right" : "left",
html_quote(cell), ttag);
}
xfree(buf_copy);
/* record ends */
l += snprintf(html + l, sizeof(html) - l, "</tr>\n");
next_is_header = is_header && strstr(buf, "\t\t");
table_line_num++;
return html;
}
static const char *
munge_action_line(const char *_buf, cachemgr_request * req)
{
static char html[2 * 1024];
char *buf = xstrdup(_buf);
char *x = buf;
const char *action, *description;
char *p;
if ((p = strchr(x, '\n')))
*p = '\0';
action = xstrtok(&x, '\t');
+ if (!action) {
+ xfree(buf);
+ return "";
+ }
description = xstrtok(&x, '\t');
if (!description)
description = action;
- if (!action)
- return "";
snprintf(html, sizeof(html), " <a href=\"%s\">%s</a>", menu_url(req, action), description);
+ xfree(buf);
return html;
}
static int
read_reply(int s, cachemgr_request * req)
{
char buf[4 * 1024];
#ifdef _SQUID_MSWIN_
int reply;
char *tmpfile = tempnam(NULL, "tmp0000");
FILE *fp = fopen(tmpfile, "w+");
#else
FILE *fp = fdopen(s, "r");
#endif
/* interpretation states */
enum {
isStatusLine, isHeaders, isActions, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError
} istate = isStatusLine;
int parse_menu = 0;
const char *action = req->action;
const char *statusStr = NULL;
int status = -1;
if (0 == strlen(req->action))
parse_menu = 1;
else if (0 == strcasecmp(req->action, "menu"))
parse_menu = 1;
if (fp == NULL) {
#ifdef _SQUID_MSWIN_
perror(tmpfile);
xfree(tmpfile);
@@ -663,147 +666,176 @@ read_reply(int s, cachemgr_request * req
#endif
return 0;
}
static int
process_request(cachemgr_request * req)
{
const struct hostent *hp;
static struct sockaddr_in S;
int s;
int l;
static char buf[2 * 1024];
if (req == NULL) {
auth_html(CACHEMGR_HOSTNAME, CACHE_HTTP_PORT, "");
return 1;
}
if (req->hostname == NULL) {
req->hostname = xstrdup(CACHEMGR_HOSTNAME);
}
if (req->port == 0) {
req->port = CACHE_HTTP_PORT;
}
if (req->action == NULL) {
req->action = xstrdup("");
}
if (strcmp(req->action, "authenticate") == 0) {
auth_html(req->hostname, req->port, req->user_name);
return 0;
}
if (!check_target_acl(req->hostname, req->port)) {
- snprintf(buf, 1024, "target %s:%d not allowed in cachemgr.conf\n", req->hostname, req->port);
+ snprintf(buf, sizeof(buf), "target %s:%d not allowed in cachemgr.conf\n", req->hostname, req->port);
error_html(buf);
return 1;
}
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
- snprintf(buf, 1024, "socket: %s\n", xstrerror());
+ snprintf(buf, sizeof(buf), "socket: %s\n", xstrerror());
error_html(buf);
return 1;
}
memset(&S, '\0', sizeof(struct sockaddr_in));
S.sin_family = AF_INET;
if ((hp = gethostbyname(req->hostname)) != NULL) {
assert(hp->h_length <= sizeof(S.sin_addr.s_addr));
xmemcpy(&S.sin_addr.s_addr, hp->h_addr, hp->h_length);
} else if (safe_inet_addr(req->hostname, &S.sin_addr))
(void) 0;
else {
- snprintf(buf, 1024, "Unknown host: %s\n", req->hostname);
+ snprintf(buf, sizeof(buf), "Unknown host: %s\n", req->hostname);
error_html(buf);
return 1;
}
S.sin_port = htons(req->port);
if (connect(s, (struct sockaddr *) &S, sizeof(struct sockaddr_in)) < 0) {
- snprintf(buf, 1024, "connect: %s\n", xstrerror());
+ snprintf(buf, sizeof(buf), "connect: %s\n", xstrerror());
error_html(buf);
return 1;
}
l = snprintf(buf, sizeof(buf),
"GET cache_object://%s/%s HTTP/1.0\r\n"
"Accept: */*\r\n"
"%s" /* Authentication info or nothing */
"\r\n",
req->hostname,
req->action,
make_auth_header(req));
#ifdef _SQUID_MSWIN_
send(s, buf, l, 0);
#else
write(s, buf, l);
#endif
debug(1) fprintf(stderr, "wrote request: '%s'\n", buf);
return read_reply(s, req);
}
int
main(int argc, char *argv[])
{
char *s;
cachemgr_request *req;
safe_inet_addr("255.255.255.255", &no_addr);
now = time(NULL);
#ifdef _SQUID_MSWIN_
Win32SockInit();
atexit(Win32SockCleanup);
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
_fmode = _O_BINARY;
if ((s = strrchr(argv[0], '\\')))
#else
if ((s = strrchr(argv[0], '/')))
#endif
progname = xstrdup(s + 1);
else
progname = xstrdup(argv[0]);
if ((s = getenv("SCRIPT_NAME")) != NULL)
script_name = xstrdup(s);
req = read_request();
return process_request(req);
}
static char *
read_post_request(void)
{
char *s;
- char *buf;
- int len;
+
if ((s = getenv("REQUEST_METHOD")) == NULL)
- return NULL;
+ return NULL;
+
if (0 != strcasecmp(s, "POST"))
- return NULL;
+ return NULL;
+
if ((s = getenv("CONTENT_LENGTH")) == NULL)
- return NULL;
- if ((len = atoi(s)) <= 0)
- return NULL;
- buf = xmalloc(len + 1);
- fread(buf, len, 1, stdin);
- buf[len] = '\0';
+ return NULL;
+
+ if (*s == '-') // negative length content huh?
+ return NULL;
+
+ uint64_t len;
+
+ char *endptr = s+ strlen(s);
+ if ((len = strtoll(s, &endptr, 10)) <= 0)
+ return NULL;
+
+ // limit the input to something reasonable.
+ // 4KB should be enough for the GET/POST data length, but may be extended.
+ if (len >= 4096) {
+ printf("Status: 400 Bad Request\n\n");
+ exit(0);
+ }
+ char *buf = (char *)xmalloc(len + 1);
+
+ size_t readLen = fread(buf, 1, len, stdin);
+ if (readLen == 0) {
+ xfree(buf);
+ return NULL;
+ }
+ buf[readLen] = '\0';
+ len -= readLen;
+
+ // purge the remainder of the request entity
+ while (len > 0 && readLen) {
+ char temp[65535];
+ readLen = fread(temp, 1, 65535, stdin);
+ len -= readLen;
+ }
+
return buf;
}
static char *
read_get_request(void)
{
char *s;
if ((s = getenv("QUERY_STRING")) == NULL)
return NULL;
return xstrdup(s);
}
static cachemgr_request *
read_request(void)
{
char *buf;
cachemgr_request *req;
char *s;
char *t;
char *q;
if ((buf = read_post_request()) != NULL)
(void) 0;
else if ((buf = read_get_request()) != NULL)
(void) 0;
else
return NULL;
#ifdef _SQUID_MSWIN_
if (strlen(buf) == 0 || strlen(buf) == 4000)
#else
if (strlen(buf) == 0)
@@ -859,110 +891,123 @@ make_pub_auth(cachemgr_request * req)
debug(3) fprintf(stderr, "cmgr: encoding for pub...\n");
if (!req->passwd || !strlen(req->passwd))
return;
/* host | time | user | passwd */
snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
req->hostname,
(int) now,
req->user_name ? req->user_name : "",
req->passwd);
debug(3) fprintf(stderr, "cmgr: pre-encoded for pub: %s\n", buf);
debug(3) fprintf(stderr, "cmgr: encoded: '%s'\n", base64_encode(buf));
req->pub_auth = xstrdup(base64_encode(buf));
}
static void
decode_pub_auth(cachemgr_request * req)
{
char *buf;
const char *host_name;
const char *time_str;
const char *user_name;
const char *passwd;
debug(2) fprintf(stderr, "cmgr: decoding pub: '%s'\n", safe_str(req->pub_auth));
safe_free(req->passwd);
if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
return;
buf = xstrdup(base64_decode(req->pub_auth));
debug(3) fprintf(stderr, "cmgr: length ok\n");
/* parse ( a lot of memory leaks, but that is cachemgr style :) */
- if ((host_name = strtok(buf, "|")) == NULL)
+ if ((host_name = strtok(buf, "|")) == NULL) {
+ xfree(buf);
return;
+ }
debug(3) fprintf(stderr, "cmgr: decoded host: '%s'\n", host_name);
- if ((time_str = strtok(NULL, "|")) == NULL)
+ if ((time_str = strtok(NULL, "|")) == NULL) {
+ xfree(buf);
return;
+ }
debug(3) fprintf(stderr, "cmgr: decoded time: '%s' (now: %d)\n", time_str, (int) now);
- if ((user_name = strtok(NULL, "|")) == NULL)
+ if ((user_name = strtok(NULL, "|")) == NULL) {
+ xfree(buf);
return;
+ }
debug(3) fprintf(stderr, "cmgr: decoded uname: '%s'\n", user_name);
- if ((passwd = strtok(NULL, "|")) == NULL)
+ if ((passwd = strtok(NULL, "|")) == NULL) {
+ xfree(buf);
return;
+ }
debug(2) fprintf(stderr, "cmgr: decoded passwd: '%s'\n", passwd);
/* verify freshness and validity */
- if (atoi(time_str) + passwd_ttl < now)
+ if (atoi(time_str) + passwd_ttl < now) {
+ xfree(buf);
return;
- if (strcasecmp(host_name, req->hostname))
+ }
+ if (strcasecmp(host_name, req->hostname)) {
+ xfree(buf);
return;
+ }
debug(1) fprintf(stderr, "cmgr: verified auth. info.\n");
/* ok, accept */
- xfree(req->user_name);
+ safe_free(req->user_name);
req->user_name = xstrdup(user_name);
req->passwd = xstrdup(passwd);
xfree(buf);
}
static void
reset_auth(cachemgr_request * req)
{
safe_free(req->passwd);
safe_free(req->pub_auth);
}
static const char *
make_auth_header(const cachemgr_request * req)
{
static char buf[1024];
int l = 0;
const char *str64;
if (!req->passwd)
return "";
snprintf(buf, sizeof(buf), "%s:%s",
req->user_name ? req->user_name : "",
req->passwd);
str64 = base64_encode(buf);
l += snprintf(buf, sizeof(buf), "Authorization: Basic %s\r\n", str64);
assert(l < sizeof(buf));
l += snprintf(&buf[l], sizeof(buf) - l,
"Proxy-Authorization: Basic %s\r\n", str64);
+ xxfree(str64);
return buf;
}
static int
check_target_acl(const char *hostname, int port)
{
char config_line[BUFSIZ];
FILE *fp = NULL;
int ret = 0;
fp = fopen("cachemgr.conf", "r");
if (fp == NULL)
fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
if (fp == NULL) {
#ifdef CACHEMGR_HOSTNAME_DEFINED
if (strcmp(hostname, CACHEMGR_HOSTNAME) == 0 && port == CACHE_HTTP_PORT)
return 1;
#else
if (strcmp(hostname, "localhost") == 0)
return 1;
if (strcmp(hostname, getfullhostname()) == 0)
return 1;
#endif
return 0;
}
while (fgets(config_line, BUFSIZ, fp)) {
char *token = NULL;
strtok(config_line, " \r\n\t");
if (config_line[0] == '#')
continue;
if (config_line[0] == '\0')