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

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2011-12-19 12:30:34 +01:00
parent 93b4a60526
commit 03419aa037
2 changed files with 33 additions and 18 deletions

View File

@ -1265,18 +1265,21 @@ static void setenv1(const char *name, const char *value)
* *
* Parameters: * Parameters:
* const char *url The requested URL (with leading /). * 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. * int post_len Length of the POST body.
* const char *cookie For set HTTP_COOKIE. * const char *cookie For set HTTP_COOKIE.
* const char *content_type For set CONTENT_TYPE. * const char *content_type For set CONTENT_TYPE.
*/ */
static void send_cgi_and_exit( static void send_cgi_and_exit(
const char *url, const char *url,
const char *orig_uri,
const char *request, const char *request,
int post_len, int post_len,
const char *cookie, const char *cookie,
const char *content_type) NORETURN; const char *content_type) NORETURN;
static void send_cgi_and_exit( static void send_cgi_and_exit(
const char *url, const char *url,
const char *orig_uri,
const char *request, const char *request,
int post_len, int post_len,
const char *cookie, const char *cookie,
@ -1314,9 +1317,9 @@ static void send_cgi_and_exit(
setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */ setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */
setenv1("REQUEST_METHOD", request); setenv1("REQUEST_METHOD", request);
if (g_query) { 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 { } else {
setenv1("REQUEST_URI", url); setenv1("REQUEST_URI", orig_uri);
} }
if (script != NULL) if (script != NULL)
*script = '\0'; /* cut off /PATH_INFO */ *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/" */ /* protect listing "cgi-bin/" */
send_headers_and_exit(HTTP_FORBIDDEN); 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 #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); strcpy(urlp, index_page);
}
if (stat(tptr, &sb) == 0) { if (stat(tptr, &sb) == 0) {
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
char *suffix = strrchr(tptr, '.'); char *suffix = strrchr(tptr, '.');
@ -2261,7 +2272,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
Htaccess *cur; Htaccess *cur;
for (cur = script_i; cur; cur = cur->next) { for (cur = script_i; cur; cur = cur->next) {
if (strcmp(cur->before_colon + 1, suffix) == 0) { 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 /* It's a dir URL and there is no index.html
* Try cgi-bin/index.cgi */ * Try cgi-bin/index.cgi */
if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
urlp[0] = '\0'; urlp[0] = '\0'; /* remove index_page */
g_query = urlcopy; send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type);
send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
} }
} }
/* else fall through to send_file, it errors out if open fails: */ /* else fall through to send_file, it errors out if open fails: */

View File

@ -221,20 +221,25 @@ int main(int argc, char *argv[])
unsigned long long size_total; unsigned long long size_total;
int odd; int odd;
DIR *dirp; DIR *dirp;
char *QUERY_STRING; char *location;
QUERY_STRING = getenv("QUERY_STRING"); location = getenv("REQUEST_URI");
if (!QUERY_STRING if (!location)
|| QUERY_STRING[0] != '/' return 1;
|| strstr(QUERY_STRING, "//")
|| strstr(QUERY_STRING, "/../") /* drop URL arguments if any */
|| strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0 strchrnul(location, '?')[0] = '\0';
if (location[0] != '/'
|| strstr(location, "//")
|| strstr(location, "/../")
|| strcmp(strrchr(location, '/'), "/..") == 0
) { ) {
return 1; return 1;
} }
if (chdir("..") if (chdir("..")
|| (QUERY_STRING[1] && chdir(QUERY_STRING + 1)) || (location[1] && chdir(location + 1))
) { ) {
return 1; return 1;
} }
@ -271,14 +276,14 @@ int main(int argc, char *argv[])
"\r\n" /* Mandatory empty line after headers */ "\r\n" /* Mandatory empty line after headers */
"<html><head><title>Index of "); "<html><head><title>Index of ");
/* Guard against directories with &, > etc */ /* Guard against directories with &, > etc */
fmt_html(QUERY_STRING); fmt_html(location);
fmt_str( fmt_str(
"</title>\n" "</title>\n"
STYLE_STR STYLE_STR
"</head>" "\n" "</head>" "\n"
"<body>" "\n" "<body>" "\n"
"<h1>Index of "); "<h1>Index of ");
fmt_html(QUERY_STRING); fmt_html(location);
fmt_str( fmt_str(
"</h1>" "\n" "</h1>" "\n"
"<table>" "\n" "<table>" "\n"