summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2025-03-04 03:28:50 +0000
committerCoprDistGit <infra@openeuler.org>2025-03-04 03:28:50 +0000
commit510937df92473c5a6830d87f078386db8dbf896d (patch)
tree64d9befb90cb19890926aedd71df1a7a5452e08c
parentdbf64f99d0f0a31203092f9afdc6c07e13917313 (diff)
automatic import of curlopeneuler24.03_LTS_SP1
-rw-r--r--.gitignore1
-rw-r--r--backport-0001-CVE-2023-46219.patch133
-rw-r--r--backport-0002-CVE-2023-46219.patch80
-rw-r--r--backport-0101-curl-7.32.0-multilib.patch91
-rw-r--r--backport-CVE-2023-46218.patch54
-rw-r--r--backport-CVE-2024-11053-post1.patch37
-rw-r--r--backport-CVE-2024-11053-post2.patch129
-rw-r--r--backport-CVE-2024-11053-pre1.patch453
-rw-r--r--backport-CVE-2024-11053-pre2.patch800
-rw-r--r--backport-CVE-2024-11053-pre3.patch349
-rw-r--r--backport-CVE-2024-11053-pre4.patch223
-rw-r--r--backport-CVE-2024-11053-pre5.patch37
-rw-r--r--backport-CVE-2024-11053.patch728
-rw-r--r--backport-CVE-2024-2004.patch139
-rw-r--r--backport-CVE-2024-2398.patch96
-rw-r--r--backport-CVE-2024-7264-x509asn1-clean-up-GTime2str.patch60
-rw-r--r--backport-CVE-2024-7264-x509asn1-unittests-and-fixes-fo.patch315
-rw-r--r--backport-CVE-2024-8096-gtls-fix-OCSP-stapling-management.patch206
-rw-r--r--backport-CVE-2024-9681.patch82
-rw-r--r--backport-CVE-2025-0167.patch170
-rw-r--r--backport-CVE-2025-0725.patch324
-rw-r--r--backport-cookie-treat-cookie-name-case-sensitively.patch71
-rw-r--r--backport-curl-7.84.0-test3026.patch71
-rw-r--r--backport-curl-7.88.0-tests-warnings.patch30
-rw-r--r--backport-libssh2-set-length-to-0-if-strdup-failed.patch31
-rw-r--r--backport-multi-avoid-memory-leak-risk.patch46
-rw-r--r--backport-multi-check-that-the-multi-handle-is-valid-in-curl_m.patch37
-rw-r--r--backport-openldap-create-ldap-URLs-correctly-for-IPv6-addresses.patch35
-rw-r--r--backport-openssl-avoid-BN_num_bits-NULL-pointer-derefs.patch34
-rw-r--r--backport-paramhlp-fix-CRLF-stripping-files-with-d-file.patch100
-rw-r--r--backport-pre-CVE-2024-2004.patch159
-rw-r--r--backport-pre-CVE-2024-9681.patch69
-rw-r--r--backport-tool_cb_rea-limit-rate-unpause-for-T-uploads.patch61
-rw-r--r--backport-tool_cfgable-free-proxy_-cipher13_list-on-exit.patch28
-rw-r--r--backport-url-allow-DoH-transfers-to-override-max-connection-limit.patch49
-rw-r--r--curl.spec570
-rw-r--r--sources1
37 files changed, 5899 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..88e50a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/curl-8.4.0.tar.xz
diff --git a/backport-0001-CVE-2023-46219.patch b/backport-0001-CVE-2023-46219.patch
new file mode 100644
index 0000000..2e2ae77
--- /dev/null
+++ b/backport-0001-CVE-2023-46219.patch
@@ -0,0 +1,133 @@
+From 73b65e94f3531179de45c6f3c836a610e3d0a846 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Thu, 23 Nov 2023 08:23:17 +0100
+Subject: [PATCH] fopen: create short(er) temporary file name
+
+Only using random letters in the name plus a ".tmp" extension. Not by
+appending characters to the final file name.
+
+Reported-by: Maksymilian Arciemowicz
+
+Closes #12388
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/73b65e94f3531179de45c6f3c836a610e3d0a846
+---
+ lib/fopen.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 60 insertions(+), 5 deletions(-)
+
+diff --git a/lib/fopen.c b/lib/fopen.c
+index 75b8a7aa5..a73ac068e 100644
+--- a/lib/fopen.c
++++ b/lib/fopen.c
+@@ -39,6 +39,51 @@
+ #include "curl_memory.h"
+ #include "memdebug.h"
+
++/*
++ The dirslash() function breaks a null-terminated pathname string into
++ directory and filename components then returns the directory component up
++ to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
++ this instead returns a "" string.
++
++ This function returns a pointer to malloc'ed memory.
++
++ The input path to this function is expected to have a file name part.
++*/
++
++#ifdef _WIN32
++#define PATHSEP "\\"
++#define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
++#elif defined(MSDOS) || defined(__EMX__) || defined(OS2)
++#define PATHSEP "\\"
++#define IS_SEP(x) ((x) == '\\')
++#else
++#define PATHSEP "/"
++#define IS_SEP(x) ((x) == '/')
++#endif
++
++static char *dirslash(const char *path)
++{
++ size_t n;
++ struct dynbuf out;
++ DEBUGASSERT(path);
++ Curl_dyn_init(&out, CURL_MAX_INPUT_LENGTH);
++ n = strlen(path);
++ if(n) {
++ /* find the rightmost path separator, if any */
++ while(n && !IS_SEP(path[n-1]))
++ --n;
++ /* skip over all the path separators, if any */
++ while(n && IS_SEP(path[n-1]))
++ --n;
++ }
++ if(Curl_dyn_addn(&out, path, n))
++ return NULL;
++ /* if there was a directory, append a single trailing slash */
++ if(n && Curl_dyn_addn(&out, PATHSEP, 1))
++ return NULL;
++ return Curl_dyn_ptr(&out);
++}
++
+ /*
+ * Curl_fopen() opens a file for writing with a temp name, to be renamed
+ * to the final name when completed. If there is an existing file using this
+@@ -50,25 +95,34 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
+ FILE **fh, char **tempname)
+ {
+ CURLcode result = CURLE_WRITE_ERROR;
+- unsigned char randsuffix[9];
++ unsigned char randbuf[41];
+ char *tempstore = NULL;
+ struct_stat sb;
+ int fd = -1;
++ char *dir;
+ *tempname = NULL;
+
++ dir = dirslash(filename);
++ if(!dir)
++ goto fail;
++
+ *fh = fopen(filename, FOPEN_WRITETEXT);
+ if(!*fh)
+ goto fail;
+- if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode))
++ if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) {
++ free(dir);
+ return CURLE_OK;
++ }
+ fclose(*fh);
+ *fh = NULL;
+
+- result = Curl_rand_alnum(data, randsuffix, sizeof(randsuffix));
++ result = Curl_rand_alnum(data, randbuf, sizeof(randbuf));
+ if(result)
+ goto fail;
+
+- tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
++ /* The temp file name should not end up too long for the target file
++ system */
++ tempstore = aprintf("%s%s.tmp", dir, randbuf);
+ if(!tempstore) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto fail;
+@@ -95,6 +149,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
+ if(!*fh)
+ goto fail;
+
++ free(dir);
+ *tempname = tempstore;
+ return CURLE_OK;
+
+@@ -105,7 +160,7 @@ fail:
+ }
+
+ free(tempstore);
+-
++ free(dir);
+ return result;
+ }
+
+--
+2.33.0
+
diff --git a/backport-0002-CVE-2023-46219.patch b/backport-0002-CVE-2023-46219.patch
new file mode 100644
index 0000000..c9c08ec
--- /dev/null
+++ b/backport-0002-CVE-2023-46219.patch
@@ -0,0 +1,80 @@
+From f27b8dba73295cb5296a50f2c19c0739b502eb94 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Fri, 24 Nov 2023 09:46:32 +0100
+Subject: [PATCH] fopen: allocate the dir after fopen
+
+Move the allocation of the directory name down to after the fopen() call
+to allow that shortcut code path to avoid a superfluous malloc+free
+cycle.
+
+Follow-up to 73b65e94f35311
+
+Closes #12398
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/f27b8dba73295cb5296a50f2c19c0739b502eb94
+---
+ lib/fopen.c | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+diff --git a/lib/fopen.c b/lib/fopen.c
+index 2e726cc95..851279fe1 100644
+--- a/lib/fopen.c
++++ b/lib/fopen.c
+@@ -99,18 +99,13 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
+ char *tempstore = NULL;
+ struct_stat sb;
+ int fd = -1;
+- char *dir;
++ char *dir = NULL;
+ *tempname = NULL;
+
+- dir = dirslash(filename);
+- if(!dir)
+- goto fail;
+-
+ *fh = fopen(filename, FOPEN_WRITETEXT);
+ if(!*fh)
+ goto fail;
+ if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) {
+- free(dir);
+ return CURLE_OK;
+ }
+ fclose(*fh);
+@@ -120,9 +115,14 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
+ if(result)
+ goto fail;
+
+- /* The temp file name should not end up too long for the target file
+- system */
+- tempstore = aprintf("%s%s.tmp", dir, randbuf);
++ dir = dirslash(filename);
++ if(dir) {
++ /* The temp file name should not end up too long for the target file
++ system */
++ tempstore = aprintf("%s%s.tmp", dir, randbuf);
++ free(dir);
++ }
++
+ if(!tempstore) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto fail;
+@@ -137,7 +137,6 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
+ if(!*fh)
+ goto fail;
+
+- free(dir);
+ *tempname = tempstore;
+ return CURLE_OK;
+
+@@ -148,7 +147,6 @@ fail:
+ }
+
+ free(tempstore);
+- free(dir);
+ return result;
+ }
+
+--
+2.33.0
+
diff --git a/backport-0101-curl-7.32.0-multilib.patch b/backport-0101-curl-7.32.0-multilib.patch
new file mode 100644
index 0000000..b4f8e2a
--- /dev/null
+++ b/backport-0101-curl-7.32.0-multilib.patch
@@ -0,0 +1,91 @@
+From 2a4754a3a7cf60ecc36d83cbe50b8c337cb87632 Mon Sep 17 00:00:00 2001
+From: Kamil Dudka <kdudka@redhat.com>
+Date: Fri, 12 Apr 2013 12:04:05 +0200
+Subject: [PATCH] prevent multilib conflicts on the curl-config script
+
+---
+ curl-config.in | 23 +++++------------------
+ docs/curl-config.1 | 4 +++-
+ libcurl.pc.in | 1 +
+ 3 files changed, 9 insertions(+), 19 deletions(-)
+
+diff --git a/curl-config.in b/curl-config.in
+index 150004d..95d0759 100644
+--- a/curl-config.in
++++ b/curl-config.in
+@@ -78,7 +78,7 @@ while test $# -gt 0; do
+ ;;
+
+ --cc)
+- echo "@CC@"
++ echo "gcc"
+ ;;
+
+ --prefix)
+@@ -157,32 +157,19 @@ while test $# -gt 0; do
+ ;;
+
+ --libs)
+- if test "X@libdir@" != "X/usr/lib" -a "X@libdir@" != "X/usr/lib64"; then
+- CURLLIBDIR="-L@libdir@ "
+- else
+- CURLLIBDIR=""
+- fi
+- if test "X@ENABLE_SHARED@" = "Xno"; then
+- echo ${CURLLIBDIR}-lcurl @LIBCURL_LIBS@
+- else
+- echo ${CURLLIBDIR}-lcurl
+- fi
++ echo -lcurl
+ ;;
+ --ssl-backends)
+ echo "@SSL_BACKENDS@"
+ ;;
+
+ --static-libs)
+- if test "X@ENABLE_STATIC@" != "Xno" ; then
+- echo "@libdir@/libcurl.@libext@" @LDFLAGS@ @LIBCURL_LIBS@
+- else
+- echo "curl was built with static libraries disabled" >&2
+- exit 1
+- fi
++ echo "curl was built with static libraries disabled" >&2
++ exit 1
+ ;;
+
+ --configure)
+- echo @CONFIGURE_OPTIONS@
++ pkg-config libcurl --variable=configure_options | sed 's/^"//;s/"$//'
+ ;;
+
+ *)
+diff --git a/docs/curl-config.1 b/docs/curl-config.1
+index 14a9d2b..ffcc004 100644
+--- a/docs/curl-config.1
++++ b/docs/curl-config.1
+@@ -72,7 +72,9 @@ no, one or several names. If more than one name, they will appear
+ comma-separated. (Added in 7.58.0)
+ .IP "--static-libs"
+ Shows the complete set of libs and other linker options you will need in order
+-to link your application with libcurl statically. (Added in 7.17.1)
++to link your application with libcurl statically. Note that Fedora/RHEL libcurl
++packages do not provide any static libraries, thus cannot be linked statically.
++(Added in 7.17.1)
+ .IP "--version"
+ Outputs version information about the installed libcurl.
+ .IP "--vernum"
+diff --git a/libcurl.pc.in b/libcurl.pc.in
+index 2ba9c39..f8f8b00 100644
+--- a/libcurl.pc.in
++++ b/libcurl.pc.in
+@@ -31,6 +31,7 @@ libdir=@libdir@
+ includedir=@includedir@
+ supported_protocols="@SUPPORT_PROTOCOLS@"
+ supported_features="@SUPPORT_FEATURES@"
++configure_options=@CONFIGURE_OPTIONS@
+
+ Name: libcurl
+ URL: https://curl.se/
+--
+2.26.2
+
diff --git a/backport-CVE-2023-46218.patch b/backport-CVE-2023-46218.patch
new file mode 100644
index 0000000..8158814
--- /dev/null
+++ b/backport-CVE-2023-46218.patch
@@ -0,0 +1,54 @@
+From 2b0994c29a721c91c572cff7808c572a24d251eb Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Thu, 23 Nov 2023 08:15:47 +0100
+Subject: [PATCH] cookie: lowercase the domain names before PSL checks
+
+Reported-by: Harry Sintonen
+
+Closes #12387
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/2b0994c29a721c91c572cff7808c572a24d251eb
+---
+ lib/cookie.c | 24 ++++++++++++++++--------
+ 1 file changed, 16 insertions(+), 8 deletions(-)
+
+diff --git a/lib/cookie.c b/lib/cookie.c
+index 568cf537a..9095cea3e 100644
+--- a/lib/cookie.c
++++ b/lib/cookie.c
+@@ -1027,15 +1027,23 @@ Curl_cookie_add(struct Curl_easy *data,
+ * dereference it.
+ */
+ if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
+- const psl_ctx_t *psl = Curl_psl_use(data);
+- int acceptable;
+-
+- if(psl) {
+- acceptable = psl_is_cookie_domain_acceptable(psl, domain, co->domain);
+- Curl_psl_release(data);
++ bool acceptable = FALSE;
++ char lcase[256];
++ char lcookie[256];
++ size_t dlen = strlen(domain);
++ size_t clen = strlen(co->domain);
++ if((dlen < sizeof(lcase)) && (clen < sizeof(lcookie))) {
++ const psl_ctx_t *psl = Curl_psl_use(data);
++ if(psl) {
++ /* the PSL check requires lowercase domain name and pattern */
++ Curl_strntolower(lcase, domain, dlen + 1);
++ Curl_strntolower(lcookie, co->domain, clen + 1);
++ acceptable = psl_is_cookie_domain_acceptable(psl, lcase, lcookie);
++ Curl_psl_release(data);
++ }
++ else
++ acceptable = !bad_domain(domain, strlen(domain));
+ }
+- else
+- acceptable = !bad_domain(domain, strlen(domain));
+
+ if(!acceptable) {
+ infof(data, "cookie '%s' dropped, domain '%s' must not "
+--
+2.33.0
+
diff --git a/backport-CVE-2024-11053-post1.patch b/backport-CVE-2024-11053-post1.patch
new file mode 100644
index 0000000..1d69ba5
--- /dev/null
+++ b/backport-CVE-2024-11053-post1.patch
@@ -0,0 +1,37 @@
+From 4b07b7ebadfbff1d26622719b9048673a78f0bf0 Mon Sep 17 00:00:00 2001
+From: Viktor Szakats <commit@vsz.me>
+Date: Sun, 17 Nov 2024 12:46:25 +0100
+Subject: [PATCH] netrc: fix pointer to bool conversion
+
+with MSVC 2008 and 2010:
+```
+lib/netrc.c(107): error C2440: 'initializing' : cannot convert from 'char *' to 'bool'
+```
+Ref: https://ci.appveyor.com/project/curlorg/curl/builds/51002792/job/jtoxd4mk984oi6fd#L164
+Ref: https://ci.appveyor.com/project/curlorg/curl/builds/51002792/job/0wxlw9a8g04e56vt#L177
+
+Follow-up to e9b9bbac22c26cf67316fa8e6c6b9e831af31949 #15586
+Closes #15601
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/4b07b7ebadfbff1d26622719b9048673a78f0bf0
+---
+ lib/netrc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/netrc.c b/lib/netrc.c
+index e787a6ffc..d5ee3c0fd 100644
+--- a/lib/netrc.c
++++ b/lib/netrc.c
+@@ -104,7 +104,7 @@ static int parsenetrc(struct store_netrc *store,
+ int retcode = NETRC_FILE_MISSING;
+ char *login = *loginp;
+ char *password = NULL;
+- bool specific_login = login; /* points to something */
++ bool specific_login = !!login; /* points to something */
+ enum host_lookup_state state = NOTHING;
+ enum found_state keyword = NONE;
+ unsigned char found = 0; /* login + password found bits, as they can come in
+--
+2.33.0
+
diff --git a/backport-CVE-2024-11053-post2.patch b/backport-CVE-2024-11053-post2.patch
new file mode 100644
index 0000000..2b9fd4e
--- /dev/null
+++ b/backport-CVE-2024-11053-post2.patch
@@ -0,0 +1,129 @@
+From 9fce2c55d4b0273ac99b59bd8cb982a6d96b88cf Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 17 Dec 2024 23:56:42 +0100
+Subject: [PATCH] netrc: fix password-only entries
+
+When a specific hostname matched, and only a password is set before
+another machine is specified in the netrc file, the parser would not be
+happy and stop there and return the password-only state. It instead
+continued and did not return a match.
+
+Add test 2005 to verify this case
+
+Regression from e9b9bba, shipped in 8.11.1.
+
+Reported-by: Ben Zanin
+Fixes #15767
+Closes #15768
+
+Conflict:context adapt
+Reference:https://github.com/curl/curl/commit/9fce2c55d4b0273ac99b59bd8cb982a6d96b88cf
+---
+ lib/netrc.c | 7 +++++-
+ tests/data/Makefile.inc | 2 +-
+ tests/data/test2005 | 55 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 62 insertions(+), 2 deletions(-)
+ create mode 100644 tests/data/test2005
+
+diff --git a/lib/netrc.c b/lib/netrc.c
+index cbc86484f..b517c1dfa 100644
+--- a/lib/netrc.c
++++ b/lib/netrc.c
+@@ -267,7 +267,8 @@ static int parsenetrc(struct store_netrc *store,
+ retcode = NETRC_FAILED; /* allocation failed */
+ goto out;
+ }
+- found |= FOUND_PASSWORD;
++ if(!specific_login || our_login)
++ found |= FOUND_PASSWORD;
+ keyword = NONE;
+ }
+ else if(strcasecompare("login", tok))
+@@ -276,6 +277,10 @@ static int parsenetrc(struct store_netrc *store,
+ keyword = PASSWORD;
+ else if(strcasecompare("machine", tok)) {
+ /* a new machine here */
++ if(found & FOUND_PASSWORD) {
++ done = TRUE;
++ break;
++ }
+ state = HOSTFOUND;
+ keyword = NONE;
+ found = 0;
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index bd9a0bbaa..105108309 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -238,7 +238,7 @@ test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \
+ test1955 test1956 test1957 test1958 test1959 test1960 test1964 \
+ test1970 test1971 test1972 test1973 test1974 test1975 \
+ \
+-test2000 test2001 test2002 test2003 test2004 \
++test2000 test2001 test2002 test2003 test2004 test2005 \
+ \
+ test2023 \
+ test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \
+diff --git a/tests/data/test2005 b/tests/data/test2005
+new file mode 100644
+index 000000000..91e256298
+--- /dev/null
++++ b/tests/data/test2005
+@@ -0,0 +1,55 @@
++<testcase>
++<info>
++<keywords>
++HTTP
++netrc
++</keywords>
++</info>
++#
++# Server-side
++<reply>
++<data>
++HTTP/1.1 200 OK
++Date: Fri, 05 Aug 2022 10:09:00 GMT
++Server: test-server/fake
++Content-Type: text/plain
++Content-Length: 6
++Connection: close
++
++-foo-
++</data>
++</reply>
++
++#
++# Client-side
++<client>
++<server>
++http
++</server>
++<name>
++netrc match with password only in file, no username. machine follows
++</name>
++<command>
++--netrc-optional --netrc-file %LOGDIR/netrc%TESTNUMBER http://%HOSTIP:%HTTPPORT/
++</command>
++<file name="%LOGDIR/netrc%TESTNUMBER" >
++machine %HOSTIP
++password 5up3r53cr37
++
++machine example.com
++</file>
++</client>
++
++#
++# Verify data after the test has been "shot"
++<verify>
++<protocol>
++GET / HTTP/1.1
++Host: %HOSTIP:%HTTPPORT
++Authorization: Basic %b64[:5up3r53cr37]b64%
++User-Agent: curl/%VERSION
++Accept: */*
++
++</protocol>
++</verify>
++</testcase>
+--
+2.33.0
+
diff --git a/backport-CVE-2024-11053-pre1.patch b/backport-CVE-2024-11053-pre1.patch
new file mode 100644
index 0000000..1a55294
--- /dev/null
+++ b/backport-CVE-2024-11053-pre1.patch
@@ -0,0 +1,453 @@
+From 142ac257b3242459b284020c59f1902b9687a954 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 6 Feb 2024 10:15:52 +0100
+Subject: [PATCH] lib: convert Curl_get_line to use dynbuf
+
+Create the line in a dynbuf. Aborts the reading of the file on
+errors. Avoids having to always allocate maximum amount from the
+start. Avoids direct malloc.
+
+Closes #12846
+
+Conflict:context adapt
+Reference:https://github.com/curl/curl/commit/142ac257b3242459b284020c59f1902b9687a954
+---
+ lib/altsvc.c | 18 +++-------
+ lib/cookie.c | 29 ++++------------
+ lib/curl_get_line.c | 55 +++++++++++++----------------
+ lib/curl_get_line.h | 7 ++--
+ lib/hsts.c | 17 +++------
+ lib/netrc.c | 10 ++++--
+ tests/unit/unit3200.c | 80 ++++++++++++++++++++++++-------------------
+ 7 files changed, 96 insertions(+), 120 deletions(-)
+
+diff --git a/lib/altsvc.c b/lib/altsvc.c
+index e9f62bf0e..c12d7bda1 100644
+--- a/lib/altsvc.c
++++ b/lib/altsvc.c
+@@ -209,7 +209,6 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
+ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
+ {
+ CURLcode result = CURLE_OK;
+- char *line = NULL;
+ FILE *fp;
+
+ /* we need a private copy of the file name so that the altsvc cache file
+@@ -221,11 +220,10 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
+
+ fp = fopen(file, FOPEN_READTEXT);
+ if(fp) {
+- line = malloc(MAX_ALTSVC_LINE);
+- if(!line)
+- goto fail;
+- while(Curl_get_line(line, MAX_ALTSVC_LINE, fp)) {
+- char *lineptr = line;
++ struct dynbuf buf;
++ Curl_dyn_init(&buf, MAX_ALTSVC_LINE);
++ while(Curl_get_line(&buf, fp)) {
++ char *lineptr = Curl_dyn_ptr(&buf);
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+ if(*lineptr == '#')
+@@ -234,16 +232,10 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
+
+ altsvc_add(asi, lineptr);
+ }
+- free(line); /* free the line buffer */
++ Curl_dyn_free(&buf); /* free the line buffer */
+ fclose(fp);
+ }
+ return result;
+-
+-fail:
+- Curl_safefree(asi->filename);
+- free(line);
+- fclose(fp);
+- return CURLE_OUT_OF_MEMORY;
+ }
+
+ /*
+diff --git a/lib/cookie.c b/lib/cookie.c
+index dc319b611..d10dd572b 100644
+--- a/lib/cookie.c
++++ b/lib/cookie.c
+@@ -1205,7 +1205,6 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+ bool newsession)
+ {
+ struct CookieInfo *c;
+- char *line = NULL;
+ FILE *handle = NULL;
+
+ if(!inc) {
+@@ -1241,16 +1240,14 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+
+ c->running = FALSE; /* this is not running, this is init */
+ if(fp) {
+-
+- line = malloc(MAX_COOKIE_LINE);
+- if(!line)
+- goto fail;
+- while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) {
+- char *lineptr = line;
++ struct dynbuf buf;
++ Curl_dyn_init(&buf, MAX_COOKIE_LINE);
++ while(Curl_get_line(&buf, fp)) {
++ char *lineptr = Curl_dyn_ptr(&buf);
+ bool headerline = FALSE;
+- if(checkprefix("Set-Cookie:", line)) {
++ if(checkprefix("Set-Cookie:", lineptr)) {
+ /* This is a cookie line, get it! */
+- lineptr = &line[11];
++ lineptr += 11;
+ headerline = TRUE;
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+@@ -1258,7 +1255,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+
+ Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
+ }
+- free(line); /* free the line buffer */
++ Curl_dyn_free(&buf); /* free the line buffer */
+
+ /*
+ * Remove expired cookies from the hash. We must make sure to run this
+@@ -1274,18 +1271,6 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+ c->running = TRUE; /* now, we're running */
+
+ return c;
+-
+-fail:
+- free(line);
+- /*
+- * Only clean up if we allocated it here, as the original could still be in
+- * use by a share handle.
+- */
+- if(!inc)
+- Curl_cookie_cleanup(c);
+- if(handle)
+- fclose(handle);
+- return NULL; /* out of memory */
+ }
+
+ /*
+diff --git a/lib/curl_get_line.c b/lib/curl_get_line.c
+index 686abe751..100207331 100644
+--- a/lib/curl_get_line.c
++++ b/lib/curl_get_line.c
+@@ -33,14 +33,16 @@
+ #include "memdebug.h"
+
+ /*
+- * Curl_get_line() makes sure to only return complete whole lines that fit in
+- * 'len' bytes and end with a newline.
++ * Curl_get_line() makes sure to only return complete whole lines that end
++ * newlines.
+ */
+-char *Curl_get_line(char *buf, int len, FILE *input)
++int Curl_get_line(struct dynbuf *buf, FILE *input)
+ {
+- bool partial = FALSE;
++ CURLcode result;
++ char buffer[128];
++ Curl_dyn_reset(buf);
+ while(1) {
+- char *b = fgets(buf, len, input);
++ char *b = fgets(buffer, sizeof(buffer), input);
+
+ if(b) {
+ size_t rlen = strlen(b);
+@@ -48,39 +50,28 @@ char *Curl_get_line(char *buf, int len, FILE *input)
+ if(!rlen)
+ break;
+
+- if(b[rlen-1] == '\n') {
+- /* b is \n terminated */
+- if(partial) {
+- partial = FALSE;
+- continue;
+- }
+- return b;
+- }
+- else if(feof(input)) {
+- if(partial)
+- /* Line is already too large to return, ignore rest */
+- break;
++ result = Curl_dyn_addn(buf, b, rlen);
++ if(result)
++ /* too long line or out of memory */
++ return 0; /* error */
+
+- if(rlen + 1 < (size_t) len) {
+- /* b is EOF terminated, insert missing \n */
+- b[rlen] = '\n';
+- b[rlen + 1] = '\0';
+- return b;
+- }
+- else
+- /* Maximum buffersize reached + EOF
+- * This line is impossible to add a \n to so we'll ignore it
+- */
+- break;
++ else if(b[rlen-1] == '\n')
++ /* end of the line */
++ return 1; /* all good */
++
++ else if(feof(input)) {
++ /* append a newline */
++ result = Curl_dyn_addn(buf, "\n", 1);
++ if(result)
++ /* too long line or out of memory */
++ return 0; /* error */
++ return 1; /* all good */
+ }
+- else
+- /* Maximum buffersize reached */
+- partial = TRUE;
+ }
+ else
+ break;
+ }
+- return NULL;
++ return 0;
+ }
+
+ #endif /* if not disabled */
+diff --git a/lib/curl_get_line.h b/lib/curl_get_line.h
+index 0ff32c5c2..7907cde88 100644
+--- a/lib/curl_get_line.h
++++ b/lib/curl_get_line.h
+@@ -24,8 +24,9 @@
+ *
+ ***************************************************************************/
+
+-/* get_line() makes sure to only return complete whole lines that fit in 'len'
+- * bytes and end with a newline. */
+-char *Curl_get_line(char *buf, int len, FILE *input);
++#include "dynbuf.h"
++
++/* Curl_get_line() returns complete lines that end with a newline. */
++int Curl_get_line(struct dynbuf *buf, FILE *input);
+
+ #endif /* HEADER_CURL_GET_LINE_H */
+diff --git a/lib/hsts.c b/lib/hsts.c
+index 8725a35c1..607755e6b 100644
+--- a/lib/hsts.c
++++ b/lib/hsts.c
+@@ -511,7 +511,6 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
+ static CURLcode hsts_load(struct hsts *h, const char *file)
+ {
+ CURLcode result = CURLE_OK;
+- char *line = NULL;
+ FILE *fp;
+
+ /* we need a private copy of the file name so that the hsts cache file
+@@ -523,11 +522,10 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
+
+ fp = fopen(file, FOPEN_READTEXT);
+ if(fp) {
+- line = malloc(MAX_HSTS_LINE);
+- if(!line)
+- goto fail;
+- while(Curl_get_line(line, MAX_HSTS_LINE, fp)) {
+- char *lineptr = line;
++ struct dynbuf buf;
++ Curl_dyn_init(&buf, MAX_HSTS_LINE);
++ while(Curl_get_line(&buf, fp)) {
++ char *lineptr = Curl_dyn_ptr(&buf);
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+ if(*lineptr == '#')
+@@ -536,15 +534,10 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
+
+ hsts_add(h, lineptr);
+ }
+- free(line); /* free the line buffer */
++ Curl_dyn_free(&buf); /* free the line buffer */
+ fclose(fp);
+ }
+ return result;
+-
+-fail:
+- Curl_safefree(h->filename);
+- fclose(fp);
+- return CURLE_OUT_OF_MEMORY;
+ }
+
+ /*
+diff --git a/lib/netrc.c b/lib/netrc.c
+index 038c6dca6..cd2a2844e 100644
+--- a/lib/netrc.c
++++ b/lib/netrc.c
+@@ -53,6 +53,8 @@ enum host_lookup_state {
+ #define NETRC_FAILED -1
+ #define NETRC_SUCCESS 0
+
++#define MAX_NETRC_LINE 4096
++
+ /*
+ * Returns zero on success.
+ */
+@@ -80,13 +82,14 @@ static int parsenetrc(const char *host,
+ file = fopen(netrcfile, FOPEN_READTEXT);
+ if(file) {
+ bool done = FALSE;
+- char netrcbuffer[4096];
+- int netrcbuffsize = (int)sizeof(netrcbuffer);
++ struct dynbuf buf;
++ Curl_dyn_init(&buf, MAX_NETRC_LINE);
+
+- while(!done && Curl_get_line(netrcbuffer, netrcbuffsize, file)) {
++ while(!done && Curl_get_line(&buf, file)) {
+ char *tok;
+ char *tok_end;
+ bool quoted;
++ char *netrcbuffer = Curl_dyn_ptr(&buf);
+ if(state == MACDEF) {
+ if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
+ state = NOTHING;
+@@ -245,6 +248,7 @@ static int parsenetrc(const char *host,
+ } /* while Curl_get_line() */
+
+ out:
++ Curl_dyn_free(&buf);
+ if(!retcode) {
+ /* success */
+ if(login_alloc) {
+diff --git a/tests/unit/unit3200.c b/tests/unit/unit3200.c
+index 0544bcc93..6f508ce07 100644
+--- a/tests/unit/unit3200.c
++++ b/tests/unit/unit3200.c
+@@ -69,7 +69,7 @@ static const char *filecontents[] = {
+ "LINE1\n"
+ C4096 "SOME EXTRA TEXT",
+
+- /* First and third line should be read */
++ /* Only first should be read */
+ "LINE1\n"
+ C4096 "SOME EXTRA TEXT\n"
+ "LINE3\n",
+@@ -84,11 +84,13 @@ static const char *filecontents[] = {
+
+ UNITTEST_START
+ size_t i;
++ int rc = 0;
+ for(i = 0; i < NUMTESTS; i++) {
+ FILE *fp;
+- char buf[4096];
++ struct dynbuf buf;
+ int len = 4096;
+ char *line;
++ Curl_dyn_init(&buf, len);
+
+ fp = fopen(arg, "wb");
+ abort_unless(fp != NULL, "Cannot open testfile");
+@@ -101,65 +103,73 @@ UNITTEST_START
+ fprintf(stderr, "Test %zd...", i);
+ switch(i) {
+ case 0:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (1)");
+- line = Curl_get_line(buf, len, fp);
++ "First line failed (1)");
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE2 NEWLINE\n", line),
+- "Second line failed (1)");
+- line = Curl_get_line(buf, len, fp);
+- abort_unless(line == NULL, "Missed EOF (1)");
++ "Second line failed (1)");
++ rc = Curl_get_line(&buf, fp);
++ abort_unless(!Curl_dyn_len(&buf), "Missed EOF (1)");
+ break;
+ case 1:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (2)");
+- line = Curl_get_line(buf, len, fp);
++ "First line failed (2)");
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE2 NONEWLINE\n", line),
+- "Second line failed (2)");
+- line = Curl_get_line(buf, len, fp);
+- abort_unless(line == NULL, "Missed EOF (2)");
++ "Second line failed (2)");
++ rc = Curl_get_line(&buf, fp);
++ abort_unless(!Curl_dyn_len(&buf), "Missed EOF (2)");
+ break;
+ case 2:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (3)");
+- line = Curl_get_line(buf, len, fp);
+- fail_unless(line == NULL,
+- "Did not detect max read on EOF (3)");
++ "First line failed (3)");
++ rc = Curl_get_line(&buf, fp);
++ fail_unless(!Curl_dyn_len(&buf),
++ "Did not detect max read on EOF (3)");
+ break;
+ case 3:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (4)");
+- line = Curl_get_line(buf, len, fp);
+- fail_unless(line == NULL,
+- "Did not ignore partial on EOF (4)");
++ "First line failed (4)");
++ rc = Curl_get_line(&buf, fp);
++ fail_unless(!Curl_dyn_len(&buf),
++ "Did not ignore partial on EOF (4)");
+ break;
+ case 4:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (5)");
+- line = Curl_get_line(buf, len, fp);
+- fail_unless(line && !strcmp("LINE3\n", line),
+- "Third line failed (5)");
+- line = Curl_get_line(buf, len, fp);
+- abort_unless(line == NULL, "Missed EOF (5)");
++ "First line failed (5)");
++ rc = Curl_get_line(&buf, fp);
++ fail_unless(!Curl_dyn_len(&buf),
++ "Did not bail out on too long line");
+ break;
+ case 5:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\x1aTEST\n", line),
+- "Missed/Misinterpreted ^Z (6)");
+- line = Curl_get_line(buf, len, fp);
+- abort_unless(line == NULL, "Missed EOF (6)");
++ "Missed/Misinterpreted ^Z (6)");
++ rc = Curl_get_line(&buf, fp);
++ abort_unless(!Curl_dyn_len(&buf), "Missed EOF (6)");
+ break;
+ default:
+ abort_unless(1, "Unknown case");
+ break;
+ }
++ Curl_dyn_free(&buf);
+ fclose(fp);
+ fprintf(stderr, "OK\n");
+ }
++ return rc;
+ UNITTEST_STOP
+
+ #else
+--
+2.33.0
+
diff --git a/backport-CVE-2024-11053-pre2.patch b/backport-CVE-2024-11053-pre2.patch
new file mode 100644
index 0000000..eff59cc
--- /dev/null
+++ b/backport-CVE-2024-11053-pre2.patch
@@ -0,0 +1,800 @@
+From 3b43a05e000aa8f65bda513f733a73fefe35d5ca Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Thu, 10 Oct 2024 18:08:07 +0200
+Subject: [PATCH] netrc: cache the netrc file in memory
+
+So that on redirects etc it does not reread the file but just parses it
+again.
+
+Reported-by: Pierre-Etienne Meunier
+Fixes #15248
+Closes #15259
+
+Conflict:context adapt
+Reference:https://github.com/curl/curl/commit/3b43a05e000aa8f65bda513f733a73fefe35d5ca
+---
+ lib/multi.c | 2 +
+ lib/netrc.c | 407 ++++++++++++++++++++++++------------------
+ lib/netrc.h | 14 +-
+ lib/url.c | 4 +-
+ lib/urldata.h | 5 +
+ tests/unit/unit1304.c | 48 ++++-
+ 6 files changed, 292 insertions(+), 188 deletions(-)
+
+diff --git a/lib/multi.c b/lib/multi.c
+index 223c2339c..0f9fedaff 100644
+--- a/lib/multi.c
++++ b/lib/multi.c
+@@ -757,6 +757,8 @@ static CURLcode multi_done(struct Curl_easy *data,
+ data->state.lastconnect_id = -1;
+ }
+
++ /* flush the netrc cache */
++ Curl_netrc_cleanup(&data->state.netrc);
+ Curl_safefree(data->state.buffer);
+ return result;
+ }
+diff --git a/lib/netrc.c b/lib/netrc.c
+index 3c0651dcc..c23f927ce 100644
+--- a/lib/netrc.c
++++ b/lib/netrc.c
+@@ -31,7 +31,6 @@
+
+ #include <curl/curl.h>
+ #include "netrc.h"
+-#include "strtok.h"
+ #include "strcase.h"
+ #include "curl_get_line.h"
+
+@@ -49,21 +48,56 @@ enum host_lookup_state {
+ MACDEF
+ };
+
++enum found_state {
++ NONE,
++ LOGIN,
++ PASSWORD
++};
++
+ #define NETRC_FILE_MISSING 1
+ #define NETRC_FAILED -1
+ #define NETRC_SUCCESS 0
+
+ #define MAX_NETRC_LINE 4096
++#define MAX_NETRC_FILE (64*1024)
++#define MAX_NETRC_TOKEN 128
++
++static CURLcode file2memory(const char *filename, struct dynbuf *filebuf)
++{
++ CURLcode result = CURLE_OK;
++ FILE *file = fopen(filename, FOPEN_READTEXT);
++ struct dynbuf linebuf;
++ Curl_dyn_init(&linebuf, MAX_NETRC_LINE);
++
++ if(file) {
++ while(Curl_get_line(&linebuf, file)) {
++ const char *line = Curl_dyn_ptr(&linebuf);
++ /* skip comments on load */
++ while(ISBLANK(*line))
++ line++;
++ if(*line == '#')
++ continue;
++ result = Curl_dyn_add(filebuf, line);
++ if(result)
++ goto done;
++ }
++ }
++done:
++ Curl_dyn_free(&linebuf);
++ if(file)
++ fclose(file);
++ return result;
++}
+
+ /*
+ * Returns zero on success.
+ */
+-static int parsenetrc(const char *host,
++static int parsenetrc(struct store_netrc *store,
++ const char *host,
+ char **loginp,
+ char **passwordp,
+- char *netrcfile)
++ const char *netrcfile)
+ {
+- FILE *file;
+ int retcode = NETRC_FILE_MISSING;
+ char *login = *loginp;
+ char *password = *passwordp;
+@@ -71,204 +105,212 @@ static int parsenetrc(const char *host,
+ bool login_alloc = FALSE;
+ bool password_alloc = FALSE;
+ enum host_lookup_state state = NOTHING;
++ enum found_state found = NONE;
++ bool our_login = TRUE; /* With specific_login, found *our* login name (or
++ login-less line) */
++ bool done = FALSE;
++ char *netrcbuffer;
++ struct dynbuf token;
++ struct dynbuf *filebuf = &store->filebuf;
++ Curl_dyn_init(&token, MAX_NETRC_TOKEN);
+
+- char state_login = 0; /* Found a login keyword */
+- char state_password = 0; /* Found a password keyword */
+- int state_our_login = TRUE; /* With specific_login, found *our* login
+- name (or login-less line) */
+-
+- DEBUGASSERT(netrcfile);
++ if(!store->loaded) {
++ if(file2memory(netrcfile, filebuf))
++ return NETRC_FAILED;
++ store->loaded = TRUE;
++ }
+
+- file = fopen(netrcfile, FOPEN_READTEXT);
+- if(file) {
+- bool done = FALSE;
+- struct dynbuf buf;
+- Curl_dyn_init(&buf, MAX_NETRC_LINE);
++ netrcbuffer = Curl_dyn_ptr(filebuf);
+
+- while(!done && Curl_get_line(&buf, file)) {
+- char *tok;
++ while(!done) {
++ char *tok = netrcbuffer;
++ while(tok) {
+ char *tok_end;
+ bool quoted;
+- char *netrcbuffer = Curl_dyn_ptr(&buf);
++ Curl_dyn_reset(&token);
++ while(ISBLANK(*tok))
++ tok++;
++ /* tok is first non-space letter */
+ if(state == MACDEF) {
+- if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
+- state = NOTHING;
+- else
+- continue;
++ if((*tok == '\n') || (*tok == '\r'))
++ state = NOTHING; /* end of macro definition */
+ }
+- tok = netrcbuffer;
+- while(tok) {
+- while(ISBLANK(*tok))
+- tok++;
+- /* tok is first non-space letter */
+- if(!*tok || (*tok == '#'))
+- /* end of line or the rest is a comment */
+- break;
+
+- /* leading double-quote means quoted string */
+- quoted = (*tok == '\"');
++ if(!*tok || (*tok == '\n'))
++ /* end of line */
++ break;
+
+- tok_end = tok;
+- if(!quoted) {
+- while(!ISSPACE(*tok_end))
+- tok_end++;
+- *tok_end = 0;
++ /* leading double-quote means quoted string */
++ quoted = (*tok == '\"');
++
++ tok_end = tok;
++ if(!quoted) {
++ size_t len = 0;
++ while(!ISSPACE(*tok_end)) {
++ tok_end++;
++ len++;
+ }
+- else {
+- bool escape = FALSE;
+- bool endquote = FALSE;
+- char *store = tok;
+- tok_end++; /* pass the leading quote */
+- while(*tok_end) {
+- char s = *tok_end;
+- if(escape) {
+- escape = FALSE;
+- switch(s) {
+- case 'n':
+- s = '\n';
+- break;
+- case 'r':
+- s = '\r';
+- break;
+- case 't':
+- s = '\t';
+- break;
+- }
+- }
+- else if(s == '\\') {
+- escape = TRUE;
+- tok_end++;
+- continue;
+- }
+- else if(s == '\"') {
+- tok_end++; /* pass the ending quote */
+- endquote = TRUE;
++ if(!len || Curl_dyn_addn(&token, tok, len)) {
++ retcode = NETRC_FAILED;
++ goto out;
++ }
++ }
++ else {
++ bool escape = FALSE;
++ bool endquote = FALSE;
++ tok_end++; /* pass the leading quote */
++ while(*tok_end) {
++ char s = *tok_end;
++ if(escape) {
++ escape = FALSE;
++ switch(s) {
++ case 'n':
++ s = '\n';
++ break;
++ case 'r':
++ s = '\r';
++ break;
++ case 't':
++ s = '\t';
+ break;
+ }
+- *store++ = s;
++ }
++ else if(s == '\\') {
++ escape = TRUE;
+ tok_end++;
++ continue;
++ }
++ else if(s == '\"') {
++ tok_end++; /* pass the ending quote */
++ endquote = TRUE;
++ break;
+ }
+- *store = 0;
+- if(escape || !endquote) {
+- /* bad syntax, get out */
++ if(Curl_dyn_addn(&token, &s, 1)) {
+ retcode = NETRC_FAILED;
+ goto out;
+ }
++ tok_end++;
+ }
+-
+- if((login && *login) && (password && *password)) {
+- done = TRUE;
+- break;
++ if(escape || !endquote) {
++ /* bad syntax, get out */
++ retcode = NETRC_FAILED;
++ goto out;
+ }
++ }
+
+- switch(state) {
+- case NOTHING:
+- if(strcasecompare("macdef", tok)) {
+- /* Define a macro. A macro is defined with the specified name; its
+- contents begin with the next .netrc line and continue until a
+- null line (consecutive new-line characters) is encountered. */
+- state = MACDEF;
+- }
+- else if(strcasecompare("machine", tok)) {
+- /* the next tok is the machine name, this is in itself the
+- delimiter that starts the stuff entered for this machine,
+- after this we need to search for 'login' and
+- 'password'. */
+- state = HOSTFOUND;
+- }
+- else if(strcasecompare("default", tok)) {
+- state = HOSTVALID;
+- retcode = NETRC_SUCCESS; /* we did find our host */
+- }
+- break;
+- case MACDEF:
+- if(!strlen(tok)) {
+- state = NOTHING;
+- }
+- break;
+- case HOSTFOUND:
+- if(strcasecompare(host, tok)) {
+- /* and yes, this is our host! */
+- state = HOSTVALID;
+- retcode = NETRC_SUCCESS; /* we did find our host */
++ if((login && *login) && (password && *password)) {
++ done = TRUE;
++ break;
++ }
++
++ tok = Curl_dyn_ptr(&token);
++
++ switch(state) {
++ case NOTHING:
++ if(strcasecompare("macdef", tok))
++ /* Define a macro. A macro is defined with the specified name; its
++ contents begin with the next .netrc line and continue until a
++ null line (consecutive new-line characters) is encountered. */
++ state = MACDEF;
++ else if(strcasecompare("machine", tok))
++ /* the next tok is the machine name, this is in itself the delimiter
++ that starts the stuff entered for this machine, after this we
++ need to search for 'login' and 'password'. */
++ state = HOSTFOUND;
++ else if(strcasecompare("default", tok)) {
++ state = HOSTVALID;
++ retcode = NETRC_SUCCESS; /* we did find our host */
++ }
++ break;
++ case MACDEF:
++ if(!*tok)
++ state = NOTHING;
++ break;
++ case HOSTFOUND:
++ if(strcasecompare(host, tok)) {
++ /* and yes, this is our host! */
++ state = HOSTVALID;
++ retcode = NETRC_SUCCESS; /* we did find our host */
++ }
++ else
++ /* not our host */
++ state = NOTHING;
++ break;
++ case HOSTVALID:
++ /* we are now parsing sub-keywords concerning "our" host */
++ if(found == LOGIN) {
++ if(specific_login) {
++ our_login = !Curl_timestrcmp(login, tok);
+ }
+- else
+- /* not our host */
+- state = NOTHING;
+- break;
+- case HOSTVALID:
+- /* we are now parsing sub-keywords concerning "our" host */
+- if(state_login) {
+- if(specific_login) {
+- state_our_login = !Curl_timestrcmp(login, tok);
++ else if(!login || Curl_timestrcmp(login, tok)) {
++ if(login_alloc)
++ free(login);
++ login = strdup(tok);
++ if(!login) {
++ retcode = NETRC_FAILED; /* allocation failed */
++ goto out;
+ }
+- else if(!login || Curl_timestrcmp(login, tok)) {
+- if(login_alloc) {
+- free(login);
+- login_alloc = FALSE;
+- }
+- login = strdup(tok);
+- if(!login) {
+- retcode = NETRC_FAILED; /* allocation failed */
+- goto out;
+- }
+- login_alloc = TRUE;
+- }
+- state_login = 0;
++ login_alloc = TRUE;
+ }
+- else if(state_password) {
+- if((state_our_login || !specific_login)
+- && (!password || Curl_timestrcmp(password, tok))) {
+- if(password_alloc) {
+- free(password);
+- password_alloc = FALSE;
+- }
+- password = strdup(tok);
+- if(!password) {
+- retcode = NETRC_FAILED; /* allocation failed */
+- goto out;
+- }
+- password_alloc = TRUE;
++ found = NONE;
++ }
++ else if(found == PASSWORD) {
++ if((our_login || !specific_login) &&
++ (!password || Curl_timestrcmp(password, tok))) {
++ if(password_alloc)
++ free(password);
++ password = strdup(tok);
++ if(!password) {
++ retcode = NETRC_FAILED; /* allocation failed */
++ goto out;
+ }
+- state_password = 0;
+- }
+- else if(strcasecompare("login", tok))
+- state_login = 1;
+- else if(strcasecompare("password", tok))
+- state_password = 1;
+- else if(strcasecompare("machine", tok)) {
+- /* ok, there's machine here go => */
+- state = HOSTFOUND;
+- state_our_login = FALSE;
++ password_alloc = TRUE;
+ }
+- break;
+- } /* switch (state) */
+- tok = ++tok_end;
+- }
+- } /* while Curl_get_line() */
++ found = NONE;
++ }
++ else if(strcasecompare("login", tok))
++ found = LOGIN;
++ else if(strcasecompare("password", tok))
++ found = PASSWORD;
++ else if(strcasecompare("machine", tok)) {
++ /* ok, there is machine here go => */
++ state = HOSTFOUND;
++ found = NONE;
++ }
++ break;
++ } /* switch (state) */
++ tok = ++tok_end;
++ }
++ if(!done) {
++ char *nl = NULL;
++ if(tok)
++ nl = strchr(tok, '\n');
++ if(!nl)
++ break;
++ /* point to next line */
++ netrcbuffer = &nl[1];
++ }
++ } /* while !done */
+
+ out:
+- Curl_dyn_free(&buf);
+- if(!retcode) {
+- /* success */
+- if(login_alloc) {
+- if(*loginp)
+- free(*loginp);
+- *loginp = login;
+- }
+- if(password_alloc) {
+- if(*passwordp)
+- free(*passwordp);
+- *passwordp = password;
+- }
++ Curl_dyn_free(&token);
++ if(!retcode) {
++ /* success */
++ if(login_alloc) {
++ free(*loginp);
++ *loginp = login;
+ }
+- else {
+- if(login_alloc)
+- free(login);
+- if(password_alloc)
+- free(password);
++ if(password_alloc) {
++ free(*passwordp);
++ *passwordp = password;
+ }
+- fclose(file);
++ }
++ else {
++ Curl_dyn_free(filebuf);
++ if(login_alloc)
++ free(login);
++ if(password_alloc)
++ free(password);
+ }
+
+ return retcode;
+@@ -280,7 +322,8 @@ out:
+ * *loginp and *passwordp MUST be allocated if they aren't NULL when passed
+ * in.
+ */
+-int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
++int Curl_parsenetrc(struct store_netrc *store, const char *host,
++ char **loginp, char **passwordp,
+ char *netrcfile)
+ {
+ int retcode = 1;
+@@ -329,7 +372,7 @@ int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
+ free(homea);
+ return -1;
+ }
+- retcode = parsenetrc(host, loginp, passwordp, filealloc);
++ retcode = parsenetrc(store, host, loginp, passwordp, filealloc);
+ free(filealloc);
+ #ifdef WIN32
+ if(retcode == NETRC_FILE_MISSING) {
+@@ -339,15 +382,25 @@ int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
+ free(homea);
+ return -1;
+ }
+- retcode = parsenetrc(host, loginp, passwordp, filealloc);
++ retcode = parsenetrc(store, host, loginp, passwordp, filealloc);
+ free(filealloc);
+ }
+ #endif
+ free(homea);
+ }
+ else
+- retcode = parsenetrc(host, loginp, passwordp, netrcfile);
++ retcode = parsenetrc(store, host, loginp, passwordp, netrcfile);
+ return retcode;
+ }
+
++void Curl_netrc_init(struct store_netrc *s)
++{
++ Curl_dyn_init(&s->filebuf, MAX_NETRC_FILE);
++ s->loaded = FALSE;
++}
++void Curl_netrc_cleanup(struct store_netrc *s)
++{
++ Curl_dyn_free(&s->filebuf);
++ s->loaded = FALSE;
++}
+ #endif
+diff --git a/lib/netrc.h b/lib/netrc.h
+index 37c95db5e..0ef9ff78e 100644
+--- a/lib/netrc.h
++++ b/lib/netrc.h
+@@ -26,9 +26,19 @@
+
+ #include "curl_setup.h"
+ #ifndef CURL_DISABLE_NETRC
++#include "dynbuf.h"
++
++struct store_netrc {
++ struct dynbuf filebuf;
++ char *filename;
++ BIT(loaded);
++};
++
++void Curl_netrc_init(struct store_netrc *s);
++void Curl_netrc_cleanup(struct store_netrc *s);
+
+ /* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
+-int Curl_parsenetrc(const char *host, char **loginp,
++int Curl_parsenetrc(struct store_netrc *s, const char *host, char **loginp,
+ char **passwordp, char *filename);
+ /* Assume: (*passwordp)[0]=0, host[0] != 0.
+ * If (*loginp)[0] = 0, search for login and password within a machine
+@@ -38,6 +48,8 @@ int Curl_parsenetrc(const char *host, char **loginp,
+ #else
+ /* disabled */
+ #define Curl_parsenetrc(a,b,c,d,e,f) 1
++#define Curl_netrc_init(x)
++#define Curl_netrc_cleanup(x)
+ #endif
+
+ #endif /* HEADER_CURL_NETRC_H */
+diff --git a/lib/url.c b/lib/url.c
+index a59cb0e34..45745bc60 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -338,6 +338,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
+ Curl_wildcard_dtor(&data->wildcard);
+ Curl_freeset(data);
+ Curl_headers_cleanup(data);
++ Curl_netrc_cleanup(&data->state.netrc);
+ free(data);
+ return CURLE_OK;
+ }
+@@ -545,6 +546,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
+
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
++ Curl_netrc_init(&data->state.netrc);
+ }
+
+ if(result) {
+@@ -2689,7 +2691,7 @@ static CURLcode override_login(struct Curl_easy *data,
+ url_provided = TRUE;
+ }
+
+- ret = Curl_parsenetrc(conn->host.name,
++ ret = Curl_parsenetrc(&data->state.netrc, conn->host.name,
+ userp, passwdp,
+ data->set.str[STRING_NETRC_FILE]);
+ if(ret > 0) {
+diff --git a/lib/urldata.h b/lib/urldata.h
+index 4e0d6ef98..6aa26237d 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -163,6 +163,7 @@ typedef unsigned int curl_prot_t;
+ #include "splay.h"
+ #include "dynbuf.h"
+ #include "dynhds.h"
++#include "netrc.h"
+
+ /* return the count of bytes sent, or -1 on error */
+ typedef ssize_t (Curl_send)(struct Curl_easy *data, /* transfer */
+@@ -1313,6 +1314,10 @@ struct UrlState {
+ CURLcode hresult; /* used to pass return codes back from hyper callbacks */
+ #endif
+
++#ifndef CURL_DISABLE_NETRC
++ struct store_netrc netrc;
++#endif
++
+ /* Dynamically allocated strings, MUST be freed before this struct is
+ killed. */
+ struct dynamically_allocated_data {
+diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c
+index 2171c0736..238d3c0f7 100644
+--- a/tests/unit/unit1304.c
++++ b/tests/unit/unit1304.c
+@@ -49,17 +49,22 @@ static void unit_stop(void)
+ }
+
+ UNITTEST_START
++{
+ int result;
++ struct store_netrc store;
+
+ /*
+ * Test a non existent host in our netrc file.
+ */
+- result = Curl_parsenetrc("test.example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "test.example.com", &login, &password, arg);
+ 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");
++ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test a non existent login in our netrc file.
+@@ -67,13 +72,16 @@ UNITTEST_START
+ free(login);
+ login = strdup("me");
+ abort_unless(login != NULL, "returned NULL!");
+- result = Curl_parsenetrc("example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "example.com", &login, &password, arg);
+ 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");
+ abort_unless(login != NULL, "returned NULL!");
+ fail_unless(strncmp(login, "me", 2) == 0,
+ "login should not have been changed");
++ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test a non existent login and host in our netrc file.
+@@ -81,13 +89,16 @@ UNITTEST_START
+ free(login);
+ login = strdup("me");
+ abort_unless(login != NULL, "returned NULL!");
+- result = Curl_parsenetrc("test.example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "test.example.com", &login, &password, arg);
+ 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");
++ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test a non existent login (substring of an existing one) in our
+@@ -96,13 +107,16 @@ UNITTEST_START
+ free(login);
+ login = strdup("admi");
+ abort_unless(login != NULL, "returned NULL!");
+- result = Curl_parsenetrc("example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "example.com", &login, &password, arg);
+ 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");
+ abort_unless(login != NULL, "returned NULL!");
+ fail_unless(strncmp(login, "admi", 4) == 0,
+ "login should not have been changed");
++ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test a non existent login (superstring of an existing one)
+@@ -111,13 +125,16 @@ UNITTEST_START
+ free(login);
+ login = strdup("adminn");
+ abort_unless(login != NULL, "returned NULL!");
+- result = Curl_parsenetrc("example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "example.com", &login, &password, arg);
+ 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");
+ abort_unless(login != NULL, "returned NULL!");
+ fail_unless(strncmp(login, "adminn", 6) == 0,
+ "login should not have been changed");
++ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test for the first existing host in our netrc file
+@@ -126,13 +143,16 @@ UNITTEST_START
+ free(login);
+ login = strdup("");
+ abort_unless(login != NULL, "returned NULL!");
+- result = Curl_parsenetrc("example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "example.com", &login, &password, arg);
+ fail_unless(result == 0, "Host should have been found");
+ abort_unless(password != NULL, "returned NULL!");
+ fail_unless(strncmp(password, "passwd", 6) == 0,
+ "password should be 'passwd'");
+ abort_unless(login != NULL, "returned NULL!");
+ fail_unless(strncmp(login, "admin", 5) == 0, "login should be 'admin'");
++ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test for the first existing host in our netrc file
+@@ -141,13 +161,16 @@ UNITTEST_START
+ free(password);
+ password = strdup("");
+ abort_unless(password != NULL, "returned NULL!");
+- result = Curl_parsenetrc("example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "example.com", &login, &password, arg);
+ fail_unless(result == 0, "Host should have been found");
+ abort_unless(password != NULL, "returned NULL!");
+ fail_unless(strncmp(password, "passwd", 6) == 0,
+ "password should be 'passwd'");
+ abort_unless(login != NULL, "returned NULL!");
+ fail_unless(strncmp(login, "admin", 5) == 0, "login should be 'admin'");
++ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test for the second existing host in our netrc file
+@@ -159,13 +182,16 @@ UNITTEST_START
+ free(login);
+ login = strdup("");
+ abort_unless(login != NULL, "returned NULL!");
+- result = Curl_parsenetrc("curl.example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "curl.example.com", &login, &password, arg);
+ fail_unless(result == 0, "Host should have been found");
+ abort_unless(password != NULL, "returned NULL!");
+ fail_unless(strncmp(password, "none", 4) == 0,
+ "password should be 'none'");
+ abort_unless(login != NULL, "returned NULL!");
+ fail_unless(strncmp(login, "none", 4) == 0, "login should be 'none'");
++ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test for the second existing host in our netrc file
+@@ -174,14 +200,18 @@ UNITTEST_START
+ free(password);
+ password = strdup("");
+ abort_unless(password != NULL, "returned NULL!");
+- result = Curl_parsenetrc("curl.example.com", &login, &password, arg);
++ Curl_netrc_init(&store);
++ result = Curl_parsenetrc(&store,
++ "curl.example.com", &login, &password, arg);
+ fail_unless(result == 0, "Host should have been found");
+ abort_unless(password != NULL, "returned NULL!");
+ fail_unless(strncmp(password, "none", 4) == 0,
+ "password should be 'none'");
+ abort_unless(login != NULL, "returned NULL!");
+ fail_unless(strncmp(login, "none", 4) == 0, "login should be 'none'");
++ Curl_netrc_cleanup(&store);
+
++}
+ UNITTEST_STOP
+
+ #else
+--
+2.33.0
+
diff --git a/backport-CVE-2024-11053-pre3.patch b/backport-CVE-2024-11053-pre3.patch
new file mode 100644
index 0000000..286a7f4
--- /dev/null
+++ b/backport-CVE-2024-11053-pre3.patch
@@ -0,0 +1,349 @@
+From 9bee39bfed2c413b4cc4eb306a57ac92a1854907 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Sat, 12 Oct 2024 23:54:39 +0200
+Subject: [PATCH] url: use same credentials on redirect
+
+Previously it could lose the username and only use the password.
+
+Added test 998 and 999 to verify.
+
+Reported-by: Tobias Bora
+Fixes #15262
+Closes #15282
+
+Conflict:context adapt
+Reference:https://github.com/curl/curl/commit/9bee39bfed2c413b4cc4eb306a57ac92a1854907
+---
+ lib/transfer.c | 3 +
+ lib/url.c | 19 ++++---
+ lib/urldata.h | 9 ++-
+ tests/data/Makefile.inc | 14 +++++++-------
+ tests/data/test998 | 92 ++++++++++++++++++++++++++++++
+ tests/data/test999 | 81 ++++++++++++++++++++++++++
+ 6 files changed, 195 insertions(+), 11 deletions(-)
+ create mode 100644 tests/data/test998
+ create mode 100644 tests/data/test999
+
+diff --git a/lib/transfer.c b/lib/transfer.c
+index 79d648cab..3a9239254 100644
+--- a/lib/transfer.c
++++ b/lib/transfer.c
+@@ -679,6 +679,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
++ if(data->set.str[STRING_USERNAME] ||
++ data->set.str[STRING_PASSWORD])
++ data->state.creds_from = CREDS_OPTION;
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.user,
+ data->set.str[STRING_USERNAME]);
+diff --git a/lib/url.c b/lib/url.c
+index 45745bc60..261f61d8d 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -1860,10 +1860,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
+ return result;
+
+ /*
+- * User name and password set with their own options override the
+- * credentials possibly set in the URL.
++ * username and password set with their own options override the credentials
++ * possibly set in the URL, but netrc does not.
+ */
+- if(!data->set.str[STRING_PASSWORD]) {
++ if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
+ uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
+ if(!uc) {
+ char *decoded;
+@@ -1876,12 +1876,13 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
+ result = Curl_setstropt(&data->state.aptr.passwd, decoded);
+ if(result)
+ return result;
++ data->state.creds_from = CREDS_URL;
+ }
+ else if(uc != CURLUE_NO_PASSWORD)
+ return Curl_uc_to_curlcode(uc);
+ }
+
+- if(!data->set.str[STRING_USERNAME]) {
++ if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
+ /* we don't use the URL API's URL decoder option here since it rejects
+ control codes and we want to allow them for some schemes in the user
+ and password fields */
+@@ -1895,13 +1896,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
+ return result;
+ conn->user = decoded;
+ result = Curl_setstropt(&data->state.aptr.user, decoded);
++ data->state.creds_from = CREDS_URL;
+ }
+ else if(uc != CURLUE_NO_USER)
+ return Curl_uc_to_curlcode(uc);
+- else if(data->state.aptr.passwd) {
+- /* no user was set but a password, set a blank user */
+- result = Curl_setstropt(&data->state.aptr.user, "");
+- }
+ if(result)
+ return result;
+ }
+@@ -2685,7 +2683,8 @@ static CURLcode override_login(struct Curl_easy *data,
+ int ret;
+ bool url_provided = FALSE;
+
+- if(data->state.aptr.user) {
++ if(data->state.aptr.user &&
++ (data->state.creds_from != CREDS_NETRC)) {
+ /* there was a user name in the URL. Use the URL decoded version */
+ userp = &data->state.aptr.user;
+ url_provided = TRUE;
+@@ -2733,6 +2732,7 @@ static CURLcode override_login(struct Curl_easy *data,
+ result = Curl_setstropt(&data->state.aptr.user, *userp);
+ if(result)
+ return result;
++ data->state.creds_from = CREDS_NETRC;
+ }
+ }
+ if(data->state.aptr.user) {
+@@ -2750,6 +2750,7 @@ static CURLcode override_login(struct Curl_easy *data,
+ CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
+ if(result)
+ return result;
++ data->state.creds_from = CREDS_NETRC;
+ }
+ if(data->state.aptr.passwd) {
+ uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
+diff --git a/lib/urldata.h b/lib/urldata.h
+index 6aa26237d..73f662159 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -1206,6 +1206,11 @@ struct urlpieces {
+ char *query;
+ };
+
++#define CREDS_NONE 0
++#define CREDS_URL 1 /* from URL */
++#define CREDS_OPTION 2 /* set with a CURLOPT_ */
++#define CREDS_NETRC 3 /* found in netrc */
++
+ struct UrlState {
+ /* Points to the connection cache */
+ struct conncache *conn_cache;
+@@ -1344,7 +1349,6 @@ struct UrlState {
+ char *proxyuser;
+ char *proxypasswd;
+ } aptr;
+-
+ unsigned char httpwant; /* when non-zero, a specific HTTP version requested
+ to be used in the library's request(s) */
+ unsigned char httpversion; /* the lowest HTTP version*10 reported by any
+@@ -1354,6 +1358,9 @@ struct UrlState {
+ unsigned char dselect_bits; /* != 0 -> bitmask of socket events for this
+ transfer overriding anything the socket may
+ report */
++ unsigned int creds_from:2; /* where is the server credentials originating
++ from, see the CREDS_* defines above */
++
+ #ifdef CURLDEBUG
+ BIT(conncache_lock);
+ #endif
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index 480a88208..02bf2ae25 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -133,7 +133,7 @@ test961 test962 test963 test964 test965 test966 test967 test968 test969 \
+ test961 test962 test963 test964 test965 test966 test967 test968 test969 \
+ test970 test971 test972 test973 test974 test975 test976 test977 test978 \
+ test979 test980 test981 test982 test983 test984 test985 test986 test987 \
+-test988 test989 test990 test991 \
++test988 test989 test990 test991 test998 test999 \
+ \
+ test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \
+ test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \
+diff --git a/tests/data/test998 b/tests/data/test998
+new file mode 100644
+index 000000000..c3a8f5169
+--- /dev/null
++++ b/tests/data/test998
+@@ -0,0 +1,92 @@
++<testcase>
++<info>
++<keywords>
++HTTP
++--location-trusted
++</keywords>
++</info>
++
++#
++# Server-side
++<reply>
++<data>
++HTTP/1.1 301 redirect
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Server: test-server/fake
++Content-Length: 0
++Connection: close
++Content-Type: text/html
++Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
++
++</data>
++<data2>
++HTTP/1.1 200 OK
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Content-Length: 6
++Content-Type: text/html
++Funny-head: yesyes
++
++-foo-
++</data2>
++
++<datacheck>
++HTTP/1.1 301 redirect
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Server: test-server/fake
++Content-Length: 0
++Connection: close
++Content-Type: text/html
++Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
++
++HTTP/1.1 200 OK
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Content-Length: 6
++Content-Type: text/html
++Funny-head: yesyes
++
++-foo-
++</datacheck>
++
++</reply>
++
++#
++# Client-side
++<client>
++<features>
++proxy
++</features>
++<server>
++http
++</server>
++<name>
++HTTP with auth in URL redirected to another host
++</name>
++<command>
++-x %HOSTIP:%HTTPPORT http://alberto:einstein@somwhere.example/%TESTNUMBER --location-trusted
++</command>
++</client>
++
++#
++# Verify data after the test has been "shot"
++<verify>
++<strip>
++QUIT
++</strip>
++<protocol>
++GET http://somwhere.example/998 HTTP/1.1
++Host: somwhere.example
++Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
++User-Agent: curl/%VERSION
++Accept: */*
++Proxy-Connection: Keep-Alive
++
++GET http://somewhere.else.example/a/path/9980002 HTTP/1.1
++Host: somewhere.else.example
++Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
++User-Agent: curl/%VERSION
++Accept: */*
++Proxy-Connection: Keep-Alive
++
++</protocol>
++</verify>
++</testcase>
+diff --git a/tests/data/test999 b/tests/data/test999
+new file mode 100644
+index 000000000..990a8d09a
+--- /dev/null
++++ b/tests/data/test999
+@@ -0,0 +1,81 @@
++<testcase>
++<info>
++<keywords>
++HTTP
++--location-trusted
++</keywords>
++</info>
++
++#
++# Server-side
++<reply>
++<data nocheck="yes">
++HTTP/1.1 200 OK
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Content-Length: 6
++Content-Type: text/html
++Funny-head: yesyes
++
++-foo-
++</data>
++
++<datacheck>
++HTTP/1.1 301 redirect
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Server: test-server/fake
++Content-Length: 0
++Connection: close
++Content-Type: text/html
++Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
++
++HTTP/1.1 200 OK
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Content-Length: 6
++Content-Type: text/html
++Funny-head: yesyes
++
++-foo-
++</datacheck>
++
++</reply>
++
++#
++# Client-side
++<client>
++<features>
++proxy
++</features>
++<server>
++http
++</server>
++<name>
++HTTP with auth in first URL but not second
++</name>
++<command>
++-x %HOSTIP:%HTTPPORT http://alberto:einstein@somwhere.example/%TESTNUMBER http://somewhere.else.example/%TESTNUMBER
++</command>
++</client>
++
++#
++# Verify data after the test has been "shot"
++<verify>
++<strip>
++QUIT
++</strip>
++<protocol>
++GET http://somwhere.example/%TESTNUMBER HTTP/1.1
++Host: somwhere.example
++Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
++User-Agent: curl/%VERSION
++Accept: */*
++Proxy-Connection: Keep-Alive
++
++GET http://somewhere.else.example/%TESTNUMBER HTTP/1.1
++Host: somewhere.else.example
++User-Agent: curl/%VERSION
++Accept: */*
++Proxy-Connection: Keep-Alive
++
++</protocol>
++</verify>
++</testcase>
+--
+2.33.0
+
diff --git a/backport-CVE-2024-11053-pre4.patch b/backport-CVE-2024-11053-pre4.patch
new file mode 100644
index 0000000..98e3deb
--- /dev/null
+++ b/backport-CVE-2024-11053-pre4.patch
@@ -0,0 +1,223 @@
+From f5c616930b5cf148b1b2632da4f5963ff48bdf88 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Thu, 7 Nov 2024 08:52:38 +0100
+Subject: [PATCH] duphandle: also init netrc
+
+The netrc init was only done in the Curl_open, meaning that a duplicated
+handle would not get inited properly.
+
+Added test 2309 to verify. It does netrc auth with a duplicated handle.
+
+Regression from 3b43a05e000aa8f65bda513f733a
+
+Reported-by: tranzystorekk on github
+Fixes #15496
+Closes #15503
+
+Conflict:context adapt
+Reference:https://github.com/curl/curl/commit/f5c616930b5cf148b1b2632da4f5963ff48bdf88
+---
+ lib/easy.c | 1 +
+ tests/data/Makefile.inc | 2 ++
+ tests/data/test2309 | 66 ++++++++++++++++++++++++++++++++++++++
+ tests/libtest/Makefile.inc | 5 ++-
+ tests/libtest/lib2309.c | 66 ++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 139 insertions(+), 1 deletions(-)
+ create mode 100644 tests/data/test2309
+ create mode 100644 tests/libtest/lib2309.c
+
+diff --git a/lib/easy.c b/lib/easy.c
+index d16fa8c07..ac8fab342 100644
+--- a/lib/easy.c
++++ b/lib/easy.c
+@@ -940,6 +940,7 @@ CURL *curl_easy_duphandle(CURL *d)
+ goto fail;
+
+ Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
++ Curl_netrc_init(&outcurl->state.netrc);
+
+ /* the connection cache is setup on demand */
+ outcurl->state.conn_cache = NULL;
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index 02bf2ae25..ea5221c00 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -255,6 +255,8 @@ test2100 \
+ test2200 test2201 test2202 test2203 test2204 test2205 \
+ \
+ test2300 test2301 test2302 test2303 test2304 test2305 test2306 \
++\
++test2309 \
+ \
+ test2400 test2401 test2402 test2403 test2404 \
+ \
+diff --git a/tests/data/test2309 b/tests/data/test2309
+new file mode 100644
+index 000000000..4ba78ee91
+--- /dev/null
++++ b/tests/data/test2309
+@@ -0,0 +1,66 @@
++<testcase>
++<info>
++<keywords>
++netrc
++HTTP
++</keywords>
++</info>
++#
++# Server-side
++<reply>
++<data crlf="yes" nocheck="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: 6
++Connection: close
++Content-Type: text/html
++Funny-head: yesyes
++
++-foo-
++</data>
++</reply>
++
++#
++# Client-side
++<client>
++<server>
++http
++</server>
++<features>
++proxy
++</features>
++
++# Reproducing issue 15496
++<name>
++HTTP with .netrc using duped easy handle
++</name>
++<tool>
++lib%TESTNUMBER
++</tool>
++<command>
++http://github.com %LOGDIR/netrc%TESTNUMBER http://%HOSTIP:%HTTPPORT/
++</command>
++<file name="%LOGDIR/netrc%TESTNUMBER" >
++
++machine github.com
++
++login daniel
++password $y$j9T$WUVjiVvDbRAWafDLs6cab1$01NX.oaZKf5lw8MR2Nk9Yaxv4CqbE0IaDF.GpGxPul1
++</file>
++</client>
++
++<verify>
++<protocol>
++GET http://github.com/ HTTP/1.1
++Host: github.com
++Authorization: Basic %b64[daniel:$y$j9T$WUVjiVvDbRAWafDLs6cab1$01NX.oaZKf5lw8MR2Nk9Yaxv4CqbE0IaDF.GpGxPul1]b64%
++Accept: */*
++Proxy-Connection: Keep-Alive
++
++</protocol>
++</verify>
++</testcase>
+diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
+index 339a00fc4..8f58fd642 100644
+--- a/tests/libtest/Makefile.inc
++++ b/tests/libtest/Makefile.inc
+@@ -77,7 +77,7 @@ LIBTESTPROGS = libauthretry libntlmconnect libprereq \
+ lib1945 lib1946 lib1947 lib1948 lib1955 lib1956 lib1957 lib1958 lib1959 \
+ lib1960 lib1964 \
+ lib1970 lib1971 lib1972 lib1973 lib1974 lib1975 \
+- lib2301 lib2302 lib2304 lib2305 lib2306 \
++ lib2301 lib2302 lib2304 lib2305 lib2306 lib2309 \
+ lib2402 lib2404 \
+ lib2502 \
+ lib3010 lib3025 lib3026 lib3027 \
+@@ -683,6 +683,9 @@ lib2306_LDADD = $(TESTUTIL_LIBS)
+ lib2306_SOURCES = lib2306.c $(SUPPORTFILES)
+ lib2306_LDADD = $(TESTUTIL_LIBS)
+
++lib2309_SOURCES = lib2309.c $(SUPPORTFILES)
++lib2309_LDADD = $(TESTUTIL_LIBS)
++
+ lib2402_SOURCES = lib2402.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
+ lib2402_LDADD = $(TESTUTIL_LIBS)
+
+diff --git a/tests/libtest/lib2309.c b/tests/libtest/lib2309.c
+new file mode 100644
+index 000000000..11f1c1fbd
+--- /dev/null
++++ b/tests/libtest/lib2309.c
+@@ -0,0 +1,66 @@
++/***************************************************************************
++ * _ _ ____ _
++ * Project ___| | | | _ \| |
++ * / __| | | | |_) | |
++ * | (__| |_| | _ <| |___
++ * \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++
++#include "test.h"
++#include "testtrace.h"
++
++#include <curl/curl.h>
++
++static size_t cb_ignore(char *buffer, size_t size, size_t nmemb, void *userp)
++{
++ (void)buffer;
++ (void)size;
++ (void)nmemb;
++ (void)userp;
++ return CURL_WRITEFUNC_ERROR;
++}
++
++int test(char *URL)
++{
++ CURL *curl;
++ CURL *curldupe;
++ int res = CURLE_OK;
++
++ global_init(CURL_GLOBAL_ALL);
++ curl = curl_easy_init();
++ if(curl) {
++ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb_ignore);
++ curl_easy_setopt(curl, CURLOPT_URL, URL);
++ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(curl, CURLOPT_PROXY, libtest_arg3);
++ curl_easy_setopt(curl, CURLOPT_NETRC, (long)CURL_NETRC_REQUIRED);
++ curl_easy_setopt(curl, CURLOPT_NETRC_FILE, libtest_arg2);
++
++ curldupe = curl_easy_duphandle(curl);
++ if(curldupe) {
++ res = curl_easy_perform(curldupe);
++ printf("Returned %d, should be %d.\n", res, CURLE_WRITE_ERROR);
++ fflush(stdout);
++ curl_easy_cleanup(curldupe);
++ }
++ curl_easy_cleanup(curl);
++ }
++ curl_global_cleanup();
++ return 0;
++}
+--
+2.33.0
+
diff --git a/backport-CVE-2024-11053-pre5.patch b/backport-CVE-2024-11053-pre5.patch
new file mode 100644
index 0000000..a50c273
--- /dev/null
+++ b/backport-CVE-2024-11053-pre5.patch
@@ -0,0 +1,37 @@
+From 0cdde0fdfbeb8c35420f6d03fa4b77ed73497694 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Thu, 7 Nov 2024 17:03:54 +0100
+Subject: [PATCH] netrc: support large file, longer lines, longer tokens
+
+Regression from 3b43a05e000aa8f6 (shipped in 8.11.0)
+
+Reported-by: Moritz
+Fixes #15513
+Closes #15514
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/0cdde0fdfbeb8c35420f6d03fa4b77ed73497694
+---
+ lib/netrc.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/lib/netrc.c b/lib/netrc.c
+index c23f927ce..034c0307a 100644
+--- a/lib/netrc.c
++++ b/lib/netrc.c
+@@ -58,9 +58,9 @@ enum found_state {
+ #define NETRC_FAILED -1
+ #define NETRC_SUCCESS 0
+
+-#define MAX_NETRC_LINE 4096
+-#define MAX_NETRC_FILE (64*1024)
+-#define MAX_NETRC_TOKEN 128
++#define MAX_NETRC_LINE 16384
++#define MAX_NETRC_FILE (128*1024)
++#define MAX_NETRC_TOKEN 4096
+
+ static CURLcode file2memory(const char *filename, struct dynbuf *filebuf)
+ {
+--
+2.33.0
+
diff --git a/backport-CVE-2024-11053.patch b/backport-CVE-2024-11053.patch
new file mode 100644
index 0000000..b920c42
--- /dev/null
+++ b/backport-CVE-2024-11053.patch
@@ -0,0 +1,728 @@
+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
+Reference:https://github.com/curl/curl/e9b9bbac22c26cf67316fa8e6c6b9e831af31949
+---
+ lib/netrc.c | 113 +++++++++++++++++++++++------------------
+ lib/url.c | 60 +++++++++++++++-------
+ tests/data/Makefile.inc | 1 +
+ tests/data/test478 | 73 ++++++++++++++++++++++++++
+ tests/data/test479 | 107 ++++++++++++++++++++++++++++++++++++++
+ tests/data/test480 | 38 ++++++++++++++
+ tests/unit/unit1304.c | 75 ++++++++-------------------
+ 7 files changed, 345 insertions(+), 122 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 034c0307a..e787a6ffc 100644
+--- a/lib/netrc.c
++++ b/lib/netrc.c
+@@ -54,6 +54,9 @@ enum found_state {
+ PASSWORD
+ };
+
++#define FOUND_LOGIN 1
++#define FOUND_PASSWORD 2
++
+ #define NETRC_FILE_MISSING 1
+ #define NETRC_FAILED -1
+ #define NETRC_SUCCESS 0
+@@ -94,24 +97,24 @@ done:
+ */
+ static int parsenetrc(struct store_netrc *store,
+ const char *host,
+- char **loginp,
++ char **loginp, /* might point to a username */
+ char **passwordp,
+ const char *netrcfile)
+ {
+ int retcode = NETRC_FILE_MISSING;
+ char *login = *loginp;
+- char *password = *passwordp;
+- bool specific_login = (login && *login != 0);
+- bool login_alloc = FALSE;
+- bool password_alloc = FALSE;
++ char *password = NULL;
++ bool specific_login = login; /* points to something */
+ enum host_lookup_state state = NOTHING;
+- enum found_state found = NONE;
+- bool our_login = TRUE; /* With specific_login, found *our* login name (or
+- login-less line) */
++ enum found_state keyword = NONE;
++ unsigned char found = 0; /* login + password found bits, as they can come in
++ any order */
++ bool our_login = FALSE; /* found our login name */
+ bool done = FALSE;
+ char *netrcbuffer;
+ struct dynbuf token;
+ struct dynbuf *filebuf = &store->filebuf;
++ DEBUGASSERT(!*passwordp);
+ Curl_dyn_init(&token, MAX_NETRC_TOKEN);
+
+ if(!store->loaded) {
+@@ -124,7 +127,7 @@ static int parsenetrc(struct store_netrc *store,
+
+ while(!done) {
+ char *tok = netrcbuffer;
+- while(tok) {
++ while(tok && !done) {
+ char *tok_end;
+ bool quoted;
+ Curl_dyn_reset(&token);
+@@ -198,11 +201,6 @@ static int parsenetrc(struct store_netrc *store,
+ }
+ }
+
+- if((login && *login) && (password && *password)) {
+- done = TRUE;
+- break;
+- }
+-
+ tok = Curl_dyn_ptr(&token);
+
+ switch(state) {
+@@ -212,11 +210,18 @@ static int parsenetrc(struct store_netrc *store,
+ contents begin with the next .netrc line and continue until a
+ null line (consecutive new-line characters) is encountered. */
+ state = MACDEF;
+- else if(strcasecompare("machine", tok))
++ else if(strcasecompare("machine", tok)) {
+ /* the next tok is the machine name, this is in itself the delimiter
+ that starts the stuff entered for this machine, after this we
+ need to search for 'login' and 'password'. */
+ state = HOSTFOUND;
++ keyword = NONE;
++ found = 0;
++ our_login = FALSE;
++ Curl_safefree(password);
++ if(!specific_login)
++ Curl_safefree(login);
++ }
+ else if(strcasecompare("default", tok)) {
+ state = HOSTVALID;
+ retcode = NETRC_SUCCESS; /* we did find our host */
+@@ -238,44 +243,54 @@ static int parsenetrc(struct store_netrc *store,
+ break;
+ case HOSTVALID:
+ /* we are now parsing sub-keywords concerning "our" host */
+- if(found == LOGIN) {
+- if(specific_login) {
++ if(keyword == LOGIN) {
++ if(specific_login)
+ our_login = !Curl_timestrcmp(login, tok);
+- }
+- else if(!login || Curl_timestrcmp(login, tok)) {
+- if(login_alloc)
+- free(login);
++ else {
++ our_login = TRUE;
++ free(login);
+ login = strdup(tok);
+ if(!login) {
+ retcode = NETRC_FAILED; /* allocation failed */
+ goto out;
+ }
+- login_alloc = TRUE;
+ }
+- found = NONE;
++ found |= FOUND_LOGIN;
++ keyword = NONE;
+ }
+- else if(found == PASSWORD) {
+- if((our_login || !specific_login) &&
+- (!password || Curl_timestrcmp(password, tok))) {
+- if(password_alloc)
+- free(password);
+- password = strdup(tok);
+- if(!password) {
+- retcode = NETRC_FAILED; /* allocation failed */
+- goto out;
+- }
+- password_alloc = TRUE;
++ else if(keyword == PASSWORD) {
++ free(password);
++ password = strdup(tok);
++ if(!password) {
++ retcode = NETRC_FAILED; /* allocation failed */
++ goto out;
+ }
+- found = NONE;
++ found |= FOUND_PASSWORD;
++ keyword = NONE;
+ }
+ else if(strcasecompare("login", tok))
+- found = LOGIN;
++ keyword = LOGIN;
+ else if(strcasecompare("password", tok))
+- found = PASSWORD;
++ keyword = PASSWORD;
+ else if(strcasecompare("machine", tok)) {
+- /* ok, there is machine here go => */
++ /* a new machine here */
+ state = HOSTFOUND;
+- found = NONE;
++ keyword = NONE;
++ found = 0;
++ Curl_safefree(password);
++ if(!specific_login)
++ Curl_safefree(login);
++ }
++ else if(strcasecompare("default", tok)) {
++ state = HOSTVALID;
++ retcode = NETRC_SUCCESS; /* we did find our host */
++ Curl_safefree(password);
++ if(!specific_login)
++ Curl_safefree(login);
++ }
++ if((found == (FOUND_PASSWORD|FOUND_LOGIN)) && our_login) {
++ done = TRUE;
++ break;
+ }
+ break;
+ } /* switch (state) */
+@@ -294,23 +309,23 @@ static int parsenetrc(struct store_netrc *store,
+
+ out:
+ Curl_dyn_free(&token);
++ if(!retcode && !password && our_login) {
++ /* success without a password, set a blank one */
++ password = strdup("");
++ if(!password)
++ retcode = 1; /* out of memory */
++ }
+ if(!retcode) {
+ /* success */
+- if(login_alloc) {
+- free(*loginp);
++ if(!specific_login)
+ *loginp = login;
+- }
+- if(password_alloc) {
+- free(*passwordp);
+- *passwordp = password;
+- }
++ *passwordp = password;
+ }
+ else {
+ Curl_dyn_free(filebuf);
+- if(login_alloc)
++ if(!specific_login)
+ free(login);
+- if(password_alloc)
+- free(password);
++ free(password);
+ }
+
+ return retcode;
+diff --git a/lib/url.c b/lib/url.c
+index f9bb05f79..436edd891 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -2651,6 +2651,17 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
+ return CURLE_OK;
+ }
+
++static bool str_has_ctrl(const char *input)
++{
++ const unsigned char *str = (const unsigned char *)input;
++ while(*str) {
++ if(*str < 0x20)
++ return TRUE;
++ str++;
++ }
++ return FALSE;
++}
++
+ /*
+ * Override the login details from the URL with that in the CURLOPT_USERPWD
+ * option or a .netrc file, if applicable.
+@@ -2682,29 +2693,40 @@ static CURLcode override_login(struct Curl_easy *data,
+
+ if(data->state.aptr.user &&
+ (data->state.creds_from != CREDS_NETRC)) {
+- /* there was a user name in the URL. Use the URL decoded version */
++ /* there was a username with a length in the URL. Use the URL decoded
++ version */
+ userp = &data->state.aptr.user;
+ url_provided = TRUE;
+ }
+
+- ret = Curl_parsenetrc(&data->state.netrc, conn->host.name,
+- userp, passwdp,
+- data->set.str[STRING_NETRC_FILE]);
+- if(ret > 0) {
+- infof(data, "Couldn't find host %s in the %s file; using defaults",
+- conn->host.name,
+- (data->set.str[STRING_NETRC_FILE] ?
+- data->set.str[STRING_NETRC_FILE] : ".netrc"));
+- }
+- else if(ret < 0) {
+- failf(data, ".netrc parser error");
+- return CURLE_READ_ERROR;
+- }
+- else {
+- /* set bits.netrc TRUE to remember that we got the name from a .netrc
+- file, so that it is safe to use even if we followed a Location: to a
+- different host or similar. */
+- conn->bits.netrc = TRUE;
++ if(!*passwdp) {
++ ret = Curl_parsenetrc(&data->state.netrc, conn->host.name,
++ userp, passwdp,
++ data->set.str[STRING_NETRC_FILE]);
++ if(ret > 0) {
++ infof(data, "Couldn't find host %s in the %s file; using defaults",
++ conn->host.name,
++ (data->set.str[STRING_NETRC_FILE] ?
++ data->set.str[STRING_NETRC_FILE] : ".netrc"));
++ }
++ else if(ret < 0) {
++ failf(data, ".netrc parser error");
++ return CURLE_READ_ERROR;
++ }
++ else {
++ if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
++ /* if the protocol can't handle control codes in credentials, make
++ sure there are none */
++ if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
++ failf(data, "control code detected in .netrc credentials");
++ return CURLE_READ_ERROR;
++ }
++ }
++ /* set bits.netrc TRUE to remember that we got the name from a .netrc
++ file, so that it is safe to use even if we followed a Location: to a
++ different host or similar. */
++ conn->bits.netrc = TRUE;
++ }
+ }
+ if(url_provided) {
+ Curl_safefree(conn->user);
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index ea5221c00..53f62c6e2 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -77,6 +77,7 @@ test435 test436 test437 test438 test439 test440 test441 test442 test443 \
+ test435 test436 test437 test438 test439 test440 test441 test442 test443 \
+ test444 test445 test446 test447 test448 test449 test450 test451 test452 \
+ test453 test454 test455 test456 test457 test458 \
++test478 test479 test480 \
+ \
+ test490 test491 test492 test493 test494 test495 test496 test497 test498 \
+ \
+diff --git a/tests/data/test478 b/tests/data/test478
+new file mode 100644
+index 000000000..6558363f5
+--- /dev/null
++++ b/tests/data/test478
+@@ -0,0 +1,73 @@
++<testcase>
++<info>
++<keywords>
++netrc
++HTTP
++</keywords>
++</info>
++#
++# Server-side
++<reply>
++<data 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: 6
++Connection: close
++Content-Type: text/html
++Funny-head: yesyes
++
++-foo-
++</data>
++</reply>
++
++#
++# Client-side
++<client>
++<server>
++http
++</server>
++<features>
++proxy
++</features>
++<name>
++.netrc with multiple accounts for same host
++</name>
++<command>
++--netrc --netrc-file %LOGDIR/netrc%TESTNUMBER -x http://%HOSTIP:%HTTPPORT/ http://debbie@github.com/
++</command>
++<file name="%LOGDIR/netrc%TESTNUMBER" >
++
++machine github.com
++password weird
++password firstone
++login daniel
++
++machine github.com
++
++machine github.com
++login debbie
++
++machine github.com
++password weird
++password "second\r"
++login debbie
++
++</file>
++</client>
++
++<verify>
++<protocol>
++GET http://github.com/ HTTP/1.1
++Host: github.com
++Authorization: Basic %b64[debbie:second%0D]b64%
++User-Agent: curl/%VERSION
++Accept: */*
++Proxy-Connection: Keep-Alive
++
++</protocol>
++</verify>
++</testcase>
+diff --git a/tests/data/test479 b/tests/data/test479
+new file mode 100644
+index 000000000..d7ce4652f
+--- /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 %LOGDIR/netrc%TESTNUMBER -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/
++</command>
++<file name="%LOGDIR/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/data/test480 b/tests/data/test480
+new file mode 100644
+index 000000000..aab889f47
+--- /dev/null
++++ b/tests/data/test480
+@@ -0,0 +1,38 @@
++<testcase>
++<info>
++<keywords>
++netrc
++pop3
++</keywords>
++</info>
++#
++# Server-side
++<reply>
++
++</reply>
++
++#
++# Client-side
++<client>
++<server>
++pop3
++</server>
++<name>
++Reject .netrc with credentials using CRLF for POP3
++</name>
++<command>
++--netrc --netrc-file %LOGDIR/netrc%TESTNUMBER pop3://%HOSTIP:%POP3PORT/%TESTNUMBER
++</command>
++<file name="%LOGDIR/netrc%TESTNUMBER" >
++machine %HOSTIP
++ login alice
++ password "password\r\ncommand"
++</file>
++</client>
++
++<verify>
++<errorcode>
++26
++</errorcode>
++</verify>
++</testcase>
+diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c
+index 238d3c0f7..817887b94 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,89 +55,61 @@ UNITTEST_START
+ result = Curl_parsenetrc(&store,
+ "test.example.com", &login, &password, arg);
+ 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!");
+ Curl_netrc_cleanup(&store);
+
+ /*
+ * Test a non existent login in our netrc file.
+ */
+- free(login);
+- login = strdup("me");
+- abort_unless(login != NULL, "returned NULL!");
++ login = (char *)"me";
+ Curl_netrc_init(&store);
+ result = Curl_parsenetrc(&store,
+ "example.com", &login, &password, arg);
+ 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");
+- 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!");
+ Curl_netrc_cleanup(&store);
+
+ /*
+ * 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";
+ Curl_netrc_init(&store);
+ result = Curl_parsenetrc(&store,
+ "test.example.com", &login, &password, arg);
+ 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!");
+ Curl_netrc_cleanup(&store);
+
+ /*
+ * 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";
+ Curl_netrc_init(&store);
+ result = Curl_parsenetrc(&store,
+ "example.com", &login, &password, arg);
+ 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");
+- abort_unless(login != NULL, "returned NULL!");
+- fail_unless(strncmp(login, "admi", 4) == 0,
+- "login should not have been changed");
++ abort_unless(password == NULL, "password is not NULL!");
+ Curl_netrc_cleanup(&store);
+
+ /*
+ * 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";
+ Curl_netrc_init(&store);
+ result = Curl_parsenetrc(&store,
+ "example.com", &login, &password, arg);
+ 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");
+- abort_unless(login != NULL, "returned NULL!");
+- fail_unless(strncmp(login, "adminn", 6) == 0,
+- "login should not have been changed");
++ abort_unless(password == NULL, "password is not NULL!");
+ Curl_netrc_cleanup(&store);
+
+ /*
+ * 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;
+ Curl_netrc_init(&store);
+ result = Curl_parsenetrc(&store,
+ "example.com", &login, &password, arg);
+@@ -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;
+ Curl_netrc_init(&store);
+ result = Curl_parsenetrc(&store,
+ "example.com", &login, &password, arg);
+@@ -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;
+ Curl_netrc_init(&store);
+ result = Curl_parsenetrc(&store,
+ "curl.example.com", &login, &password, arg);
+@@ -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;
+ Curl_netrc_init(&store);
+ result = Curl_parsenetrc(&store,
+ "curl.example.com", &login, &password, arg);
+--
+2.33.0
+
diff --git a/backport-CVE-2024-2004.patch b/backport-CVE-2024-2004.patch
new file mode 100644
index 0000000..b8d947b
--- /dev/null
+++ b/backport-CVE-2024-2004.patch
@@ -0,0 +1,139 @@
+From 17d302e56221f5040092db77d4f85086e8a20e0e Mon Sep 17 00:00:00 2001
+From: Daniel Gustafsson <daniel@yesql.se>
+Date: Tue, 27 Feb 2024 15:43:56 +0100
+Subject: [PATCH] setopt: Fix disabling all protocols
+
+When disabling all protocols without enabling any, the resulting
+set of allowed protocols remained the default set. Clearing the
+allowed set before inspecting the passed value from --proto make
+the set empty even in the errorpath of no protocols enabled.
+
+Co-authored-by: Dan Fandrich <dan@telarity.com>
+Reported-by: Dan Fandrich <dan@telarity.com>
+Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+Closes: #13004
+
+Conflict:Context adapt
+Reference:https://github.com/curl/curl/commit/17d302e56221f5040092db77d4f85086e8a20e0e
+---
+ lib/setopt.c | 16 ++++++++--------
+ tests/data/Makefile.inc | 2 +-
+ tests/data/test1474 | 42 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 51 insertions(+), 9 deletions(-)
+ create mode 100644 tests/data/test1474
+
+diff --git a/lib/setopt.c b/lib/setopt.c
+index 6a4990cce..ce1321fc8 100644
+--- a/lib/setopt.c
++++ b/lib/setopt.c
+@@ -155,6 +155,12 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
+
+ static CURLcode protocol2num(const char *str, curl_prot_t *val)
+ {
++ /*
++ * We are asked to cherry-pick protocols, so play it safe and disallow all
++ * protocols to start with, and re-add the wanted ones back in.
++ */
++ *val = 0;
++
+ if(!str)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+@@ -163,8 +169,6 @@ static CURLcode protocol2num(const char *str, curl_prot_t *val)
+ return CURLE_OK;
+ }
+
+- *val = 0;
+-
+ do {
+ const char *token = str;
+ size_t tlen;
+@@ -2654,22 +2658,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
+ break;
+
+ case CURLOPT_PROTOCOLS_STR: {
+- curl_prot_t prot;
+ argptr = va_arg(param, char *);
+- result = protocol2num(argptr, &prot);
++ result = protocol2num(argptr, &data->set.allowed_protocols);
+ if(result)
+ return result;
+- data->set.allowed_protocols = prot;
+ break;
+ }
+
+ case CURLOPT_REDIR_PROTOCOLS_STR: {
+- curl_prot_t prot;
+ argptr = va_arg(param, char *);
+- result = protocol2num(argptr, &prot);
++ result = protocol2num(argptr, &data->set.redir_protocols);
+ if(result)
+ return result;
+- data->set.redir_protocols = prot;
+ break;
+ }
+
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index c20f90d94..b80ffb618 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -187,7 +187,7 @@ test1439 test1440 test1441 test1442 test1443 test1444 test1445 test1446 \
+ test1447 test1448 test1449 test1450 test1451 test1452 test1453 test1454 \
+ test1455 test1456 test1457 test1458 test1459 test1460 test1461 test1462 \
+ test1463 test1464 test1465 test1466 test1467 test1468 test1469 test1470 \
+-test1471 test1472 test1473 \
++test1471 test1472 test1473 test1474 \
+ \
+ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
+ test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
+diff --git a/tests/data/test1474 b/tests/data/test1474
+new file mode 100644
+index 000000000..c66fa2810
+--- /dev/null
++++ b/tests/data/test1474
+@@ -0,0 +1,42 @@
++<testcase>
++<info>
++<keywords>
++HTTP
++HTTP GET
++--proto
++</keywords>
++</info>
++
++#
++# Server-side
++<reply>
++<data>
++</data>
++</reply>
++
++#
++# Client-side
++<client>
++<server>
++none
++</server>
++<features>
++http
++</features>
++<name>
++--proto -all disables all protocols
++</name>
++<command>
++--proto -all http://%HOSTIP:%NOLISTENPORT/%TESTNUMBER
++</command>
++</client>
++
++#
++# Verify data after the test has been "shot"
++<verify>
++# 1 - Protocol "http" disabled
++<errorcode>
++1
++</errorcode>
++</verify>
++</testcase>
+--
+2.33.0
+
diff --git a/backport-CVE-2024-2398.patch b/backport-CVE-2024-2398.patch
new file mode 100644
index 0000000..c3128b1
--- /dev/null
+++ b/backport-CVE-2024-2398.patch
@@ -0,0 +1,96 @@
+From deca8039991886a559b67bcd6701db800a5cf764 Mon Sep 17 00:00:00 2001
+From: Stefan Eissing <stefan@eissing.org>
+Date: Wed, 6 Mar 2024 09:36:08 +0100
+Subject: [PATCH] http2: push headers better cleanup
+
+- provide common cleanup method for push headers
+
+Closes #13054
+
+Conflict:struct h2_stream_ctx *stream => struct stream_ctx *stream
+Context adapt
+Reference:https://github.com/curl/curl/commit/deca8039991886a559b67bcd6701db800a5cf764
+---
+ lib/http2.c | 34 +++++++++++++++-------------------
+ 1 file changed, 15 insertions(+), 19 deletions(-)
+
+diff --git a/lib/http2.c b/lib/http2.c
+index c63ecd383..96868728a 100644
+--- a/lib/http2.c
++++ b/lib/http2.c
+@@ -271,6 +271,15 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf,
+ return CURLE_OK;
+ }
+
++static void free_push_headers(struct stream_ctx *stream)
++{
++ size_t i;
++ for(i = 0; i<stream->push_headers_used; i++)
++ free(stream->push_headers[i]);
++ Curl_safefree(stream->push_headers);
++ stream->push_headers_used = 0;
++}
++
+ static void http2_data_done(struct Curl_cfilter *cf,
+ struct Curl_easy *data, bool premature)
+ {
+@@ -306,15 +315,7 @@ static void http2_data_done(struct Curl_cfilter *cf,
+ Curl_bufq_free(&stream->recvbuf);
+ Curl_h1_req_parse_free(&stream->h1);
+ Curl_dynhds_free(&stream->resp_trailers);
+- if(stream->push_headers) {
+- /* if they weren't used and then freed before */
+- for(; stream->push_headers_used > 0; --stream->push_headers_used) {
+- free(stream->push_headers[stream->push_headers_used - 1]);
+- }
+- free(stream->push_headers);
+- stream->push_headers = NULL;
+- }
+-
++ free_push_headers(stream);
+ free(stream);
+ H2_STREAM_LCTX(data) = NULL;
+ }
+@@ -860,7 +861,6 @@ static int push_promise(struct Curl_cfilter *cf,
+ struct curl_pushheaders heads;
+ CURLMcode rc;
+ CURLcode result;
+- size_t i;
+ /* clone the parent */
+ struct Curl_easy *newhandle = h2_duphandle(cf, data);
+ if(!newhandle) {
+@@ -905,11 +905,7 @@ static int push_promise(struct Curl_cfilter *cf,
+ Curl_set_in_callback(data, false);
+
+ /* free the headers again */
+- for(i = 0; i<stream->push_headers_used; i++)
+- free(stream->push_headers[i]);
+- free(stream->push_headers);
+- stream->push_headers = NULL;
+- stream->push_headers_used = 0;
++ free_push_headers(stream);
+
+ if(rv) {
+ DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
+@@ -1430,14 +1426,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
+ if(stream->push_headers_alloc > 1000) {
+ /* this is beyond crazy many headers, bail out */
+ failf(data_s, "Too many PUSH_PROMISE headers");
+- Curl_safefree(stream->push_headers);
++ free_push_headers(stream);
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
+ }
+ stream->push_headers_alloc *= 2;
+- headp = Curl_saferealloc(stream->push_headers,
+- stream->push_headers_alloc * sizeof(char *));
++ headp = realloc(stream->push_headers,
++ stream->push_headers_alloc * sizeof(char *));
+ if(!headp) {
+- stream->push_headers = NULL;
++ free_push_headers(stream);
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
+ }
+ stream->push_headers = headp;
+--
+2.33.0
+
diff --git a/backport-CVE-2024-7264-x509asn1-clean-up-GTime2str.patch b/backport-CVE-2024-7264-x509asn1-clean-up-GTime2str.patch
new file mode 100644
index 0000000..4f3ef5d
--- /dev/null
+++ b/backport-CVE-2024-7264-x509asn1-clean-up-GTime2str.patch
@@ -0,0 +1,60 @@
+From 3c914bc680155b32178f1f15ca8d47c7f4640afe Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 30 Jul 2024 10:05:17 +0200
+Subject: [PATCH] x509asn1: clean up GTime2str
+
+Co-authored-by: Stefan Eissing
+Reported-by: Dov Murik
+
+Closes #14307
+---
+ lib/vtls/x509asn1.c | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c
+index c3fd3a3..dd7985d 100644
+--- a/lib/vtls/x509asn1.c
++++ b/lib/vtls/x509asn1.c
+@@ -537,7 +537,7 @@ static const char *GTime2str(const char *beg, const char *end)
+ /* Convert an ASN.1 Generalized time to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+- for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
++ for(fracp = beg; fracp < end && ISDIGIT(*fracp); fracp++)
+ ;
+
+ /* Get seconds digits. */
+@@ -556,17 +556,22 @@ static const char *GTime2str(const char *beg, const char *end)
+ return NULL;
+ }
+
+- /* Scan for timezone, measure fractional seconds. */
++ /* timezone follows optional fractional seconds. */
+ tzp = fracp;
+- fracl = 0;
++ fracl = 0; /* no fractional seconds detected so far */
+ if(fracp < end && (*fracp == '.' || *fracp == ',')) {
+- fracp++;
+- do
++ /* Have fractional seconds, e.g. "[.,]\d+". How many? */
++ tzp = fracp++; /* should be a digit char or BAD ARGUMENT */
++ while(tzp < end && ISDIGIT(*tzp))
+ tzp++;
+- while(tzp < end && *tzp >= '0' && *tzp <= '9');
+- /* Strip leading zeroes in fractional seconds. */
+- for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
+- ;
++ if(tzp == fracp) /* never looped, no digit after [.,] */
++ return CURLE_BAD_FUNCTION_ARGUMENT;
++ fracl = tzp - fracp - 1; /* number of fractional sec digits */
++ DEBUGASSERT(fracl > 0);
++ /* Strip trailing zeroes in fractional seconds.
++ * May reduce fracl to 0 if only '0's are present. */
++ while(fracl && fracp[fracl - 1] == '0')
++ fracl--;
+ }
+
+ /* Process timezone. */
+--
+2.41.0
+
diff --git a/backport-CVE-2024-7264-x509asn1-unittests-and-fixes-fo.patch b/backport-CVE-2024-7264-x509asn1-unittests-and-fixes-fo.patch
new file mode 100644
index 0000000..f4949bc
--- /dev/null
+++ b/backport-CVE-2024-7264-x509asn1-unittests-and-fixes-fo.patch
@@ -0,0 +1,315 @@
+From 27959ecce75cdb2809c0bdb3286e60e08fadb519 Mon Sep 17 00:00:00 2001
+From: Stefan Eissing <stefan@eissing.org>
+Date: Tue, 30 Jul 2024 16:40:48 +0200
+Subject: [PATCH] x509asn1: unittests and fixes for gtime2str
+
+Fix issues in GTime2str() and add unit test cases to verify correct
+behaviour.
+
+Follow-up to 3c914bc6801
+
+Closes #14316
+---
+ lib/vtls/x509asn1.c | 32 +++++++---
+ lib/vtls/x509asn1.h | 11 ++++
+ tests/data/Makefile.inc | 2 +-
+ tests/data/test1656 | 22 +++++++
+ tests/unit/Makefile.inc | 4 +-
+ tests/unit/unit1656.c | 133 ++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 194 insertions(+), 10 deletions(-)
+ create mode 100644 tests/data/test1656
+ create mode 100644 tests/unit/unit1656.c
+
+diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c
+index dd7985d..5c65df1 100644
+--- a/lib/vtls/x509asn1.c
++++ b/lib/vtls/x509asn1.c
+@@ -561,12 +561,13 @@ static const char *GTime2str(const char *beg, const char *end)
+ fracl = 0; /* no fractional seconds detected so far */
+ if(fracp < end && (*fracp == '.' || *fracp == ',')) {
+ /* Have fractional seconds, e.g. "[.,]\d+". How many? */
+- tzp = fracp++; /* should be a digit char or BAD ARGUMENT */
++ fracp++; /* should be a digit char or BAD ARGUMENT */
++ tzp = fracp;
+ while(tzp < end && ISDIGIT(*tzp))
+ tzp++;
+ if(tzp == fracp) /* never looped, no digit after [.,] */
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+- fracl = tzp - fracp - 1; /* number of fractional sec digits */
++ fracl = tzp - fracp; /* number of fractional sec digits */
+ DEBUGASSERT(fracl > 0);
+ /* Strip trailing zeroes in fractional seconds.
+ * May reduce fracl to 0 if only '0's are present. */
+@@ -575,18 +576,24 @@ static const char *GTime2str(const char *beg, const char *end)
+ }
+
+ /* Process timezone. */
+- if(tzp >= end)
+- ; /* Nothing to do. */
++ if(tzp >= end) {
++ tzp = "";
++ tzl = 0;
++ }
+ else if(*tzp == 'Z') {
+- tzp = " GMT";
+- end = tzp + 4;
++ sep = " ";
++ tzp = "GMT";
++ tzl = 3;
++ }
++ else if((*tzp == '+') || (*tzp == '-')) {
++ sep = " UTC";
++ tzl = end - tzp;
+ }
+ else {
+ sep = " ";
+- tzp++;
++ tzl = end - tzp;
+ }
+
+- tzl = end - tzp;
+ return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
+ beg, beg + 4, beg + 6,
+ beg + 8, beg + 10, sec1, sec2,
+@@ -594,6 +601,15 @@ static const char *GTime2str(const char *beg, const char *end)
+ sep, (int)tzl, tzp);
+ }
+
++#ifdef UNITTESTS
++/* used by unit1656.c */
++CURLcode Curl_x509_GTime2str(struct dynbuf *store,
++ const char *beg, const char *end)
++{
++ return GTime2str(store, beg, end);
++}
++#endif
++
+ /*
+ * Convert an ASN.1 UTC time to a printable string.
+ * Return the dynamically allocated string, or NULL if an error occurs.
+diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h
+index 23a67b8..1d8bbab 100644
+--- a/lib/vtls/x509asn1.h
++++ b/lib/vtls/x509asn1.h
+@@ -76,5 +76,16 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
+ const char *beg, const char *end);
+ CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const char *beg, const char *end);
++
++#ifdef UNITTESTS
++#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
++ defined(USE_MBEDTLS)
++
++/* used by unit1656.c */
++CURLcode Curl_x509_GTime2str(struct dynbuf *store,
++ const char *beg, const char *end);
++#endif
++#endif
++
+ #endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
+ #endif /* HEADER_CURL_X509ASN1_H */
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index 1472b19..0af94e6 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -207,7 +207,7 @@ test1620 test1621 \
+ \
+ test1630 test1631 test1632 test1633 test1634 test1635 \
+ \
+-test1650 test1651 test1652 test1653 test1654 test1655 \
++test1650 test1651 test1652 test1653 test1654 test1655 test1656 \
+ test1660 test1661 test1662 \
+ \
+ test1670 test1671 \
+diff --git a/tests/data/test1656 b/tests/data/test1656
+new file mode 100644
+index 0000000..2fab21b
+--- /dev/null
++++ b/tests/data/test1656
+@@ -0,0 +1,22 @@
++<testcase>
++<info>
++<keywords>
++unittest
++Curl_x509_GTime2str
++</keywords>
++</info>
++
++#
++# Client-side
++<client>
++<server>
++none
++</server>
++<features>
++unittest
++</features>
++<name>
++Curl_x509_GTime2str unit tests
++</name>
++</client>
++</testcase>
+diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc
+index 36e922b..b0eaf64 100644
+--- a/tests/unit/Makefile.inc
++++ b/tests/unit/Makefile.inc
+@@ -36,7 +36,7 @@ UNITPROGS = unit1300 unit1302 unit1303 unit1304 unit1305 unit1307 \
+ unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
+ unit1608 unit1609 unit1610 unit1611 unit1612 unit1614 \
+ unit1620 unit1621 \
+- unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
++ unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 unit1656 \
+ unit1660 unit1661 \
+ unit2600 unit2601 unit2602 unit2603 \
+ unit3200
+@@ -117,6 +117,8 @@ unit1654_SOURCES = unit1654.c $(UNITFILES)
+
+ unit1655_SOURCES = unit1655.c $(UNITFILES)
+
++unit1656_SOURCES = unit1656.c $(UNITFILES)
++
+ unit1660_SOURCES = unit1660.c $(UNITFILES)
+
+ unit1661_SOURCES = unit1661.c $(UNITFILES)
+diff --git a/tests/unit/unit1656.c b/tests/unit/unit1656.c
+new file mode 100644
+index 0000000..644e72f
+--- /dev/null
++++ b/tests/unit/unit1656.c
+@@ -0,0 +1,133 @@
++/***************************************************************************
++ * _ _ ____ _
++ * Project ___| | | | _ \| |
++ * / __| | | | |_) | |
++ * | (__| |_| | _ <| |___
++ * \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++#include "curlcheck.h"
++
++#include "vtls/x509asn1.h"
++
++static CURLcode unit_setup(void)
++{
++ return CURLE_OK;
++}
++
++static void unit_stop(void)
++{
++
++}
++
++#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
++ defined(USE_MBEDTLS)
++
++#ifndef ARRAYSIZE
++#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
++#endif
++
++struct test_spec {
++ const char *input;
++ const char *exp_output;
++ CURLcode exp_result;
++};
++
++static struct test_spec test_specs[] = {
++ { "190321134340", "1903-21-13 43:40:00", CURLE_OK },
++ { "", NULL, CURLE_BAD_FUNCTION_ARGUMENT },
++ { "WTF", NULL, CURLE_BAD_FUNCTION_ARGUMENT },
++ { "0WTF", NULL, CURLE_BAD_FUNCTION_ARGUMENT },
++ { "19032113434", NULL, CURLE_BAD_FUNCTION_ARGUMENT },
++ { "19032113434WTF", NULL, CURLE_BAD_FUNCTION_ARGUMENT },
++ { "190321134340.", NULL, CURLE_BAD_FUNCTION_ARGUMENT },
++ { "190321134340.1", "1903-21-13 43:40:00.1", CURLE_OK },
++ { "19032113434017.0", "1903-21-13 43:40:17", CURLE_OK },
++ { "19032113434017.01", "1903-21-13 43:40:17.01", CURLE_OK },
++ { "19032113434003.001", "1903-21-13 43:40:03.001", CURLE_OK },
++ { "19032113434003.090", "1903-21-13 43:40:03.09", CURLE_OK },
++ { "190321134340Z", "1903-21-13 43:40:00 GMT", CURLE_OK },
++ { "19032113434017.0Z", "1903-21-13 43:40:17 GMT", CURLE_OK },
++ { "19032113434017.01Z", "1903-21-13 43:40:17.01 GMT", CURLE_OK },
++ { "19032113434003.001Z", "1903-21-13 43:40:03.001 GMT", CURLE_OK },
++ { "19032113434003.090Z", "1903-21-13 43:40:03.09 GMT", CURLE_OK },
++ { "190321134340CET", "1903-21-13 43:40:00 CET", CURLE_OK },
++ { "19032113434017.0CET", "1903-21-13 43:40:17 CET", CURLE_OK },
++ { "19032113434017.01CET", "1903-21-13 43:40:17.01 CET", CURLE_OK },
++ { "190321134340+02:30", "1903-21-13 43:40:00 UTC+02:30", CURLE_OK },
++ { "19032113434017.0+02:30", "1903-21-13 43:40:17 UTC+02:30", CURLE_OK },
++ { "19032113434017.01+02:30", "1903-21-13 43:40:17.01 UTC+02:30", CURLE_OK },
++ { "190321134340-3", "1903-21-13 43:40:00 UTC-3", CURLE_OK },
++ { "19032113434017.0-04", "1903-21-13 43:40:17 UTC-04", CURLE_OK },
++ { "19032113434017.01-01:10", "1903-21-13 43:40:17.01 UTC-01:10", CURLE_OK },
++};
++
++static bool do_test(struct test_spec *spec, size_t i, struct dynbuf *dbuf)
++{
++ CURLcode result;
++ const char *in = spec->input;
++
++ Curl_dyn_reset(dbuf);
++ result = Curl_x509_GTime2str(dbuf, in, in + strlen(in));
++ if(result != spec->exp_result) {
++ fprintf(stderr, "test %zu: expect result %d, got %d\n",
++ i, spec->exp_result, result);
++ return FALSE;
++ }
++ else if(!result && strcmp(spec->exp_output, Curl_dyn_ptr(dbuf))) {
++ fprintf(stderr, "test %zu: input '%s', expected output '%s', got '%s'\n",
++ i, in, spec->exp_output, Curl_dyn_ptr(dbuf));
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++UNITTEST_START
++{
++ size_t i;
++ struct dynbuf dbuf;
++ bool all_ok = TRUE;
++
++ Curl_dyn_init(&dbuf, 32*1024);
++
++ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
++ fprintf(stderr, "curl_global_init() failed\n");
++ return TEST_ERR_MAJOR_BAD;
++ }
++
++ for(i = 0; i < ARRAYSIZE(test_specs); ++i) {
++ if(!do_test(&test_specs[i], i, &dbuf))
++ all_ok = FALSE;
++ }
++ fail_unless(all_ok, "some tests of Curl_x509_GTime2str() fails");
++
++ Curl_dyn_free(&dbuf);
++ curl_global_cleanup();
++}
++UNITTEST_STOP
++
++#else
++
++UNITTEST_START
++{
++ puts("not tested since Curl_x509_GTime2str() is not built-in");
++}
++UNITTEST_STOP
++
++#endif
+--
+2.41.0
+
diff --git a/backport-CVE-2024-8096-gtls-fix-OCSP-stapling-management.patch b/backport-CVE-2024-8096-gtls-fix-OCSP-stapling-management.patch
new file mode 100644
index 0000000..462971d
--- /dev/null
+++ b/backport-CVE-2024-8096-gtls-fix-OCSP-stapling-management.patch
@@ -0,0 +1,206 @@
+From aeb1a281cab13c7ba791cb104e556b20e713941f Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 20 Aug 2024 16:14:39 +0200
+Subject: [PATCH] gtls: fix OCSP stapling management
+
+Reported-by: Hiroki Kurosawa
+Closes #14642
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/aeb1a281cab13c7ba791cb104e556b20e713941f
+---
+ lib/vtls/gtls.c | 146 ++++++++++++++++++++++++------------------------
+ 1 file changed, 73 insertions(+), 73 deletions(-)
+
+diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
+index 03d6fcc03..c7589d9d3 100644
+--- a/lib/vtls/gtls.c
++++ b/lib/vtls/gtls.c
+@@ -850,6 +850,13 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
+ init_flags |= GNUTLS_NO_TICKETS;
+ #endif
+
++#if defined(GNUTLS_NO_STATUS_REQUEST)
++ if(!config->verifystatus)
++ /* Disable the "status_request" TLS extension, enabled by default since
++ GnuTLS 3.8.0. */
++ init_flags |= GNUTLS_NO_STATUS_REQUEST;
++#endif
++
+ rc = gnutls_init(&gtls->session, init_flags);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_init() failed: %d", rc);
+@@ -1321,104 +1328,97 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
+ infof(data, " server certificate verification SKIPPED");
+
+ if(config->verifystatus) {
+- if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
+- gnutls_datum_t status_request;
+- gnutls_ocsp_resp_t ocsp_resp;
++ gnutls_datum_t status_request;
++ gnutls_ocsp_resp_t ocsp_resp;
++ gnutls_ocsp_cert_status_t status;
++ gnutls_x509_crl_reason_t reason;
+
+- gnutls_ocsp_cert_status_t status;
+- gnutls_x509_crl_reason_t reason;
++ rc = gnutls_ocsp_status_request_get(session, &status_request);
+
+- rc = gnutls_ocsp_status_request_get(session, &status_request);
++ if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
++ failf(data, "No OCSP response received");
++ return CURLE_SSL_INVALIDCERTSTATUS;
++ }
+
+- infof(data, " server certificate status verification FAILED");
++ if(rc < 0) {
++ failf(data, "Invalid OCSP response received");
++ return CURLE_SSL_INVALIDCERTSTATUS;
++ }
+
+- if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+- failf(data, "No OCSP response received");
+- return CURLE_SSL_INVALIDCERTSTATUS;
+- }
++ gnutls_ocsp_resp_init(&ocsp_resp);
+
+- if(rc < 0) {
+- failf(data, "Invalid OCSP response received");
+- return CURLE_SSL_INVALIDCERTSTATUS;
+- }
++ rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
++ if(rc < 0) {
++ failf(data, "Invalid OCSP response received");
++ return CURLE_SSL_INVALIDCERTSTATUS;
++ }
+
+- gnutls_ocsp_resp_init(&ocsp_resp);
++ (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
++ &status, NULL, NULL, NULL, &reason);
+
+- rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
+- if(rc < 0) {
+- failf(data, "Invalid OCSP response received");
+- return CURLE_SSL_INVALIDCERTSTATUS;
+- }
++ switch(status) {
++ case GNUTLS_OCSP_CERT_GOOD:
++ break;
+
+- (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
+- &status, NULL, NULL, NULL, &reason);
++ case GNUTLS_OCSP_CERT_REVOKED: {
++ const char *crl_reason;
+
+- switch(status) {
+- case GNUTLS_OCSP_CERT_GOOD:
++ switch(reason) {
++ default:
++ case GNUTLS_X509_CRLREASON_UNSPECIFIED:
++ crl_reason = "unspecified reason";
+ break;
+
+- case GNUTLS_OCSP_CERT_REVOKED: {
+- const char *crl_reason;
+-
+- switch(reason) {
+- default:
+- case GNUTLS_X509_CRLREASON_UNSPECIFIED:
+- crl_reason = "unspecified reason";
+- break;
+-
+- case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
+- crl_reason = "private key compromised";
+- break;
+-
+- case GNUTLS_X509_CRLREASON_CACOMPROMISE:
+- crl_reason = "CA compromised";
+- break;
+-
+- case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
+- crl_reason = "affiliation has changed";
+- break;
++ case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
++ crl_reason = "private key compromised";
++ break;
+
+- case GNUTLS_X509_CRLREASON_SUPERSEDED:
+- crl_reason = "certificate superseded";
+- break;
++ case GNUTLS_X509_CRLREASON_CACOMPROMISE:
++ crl_reason = "CA compromised";
++ break;
+
+- case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
+- crl_reason = "operation has ceased";
+- break;
++ case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
++ crl_reason = "affiliation has changed";
++ break;
+
+- case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
+- crl_reason = "certificate is on hold";
+- break;
++ case GNUTLS_X509_CRLREASON_SUPERSEDED:
++ crl_reason = "certificate superseded";
++ break;
+
+- case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
+- crl_reason = "will be removed from delta CRL";
+- break;
++ case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
++ crl_reason = "operation has ceased";
++ break;
+
+- case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
+- crl_reason = "privilege withdrawn";
+- break;
++ case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
++ crl_reason = "certificate is on hold";
++ break;
+
+- case GNUTLS_X509_CRLREASON_AACOMPROMISE:
+- crl_reason = "AA compromised";
+- break;
+- }
++ case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
++ crl_reason = "will be removed from delta CRL";
++ break;
+
+- failf(data, "Server certificate was revoked: %s", crl_reason);
++ case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
++ crl_reason = "privilege withdrawn";
+ break;
+- }
+
+- default:
+- case GNUTLS_OCSP_CERT_UNKNOWN:
+- failf(data, "Server certificate status is unknown");
++ case GNUTLS_X509_CRLREASON_AACOMPROMISE:
++ crl_reason = "AA compromised";
+ break;
+ }
+
+- gnutls_ocsp_resp_deinit(ocsp_resp);
++ failf(data, "Server certificate was revoked: %s", crl_reason);
++ break;
++ }
+
+- return CURLE_SSL_INVALIDCERTSTATUS;
++ default:
++ case GNUTLS_OCSP_CERT_UNKNOWN:
++ failf(data, "Server certificate status is unknown");
++ break;
+ }
+- else
+- infof(data, " server certificate status verification OK");
++
++ gnutls_ocsp_resp_deinit(ocsp_resp);
++ if(status != GNUTLS_OCSP_CERT_GOOD)
++ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
+ else
+ infof(data, " server certificate status verification SKIPPED");
+--
+2.33.0
+
diff --git a/backport-CVE-2024-9681.patch b/backport-CVE-2024-9681.patch
new file mode 100644
index 0000000..6b5abae
--- /dev/null
+++ b/backport-CVE-2024-9681.patch
@@ -0,0 +1,82 @@
+From a94973805df96269bf3f3bf0a20ccb9887313316 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Wed, 9 Oct 2024 10:04:35 +0200
+Subject: [PATCH] hsts: improve subdomain handling
+
+- on load, only replace existing HSTS entries if there is a full host
+ match
+
+- on matching, prefer a full host match and secondary the longest tail
+ subdomain match
+
+Closes #15210
+Conflict:Context adapt
+Reference:https://github.com/curl/curl/commit/a94973805df96269bf3f3bf0a20ccb9887313316
+---
+ lib/hsts.c | 14 ++++++++++----
+ tests/data/test1660 | 2 +-
+ 2 files changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/lib/hsts.c b/lib/hsts.c
+index d5e883f51ef0f7..12052ce53c1c5a 100644
+--- a/lib/hsts.c
++++ b/lib/hsts.c
+@@ -249,11 +249,13 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
+ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+ bool subdomain)
+ {
++ struct stsentry *bestsub = NULL;
+ if(h) {
+ time_t now = time(NULL);
+ size_t hlen = strlen(hostname);
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
++ size_t blen = 0;
+
+ if((hlen > MAX_HSTS_HOSTLEN) || !hlen)
+ return NULL;
+@@ -275,15 +277,19 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+ if((subdomain && sts->includeSubDomains) && (ntail < hlen)) {
+ size_t offs = hlen - ntail;
+ if((hostname[offs-1] == '.') &&
+- strncasecompare(&hostname[offs], sts->host, ntail))
+- return sts;
++ strncasecompare(&hostname[offs], sts->host, ntail) &&
++ (ntail > blen)) {
++ /* save the tail match with the longest tail */
++ bestsub = sts;
++ blen = ntail;
++ }
+ }
+ /* avoid strcasecompare because the host name is not null terminated */
+ if((hlen == ntail) && strncasecompare(hostname, sts->host, hlen))
+ return sts;
+ }
+ }
+- return NULL; /* no match */
++ return bestsub;
+ }
+
+ /*
+@@ -435,7 +441,7 @@ static CURLcode hsts_add(struct hsts *h, char *line)
+ e = Curl_hsts(h, p, subdomain);
+ if(!e)
+ result = hsts_create(h, p, subdomain, expires);
+- else {
++ else if(strcasecompare(p, e->host)) {
+ /* the same host name, use the largest expire time */
+ if(expires > e->expires)
+ e->expires = expires;
+diff --git a/tests/data/test1660 b/tests/data/test1660
+index f86126d19cf269..4b6f9615c9d517 100644
+--- a/tests/data/test1660
++++ b/tests/data/test1660
+@@ -52,7 +52,7 @@ this.example [this.example]: 1548400797
+ Input 12: error 43
+ Input 13: error 43
+ Input 14: error 43
+-3.example.com [example.com]: 1569905261 includeSubDomains
++3.example.com [3.example.com]: 1569905261 includeSubDomains
+ 3.example.com [example.com]: 1569905261 includeSubDomains
+ foo.example.com [example.com]: 1569905261 includeSubDomains
+ 'foo.xample.com' is not HSTS
diff --git a/backport-CVE-2025-0167.patch b/backport-CVE-2025-0167.patch
new file mode 100644
index 0000000..4b33584
--- /dev/null
+++ b/backport-CVE-2025-0167.patch
@@ -0,0 +1,170 @@
+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 | 15 ++++--
+ tests/data/Makefile.inc | 2 +-
+ tests/data/test486 | 105 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 116 insertions(+), 6 deletions(-)
+ create mode 100644 tests/data/test486
+
+diff --git a/lib/netrc.c b/lib/netrc.c
+index b517c1dfab67..7ad81ece229f 100644
+--- a/lib/netrc.c
++++ b/lib/netrc.c
+@@ -316,11 +316,16 @@ static int parsenetrc(struct store_netrc *store,
+
+ out:
+ Curl_dyn_free(&token);
+- if(!retcode && !password && our_login) {
+- /* success without a password, set a blank one */
+- password = strdup("");
+- if(!password)
+- retcode = 1; /* out of memory */
++ if(!retcode) {
++ if(!password && our_login) {
++ /* success without a password, set a blank one */
++ password = strdup("");
++ if(!password)
++ retcode = 1; /* out of memory */
++ }
++ 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 test427 test428 test429 test430 test431 test432 test433 test434 \
+ test435 test436 test437 test438 test439 test440 test441 test442 test443 \
+ test444 test445 test446 test447 test448 test449 test450 test451 test452 \
+ test453 test454 test455 test456 test457 test458 \
+-test478 test479 test480 \
++test478 test479 test480 test486 \
+ \
+ test490 test491 test492 test493 test494 test495 test496 test497 test498 \
+ \
+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 %LOGDIR/netrc%TESTNUMBER -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/
++</command>
++<file name="%LOGDIR/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>
diff --git a/backport-CVE-2025-0725.patch b/backport-CVE-2025-0725.patch
new file mode 100644
index 0000000..1d36d08
--- /dev/null
+++ b/backport-CVE-2025-0725.patch
@@ -0,0 +1,324 @@
+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 d7513a8..f8aba15 100644
+--- a/docs/INTERNALS.md
++++ b/docs/INTERNALS.md
+@@ -20,7 +20,7 @@ versions of libs and build tools.
+
+ - 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 be7c075..7fc418e 100644
+--- a/lib/content_encoding.c
++++ b/lib/content_encoding.c
+@@ -65,31 +65,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;
+
+@@ -134,9 +116,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);
+@@ -185,8 +164,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
+@@ -333,114 +311,27 @@ static CURLcode gzip_init_writer(struct Curl_easy *data,
+ {
+ struct zlib_writer *zp = (struct zlib_writer *) writer;
+ z_stream *z = &zp->z; /* zlib state structure */
++ const char *v = zlibVersion();
+
+ /* Initialize zlib */
+ 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)
+@@ -456,117 +347,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,
diff --git a/backport-cookie-treat-cookie-name-case-sensitively.patch b/backport-cookie-treat-cookie-name-case-sensitively.patch
new file mode 100644
index 0000000..bc1f790
--- /dev/null
+++ b/backport-cookie-treat-cookie-name-case-sensitively.patch
@@ -0,0 +1,71 @@
+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 | 4 ++--
+ tests/data/test31 | 3 +++
+ 2 files changed, 5 insertions(+), 2 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,
+ myhash = cookiehash(co->domain);
+ clist = c->cookies[myhash];
+ while(clist) {
+- if(strcasecompare(clist->name, co->name)) {
++ if(!strcmp(clist->name, co->name)) {
+ /* the names are identical */
+ bool matching_domains = FALSE;
+
+@@ -1029,7 +1029,7 @@ replace_existing(struct Curl_easy *data,
+ }
+ }
+
+- if(!replace_co && strcasecompare(clist->name, co->name)) {
++ if(!replace_co && !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
+ test31.curl FALSE / FALSE 0 blankdomain sure
+ </file>
+--
+2.33.0
+
diff --git a/backport-curl-7.84.0-test3026.patch b/backport-curl-7.84.0-test3026.patch
new file mode 100644
index 0000000..1098583
--- /dev/null
+++ b/backport-curl-7.84.0-test3026.patch
@@ -0,0 +1,71 @@
+From 279b990727a1fd3e2828fbbd80581777e4200b67 Mon Sep 17 00:00:00 2001
+From: Kamil Dudka <kdudka@redhat.com>
+Date: Mon, 27 Jun 2022 16:50:57 +0200
+Subject: [PATCH] test3026: disable valgrind
+
+It fails on x86_64 with:
+```
+ Use --max-threads=INT to specify a larger number of threads
+ and rerun valgrind
+ valgrind: the 'impossible' happened:
+ Max number of threads is too low
+ host stacktrace:
+ ==174357== at 0x58042F5A: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x58043087: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x580432EF: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x58043310: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x58099E77: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x580E67E9: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x5809D59D: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x5809901A: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x5809B0B6: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ ==174357== by 0x580E4050: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux)
+ sched status:
+ running_tid=1
+ Thread 1: status = VgTs_Runnable syscall 56 (lwpid 174357)
+ ==174357== at 0x4A07816: clone (in /usr/lib64/libc.so.6)
+ ==174357== by 0x4A08720: __clone_internal (in /usr/lib64/libc.so.6)
+ ==174357== by 0x4987ACF: create_thread (in /usr/lib64/libc.so.6)
+ ==174357== by 0x49885F6: pthread_create@@GLIBC_2.34 (in /usr/lib64/libc.so.6)
+ ==174357== by 0x1093B5: test.part.0 (lib3026.c:64)
+ ==174357== by 0x492454F: (below main) (in /usr/lib64/libc.so.6)
+ client stack range: [0x1FFEFFC000 0x1FFF000FFF] client SP: 0x1FFEFFC998
+ valgrind stack range: [0x1002BAA000 0x1002CA9FFF] top usage: 11728 of 1048576
+[...]
+```
+---
+ tests/data/test3026 | 3 +++
+ tests/libtest/lib3026.c | 4 ++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/tests/data/test3026 b/tests/data/test3026
+index fb80cc8..01f2ba5 100644
+--- a/tests/data/test3026
++++ b/tests/data/test3026
+@@ -41,5 +41,8 @@ none
+ <errorcode>
+ 0
+ </errorcode>
++<valgrind>
++disable
++</valgrind>
+ </verify>
+ </testcase>
+diff --git a/tests/libtest/lib3026.c b/tests/libtest/lib3026.c
+index 43fe335..70cd7a4 100644
+--- a/tests/libtest/lib3026.c
++++ b/tests/libtest/lib3026.c
+@@ -147,8 +147,8 @@ int test(char *URL)
+ results[i] = CURL_LAST; /* initialize with invalid value */
+ res = pthread_create(&tids[i], NULL, run_thread, &results[i]);
+ if(res) {
+- fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n",
+- __FILE__, __LINE__, res);
++ fprintf(stderr, "%s:%d Couldn't create thread, i=%u, errno %d\n",
++ __FILE__, __LINE__, i, res);
+ tid_count = i;
+ test_failure = -1;
+ goto cleanup;
+--
+2.37.1
+
diff --git a/backport-curl-7.88.0-tests-warnings.patch b/backport-curl-7.88.0-tests-warnings.patch
new file mode 100644
index 0000000..04b2ba2
--- /dev/null
+++ b/backport-curl-7.88.0-tests-warnings.patch
@@ -0,0 +1,30 @@
+From d506d885aa16b4a87acbac082eea41dccdc7b69f Mon Sep 17 00:00:00 2001
+From: Kamil Dudka <kdudka@redhat.com>
+Date: Wed, 15 Feb 2023 10:42:38 +0100
+Subject: [PATCH] Revert "runtests: consider warnings fatal and error on them"
+
+While it might be useful for upstream developers, it is not so useful
+for downstream consumers.
+
+This reverts upstream commit 22f795c834cfdbacbb1b55426028a581e3cf67a8.
+---
+ tests/runtests.pl | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/tests/runtests.pl b/tests/runtests.pl
+index 71644ad18..0cf85c3fe 100755
+--- a/tests/runtests.pl
++++ b/tests/runtests.pl
+@@ -55,8 +55,7 @@
+ # given, this won't be a problem.
+
+ use strict;
+-# Promote all warnings to fatal
+-use warnings FATAL => 'all';
++use warnings;
+ use 5.006;
+
+ # These should be the only variables that might be needed to get edited:
+--
+2.39.1
+
diff --git a/backport-libssh2-set-length-to-0-if-strdup-failed.patch b/backport-libssh2-set-length-to-0-if-strdup-failed.patch
new file mode 100644
index 0000000..eeeb7c0
--- /dev/null
+++ b/backport-libssh2-set-length-to-0-if-strdup-failed.patch
@@ -0,0 +1,31 @@
+From 6f3204820052263f488f86e02c206e1d24c4da2c Mon Sep 17 00:00:00 2001
+From: Tobias Stoeckmann <tobias@stoeckmann.org>
+Date: Thu, 28 Mar 2024 00:38:09 +0100
+Subject: [PATCH] libssh2: set length to 0 if strdup failed
+
+Internally, libssh2 dereferences the NULL pointer if length is non-zero.
+The callback function cannot return the error condition, so at least
+prevent subsequent crash.
+
+Closes #13213
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/6f3204820052263f488f86e02c206e1d24c4da2c
+---
+ lib/vssh/libssh2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c
+index 3cfbe126c69df3..7d8d5f46571e9f 100644
+--- a/lib/vssh/libssh2.c
++++ b/lib/vssh/libssh2.c
+@@ -201,7 +201,8 @@ kbd_callback(const char *name, int name_len, const char *instruction,
+ if(num_prompts == 1) {
+ struct connectdata *conn = data->conn;
+ responses[0].text = strdup(conn->passwd);
+- responses[0].length = curlx_uztoui(strlen(conn->passwd));
++ responses[0].length =
++ responses[0].text == NULL ? 0 : curlx_uztoui(strlen(conn->passwd));
+ }
+ (void)prompts;
+ } /* kbd_callback */
diff --git a/backport-multi-avoid-memory-leak-risk.patch b/backport-multi-avoid-memory-leak-risk.patch
new file mode 100644
index 0000000..0a0ed59
--- /dev/null
+++ b/backport-multi-avoid-memory-leak-risk.patch
@@ -0,0 +1,46 @@
+From 3572dd65bb233fc2720634804312192e3bdf4adf Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Thu, 25 Apr 2024 09:52:51 +0200
+Subject: [PATCH] multi: avoid memory-leak risk
+
+'newurl' is allocated in some conditions and used in a few scenarios,
+but there were theoretical combinations in which it would not get freed.
+Move the free to happen unconditionally. Never triggered by tests, but
+spotted by Coverity.
+
+Closes #13471
+
+Conflict:Context adapt
+Reference:https://github.com/curl/curl/commit/3572dd65bb233fc2720634804312192e3bdf4adf
+---
+ lib/multi.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/lib/multi.c b/lib/multi.c
+index fb98d80639f3b7..7e7590d60f8bcb 100644
+--- a/lib/multi.c
++++ b/lib/multi.c
+@@ -2530,7 +2530,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
+ multistate(data, MSTATE_CONNECT);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+- free(newurl);
+ }
+ else {
+ /* after the transfer is done, go DONE */
+@@ -2542,7 +2541,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
+ newurl = data->req.location;
+ data->req.location = NULL;
+ result = Curl_follow(data, newurl, FOLLOW_FAKE);
+- free(newurl);
+ if(result) {
+ stream_error = TRUE;
+ result = multi_done(data, result, TRUE);
+@@ -2561,6 +2559,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
+ transfers */
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ }
++ free(newurl);
+ break;
+ }
+
diff --git a/backport-multi-check-that-the-multi-handle-is-valid-in-curl_m.patch b/backport-multi-check-that-the-multi-handle-is-valid-in-curl_m.patch
new file mode 100644
index 0000000..c1dc6f5
--- /dev/null
+++ b/backport-multi-check-that-the-multi-handle-is-valid-in-curl_m.patch
@@ -0,0 +1,37 @@
+From 48f61e781a01e6a8dbc4a347e280644b1c68ab6a Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Wed, 11 Sep 2024 14:12:41 +0200
+Subject: [PATCH] multi: check that the multi handle is valid in
+ curl_multi_assign
+
+By requiring that the multi handle is fine, it can detect bad usage
+better and by that avoid crashes. Like in the #14860 case, which is an
+application calling curl_multi_assign() with a NULL pointer multi
+handle.
+
+Reported-by: Carlo Cabrera
+Fixes #14860
+Closes #14862
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/48f61e781a01e6a8dbc4a347e280644b1c68ab6a
+---
+ lib/multi.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/lib/multi.c b/lib/multi.c
+index 062d09cc0..78e5c0a1e 100644
+--- a/lib/multi.c
++++ b/lib/multi.c
+@@ -3688,6 +3688,8 @@ CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
+ void *hashp)
+ {
+ struct Curl_sh_entry *there = NULL;
++ if(!GOOD_MULTI_HANDLE(multi))
++ return CURLM_BAD_HANDLE;
+
+ there = sh_getentry(&multi->sockhash, s);
+
+--
+2.33.0
+
diff --git a/backport-openldap-create-ldap-URLs-correctly-for-IPv6-addresses.patch b/backport-openldap-create-ldap-URLs-correctly-for-IPv6-addresses.patch
new file mode 100644
index 0000000..aabfa79
--- /dev/null
+++ b/backport-openldap-create-ldap-URLs-correctly-for-IPv6-addresses.patch
@@ -0,0 +1,35 @@
+From 56935a7dada6975d5a46aa494de0af195e4e8659 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Sat, 30 Mar 2024 11:14:54 +0100
+Subject: [PATCH] openldap: create ldap URLs correctly for IPv6 addresses
+
+Reported-by: Sergio Durigan Junior
+Fixes #13228
+Closes #13235
+
+Conflict:Context adapt
+Reference:https://github.com/curl/curl/commit/56935a7dada6975d5a46aa494de0af195e4e8659
+---
+ lib/openldap.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/lib/openldap.c b/lib/openldap.c
+index 47266f64e44733..85a37b8186041a 100644
+--- a/lib/openldap.c
++++ b/lib/openldap.c
+@@ -548,9 +548,12 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
+
+ (void)done;
+
+- hosturl = aprintf("ldap%s://%s:%d",
+- conn->handler->flags & PROTOPT_SSL? "s": "",
+- conn->host.name, conn->remote_port);
++ hosturl = aprintf("%s://%s%s%s:%d",
++ conn->handler->scheme,
++ conn->bits.ipv6_ip? "[": "",
++ conn->host.name,
++ conn->bits.ipv6_ip? "]": "",
++ conn->remote_port);
+ if(!hosturl)
+ return CURLE_OUT_OF_MEMORY;
+
diff --git a/backport-openssl-avoid-BN_num_bits-NULL-pointer-derefs.patch b/backport-openssl-avoid-BN_num_bits-NULL-pointer-derefs.patch
new file mode 100644
index 0000000..4a75f4c
--- /dev/null
+++ b/backport-openssl-avoid-BN_num_bits-NULL-pointer-derefs.patch
@@ -0,0 +1,34 @@
+From b9f832edcce9db2de31070e76c3cbe59ca9ef512 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Thu, 12 Oct 2023 16:00:38 +0200
+Subject: [PATCH] openssl: avoid BN_num_bits() NULL pointer derefs
+
+Reported-by: icy17 on github
+Fixes #12099
+Closes #12100
+
+Conflict: NA
+Reference: https://github.com/curl/curl/commit/b9f832edcce9db2de31070e76c3cbe59ca9ef512
+---
+ lib/vtls/openssl.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
+index 9f9c8d136..6be86f871 100644
+--- a/lib/vtls/openssl.c
++++ b/lib/vtls/openssl.c
+@@ -538,9 +538,9 @@ CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
+ #else
+ RSA_get0_key(rsa, &n, &e, NULL);
+ #endif /* HAVE_EVP_PKEY_GET_PARAMS */
+- BIO_printf(mem, "%d", BN_num_bits(n));
++ BIO_printf(mem, "%d", n ? BN_num_bits(n) : 0);
+ #else
+- BIO_printf(mem, "%d", BN_num_bits(rsa->n));
++ BIO_printf(mem, "%d", rsa->n ? BN_num_bits(rsa->n) : 0);
+ #endif /* HAVE_OPAQUE_RSA_DSA_DH */
+ push_certinfo("RSA Public Key", i);
+ print_pubkey_BN(rsa, n, i);
+--
+2.33.0
+
diff --git a/backport-paramhlp-fix-CRLF-stripping-files-with-d-file.patch b/backport-paramhlp-fix-CRLF-stripping-files-with-d-file.patch
new file mode 100644
index 0000000..2e2bd23
--- /dev/null
+++ b/backport-paramhlp-fix-CRLF-stripping-files-with-d-file.patch
@@ -0,0 +1,100 @@
+From 923f7f8ce51b7f2f20282883cdafeb283310f3d9 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Wed, 6 Mar 2024 15:39:09 +0100
+Subject: [PATCH] paramhlp: fix CRLF-stripping files with "-d @file"
+
+All CR and LF bytes should be stripped, as documented, and all other
+bytes are inluded in the data. Starting now, it also excludes null bytes
+as they would otherwise also cut the data short.
+
+Reported-by: Simon K
+Fixes #13063
+Closes #13064
+
+Conflict:remove change of docs/cmdline-opts/data.md which is not exist
+Reference:https://github.com/curl/curl/commit/923f7f8ce51b7f2f20282883cdafeb283310f3d9
+---
+ src/tool_paramhlp.c | 63 +++++++++++++++++++++++++++++++--------
+ 1 files changed, 51 insertions(+), 12 deletions(-)
+
+diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c
+index 2725815000dc95..c26f6bbefd775c 100644
+--- a/src/tool_paramhlp.c
++++ b/src/tool_paramhlp.c
+@@ -63,6 +63,33 @@ struct getout *new_getout(struct OperationConfig *config)
+ return node;
+ }
+
++#define ISCRLF(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
++
++/* memcrlf() has two modes. Both operate on a given memory area with
++ a specified size.
++
++ countcrlf FALSE - return number of bytes from the start that DO NOT include
++ any CR or LF or NULL
++
++ countcrlf TRUE - return number of bytes from the start that are ONLY CR or
++ LF or NULL.
++
++*/
++static size_t memcrlf(char *orig,
++ bool countcrlf, /* TRUE if we count CRLF, FALSE
++ if we count non-CRLF */
++ size_t max)
++{
++ char *ptr = orig;
++ size_t total = max;
++ for(ptr = orig; max; max--, ptr++) {
++ bool crlf = ISCRLF(*ptr);
++ if(countcrlf ^ crlf)
++ return ptr - orig;
++ }
++ return total; /* no delimiter found */
++}
++
+ #define MAX_FILE2STRING (256*1024*1024) /* big enough ? */
+
+ ParameterError file2string(char **bufp, FILE *file)
+@@ -71,18 +98,30 @@ ParameterError file2string(char **bufp, FILE *file)
+ DEBUGASSERT(MAX_FILE2STRING < INT_MAX); /* needs to fit in an int later */
+ curlx_dyn_init(&dyn, MAX_FILE2STRING);
+ if(file) {
+- char buffer[256];
+-
+- while(fgets(buffer, sizeof(buffer), file)) {
+- char *ptr = strchr(buffer, '\r');
+- if(ptr)
+- *ptr = '\0';
+- ptr = strchr(buffer, '\n');
+- if(ptr)
+- *ptr = '\0';
+- if(curlx_dyn_add(&dyn, buffer))
+- return PARAM_NO_MEM;
+- }
++ do {
++ char buffer[4096];
++ char *ptr;
++ size_t nread = fread(buffer, 1, sizeof(buffer), file);
++ if(ferror(file)) {
++ curlx_dyn_free(&dyn);
++ *bufp = NULL;
++ return PARAM_READ_ERROR;
++ }
++ ptr = buffer;
++ while(nread) {
++ size_t nlen = memcrlf(ptr, FALSE, nread);
++ if(curlx_dyn_addn(&dyn, ptr, nlen))
++ return PARAM_NO_MEM;
++ nread -= nlen;
++
++ if(nread) {
++ ptr += nlen;
++ nlen = memcrlf(ptr, TRUE, nread);
++ ptr += nlen;
++ nread -= nlen;
++ }
++ }
++ } while(!feof(file));
+ }
+ *bufp = curlx_dyn_ptr(&dyn);
+ return PARAM_OK;
diff --git a/backport-pre-CVE-2024-2004.patch b/backport-pre-CVE-2024-2004.patch
new file mode 100644
index 0000000..d297555
--- /dev/null
+++ b/backport-pre-CVE-2024-2004.patch
@@ -0,0 +1,159 @@
+From de0cd5e8e7c9a0cbf28c4a9dec998ad4b6dfa08c Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Mon, 11 Dec 2023 23:17:26 +0100
+Subject: [PATCH] test1474: removed
+
+The test was already somewhat flaky and disabled on several platforms,
+and after 1da640abb688 even more unstable.
+
+Conflict:Context adapt
+Reference:https://github.com/curl/curl/commit/de0cd5e8e7c9a0cbf28c4a9dec998ad4b6dfa08c
+---
+ tests/data/Makefile.inc | 2 +-
+ tests/data/test1474 | 121 ----------------------------------------
+ 2 files changed, 1 insertion(+), 122 deletions(-)
+ delete mode 100644 tests/data/test1474
+
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index de13c525e..6d1a2ad13 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -186,7 +186,7 @@ test1439 test1440 test1441 test1442 test1443 test1444 test1445 test1446 \
+ test1447 test1448 test1449 test1450 test1451 test1452 test1453 test1454 \
+ test1455 test1456 test1457 test1458 test1459 test1460 test1461 test1462 \
+ test1463 test1464 test1465 test1466 test1467 test1468 test1469 test1470 \
+-test1471 test1472 test1473 test1474 \
++test1471 test1472 test1473 \
+ \
+ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
+ test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
+diff --git a/tests/data/test1474 b/tests/data/test1474
+deleted file mode 100644
+index a87044d1a..000000000
+--- a/tests/data/test1474
++++ /dev/null
+@@ -1,121 +0,0 @@
+-<testcase>
+-# This test is quite timing dependent and tricky to set up. The time line of
+-# test operations looks like this:
+-#
+-# 1. curl sends a PUT request with Expect: 100-continue and waits only 1 msec
+-# for a 100 response.
+-# 2. The HTTP server accepts the connection but waits 500 msec before acting
+-# on the request.
+-# 3. curl doesn't receive the expected 100 response before its timeout expires,
+-# so it starts sending the body. It is throttled by a --limit-rate, so it
+-# sends the first 64 KiB then stops for 1000 msec due to this
+-# throttling.
+-# 4. The server sends its 417 response while curl is throttled.
+-# 5. curl responds to this 417 response by closing the connection (because it
+-# has a half-completed response outstanding) and starting a new one. This
+-# new request does not have an Expect: header so it is sent without delay.
+-# It's still throttled, however, so it takes about 16 seconds to finish
+-# sending.
+-# 6. The server receives the response and this time acks it with 200.
+-#
+-# Because of the timing sensitivity (scheduling delays of 500 msec can cause
+-# the test to fail), this test is marked flaky to avoid it being run in the CI
+-# builds which are often run on overloaded servers.
+-# Increasing the --limit-rate would decrease the test time, but at the cost of
+-# becoming even more sensitive to delays (going from 500 msec to 250 msec or
+-# less of accepted delay before failure). Adding a --speed-time would increase
+-# the 1 second delay between writes to longer, but it would also increase the
+-# total time needed by the test, which is already quite high.
+-#
+-# The assumption in step 3 is also broken on NetBSD 9.3, OpenBSD 7.3 and
+-# Solaris 10 as they only usually send about half the requested amount of data
+-# (see https://curl.se/mail/lib-2023-09/0021.html).
+-<info>
+-<keywords>
+-HTTP
+-HTTP PUT
+-Expect
+-flaky
+-timing-dependent
+-</keywords>
+-</info>
+-# Server-side
+-<reply>
+-# 417 means the server didn't like the Expect header
+-<data>
+-HTTP/1.1 417 BAD swsbounce
+-Date: Tue, 09 Nov 2010 14:49:00 GMT
+-Server: test-server/fake
+-Content-Length: 0
+-
+-</data>
+-<data1>
+-HTTP/1.1 200 OK
+-Date: Tue, 09 Nov 2010 14:49:00 GMT
+-Server: test-server/fake
+-Content-Length: 10
+-
+-blablabla
+-</data1>
+-<datacheck>
+-HTTP/1.1 417 BAD swsbounce
+-Date: Tue, 09 Nov 2010 14:49:00 GMT
+-Server: test-server/fake
+-Content-Length: 0
+-
+-HTTP/1.1 200 OK
+-Date: Tue, 09 Nov 2010 14:49:00 GMT
+-Server: test-server/fake
+-Content-Length: 10
+-
+-blablabla
+-</datacheck>
+-<servercmd>
+-no-expect
+-delay: 500
+-connection-monitor
+-</servercmd>
+-</reply>
+-
+-# Client-side
+-<client>
+-<server>
+-http
+-</server>
+-<name>
+-HTTP PUT with Expect: 100-continue and 417 response during upload
+-</name>
+-<command>
+-http://%HOSTIP:%HTTPPORT/we/want/%TESTNUMBER -T %LOGDIR/test%TESTNUMBER.txt --limit-rate 64K --expect100-timeout 0.001
+-</command>
+-<precheck>
+-perl -e "print 'Test does not work on this BSD system' if ( $^O eq 'netbsd' || $^O eq 'openbsd' || ($^O eq 'solaris' && qx/uname -r/ * 100 <= 510));"
+-</precheck>
+-# Must be large enough to trigger curl's automatic 100-continue behaviour
+-<file name="%LOGDIR/test%TESTNUMBER.txt">
+-%repeat[132 x S]%%repeat[16462 x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%0a]%
+-</file>
+-</client>
+-
+-# Verify data after the test has been "shot"
+-<verify>
+-<protocol>
+-PUT /we/want/%TESTNUMBER HTTP/1.1
+-Host: %HOSTIP:%HTTPPORT
+-User-Agent: curl/%VERSION
+-Accept: */*
+-Content-Length: 1053701
+-Expect: 100-continue
+-
+-%repeat[132 x S]%%repeat[1021 x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%0a]%%repeat[60 x x]%[DISCONNECT]
+-PUT /we/want/%TESTNUMBER HTTP/1.1
+-Host: %HOSTIP:%HTTPPORT
+-User-Agent: curl/%VERSION
+-Accept: */*
+-Content-Length: 1053701
+-
+-%repeat[132 x S]%%repeat[16462 x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%0a]%
+-[DISCONNECT]
+-</protocol>
+-</verify>
+-</testcase>
+--
+2.33.0
+
diff --git a/backport-pre-CVE-2024-9681.patch b/backport-pre-CVE-2024-9681.patch
new file mode 100644
index 0000000..cac0ac4
--- /dev/null
+++ b/backport-pre-CVE-2024-9681.patch
@@ -0,0 +1,69 @@
+From 60d8663afb0fb7f113604404c50840dfe9320039 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 8 Oct 2024 11:20:40 +0200
+Subject: [PATCH] hsts: avoid the local buffer and memcpy on lookup
+
+Closes #15190
+Conflict:Context adapt
+Reference:https://github.com/curl/curl/commit/60d8663afb0fb7f113604404c50840dfe9320039
+---
+ lib/hsts.c | 22 +++++++++-------------
+ 1 file changed, 9 insertions(+), 13 deletions(-)
+
+diff --git a/lib/hsts.c b/lib/hsts.c
+index 7ecf004..f5e5bbf 100644
+--- a/lib/hsts.c
++++ b/lib/hsts.c
+@@ -250,7 +250,6 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+ bool subdomain)
+ {
+ if(h) {
+- char buffer[MAX_HSTS_HOSTLEN + 1];
+ time_t now = time(NULL);
+ size_t hlen = strlen(hostname);
+ struct Curl_llist_element *e;
+@@ -258,15 +257,13 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+
+ if((hlen > MAX_HSTS_HOSTLEN) || !hlen)
+ return NULL;
+- memcpy(buffer, hostname, hlen);
+ if(hostname[hlen-1] == '.')
+ /* remove the trailing dot */
+ --hlen;
+- buffer[hlen] = 0;
+- hostname = buffer;
+
+ for(e = h->list.head; e; e = n) {
+ struct stsentry *sts = e->ptr;
++ size_t ntail;
+ n = e->next;
+ if(sts->expires <= now) {
+ /* remove expired entries */
+@@ -274,16 +271,15 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+ hsts_free(sts);
+ continue;
+ }
+- if(subdomain && sts->includeSubDomains) {
+- size_t ntail = strlen(sts->host);
+- if(ntail < hlen) {
+- size_t offs = hlen - ntail;
+- if((hostname[offs-1] == '.') &&
+- strncasecompare(&hostname[offs], sts->host, ntail))
+- return sts;
+- }
++ ntail = strlen(sts->host);
++ if((subdomain && sts->includeSubDomains) && (ntail < hlen)) {
++ size_t offs = hlen - ntail;
++ if((hostname[offs-1] == '.') &&
++ strncasecompare(&hostname[offs], sts->host, ntail))
++ return sts;
+ }
+- if(strcasecompare(hostname, sts->host))
++ /* avoid strcasecompare because the host name is not null terminated */
++ if((hlen == ntail) && strncasecompare(hostname, sts->host, hlen))
+ return sts;
+ }
+ }
+--
+2.43.0
+
diff --git a/backport-tool_cb_rea-limit-rate-unpause-for-T-uploads.patch b/backport-tool_cb_rea-limit-rate-unpause-for-T-uploads.patch
new file mode 100644
index 0000000..fd98749
--- /dev/null
+++ b/backport-tool_cb_rea-limit-rate-unpause-for-T-uploads.patch
@@ -0,0 +1,61 @@
+From 5f4aaf8b66ef04208c1c2121d4b780c792303f32 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 30 Apr 2024 11:07:28 +0200
+Subject: [PATCH] tool_cb_rea: limit rate unpause for -T . uploads
+Reference:https://github.com/curl/curl/pull/13506
+
+---
+ src/tool_cb_rea.c | 30 ++++++++++++++++++++++++++++--
+ 1 file changed, 28 insertions(+), 2 deletions(-)
+
+diff --git a/src/tool_cb_rea.c b/src/tool_cb_rea.c
+index d70a9b9..f510f81 100644
+--- a/src/tool_cb_rea.c
++++ b/src/tool_cb_rea.c
+@@ -36,6 +36,7 @@
+ #include "tool_operate.h"
+ #include "tool_util.h"
+ #include "tool_msgs.h"
++#include "tool_sleep.h"
+
+ #include "memdebug.h" /* keep this as LAST include */
+
+@@ -124,8 +125,33 @@ int tool_readbusy_cb(void *clientp,
+ (void)ulnow; /* unused */
+
+ if(config->readbusy) {
+- config->readbusy = FALSE;
+- curl_easy_pause(per->curl, CURLPAUSE_CONT);
++ /* lame code to keep the rate down because the input might not deliver
++ anything, get paused again and come back here immediately */
++ static long rate = 500;
++ static struct timeval prev;
++ static curl_off_t ulprev;
++
++ if(ulprev == ulnow) {
++ /* it did not upload anything since last call */
++ struct timeval now = tvnow();
++ if(prev.tv_sec)
++ /* get a rolling average rate */
++ /* rate = rate - rate/4 + tvdiff(now, prev)/4; */
++ rate -= rate/4 - tvdiff(now, prev)/4;
++ prev = now;
++ }
++ else {
++ rate = 50;
++ ulprev = ulnow;
++ }
++ if(rate >= 50) {
++ /* keeps the looping down to 20 times per second in the crazy case */
++ config->readbusy = FALSE;
++ curl_easy_pause(per->curl, CURLPAUSE_CONT);
++ }
++ else
++ /* sleep half a period */
++ tool_go_sleep(25);
+ }
+
+ return per->noprogress? 0 : CURL_PROGRESSFUNC_CONTINUE;
+--
+2.27.0
+
diff --git a/backport-tool_cfgable-free-proxy_-cipher13_list-on-exit.patch b/backport-tool_cfgable-free-proxy_-cipher13_list-on-exit.patch
new file mode 100644
index 0000000..ada0c62
--- /dev/null
+++ b/backport-tool_cfgable-free-proxy_-cipher13_list-on-exit.patch
@@ -0,0 +1,28 @@
+From 87d14e77b7d59a961eb56500017c0580f89f252b Mon Sep 17 00:00:00 2001
+From: Jan Venekamp <1422460+jan2000@users.noreply.github.com>
+Date: Sat, 4 May 2024 03:05:51 +0200
+Subject: [PATCH] tool_cfgable: free {proxy_}cipher13_list on exit
+
+Author: Jan Venekamp
+Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
+Closes: #13531
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/87d14e77b7d59a961eb56500017c0580f89f252b
+---
+ src/tool_cfgable.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c
+index bb271583263db3..5564e250d33782 100644
+--- a/src/tool_cfgable.c
++++ b/src/tool_cfgable.c
+@@ -114,6 +114,8 @@ static void free_config_fields(struct OperationConfig *config)
+ Curl_safefree(config->doh_url);
+ Curl_safefree(config->cipher_list);
+ Curl_safefree(config->proxy_cipher_list);
++ Curl_safefree(config->cipher13_list);
++ Curl_safefree(config->proxy_cipher13_list);
+ Curl_safefree(config->cert);
+ Curl_safefree(config->proxy_cert);
+ Curl_safefree(config->cert_type);
diff --git a/backport-url-allow-DoH-transfers-to-override-max-connection-limit.patch b/backport-url-allow-DoH-transfers-to-override-max-connection-limit.patch
new file mode 100644
index 0000000..11e7a50
--- /dev/null
+++ b/backport-url-allow-DoH-transfers-to-override-max-connection-limit.patch
@@ -0,0 +1,49 @@
+From b049388d473a9a0189f3180e57e04a39a3793382 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 4 Jun 2024 17:00:05 +0200
+Subject: [PATCH] url: allow DoH transfers to override max connection limit
+
+When reaching the set maximum limit of allowed connections, allow a new
+connection anyway if the transfer is created for the (internal) purpose
+of doing a DoH name resolve. Otherwise, unrelated "normal" transfers can
+starve out new DoH requests making it impossible to name resolve for new
+transfers.
+
+Bug: https://curl.se/mail/lib-2024-06/0001.html
+Reported-by: kartatz
+Closes #13880
+
+Conflict:NA
+Reference:https://github.com/curl/curl/commit/b049388d473a9a0189f3180e57e04a39a3793382
+---
+ lib/url.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/lib/url.c b/lib/url.c
+index 41e35e153..4eabf0c87 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -3662,10 +3662,16 @@ static CURLcode create_conn(struct Curl_easy *data,
+ conn_candidate = Curl_conncache_extract_oldest(data);
+ if(conn_candidate)
+ Curl_disconnect(data, conn_candidate, FALSE);
+- else {
+- infof(data, "No connections available in cache");
+- connections_available = FALSE;
+- }
++ else
++#ifndef CURL_DISABLE_DOH
++ if(data->set.dohfor)
++ infof(data, "Allowing DoH to override max connection limit");
++ else
++#endif
++ {
++ infof(data, "No connections available in cache");
++ connections_available = FALSE;
++ }
+ }
+
+ if(!connections_available) {
+--
+2.33.0
+
diff --git a/curl.spec b/curl.spec
new file mode 100644
index 0000000..d6f465c
--- /dev/null
+++ b/curl.spec
@@ -0,0 +1,570 @@
+#Global macro or variable
+%global libpsl_version %(pkg-config --modversion libpsl 2>/dev/null || echo 0)
+%global libssh_version %(pkg-config --modversion libssh 2>/dev/null || echo 0)
+%global openssl_version %({ pkg-config --modversion openssl 2>/dev/null || echo 0;} | sed 's|-|-0.|')
+%global libnghttp2_version %(pkg-config --modversion libnghttp2 2>/dev/null || echo 0)
+%global _configure ../configure
+
+Name: curl
+Version: 8.4.0
+Release: 15
+Summary: Curl is used in command lines or scripts to transfer data
+License: curl
+URL: https://curl.se/
+Source: https://curl.se/download/curl-%{version}.tar.xz
+
+Patch1: backport-0101-curl-7.32.0-multilib.patch
+Patch2: backport-curl-7.84.0-test3026.patch
+Patch4: backport-curl-7.88.0-tests-warnings.patch
+Patch11: backport-CVE-2023-46218.patch
+Patch12: backport-0001-CVE-2023-46219.patch
+Patch13: backport-0002-CVE-2023-46219.patch
+Patch15: backport-openssl-avoid-BN_num_bits-NULL-pointer-derefs.patch
+Patch16: backport-pre-CVE-2024-2004.patch
+Patch17: backport-CVE-2024-2004.patch
+Patch18: backport-CVE-2024-2398.patch
+Patch19: backport-tool_cb_rea-limit-rate-unpause-for-T-uploads.patch
+#https://github.com/curl/curl/pull/13506
+Patch20: backport-paramhlp-fix-CRLF-stripping-files-with-d-file.patch
+Patch21: backport-libssh2-set-length-to-0-if-strdup-failed.patch
+Patch22: backport-openldap-create-ldap-URLs-correctly-for-IPv6-addresses.patch
+Patch23: backport-multi-avoid-memory-leak-risk.patch
+Patch24: backport-tool_cfgable-free-proxy_-cipher13_list-on-exit.patch
+Patch25: backport-CVE-2024-7264-x509asn1-clean-up-GTime2str.patch
+Patch26: backport-CVE-2024-7264-x509asn1-unittests-and-fixes-fo.patch
+Patch27: backport-CVE-2024-8096-gtls-fix-OCSP-stapling-management.patch
+Patch28: backport-url-allow-DoH-transfers-to-override-max-connection-limit.patch
+Patch29: backport-pre-CVE-2024-9681.patch
+Patch30: backport-CVE-2024-9681.patch
+Patch31: backport-multi-check-that-the-multi-handle-is-valid-in-curl_m.patch
+Patch32: backport-cookie-treat-cookie-name-case-sensitively.patch
+Patch33: backport-CVE-2024-11053-pre1.patch
+Patch34: backport-CVE-2024-11053-pre2.patch
+Patch35: backport-CVE-2024-11053-pre3.patch
+Patch36: backport-CVE-2024-11053-pre4.patch
+Patch37: backport-CVE-2024-11053-pre5.patch
+Patch38: backport-CVE-2024-11053.patch
+Patch39: backport-CVE-2024-11053-post1.patch
+Patch40: backport-CVE-2024-11053-post2.patch
+Patch41: backport-CVE-2025-0167.patch
+Patch42: backport-CVE-2025-0725.patch
+
+BuildRequires: automake brotli-devel coreutils gcc groff krb5-devel
+BuildRequires: libidn2-devel libnghttp2-devel libpsl-devel
+BuildRequires: libssh-devel make openldap-devel openssh-clients openssh-server
+BuildRequires: openssl-devel perl-interpreter pkgconfig python3-devel sed
+BuildRequires: zlib-devel gnutls-utils nghttp2 perl(IO::Compress::Gzip)
+BuildRequires: perl(Getopt::Long) perl(Pod::Usage) perl(strict) perl(warnings)
+BuildRequires: perl(Cwd) perl(Digest::MD5) perl(Exporter) perl(File::Basename)
+BuildRequires: perl(File::Copy) perl(File::Spec) perl(IPC::Open2) perl(MIME::Base64)
+BuildRequires: perl(Time::Local) perl(Time::HiRes) perl(vars) perl(Digest::SHA)
+
+%ifnarch aarch64
+BuildRequires: stunnel
+%endif
+
+Requires: libcurl = %{version}-%{release}
+Provides: curl-full = %{version}-%{release} webclient
+
+%description
+cURL is a computer software project providing a library (libcurl) and
+command-line tool (curl) for transferring data using various protocols.
+
+%package -n libcurl
+Summary: A library for getting files from web servers
+Requires: libssh >= %{libssh_version} libpsl >= %{libpsl_version}
+Requires: openssl-libs >= 1:%{openssl_version}
+Requires: libnghttp2 >= %{libnghttp2_version}
+Provides: libcurl-full = %{version}-%{release}
+Conflicts: curl < 7.66.0-3
+
+%description -n libcurl
+A library for getting files from web servers.
+
+%package -n libcurl-devel
+Summary: Header files for libcurl
+Requires: libcurl = %{version}-%{release}
+Provides: curl-devel = %{version}-%{release}
+Obsoletes: curl-devel < %{version}-%{release}
+
+%description -n libcurl-devel
+Header files for libcurl.
+
+%package_help
+
+%prep
+%autosetup -n %{name}-%{version} -p1
+
+echo "1801" >> tests/data/DISABLED
+
+# adapt test 323 for updated OpenSSL
+sed -e 's/^35$/35,52/' -i tests/data/test323
+# use localhost6 instead of ip6-localhost in the curl test-suite
+(
+ # avoid glob expansion in the trace output of `bash -x`
+ { set +x; } 2>/dev/null
+ cmd="sed -e 's|ip6-localhost|localhost6|' -i tests/data/test[0-9]*"
+ printf "+ %s\n" "$cmd" >&2
+ eval "$cmd"
+)
+
+%build
+# regenerate Makefile.in files
+aclocal -I m4
+automake
+
+install -d build-full
+export common_configure_opts="--cache-file=../config.cache \
+ --enable-hsts --enable-ipv6 --enable-symbol-hiding --enable-threaded-resolver \
+ --without-zstd --with-gssapi --with-libidn2 --with-nghttp2 --with-ssl \
+ --with-ca-bundle=%{_sysconfdir}/pki/tls/certs/ca-bundle.crt"
+
+%global _configure ../configure
+
+# configure full build
+(
+ cd build-full
+ %configure $common_configure_opts \
+ --enable-dict \
+ --enable-gopher \
+ --enable-imap \
+ --enable-ldap \
+ --enable-ldaps \
+ --enable-manual \
+ --enable-mqtt \
+ --enable-ntlm \
+ --enable-ntlm-wb \
+ --enable-pop3 \
+ --enable-rtsp \
+ --enable-smb \
+ --enable-smtp \
+ --enable-telnet \
+ --enable-tftp \
+ --enable-tls-srp \
+ --with-brotli \
+ --with-libpsl \
+ --with-libssh
+)
+
+sed -e 's/^runpath_var=.*/runpath_var=/' \
+ -e 's/^hardcode_libdir_flag_spec=".*"$/hardcode_libdir_flag_spec=""/' \
+ -i build-full/libtool
+
+%make_build V=1 -C build-full
+
+%check
+# compile upstream test-cases
+%make_build V=1 -C build-full/tests
+
+# relax crypto policy for the test-suite to make it pass again (#1610888)
+export OPENSSL_SYSTEM_CIPHERS_OVERRIDE=XXX
+export OPENSSL_CONF=
+
+# make runtests.pl work for out-of-tree builds
+export srcdir=../../tests
+
+# prevent valgrind from being extremely slow (#1662656)
+unset DEBUGINFOD_URLS
+
+# run the upstream test-suite for curl-full
+for size in full; do (
+ cd build-${size}
+
+ # we have to override LD_LIBRARY_PATH because we eliminated rpath
+ export LD_LIBRARY_PATH="${PWD}/lib/.libs"
+
+ cd tests
+ perl -I../../tests ../../tests/runtests.pl -a -n -p -v '!flaky'
+)
+done
+
+%install
+rm -f ${RPM_BUILD_ROOT}%{_libdir}/libcurl.{la,so}
+
+# install libcurl.m4 for devel
+install -D -m 644 docs/libcurl/libcurl.m4 $RPM_BUILD_ROOT%{_datadir}/aclocal/libcurl.m4
+
+# curl file install
+cd build-full
+%make_install
+
+# install zsh completion for curl
+LD_LIBRARY_PATH="$RPM_BUILD_ROOT%{_libdir}:$LD_LIBRARY_PATH" %make_install -C scripts
+
+# do not install /usr/share/fish/completions/curl.fish which is also installed
+# by fish-3.0.2-1.module_f31+3716+57207597 and would trigger a conflict
+rm -rf ${RPM_BUILD_ROOT}%{_datadir}/fish
+
+rm -f ${RPM_BUILD_ROOT}%{_libdir}/libcurl.a
+rm -rf ${RPM_BUILD_ROOT}%{_libdir}/libcurl.la
+
+%ldconfig_scriptlets
+
+%ldconfig_scriptlets -n libcurl
+
+%files
+%defattr(-,root,root)
+%license COPYING
+%{_bindir}/curl
+%{_datadir}/zsh
+
+%files -n libcurl
+%defattr(-,root,root)
+%{_libdir}/libcurl.so.4
+%{_libdir}/libcurl.so.4.[0-9].[0-9]
+
+%files -n libcurl-devel
+%defattr(-,root,root)
+%doc docs/examples/*.c docs/examples/Makefile.example docs/INTERNALS.md
+%doc docs/CONTRIBUTE.md docs/libcurl/ABI.md
+%{_bindir}/curl-config*
+%{_includedir}/curl
+%{_libdir}/*.so
+%{_libdir}/pkgconfig/*.pc
+%{_datadir}/aclocal/libcurl.m4
+
+%files help
+%defattr(-,root,root)
+%doc CHANGES README*
+%doc docs/BUGS.md docs/FAQ docs/FEATURES.md
+%doc docs/TheArtOfHttpScripting.md docs/TODO
+%{_mandir}/man1/curl.1*
+%{_mandir}/man1/curl-config.1*
+%{_mandir}/man3/*
+
+%changelog
+* Sat Feb 08 2025 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-15
+- Type:CVE
+- CVE:CVE-2025-0167 CVE-2025-0725
+- SUG:NA
+- DESC:fix CVE-2025-0167 CVE-2025-0725
+
+* Tue Jan 07 2025 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-14
+- Type:CVE
+- CVE:CVE-2024-11053
+- SUG:NA
+- DESC:fix CVE-2024-11053
+
+* Mon Dec 09 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-13
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:cookie: treat cookie name case sensitively
+
+* Sat Nov 30 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-12
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:multi: check that the multi handle is valid in curl_multi_assign
+
+* Mon Nov 11 2024 yanglu <yanglu72@h-partners.com> - 8.4.0-11
+- Type:CVE
+- CVE:CVE-2024-9681
+- SUG:NA
+- DESC:fix CVE-2024-9681
+
+* Fri Sep 20 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-10
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:url: allow DoH transfers to override max connection limit
+
+* Thu Sep 12 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-9
+- Type:CVE
+- CVE:CVE-2024-8096
+- SUG:NA
+- DESC:fix CVE-2024-8096
+
+* Thu Sep 05 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-8
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:revert modify licence from curl to MIT
+
+* Thu Aug 15 2024 zhangxianjun <zhangxianjun@kylinos.cn> - 8.4.0-7
+- modify licence from curl to MIT
+
+* Wed Jul 31 2024 yinyongkang <yinyongkang@kylinos.cn> - 8.4.0-6
+- Type:CVE
+- CVE:CVE-2024-7264
+- SUG:NA
+- DESC:fix CVE-2024-7264
+
+* Mon Jun 24 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-5
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:paramhlp: fix CRLF-stripping files with "-d @file"
+ libssh2: set length to 0 if strdup failed
+ openldap: create ldap URLs correctly for IPv6 addresses
+ multi: avoid memory-leak risk
+ tool_cfgable: free {proxy_}cipher13_list on exit
+
+* Wed Jun 12 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-4
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:add version require of nghttp2 for libcurl
+
+* Thu May 09 2024 baiguo <baiguo@kylinos.cn> - 8.4.0-3
+- DESC: tool_cb_rea: limit rate unpause for -T . uploads
+
+* Mon Apr 01 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-2
+- Type:CVE
+- CVE:CVE-2024-2004 CVE-2024-2398
+- SUG:NA
+- DESC:fix CVE-2024-2004 CVE-2024-2398
+
+* Tue Jan 09 2024 zhouyihang <zhouyihang3@h-partners.com> - 8.4.0-1
+- Type:requirement
+- CVE:NA
+- SUG:NA
+- DESC:update curl to 8.4.0
+
+* Thu Dec 28 2023 zhouyihang <zhouyihang3@h-partners.com> - 8.1.2-7
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:transfer: also stop the sending on closed connection
+ openssl: avoid BN_num_bits() NULL pointer derefs
+
+* Fri Dec 08 2023 zhouyihang <zhouyihang3@h-partners.com> - 8.1.2-6
+- Type:CVE
+- CVE:CVE-2023-46218 CVE-2023-46219
+- SUG:NA
+- DESC:fix CVE-2023-46218 CVE-2023-46219
+
+* Thu Oct 12 2023 zhouyihang <zhouyihang3@h-partners.com> - 8.1.2-5
+- Type:CVE
+- CVE:CVE-2023-38545 CVE-2023-38546
+- SUG:NA
+- DESC:fix CVE-2023-38545 CVE-2023-38546
+
+* Thu Sep 14 2023 gaihuiying <eaglegai@163.com> - 8.1.2-4
+- Type:CVE
+- CVE:CVE-2023-38039
+- SUG:NA
+- DESC:fix CVE-2023-38039
+
+* Wed Sep 06 2023 yanglu <yanglu72@h-partners.com> - 8.1.2-3
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:vtls:avoid memory leak if sha256 call fails
+ urlapi:make sure zoneid is also duplicated in curl_url_dup
+
+* Thu Jul 20 2023 zhouyihang <zhouyihang3@h-partners.com> - 8.1.2-2
+- Type:CVE
+- CVE:CVE-2023-32001
+- SUG:NA
+- DESC:fix CVE-2023-32001
+
+* Sat Jul 15 2023 gaihuiying <eaglegai@163.com> - 8.1.2-1
+- Type:requirement
+- CVE:NA
+- SUG:NA
+- DESC:update to curl 8.1.2
+
+* Sat Jun 10 2023 zhouyihang <zhouyihang3@h-partners.com> - 7.88.1-4
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:disable valgrind in tests
+
+* Thu Jun 08 2023 xingwei <xingwei14@h-partners.com> - 7.88.1-3
+- Type:CVE
+- CVE:CVE-2023-28320,CVE-2023-28321,CVE-2023-28322
+- SUG:NA
+- DESC:fix CVE-2023-28320,CVE-2023-28321,CVE-2023-28322
+
+* Wed Mar 22 2023 zengwefeng <zwfeng@huawei.com> - 7.88.1-2
+- Type:cves
+- ID:CVE-2023-27533 CVE-2023-27534 CVE-2023-27535 CVE-2023-27536 CVE-2023-27537 CVE-2023-27538
+- SUG:NA
+- DESC:fix CVE-2023-27533 CVE-2023-27534 CVE-2023-27535 CVE-2023-27536 CVE-2023-27537 CVE-2023-27538
+
+
+* Thu Mar 02 2023 xinghe <xinghe2@h-partners.com> - 7.88.1-1
+- Type:requirements
+- ID:NA
+- SUG:NA
+- DESC:upgrade to 7.88.1
+
+* Sat Feb 18 2023 xinghe <xinghe2@h-partners.com> - 7.86.0-3
+- Type:cves
+- ID:CVE-2023-23914 CVE-2023-23915 CVE-2023-23916
+- SUG:NA
+- DESC:fix CVE-2023-23914 CVE-2023-23915 CVE-2023-23916
+
+* Thu Dec 22 2022 zhouyihang <zhouyihang3@h-partners.com> - 7.86.0-2
+- Type:cves
+- ID:CVE-2022-43551 CVE-2022-43552
+- SUG:NA
+- DESC:fix CVE-2022-43551 CVE-2022-43552
+
+* Wed Nov 16 2022 xinghe <xinghe2@h-partners.com> - 7.86.0-1
+- Type:requirements
+- ID:NA
+- SUG:NA
+- DESC:upgrade to 7.86.0
+
+* Thu Oct 27 2022 yanglu <yanglu72@h-partners.com> - 7.79.1-12
+- Type:cves
+- CVE:CVE-2022-32221 CVE-2022-42915 CVE-2022-42916
+- SUG:NA
+- DESC:fix CVE-2022-32221 CVE-2022-42915 CVE-2022-42916
+
+* Tue Oct 11 2022 huangduirong <huangduirong@huawei.com> - 7.79.1-11
+- Type:bugfix
+- ID:NA
+- SUG:NA
+- DESC:Move autoreconf to build
+
+* Thu Sep 01 2022 zhouyihang <zhouyihang@h-partners.com> - 7.79.1-10
+- Type:cves
+- CVE:CVE-2022-35252
+- SUG:NA
+- DESC:fix CVE-2022-35252
+
+* Thu Jul 28 2022 gaihuiying <eaglegai@163.com> - 7.79.1-9
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:just rebuild release to 7.79.1-9
+
+* Mon Jul 25 2022 gaihuiying <eaglegai@163.com> - 7.79.1-8
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:fix build error when add --disable-http-auth configure option
+
+* Tue Jul 05 2022 gaihuiying <eaglegai@163.com> - 7.79.1-7
+- Type:cves
+- CVE:CVE-2022-32207
+- SUG:NA
+- DESC:fix CVE-2022-32207 better
+
+* Wed Jun 29 2022 gaihuiying <eaglegai@163.com> - 7.79.1-6
+- Type:cves
+- CVE:CVE-2022-32205 CVE-2022-32206 CVE-2022-32207 CVE-2022-32208
+- SUG:NA
+- DESC:fix CVE-2022-32205 CVE-2022-32206 CVE-2022-32207 CVE-2022-32208
+
+* Tue May 17 2022 gaihuiying <eaglegai@163.com> - 7.79.1-5
+- Type:cves
+- CVE:CVE-2022-27781 CVE-2022-27782
+- SUG:NA
+- DESC:fix CVE-2022-27781 CVE-2022-27782
+
+* Sat May 14 2022 gaoxingwang <gaoxingwang1@huawei.com> - 7.79.1-4
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:fix dict and neg telnet server start fail in upstream testcase
+
+* Fri May 06 2022 gaihuiying <eaglegai@163.com> - 7.79.1-3
+- Type:cves
+- CVE:CVE-2022-22576 CVE-2022-27774 CVE-2022-27775 CVE-2022-27776
+- SUG:NA
+- DESC:fix CVE-2022-22576 CVE-2022-27774 CVE-2022-27775 CVE-2022-27776
+
+* Mon Apr 25 2022 gaoxingwang <gaoxingwang1@huawei.com> - 7.79.1-2
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:enable check in spec
+
+* Thu Jan 20 2022 gaoxingwang <gaoxingwang@huawei.com> - 7.79.1-1
+- Type:bugfix
+- CVE:NA
+- SUG:NA
+- DESC:update curl to 7.79.1
+* Wed Sep 29 2021 yanglu <yanglu72@huawei.com> - 7.77.0-3
+- Type:CVE
+- CVE:CVE-2021-22945 CVE-2021-22946 CVE-2021-22947
+- SUG:NA
+- DESC:fix CVE-2021-22945 CVE-2021-22946CVE-2021-22947
+
+* Fri Aug 13 2021 gaihuiying <gaihuiying1@huawei.com> - 7.77.0-2
+- Type:CVE
+- CVE:CVE-2021-22925 CVE-2021-22926
+- SUG:NA
+- DESC:fix CVE-2021-22925 CVE-2021-22926
+
+* Thu Jul 8 2021 gaihuiying <gaihuiying1@huawei.com> - 7.77.0-1
+- Type:requirement
+- CVE:NA
+- SUG:NA
+- DESC:update curl to 7.77.0
+
+* Tue Jun 8 2021 gaihuiying <gaihuiying1@huawei.com> - 7.71.1-9
+- Type:CVE
+- CVE:CVE-2021-22897 CVE-2021-22898
+- SUG:NA
+- DESC:fix CVE-2021-22897 CVE-2021-22898
+
+* Tue Apr 20 2021 gaihuiying <gaihuiying1@huawei.com> - 7.71.1-8
+- Type:CVE
+- CVE:CVE-2021-22890
+- SUG:NA
+- DESC:fix CVE-2021-22890
+
+* Thu Apr 8 2021 xieliuhua <xieliuhua@huawei.com> - 7.71.1-7
+- Type:CVE
+- CVE:CVE-2021-22876
+- SUG:NA
+- DESC:fix CVE-2021-22876
+
+* Tue Jan 26 2021 wangxiaopeng <wangxiaopeng7@huawei.com> - 7.71.1-6
+- Type:CVE
+- CVE:CVE-2020-8285
+- SUG:NA
+- DESC:fix CVE-2020-8285
+
+* Tue Jan 19 2021 xielh2000 <xielh2000@163.com> - 7.71.1-5
+- Type:CVE
+- CVE:CVE-2020-8286
+- SUG:NA
+- DESC:fix CVE-2020-8286
+
+* Mon Jan 18 2021 xihaochen <xihaochen@huawei.com> - 7.71.1-4
+- Type:CVE
+- CVE:CVE-2020-8284
+- SUG:NA
+- DESC:fix CVE-2020-8284
+
+* Tue Jan 5 2021 gaihuiying <gaihuiying1@huawei.com> - 7.71.1-3
+- Type:bugfix
+- ID:NA
+- SUG:NA
+- DESC:fix downgrade error
+
+* Mon Dec 28 2020 liuxin <liuxin264@huawei.com> - 7.71.1-2
+- Type:cves
+- ID:CVE-2020-8231
+- SUG:NA
+- DESC:fix CVE-2020-8231
+
+* Fri Jul 24 2020 zhujunhao <zhujunhao8@huawei.com> - 7.71.1-1
+- Update to 7.71.1
+
+* Thu Apr 9 2020 songnannan <songnannan2@huawei.com> - 7.66.0-3
+- split out the libcurl and libcurl-devel package
+
+* Tue Mar 17 2020 chenzhen <chenzhen44@huawei.com> - 7.66.0-2
+- Type:cves
+- ID:CVE-2019-15601
+- SUG:NA
+- DESC:fix CVE-2019-15601
+
+* Sat Jan 11 2020 openEuler Buildteam <buildteam@openeuler.org> - 7.66.0-1
+- update to 7.66.0
+
+* Sat Dec 21 2019 openEuler Buildteam <buildteam@openeuler.org> - 7.61.1-4
+- Type:cves
+- ID:CVE-2019-5481 CVE-2019-5482
+- SUG:NA
+- DESC:fix CVE-2019-5481 CVE-2019-5482
+
+* Wed Sep 18 2019 guanyanjie <guanyanjie@huawei.com> - 7.61.1-3
+- Init for openEuler
diff --git a/sources b/sources
new file mode 100644
index 0000000..cceefee
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+8424597f247da68b6041dd7f9ca367fe curl-8.4.0.tar.xz