Compare commits
10 Commits
f6cff68ada
...
f2bd9e6727
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2bd9e6727 | ||
|
|
b8fde0f065 | ||
|
|
6b3982853f | ||
|
|
d322d176cf | ||
|
|
dc35064ac9 | ||
|
|
b2ea774234 | ||
|
|
e809167868 | ||
|
|
99b8b65391 | ||
|
|
7cf8495b55 | ||
|
|
43afd63dd7 |
358
backport-CVE-2024-11053.patch
Normal file
358
backport-CVE-2024-11053.patch
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
From e9b9bbac22c26cf67316fa8e6c6b9e831af31949 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
Date: Fri, 15 Nov 2024 11:06:36 +0100
|
||||||
|
Subject: [PATCH] netrc: address several netrc parser flaws
|
||||||
|
|
||||||
|
- make sure that a match that returns a username also returns a
|
||||||
|
password, that should be blank if no password is found
|
||||||
|
|
||||||
|
- fix handling of multiple logins for same host where the password/login
|
||||||
|
order might be reversed.
|
||||||
|
|
||||||
|
- reject credentials provided in the .netrc if they contain ASCII control
|
||||||
|
codes - if the used protocol does not support such (like HTTP and WS do)
|
||||||
|
|
||||||
|
Reported-by: Harry Sintonen
|
||||||
|
|
||||||
|
Add test 478, 479 and 480 to verify. Updated unit 1304.
|
||||||
|
|
||||||
|
Closes #15586
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
remove some code irrelevant with CVE
|
||||||
|
Reference:https://github.com/curl/curl/commit/e9b9bbac22c26cf67316fa8e6c6b9e831af31949
|
||||||
|
---
|
||||||
|
lib/netrc.c | 19 ++++++++++++++++++
|
||||||
|
tests/data/Makefile.inc | 1 +
|
||||||
|
tests/data/test479 | 107 ++++++++++++++++++++++++++++++++++++++
|
||||||
|
tests/unit/unit1304.c | 75 ++++++++-------------------
|
||||||
|
3 files changed, 180 insertions(+), 20 deletions(-)
|
||||||
|
create mode 100644 tests/data/test478
|
||||||
|
create mode 100644 tests/data/test479
|
||||||
|
create mode 100644 tests/data/test480
|
||||||
|
|
||||||
|
diff --git a/lib/netrc.c b/lib/netrc.c
|
||||||
|
index b771b60..9e183a2 100644
|
||||||
|
--- a/lib/netrc.c
|
||||||
|
+++ b/lib/netrc.c
|
||||||
|
@@ -152,6 +152,7 @@ static int parsenetrc(const char *host,
|
||||||
|
retcode = NETRC_FAILED; /* allocation failed */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
+ state_our_login = TRUE;
|
||||||
|
login_alloc = TRUE;
|
||||||
|
}
|
||||||
|
state_login = 0;
|
||||||
|
@@ -181,6 +182,16 @@ static int parsenetrc(const char *host,
|
||||||
|
state = HOSTFOUND;
|
||||||
|
state_our_login = FALSE;
|
||||||
|
}
|
||||||
|
+ else if(strcasecompare("default", tok)) {
|
||||||
|
+ state = HOSTVALID;
|
||||||
|
+ retcode = NETRC_SUCCESS; /* we did find our host */
|
||||||
|
+ Curl_safefree(password);
|
||||||
|
+ if(!specific_login)
|
||||||
|
+ if(login_alloc) {
|
||||||
|
+ free(login);
|
||||||
|
+ login_alloc = FALSE;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
break;
|
||||||
|
} /* switch (state) */
|
||||||
|
|
||||||
|
@@ -189,6 +200,14 @@ static int parsenetrc(const char *host,
|
||||||
|
} /* while fgets() */
|
||||||
|
|
||||||
|
out:
|
||||||
|
+ if(!retcode && !password && state_our_login) {
|
||||||
|
+ /* success without a password, set a blank one */
|
||||||
|
+ password = strdup("");
|
||||||
|
+ if(!password)
|
||||||
|
+ retcode = 1; /* out of memory */
|
||||||
|
+ else
|
||||||
|
+ password_alloc = TRUE;
|
||||||
|
+ }
|
||||||
|
if(!retcode) {
|
||||||
|
/* success */
|
||||||
|
*login_changed = FALSE;
|
||||||
|
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
|
||||||
|
index ea5221c00fd419..53f62c6e28f650 100644
|
||||||
|
--- a/tests/data/Makefile.inc
|
||||||
|
+++ b/tests/data/Makefile.inc
|
||||||
|
@@ -77,6 +77,7 @@ test435 test436 test437 test438 test439 test440 test441 test442 test443 \
|
||||||
|
test430 test431 test432 test433 test434 test435 test445 test446\
|
||||||
|
\
|
||||||
|
test442 test443 test444 \
|
||||||
|
+test479 \
|
||||||
|
test490 test491 test492 test493 test494 \
|
||||||
|
\
|
||||||
|
test500 test501 test502 test503 test504 test505 test506 test507 test508 \
|
||||||
|
diff --git a/tests/data/test479 b/tests/data/test479
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000000000..d7ce4652fae272
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/data/test479
|
||||||
|
@@ -0,0 +1,107 @@
|
||||||
|
+<testcase>
|
||||||
|
+<info>
|
||||||
|
+<keywords>
|
||||||
|
+netrc
|
||||||
|
+HTTP
|
||||||
|
+</keywords>
|
||||||
|
+</info>
|
||||||
|
+#
|
||||||
|
+# Server-side
|
||||||
|
+<reply>
|
||||||
|
+<data crlf="yes">
|
||||||
|
+HTTP/1.1 301 Follow this you fool
|
||||||
|
+Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
+Server: test-server/fake
|
||||||
|
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||||
|
+ETag: "21025-dc7-39462498"
|
||||||
|
+Accept-Ranges: bytes
|
||||||
|
+Content-Length: 6
|
||||||
|
+Connection: close
|
||||||
|
+Location: http://b.com/%TESTNUMBER0002
|
||||||
|
+
|
||||||
|
+-foo-
|
||||||
|
+</data>
|
||||||
|
+
|
||||||
|
+<data2 crlf="yes">
|
||||||
|
+HTTP/1.1 200 OK
|
||||||
|
+Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
+Server: test-server/fake
|
||||||
|
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||||
|
+ETag: "21025-dc7-39462498"
|
||||||
|
+Accept-Ranges: bytes
|
||||||
|
+Content-Length: 7
|
||||||
|
+Connection: close
|
||||||
|
+
|
||||||
|
+target
|
||||||
|
+</data2>
|
||||||
|
+
|
||||||
|
+<datacheck crlf="yes">
|
||||||
|
+HTTP/1.1 301 Follow this you fool
|
||||||
|
+Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
+Server: test-server/fake
|
||||||
|
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||||
|
+ETag: "21025-dc7-39462498"
|
||||||
|
+Accept-Ranges: bytes
|
||||||
|
+Content-Length: 6
|
||||||
|
+Connection: close
|
||||||
|
+Location: http://b.com/%TESTNUMBER0002
|
||||||
|
+
|
||||||
|
+HTTP/1.1 200 OK
|
||||||
|
+Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
+Server: test-server/fake
|
||||||
|
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||||
|
+ETag: "21025-dc7-39462498"
|
||||||
|
+Accept-Ranges: bytes
|
||||||
|
+Content-Length: 7
|
||||||
|
+Connection: close
|
||||||
|
+
|
||||||
|
+target
|
||||||
|
+</datacheck>
|
||||||
|
+</reply>
|
||||||
|
+
|
||||||
|
+#
|
||||||
|
+# Client-side
|
||||||
|
+<client>
|
||||||
|
+<server>
|
||||||
|
+http
|
||||||
|
+</server>
|
||||||
|
+<features>
|
||||||
|
+proxy
|
||||||
|
+</features>
|
||||||
|
+<name>
|
||||||
|
+.netrc with redirect and default without password
|
||||||
|
+</name>
|
||||||
|
+<command>
|
||||||
|
+--netrc --netrc-file log/netrc%TESTNUMBER -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/
|
||||||
|
+</command>
|
||||||
|
+<file name="log/netrc%TESTNUMBER" >
|
||||||
|
+
|
||||||
|
+machine a.com
|
||||||
|
+ login alice
|
||||||
|
+ password alicespassword
|
||||||
|
+
|
||||||
|
+default
|
||||||
|
+ login bob
|
||||||
|
+
|
||||||
|
+</file>
|
||||||
|
+</client>
|
||||||
|
+
|
||||||
|
+<verify>
|
||||||
|
+<protocol>
|
||||||
|
+GET http://a.com/ HTTP/1.1
|
||||||
|
+Host: a.com
|
||||||
|
+Authorization: Basic %b64[alice:alicespassword]b64%
|
||||||
|
+User-Agent: curl/%VERSION
|
||||||
|
+Accept: */*
|
||||||
|
+Proxy-Connection: Keep-Alive
|
||||||
|
+
|
||||||
|
+GET http://b.com/%TESTNUMBER0002 HTTP/1.1
|
||||||
|
+Host: b.com
|
||||||
|
+Authorization: Basic %b64[bob:]b64%
|
||||||
|
+User-Agent: curl/%VERSION
|
||||||
|
+Accept: */*
|
||||||
|
+Proxy-Connection: Keep-Alive
|
||||||
|
+
|
||||||
|
+</protocol>
|
||||||
|
+</verify>
|
||||||
|
+</testcase>
|
||||||
|
diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c
|
||||||
|
index 238d3c0f7fb09a..817887b94c8748 100644
|
||||||
|
--- a/tests/unit/unit1304.c
|
||||||
|
+++ b/tests/unit/unit1304.c
|
||||||
|
@@ -32,13 +32,8 @@ static char *password;
|
||||||
|
|
||||||
|
static CURLcode unit_setup(void)
|
||||||
|
{
|
||||||
|
- password = strdup("");
|
||||||
|
- login = strdup("");
|
||||||
|
- if(!password || !login) {
|
||||||
|
- Curl_safefree(password);
|
||||||
|
- Curl_safefree(login);
|
||||||
|
- return CURLE_OUT_OF_MEMORY;
|
||||||
|
- }
|
||||||
|
+ password = NULL;
|
||||||
|
+ login = NULL;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -60,86 +55,52 @@ UNITTEST_START
|
||||||
|
result = Curl_parsenetrc("test.example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 1, "Host not found should return 1");
|
||||||
|
- abort_unless(password != NULL, "returned NULL!");
|
||||||
|
- fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
- fail_unless(login[0] == 0, "login should not have been changed");
|
||||||
|
+ abort_unless(password == NULL, "password did not return NULL!");
|
||||||
|
+ abort_unless(login == NULL, "user did not return NULL!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test a non existent login in our netrc file.
|
||||||
|
*/
|
||||||
|
- free(login);
|
||||||
|
- login = strdup("me");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
+ login = (char *)"me";
|
||||||
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
|
- abort_unless(password != NULL, "returned NULL!");
|
||||||
|
- fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
|
- fail_unless(!password_changed, "password should not have been changed");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
- fail_unless(strncmp(login, "me", 2) == 0,
|
||||||
|
- "login should not have been changed");
|
||||||
|
- fail_unless(!login_changed, "login should not have been changed");
|
||||||
|
+ abort_unless(password == NULL, "password is not NULL!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test a non existent login and host in our netrc file.
|
||||||
|
*/
|
||||||
|
- free(login);
|
||||||
|
- login = strdup("me");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
+ login = (char *)"me";
|
||||||
|
result = Curl_parsenetrc("test.example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 1, "Host not found should return 1");
|
||||||
|
- abort_unless(password != NULL, "returned NULL!");
|
||||||
|
- fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
- fail_unless(strncmp(login, "me", 2) == 0,
|
||||||
|
- "login should not have been changed");
|
||||||
|
+ abort_unless(password == NULL, "password is not NULL!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test a non existent login (substring of an existing one) in our
|
||||||
|
* netrc file.
|
||||||
|
*/
|
||||||
|
- free(login);
|
||||||
|
- login = strdup("admi");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
+ login = (char *)"admi";
|
||||||
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
|
- abort_unless(password != NULL, "returned NULL!");
|
||||||
|
- fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
|
- fail_unless(!password_changed, "password should not have been changed");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
- fail_unless(strncmp(login, "admi", 4) == 0,
|
||||||
|
- "login should not have been changed");
|
||||||
|
- fail_unless(!login_changed, "login should not have been changed");
|
||||||
|
+ abort_unless(password == NULL, "password is not NULL!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test a non existent login (superstring of an existing one)
|
||||||
|
* in our netrc file.
|
||||||
|
*/
|
||||||
|
- free(login);
|
||||||
|
- login = strdup("adminn");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
+ login = (char *)"adminn";
|
||||||
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
|
- abort_unless(password != NULL, "returned NULL!");
|
||||||
|
- fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
|
- fail_unless(!password_changed, "password should not have been changed");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
- fail_unless(strncmp(login, "adminn", 6) == 0,
|
||||||
|
- "login should not have been changed");
|
||||||
|
- fail_unless(!login_changed, "login should not have been changed");
|
||||||
|
+ abort_unless(password == NULL, "password is not NULL!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test for the first existing host in our netrc file
|
||||||
|
* with login[0] = 0.
|
||||||
|
*/
|
||||||
|
- free(login);
|
||||||
|
- login = strdup("");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
+ login = NULL;
|
||||||
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
|
@@ -159,8 +126,9 @@ UNITTEST_START
|
||||||
|
* with login[0] != 0.
|
||||||
|
*/
|
||||||
|
free(password);
|
||||||
|
- password = strdup("");
|
||||||
|
- abort_unless(password != NULL, "returned NULL!");
|
||||||
|
+ free(login);
|
||||||
|
+ password = NULL;
|
||||||
|
+ login = NULL;
|
||||||
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
|
@@ -177,11 +145,9 @@ UNITTEST_START
|
||||||
|
* with login[0] = 0.
|
||||||
|
*/
|
||||||
|
free(password);
|
||||||
|
- password = strdup("");
|
||||||
|
- abort_unless(password != NULL, "returned NULL!");
|
||||||
|
+ password = NULL;
|
||||||
|
free(login);
|
||||||
|
- login = strdup("");
|
||||||
|
- abort_unless(login != NULL, "returned NULL!");
|
||||||
|
+ login = NULL;
|
||||||
|
result = Curl_parsenetrc("curl.example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
|
@@ -198,8 +164,9 @@ UNITTEST_START
|
||||||
|
* with login[0] != 0.
|
||||||
|
*/
|
||||||
|
free(password);
|
||||||
|
- password = strdup("");
|
||||||
|
- abort_unless(password != NULL, "returned NULL!");
|
||||||
|
+ free(login);
|
||||||
|
+ password = NULL;
|
||||||
|
+ login = NULL;
|
||||||
|
result = Curl_parsenetrc("curl.example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
174
backport-CVE-2025-0167.patch
Normal file
174
backport-CVE-2025-0167.patch
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
From 0e120c5b925e8ca75d5319e319e5ce4b8080d8eb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
Date: Fri, 3 Jan 2025 16:22:27 +0100
|
||||||
|
Subject: [PATCH] netrc: 'default' with no credentials is not a match
|
||||||
|
|
||||||
|
Test 486 verifies.
|
||||||
|
|
||||||
|
Reported-by: Yihang Zhou
|
||||||
|
|
||||||
|
Closes #15908
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
Reference:https://github.com/curl/curl/commit/0e120c5b925e8ca75d5319e
|
||||||
|
---
|
||||||
|
lib/netrc.c | 19 ++++--
|
||||||
|
tests/data/Makefile.inc | 2 +-
|
||||||
|
tests/data/test486 | 105 +++++++++++++++++++++++++++++++++++++++++
|
||||||
|
3 files changed, 118 insertions(+), 8 deletions(-)
|
||||||
|
create mode 100644 tests/data/test486
|
||||||
|
|
||||||
|
diff --git a/lib/netrc.c b/lib/netrc.c
|
||||||
|
index 7d2b903..8096b4b 100644
|
||||||
|
--- a/lib/netrc.c
|
||||||
|
+++ b/lib/netrc.c
|
||||||
|
@@ -200,13 +200,18 @@ static int parsenetrc(const char *host,
|
||||||
|
} /* while fgets() */
|
||||||
|
|
||||||
|
out:
|
||||||
|
- if(!retcode && !password && state_our_login) {
|
||||||
|
- /* success without a password, set a blank one */
|
||||||
|
- password = strdup("");
|
||||||
|
- if(!password)
|
||||||
|
- retcode = 1; /* out of memory */
|
||||||
|
- else
|
||||||
|
- password_alloc = TRUE;
|
||||||
|
+ if(!retcode) {
|
||||||
|
+ if(!password && state_our_login) {
|
||||||
|
+ /* success without a password, set a blank one */
|
||||||
|
+ password = strdup("");
|
||||||
|
+ if(!password)
|
||||||
|
+ retcode = 1; /* out of memory */
|
||||||
|
+ else
|
||||||
|
+ password_alloc = TRUE;
|
||||||
|
+ }
|
||||||
|
+ else if(!login && !password)
|
||||||
|
+ /* a default with no credentials */
|
||||||
|
+ retcode = NETRC_FILE_MISSING;
|
||||||
|
}
|
||||||
|
if(!retcode) {
|
||||||
|
/* success */
|
||||||
|
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
|
||||||
|
index 9ec101a7c74b..fc5e4cef5668 100644
|
||||||
|
--- a/tests/data/Makefile.inc
|
||||||
|
+++ b/tests/data/Makefile.inc
|
||||||
|
@@ -78,7 +78,7 @@ test426 \
|
||||||
|
test430 test431 test432 test433 test434 test435 test445 test446\
|
||||||
|
\
|
||||||
|
test442 test443 test444 \
|
||||||
|
-test479 \
|
||||||
|
+test479 test486 \
|
||||||
|
test490 test491 test492 test493 test494 \
|
||||||
|
\
|
||||||
|
test500 test501 test502 test503 test504 test505 test506 test507 test508 \
|
||||||
|
diff --git a/tests/data/test486 b/tests/data/test486
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..53efae597a1b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/data/test486
|
||||||
|
@@ -0,0 +1,105 @@
|
||||||
|
+<testcase>
|
||||||
|
+<info>
|
||||||
|
+<keywords>
|
||||||
|
+netrc
|
||||||
|
+HTTP
|
||||||
|
+</keywords>
|
||||||
|
+</info>
|
||||||
|
+#
|
||||||
|
+# Server-side
|
||||||
|
+<reply>
|
||||||
|
+<data crlf="yes">
|
||||||
|
+HTTP/1.1 301 Follow this you fool
|
||||||
|
+Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
+Server: test-server/fake
|
||||||
|
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||||
|
+ETag: "21025-dc7-39462498"
|
||||||
|
+Accept-Ranges: bytes
|
||||||
|
+Content-Length: 6
|
||||||
|
+Connection: close
|
||||||
|
+Location: http://b.com/%TESTNUMBER0002
|
||||||
|
+
|
||||||
|
+-foo-
|
||||||
|
+</data>
|
||||||
|
+
|
||||||
|
+<data2 crlf="yes">
|
||||||
|
+HTTP/1.1 200 OK
|
||||||
|
+Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
+Server: test-server/fake
|
||||||
|
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||||
|
+ETag: "21025-dc7-39462498"
|
||||||
|
+Accept-Ranges: bytes
|
||||||
|
+Content-Length: 7
|
||||||
|
+Connection: close
|
||||||
|
+
|
||||||
|
+target
|
||||||
|
+</data2>
|
||||||
|
+
|
||||||
|
+<datacheck crlf="yes">
|
||||||
|
+HTTP/1.1 301 Follow this you fool
|
||||||
|
+Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
+Server: test-server/fake
|
||||||
|
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||||
|
+ETag: "21025-dc7-39462498"
|
||||||
|
+Accept-Ranges: bytes
|
||||||
|
+Content-Length: 6
|
||||||
|
+Connection: close
|
||||||
|
+Location: http://b.com/%TESTNUMBER0002
|
||||||
|
+
|
||||||
|
+HTTP/1.1 200 OK
|
||||||
|
+Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
+Server: test-server/fake
|
||||||
|
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||||
|
+ETag: "21025-dc7-39462498"
|
||||||
|
+Accept-Ranges: bytes
|
||||||
|
+Content-Length: 7
|
||||||
|
+Connection: close
|
||||||
|
+
|
||||||
|
+target
|
||||||
|
+</datacheck>
|
||||||
|
+</reply>
|
||||||
|
+
|
||||||
|
+#
|
||||||
|
+# Client-side
|
||||||
|
+<client>
|
||||||
|
+<server>
|
||||||
|
+http
|
||||||
|
+</server>
|
||||||
|
+<features>
|
||||||
|
+proxy
|
||||||
|
+</features>
|
||||||
|
+<name>
|
||||||
|
+.netrc with redirect and "default" with no password or login
|
||||||
|
+</name>
|
||||||
|
+<command>
|
||||||
|
+--netrc --netrc-file log/netrc%TESTNUMBER -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/
|
||||||
|
+</command>
|
||||||
|
+<file name="log/netrc%TESTNUMBER" >
|
||||||
|
+
|
||||||
|
+machine a.com
|
||||||
|
+ login alice
|
||||||
|
+ password alicespassword
|
||||||
|
+
|
||||||
|
+default
|
||||||
|
+
|
||||||
|
+</file>
|
||||||
|
+</client>
|
||||||
|
+
|
||||||
|
+<verify>
|
||||||
|
+<protocol>
|
||||||
|
+GET http://a.com/ HTTP/1.1
|
||||||
|
+Host: a.com
|
||||||
|
+Authorization: Basic %b64[alice:alicespassword]b64%
|
||||||
|
+User-Agent: curl/%VERSION
|
||||||
|
+Accept: */*
|
||||||
|
+Proxy-Connection: Keep-Alive
|
||||||
|
+
|
||||||
|
+GET http://b.com/%TESTNUMBER0002 HTTP/1.1
|
||||||
|
+Host: b.com
|
||||||
|
+User-Agent: curl/%VERSION
|
||||||
|
+Accept: */*
|
||||||
|
+Proxy-Connection: Keep-Alive
|
||||||
|
+
|
||||||
|
+</protocol>
|
||||||
|
+</verify>
|
||||||
|
+</testcase>
|
||||||
326
backport-CVE-2025-0725.patch
Normal file
326
backport-CVE-2025-0725.patch
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
From 76f83f0db23846e254d940ec7fe141010077eb88 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
Date: Fri, 24 Jan 2025 11:13:24 +0100
|
||||||
|
Subject: [PATCH] content_encoding: drop support for zlib before 1.2.0.4
|
||||||
|
|
||||||
|
zlib 1.2.0.4 was released on 10 August 2003
|
||||||
|
|
||||||
|
Closes #16079
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
Reference:https://github.com/curl/curl/commit/76f83f0db23846e254d940ec7
|
||||||
|
---
|
||||||
|
docs/INTERNALS.md | 2 +-
|
||||||
|
lib/content_encoding.c | 232 ++---------------------------------------
|
||||||
|
2 files changed, 8 insertions(+), 226 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md
|
||||||
|
index 176ca52..a5b0efb 100644
|
||||||
|
--- a/docs/INTERNALS.md
|
||||||
|
+++ b/docs/INTERNALS.md
|
||||||
|
@@ -86,7 +86,7 @@ Dependencies
|
||||||
|
|
||||||
|
- OpenSSL 0.9.7
|
||||||
|
- GnuTLS 3.1.10
|
||||||
|
- - zlib 1.1.4
|
||||||
|
+ - zlib 1.2.0.4
|
||||||
|
- libssh2 1.0
|
||||||
|
- c-ares 1.16.0
|
||||||
|
- libidn2 2.0.0
|
||||||
|
diff --git a/lib/content_encoding.c b/lib/content_encoding.c
|
||||||
|
index c870df2..74f2e68 100644
|
||||||
|
--- a/lib/content_encoding.c
|
||||||
|
+++ b/lib/content_encoding.c
|
||||||
|
@@ -52,31 +52,13 @@
|
||||||
|
|
||||||
|
#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
|
||||||
|
|
||||||
|
-
|
||||||
|
#ifdef HAVE_LIBZ
|
||||||
|
|
||||||
|
-/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
|
||||||
|
- (doing so will reduce code size slightly). */
|
||||||
|
-#define OLD_ZLIB_SUPPORT 1
|
||||||
|
-
|
||||||
|
-#define GZIP_MAGIC_0 0x1f
|
||||||
|
-#define GZIP_MAGIC_1 0x8b
|
||||||
|
-
|
||||||
|
-/* gzip flag byte */
|
||||||
|
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
|
||||||
|
-#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
|
||||||
|
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
|
||||||
|
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
|
||||||
|
-#define COMMENT 0x10 /* bit 4 set: file comment present */
|
||||||
|
-#define RESERVED 0xE0 /* bits 5..7: reserved */
|
||||||
|
-
|
||||||
|
typedef enum {
|
||||||
|
ZLIB_UNINIT, /* uninitialized */
|
||||||
|
ZLIB_INIT, /* initialized */
|
||||||
|
ZLIB_INFLATING, /* inflating started. */
|
||||||
|
ZLIB_EXTERNAL_TRAILER, /* reading external trailer */
|
||||||
|
- ZLIB_GZIP_HEADER, /* reading gzip header */
|
||||||
|
- ZLIB_GZIP_INFLATING, /* inflating gzip stream */
|
||||||
|
ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
|
||||||
|
} zlibInitState;
|
||||||
|
|
||||||
|
@@ -120,9 +102,6 @@ static CURLcode
|
||||||
|
exit_zlib(struct Curl_easy *data,
|
||||||
|
z_stream *z, zlibInitState *zlib_init, CURLcode result)
|
||||||
|
{
|
||||||
|
- if(*zlib_init == ZLIB_GZIP_HEADER)
|
||||||
|
- Curl_safefree(z->next_in);
|
||||||
|
-
|
||||||
|
if(*zlib_init != ZLIB_UNINIT) {
|
||||||
|
if(inflateEnd(z) != Z_OK && result == CURLE_OK)
|
||||||
|
result = process_zlib_error(data, z);
|
||||||
|
@@ -171,8 +150,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
|
||||||
|
/* Check state. */
|
||||||
|
if(zp->zlib_init != ZLIB_INIT &&
|
||||||
|
zp->zlib_init != ZLIB_INFLATING &&
|
||||||
|
- zp->zlib_init != ZLIB_INIT_GZIP &&
|
||||||
|
- zp->zlib_init != ZLIB_GZIP_INFLATING)
|
||||||
|
+ zp->zlib_init != ZLIB_INIT_GZIP)
|
||||||
|
return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
|
||||||
|
|
||||||
|
/* Dynamically allocate a buffer for decompression because it's uncommonly
|
||||||
|
@@ -321,6 +299,7 @@ static CURLcode gzip_init_writer(struct Curl_easy *data,
|
||||||
|
{
|
||||||
|
struct zlib_params *zp = (struct zlib_params *) &writer->params;
|
||||||
|
z_stream *z = &zp->z; /* zlib state structure */
|
||||||
|
+ const char *v = zlibVersion();
|
||||||
|
|
||||||
|
if(!writer->downstream)
|
||||||
|
return CURLE_WRITE_ERROR;
|
||||||
|
@@ -329,109 +308,21 @@ static CURLcode gzip_init_writer(struct Curl_easy *data,
|
||||||
|
z->zalloc = (alloc_func) zalloc_cb;
|
||||||
|
z->zfree = (free_func) zfree_cb;
|
||||||
|
|
||||||
|
- if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
|
||||||
|
- /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
|
||||||
|
+ if(strcmp(v, "1.2.0.4") >= 0) {
|
||||||
|
+ /* zlib version >= 1.2.0.4 supports transparent gzip decompressing */
|
||||||
|
if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
|
||||||
|
return process_zlib_error(data, z);
|
||||||
|
}
|
||||||
|
zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
- /* we must parse the gzip header and trailer ourselves */
|
||||||
|
- if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
|
||||||
|
- return process_zlib_error(data, z);
|
||||||
|
- }
|
||||||
|
- zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */
|
||||||
|
- zp->zlib_init = ZLIB_INIT; /* Initial call state */
|
||||||
|
+ failf(data, "too old zlib version: %s", v);
|
||||||
|
+ return CURLE_FAILED_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
-#ifdef OLD_ZLIB_SUPPORT
|
||||||
|
-/* Skip over the gzip header */
|
||||||
|
-static enum {
|
||||||
|
- GZIP_OK,
|
||||||
|
- GZIP_BAD,
|
||||||
|
- GZIP_UNDERFLOW
|
||||||
|
-} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
|
||||||
|
-{
|
||||||
|
- int method, flags;
|
||||||
|
- const ssize_t totallen = len;
|
||||||
|
-
|
||||||
|
- /* The shortest header is 10 bytes */
|
||||||
|
- if(len < 10)
|
||||||
|
- return GZIP_UNDERFLOW;
|
||||||
|
-
|
||||||
|
- if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
|
||||||
|
- return GZIP_BAD;
|
||||||
|
-
|
||||||
|
- method = data[2];
|
||||||
|
- flags = data[3];
|
||||||
|
-
|
||||||
|
- if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
|
||||||
|
- /* Can't handle this compression method or unknown flag */
|
||||||
|
- return GZIP_BAD;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* Skip over time, xflags, OS code and all previous bytes */
|
||||||
|
- len -= 10;
|
||||||
|
- data += 10;
|
||||||
|
-
|
||||||
|
- if(flags & EXTRA_FIELD) {
|
||||||
|
- ssize_t extra_len;
|
||||||
|
-
|
||||||
|
- if(len < 2)
|
||||||
|
- return GZIP_UNDERFLOW;
|
||||||
|
-
|
||||||
|
- extra_len = (data[1] << 8) | data[0];
|
||||||
|
-
|
||||||
|
- if(len < (extra_len + 2))
|
||||||
|
- return GZIP_UNDERFLOW;
|
||||||
|
-
|
||||||
|
- len -= (extra_len + 2);
|
||||||
|
- data += (extra_len + 2);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if(flags & ORIG_NAME) {
|
||||||
|
- /* Skip over NUL-terminated file name */
|
||||||
|
- while(len && *data) {
|
||||||
|
- --len;
|
||||||
|
- ++data;
|
||||||
|
- }
|
||||||
|
- if(!len || *data)
|
||||||
|
- return GZIP_UNDERFLOW;
|
||||||
|
-
|
||||||
|
- /* Skip over the NUL */
|
||||||
|
- --len;
|
||||||
|
- ++data;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if(flags & COMMENT) {
|
||||||
|
- /* Skip over NUL-terminated comment */
|
||||||
|
- while(len && *data) {
|
||||||
|
- --len;
|
||||||
|
- ++data;
|
||||||
|
- }
|
||||||
|
- if(!len || *data)
|
||||||
|
- return GZIP_UNDERFLOW;
|
||||||
|
-
|
||||||
|
- /* Skip over the NUL */
|
||||||
|
- --len;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if(flags & HEAD_CRC) {
|
||||||
|
- if(len < 2)
|
||||||
|
- return GZIP_UNDERFLOW;
|
||||||
|
-
|
||||||
|
- len -= 2;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- *headerlen = totallen - len;
|
||||||
|
- return GZIP_OK;
|
||||||
|
-}
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
static CURLcode gzip_unencode_write(struct Curl_easy *data,
|
||||||
|
struct contenc_writer *writer,
|
||||||
|
const char *buf, size_t nbytes)
|
||||||
|
@@ -447,117 +338,8 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
|
||||||
|
return inflate_stream(data, writer, ZLIB_INIT_GZIP);
|
||||||
|
}
|
||||||
|
|
||||||
|
-#ifndef OLD_ZLIB_SUPPORT
|
||||||
|
- /* Support for old zlib versions is compiled away and we are running with
|
||||||
|
- an old version, so return an error. */
|
||||||
|
+ /* We are running with an old version: return error. */
|
||||||
|
return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
|
||||||
|
-
|
||||||
|
-#else
|
||||||
|
- /* This next mess is to get around the potential case where there isn't
|
||||||
|
- * enough data passed in to skip over the gzip header. If that happens, we
|
||||||
|
- * malloc a block and copy what we have then wait for the next call. If
|
||||||
|
- * there still isn't enough (this is definitely a worst-case scenario), we
|
||||||
|
- * make the block bigger, copy the next part in and keep waiting.
|
||||||
|
- *
|
||||||
|
- * This is only required with zlib versions < 1.2.0.4 as newer versions
|
||||||
|
- * can handle the gzip header themselves.
|
||||||
|
- */
|
||||||
|
-
|
||||||
|
- switch(zp->zlib_init) {
|
||||||
|
- /* Skip over gzip header? */
|
||||||
|
- case ZLIB_INIT:
|
||||||
|
- {
|
||||||
|
- /* Initial call state */
|
||||||
|
- ssize_t hlen;
|
||||||
|
-
|
||||||
|
- switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) {
|
||||||
|
- case GZIP_OK:
|
||||||
|
- z->next_in = (Bytef *) buf + hlen;
|
||||||
|
- z->avail_in = (uInt) (nbytes - hlen);
|
||||||
|
- zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
- case GZIP_UNDERFLOW:
|
||||||
|
- /* We need more data so we can find the end of the gzip header. It's
|
||||||
|
- * possible that the memory block we malloc here will never be freed if
|
||||||
|
- * the transfer abruptly aborts after this point. Since it's unlikely
|
||||||
|
- * that circumstances will be right for this code path to be followed in
|
||||||
|
- * the first place, and it's even more unlikely for a transfer to fail
|
||||||
|
- * immediately afterwards, it should seldom be a problem.
|
||||||
|
- */
|
||||||
|
- z->avail_in = (uInt) nbytes;
|
||||||
|
- z->next_in = malloc(z->avail_in);
|
||||||
|
- if(!z->next_in) {
|
||||||
|
- return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
|
||||||
|
- }
|
||||||
|
- memcpy(z->next_in, buf, z->avail_in);
|
||||||
|
- zp->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
|
||||||
|
- /* We don't have any data to inflate yet */
|
||||||
|
- return CURLE_OK;
|
||||||
|
-
|
||||||
|
- case GZIP_BAD:
|
||||||
|
- default:
|
||||||
|
- return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- }
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
- case ZLIB_GZIP_HEADER:
|
||||||
|
- {
|
||||||
|
- /* Need more gzip header data state */
|
||||||
|
- ssize_t hlen;
|
||||||
|
- z->avail_in += (uInt) nbytes;
|
||||||
|
- z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
|
||||||
|
- if(!z->next_in) {
|
||||||
|
- return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
|
||||||
|
- }
|
||||||
|
- /* Append the new block of data to the previous one */
|
||||||
|
- memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
|
||||||
|
-
|
||||||
|
- switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
|
||||||
|
- case GZIP_OK:
|
||||||
|
- /* This is the zlib stream data */
|
||||||
|
- free(z->next_in);
|
||||||
|
- /* Don't point into the malloced block since we just freed it */
|
||||||
|
- z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
|
||||||
|
- z->avail_in = (uInt) (z->avail_in - hlen);
|
||||||
|
- zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
- case GZIP_UNDERFLOW:
|
||||||
|
- /* We still don't have any data to inflate! */
|
||||||
|
- return CURLE_OK;
|
||||||
|
-
|
||||||
|
- case GZIP_BAD:
|
||||||
|
- default:
|
||||||
|
- return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- }
|
||||||
|
- break;
|
||||||
|
-
|
||||||
|
- case ZLIB_EXTERNAL_TRAILER:
|
||||||
|
- z->next_in = (Bytef *) buf;
|
||||||
|
- z->avail_in = (uInt) nbytes;
|
||||||
|
- return process_trailer(data, zp);
|
||||||
|
-
|
||||||
|
- case ZLIB_GZIP_INFLATING:
|
||||||
|
- default:
|
||||||
|
- /* Inflating stream state */
|
||||||
|
- z->next_in = (Bytef *) buf;
|
||||||
|
- z->avail_in = (uInt) nbytes;
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if(z->avail_in == 0) {
|
||||||
|
- /* We don't have any data to inflate; wait until next time */
|
||||||
|
- return CURLE_OK;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* We've parsed the header, now uncompress the data */
|
||||||
|
- return inflate_stream(data, writer, ZLIB_GZIP_INFLATING);
|
||||||
|
-#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gzip_close_writer(struct Curl_easy *data,
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
From c3857eca70e3bf293fff2fe0b3766cfcad1b1251 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
Date: Sat, 14 Dec 2024 23:09:16 +0100
|
||||||
|
Subject: [PATCH] altsvc: avoid integer overflow in expire calculation
|
||||||
|
|
||||||
|
A bad value here just makes for a bad alt-svc experience, not a security
|
||||||
|
problem.
|
||||||
|
|
||||||
|
Detected by OSS-Fuzz
|
||||||
|
|
||||||
|
Bug: https://issues.oss-fuzz.com/issues/383911309
|
||||||
|
|
||||||
|
Closes #15745
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
Reference:https://github.com/curl/curl/commit/c3857eca70e3bf293fff2fe0b3766cfcad1b1251
|
||||||
|
---
|
||||||
|
lib/altsvc.c | 10 +++++++---
|
||||||
|
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/lib/altsvc.c b/lib/altsvc.c
|
||||||
|
index a3ab368c5014..62f2c545fe55 100644
|
||||||
|
--- a/lib/altsvc.c
|
||||||
|
+++ b/lib/altsvc.c
|
||||||
|
@@ -659,9 +659,13 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
|
||||||
|
srcalpnid, dstalpnid,
|
||||||
|
srcport, dstport);
|
||||||
|
if(as) {
|
||||||
|
- /* The expires time also needs to take the Age: value (if any) into
|
||||||
|
- account. [See RFC 7838 section 3.1] */
|
||||||
|
- as->expires = maxage + time(NULL);
|
||||||
|
+ time_t secs = time(NULL);
|
||||||
|
+ /* The expires time also needs to take the Age: value (if any)
|
||||||
|
+ into account. [See RFC 7838 section 3.1] */
|
||||||
|
+ if(maxage > (TIME_T_MAX - secs))
|
||||||
|
+ as->expires = TIME_T_MAX;
|
||||||
|
+ else
|
||||||
|
+ as->expires = maxage + secs;
|
||||||
|
as->persist = persist;
|
||||||
|
Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
|
||||||
|
infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
|
||||||
62
backport-cookie-treat-cookie-name-case-sensitively.patch
Normal file
62
backport-cookie-treat-cookie-name-case-sensitively.patch
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
From 9919149aef67014150e2a1c75a7aa2c79204e30d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
Date: Wed, 6 Nov 2024 11:26:25 +0100
|
||||||
|
Subject: [PATCH] cookie: treat cookie name case sensitively
|
||||||
|
|
||||||
|
Extend test 31 to verify
|
||||||
|
|
||||||
|
Reported-by: delogicsreal on github
|
||||||
|
Fixes #15492
|
||||||
|
Closes #15493
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
Reference:https://github.com/curl/curl/commit/9919149aef67014150e2a1c75a7aa2c79204e30d
|
||||||
|
---
|
||||||
|
lib/cookie.c | 2 +-
|
||||||
|
tests/data/test31 | 3 +++
|
||||||
|
2 files changed, 4 insertions(+), 1 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/lib/cookie.c b/lib/cookie.c
|
||||||
|
index ca8c3c596..e37d58f1d 100644
|
||||||
|
--- a/lib/cookie.c
|
||||||
|
+++ b/lib/cookie.c
|
||||||
|
@@ -989,7 +989,7 @@ replace_existing(struct Curl_easy *data,
|
||||||
|
clist = c->cookies[myhash];
|
||||||
|
replace_old = FALSE;
|
||||||
|
while(clist) {
|
||||||
|
- if(strcasecompare(clist->name, co->name)) {
|
||||||
|
+ if(!strcmp(clist->name, co->name)) {
|
||||||
|
/* the names are identical */
|
||||||
|
|
||||||
|
if(clist->domain && co->domain) {
|
||||||
|
diff --git a/tests/data/test31 b/tests/data/test31
|
||||||
|
index d9d073996..2d411b5cd 100644
|
||||||
|
--- a/tests/data/test31
|
||||||
|
+++ b/tests/data/test31
|
||||||
|
@@ -26,6 +26,7 @@ Set-Cookie: blankdomain=sure; domain=; path=/
|
||||||
|
%if !hyper
|
||||||
|
Set-Cookie: foobar=name; domain=anything.com; path=/ ; secure
|
||||||
|
Set-Cookie:ismatch=this ; domain=test31.curl; path=/silly/
|
||||||
|
+Set-Cookie:ISMATCH=this ; domain=test31.curl; path=/silly/
|
||||||
|
Set-Cookie: overwrite=this ; domain=test31.curl; path=/overwrite/
|
||||||
|
Set-Cookie: overwrite=this2 ; domain=test31.curl; path=/overwrite
|
||||||
|
Set-Cookie: sec1value=secure1 ; domain=test31.curl; path=/secure1/ ; secure
|
||||||
|
@@ -75,6 +76,7 @@ Set-Cookie: securewithspace=after ; secure =
|
||||||
|
%else
|
||||||
|
Set-Cookie: foobar=name; domain=anything.com; path=/ ; secure
|
||||||
|
Set-Cookie: ismatch=this ; domain=test31.curl; path=/silly/
|
||||||
|
+Set-Cookie:ISMATCH=this ; domain=test31.curl; path=/silly/
|
||||||
|
Set-Cookie: overwrite=this ; domain=test31.curl; path=/overwrite/
|
||||||
|
Set-Cookie: overwrite=this2 ; domain=test31.curl; path=/overwrite
|
||||||
|
Set-Cookie: sec1value=secure1 ; domain=test31.curl; path=/secure1/ ; secure
|
||||||
|
@@ -181,6 +183,7 @@ test31.curl FALSE /we/want/ FALSE 2118138987 nodomain value
|
||||||
|
#HttpOnly_.test31.curl TRUE /p2/ FALSE 0 httpo2 value2
|
||||||
|
#HttpOnly_.test31.curl TRUE /p1/ FALSE 0 httpo1 value1
|
||||||
|
.test31.curl TRUE /overwrite FALSE 0 overwrite this2
|
||||||
|
+.test31.curl TRUE /silly/ FALSE 0 ISMATCH this
|
||||||
|
.test31.curl TRUE /silly/ FALSE 0 ismatch this
|
||||||
|
</file>
|
||||||
|
</verify>
|
||||||
|
--
|
||||||
|
2.33.0
|
||||||
|
|
||||||
176
backport-libssh-fix-freeing-of-resources-in-disconnect.patch
Normal file
176
backport-libssh-fix-freeing-of-resources-in-disconnect.patch
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
From 571e92f730831a860f8d2786674177ca08c0f592 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Stefan Eissing <stefan@eissing.org>
|
||||||
|
Date: Mon, 10 Mar 2025 17:08:57 +0100
|
||||||
|
Subject: [PATCH] libssh: fix freeing of resources in disconnect
|
||||||
|
|
||||||
|
ssh's disconnect assumed that the session to the server could be shut
|
||||||
|
down successfully during disconnect. When this failed, e.g. timed out,
|
||||||
|
memory was leaked.
|
||||||
|
|
||||||
|
Closes #16659
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
Curl_dyn_free(&sshc->readdir_buf); => Curl_safefree(sshc->readdir_line);
|
||||||
|
Reference:https://github.com/curl/curl/commit/571e92f730831a860f8d2786674177ca08c0f592
|
||||||
|
---
|
||||||
|
lib/vssh/libssh.c | 95 ++++++++++++++++++++++++++---------------------
|
||||||
|
1 file changed, 53 insertions(+), 42 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c
|
||||||
|
index 0467de041..8a08d8161 100644
|
||||||
|
--- a/lib/vssh/libssh.c
|
||||||
|
+++ b/lib/vssh/libssh.c
|
||||||
|
@@ -138,6 +138,7 @@ static void myssh_block2waitfor(struct connectdata *conn, bool block);
|
||||||
|
|
||||||
|
static CURLcode myssh_setup_connection(struct Curl_easy *data,
|
||||||
|
struct connectdata *conn);
|
||||||
|
+static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SCP protocol handler.
|
||||||
|
@@ -1943,48 +1944,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
|
||||||
|
state(data, SSH_SESSION_FREE);
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case SSH_SESSION_FREE:
|
||||||
|
- if(sshc->ssh_session) {
|
||||||
|
- ssh_free(sshc->ssh_session);
|
||||||
|
- sshc->ssh_session = NULL;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* worst-case scenario cleanup */
|
||||||
|
-
|
||||||
|
- DEBUGASSERT(sshc->ssh_session == NULL);
|
||||||
|
- DEBUGASSERT(sshc->scp_session == NULL);
|
||||||
|
-
|
||||||
|
- if(sshc->readdir_tmp) {
|
||||||
|
- ssh_string_free_char(sshc->readdir_tmp);
|
||||||
|
- sshc->readdir_tmp = NULL;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if(sshc->quote_attrs)
|
||||||
|
- sftp_attributes_free(sshc->quote_attrs);
|
||||||
|
-
|
||||||
|
- if(sshc->readdir_attrs)
|
||||||
|
- sftp_attributes_free(sshc->readdir_attrs);
|
||||||
|
-
|
||||||
|
- if(sshc->readdir_link_attrs)
|
||||||
|
- sftp_attributes_free(sshc->readdir_link_attrs);
|
||||||
|
-
|
||||||
|
- if(sshc->privkey)
|
||||||
|
- ssh_key_free(sshc->privkey);
|
||||||
|
- if(sshc->pubkey)
|
||||||
|
- ssh_key_free(sshc->pubkey);
|
||||||
|
-
|
||||||
|
- Curl_safefree(sshc->rsa_pub);
|
||||||
|
- Curl_safefree(sshc->rsa);
|
||||||
|
- Curl_safefree(sshc->quote_path1);
|
||||||
|
- Curl_safefree(sshc->quote_path2);
|
||||||
|
- Curl_safefree(sshc->readdir_line);
|
||||||
|
- Curl_safefree(sshc->readdir_linkPath);
|
||||||
|
- SSH_STRING_FREE_CHAR(sshc->homedir);
|
||||||
|
-
|
||||||
|
+ sshc_cleanup(sshc, data);
|
||||||
|
/* the code we are about to return */
|
||||||
|
result = sshc->actualcode;
|
||||||
|
-
|
||||||
|
memset(sshc, 0, sizeof(struct ssh_conn));
|
||||||
|
-
|
||||||
|
connclose(conn, "SSH session free");
|
||||||
|
sshc->state = SSH_SESSION_FREE; /* current */
|
||||||
|
sshc->nextstate = SSH_NO_STATE;
|
||||||
|
@@ -2328,6 +2291,52 @@ static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data)
|
||||||
|
+{
|
||||||
|
+ (void)data;
|
||||||
|
+ if(sshc->ssh_session) {
|
||||||
|
+ ssh_free(sshc->ssh_session);
|
||||||
|
+ sshc->ssh_session = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* worst-case scenario cleanup */
|
||||||
|
+ DEBUGASSERT(sshc->ssh_session == NULL);
|
||||||
|
+ DEBUGASSERT(sshc->scp_session == NULL);
|
||||||
|
+
|
||||||
|
+ if(sshc->readdir_tmp) {
|
||||||
|
+ ssh_string_free_char(sshc->readdir_tmp);
|
||||||
|
+ sshc->readdir_tmp = NULL;
|
||||||
|
+ }
|
||||||
|
+ if(sshc->quote_attrs) {
|
||||||
|
+ sftp_attributes_free(sshc->quote_attrs);
|
||||||
|
+ sshc->quote_attrs = NULL;
|
||||||
|
+ }
|
||||||
|
+ if(sshc->readdir_attrs) {
|
||||||
|
+ sftp_attributes_free(sshc->readdir_attrs);
|
||||||
|
+ sshc->readdir_attrs = NULL;
|
||||||
|
+ }
|
||||||
|
+ if(sshc->readdir_link_attrs) {
|
||||||
|
+ sftp_attributes_free(sshc->readdir_link_attrs);
|
||||||
|
+ sshc->readdir_link_attrs = NULL;
|
||||||
|
+ }
|
||||||
|
+ if(sshc->privkey) {
|
||||||
|
+ ssh_key_free(sshc->privkey);
|
||||||
|
+ sshc->privkey = NULL;
|
||||||
|
+ }
|
||||||
|
+ if(sshc->pubkey) {
|
||||||
|
+ ssh_key_free(sshc->pubkey);
|
||||||
|
+ sshc->pubkey = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Curl_safefree(sshc->rsa_pub);
|
||||||
|
+ Curl_safefree(sshc->rsa);
|
||||||
|
+ Curl_safefree(sshc->quote_path1);
|
||||||
|
+ Curl_safefree(sshc->quote_path2);
|
||||||
|
+ Curl_safefree(sshc->readdir_line);
|
||||||
|
+ Curl_safefree(sshc->readdir_linkPath);
|
||||||
|
+ SSH_STRING_FREE_CHAR(sshc->homedir);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* BLOCKING, but the function is using the state machine so the only reason
|
||||||
|
this is still blocking is that the multi interface code has no support for
|
||||||
|
disconnecting operations that takes a while */
|
||||||
|
@@ -2336,10 +2345,10 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
|
||||||
|
bool dead_connection)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
- struct ssh_conn *ssh = &conn->proto.sshc;
|
||||||
|
+ struct ssh_conn *sshc = &conn->proto.sshc;
|
||||||
|
(void) dead_connection;
|
||||||
|
|
||||||
|
- if(ssh->ssh_session) {
|
||||||
|
+ if(sshc->ssh_session) {
|
||||||
|
/* only if there's a session still around to use! */
|
||||||
|
|
||||||
|
state(data, SSH_SESSION_DISCONNECT);
|
||||||
|
@@ -2347,6 +2356,7 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
|
||||||
|
result = myssh_block_statemach(data, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ sshc_cleanup(sshc, data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -2500,6 +2510,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
|
||||||
|
struct connectdata *conn,
|
||||||
|
bool dead_connection)
|
||||||
|
{
|
||||||
|
+ struct ssh_conn *sshc = &conn->proto.sshc;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
(void) dead_connection;
|
||||||
|
|
||||||
|
@@ -2512,9 +2523,9 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGF(infof(data, "SSH DISCONNECT is done"));
|
||||||
|
+ sshc_cleanup(sshc, data);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
-
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
||||||
48
backport-openssl-fix-crash-on-missing-cert-password.patch
Normal file
48
backport-openssl-fix-crash-on-missing-cert-password.patch
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
From e60166815448f1ce4cc27e59a16e5805e864113d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jay Satiro <raysatiro@yahoo.com>
|
||||||
|
Date: Mon, 24 Mar 2025 02:48:01 -0400
|
||||||
|
Subject: [PATCH] openssl: fix crash on missing cert password
|
||||||
|
|
||||||
|
- Return 0 for password length if OpenSSL is expecting a certificate
|
||||||
|
password but the user did not provide one.
|
||||||
|
|
||||||
|
Prior to this change libcurl would crash if OpenSSL called the certificate
|
||||||
|
password callback in libcurl but no password was provided (NULL).
|
||||||
|
|
||||||
|
Reported-by: Roman Zharkov
|
||||||
|
|
||||||
|
Fixes https://github.com/curl/curl/issues/16806
|
||||||
|
Closes https://github.com/curl/curl/pull/16807
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
Reference:https://github.com/curl/curl/commit/e60166815448f1ce4cc27e59a16e5805e864113d
|
||||||
|
---
|
||||||
|
lib/vtls/openssl.c | 8 ++++----
|
||||||
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
|
||||||
|
index 1beda3133..4d5e1be29 100644
|
||||||
|
--- a/lib/vtls/openssl.c
|
||||||
|
+++ b/lib/vtls/openssl.c
|
||||||
|
@@ -931,14 +931,14 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size)
|
||||||
|
}
|
||||||
|
|
||||||
|
static int passwd_callback(char *buf, int num, int encrypting,
|
||||||
|
- void *global_passwd)
|
||||||
|
+ void *password)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(0 == encrypting);
|
||||||
|
|
||||||
|
- if(!encrypting) {
|
||||||
|
- int klen = curlx_uztosi(strlen((char *)global_passwd));
|
||||||
|
+ if(!encrypting && num >= 0 && password) {
|
||||||
|
+ int klen = curlx_uztosi(strlen((char *)password));
|
||||||
|
if(num > klen) {
|
||||||
|
- memcpy(buf, global_passwd, klen + 1);
|
||||||
|
+ memcpy(buf, password, klen + 1);
|
||||||
|
return klen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
||||||
107
backport-test391-verify-path-as-is-with-redirect.patch
Normal file
107
backport-test391-verify-path-as-is-with-redirect.patch
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
From 5394cbf570cda0510d6f10bd875e9aba9f898ce4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
Date: Tue, 7 Jun 2022 23:26:59 +0200
|
||||||
|
Subject: [PATCH] test391: verify --path-as-is with redirect
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
Reference:https://github.com/curl/curl/commit/5394cbf570cda0510d6f10bd875e9aba9f898ce4
|
||||||
|
---
|
||||||
|
tests/data/Makefile.inc | 2 +-
|
||||||
|
tests/data/test391 | 72 +++++++++++++++++++++++++++++++++++++++++
|
||||||
|
2 files changed, 73 insertions(+), 1 deletion(-)
|
||||||
|
create mode 100644 tests/data/test391
|
||||||
|
|
||||||
|
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
|
||||||
|
index 2196e2fd9787..d41052e53907 100644
|
||||||
|
--- a/tests/data/Makefile.inc
|
||||||
|
+++ b/tests/data/Makefile.inc
|
||||||
|
@@ -64,7 +64,7 @@ test352 test353 test354 test355 test356 test357 test358 test359 test360 \
|
||||||
|
test361 test362 test363 test364 test365 test366 \
|
||||||
|
test387 test388 \
|
||||||
|
\
|
||||||
|
-test392 test393 test394 test395 test396 test397 \
|
||||||
|
+test391 test392 test393 test394 test395 test396 test397 \
|
||||||
|
\
|
||||||
|
test400 test401 test402 test403 test404 test405 test406 test407 test408 \
|
||||||
|
test409 test410 \
|
||||||
|
diff --git a/tests/data/test391 b/tests/data/test391
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..1eff2ef3e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/data/test391
|
||||||
|
@@ -0,0 +1,72 @@
|
||||||
|
+<testcase>
|
||||||
|
+<info>
|
||||||
|
+<keywords>
|
||||||
|
+HTTP
|
||||||
|
+HTTP GET
|
||||||
|
+--path-as-is
|
||||||
|
+</keywords>
|
||||||
|
+</info>
|
||||||
|
+
|
||||||
|
+#
|
||||||
|
+# Server-side
|
||||||
|
+<reply>
|
||||||
|
+<data>
|
||||||
|
+HTTP/1.1 301 OK
|
||||||
|
+Content-Length: 6
|
||||||
|
+Content-Type: text/html
|
||||||
|
+Location: ../%TESTNUMBER0002
|
||||||
|
+
|
||||||
|
+-foo-
|
||||||
|
+</data>
|
||||||
|
+<data2>
|
||||||
|
+HTTP/1.1 200 OK
|
||||||
|
+Content-Length: 6
|
||||||
|
+Content-Type: text/html
|
||||||
|
+
|
||||||
|
+-muu-
|
||||||
|
+</data2>
|
||||||
|
+<datacheck>
|
||||||
|
+HTTP/1.1 301 OK
|
||||||
|
+Content-Length: 6
|
||||||
|
+Content-Type: text/html
|
||||||
|
+Location: ../%TESTNUMBER0002
|
||||||
|
+
|
||||||
|
+HTTP/1.1 200 OK
|
||||||
|
+Content-Length: 6
|
||||||
|
+Content-Type: text/html
|
||||||
|
+
|
||||||
|
+-muu-
|
||||||
|
+</datacheck>
|
||||||
|
+</reply>
|
||||||
|
+
|
||||||
|
+#
|
||||||
|
+# Client-side
|
||||||
|
+<client>
|
||||||
|
+<server>
|
||||||
|
+http
|
||||||
|
+</server>
|
||||||
|
+ <name>
|
||||||
|
+--path-as-is with redirect, keeping dotdots
|
||||||
|
+ </name>
|
||||||
|
+ <command>
|
||||||
|
+http://%HOSTIP:%HTTPPORT/../../%TESTNUMBER --path-as-is -L
|
||||||
|
+</command>
|
||||||
|
+</client>
|
||||||
|
+
|
||||||
|
+#
|
||||||
|
+# Verify data after the test has been "shot"
|
||||||
|
+<verify>
|
||||||
|
+<protocol>
|
||||||
|
+GET /../../%TESTNUMBER HTTP/1.1
|
||||||
|
+Host: %HOSTIP:%HTTPPORT
|
||||||
|
+User-Agent: curl/%VERSION
|
||||||
|
+Accept: */*
|
||||||
|
+
|
||||||
|
+GET /../%TESTNUMBER0002 HTTP/1.1
|
||||||
|
+Host: %HOSTIP:%HTTPPORT
|
||||||
|
+User-Agent: curl/%VERSION
|
||||||
|
+Accept: */*
|
||||||
|
+
|
||||||
|
+</protocol>
|
||||||
|
+</verify>
|
||||||
|
+</testcase>
|
||||||
|
--
|
||||||
|
2.33.0
|
||||||
|
|
||||||
117
backport-tool_getparam-clear-sensitive-arguments-better.patch
Normal file
117
backport-tool_getparam-clear-sensitive-arguments-better.patch
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
From 654f8cb5f353905c6eb5b2a6ef7e5beafa7d0634 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
Date: Wed, 19 Feb 2025 23:55:31 +0100
|
||||||
|
Subject: [PATCH] tool_getparam: clear sensitive arguments better
|
||||||
|
|
||||||
|
curl attempts to clear some flags to hide them from snooping neighbors
|
||||||
|
(on platforms where it works). For example the credentials provided with
|
||||||
|
-u. Previously it would only do that if there was a space between the
|
||||||
|
option and the credentials as in "-u joe:s3cr3t" but not when done
|
||||||
|
without a separating space as in "-ujoe:s3cr3t".
|
||||||
|
|
||||||
|
This addresses that previous shortcoming.
|
||||||
|
|
||||||
|
Reported-by: kayrus on github
|
||||||
|
Fixes #16396
|
||||||
|
Closes #16401
|
||||||
|
|
||||||
|
Conflict:context adapt
|
||||||
|
Reference:https://github.com/curl/curl/commit/654f8cb5f353905c6eb5b2a6ef7e5beafa7d0634
|
||||||
|
---
|
||||||
|
src/tool_getparam.c | 19 ++++++++++++------
|
||||||
|
src/tool_getparam.h | 3 ++-
|
||||||
|
src/tool_parsecfg.c | 3 ++-
|
||||||
|
3 files changed, 19 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
|
||||||
|
index f66124d40a27..6944059df740 100644
|
||||||
|
--- a/src/tool_getparam.c
|
||||||
|
+++ b/src/tool_getparam.c
|
||||||
|
@@ -1564,7 +1564,8 @@ static ParameterError parse_time_cond(struct GlobalConfig *global,
|
||||||
|
|
||||||
|
ParameterError getparameter(const char *flag, /* f or -long-flag */
|
||||||
|
char *nextarg, /* NULL if unset */
|
||||||
|
- argv_item_t cleararg,
|
||||||
|
+ argv_item_t cleararg1,
|
||||||
|
+ argv_item_t cleararg2,
|
||||||
|
bool *usedarg, /* set to TRUE if the arg
|
||||||
|
has been used */
|
||||||
|
struct GlobalConfig *global,
|
||||||
|
@@ -1590,6 +1591,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
|
||||||
|
by using --OPTION or --no-OPTION */
|
||||||
|
#ifdef HAVE_WRITABLE_ARGV
|
||||||
|
argv_item_t clearthis = NULL;
|
||||||
|
+#else
|
||||||
|
+ (void)cleararg1;
|
||||||
|
+ (void)cleararg2;
|
||||||
|
#endif
|
||||||
|
*usedarg = FALSE; /* default is that we don't use the arg */
|
||||||
|
|
||||||
|
@@ -1669,6 +1671,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
|
||||||
|
if(!longopt && parse[1]) {
|
||||||
|
nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
|
||||||
|
singleopt = TRUE; /* don't loop anymore after this */
|
||||||
|
+#ifdef HAVE_WRITABLE_ARGV
|
||||||
|
+ clearthis = &cleararg1[parse + 2 - flag];
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
else if(!nextarg)
|
||||||
|
return PARAM_REQUIRES_PARAMETER;
|
||||||
|
@@ -1676,7 +1681,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
|
||||||
|
return PARAM_REQUIRES_PARAMETER;
|
||||||
|
else {
|
||||||
|
#ifdef HAVE_WRITABLE_ARGV
|
||||||
|
- clearthis = cleararg;
|
||||||
|
+ clearthis = cleararg2;
|
||||||
|
#endif
|
||||||
|
*usedarg = TRUE; /* mark it as used */
|
||||||
|
}
|
||||||
|
@@ -2889,8 +2894,8 @@ ParameterError parse_args(struct GlobalConfig *global, int argc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- result = getparameter(orig_opt, nextarg, argv[i + 1], &passarg,
|
||||||
|
- global, config);
|
||||||
|
+ result = getparameter(orig_opt, nextarg, argv[i], argv[i + 1],
|
||||||
|
+ &passarg, global, config);
|
||||||
|
curlx_unicodefree(nextarg);
|
||||||
|
config = global->last;
|
||||||
|
if(result == PARAM_NEXT_OPERATION) {
|
||||||
|
@@ -2932,7 +2937,8 @@ ParameterError parse_args(struct GlobalConfig *global, int argc,
|
||||||
|
bool used;
|
||||||
|
|
||||||
|
/* Just add the URL please */
|
||||||
|
- result = getparameter("--url", orig_opt, argv[i], &used, global, config);
|
||||||
|
+ result = getparameter("--url", orig_opt, NULL, NULL,
|
||||||
|
+ &used, global, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!result)
|
||||||
|
diff --git a/src/tool_getparam.h b/src/tool_getparam.h
|
||||||
|
index beef191c66e8..bcfb35f0657e 100644
|
||||||
|
--- a/src/tool_getparam.h
|
||||||
|
+++ b/src/tool_getparam.h
|
||||||
|
@@ -361,7 +361,8 @@ const struct LongShort *findlongopt(const char *opt);
|
||||||
|
struct OperationConfig;
|
||||||
|
|
||||||
|
ParameterError getparameter(const char *flag, char *nextarg,
|
||||||
|
- argv_item_t cleararg,
|
||||||
|
+ argv_item_t cleararg1,
|
||||||
|
+ argv_item_t cleararg2,
|
||||||
|
bool *usedarg,
|
||||||
|
struct GlobalConfig *global,
|
||||||
|
struct OperationConfig *operation);
|
||||||
|
diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c
|
||||||
|
index 651ec8e9f401..b9fd56b300ba 100644
|
||||||
|
--- a/src/tool_parsecfg.c
|
||||||
|
+++ b/src/tool_parsecfg.c
|
||||||
|
@@ -190,7 +190,8 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
|
||||||
|
#ifdef DEBUG_CONFIG
|
||||||
|
fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
|
||||||
|
#endif
|
||||||
|
- res = getparameter(option, param, NULL, &usedarg, global, operation);
|
||||||
|
+ res = getparameter(option, param, NULL, NULL,
|
||||||
|
+ &usedarg, global, operation);
|
||||||
|
operation = global->last;
|
||||||
|
|
||||||
|
if(!res && param && *param && !usedarg)
|
||||||
@ -0,0 +1,238 @@
|
|||||||
|
From 66e5351e0adda5891b2ff17ccbafc81f620c0e01 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Stenberg <daniel@haxx.se>
|
||||||
|
Date: Sat, 28 Dec 2024 14:47:01 +0100
|
||||||
|
Subject: [PATCH] urlapi: fix redirect to a new fragment or query (only)
|
||||||
|
|
||||||
|
The redirect logic was broken when the redirect-to URL was a relative
|
||||||
|
URL only as a fragment or query (starting with '#' or '?').
|
||||||
|
|
||||||
|
Extended test 1560 to reproduce, then verify.
|
||||||
|
|
||||||
|
Reported-by: Jeroen Ooms
|
||||||
|
Fixes #15836
|
||||||
|
Closes #15848
|
||||||
|
|
||||||
|
Conflict:remove doc CURLOPT_PATH_AS_IS.md which is not exist
|
||||||
|
context adapt
|
||||||
|
Reference:https://github.com/curl/curl/commit/66e5351e0adda5891b2ff17ccbafc81f620c0e01
|
||||||
|
|
||||||
|
---
|
||||||
|
lib/urlapi.c | 102 ++++++------------------
|
||||||
|
tests/data/test391 | 2 +-
|
||||||
|
tests/libtest/lib1560.c | 32 +++++++
|
||||||
|
3 files changed, 60 insertions(+), 76 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/lib/urlapi.c b/lib/urlapi.c
|
||||||
|
index b676c4d..0f8ffbf 100644
|
||||||
|
--- a/lib/urlapi.c
|
||||||
|
+++ b/lib/urlapi.c
|
||||||
|
@@ -275,8 +275,6 @@ static char *concat_url(const char *base, const char *relurl)
|
||||||
|
problems in the future...
|
||||||
|
*/
|
||||||
|
char *newest;
|
||||||
|
- char *protsep;
|
||||||
|
- char *pathsep;
|
||||||
|
size_t newlen;
|
||||||
|
bool host_changed = FALSE;
|
||||||
|
|
||||||
|
@@ -291,66 +289,35 @@ static char *concat_url(const char *base, const char *relurl)
|
||||||
|
return NULL; /* skip out of this NOW */
|
||||||
|
|
||||||
|
/* protsep points to the start of the host name */
|
||||||
|
- protsep = strstr(url_clone, "//");
|
||||||
|
+ char *protsep = strstr(url_clone, "//");
|
||||||
|
+ DEBUGASSERT(protsep);
|
||||||
|
if(!protsep)
|
||||||
|
protsep = url_clone;
|
||||||
|
else
|
||||||
|
protsep += 2; /* pass the slashes */
|
||||||
|
|
||||||
|
- if('/' != relurl[0]) {
|
||||||
|
- int level = 0;
|
||||||
|
-
|
||||||
|
- /* First we need to find out if there's a ?-letter in the URL,
|
||||||
|
+ if(('/' != relurl[0]) && ('#' != relurl[0])) {
|
||||||
|
+ /* First we need to find out if there is a ?-letter in the original URL,
|
||||||
|
and cut it and the right-side of that off */
|
||||||
|
- pathsep = strchr(protsep, '?');
|
||||||
|
+ char *pathsep = strchr(protsep, '?');
|
||||||
|
if(pathsep)
|
||||||
|
*pathsep = 0;
|
||||||
|
-
|
||||||
|
- /* we have a relative path to append to the last slash if there's one
|
||||||
|
- available, or if the new URL is just a query string (starts with a
|
||||||
|
- '?') we append the new one at the end of the entire currently worked
|
||||||
|
- out URL */
|
||||||
|
- if(useurl[0] != '?') {
|
||||||
|
- pathsep = strrchr(protsep, '/');
|
||||||
|
+ else {
|
||||||
|
+ /* if not, cut off the potential fragment */
|
||||||
|
+ pathsep = strchr(protsep, '#');
|
||||||
|
if(pathsep)
|
||||||
|
*pathsep = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Check if there's any slash after the host name, and if so, remember
|
||||||
|
- that position instead */
|
||||||
|
- pathsep = strchr(protsep, '/');
|
||||||
|
- if(pathsep)
|
||||||
|
- protsep = pathsep + 1;
|
||||||
|
- else
|
||||||
|
- protsep = NULL;
|
||||||
|
-
|
||||||
|
- /* now deal with one "./" or any amount of "../" in the newurl
|
||||||
|
- and act accordingly */
|
||||||
|
-
|
||||||
|
- if((useurl[0] == '.') && (useurl[1] == '/'))
|
||||||
|
- useurl += 2; /* just skip the "./" */
|
||||||
|
-
|
||||||
|
- while((useurl[0] == '.') &&
|
||||||
|
- (useurl[1] == '.') &&
|
||||||
|
- (useurl[2] == '/')) {
|
||||||
|
- level++;
|
||||||
|
- useurl += 3; /* pass the "../" */
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if(protsep) {
|
||||||
|
- while(level--) {
|
||||||
|
- /* cut off one more level from the right of the original URL */
|
||||||
|
- pathsep = strrchr(protsep, '/');
|
||||||
|
- if(pathsep)
|
||||||
|
- *pathsep = 0;
|
||||||
|
- else {
|
||||||
|
- *protsep = 0;
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ /* if the redirect-to piece is not just a query, cut the path after the
|
||||||
|
+ last slash */
|
||||||
|
+ if(useurl[0] != '?') {
|
||||||
|
+ pathsep = strrchr(protsep, '/');
|
||||||
|
+ if(pathsep)
|
||||||
|
+ pathsep[1] = 0; /* leave the slash */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- else {
|
||||||
|
+ else if('/' == relurl[0]) {
|
||||||
|
/* We got a new absolute path for this server */
|
||||||
|
|
||||||
|
if(relurl[1] == '/') {
|
||||||
|
@@ -362,29 +329,20 @@ static char *concat_url(const char *base, const char *relurl)
|
||||||
|
host_changed = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
- /* cut off the original URL from the first slash, or deal with URLs
|
||||||
|
- without slash */
|
||||||
|
- pathsep = strchr(protsep, '/');
|
||||||
|
- if(pathsep) {
|
||||||
|
- /* When people use badly formatted URLs, such as
|
||||||
|
- "http://www.url.com?dir=/home/daniel" we must not use the first
|
||||||
|
- slash, if there's a ?-letter before it! */
|
||||||
|
- char *sep = strchr(protsep, '?');
|
||||||
|
- if(sep && (sep < pathsep))
|
||||||
|
- pathsep = sep;
|
||||||
|
+ /* cut the original URL at first slash */
|
||||||
|
+ char *pathsep = strchr(protsep, '/');
|
||||||
|
+ if(pathsep)
|
||||||
|
*pathsep = 0;
|
||||||
|
- }
|
||||||
|
- else {
|
||||||
|
- /* There was no slash. Now, since we might be operating on a badly
|
||||||
|
- formatted URL, such as "http://www.url.com?id=2380" which doesn't
|
||||||
|
- use a slash separator as it is supposed to, we need to check for a
|
||||||
|
- ?-letter as well! */
|
||||||
|
- pathsep = strchr(protsep, '?');
|
||||||
|
- if(pathsep)
|
||||||
|
- *pathsep = 0;
|
||||||
|
- }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ else {
|
||||||
|
+ /* the relative piece starts with '#' */
|
||||||
|
+
|
||||||
|
+ /* If there is a fragment in the original URL, cut it off */
|
||||||
|
+ char *pathsep = strchr(protsep, '#');
|
||||||
|
+ if(pathsep)
|
||||||
|
+ *pathsep = 0;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/* If the new part contains a space, this is a mighty stupid redirect
|
||||||
|
but we still make an effort to do "right". To the left of a '?'
|
||||||
|
@@ -406,12 +364,6 @@ static char *concat_url(const char *base, const char *relurl)
|
||||||
|
/* copy over the root url part */
|
||||||
|
memcpy(newest, url_clone, urllen);
|
||||||
|
|
||||||
|
- /* check if we need to append a slash */
|
||||||
|
- if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
|
||||||
|
- ;
|
||||||
|
- else
|
||||||
|
- newest[urllen++]='/';
|
||||||
|
-
|
||||||
|
/* then append the new piece on the right side */
|
||||||
|
strcpy_url(&newest[urllen], useurl, !host_changed);
|
||||||
|
|
||||||
|
@@ -1463,7 +1415,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||||
|
free(redired_url);
|
||||||
|
return CURLUE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
- result = parseurl(redired_url, handle2, flags);
|
||||||
|
+ result = parseurl(redired_url, handle2, flags&~CURLU_PATH_AS_IS);
|
||||||
|
free(redired_url);
|
||||||
|
if(!result)
|
||||||
|
mv_urlhandle(handle2, u);
|
||||||
|
diff --git a/tests/data/test391 b/tests/data/test391
|
||||||
|
index 24428a08f0f2..279c562de317 100644
|
||||||
|
--- a/tests/data/test391
|
||||||
|
+++ b/tests/data/test391
|
||||||
|
@@ -62,7 +62,7 @@ Host: %HOSTIP:%HTTPPORT
|
||||||
|
User-Agent: curl/%VERSION
|
||||||
|
Accept: */*
|
||||||
|
|
||||||
|
-GET /../%TESTNUMBER0002 HTTP/1.1
|
||||||
|
+GET /%TESTNUMBER0002 HTTP/1.1
|
||||||
|
Host: %HOSTIP:%HTTPPORT
|
||||||
|
User-Agent: curl/%VERSION
|
||||||
|
Accept: */*
|
||||||
|
diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c
|
||||||
|
index d5253a739a10..3103c69f2090 100644
|
||||||
|
--- a/tests/libtest/lib1560.c
|
||||||
|
+++ b/tests/libtest/lib1560.c
|
||||||
|
@@ -1143,6 +1143,38 @@ static CURLUcode updateurl(CURLU *u, const char *cmd, unsigned int setflags)
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct redircase set_url_list[] = {
|
||||||
|
+ {"http://example.org#withs/ash", "/moo#frag",
|
||||||
|
+ "http://example.org/moo#frag",
|
||||||
|
+ 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/", "../path/././../././../moo",
|
||||||
|
+ "http://example.org/moo",
|
||||||
|
+ 0, 0, CURLUE_OK},
|
||||||
|
+
|
||||||
|
+ {"http://example.org?bar/moo", "?weird",
|
||||||
|
+ "http://example.org/?weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/foo?bar", "?weird",
|
||||||
|
+ "http://example.org/foo?weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/foo", "?weird",
|
||||||
|
+ "http://example.org/foo?weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org", "?weird",
|
||||||
|
+ "http://example.org/?weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/#original", "?weird#moo",
|
||||||
|
+ "http://example.org/?weird#moo", 0, 0, CURLUE_OK},
|
||||||
|
+
|
||||||
|
+ {"http://example.org?bar/moo#yes/path", "#new/slash",
|
||||||
|
+ "http://example.org/?bar/moo#new/slash", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/foo?bar", "#weird",
|
||||||
|
+ "http://example.org/foo?bar#weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/foo?bar#original", "#weird",
|
||||||
|
+ "http://example.org/foo?bar#weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/foo#original", "#weird",
|
||||||
|
+ "http://example.org/foo#weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/#original", "#weird",
|
||||||
|
+ "http://example.org/#weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org#original", "#weird",
|
||||||
|
+ "http://example.org/#weird", 0, 0, CURLUE_OK},
|
||||||
|
+ {"http://example.org/foo?bar", "moo?hey#weird",
|
||||||
|
+ "http://example.org/moo?hey#weird", 0, 0, CURLUE_OK},
|
||||||
|
{"http://example.org/static/favicon/wikipedia.ico",
|
||||||
|
"//fake.example.com/licenses/by-sa/3.0/",
|
||||||
|
"http://fake.example.com/licenses/by-sa/3.0/",
|
||||||
46
curl.spec
46
curl.spec
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Name: curl
|
Name: curl
|
||||||
Version: 7.79.1
|
Version: 7.79.1
|
||||||
Release: 34
|
Release: 39
|
||||||
Summary: Curl is used in command lines or scripts to transfer data
|
Summary: Curl is used in command lines or scripts to transfer data
|
||||||
License: MIT
|
License: MIT
|
||||||
URL: https://curl.haxx.se/
|
URL: https://curl.haxx.se/
|
||||||
@ -109,6 +109,16 @@ Patch95: backport-CVE-2024-8096-gtls-fix-OCSP-stapling-management.patch
|
|||||||
Patch96: backport-url-allow-DoH-transfers-to-override-max-connection-limit.patch
|
Patch96: backport-url-allow-DoH-transfers-to-override-max-connection-limit.patch
|
||||||
Patch97: backport-CVE-2024-9681.patch
|
Patch97: backport-CVE-2024-9681.patch
|
||||||
Patch98: backport-multi-check-that-the-multi-handle-is-valid-in-curl_m.patch
|
Patch98: backport-multi-check-that-the-multi-handle-is-valid-in-curl_m.patch
|
||||||
|
Patch99: backport-cookie-treat-cookie-name-case-sensitively.patch
|
||||||
|
Patch100: backport-CVE-2024-11053.patch
|
||||||
|
Patch101: backport-CVE-2025-0167.patch
|
||||||
|
Patch102: backport-CVE-2025-0725.patch
|
||||||
|
Patch103: backport-altsvc-avoid-integer-overflow-in-expire-calculation.patch
|
||||||
|
Patch104: backport-test391-verify-path-as-is-with-redirect.patch
|
||||||
|
Patch105: backport-urlapi-fix-redirect-to-a-new-fragment-or-query-only-adapt.patch
|
||||||
|
Patch106: backport-tool_getparam-clear-sensitive-arguments-better.patch
|
||||||
|
Patch107: backport-libssh-fix-freeing-of-resources-in-disconnect.patch
|
||||||
|
Patch108: backport-openssl-fix-crash-on-missing-cert-password.patch
|
||||||
|
|
||||||
BuildRequires: automake brotli-devel coreutils gcc groff krb5-devel
|
BuildRequires: automake brotli-devel coreutils gcc groff krb5-devel
|
||||||
BuildRequires: libidn2-devel libnghttp2-devel libpsl-devel
|
BuildRequires: libidn2-devel libnghttp2-devel libpsl-devel
|
||||||
@ -277,6 +287,40 @@ rm -rf ${RPM_BUILD_ROOT}%{_libdir}/libcurl.la
|
|||||||
%{_mandir}/man3/*
|
%{_mandir}/man3/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue May 06 2025 zhouyihang <zhouyihang3@h-partners.com> - 7.79.1-39
|
||||||
|
- Type:bugfix
|
||||||
|
- CVE:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:libssh: fix freeing of resources in disconnect
|
||||||
|
openssl: fix crash on missing cert password
|
||||||
|
|
||||||
|
* Tue Mar 25 2025 xingwei <xingwei14@h-partners.com> - 7.79.1-38
|
||||||
|
- Type:bugfix
|
||||||
|
- CVE:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:altsvc: avoid integer overflow in expire calculation
|
||||||
|
test391: verify --path-as-is with redirect
|
||||||
|
urlapi: fix redirect to a new fragment or query (only)
|
||||||
|
tool_getparam: clear sensitive arguments better
|
||||||
|
|
||||||
|
* Sat Feb 08 2025 zhouyihang <zhouyihang3@h-partners.com> - 7.79.1-37
|
||||||
|
- Type:CVE
|
||||||
|
- CVE:CVE-2025-0167 CVE-2025-0725
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:fix CVE-2025-0167 CVE-2025-0725
|
||||||
|
|
||||||
|
* Fri Jan 03 2025 zhouyihang <zhouyihang3@h-partners.com> - 7.79.1-36
|
||||||
|
- Type:CVE
|
||||||
|
- CVE:CVE-2024-11053
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:fix CVE-2024-11053
|
||||||
|
|
||||||
|
* Mon Dec 09 2024 zhouyihang <zhouyihang3@h-partners.com> - 7.79.1-35
|
||||||
|
- Type:bugfix
|
||||||
|
- CVE:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:cookie: treat cookie name case sensitively
|
||||||
|
|
||||||
* Sat Nov 30 2024 zhouyihang <zhouyihang3@h-partners.com> - 7.79.1-34
|
* Sat Nov 30 2024 zhouyihang <zhouyihang3@h-partners.com> - 7.79.1-34
|
||||||
- Type:bugfix
|
- Type:bugfix
|
||||||
- CVE:NA
|
- CVE:NA
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user