diff --git a/src/buffer.c b/src/buffer.c index 5e03e273..da65a775 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -806,13 +806,6 @@ void buffer_path_simplify(buffer *dest, buffer *src) force_assert('\0' == src->ptr[src->used-1]); - /* might need one character more for the '/' prefix */ - if (src == dest) { - buffer_string_prepare_append(dest, 1); - } else { - buffer_string_prepare_copy(dest, buffer_string_length(src) + 1); - } - #if defined(__WIN32) || defined(__CYGWIN__) /* cygwin is treating \ and / the same, so we have to that too */ { @@ -832,14 +825,15 @@ void buffer_path_simplify(buffer *dest, buffer *src) while (*walk == ' ') { walk++; } + if (*walk == '.') { + if (walk[1] == '/' || walk[1] == '\0') + ++walk; + else if (walk[1] == '.' && (walk[2] == '/' || walk[2] == '\0')) + walk+=2; + } pre1 = 0; c = *(walk++); - /* prefix with '/' if not already present */ - if (c != '/') { - pre1 = '/'; - *(out++) = '/'; - } while (c != '\0') { /* assert((src != dest || out <= walk) && slash <= out); */ @@ -859,7 +853,7 @@ void buffer_path_simplify(buffer *dest, buffer *src) if (c == '/' || c == '\0') { const size_t toklen = out - slash; - if (toklen == 3 && pre2 == '.' && pre1 == '.') { + if (toklen == 3 && pre2 == '.' && pre1 == '.' && *slash == '/') { /* "/../" or ("/.." at end of string) */ out = slash; /* if there is something before "/..", there is at least one diff --git a/src/mod_webdav.c b/src/mod_webdav.c index e7d33d26..aa3e9106 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -1998,6 +1998,11 @@ static handler_t mod_webdav_copymove(server *srv, connection *con, plugin_data * buffer_urldecode_path(p->uri.path); buffer_path_simplify(p->uri.path, p->uri.path); + if (buffer_string_is_empty(p->uri.path) || p->uri.path->ptr[0] != '/') { + con->http_status = 400; + return HANDLER_FINISHED; + } + /* we now have a URI which is clean. transform it into a physical path */ buffer_copy_buffer(p->physical.doc_root, con->physical.doc_root); buffer_copy_buffer(p->physical.rel_path, p->uri.path); diff --git a/src/response.c b/src/response.c index 781505b0..aa02b529 100644 --- a/src/response.c +++ b/src/response.c @@ -396,6 +396,14 @@ handler_t http_response_prepare(server *srv, connection *con) { buffer_copy_buffer(con->uri.path, con->uri.path_raw); buffer_urldecode_path(con->uri.path); buffer_path_simplify(con->uri.path, con->uri.path); + if (buffer_string_is_empty(con->uri.path) || con->uri.path->ptr[0] != '/') { + log_error_write(srv, __FILE__, __LINE__, "sbs", + "uri-path does not begin with '/':", con->uri.path, "-> 400"); + con->keep_alive = 0; + con->http_status = 400; + con->file_finished = 1; + return HANDLER_FINISHED; + } } con->conditional_is_valid[COMP_SERVER_SOCKET] = 1; /* SERVERsocket */ diff --git a/src/t/test_buffer.c b/src/t/test_buffer.c index 2dd0e400..3e6eb4df 100644 --- a/src/t/test_buffer.c +++ b/src/t/test_buffer.c @@ -23,15 +23,6 @@ static void run_buffer_path_simplify(buffer *psrc, buffer *pdest, const char *in fflush(stderr); abort(); } else { - #if 0 - fprintf(stdout, - "%s.%d: buffer_path_simplify('%s') succeeded: got '%s'\n", - __FILE__, - __LINE__, - in, - out); - #endif - if (psrc != pdest) buffer_copy_buffer(psrc, pdest); buffer_path_simplify(pdest, psrc); @@ -40,7 +31,7 @@ static void run_buffer_path_simplify(buffer *psrc, buffer *pdest, const char *in "%s.%d: buffer_path_simplify('%s') failed - not idempotent: expected '%s', got '%s'\n", __FILE__, __LINE__, - out, + in, out, pdest->ptr ? pdest->ptr : ""); fflush(stderr); @@ -51,21 +42,25 @@ static void run_buffer_path_simplify(buffer *psrc, buffer *pdest, const char *in static void test_buffer_path_simplify_with(buffer *psrc, buffer *pdest) { run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(""), CONST_STR_LEN("")); - run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(" "), CONST_STR_LEN("/")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/"), CONST_STR_LEN("/")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("//"), CONST_STR_LEN("/")); - run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc"), CONST_STR_LEN("/abc")); - run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc//"), CONST_STR_LEN("/abc/")); - run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/./xyz"), CONST_STR_LEN("/abc/xyz")); - run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/.//xyz"), CONST_STR_LEN("/abc/xyz")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc"), CONST_STR_LEN("abc")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc//"), CONST_STR_LEN("abc/")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/./xyz"), CONST_STR_LEN("abc/xyz")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/.//xyz"), CONST_STR_LEN("abc/xyz")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/../xyz"), CONST_STR_LEN("/xyz")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc/./xyz"), CONST_STR_LEN("/abc/xyz")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc//./xyz"), CONST_STR_LEN("/abc/xyz")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc/../xyz"), CONST_STR_LEN("/xyz")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/../xyz/."), CONST_STR_LEN("/xyz/")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc/../xyz/."), CONST_STR_LEN("/xyz/")); - run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/./xyz/.."), CONST_STR_LEN("/abc/")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("abc/./xyz/.."), CONST_STR_LEN("abc/")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/abc/./xyz/.."), CONST_STR_LEN("/abc/")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("."), CONST_STR_LEN("")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(".."), CONST_STR_LEN("")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("..."), CONST_STR_LEN("...")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("...."), CONST_STR_LEN("....")); + run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(".../"), CONST_STR_LEN(".../")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("./xyz/.."), CONST_STR_LEN("/")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN(".//xyz/.."), CONST_STR_LEN("/")); run_buffer_path_simplify(psrc, pdest, CONST_STR_LEN("/./xyz/.."), CONST_STR_LEN("/")); diff --git a/src/t/test_burl.c b/src/t/test_burl.c index e83bebea..7be9be50 100644 --- a/src/t/test_burl.c +++ b/src/t/test_burl.c @@ -31,6 +31,7 @@ static void test_burl_normalize (void) { int flags; flags = HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED; + run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("no-slash"), CONST_STR_LEN("no-slash")); run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/"), CONST_STR_LEN("/")); run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc"), CONST_STR_LEN("/abc")); run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/abc/"), CONST_STR_LEN("/abc/"));