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')
openSUSE Build Service is sponsored by