diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-12-19 12:30:34 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-12-19 12:30:34 +0100 |
commit | 03419aa037ce37d1c3accb0df52fdc456b360541 (patch) | |
tree | 6f96d1d0bdaafd2e197c9651dde789a8451c09b9 | |
parent | 93b4a605263612cf32ad9de746a4fafaf4515115 (diff) | |
download | busybox-03419aa037ce37d1c3accb0df52fdc456b360541.tar.gz |
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>
-rw-r--r-- | networking/httpd.c | 26 | ||||
-rw-r--r-- | networking/httpd_indexcgi.c | 27 |
2 files changed, 34 insertions, 19 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index e9cd213f1..3f4e6aab7 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 7e0225e19..d732cd4f8 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" |