httpd: don't drop/abuse QUERY_STRING when /cgi-bin/index.cgi is used
authorDenys Vlasenko <vda.linux@googlemail.com>
Mon, 19 Dec 2011 11:30:34 +0000 (12:30 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 19 Dec 2011 11:30:34 +0000 (12:30 +0100)
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/httpd.c
networking/httpd_indexcgi.c

index e9cd213f1fbc8e2434db757873d0b4176424878c..3f4e6aab7c9f4c8881f563d95fe8e4035ac4b8d2 100644 (file)
@@ -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: */
index 7e0225e198722effa488c3c213c4a5ed4f224613..d732cd4f8a9f6e6b0baecec4d2278879d9886295 100644 (file)
@@ -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"