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:
parent
93b4a60526
commit
03419aa037
@ -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: */
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user