[git commit] httpd: don't drop/abuse QUERY_STRING when /cgi-bin/index.cgi is used

Denys Vlasenko vda.linux at googlemail.com
Mon Dec 19 11:30:34 UTC 2011


commit: http://git.busybox.net/busybox/commit/?id=03419aa037ce37d1c3accb0df52fdc456b360541
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 networking/httpd.c          |   26 ++++++++++++++++++--------
 networking/httpd_indexcgi.c |   25 +++++++++++++++----------
 2 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/networking/httpd.c b/networking/httpd.c
index e9cd213..3f4e6aa 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -1265,18 +1265,21 @@ static void setenv1(const char *name, const char *value)
  *
  * Parameters:
  * const char *url              The requested URL (with leading /).
+ * const char *orig_uri         The original URI before rewriting (if any)
  * int post_len                 Length of the POST body.
  * const char *cookie           For set HTTP_COOKIE.
  * const char *content_type     For set CONTENT_TYPE.
  */
 static void send_cgi_and_exit(
 		const char *url,
+		const char *orig_uri,
 		const char *request,
 		int post_len,
 		const char *cookie,
 		const char *content_type) NORETURN;
 static void send_cgi_and_exit(
 		const char *url,
+		const char *orig_uri,
 		const char *request,
 		int post_len,
 		const char *cookie,
@@ -1314,9 +1317,9 @@ static void send_cgi_and_exit(
 	setenv1("PATH_INFO", script);   /* set to /PATH_INFO or "" */
 	setenv1("REQUEST_METHOD", request);
 	if (g_query) {
-		putenv(xasprintf("%s=%s?%s", "REQUEST_URI", url, g_query));
+		putenv(xasprintf("%s=%s?%s", "REQUEST_URI", orig_uri, g_query));
 	} else {
-		setenv1("REQUEST_URI", url);
+		setenv1("REQUEST_URI", orig_uri);
 	}
 	if (script != NULL)
 		*script = '\0';         /* cut off /PATH_INFO */
@@ -2248,12 +2251,20 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 			/* protect listing "cgi-bin/" */
 			send_headers_and_exit(HTTP_FORBIDDEN);
 		}
-		send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);
+		send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type);
 	}
 #endif
 
-	if (urlp[-1] == '/')
+	if (urlp[-1] == '/') {
+		/* When index_page string is appended to <dir>/ URL, it overwrites
+		 * the query string. If we fall back to call /cgi-bin/index.cgi,
+		 * query string would be lost and not available to the CGI.
+		 * Work around it by making a deep copy.
+		 */
+		if (ENABLE_FEATURE_HTTPD_CGI)
+			g_query = xstrdup(g_query); /* ok for NULL too */
 		strcpy(urlp, index_page);
+	}
 	if (stat(tptr, &sb) == 0) {
 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
 		char *suffix = strrchr(tptr, '.');
@@ -2261,7 +2272,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 			Htaccess *cur;
 			for (cur = script_i; cur; cur = cur->next) {
 				if (strcmp(cur->before_colon + 1, suffix) == 0) {
-					send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);
+					send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type);
 				}
 			}
 		}
@@ -2274,9 +2285,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 		/* It's a dir URL and there is no index.html
 		 * Try cgi-bin/index.cgi */
 		if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
-			urlp[0] = '\0';
-			g_query = urlcopy;
-			send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
+			urlp[0] = '\0'; /* remove index_page */
+			send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type);
 		}
 	}
 	/* else fall through to send_file, it errors out if open fails: */
diff --git a/networking/httpd_indexcgi.c b/networking/httpd_indexcgi.c
index 7e0225e..d732cd4 100644
--- a/networking/httpd_indexcgi.c
+++ b/networking/httpd_indexcgi.c
@@ -221,20 +221,25 @@ int main(int argc, char *argv[])
 	unsigned long long size_total;
 	int odd;
 	DIR *dirp;
-	char *QUERY_STRING;
-
-	QUERY_STRING = getenv("QUERY_STRING");
-	if (!QUERY_STRING
-	 || QUERY_STRING[0] != '/'
-	 || strstr(QUERY_STRING, "//")
-	 || strstr(QUERY_STRING, "/../")
-	 || strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0
+	char *location;
+
+	location = getenv("REQUEST_URI");
+	if (!location)
+		return 1;
+
+	/* drop URL arguments if any */
+	strchrnul(location, '?')[0] = '\0';
+
+	if (location[0] != '/'
+	 || strstr(location, "//")
+	 || strstr(location, "/../")
+	 || strcmp(strrchr(location, '/'), "/..") == 0
 	) {
 		return 1;
 	}
 
 	if (chdir("..")
-	 || (QUERY_STRING[1] && chdir(QUERY_STRING + 1))
+	 || (location[1] && chdir(location + 1))
 	) {
 		return 1;
 	}
@@ -271,14 +276,14 @@ int main(int argc, char *argv[])
 		"\r\n" /* Mandatory empty line after headers */
 		"<html><head><title>Index of ");
 	/* Guard against directories with &, > etc */
-	fmt_html(QUERY_STRING);
+	fmt_html(location);
 	fmt_str(
 		"</title>\n"
 		STYLE_STR
 		"</head>" "\n"
 		"<body>" "\n"
 		"<h1>Index of ");
-	fmt_html(QUERY_STRING);
+	fmt_html(location);
 	fmt_str(
 		"</h1>" "\n"
 		"<table>" "\n"


More information about the busybox-cvs mailing list