]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
urlapi: don't accept blank port number field without scheme
authorDaniel Stenberg <daniel@haxx.se>
Fri, 4 Dec 2020 16:27:57 +0000 (17:27 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 6 Dec 2020 23:50:49 +0000 (00:50 +0100)
... as it makes the URL parser accept "very-long-hostname://" as a valid
host name and we don't want that. The parser now only accepts a blank
(no digits) after the colon if the URL starts with a scheme.

Reported-by: d4d on hackerone
Closes #6283

lib/urlapi-int.h
lib/urlapi.c
tests/data/test1653
tests/unit/unit1653.c

index 0ac5d9e0ca89aa4b7d6824995753bd7d219c1f5a..42572330946db57d913c0b4cb90e7fbe455e648b 100644 (file)
@@ -28,7 +28,7 @@
 bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen);
 
 #ifdef DEBUGBUILD
-CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname);
+CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, bool);
 #endif
 
 #endif /* HEADER_CURL_URLAPI_INT_H */
index 4bce3d4ebebd872c9f62ceea229b421acc097fbc..ae75963595e5d00788054d94c610c13ff794a8c8 100644 (file)
@@ -497,7 +497,8 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
   return result;
 }
 
-UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
+UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
+                                   bool has_scheme)
 {
   char *portptr = NULL;
   char endbracket;
@@ -542,10 +543,14 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
 
     /* Browser behavior adaptation. If there's a colon with no digits after,
        just cut off the name there which makes us ignore the colon and just
-       use the default port. Firefox, Chrome and Safari all do that. */
+       use the default port. Firefox, Chrome and Safari all do that.
+
+       Don't do it if the URL has no scheme, to make something that looks like
+       a scheme not work!
+    */
     if(!portptr[1]) {
       *portptr = '\0';
-      return CURLUE_OK;
+      return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER;
     }
 
     if(!ISDIGIT(portptr[1]))
@@ -904,7 +909,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
     if(result)
       return result;
 
-    result = Curl_parse_port(u, hostname);
+    result = Curl_parse_port(u, hostname, url_has_scheme);
     if(result)
       return result;
 
index 59ec3f3962017a945e2829848e22e19c1b7a42c2..fff7f6e56c0dfb8dbacce33a89af153368c99a49 100644 (file)
@@ -14,7 +14,7 @@ none
 unittest
 </features>
 <name>
-urlapi
+urlapi port number parsing
 </name>
 </client>
 </testcase>
index d245ea6ecd4a65531641565d943d9ead6a6ba403..7d02ae6de1e2db56b8caf9774f091f0826cce943 100644 (file)
@@ -55,7 +55,7 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15]");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error");
   ret = curl_url_get(u, CURLUPART_PORT, &portnum, CURLU_NO_DEFAULT_PORT);
   fail_unless(ret != CURLUE_OK, "curl_url_get portnum returned something");
@@ -69,7 +69,7 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15|");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret != CURLUE_OK, "Curl_parse_port true on error");
   free_and_clear(ipv6port);
   curl_url_cleanup(u);
@@ -80,7 +80,7 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff;fea7:da15]:80");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret != CURLUE_OK, "Curl_parse_port true on error");
   free_and_clear(ipv6port);
   curl_url_cleanup(u);
@@ -92,7 +92,7 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15%25eth3]:80");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error");
   ret = curl_url_get(u, CURLUPART_PORT, &portnum, 0);
   fail_unless(ret == CURLUE_OK, "curl_url_get portnum returned error");
@@ -108,7 +108,7 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15%25eth3]");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error");
   free_and_clear(ipv6port);
   curl_url_cleanup(u);
@@ -120,7 +120,7 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15]:81");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error");
   ret = curl_url_get(u, CURLUPART_PORT, &portnum, 0);
   fail_unless(ret == CURLUE_OK, "curl_url_get portnum returned error");
@@ -136,7 +136,7 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15];81");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret != CURLUE_OK, "Curl_parse_port true on error");
   free_and_clear(ipv6port);
   curl_url_cleanup(u);
@@ -147,19 +147,20 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15]80");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret != CURLUE_OK, "Curl_parse_port true on error");
   free_and_clear(ipv6port);
   curl_url_cleanup(u);
 
-  /* Valid IPv6 with no port after the colon, should use default */
+  /* Valid IPv6 with no port after the colon, should use default if a scheme
+     was used in the URL */
   u = curl_url();
   if(!u)
     goto fail;
   ipv6port = strdup("[fe80::250:56ff:fea7:da15]:");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, TRUE);
   fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error");
   free_and_clear(ipv6port);
   curl_url_cleanup(u);
@@ -171,7 +172,7 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15!25eth3]:80");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret != CURLUE_OK, "Curl_parse_port returned non-error");
   free_and_clear(ipv6port);
   curl_url_cleanup(u);
@@ -183,10 +184,25 @@ UNITTEST_START
   ipv6port = strdup("[fe80::250:56ff:fea7:da15%eth3]:80");
   if(!ipv6port)
     goto fail;
-  ret = Curl_parse_port(u, ipv6port);
+  ret = Curl_parse_port(u, ipv6port, FALSE);
   fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error");
+  free_and_clear(ipv6port);
+  curl_url_cleanup(u);
+
+  /* No scheme and no digits following the colon - not accepted. Because that
+     makes (a*50):// that looks like a scheme be an acceptable input. */
+  u = curl_url();
+  if(!u)
+    goto fail;
+  ipv6port = strdup("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+                    "aaaaaaaaaaaaaaaaaaaaaa:");
+  if(!ipv6port)
+    goto fail;
+  ret = Curl_parse_port(u, ipv6port, FALSE);
+  fail_unless(ret == CURLUE_BAD_PORT_NUMBER, "Curl_parse_port did wrong");
   fail:
   free(ipv6port);
   curl_url_cleanup(u);
+
 }
 UNITTEST_STOP