From 7417f14b93b2bcc4ed31696dee7e9404ab2897af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 16:54:27 +0000 Subject: [PATCH 001/208] GHA: update rojopolis/spellcheck-github-actions digest to 739a1e3 Closes #18515 --- .github/workflows/checkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index 917efc539891..36a4ff999e3a 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -117,7 +117,7 @@ jobs: run: grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt - name: 'check Spelling' - uses: rojopolis/spellcheck-github-actions@35a02bae020e6999c5c37fabaf447f2eb8822ca7 # v0 + uses: rojopolis/spellcheck-github-actions@739a1e3ceb79a98a5d4a9bf76f351137f9d78892 # v0 with: config_path: .github/scripts/spellcheck.yaml From 39c2d4b54363609865fa49f0f0d7adff84a03d03 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 18:40:05 +0000 Subject: [PATCH 002/208] GHA: update github/codeql-action digest to 192325c Closes #18516 --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 25a8f8cbc0fa..9863f7624d2c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -52,10 +52,10 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3 + uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3 with: languages: actions, python queries: security-extended - name: 'perform analysis' - uses: github/codeql-action/analyze@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3 + uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 From aa8a44ecfa0e46a839affb58c6640b514b062995 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 11 Sep 2025 11:20:08 +0200 Subject: [PATCH 003/208] GHA: fix and tweak installed packages for http3-linux and Windows-cross - explicitly install `libldap-dev` to not rely on test-specific packages installing it implicitly, to have the same `curl -V` output for each TLS backend build pair. Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 - install `libev-dev` for tests. It's a runtime dependency for the local build of `nghttpx`. Missing it made pytest skip 178 tests. Also skewing the 'Gain' time. I estimate it to account for 3 minutes, making the total gain ~20 minutes. Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 (It may be a better solution to disable libev for the local nghttp2 build, to avoid this hidden dependency.) - fix quiche jobs to use the local build of `libnghttp2`. - stop installing the `clang` package for Windows-cross. `clang` and `clang-tidy` tools are preinstalled on the Ubuntu 24.04 runner. Closes #18519 --- .github/workflows/http3-linux.yml | 7 ++++--- .github/workflows/windows.yml | 4 +--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 1a7ff07d5f25..3443b1146466 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -476,6 +476,7 @@ jobs: - name: 'quiche' install_steps: skipall + PKG_CONFIG_PATH: /home/runner/nghttp2/build/lib/pkgconfig configure: >- LDFLAGS=-Wl,-rpath,/home/runner/quiche/target/release --with-openssl=/home/runner/quiche/quiche/deps/boringssl/src @@ -484,7 +485,7 @@ jobs: --enable-unity - name: 'quiche' - PKG_CONFIG_PATH: /home/runner/quiche/target/release + PKG_CONFIG_PATH: /home/runner/nghttp2/build/lib/pkgconfig:/home/runner/quiche/target/release generate: >- -DOPENSSL_ROOT_DIR=/home/runner/quiche/quiche/deps/boringssl/src -DUSE_QUICHE=ON @@ -495,7 +496,7 @@ jobs: env: INSTALL_PACKAGES: >- ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'stunnel4 ' || '' }} - ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'apache2 apache2-dev libnghttp2-dev vsftpd dante-server' || '' }} + ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'apache2 apache2-dev libnghttp2-dev vsftpd dante-server libev-dev' || '' }} run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list @@ -503,7 +504,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install \ libtool autoconf automake pkgconf \ - libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libidn2-0-dev libuv1-dev \ + libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libidn2-0-dev libldap-dev libuv1-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} python3 -m venv ~/venv diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0938142df92b..9acc8cbde659 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -721,11 +721,9 @@ jobs: - { build: 'cmake' , compiler: 'clang-tidy' } steps: - name: 'install packages' - env: - INSTALL_PACKAGES: ${{ matrix.compiler == 'clang-tidy' && 'clang' || '' }} run: | sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install gcc-mingw-w64-x86-64-win32 ${INSTALL_PACKAGES} + sudo apt-get -o Dpkg::Use-Pty=0 install gcc-mingw-w64-x86-64-win32 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: From bf6ae59ab1586e3cd97f27341e4964a9316dc3d5 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 11 Sep 2025 15:02:57 +0200 Subject: [PATCH 004/208] GHA/windows: drop repeated word from comment --- .github/workflows/windows.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9acc8cbde659..b519af47d66c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -950,9 +950,8 @@ jobs: # Use Ninja when running tests to avoid MSBuild heuristics picking # up "error messages" in the test log output and making the job fail. # Officially this requires the vcvarsall.bat MS-DOS batch file (as of - # VS2022). Since it integrates badly with CI steps and shell scripts - # scripts, reproduce the necessary build configuration manually, and - # without envs. + # VS2022). Since it integrates badly with CI steps and shell scripts, + # reproduce the necessary build configuration manually, without envs. [[ "$(uname -s)" = *'ARM64'* ]] && MSVC_HOST='arm64' || MSVC_HOST='x64' # x86 MSVC_ROOTD="$(cygpath --mixed --short-name "$PROGRAMFILES/Microsoft Visual Studio")" # to avoid spaces in directory names MSVC_ROOTU="$(/usr/bin/find "$(cygpath --unix "$MSVC_ROOTD/2022/Enterprise/vc/tools/msvc")" -mindepth 1 -maxdepth 1 -type d -name '*.*' | sort | tail -n 1)" From b178d58266d4d9805de6da913b5be25c0485b6c2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 11 Sep 2025 12:59:22 +0200 Subject: [PATCH 005/208] quic: fix min TLS version handling When switching to TSLv1.2 as default in 9d8998c99408e1adf8eba629fad9f87b3235bdfa, this led to an explicit setting of 1.2 on QUIC connections when using quictls, overriding the already set min version of 1.3. This leads to a ClientHello with TLS 1.2+1.3 offered on a QUIC connect which is rejected by the Caddy server. Using ngtcp2 with OpenSSL 3.5+, GnuTLS or AWS-LC is not affected. Fixes #18518 Reported-by: fds242 on github Closes #18520 --- lib/vtls/openssl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index a49203ab07d2..5c22ad25dc94 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2865,11 +2865,12 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ static CURLcode -ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) +ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx, + unsigned int ssl_version_min) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); /* first, TLS min version... */ - long curl_ssl_version_min = conn_config->version; + long curl_ssl_version_min = (long)ssl_version_min; long curl_ssl_version_max; /* convert curl min SSL version option to OpenSSL constant */ @@ -4110,7 +4111,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, ctx_options |= SSL_OP_NO_SSLv3; #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ - result = ossl_set_ssl_version_min_max(cf, octx->ssl_ctx); + result = ossl_set_ssl_version_min_max(cf, octx->ssl_ctx, ssl_version_min); #else result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data); #endif From 115fe808f2346b9c02d2720d8f575098e473a5d2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 11 Sep 2025 14:12:04 +0200 Subject: [PATCH 006/208] ngtcp2: check error code on connect failure Access the error codes of ngtcp2 when a connect attempt failes. Trace the information for analysis. Treat errors as permanent failure by default, trigger retrying only when the server refused without indicating an error. Closes #18521 --- lib/vquic/curl_ngtcp2.c | 30 +++++++++++++++++++++++++----- tests/http/testenv/nghttpx.py | 7 ++++--- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 6470f1506d15..3f7c58d08af2 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2578,11 +2578,31 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, out: if(result == CURLE_RECV_ERROR && ctx->qconn && ngtcp2_conn_in_draining_period(ctx->qconn)) { - /* When a QUIC server instance is shutting down, it may send us a - * CONNECTION_CLOSE right away. Our connection then enters the DRAINING - * state. The CONNECT may work in the near future again. Indicate - * that as a "weird" reply. */ - result = CURLE_WEIRD_SERVER_REPLY; + const ngtcp2_ccerr *cerr = ngtcp2_conn_get_ccerr(ctx->qconn); + + result = CURLE_COULDNT_CONNECT; + if(cerr) { + CURL_TRC_CF(data, cf, "connect error, type=%d, code=%" + FMT_PRIu64, + cerr->type, (curl_uint64_t)cerr->error_code); + switch(cerr->type) { + case NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION: + CURL_TRC_CF(data, cf, "error in version negotiation"); + break; + default: + if(cerr->error_code >= NGTCP2_CRYPTO_ERROR) { + CURL_TRC_CF(data, cf, "crypto error, tls alert=%u", + (unsigned int)(cerr->error_code & 0xffu)); + } + else if(cerr->error_code == NGTCP2_CONNECTION_REFUSED) { + CURL_TRC_CF(data, cf, "connection refused by server"); + /* When a QUIC server instance is shutting down, it may send us a + * CONNECTION_CLOSE with this code right away. We want + * to keep on trying in this case. */ + result = CURLE_WEIRD_SERVER_REPLY; + } + } + } } #ifndef CURL_DISABLE_VERBOSE_STRINGS diff --git a/tests/http/testenv/nghttpx.py b/tests/http/testenv/nghttpx.py index 0bd46ac3603c..dfb416334c5a 100644 --- a/tests/http/testenv/nghttpx.py +++ b/tests/http/testenv/nghttpx.py @@ -124,15 +124,16 @@ def reload(self, timeout: timedelta = timedelta(seconds=Env.SERVER_TIMEOUT)): running = self._process self._process = None os.kill(running.pid, signal.SIGQUIT) - end_wait = datetime.now() + timeout + end_wait = datetime.now() + timedelta(seconds=5) if not self.start(wait_live=False): self._process = running return False while datetime.now() < end_wait: try: log.debug(f'waiting for nghttpx({running.pid}) to exit.') - running.wait(2) + running.wait(1) log.debug(f'nghttpx({running.pid}) terminated -> {running.returncode}') + running = None break except subprocess.TimeoutExpired: log.warning(f'nghttpx({running.pid}), not shut down yet.') @@ -142,7 +143,7 @@ def reload(self, timeout: timedelta = timedelta(seconds=Env.SERVER_TIMEOUT)): os.kill(running.pid, signal.SIGKILL) running.terminate() running.wait(1) - return self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT)) + return self.wait_live(timeout=timeout) return False def wait_dead(self, timeout: timedelta): From 839b22863e2f3dfdceab91e66c23257bc8726863 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 16:09:45 +0200 Subject: [PATCH 007/208] ssl-sessions.md: mark option experimental Also make managen output the experimental text with the correct prefix/margin for the ascii version. Closes #18523 --- docs/cmdline-opts/ssl-sessions.md | 1 + scripts/managen | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/cmdline-opts/ssl-sessions.md b/docs/cmdline-opts/ssl-sessions.md index bb1e251e732d..33ef984a3ec4 100644 --- a/docs/cmdline-opts/ssl-sessions.md +++ b/docs/cmdline-opts/ssl-sessions.md @@ -8,6 +8,7 @@ Help: Load/save SSL session tickets from/to this file Added: 8.12.0 Category: tls Multi: single +Experimental: yes See-also: - tls-earlydata Example: diff --git a/scripts/managen b/scripts/managen index 459b651240a6..1eb536a0e6d7 100755 --- a/scripts/managen +++ b/scripts/managen @@ -728,7 +728,8 @@ sub single { } if($experimental) { - push @leading, "**WARNING**: this option is experimental. Do not use in production.\n\n"; + my $pref = $manpage ? "" : "[1]"; + push @leading, "$pref**WARNING**: this option is experimental. Do not use in production.\n\n"; } my $pre = $manpage ? "\n": "[1]"; From 53f90cb3b5678de16a0129ff4f9f3f0e87dfd78b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 11 Sep 2025 15:05:28 +0200 Subject: [PATCH 008/208] GHA/http3-linux: fix nghttpx build and other tweaks - fix `nghttp2` build to also build the `nghttpx` application. Restore required `libc-ares-dev`. Also confirm that `libev-dev` is required too. Document these requirements. Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 - explicitly enable `nghttpx` for the `nghttp2` build to make it fail if requirements aren't met: ``` configure: error: applications were requested (--enable-app) but dependencies are not met. ``` - explicitly install brotli, zstd, zlib for the dependency builds. Of these, zstd and zlib are preinstalled. zlib is required for `nghttpx`. zstd and brotli doesn't seem to be used, but keep them there just in case and to match the test env. Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 - enable brotli for `nghttpx`. It doesn't change the tests, and also cost almost nothing, so I figure why not. Closes #18522 --- .github/workflows/http3-linux.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 3443b1146466..195437182f11 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -193,7 +193,10 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install \ libtool autoconf automake pkgconf \ - nettle-dev libp11-kit-dev libev-dev autopoint bison gperf gtk-doc-tools libtasn1-bin # for gnutls + libbrotli-dev libzstd-dev zlib1g-dev \ + libev-dev \ + libc-ares-dev \ + nettle-dev libp11-kit-dev autopoint bison gperf gtk-doc-tools libtasn1-bin # for GnuTLS echo 'CC=gcc-12' >> "$GITHUB_ENV" echo 'CXX=g++-12' >> "$GITHUB_ENV" @@ -256,6 +259,7 @@ jobs: cd ~ git clone --quiet --depth=1 -b "${GNUTLS_VERSION}" https://github.com/gnutls/gnutls.git cd gnutls + # required: nettle-dev libp11-kit-dev libev-dev autopoint bison gperf gtk-doc-tools libtasn1-bin ./bootstrap ./configure --disable-dependency-tracking --prefix="$PWD"/build \ LDFLAGS="-Wl,-rpath,$PWD/build/lib -L$PWD/build/lib" \ @@ -332,10 +336,13 @@ jobs: cd nghttp2 git submodule update --init --depth=1 autoreconf -fi + # required (for nghttpx application): libc-ares-dev libev-dev zlib1g-dev + # optional (for nghttpx application): libbrotli-dev ./configure --disable-dependency-tracking --prefix="$PWD"/build \ PKG_CONFIG_PATH=/home/runner/quictls/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/ngtcp2/build/lib/pkgconfig \ LDFLAGS=-Wl,-rpath,/home/runner/quictls/build/lib \ - --enable-http3 + --with-libbrotlienc --with-libbrotlidec \ + --enable-app --enable-http3 make install linux: From c184f464f795dbdf8db354b9b2bc01891ddc4fdd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 17:50:59 +0200 Subject: [PATCH 009/208] CURLOPT_MAXLIFETIME_CONN: make default 24 hours Set a default value to only reuse existing connections if less than 24 hours old. This makes the TLS certificate check get redone for the new connection. An application can still set it to zero. Closes #18527 --- docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md | 14 ++++++++------ lib/url.c | 2 +- lib/urldata.h | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md b/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md index b29e61a2c3e5..8c1fbf82f86b 100644 --- a/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md +++ b/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md @@ -35,16 +35,18 @@ connection to have to be considered for reuse for this request. libcurl features a connection cache that holds previously used connections. When a new request is to be done, libcurl considers any connection that -matches for reuse. The CURLOPT_MAXLIFETIME_CONN(3) limit prevents -libcurl from trying too old connections for reuse. This can be used for -client-side load balancing. If a connection is found in the cache that is -older than this set *maxlifetime*, it is instead marked for closure. +matches for reuse. The CURLOPT_MAXLIFETIME_CONN(3) limit prevents libcurl from +trying too old connections for reuse. This can be used for client-side load +balancing. If a connection is found in the cache that is older than this set +*maxlifetime*, it is instead marked for closure. -If set to 0, this behavior is disabled: all connections are eligible for reuse. +If set to 0, this behavior is disabled: all connections are eligible for +reuse. # DEFAULT -0 seconds (i.e., disabled) +24 hours (since 8.17.0). Before that, the default was 0 seconds (i.e., +disabled) # %PROTOCOLS% diff --git a/lib/url.c b/lib/url.c index 45d44bac738f..283da6d68b50 100644 --- a/lib/url.c +++ b/lib/url.c @@ -488,7 +488,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ set->conn_max_idle_ms = 118 * 1000; - set->conn_max_age_ms = 0; + set->conn_max_age_ms = 24 * 3600 * 1000; set->http09_allowed = FALSE; set->httpwant = CURL_HTTP_VERSION_NONE ; diff --git a/lib/urldata.h b/lib/urldata.h index cf181af641fd..a0ee614da838 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1390,9 +1390,9 @@ struct UserDefined { void *progress_client; /* pointer to pass to the progress callback */ void *ioctl_client; /* pointer to pass to the ioctl callback */ timediff_t conn_max_idle_ms; /* max idle time to allow a connection that - is to be reused */ + is to be reused */ timediff_t conn_max_age_ms; /* max time since creation to allow a - connection that is to be reused */ + connection that is to be reused */ curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ long low_speed_time; /* number of seconds */ From 16cd81ed69b9123584dd73a6924a8f852dc2372a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 16:52:40 +0200 Subject: [PATCH 010/208] urldata: FILE is not a list-only protocol The struct field thus does not depend on the presence of it Closes #18525 --- lib/urldata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/urldata.h b/lib/urldata.h index a0ee614da838..4f00c8c9a093 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -116,7 +116,7 @@ typedef unsigned int curl_prot_t; #define PROTO_FAMILY_SSH (CURLPROTO_SCP|CURLPROTO_SFTP) #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) || \ - !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_FILE) + !defined(CURL_DISABLE_POP3) /* these protocols support CURLOPT_DIRLISTONLY */ #define CURL_LIST_ONLY_PROTOCOL 1 #endif From 57b195bf51ae863d93f48257039c080be4e61359 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 23:46:34 +0200 Subject: [PATCH 011/208] CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well Closes #18531 --- docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md index a25ac0a72c74..08b5a6d336ba 100644 --- a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md +++ b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md @@ -9,6 +9,7 @@ See-also: - curl_easy_setopt (3) Protocol: - FTP + - SFTP Added-in: 7.15.4 --- @@ -28,7 +29,7 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FTP_ENTRY_PATH, char **path); Pass a pointer to a char pointer to receive a pointer to a string holding the path of the entry path. That is the initial path libcurl ended up in when -logging on to the remote FTP server. This stores a NULL as pointer if +logging on to the remote FTP or SFTP server. This stores a NULL as pointer if something is wrong. The **path** pointer is NULL or points to private memory. You MUST NOT free From d7d32ad9b9e9dbf7a372689affd497dcec18df6e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 23:16:55 +0200 Subject: [PATCH 012/208] docs/libcurl: remove ancient version references To make the texts easier on the eye. - Remove most free text references to curl versions before 7.60.0 (May 2018) - Leave those present in a HISTORY section Most of them are already documented in symbols-in-versions anyway. Closes #18530 --- docs/libcurl/curl_easy_getinfo.md | 6 +-- docs/libcurl/curl_formadd.md | 15 +++---- docs/libcurl/curl_global_init.md | 2 +- docs/libcurl/curl_version_info.md | 40 ++++++++----------- docs/libcurl/libcurl-errors.md | 20 ++++------ .../opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md | 4 +- docs/libcurl/opts/CURLINFO_TLS_SESSION.md | 13 +++--- docs/libcurl/opts/CURLOPT_HTTP_VERSION.md | 10 ++--- docs/libcurl/opts/CURLOPT_ISSUERCERT.md | 4 +- docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md | 1 - .../opts/CURLOPT_OPENSOCKETFUNCTION.md | 1 - docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md | 11 ----- .../libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md | 3 +- docs/libcurl/opts/CURLOPT_QUOTE.md | 2 +- docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md | 1 - docs/libcurl/opts/CURLOPT_SSLVERSION.md | 26 ++++-------- docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md | 3 +- docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md | 2 +- docs/libcurl/opts/CURLSHOPT_SHARE.md | 10 ++--- 19 files changed, 63 insertions(+), 111 deletions(-) diff --git a/docs/libcurl/curl_easy_getinfo.md b/docs/libcurl/curl_easy_getinfo.md index dff050447748..9515fadeed2c 100644 --- a/docs/libcurl/curl_easy_getinfo.md +++ b/docs/libcurl/curl_easy_getinfo.md @@ -45,7 +45,7 @@ The session's active socket. See CURLINFO_ACTIVESOCKET(3) ## CURLINFO_APPCONNECT_TIME The time it took from the start until the SSL connect/handshake with the -remote host was completed as a double in number of seconds. (Added in 7.19.0) +remote host was completed as a double in number of seconds. ## CURLINFO_APPCONNECT_TIME_T @@ -222,7 +222,7 @@ User's private data pointer. See CURLINFO_PRIVATE(3) ## CURLINFO_PROTOCOL -(**Deprecated**) The protocol used for the connection. (Added in 7.52.0) See +(**Deprecated**) The protocol used for the connection. See CURLINFO_PROTOCOL(3) ## CURLINFO_PROXYAUTH_AVAIL @@ -303,7 +303,7 @@ RTSP session ID. See CURLINFO_RTSP_SESSION_ID(3) ## CURLINFO_SCHEME -The scheme used for the connection. (Added in 7.52.0) See CURLINFO_SCHEME(3) +The scheme used for the connection. See CURLINFO_SCHEME(3) ## CURLINFO_SIZE_DOWNLOAD diff --git a/docs/libcurl/curl_formadd.md b/docs/libcurl/curl_formadd.md index 6bef05523a9b..f35e50eab754 100644 --- a/docs/libcurl/curl_formadd.md +++ b/docs/libcurl/curl_formadd.md @@ -101,8 +101,6 @@ If you pass a 0 (zero) for this option, libcurl calls strlen() on the contents to figure out the size. If you really want to send a zero byte content then you must make sure strlen() on the data pointer returns zero. -(Option added in 7.46.0) - ## CURLFORM_CONTENTSLENGTH (This option is deprecated. Use *CURLFORM_CONTENTLEN* instead.) @@ -171,13 +169,12 @@ long which gives the length of the buffer. ## CURLFORM_STREAM -Tells libcurl to use the CURLOPT_READFUNCTION(3) callback to get -data. The parameter you pass to *CURLFORM_STREAM* is the pointer passed on -to the read callback's fourth argument. If you want the part to look like a -file upload one, set the *CURLFORM_FILENAME* parameter as well. Note that -when using *CURLFORM_STREAM*, *CURLFORM_CONTENTSLENGTH* must also be -set with the total expected length of the part unless the formpost is sent -chunked encoded. (Option added in libcurl 7.18.2) +Tells libcurl to use the CURLOPT_READFUNCTION(3) callback to get data. The +parameter you pass to *CURLFORM_STREAM* is the pointer passed on to the read +callback's fourth argument. If you want the part to look like a file upload +one, set the *CURLFORM_FILENAME* parameter as well. Note that when using +*CURLFORM_STREAM*, *CURLFORM_CONTENTSLENGTH* must also be set with the total +expected length of the part unless the formpost is sent chunked encoded. ## CURLFORM_ARRAY diff --git a/docs/libcurl/curl_global_init.md b/docs/libcurl/curl_global_init.md index 198b6e9f3058..724f90cddc8f 100644 --- a/docs/libcurl/curl_global_init.md +++ b/docs/libcurl/curl_global_init.md @@ -108,7 +108,7 @@ This bit has no point since 7.69.0 but its behavior is instead the default. Before 7.69.0: when this flag is set, curl acknowledges EINTR condition when connecting or when waiting for data. Otherwise, curl waits until full timeout -elapses. (Added in 7.30.0) +elapses. # %PROTOCOLS% diff --git a/docs/libcurl/curl_version_info.md b/docs/libcurl/curl_version_info.md index 8a8671dbf907..a9c97b39c596 100644 --- a/docs/libcurl/curl_version_info.md +++ b/docs/libcurl/curl_version_info.md @@ -165,13 +165,13 @@ HTTP Alt-Svc parsing and the associated options (Added in 7.64.1) libcurl was built with support for asynchronous name lookups, which allows more exact timeouts (even on Windows) and less blocking when using the multi -interface. (added in 7.10.7) +interface. ## `brotli` *features* mask bit: CURL_VERSION_BROTLI -supports HTTP Brotli content encoding using libbrotlidec (Added in 7.57.0) +supports HTTP Brotli content encoding using libbrotlidec ## `asyn-rr` @@ -185,7 +185,7 @@ resolves, but uses the threaded resolver for "normal" resolves (Added in *features* mask bit: CURL_VERSION_DEBUG -libcurl was built with debug capabilities (added in 7.10.6) +libcurl was built with debug capabilities ## `ECH` @@ -207,7 +207,6 @@ authentication methods. (added in 7.76.0) libcurl was built with support for GSS-API. This makes libcurl use provided functions for Kerberos and SPNEGO authentication. It also allows libcurl to use the current user credentials without the app having to pass them on. -(Added in 7.38.0) ## `HSTS` @@ -221,7 +220,6 @@ libcurl was built with support for HSTS (HTTP Strict Transport Security) *features* mask bit: CURL_VERSION_HTTP2 libcurl was built with support for HTTP2. -(Added in 7.33.0) ## `HTTP3` @@ -234,7 +232,6 @@ HTTP/3 and QUIC support are built-in (Added in 7.66.0) *features* mask bit: CURL_VERSION_HTTPS_PROXY libcurl was built with support for HTTPS-proxy. -(Added in 7.52.0) ## `HTTPSRR` @@ -248,7 +245,7 @@ in 8.12.0) *features* mask bit: CURL_VERSION_IDN libcurl was built with support for IDNA, domain names with international -letters. (Added in 7.12.0) +letters. ## `IPv6` @@ -261,19 +258,19 @@ supports IPv6 *features* mask bit: CURL_VERSION_KERBEROS5 supports Kerberos V5 authentication for FTP, IMAP, LDAP, POP3, SMTP and -SOCKSv5 proxy. (Added in 7.40.0) +SOCKSv5 proxy. ## `Largefile` *features* mask bit: CURL_VERSION_LARGEFILE -libcurl was built with support for large files. (Added in 7.11.1) +libcurl was built with support for large files. ## `libz` *features* mask bit: CURL_VERSION_LIBZ -supports HTTP deflate using libz (Added in 7.10) +supports HTTP deflate using libz ## `MultiSSL` @@ -281,20 +278,19 @@ supports HTTP deflate using libz (Added in 7.10) libcurl was built with multiple SSL backends. For details, see curl_global_sslset(3). -(Added in 7.56.0) ## `NTLM` *features* mask bit: CURL_VERSION_NTLM -supports HTTP NTLM (added in 7.10.6) +supports HTTP NTLM ## `NTLM_WB` *features* mask bit: CURL_VERSION_NTLM_WB -libcurl was built with support for NTLM delegation to a winbind helper. -(Added in 7.22.0) This feature was removed from curl in 8.8.0. +libcurl was built with support for NTLM delegation to a winbind helper. This +feature was removed from curl in 8.8.0. ## `PSL` @@ -302,20 +298,19 @@ libcurl was built with support for NTLM delegation to a winbind helper. libcurl was built with support for Mozilla's Public Suffix List. This makes libcurl ignore cookies with a domain that is on the list. -(Added in 7.47.0) ## `SPNEGO` *features* mask bit: CURL_VERSION_SPNEGO libcurl was built with support for SPNEGO authentication (Simple and Protected -GSS-API Negotiation Mechanism, defined in RFC 2478.) (added in 7.10.8) +GSS-API Negotiation Mechanism, defined in RFC 2478.) ## `SSL` *features* mask bit: CURL_VERSION_SSL -supports SSL (HTTPS/FTPS) (Added in 7.10) +supports SSL (HTTPS/FTPS) ## `SSLS-EXPORT` @@ -331,7 +326,7 @@ libcurl was built with SSL session import/export support libcurl was built with support for SSPI. This is only available on Windows and makes libcurl use Windows-provided functions for Kerberos, NTLM, SPNEGO and Digest authentication. It also allows libcurl to use the current user -credentials without the app having to pass them on. (Added in 7.13.2) +credentials without the app having to pass them on. ## `threadsafe` @@ -345,14 +340,14 @@ curl initialization. (Added in 7.84.0) See libcurl-thread(3) *features* mask bit: CURL_VERSION_TLSAUTH_SRP libcurl was built with support for TLS-SRP (in one or more of the built-in TLS -backends). (Added in 7.21.4) +backends). ## `TrackMemory` *features* mask bit: CURL_VERSION_CURLDEBUG libcurl was built with memory tracking debug capabilities. This is mainly of -interest for libcurl hackers. (added in 7.19.6) +interest for libcurl hackers. ## `Unicode` @@ -366,7 +361,6 @@ characters work in filenames and options passed to libcurl. (Added in 7.72.0) *features* mask bit: CURL_VERSION_UNIX_SOCKETS libcurl was built with support for Unix domain sockets. -(Added in 7.40.0) ## `zstd` @@ -379,13 +373,13 @@ supports HTTP zstd content encoding using zstd library (Added in 7.72.0) *features* mask bit: CURL_VERSION_CONV libcurl was built with support for character conversions provided by -callbacks. Always 0 since 7.82.0. (Added in 7.15.4, deprecated.) +callbacks. Always 0 since 7.82.0. Deprecated. ## no name *features* mask bit: CURL_VERSION_GSSNEGOTIATE -supports HTTP GSS-Negotiate (added in 7.10.6, deprecated in 7.38.0) +supports HTTP GSS-Negotiate. Deprecated. ## no name diff --git a/docs/libcurl/libcurl-errors.md b/docs/libcurl/libcurl-errors.md index 773601dae71f..25d63bf81fd3 100644 --- a/docs/libcurl/libcurl-errors.md +++ b/docs/libcurl/libcurl-errors.md @@ -349,7 +349,7 @@ Initiating the SSL Engine failed. ## CURLE_LOGIN_DENIED (67) -The remote server denied curl to login (Added in 7.13.1) +The remote server denied curl to login ## CURLE_TFTP_NOTFOUND (68) @@ -403,22 +403,20 @@ Failed to shut down the SSL connection. Socket is not ready for send/recv. Wait until it is ready and try again. This return code is only returned from curl_easy_recv(3) and curl_easy_send(3) -(Added in 7.18.2) ## CURLE_SSL_CRL_BADFILE (82) -Failed to load CRL file (Added in 7.19.0) +Failed to load CRL file ## CURLE_SSL_ISSUER_ERROR (83) -Issuer check failed (Added in 7.19.0) +Issuer check failed ## CURLE_FTP_PRET_FAILED (84) The FTP server does not understand the PRET command at all or does not support the given argument. Be careful when using CURLOPT_CUSTOMREQUEST(3), a -custom LIST command is sent with the PRET command before PASV as well. (Added -in 7.20.0) +custom LIST command is sent with the PRET command before PASV as well. ## CURLE_RTSP_CSEQ_ERROR (85) @@ -439,7 +437,7 @@ Chunk callback reported error. ## CURLE_NO_CONNECTION_AVAILABLE (89) (For internal use only, is never returned by libcurl) No connection available, -the session is queued. (added in 7.30.0) +the session is queued. ## CURLE_SSL_PINNEDPUBKEYNOTMATCH (90) @@ -509,7 +507,6 @@ used. An alias for *CURLM_CALL_MULTI_PERFORM*. Never returned by modern libcurl versions. -(Added in 7.15.5) ## CURLM_OK (0) @@ -536,17 +533,15 @@ This can only be returned if libcurl bugs. Please report it to us. ## CURLM_BAD_SOCKET (5) The passed-in socket is not a valid one that libcurl already knows about. -(Added in 7.15.4) ## CURLM_UNKNOWN_OPTION (6) curl_multi_setopt() with unsupported option -(Added in 7.15.4) ## CURLM_ADDED_ALREADY (7) An easy handle already added to a multi handle was attempted to get added a -second time. (Added in 7.32.1) +second time. ## CURLM_RECURSIVE_API_CALL (8) @@ -592,12 +587,11 @@ An invalid share object was passed to the function. ## CURLSHE_NOMEM (4) Not enough memory was available. -(Added in 7.12.0) ## CURLSHE_NOT_BUILT_IN (5) The requested sharing could not be done because the library you use do not have -that particular feature enabled. (Added in 7.23.0) +that particular feature enabled. # CURLUcode diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md index 60fae12acd89..46e8e7ba015d 100644 --- a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md +++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md @@ -29,8 +29,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, # DESCRIPTION Pass a pointer to a double to receive the content-length of the download. This -is the value read from the Content-Length: field. Since 7.19.4, this returns --1 if the size is not known. +is the value read from the Content-Length: field. This returns -1 if the size +is not known. CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) is a newer replacement that returns a more sensible variable type. diff --git a/docs/libcurl/opts/CURLINFO_TLS_SESSION.md b/docs/libcurl/opts/CURLINFO_TLS_SESSION.md index 4fb5425f852f..f4209b45b6b0 100644 --- a/docs/libcurl/opts/CURLINFO_TLS_SESSION.md +++ b/docs/libcurl/opts/CURLINFO_TLS_SESSION.md @@ -31,14 +31,11 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_TLS_SESSION, # DESCRIPTION -**This option has been superseded** by CURLINFO_TLS_SSL_PTR(3) which -was added in 7.48.0. The only reason you would use this option instead is if -you could be using a version of libcurl earlier than 7.48.0. - -This option is exactly the same as CURLINFO_TLS_SSL_PTR(3) except in the -case of OpenSSL and wolfSSL. If the session *backend* is -CURLSSLBACKEND_OPENSSL the session *internals* pointer varies depending -on the option: +**This option has been superseded** by CURLINFO_TLS_SSL_PTR(3). + +This option is exactly the same as CURLINFO_TLS_SSL_PTR(3) except in the case +of OpenSSL and wolfSSL. If the session *backend* is CURLSSLBACKEND_OPENSSL the +session *internals* pointer varies depending on the option: ## OpenSSL: diff --git a/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md b/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md index dd791b81cb2c..4cabb09f8772 100644 --- a/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md +++ b/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md @@ -51,27 +51,27 @@ Enforce HTTP 1.1 requests. ## CURL_HTTP_VERSION_2_0 Attempt HTTP 2 requests. libcurl falls back to HTTP 1.1 if HTTP 2 cannot be -negotiated with the server. (Added in 7.33.0) +negotiated with the server. When libcurl uses HTTP/2 over HTTPS, it does not itself insist on TLS 1.2 or higher even though that is required by the specification. A user can add this version requirement with CURLOPT_SSLVERSION(3). -The alias *CURL_HTTP_VERSION_2* was added in 7.43.0 to better reflect the -actual protocol name. +The alias *CURL_HTTP_VERSION_2* was added to better reflect the actual +protocol name. ## CURL_HTTP_VERSION_2TLS Attempt HTTP 2 over TLS (HTTPS) only. libcurl falls back to HTTP 1.1 if HTTP 2 cannot be negotiated with the HTTPS server. For clear text HTTP servers, -libcurl uses 1.1. (Added in 7.47.0) +libcurl uses 1.1. ## CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE Issue non-TLS HTTP requests using HTTP/2 without HTTP/1.1 Upgrade. It requires prior knowledge that the server supports HTTP/2 straight away. HTTPS requests still do HTTP/2 the standard way with negotiated protocol version in the TLS -handshake. (Added in 7.49.0) +handshake. Since 8.10.0 if this option is set for an HTTPS request then the application layer protocol version (ALPN) offered to the server is only HTTP/2. Prior to diff --git a/docs/libcurl/opts/CURLOPT_ISSUERCERT.md b/docs/libcurl/opts/CURLOPT_ISSUERCERT.md index 0dc4c2243c50..7b6998040bcb 100644 --- a/docs/libcurl/opts/CURLOPT_ISSUERCERT.md +++ b/docs/libcurl/opts/CURLOPT_ISSUERCERT.md @@ -43,8 +43,8 @@ not considered as failure. A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option, which is returned if the setup of the SSL/TLS session has failed due to a -mismatch with the issuer of peer certificate (CURLOPT_SSL_VERIFYPEER(3) -has to be set too for the check to fail). (Added in 7.19.0) +mismatch with the issuer of peer certificate (CURLOPT_SSL_VERIFYPEER(3) has to +be set too for the check to fail). Using this option multiple times makes the last set string override the previous ones. Set it to NULL to disable its use again. diff --git a/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md b/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md index 2962994b2ae2..d91a7da3ba7f 100644 --- a/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md +++ b/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md @@ -56,7 +56,6 @@ static curl_socket_t opensocket(void *clientp, static int sockopt_callback(void *clientp, curl_socket_t curlfd, curlsocktype purpose) { - /* This return code was added in libcurl 7.21.5 */ return CURL_SOCKOPT_ALREADY_CONNECTED; } diff --git a/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md b/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md index b8517c4f3233..89931d0e066c 100644 --- a/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md @@ -104,7 +104,6 @@ static curl_socket_t opensocket(void *clientp, static int sockopt_callback(void *clientp, curl_socket_t curlfd, curlsocktype purpose) { - /* This return code was added in libcurl 7.21.5 */ return CURL_SOCKOPT_ALREADY_CONNECTED; } diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md index 7e1f6f140066..bb35bda1ae97 100644 --- a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md @@ -72,33 +72,22 @@ supported for wolfSSL. The flag defines the maximum supported TLS version as TLSv1.2, or the default value from the SSL library. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_0 The flag defines maximum supported TLS version as TLSv1.0. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_1 The flag defines maximum supported TLS version as TLSv1.1. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_2 The flag defines maximum supported TLS version as TLSv1.2. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_3 The flag defines maximum supported TLS version as TLSv1.3. -(Added in 7.54.0) - -## - -In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were -documented to allow *only* the specified TLS version, but behavior was -inconsistent depending on the TLS library. # DEFAULT diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md index 0729518a0df1..18b7ce6b36a1 100644 --- a/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md @@ -49,8 +49,7 @@ Transport and OpenSSL. Tells libcurl to disable certificate revocation checks for those SSL backends where such behavior is present. This option is only supported for Schannel (the native Windows SSL library), with an exception in the case of Windows' -Untrusted Publishers block list which it seems cannot be bypassed. (Added in -7.44.0) +Untrusted Publishers block list which it seems cannot be bypassed. ## CURLSSLOPT_NO_PARTIALCHAIN diff --git a/docs/libcurl/opts/CURLOPT_QUOTE.md b/docs/libcurl/opts/CURLOPT_QUOTE.md index 8687f527a9d5..5e00f45137ef 100644 --- a/docs/libcurl/opts/CURLOPT_QUOTE.md +++ b/docs/libcurl/opts/CURLOPT_QUOTE.md @@ -120,7 +120,7 @@ operand, provided it is empty. ## statvfs file The statvfs command returns statistics on the file system in which specified -file resides. (Added in 7.49.0) +file resides. ## symlink source_file target_file diff --git a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md index 0efdd0b3be5e..a2ded45692c8 100644 --- a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md @@ -96,7 +96,6 @@ static curl_socket_t opensocket(void *clientp, static int sockopt_callback(void *clientp, curl_socket_t curlfd, curlsocktype purpose) { - /* This return code was added in libcurl 7.21.5 */ return CURL_SOCKOPT_ALREADY_CONNECTED; } diff --git a/docs/libcurl/opts/CURLOPT_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_SSLVERSION.md index 366edc0a7e27..6aa641def9a2 100644 --- a/docs/libcurl/opts/CURLOPT_SSLVERSION.md +++ b/docs/libcurl/opts/CURLOPT_SSLVERSION.md @@ -58,58 +58,48 @@ SSL v3 - refused ## CURL_SSLVERSION_TLSv1_0 -TLS v1.0 or later (Added in 7.34.0) +TLS v1.0 or later ## CURL_SSLVERSION_TLSv1_1 -TLS v1.1 or later (Added in 7.34.0) +TLS v1.1 or later ## CURL_SSLVERSION_TLSv1_2 -TLS v1.2 or later (Added in 7.34.0) +TLS v1.2 or later ## CURL_SSLVERSION_TLSv1_3 -TLS v1.3 or later (Added in 7.52.0) +TLS v1.3 or later ## -The maximum TLS version can be set by using *one* of the -CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the -CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros. +The maximum TLS version can be set by using *one* of the CURL_SSLVERSION_MAX_ +macros below. It is also possible to OR *one* of the CURL_SSLVERSION_ macros +with *one* of the CURL_SSLVERSION_MAX_ macros. ## CURL_SSLVERSION_MAX_DEFAULT The flag defines the maximum supported TLS version by libcurl, or the default value from the SSL library is used. libcurl uses a sensible default maximum, which was TLS v1.2 up to before 7.61.0 and is TLS v1.3 since then - assuming -the TLS library support it. (Added in 7.54.0) +the TLS library support it. ## CURL_SSLVERSION_MAX_TLSv1_0 The flag defines maximum supported TLS version as TLS v1.0. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_1 The flag defines maximum supported TLS version as TLS v1.1. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_2 The flag defines maximum supported TLS version as TLS v1.2. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_3 The flag defines maximum supported TLS version as TLS v1.3. -(Added in 7.54.0) - -## - -In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were -documented to allow *only* the specified TLS version, but behavior was -inconsistent depending on the TLS library. # DEFAULT diff --git a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md index 89a1d430f789..2065fe6f1660 100644 --- a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md +++ b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md @@ -47,8 +47,7 @@ Transport and OpenSSL. Tells libcurl to disable certificate revocation checks for those SSL backends where such behavior is present. This option is only supported for Schannel (the native Windows SSL library), with an exception in the case of Windows' -Untrusted Publishers block list which it seems cannot be bypassed. (Added in -7.44.0) +Untrusted Publishers block list which it seems cannot be bypassed. ## CURLSSLOPT_NO_PARTIALCHAIN diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md index 9ac65c42b411..2d664439a28b 100644 --- a/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md +++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md @@ -28,7 +28,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPINTVL, long interval); # DESCRIPTION Pass a long. Sets the interval, in seconds, to wait between sending keepalive -probes. Not all operating systems support this option. (Added in 7.25.0) +probes. Not all operating systems support this option. The maximum value this accepts is 2147483648. Any larger value is capped to this amount. diff --git a/docs/libcurl/opts/CURLSHOPT_SHARE.md b/docs/libcurl/opts/CURLSHOPT_SHARE.md index 4171430a790a..92a279a31012 100644 --- a/docs/libcurl/opts/CURLSHOPT_SHARE.md +++ b/docs/libcurl/opts/CURLSHOPT_SHARE.md @@ -54,10 +54,9 @@ the same multi handle share the DNS cache by default without using this option. ## CURL_LOCK_DATA_SSL_SESSION -SSL sessions are shared across the easy handles using this shared -object. This reduces the time spent in the SSL handshake when reconnecting to -the same server. This symbol was added in 7.10.3 but was not implemented until -7.23.0. +SSL sessions are shared across the easy handles using this shared object. This +reduces the time spent in the SSL handshake when reconnecting to the same +server. Note that when you use the multi interface, all easy handles added to the same multi handle share the SSL session cache by default without using this option. @@ -74,9 +73,6 @@ additional transfers added to them if the existing connection is held by the same multi or easy handle. libcurl does not support doing multiplexed streams in different threads using a shared connection. -Support for **CURL_LOCK_DATA_CONNECT** was added in 7.57.0, but the symbol -existed before this. - Note that when you use the multi interface, all easy handles added to the same multi handle share the connection cache by default without using this option. From bbdb869ec7e708d12128784a13a1b9e34c67b450 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 12 Sep 2025 00:10:20 -0700 Subject: [PATCH 013/208] libcurl-security.md: mention long-running connections Some applications may want to periodically recheck the remote server certificate, which doesn't happen on a long-running connection. Ref: #18527 Closes #18533 --- docs/libcurl/libcurl-security.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/libcurl/libcurl-security.md b/docs/libcurl/libcurl-security.md index c6a10cd27151..7fbd32974d2c 100644 --- a/docs/libcurl/libcurl-security.md +++ b/docs/libcurl/libcurl-security.md @@ -98,6 +98,24 @@ Use authenticated protocols protected with HTTPS or SSH. Never ever switch off certificate verification. +# Certificates and Long-running Connections + +Certificate validation of encrypted connections is performed immediately after +a connection is established. That connection could be used for many subsequent +transfers, even if the certificate used for validation expires or is revoked, +the local certificate bundle is changed in a way that would have caused that +certificate to fail validation, the server changes its certificate to one +that would have failed validation, or even if a completely different server is +brought up under the same hostname. This could continue for many hours (or +even years) after such a change occurs, which may not be desired behavior for +some applications. + +Remedies: + +Use the CURLOPT_MAXLIFETIME_CONN(3) option to limit the amount of time that +connections are used after they have been successfully validated. Further +transfers require a new connection with validation performed again. + # Redirects The CURLOPT_FOLLOWLOCATION(3) option automatically follows HTTP From cc50f05370981e4933504e8aaec6b15880ff847f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 11 Sep 2025 19:50:40 +0200 Subject: [PATCH 014/208] GHA/codeql: re-enable for C with the default query pack Earlier we used `security-extended` and tried `security-and-quality`. Try the default to see how it works. CodeQL no longer uses the project's Actions cache, also fixing the previously seen repeat cache entry issue. - switch to `manual` build. It's 3x faster than the default `autobuild`. - enable more dependencies to increase coverage. - docs/tests/CI.md: re-add CodeQL. Ref: https://docs.github.com/en/code-security/code-scanning/managing-your-code-scanning-configuration/codeql-query-suites Ref: https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages Ref: #16263 Ref: 173805b2e76960de5c51fd5fe64286d8ac81f1ff #15798 Closes #18528 --- .github/scripts/spellcheck.words | 1 + .github/workflows/codeql.yml | 34 ++++++++++++++++++++++++++++++++ docs/tests/CI.md | 4 ++++ 3 files changed, 39 insertions(+) diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index 13b7b2f3674d..46c05b741bcf 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -122,6 +122,7 @@ CMakeLists CNA CNAME CNAMEs +CodeQL CODESET codeset CodeSonar diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9863f7624d2c..0952eb3d1d22 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -59,3 +59,37 @@ jobs: - name: 'perform analysis' uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 + + c: + name: 'C' + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: 'install prereqs' + timeout-minutes: 5 + run: | + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get -o Dpkg::Use-Pty=0 update + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + persist-credentials: false + + - name: 'initialize' + uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3 + with: + languages: cpp + build-mode: manual + + - name: 'build' + timeout-minutes: 10 + run: | + cmake -B . -G Ninja + cmake --build . --verbose + src/curl -V + + - name: 'perform analysis' + uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 diff --git a/docs/tests/CI.md b/docs/tests/CI.md index d101e3563c71..40c87ba14e16 100644 --- a/docs/tests/CI.md +++ b/docs/tests/CI.md @@ -31,8 +31,10 @@ Consider the following table while looking at pull request failures: | CI platform as shown in PR | State | What to look at next | | ----------------------------------- | ------ | -------------------------- | + | CI / CodeQL | stable | quality check results | | CI / fuzzing | stable | fuzzing results | | CI / macos ... | stable | all errors and failures | + | Code scanning results / CodeQL | stable | quality check results | | FreeBSD FreeBSD: ... | stable | all errors and failures | | LGTM analysis: Python | stable | new findings | | LGTM analysis: C/C++ | stable | new findings | @@ -40,6 +42,7 @@ Consider the following table while looking at pull request failures: | AppVeyor | flaky | all errors and failures | | curl.curl (linux ...) | stable | all errors and failures | | curl.curl (windows ...) | flaky | repetitive errors/failures | + | CodeQL | stable | new findings | Sometimes the tests fail due to a dependency service temporarily being offline or otherwise unavailable, for example package downloads. In this case you can @@ -58,6 +61,7 @@ GitHub Actions runs the following tests: - macOS tests with a variety of different compilation options - Fuzz tests ([see the curl-fuzzer repo for more info](https://github.com/curl/curl-fuzzer)). +- CodeQL static analysis These are each configured in different files in `.github/workflows`. From 83c457f9f3244544c4f0f13051cd00e637c6de88 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 13 Sep 2025 17:20:22 +0200 Subject: [PATCH 015/208] GHA: document permissions as required by zizmor 1.13.0 Ref: https://github.com/zizmorcore/zizmor/pull/1131 Ref: https://docs.zizmor.sh/audits/#undocumented-permissions Bug: https://github.com/curl/curl/pull/18539#issuecomment-3288151910 Closes #18541 --- .github/workflows/appveyor-status.yml | 2 +- .github/workflows/codeql.yml | 4 ++-- .github/workflows/hacktoberfest-accepted.yml | 5 ++--- .github/workflows/label.yml | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/appveyor-status.yml b/.github/workflows/appveyor-status.yml index cb7f96b1907e..5269f3ca65b9 100644 --- a/.github/workflows/appveyor-status.yml +++ b/.github/workflows/appveyor-status.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.sender.login == 'appveyor[bot]' }} permissions: - statuses: write + statuses: write # To update build statuses steps: - name: 'Create individual AppVeyor build statuses' if: ${{ github.event.sha && github.event.target_url }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0952eb3d1d22..ff2e91c32a42 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -45,7 +45,7 @@ jobs: name: 'GHA and Python' runs-on: ubuntu-latest permissions: - security-events: write + security-events: write # To create/update security events steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: @@ -64,7 +64,7 @@ jobs: name: 'C' runs-on: ubuntu-latest permissions: - security-events: write + security-events: write # To create/update security events steps: - name: 'install prereqs' timeout-minutes: 5 diff --git a/.github/workflows/hacktoberfest-accepted.yml b/.github/workflows/hacktoberfest-accepted.yml index 916b354481ca..3aacbd6d0c5c 100644 --- a/.github/workflows/hacktoberfest-accepted.yml +++ b/.github/workflows/hacktoberfest-accepted.yml @@ -23,9 +23,8 @@ jobs: name: 'Add hacktoberfest-accepted label' runs-on: ubuntu-latest permissions: - # requires issues AND pull-requests write permissions to edit labels on PRs! - issues: write - pull-requests: write + issues: write # To edit labels on PRs + pull-requests: write # To edit labels on PRs steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index b84702a8a1b9..cfafde14f7fe 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -19,8 +19,8 @@ jobs: name: 'Labeler' runs-on: ubuntu-latest permissions: - contents: read - pull-requests: write + contents: read # To comply with https://github.com/actions/labeler documentation + pull-requests: write # To edit labels on PRs steps: - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6 From eb319bf6ea4811e9ea19308d7f3d45f340cc7766 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 10:33:38 +0200 Subject: [PATCH 016/208] RELEASE-NOTES: synced --- RELEASE-NOTES | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 04e1ad4779d9..58d8fe6d02d4 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,7 +4,7 @@ curl and libcurl 8.16.1 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3499 + Contributors: 3500 This release includes the following changes: @@ -12,8 +12,17 @@ This release includes the following changes: This release includes the following bugfixes: o curl_easy_getinfo: error code on NULL arg [2] + o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] + o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] + o CURLOPT_MAXLIFETIME_CONN: make default 24 hours [10] + o docs/libcurl: remove ancient version references [7] o easy_getinfo: check magic, Curl_close safety [3] + o libcurl-security.md: mention long-running connections [6] + o ngtcp2: check error code on connect failure [13] + o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o ssl-sessions.md: mark option experimental [12] + o urldata: FILE is not a list-only protocol [9] This release includes the following known bugs: @@ -37,11 +46,22 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Daniel Stenberg, Ethan Everett, Stefan Eissing - (3 contributors) + Andrew Kirillov, Dan Fandrich, Daniel Stenberg, Emilio Pozuelo Monfort, + Ethan Everett, fds242 on github, renovate[bot], Stefan Eissing, + Viktor Szakats + (9 contributors) References to bug reports and discussions on issues: [2] = https://curl.se/bug/?i=18512 [3] = https://curl.se/bug/?i=18511 [4] = https://curl.se/bug/?i=18505 + [6] = https://curl.se/bug/?i=18533 + [7] = https://curl.se/bug/?i=18530 + [8] = https://curl.se/bug/?i=18531 + [9] = https://curl.se/bug/?i=18525 + [10] = https://curl.se/bug/?i=18527 + [12] = https://curl.se/bug/?i=18523 + [13] = https://curl.se/bug/?i=18521 + [14] = https://curl.se/bug/?i=18518 + [19] = https://curl.se/bug/?i=18510 From d52af3c692943377a28a5bfa270248d009a9eed1 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 11:55:50 +0200 Subject: [PATCH 017/208] appveyor: bump to OpenSSL 3.5, adjust to dropped 1.1.1 on VS2019 - bump OpenSSL 3.4 to 3.5 on VS2022 runners. - bump OpenSSL 1.1.1 to 3.0 on VS2019 runners. 1.1.1 is documented to be present, but missing. Fixes: ``` + cmake -G 'Visual Studio 16 2019' -A x64 [...] -DOPENSSL_ROOT_DIR=C:/OpenSSL-v111-Win64 [...] CMake Error at C:/Program Files/CMake/share/cmake-4.1/Modules/FindPackageHandleStandardArgs.cmake:227 (message): Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_CRYPTO_LIBRARY OPENSSL_INCLUDE_DIR) Call Stack (most recent call first): CMakeLists.txt:757 (find_package) ``` Ref: https://ci.appveyor.com/project/curlorg/curl/builds/52740431/job/tq6h4xhqpa3vgq47?fullLog=true Ref: https://www.appveyor.com/docs/windows-images-software/ Ref: https://github.com/appveyor/website/commit/9a739f7bce4a624b28ff382d58a9ebc507ab0f78 Closes #18543 --- appveyor.sh | 4 +++- appveyor.yml | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/appveyor.sh b/appveyor.sh index 1e4c16362fa5..dea58c954542 100644 --- a/appveyor.sh +++ b/appveyor.sh @@ -34,7 +34,9 @@ case "${TARGET:-}" in esac if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2022' ]; then - openssl_root_win="C:/OpenSSL-v34${openssl_suffix}" + openssl_root_win="C:/OpenSSL-v35${openssl_suffix}" +elif [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2019' ]; then + openssl_root_win="C:/OpenSSL-v30${openssl_suffix}" else openssl_root_win="C:/OpenSSL-v111${openssl_suffix}" fi diff --git a/appveyor.yml b/appveyor.yml index effd8589d17e..42b580883c3b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -46,7 +46,7 @@ environment: # generated CMake-based Visual Studio builds - - job_name: 'CMake, VS2022, Release, x64, OpenSSL 3.4, Shared, Build-tests' + - job_name: 'CMake, VS2022, Release, x64, OpenSSL 3.5, Shared, Build-tests' APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022' PRJ_GEN: 'Visual Studio 17 2022' TARGET: '-A x64' @@ -101,7 +101,7 @@ environment: OPENSSL: 'ON' SHARED: 'ON' TFLAGS: 'skipall' - - job_name: 'CMake, VS2019, Debug, x64, OpenSSL 1.1.1 + Schannel, Shared, Build-tests' + - job_name: 'CMake, VS2019, Debug, x64, OpenSSL 3.0 + Schannel, Shared, Build-tests' APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2019' PRJ_GEN: 'Visual Studio 16 2019' TARGET: '-A x64' @@ -109,7 +109,7 @@ environment: OPENSSL: 'ON' SCHANNEL: 'ON' SHARED: 'ON' - - job_name: 'CMake, VS2022, Debug, x64, OpenSSL 3.4 + Schannel, Static, Unicode, Build-tests & examples, clang-cl' + - job_name: 'CMake, VS2022, Debug, x64, OpenSSL 3.5 + Schannel, Static, Unicode, Build-tests & examples, clang-cl' APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022' PRJ_GEN: 'Visual Studio 17 2022' TARGET: '-A x64' From 6bb53f29efb7c379f3d22f9e6298e001bf1ff7da Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 11:44:35 +0200 Subject: [PATCH 018/208] TODO: remove already implemented or bad items - remove "connect to multiple IPs in parallel" - remove "CURLOPT_RESOLVE for any port number", It can already be accomplished with CURLOPT_CONNECT_TO - remove "dynamically load modules", we don't believe in this - remove "netrc caching and sharing", we already cache it - remove "Offer API to flush the connection pool", this is effectively what CURLMOPT_NETWORK_CHANGED now allows - remove "WebSocket read callback", introduced in 8.16.0 Closes #18542 --- docs/TODO | 53 ----------------------------------------------------- 1 file changed, 53 deletions(-) diff --git a/docs/TODO b/docs/TODO index 1e22814f385f..6075577f318f 100644 --- a/docs/TODO +++ b/docs/TODO @@ -23,24 +23,18 @@ 1.4 alt-svc sharing 1.5 get rid of PATH_MAX 1.6 thread-safe sharing - 1.8 CURLOPT_RESOLVE for any port number 1.10 auto-detect proxy - 1.11 minimize dependencies with dynamically loaded modules 1.12 updated DNS server while running 1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION - 1.14 connect to multiple IPs in parallel 1.15 Monitor connections in the connection pool 1.16 Try to URL encode given URL 1.17 Add support for IRIs 1.18 try next proxy if one does not work 1.19 provide timing info for each redirect 1.20 SRV and URI DNS records - 1.21 netrc caching and sharing 1.22 CURLINFO_PAUSE_STATE - 1.23 Offer API to flush the connection pool 1.25 Expose tried IP addresses that failed 1.28 FD_CLOEXEC - 1.29 WebSocket read callback 1.30 config file parsing 1.31 erase secrets from heap/stack after use 1.32 add asynch getaddrinfo support @@ -252,14 +246,6 @@ share between multiple concurrent threads. Fixing this would enable more users to share data in more powerful ways. -1.8 CURLOPT_RESOLVE for any port number - - This option allows applications to set a replacement IP address for a given - host + port pair. Consider making support for providing a replacement address - for the hostname on all port numbers. - - See https://github.com/curl/curl/issues/1264 - 1.10 auto-detect proxy libcurl could be made to detect the system proxy setup automatically and use @@ -272,14 +258,6 @@ libdetectproxy is a (C++) library for detecting the proxy on Windows https://github.com/paulharris/libdetectproxy -1.11 minimize dependencies with dynamically loaded modules - - We can create a system with loadable modules/plug-ins, where these modules - would be the ones that link to 3rd party libs. That would allow us to avoid - having to load ALL dependencies since only the necessary ones for this - app/invoke/used protocols would be necessary to load. See - https://github.com/curl/curl/issues/349 - 1.12 updated DNS server while running If /etc/resolv.conf gets updated while a program using libcurl is running, it @@ -301,17 +279,6 @@ See https://github.com/curl/curl/issues/2734 -1.14 connect to multiple IPs in parallel - - curl currently implements the happy eyeball algorithm for connecting to the - IPv4 and IPv6 alternatives for a host in parallel, sticking with the - connection that "wins". We could implement a similar algorithm per individual - IP family as well when there are multiple available addresses: start with the - first address, then start a second attempt N milliseconds after and then a - third another N milliseconds later. That way there would be less waiting when - the first IP has problems. It also improves the connection timeout value - handling for multiple address situations. - 1.15 Monitor connections in the connection pool libcurl's connection cache or pool holds a number of open connections for the @@ -368,24 +335,11 @@ Offer support for resolving SRV and URI DNS records for libcurl to know which server to connect to for various protocols (including HTTP). -1.21 netrc caching and sharing - - The netrc file is read and parsed each time a connection is setup, which - means that if a transfer needs multiple connections for authentication or - redirects, the file might be reread (and parsed) multiple times. This makes - it impossible to provide the file as a pipe. - 1.22 CURLINFO_PAUSE_STATE Return information about the transfer's current pause state, in both directions. https://github.com/curl/curl/issues/2588 -1.23 Offer API to flush the connection pool - - Sometimes applications want to flush all the existing connections kept alive. - An API could allow a forced flush or just a forced loop that would properly - close all connections that have been closed by the server already. - 1.25 Expose tried IP addresses that failed When libcurl fails to connect to a host, it could offer the application the @@ -403,13 +357,6 @@ https://github.com/curl/curl/issues/2252 -1.29 WebSocket read callback - - Call the read callback once the connection is established to allow sending - the first message in the connection. - - https://github.com/curl/curl/issues/11402 - 1.30 config file parsing Consider providing an API, possibly in a separate companion library, for From 07837204cdd18f470594fc0caea7fbb50de286df Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 12:38:29 +0200 Subject: [PATCH 019/208] GHA/distcheck: disable `man-db/auto-update` Make sure to not rebuild man pages after purging system curl, to make the job faster and avoid timeouts: ``` Sun, 14 Sep 2025 10:16:28 GMT Removing curl (8.5.0-2ubuntu10.6) ... Sun, 14 Sep 2025 10:16:28 GMT Processing triggers for man-db (2.12.0-4build2) ... Sun, 14 Sep 2025 10:21:22 GMT (Reading database ... 218629 files and directories currently installed.) ``` Ref: https://github.com/curl/curl/actions/runs/17709785947/job/50326910814?pr=18535#step:3:19 Closes #18544 --- .github/workflows/distcheck.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index bf6c69bfcfd0..9d893481bcfd 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -33,7 +33,9 @@ jobs: persist-credentials: false - name: 'remove preinstalled curl libcurl4{-doc}' - run: sudo apt-get -o Dpkg::Use-Pty=0 purge curl libcurl4 libcurl4-doc + run: | + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get -o Dpkg::Use-Pty=0 purge curl libcurl4 libcurl4-doc - name: 'autoreconf' run: autoreconf -fi @@ -233,7 +235,9 @@ jobs: persist-credentials: false - name: 'remove preinstalled curl libcurl4{-doc}' - run: sudo apt-get -o Dpkg::Use-Pty=0 purge curl libcurl4 libcurl4-doc + run: | + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get -o Dpkg::Use-Pty=0 purge curl libcurl4 libcurl4-doc - name: 'generate release tarballs' run: ./scripts/dmaketgz 9.10.11 From c1be5459d9619163e26d5732ee732b417d697e9d Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 14:14:34 +0200 Subject: [PATCH 020/208] GHA/codeql: analyse Windows Schannel WinIDN build Follow-up to cc50f05370981e4933504e8aaec6b15880ff847f #18528 Closes #18545 --- .github/workflows/codeql.yml | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ff2e91c32a42..e33540959543 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -61,12 +61,23 @@ jobs: uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 c: - name: 'C' - runs-on: ubuntu-latest + name: 'C (${{ matrix.build.name }})' + runs-on: ${{ matrix.build.image }} permissions: security-events: write # To create/update security events + strategy: + fail-fast: false + matrix: + build: + - name: 'Linux' + image: ubuntu-latest + - name: 'Windows' + image: windows-2022 + env: + MATRIX_IMAGE: '${{ matrix.build.image }}' steps: - name: 'install prereqs' + if: ${{ contains(matrix.build.image, 'ubuntu') }} timeout-minutes: 5 run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list @@ -86,10 +97,19 @@ jobs: - name: 'build' timeout-minutes: 10 + shell: bash run: | - cmake -B . -G Ninja - cmake --build . --verbose - src/curl -V + if [[ "${MATRIX_IMAGE}" = *'windows'* ]]; then + cmake -B . -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_VS_GLOBALS=TrackFileAccess=false \ + -DCURL_USE_SCHANNEL=ON -DCURL_USE_LIBPSL=OFF -DUSE_WIN32_IDN=ON + cmake --build . --verbose + src/Debug/curl.exe --disable --version + else + cmake -B . -G Ninja + cmake --build . --verbose + src/curl --disable --version + fi - name: 'perform analysis' uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 From 64347831684d3a7905fd7ef95bfab59df44b6aea Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 14:29:13 +0200 Subject: [PATCH 021/208] tool_getparam: split opt_filestring into two sep functions One for file name arguments and one for "strings". Closes #18546 --- src/tool_getparam.c | 232 +++++++++++++++++++++++--------------------- 1 file changed, 121 insertions(+), 111 deletions(-) diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 6be57dbd5c31..f2ad6daf2ef9 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -2163,11 +2163,123 @@ static ParameterError opt_bool(struct OperationConfig *config, return PARAM_OK; } +/* opt_file handles file options */ +static ParameterError opt_file(struct OperationConfig *config, + const struct LongShort *a, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + if((nextarg[0] == '-') && nextarg[1]) { + /* if the filename looks like a command line option */ + warnf("The filename argument '%s' looks like a flag.", nextarg); + } + switch(a->cmd) { + case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */ + config->abstract_unix_socket = TRUE; + err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); + break; + case C_CACERT: /* --cacert */ + err = getstr(&config->cacert, nextarg, DENY_BLANK); + break; + case C_CAPATH: /* --capath */ + err = getstr(&config->capath, nextarg, DENY_BLANK); + break; + case C_CERT: /* --cert */ + GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); + break; + case C_CONFIG: /* --config */ + if(parseconfig(nextarg)) { + errorf("cannot read config from '%s'", nextarg); + err = PARAM_READ_ERROR; + } + break; + case C_CRLFILE: /* --crlfile */ + err = getstr(&config->crlfile, nextarg, DENY_BLANK); + break; + case C_DUMP_HEADER: /* --dump-header */ + err = getstr(&config->headerfile, nextarg, DENY_BLANK); + break; + case C_ETAG_SAVE: /* --etag-save */ + if(config->num_urls > 1) { + errorf("The etag options only work on a single URL"); + err = PARAM_BAD_USE; + } + else + err = getstr(&config->etag_save_file, nextarg, DENY_BLANK); + break; + case C_ETAG_COMPARE: /* --etag-compare */ + if(config->num_urls > 1) { + errorf("The etag options only work on a single URL"); + err = PARAM_BAD_USE; + } + else + err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK); + break; + case C_KEY: /* --key */ + err = getstr(&config->key, nextarg, DENY_BLANK); + break; + case C_NETRC_FILE: /* --netrc-file */ + err = getstr(&config->netrc_file, nextarg, DENY_BLANK); + break; + case C_OUTPUT: /* --output */ + err = parse_output(config, nextarg); + break; + case C_PROXY_CACERT: /* --proxy-cacert */ + err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK); + break; + case C_PROXY_CAPATH: /* --proxy-capath */ + err = getstr(&config->proxy_capath, nextarg, DENY_BLANK); + break; + case C_PROXY_CERT: /* --proxy-cert */ + GetFileAndPassword(nextarg, &config->proxy_cert, + &config->proxy_key_passwd); + break; + case C_PROXY_CRLFILE: /* --proxy-crlfile */ + err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK); + break; + case C_PROXY_KEY: /* --proxy-key */ + err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK); + break; + case C_SSL_SESSIONS: /* --ssl-sessions */ + if(feature_ssls_export) + err = getstr(&global->ssl_sessions, nextarg, DENY_BLANK); + else + err = PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case C_STDERR: /* --stderr */ + tool_set_stderr_file(nextarg); + break; + case C_TRACE: /* --trace */ + err = getstr(&global->trace_dump, nextarg, DENY_BLANK); + if(!err) { + if(global->tracetype && (global->tracetype != TRACE_BIN)) + warnf("--trace overrides an earlier trace/verbose option"); + global->tracetype = TRACE_BIN; + } + break; + case C_TRACE_ASCII: /* --trace-ascii */ + err = getstr(&global->trace_dump, nextarg, DENY_BLANK); + if(!err) { + if(global->tracetype && (global->tracetype != TRACE_ASCII)) + warnf("--trace-ascii overrides an earlier trace/verbose option"); + global->tracetype = TRACE_ASCII; + } + break; + case C_UNIX_SOCKET: /* --unix-socket */ + config->abstract_unix_socket = FALSE; + err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); + break; + case C_UPLOAD_FILE: /* --upload-file */ + err = parse_upload_file(config, nextarg); + break; + } + return err; +} -/* opt_filestring handles string and file options */ -static ParameterError opt_filestring(struct OperationConfig *config, - const struct LongShort *a, - const char *nextarg) +/* opt_string handles string options */ +static ParameterError opt_string(struct OperationConfig *config, + const struct LongShort *a, + const char *nextarg) { ParameterError err = PARAM_OK; curl_off_t value; @@ -2227,22 +2339,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, /* IP addrs of DNS servers */ err = getstr(&config->dns_servers, nextarg, DENY_BLANK); break; - case C_TRACE: /* --trace */ - err = getstr(&global->trace_dump, nextarg, DENY_BLANK); - if(!err) { - if(global->tracetype && (global->tracetype != TRACE_BIN)) - warnf("--trace overrides an earlier trace/verbose option"); - global->tracetype = TRACE_BIN; - } - break; - case C_TRACE_ASCII: /* --trace-ascii */ - err = getstr(&global->trace_dump, nextarg, DENY_BLANK); - if(!err) { - if(global->tracetype && (global->tracetype != TRACE_ASCII)) - warnf("--trace-ascii overrides an earlier trace/verbose option"); - global->tracetype = TRACE_ASCII; - } - break; case C_LIMIT_RATE: /* --limit-rate */ err = GetSizeParameter(nextarg, "rate", &value); if(!err) { @@ -2272,9 +2368,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, config->authtype |= CURLAUTH_AWS_SIGV4; err = getstr(&config->aws_sigv4, nextarg, ALLOW_BLANK); break; - case C_STDERR: /* --stderr */ - tool_set_stderr_file(nextarg); - break; case C_INTERFACE: /* --interface */ /* interface */ err = getstr(&config->iface, nextarg, DENY_BLANK); @@ -2406,10 +2499,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_SASL_AUTHZID: /* --sasl-authzid */ err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK); break; - case C_UNIX_SOCKET: /* --unix-socket */ - config->abstract_unix_socket = FALSE; - err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); - break; case C_PROXY_SERVICE_NAME: /* --proxy-service-name */ err = getstr(&config->proxy_service_name, nextarg, DENY_BLANK); break; @@ -2427,10 +2516,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_CONNECT_TO: /* --connect-to */ err = add2list(&config->connect_to, nextarg); break; - case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */ - config->abstract_unix_socket = TRUE; - err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); - break; case C_TLS_MAX: /* --tls-max */ err = str2tls_max(&config->ssl_version_max, nextarg); if(!err && (config->ssl_version_max < config->ssl_version)) { @@ -2499,9 +2584,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_URL_QUERY: /* --url-query */ err = url_query(nextarg, config); break; - case C_DUMP_HEADER: /* --dump-header */ - err = getstr(&config->headerfile, nextarg, DENY_BLANK); - break; case C_REFERER: { /* --referer */ size_t len = strlen(nextarg); /* does it end with ;auto ? */ @@ -2520,18 +2602,9 @@ static ParameterError opt_filestring(struct OperationConfig *config, tool_safefree(config->referer); } break; - case C_CERT: /* --cert */ - GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); - break; - case C_CACERT: /* --cacert */ - err = getstr(&config->cacert, nextarg, DENY_BLANK); - break; case C_CERT_TYPE: /* --cert-type */ err = getstr(&config->cert_type, nextarg, DENY_BLANK); break; - case C_KEY: /* --key */ - err = getstr(&config->key, nextarg, DENY_BLANK); - break; case C_KEY_TYPE: /* --key-type */ err = getstr(&config->key_type, nextarg, DENY_BLANK); break; @@ -2548,9 +2621,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_ECH: /* --ech */ err = parse_ech(config, nextarg); break; - case C_CAPATH: /* --capath */ - err = getstr(&config->capath, nextarg, DENY_BLANK); - break; case C_PUBKEY: /* --pubkey */ err = getstr(&config->pubkey, nextarg, DENY_BLANK); break; @@ -2567,9 +2637,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, else err = getstr(&config->hostpubsha256, nextarg, DENY_BLANK); break; - case C_CRLFILE: /* --crlfile */ - err = getstr(&config->crlfile, nextarg, DENY_BLANK); - break; case C_TLSUSER: /* --tlsuser */ if(!feature_tls_srp) err = PARAM_LIBCURL_DOESNT_SUPPORT; @@ -2597,12 +2664,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_PROXY_PINNEDPUBKEY: /* --proxy-pinnedpubkey */ err = getstr(&config->proxy_pinnedpubkey, nextarg, DENY_BLANK); break; - case C_SSL_SESSIONS: /* --ssl-sessions */ - if(feature_ssls_export) - err = getstr(&global->ssl_sessions, nextarg, DENY_BLANK); - else - err = PARAM_LIBCURL_DOESNT_SUPPORT; - break; case C_PROXY_TLSUSER: /* --proxy-tlsuser */ if(!feature_tls_srp) err = PARAM_LIBCURL_DOESNT_SUPPORT; @@ -2625,16 +2686,9 @@ static ParameterError opt_filestring(struct OperationConfig *config, err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ } break; - case C_PROXY_CERT: /* --proxy-cert */ - GetFileAndPassword(nextarg, &config->proxy_cert, - &config->proxy_key_passwd); - break; case C_PROXY_CERT_TYPE: /* --proxy-cert-type */ err = getstr(&config->proxy_cert_type, nextarg, DENY_BLANK); break; - case C_PROXY_KEY: /* --proxy-key */ - err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK); - break; case C_PROXY_KEY_TYPE: /* --proxy-key-type */ err = getstr(&config->proxy_key_type, nextarg, DENY_BLANK); break; @@ -2644,34 +2698,9 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_PROXY_CIPHERS: /* --proxy-ciphers */ err = getstr(&config->proxy_cipher_list, nextarg, DENY_BLANK); break; - case C_PROXY_CRLFILE: /* --proxy-crlfile */ - err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK); - break; case C_LOGIN_OPTIONS: /* --login-options */ err = getstr(&config->login_options, nextarg, ALLOW_BLANK); break; - case C_PROXY_CACERT: /* --proxy-cacert */ - err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK); - break; - case C_PROXY_CAPATH: /* --proxy-capath */ - err = getstr(&config->proxy_capath, nextarg, DENY_BLANK); - break; - case C_ETAG_SAVE: /* --etag-save */ - if(config->num_urls > 1) { - errorf("The etag options only work on a single URL"); - err = PARAM_BAD_USE; - } - else - err = getstr(&config->etag_save_file, nextarg, DENY_BLANK); - break; - case C_ETAG_COMPARE: /* --etag-compare */ - if(config->num_urls > 1) { - errorf("The etag options only work on a single URL"); - err = PARAM_BAD_USE; - } - else - err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK); - break; case C_CURVES: /* --curves */ err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK); break; @@ -2695,25 +2724,13 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_PROXY_HEADER: /* --proxy-header */ err = parse_header(config, (cmdline_t)a->cmd, nextarg); break; - case C_CONFIG: /* --config */ - if(parseconfig(nextarg)) { - errorf("cannot read config from '%s'", nextarg); - err = PARAM_READ_ERROR; - } - break; case C_MAX_TIME: /* --max-time */ /* specified max time */ err = secs2ms(&config->timeout_ms, nextarg); break; - case C_NETRC_FILE: /* --netrc-file */ - err = getstr(&config->netrc_file, nextarg, DENY_BLANK); - break; case C_OUTPUT_DIR: /* --output-dir */ err = getstr(&config->output_dir, nextarg, DENY_BLANK); break; - case C_OUTPUT: /* --output */ - err = parse_output(config, nextarg); - break; case C_FTP_PORT: /* --ftp-port */ /* This makes the FTP sessions use PORT instead of PASV */ /* use or <192.168.10.10> style addresses. Anything except @@ -2736,9 +2753,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, /* Telnet options */ err = add2list(&config->telnet_options, nextarg); break; - case C_UPLOAD_FILE: /* --upload-file */ - err = parse_upload_file(config, nextarg); - break; case C_USER: /* --user */ /* user:password */ err = getstr(&config->userpwd, nextarg, ALLOW_BLANK); @@ -2947,18 +2961,14 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; } - if((ARGTYPE(a->desc) == ARG_FILE) && - (nextarg[0] == '-') && nextarg[1]) { - /* if the filename looks like a command line option */ - warnf("The filename argument '%s' looks like a flag.", - nextarg); - } - else if(has_leading_unicode((const unsigned char *)nextarg)) { + if(has_leading_unicode((const unsigned char *)nextarg)) { warnf("The argument '%s' starts with a Unicode character. " "Maybe ASCII was intended?", nextarg); } - /* ARG_FILE | ARG_STRG */ - err = opt_filestring(config, a, nextarg); + if(ARGTYPE(a->desc) == ARG_FILE) + err = opt_file(config, a, nextarg); + else /* if(ARGTYPE(a->desc) == ARG_STRG) */ + err = opt_string(config, a, nextarg); if(a->desc & ARG_CLEAR) cleanarg(CURL_UNCONST(nextarg)); } From 58bdfb4e1d643c4ba7bd8db855e3218ac7757e7c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 23:30:13 +0200 Subject: [PATCH 022/208] CURLOPT_SSL_VERIFYHOST.md: add see-also to two other VERIFYHOST options Closes #18548 --- docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md b/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md index 9db4d4dfd3af..b87e0a739dc4 100644 --- a/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md +++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md @@ -8,6 +8,8 @@ See-also: - CURLOPT_CAINFO (3) - CURLOPT_PINNEDPUBLICKEY (3) - CURLOPT_SSL_VERIFYPEER (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_DOH_SSL_VERIFYHOST (3) Protocol: - TLS TLS-backend: From f7cac7cc07a45481b246c875e8113d741ba2a6e1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 23:28:03 +0200 Subject: [PATCH 023/208] setopt: accept *_SSL_VERIFYHOST set to 2L ... without outputing a verbose message about it. In the early days we had 2L and 1L have different functionalities. Reported-by: Jicea Bug: https://curl.se/mail/lib-2025-09/0031.html Closes #18547 --- lib/setopt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/setopt.c b/lib/setopt.c index 5adfe4dbebb0..6f98e7dce4e3 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -443,6 +443,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, long arg, bool *set) { bool enabled = !!arg; + int ok = 1; struct UserDefined *s = &data->set; switch(option) { case CURLOPT_FORBID_REUSE: @@ -619,7 +620,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, * Enable verification of the hostname in the peer certificate for proxy */ s->proxy_ssl.primary.verifyhost = enabled; - + ok = 2; /* Update the current connection proxy_ssl_config. */ Curl_ssl_conn_config_update(data, TRUE); break; @@ -723,6 +724,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, * Enable verification of the hostname in the peer certificate for DoH */ s->doh_verifyhost = enabled; + ok = 2; break; case CURLOPT_DOH_SSL_VERIFYSTATUS: /* @@ -732,6 +734,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, return CURLE_NOT_BUILT_IN; s->doh_verifystatus = enabled; + ok = 2; break; #endif /* ! CURL_DISABLE_DOH */ case CURLOPT_SSL_VERIFYHOST: @@ -743,6 +746,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, this argument took a boolean when it was not and misused it. Treat 1 and 2 the same */ s->ssl.primary.verifyhost = enabled; + ok = 2; /* Update the current connection ssl_config. */ Curl_ssl_conn_config_update(data, FALSE); @@ -844,7 +848,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, default: return CURLE_OK; } - if((arg > 1) || (arg < 0)) + if((arg > ok) || (arg < 0)) /* reserve other values for future use */ infof(data, "boolean setopt(%d) got unsupported argument %ld," " treated as %d", option, arg, enabled); From de3fc1d7adb78c078e4cc7ccc48e550758094ad3 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Sat, 13 Sep 2025 15:25:53 +0200 Subject: [PATCH 024/208] asyn-thrdd: drop pthread_cancel Remove use of pthread_cancel in asnyc threaded resolving. While there are system where this works, others might leak to resource leakage (memory, files, etc.). The popular nsswitch is one example where resolve code can be dragged in that is not prepared. The overall promise and mechanism of pthread_cancel() is just too brittle and the historcal design of getaddrinfo() continues to haunt us. Fixes #18532 Reported-by: Javier Blazquez Closes #18540 --- docs/libcurl/libcurl-env-dbg.md | 5 --- lib/asyn-thrdd.c | 67 +++++++-------------------------- lib/curl_threads.c | 36 ------------------ lib/curl_threads.h | 16 -------- lib/hostip.c | 19 ---------- lib/hostip.h | 4 -- tests/data/Makefile.am | 2 +- tests/data/test795 | 36 ------------------ tests/libtest/Makefile.am | 2 +- tests/libtest/test795.pl | 46 ---------------------- 10 files changed, 16 insertions(+), 217 deletions(-) delete mode 100644 tests/data/test795 delete mode 100755 tests/libtest/test795.pl diff --git a/docs/libcurl/libcurl-env-dbg.md b/docs/libcurl/libcurl-env-dbg.md index d142e94410f4..3fcc1935d5ee 100644 --- a/docs/libcurl/libcurl-env-dbg.md +++ b/docs/libcurl/libcurl-env-dbg.md @@ -83,11 +83,6 @@ When built with c-ares for name resolving, setting this environment variable to `[IP:port]` makes libcurl use that DNS server instead of the system default. This is used by the curl test suite. -## `CURL_DNS_DELAY_MS` - -Delay the DNS resolve by this many milliseconds. This is used in the test -suite to check proper handling of CURLOPT_CONNECTTIMEOUT(3). - ## `CURL_FTP_PWD_STOP` When set, the first transfer - when using ftp: - returns before sending diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index ca6830a0bee1..2edef32f7b38 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -199,14 +199,6 @@ addr_ctx_create(struct Curl_easy *data, return NULL; } -static void async_thrd_cleanup(void *arg) -{ - struct async_thrdd_addr_ctx *addr_ctx = arg; - - Curl_thread_disable_cancel(); - addr_ctx_unlink(&addr_ctx, NULL); -} - #ifdef HAVE_GETADDRINFO /* @@ -220,15 +212,6 @@ static CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg) struct async_thrdd_addr_ctx *addr_ctx = arg; bool do_abort; -/* clang complains about empty statements and the pthread_cleanup* macros - * are pretty ill defined. */ -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra-semi-stmt" -#endif - - Curl_thread_push_cleanup(async_thrd_cleanup, addr_ctx); - Curl_mutex_acquire(&addr_ctx->mutx); do_abort = addr_ctx->do_abort; Curl_mutex_release(&addr_ctx->mutx); @@ -237,9 +220,6 @@ static CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg) char service[12]; int rc; -#ifdef DEBUGBUILD - Curl_resolve_test_delay(); -#endif msnprintf(service, sizeof(service), "%d", addr_ctx->port); rc = Curl_getaddrinfo_ex(addr_ctx->hostname, service, @@ -274,11 +254,6 @@ static CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg) } - Curl_thread_pop_cleanup(); -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - addr_ctx_unlink(&addr_ctx, NULL); return 0; } @@ -293,24 +268,11 @@ static CURL_THREAD_RETURN_T CURL_STDCALL gethostbyname_thread(void *arg) struct async_thrdd_addr_ctx *addr_ctx = arg; bool do_abort; -/* clang complains about empty statements and the pthread_cleanup* macros - * are pretty ill defined. */ -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra-semi-stmt" -#endif - - Curl_thread_push_cleanup(async_thrd_cleanup, addr_ctx); - Curl_mutex_acquire(&addr_ctx->mutx); do_abort = addr_ctx->do_abort; Curl_mutex_release(&addr_ctx->mutx); if(!do_abort) { -#ifdef DEBUGBUILD - Curl_resolve_test_delay(); -#endif - addr_ctx->res = Curl_ipv4_resolve_r(addr_ctx->hostname, addr_ctx->port); if(!addr_ctx->res) { addr_ctx->sock_error = SOCKERRNO; @@ -337,12 +299,7 @@ static CURL_THREAD_RETURN_T CURL_STDCALL gethostbyname_thread(void *arg) #endif } - Curl_thread_pop_cleanup(); -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - - async_thrd_cleanup(addr_ctx); + addr_ctx_unlink(&addr_ctx, NULL); return 0; } @@ -381,12 +338,12 @@ static void async_thrdd_destroy(struct Curl_easy *data) CURL_TRC_DNS(data, "async_thrdd_destroy, thread joined"); } else { - /* thread is still running. Detach the thread while mutexed, it will - * trigger the cleanup when it releases its reference. */ + /* thread is still running. Detach it. */ Curl_thread_destroy(&addr->thread_hnd); CURL_TRC_DNS(data, "async_thrdd_destroy, thread detached"); } } + /* release our reference to the shared context */ addr_ctx_unlink(&thrdd->addr, data); } @@ -532,10 +489,12 @@ static void async_thrdd_shutdown(struct Curl_easy *data) done = addr_ctx->thrd_done; Curl_mutex_release(&addr_ctx->mutx); - DEBUGASSERT(addr_ctx->thread_hnd != curl_thread_t_null); - if(!done && (addr_ctx->thread_hnd != curl_thread_t_null)) { - CURL_TRC_DNS(data, "cancelling resolve thread"); - (void)Curl_thread_cancel(&addr_ctx->thread_hnd); + /* Wait for the thread to terminate if it is already marked done. If it is + not done yet we cannot do anything here. We had tried pthread_cancel but + it caused hanging and resource leaks (#18532). */ + if(done && (addr_ctx->thread_hnd != curl_thread_t_null)) { + Curl_thread_join(&addr_ctx->thread_hnd); + CURL_TRC_DNS(data, "async_thrdd_shutdown, thread joined"); } } @@ -553,9 +512,11 @@ static CURLcode asyn_thrdd_await(struct Curl_easy *data, if(!entry) async_thrdd_shutdown(data); - CURL_TRC_DNS(data, "resolve, wait for thread to finish"); - if(!Curl_thread_join(&addr_ctx->thread_hnd)) { - DEBUGASSERT(0); + if(addr_ctx->thread_hnd != curl_thread_t_null) { + CURL_TRC_DNS(data, "resolve, wait for thread to finish"); + if(!Curl_thread_join(&addr_ctx->thread_hnd)) { + DEBUGASSERT(0); + } } if(entry) diff --git a/lib/curl_threads.c b/lib/curl_threads.c index 2750f5ad9f78..96fd0f8a7af9 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -100,34 +100,6 @@ int Curl_thread_join(curl_thread_t *hnd) return ret; } -/* do not use pthread_cancel if: - * - pthread_cancel seems to be absent - * - on FreeBSD, as we see hangers in CI testing - * - this is a -fsanitize=thread build - * (clang sanitizer reports false positive when functions to not return) - */ -#if defined(PTHREAD_CANCEL_ENABLE) && !defined(__FreeBSD__) -#if defined(__has_feature) -# if !__has_feature(thread_sanitizer) -#define USE_PTHREAD_CANCEL -# endif -#else /* __has_feature */ -#define USE_PTHREAD_CANCEL -#endif /* !__has_feature */ -#endif /* PTHREAD_CANCEL_ENABLE && !__FreeBSD__ */ - -int Curl_thread_cancel(curl_thread_t *hnd) -{ - (void)hnd; - if(*hnd != curl_thread_t_null) -#ifdef USE_PTHREAD_CANCEL - return pthread_cancel(**hnd); -#else - return 1; /* not supported */ -#endif - return 0; -} - #elif defined(USE_THREADS_WIN32) curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T @@ -182,12 +154,4 @@ int Curl_thread_join(curl_thread_t *hnd) return ret; } -int Curl_thread_cancel(curl_thread_t *hnd) -{ - if(*hnd != curl_thread_t_null) { - return 1; /* not supported */ - } - return 0; -} - #endif /* USE_THREADS_* */ diff --git a/lib/curl_threads.h b/lib/curl_threads.h index 115277c00eaa..82f08c5fbb56 100644 --- a/lib/curl_threads.h +++ b/lib/curl_threads.h @@ -66,22 +66,6 @@ void Curl_thread_destroy(curl_thread_t *hnd); int Curl_thread_join(curl_thread_t *hnd); -int Curl_thread_cancel(curl_thread_t *hnd); - -#if defined(USE_THREADS_POSIX) && defined(PTHREAD_CANCEL_ENABLE) -#define Curl_thread_push_cleanup(a,b) pthread_cleanup_push(a,b) -#define Curl_thread_pop_cleanup() pthread_cleanup_pop(0) -#define Curl_thread_enable_cancel() \ - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) -#define Curl_thread_disable_cancel() \ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) -#else -#define Curl_thread_push_cleanup(a,b) ((void)a,(void)b) -#define Curl_thread_pop_cleanup() Curl_nop_stmt -#define Curl_thread_enable_cancel() Curl_nop_stmt -#define Curl_thread_disable_cancel() Curl_nop_stmt -#endif - #endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ #endif /* HEADER_CURL_THREADS_H */ diff --git a/lib/hostip.c b/lib/hostip.c index 2d122fb9996b..b6be2ca1f275 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -1132,10 +1132,6 @@ CURLcode Curl_resolv_timeout(struct Curl_easy *data, prev_alarm = alarm(curlx_sltoui(timeout/1000L)); } -#ifdef DEBUGBUILD - Curl_resolve_test_delay(); -#endif - #else /* !USE_ALARM_TIMEOUT */ #ifndef CURLRES_ASYNCH if(timeoutms) @@ -1639,18 +1635,3 @@ CURLcode Curl_resolver_error(struct Curl_easy *data, const char *detail) return result; } #endif /* USE_CURL_ASYNC */ - -#ifdef DEBUGBUILD -#include "curlx/wait.h" - -void Curl_resolve_test_delay(void) -{ - const char *p = getenv("CURL_DNS_DELAY_MS"); - if(p) { - curl_off_t l; - if(!curlx_str_number(&p, &l, TIME_T_MAX) && l) { - curlx_wait_ms((timediff_t)l); - } - } -} -#endif diff --git a/lib/hostip.h b/lib/hostip.h index 2f78be82c2e7..3eb82cd1498a 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -216,8 +216,4 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data, #endif -#ifdef DEBUGBUILD -void Curl_resolve_test_delay(void); -#endif - #endif /* HEADER_CURL_HOSTIP_H */ diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index daed381e4781..4523de48864f 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -112,7 +112,7 @@ test754 test755 test756 test757 test758 test759 test760 test761 test762 \ test763 \ \ test780 test781 test782 test783 test784 test785 test786 test787 test788 \ -test789 test790 test791 test792 test793 test794 test795 test796 test797 \ +test789 test790 test791 test792 test793 test794 test796 test797 \ \ test799 test800 test801 test802 test803 test804 test805 test806 test807 \ test808 test809 test810 test811 test812 test813 test814 test815 test816 \ diff --git a/tests/data/test795 b/tests/data/test795 deleted file mode 100644 index 2c98b3bcc472..000000000000 --- a/tests/data/test795 +++ /dev/null @@ -1,36 +0,0 @@ - - - -DNS - - - -# Client-side - - -http -Debug -!c-ares -!win32 - - -Delayed resolve --connect-timeout check - - -CURL_DNS_DELAY_MS=5000 - - -http://test.invalid -v --no-progress-meter --trace-config dns --connect-timeout 1 -w \%{time_total} - - - -# Verify data after the test has been "shot" - - -28 - - -%SRCDIR/libtest/test795.pl %LOGDIR/stdout%TESTNUMBER 2 >> %LOGDIR/stderr%TESTNUMBER - - - diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am index 4ccfbd2b7bae..b62a359eabef 100644 --- a/tests/libtest/Makefile.am +++ b/tests/libtest/Makefile.am @@ -42,7 +42,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ include Makefile.inc EXTRA_DIST = CMakeLists.txt $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C) \ - test307.pl test610.pl test613.pl test795.pl test1013.pl test1022.pl mk-lib1521.pl + test307.pl test610.pl test613.pl test1013.pl test1022.pl mk-lib1521.pl CFLAGS += @CURL_CFLAG_EXTRAS@ diff --git a/tests/libtest/test795.pl b/tests/libtest/test795.pl deleted file mode 100755 index 6aa793f7f65c..000000000000 --- a/tests/libtest/test795.pl +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env perl -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) Daniel Stenberg, , 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 -# -########################################################################### -use strict; -use warnings; - -my $ok = 1; -my $exp_duration = $ARGV[1] + 0.0; - -# Read the output of curl --version -open(F, $ARGV[0]) || die "Can't open test result from $ARGV[0]\n"; -$_ = ; -chomp; -/\s*([\.\d]+)\s*/; -my $duration = $1 + 0.0; -close F; - -if ($duration <= $exp_duration) { - print "OK: duration of $duration in expected range\n"; - $ok = 0; -} -else { - print "FAILED: duration of $duration is larger than $exp_duration\n"; -} -exit $ok; From e09f45fea4fca38c5e09f858a383ad5e45a92c24 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 23:59:41 +0200 Subject: [PATCH 025/208] dist: do not distribute `CI.md` `CI.md` slipped into the 8.15.0, 8.16.0 tarballs by accident. Remove it again and update the checker exception. Follow-up to fa3f889752e6b5034966de61a372a60773a69ca8 #17463 Closes #18549 --- .github/scripts/distfiles.sh | 4 ++-- docs/Makefile.am | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/scripts/distfiles.sh b/.github/scripts/distfiles.sh index 26370744d7fd..eaa7857af27e 100755 --- a/.github/scripts/distfiles.sh +++ b/.github/scripts/distfiles.sh @@ -19,6 +19,7 @@ gitonly=".git* ^SECURITY.md ^LICENSES/* ^docs/examples/adddocsref.pl +^docs/tests/CI.md ^docs/THANKS-filter ^projects/Windows/* ^scripts/ciconfig.pl @@ -28,8 +29,7 @@ gitonly=".git* ^scripts/delta ^scripts/installcheck.sh ^scripts/release-notes.pl -^scripts/singleuse.pl -^tests/CI.md" +^scripts/singleuse.pl" tarfiles="$(mktemp)" gitfiles="$(mktemp)" diff --git a/docs/Makefile.am b/docs/Makefile.am index 554657e8895b..65ba28c0eb50 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -42,7 +42,6 @@ CLEANFILES = $(MK_CA_DOCS) $(man_MANS) $(TEST_DOCS) endif TESTDOCS = \ - tests/CI.md \ tests/FILEFORMAT.md \ tests/HTTP.md \ tests/TEST-SUITE.md From 8de37b8cda7342e54615a9a840c076def155b023 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 15 Sep 2025 10:33:19 +0200 Subject: [PATCH 026/208] cmdline-docs: extended, clarified, refreshed Closes #18550 --- docs/cmdline-opts/abstract-unix-socket.md | 6 +++--- docs/cmdline-opts/compressed-ssh.md | 3 ++- docs/cmdline-opts/disallow-username-in-url.md | 3 +++ docs/cmdline-opts/engine.md | 7 +++++-- docs/cmdline-opts/follow.md | 4 ++++ docs/cmdline-opts/globoff.md | 3 +++ docs/cmdline-opts/http2.md | 1 + docs/cmdline-opts/http3.md | 2 ++ docs/cmdline-opts/junk-session-cookies.md | 5 ++++- docs/cmdline-opts/location.md | 4 ++++ docs/cmdline-opts/max-redirs.md | 8 +++++--- docs/cmdline-opts/proto-redir.md | 5 +++-- docs/cmdline-opts/proxy.md | 3 +-- docs/cmdline-opts/request.md | 11 ++++++----- docs/cmdline-opts/retry-connrefused.md | 6 ++++-- docs/cmdline-opts/retry.md | 13 ++++++++----- docs/cmdline-opts/sasl-ir.md | 4 +++- docs/cmdline-opts/tr-encoding.md | 5 +++++ docs/cmdline-opts/trace-ids.md | 4 ++++ docs/cmdline-opts/unix-socket.md | 5 ++++- 20 files changed, 74 insertions(+), 28 deletions(-) diff --git a/docs/cmdline-opts/abstract-unix-socket.md b/docs/cmdline-opts/abstract-unix-socket.md index 7078e642fd8b..b1b6100e1611 100644 --- a/docs/cmdline-opts/abstract-unix-socket.md +++ b/docs/cmdline-opts/abstract-unix-socket.md @@ -16,6 +16,6 @@ Example: # `--abstract-unix-socket` -Connect through an abstract Unix domain socket, instead of using the network. -Note: netstat shows the path of an abstract socket prefixed with `@`, however -the \ argument should not have this leading character. +Connect to the server through an abstract Unix domain socket, instead of using +the network. Note: netstat shows the path of an abstract socket prefixed with +`@`, however the \ argument should not have this leading character. diff --git a/docs/cmdline-opts/compressed-ssh.md b/docs/cmdline-opts/compressed-ssh.md index 955c59c2b704..07d3981b484e 100644 --- a/docs/cmdline-opts/compressed-ssh.md +++ b/docs/cmdline-opts/compressed-ssh.md @@ -16,4 +16,5 @@ Example: # `--compressed-ssh` Enable SSH compression. This is a request, not an order; the server may or may -not do it. +not do it. This allows the data to be sent compressed over the wire, and +automatically decompressed in the receiving end, to save bandwidth. diff --git a/docs/cmdline-opts/disallow-username-in-url.md b/docs/cmdline-opts/disallow-username-in-url.md index 012f2d0dc80a..0507f531cc76 100644 --- a/docs/cmdline-opts/disallow-username-in-url.md +++ b/docs/cmdline-opts/disallow-username-in-url.md @@ -16,3 +16,6 @@ Example: Exit with error if passed a URL containing a username. Probably most useful when the URL is being provided at runtime or similar. + +Accepting and using credentials in a URL is normally considered a security +hazard as they are easily leaked that way. diff --git a/docs/cmdline-opts/engine.md b/docs/cmdline-opts/engine.md index 511190023ef2..cde6949b8691 100644 --- a/docs/cmdline-opts/engine.md +++ b/docs/cmdline-opts/engine.md @@ -17,6 +17,9 @@ Example: # `--engine` -Select the OpenSSL crypto engine to use for cipher operations. Use --engine -list to print a list of build-time supported engines. Note that not all (and +Select the OpenSSL crypto engine to use for cipher operations. Use `--engine +list` to print a list of build-time supported engines. Note that not all (and possibly none) of the engines may be available at runtime. + +The OpenSSL concept "engines" has been superseded by "providers" in OpenSSL 3, +and this option should work fine to specify such as well. diff --git a/docs/cmdline-opts/follow.md b/docs/cmdline-opts/follow.md index 9d4225ab355d..47d912844180 100644 --- a/docs/cmdline-opts/follow.md +++ b/docs/cmdline-opts/follow.md @@ -9,6 +9,8 @@ Multi: boolean See-also: - request - location + - proto-redir + - max-redirs Example: - -X POST --follow $URL --- @@ -23,3 +25,5 @@ status codes 307 or 308, but may be reset to GET for 301, 302 and 303. This is subtly different than --location, as that option always set the custom method in all subsequent requests independent of response code. + +Restrict which protocols a redirect is accepted to follow with --proto-redir. diff --git a/docs/cmdline-opts/globoff.md b/docs/cmdline-opts/globoff.md index 3c8c341439d3..5ef4b2ae8843 100644 --- a/docs/cmdline-opts/globoff.md +++ b/docs/cmdline-opts/globoff.md @@ -20,3 +20,6 @@ Switch off the URL globbing function. When you set this option, you can specify URLs that contain the letters {}[] without having curl itself interpret them. Note that these letters are not normal legal URL contents but they should be encoded according to the URI standard. + +curl detects numerical IPv6 addresses when used in URLs and excludes them from +the treatment, so they can still be used without having to disable globbing. diff --git a/docs/cmdline-opts/http2.md b/docs/cmdline-opts/http2.md index ae4d26974c8b..f5180be2b533 100644 --- a/docs/cmdline-opts/http2.md +++ b/docs/cmdline-opts/http2.md @@ -14,6 +14,7 @@ See-also: - http1.1 - http3 - no-alpn + - proxy-http2 Example: - --http2 $URL --- diff --git a/docs/cmdline-opts/http3.md b/docs/cmdline-opts/http3.md index a66d7978297e..e4dfeef075be 100644 --- a/docs/cmdline-opts/http3.md +++ b/docs/cmdline-opts/http3.md @@ -33,3 +33,5 @@ still tries to proceed with an older HTTP version. The fallback performs the regular negotiation between HTTP/1 and HTTP/2. Use --http3-only for similar functionality *without* a fallback. + +curl cannot do HTTP/3 over any proxy. diff --git a/docs/cmdline-opts/junk-session-cookies.md b/docs/cmdline-opts/junk-session-cookies.md index 63971050c030..668dfce2d67f 100644 --- a/docs/cmdline-opts/junk-session-cookies.md +++ b/docs/cmdline-opts/junk-session-cookies.md @@ -18,5 +18,8 @@ Example: # `--junk-session-cookies` When curl is told to read cookies from a given file, this option makes it -discard all "session cookies". This has the same effect as if a new session is +discard all session cookies. This has the same effect as if a new session is started. Typical browsers discard session cookies when they are closed down. + +Session cookies are cookies without a set expiry time. They are meant to only +last for "a session". diff --git a/docs/cmdline-opts/location.md b/docs/cmdline-opts/location.md index 86ae7e358013..56950c2dfc1e 100644 --- a/docs/cmdline-opts/location.md +++ b/docs/cmdline-opts/location.md @@ -12,6 +12,8 @@ See-also: - resolve - alt-svc - follow + - proto-redir + - max-redirs Example: - -L $URL --- @@ -40,3 +42,5 @@ using the dedicated options for that: --post301, --post302 and --post303. The method set with --request overrides the method curl would otherwise select to use. + +Restrict which protocols a redirect is accepted to follow with --proto-redir. diff --git a/docs/cmdline-opts/max-redirs.md b/docs/cmdline-opts/max-redirs.md index 7c9f193d2c4d..02bdfaa7fb63 100644 --- a/docs/cmdline-opts/max-redirs.md +++ b/docs/cmdline-opts/max-redirs.md @@ -10,12 +10,14 @@ Added: 7.5 Multi: single See-also: - location + - follow Example: - --max-redirs 3 --location $URL --- # `--max-redirs` -Set the maximum number of redirections to follow. When --location is used, to -prevent curl from following too many redirects, by default, the limit is -set to 50 redirects. Set this option to -1 to make it unlimited. +Set the maximum number of redirections to follow. When --location or --follow +are used, this option prevents curl from following too many redirects. By +default the limit is set to 50 redirects. Set this option to -1 to make it +unlimited. diff --git a/docs/cmdline-opts/proto-redir.md b/docs/cmdline-opts/proto-redir.md index 337aa93cb682..1f75bfdfd6c9 100644 --- a/docs/cmdline-opts/proto-redir.md +++ b/docs/cmdline-opts/proto-redir.md @@ -9,8 +9,9 @@ Category: connection curl Multi: single See-also: - proto + - follow Example: - - --proto-redir =http,https $URL + - --proto-redir =http,https --follow $URL --- # `--proto-redir` @@ -20,7 +21,7 @@ not overridden by this option. See --proto for how protocols are represented. Example, allow only HTTP and HTTPS on redirect: - curl --proto-redir -all,http,https http://example.com + curl --proto-redir -all,http,https --follow http://example.com By default curl only allows HTTP, HTTPS, FTP and FTPS on redirects (added in 7.65.2). Specifying *all* or *+all* enables all protocols on diff --git a/docs/cmdline-opts/proxy.md b/docs/cmdline-opts/proxy.md index 1ed503c10844..6cd456169d34 100644 --- a/docs/cmdline-opts/proxy.md +++ b/docs/cmdline-opts/proxy.md @@ -31,8 +31,7 @@ HTTPS proxy support works with the https:// protocol prefix for OpenSSL and GnuTLS (added in 7.52.0). It also works for mbedTLS, Rustls, Schannel and wolfSSL (added in 7.87.0). -Unrecognized and unsupported proxy protocols cause an error (added in 7.52.0). -Ancient curl versions ignored unknown schemes and used http:// instead. +Unrecognized and unsupported proxy protocol schemes cause an error. If the port number is not specified in the proxy string, it is assumed to be 1080. diff --git a/docs/cmdline-opts/request.md b/docs/cmdline-opts/request.md index 86cf10deafa4..2c9d7776e587 100644 --- a/docs/cmdline-opts/request.md +++ b/docs/cmdline-opts/request.md @@ -10,8 +10,9 @@ Added: 6.0 Multi: single See-also: - request-target + - follow Example: - - -X "DELETE" $URL + - --request "DELETE" $URL - -X NLST ftp://example.com/ --- @@ -37,10 +38,10 @@ This option only changes the actual word used in the HTTP request, it does not alter the way curl behaves. For example if you want to make a proper HEAD request, using -X HEAD does not suffice. You need to use the --head option. -The method string you set with --request is used for all requests, which -if you for example use --location may cause unintended side-effects when curl -does not change request method according to the HTTP 30x response codes - and -similar. +If --location is used, the method string you set with --request is used for +all requests, which may cause unintended side-effects when curl does not +change request method according to the HTTP 30x response codes - and similar. +Consider using --follow instead in combination with --request. ## FTP Specifies a custom FTP command to use instead of *LIST* when doing file lists diff --git a/docs/cmdline-opts/retry-connrefused.md b/docs/cmdline-opts/retry-connrefused.md index 22345cd8818e..2e6ba8068696 100644 --- a/docs/cmdline-opts/retry-connrefused.md +++ b/docs/cmdline-opts/retry-connrefused.md @@ -15,5 +15,7 @@ Example: # `--retry-connrefused` -In addition to the other conditions, consider ECONNREFUSED as a transient -error too for --retry. This option is used together with --retry. +In addition to the other conditions, also consider ECONNREFUSED as a transient +error for --retry. This option is used together with --retry. Normally, a +confused connection is not considered a transient error and therefore thus not +otherwise trigger a retry. diff --git a/docs/cmdline-opts/retry.md b/docs/cmdline-opts/retry.md index 2176e8f43da1..f55d8edcca12 100644 --- a/docs/cmdline-opts/retry.md +++ b/docs/cmdline-opts/retry.md @@ -9,6 +9,8 @@ Category: curl Multi: single See-also: - retry-max-time + - retry-connrefused + - retry-delay Example: - --retry 7 $URL --- @@ -16,16 +18,17 @@ Example: # `--retry` If a transient error is returned when curl tries to perform a transfer, it -retries this number of times before giving up. Setting the number to 0 -makes curl do no retries (which is the default). Transient error means either: -a timeout, an FTP 4xx response code or an HTTP 408, 429, 500, 502, 503 or 504 +retries this number of times before giving up. Setting the number to 0 makes +curl do no retries (which is the default). Transient error means either: a +timeout, an FTP 4xx response code or an HTTP 408, 429, 500, 502, 503 or 504 response code. When curl is about to retry a transfer, it first waits one second and then for all forthcoming retries it doubles the waiting time until it reaches 10 minutes, which then remains the set fixed delay time between the rest of the -retries. By using --retry-delay you disable this exponential backoff algorithm. -See also --retry-max-time to limit the total time allowed for retries. +retries. By using --retry-delay you disable this exponential backoff +algorithm. See also --retry-max-time to limit the total time allowed for +retries. curl complies with the Retry-After: response header if one was present to know when to issue the next retry (added in 7.66.0). diff --git a/docs/cmdline-opts/sasl-ir.md b/docs/cmdline-opts/sasl-ir.md index b11137df0a63..0f759c6d1005 100644 --- a/docs/cmdline-opts/sasl-ir.md +++ b/docs/cmdline-opts/sasl-ir.md @@ -14,4 +14,6 @@ Example: # `--sasl-ir` -Enable initial response in SASL authentication. +Enable initial response in SASL authentication. Such an "initial response" is +a message sent by the client to the server after the client selects an +authentication mechanism. diff --git a/docs/cmdline-opts/tr-encoding.md b/docs/cmdline-opts/tr-encoding.md index cdd8f02d67b3..c364c07d4b23 100644 --- a/docs/cmdline-opts/tr-encoding.md +++ b/docs/cmdline-opts/tr-encoding.md @@ -17,3 +17,8 @@ Example: Request a compressed Transfer-Encoding response using one of the algorithms curl supports, and uncompress the data while receiving it. + +This method was once intended to be the way to do automatic data compression +for HTTP but for all practical purposes using Content-Encoding as done with +--compressed has superseded transfer encoding. The --tr-encoding option is +therefore often not be one you want. diff --git a/docs/cmdline-opts/trace-ids.md b/docs/cmdline-opts/trace-ids.md index b9a622260040..302631d8440e 100644 --- a/docs/cmdline-opts/trace-ids.md +++ b/docs/cmdline-opts/trace-ids.md @@ -18,3 +18,7 @@ Example: Prepend the transfer and connection identifiers to each trace or verbose line that curl displays. + +The identifiers are unique numbers assigned to each connection and transfer to +allow a user to better understand which transfer and connection each verbose +output line refers to. diff --git a/docs/cmdline-opts/unix-socket.md b/docs/cmdline-opts/unix-socket.md index 582f32dc50e1..34cc714f79df 100644 --- a/docs/cmdline-opts/unix-socket.md +++ b/docs/cmdline-opts/unix-socket.md @@ -16,4 +16,7 @@ Example: # `--unix-socket` -Connect through this Unix domain socket, instead of using the network. +Connect to the server through this Unix domain socket, instead of using the +network. + +To connect to a proxy over Unix domain socket, see --proxy. From 61b79dee7966e979cb5ae950ea773ecf4c048a62 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 15 Sep 2025 12:51:58 +0200 Subject: [PATCH 027/208] CURLOPT_TIMECONDITION.md: works for FILE and FTP as well Closes #18551 --- docs/libcurl/opts/CURLOPT_TIMECONDITION.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_TIMECONDITION.md b/docs/libcurl/opts/CURLOPT_TIMECONDITION.md index d17174c254ec..f03473f60840 100644 --- a/docs/libcurl/opts/CURLOPT_TIMECONDITION.md +++ b/docs/libcurl/opts/CURLOPT_TIMECONDITION.md @@ -9,6 +9,8 @@ See-also: - CURLOPT_TIMEVALUE (3) Protocol: - HTTP + - FILE + - FTP Added-in: 7.1 --- @@ -26,15 +28,15 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMECONDITION, long cond); # DESCRIPTION -Pass a long as parameter. This defines how the CURLOPT_TIMEVALUE(3) time -value is treated. You can set this parameter to *CURL_TIMECOND_IFMODSINCE* -or *CURL_TIMECOND_IFUNMODSINCE*. +Pass a long as parameter. This defines how the CURLOPT_TIMEVALUE(3) time value +is treated. You can set this parameter to *CURL_TIMECOND_IFMODSINCE* or +*CURL_TIMECOND_IFUNMODSINCE*. The last modification time of a file is not always known and in such instances this feature has no effect even if the given time condition would not have -been met. curl_easy_getinfo(3) with the *CURLINFO_CONDITION_UNMET* -option can be used after a transfer to learn if a zero-byte successful -"transfer" was due to this condition not matching. +been met. curl_easy_getinfo(3) with the *CURLINFO_CONDITION_UNMET* option can +be used after a transfer to learn if a zero-byte successful "transfer" was due +to this condition not matching. # DEFAULT From a4196e22493b945bc61f51767105d5922c7feb93 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 2 Sep 2025 14:20:26 +0200 Subject: [PATCH 028/208] tidy-up: whitespace Closes #18553 --- docs/examples/Makefile.example | 4 ++-- docs/examples/ephiperfifo.c | 9 --------- docs/examples/evhiperfifo.c | 8 -------- docs/examples/hiperfifo.c | 12 ------------ lib/ftp.c | 5 +---- lib/md4.c | 6 +++--- lib/md5.c | 8 ++++---- lib/memdebug.c | 10 +++++----- lib/url.c | 4 ++-- lib/vauth/digest_sspi.c | 16 ++++++++-------- lib/vauth/krb5_sspi.c | 6 +++--- lib/vauth/ntlm_sspi.c | 24 ++++++++++++------------ lib/vauth/spnego_sspi.c | 4 ++-- lib/vquic/curl_ngtcp2.c | 4 +--- lib/vquic/curl_osslq.c | 4 +--- lib/vquic/curl_quiche.c | 4 +--- lib/ws.c | 2 +- scripts/checksrc.pl | 1 - src/terminal.c | 2 +- tests/data/test1634 | 2 +- tests/data/test1635 | 2 +- tests/data/test612 | 2 +- tests/unit/unit1304.c | 2 +- 23 files changed, 51 insertions(+), 90 deletions(-) diff --git a/docs/examples/Makefile.example b/docs/examples/Makefile.example index cfb59c94ef10..9738e94bb82d 100644 --- a/docs/examples/Makefile.example +++ b/docs/examples/Makefile.example @@ -26,7 +26,7 @@ TARGET = example # Which object files that the executable consists of -OBJS= ftpget.o +OBJS = ftpget.o # What compiler to use CC = gcc @@ -48,7 +48,7 @@ LIBS = -lcurl -lsocket -lnsl -lssl -lcrypto # Link the target with all objects and libraries $(TARGET) : $(OBJS) - $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS) + $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS) # Compile the source files into object files ftpget.o : ftpget.c diff --git a/docs/examples/ephiperfifo.c b/docs/examples/ephiperfifo.c index d30b944bbc95..3fddb2b7431f 100644 --- a/docs/examples/ephiperfifo.c +++ b/docs/examples/ephiperfifo.c @@ -88,7 +88,6 @@ struct GlobalInfo { FILE *input; }; - /* Information associated with a specific easy handle */ struct ConnInfo { CURL *easy; @@ -97,7 +96,6 @@ struct ConnInfo { char error[CURL_ERROR_SIZE]; }; - /* Information associated with a specific socket */ struct SockInfo { curl_socket_t sockfd; @@ -167,7 +165,6 @@ static int multi_timer_cb(CURLM *multi, long timeout_ms, struct GlobalInfo *g) return 0; } - /* Check for completed transfers, and remove their easy handles */ static void check_multi_info(struct GlobalInfo *g) { @@ -244,7 +241,6 @@ static void timer_cb(struct GlobalInfo *g, int revents) check_multi_info(g); } - /* Clean up the SockInfo structure */ static void remsock(struct SockInfo *f, struct GlobalInfo *g) { @@ -258,7 +254,6 @@ static void remsock(struct SockInfo *f, struct GlobalInfo *g) } } - /* Assign information to a SockInfo structure */ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, struct GlobalInfo *g) @@ -284,7 +279,6 @@ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, s, strerror(errno)); } - /* Initialize a new SockInfo structure */ static void addsock(curl_socket_t s, CURL *easy, int action, struct GlobalInfo *g) @@ -324,7 +318,6 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) return 0; } - /* CURLOPT_WRITEFUNCTION */ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) { @@ -333,7 +326,6 @@ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) return size * nmemb; } - /* CURLOPT_PROGRESSFUNCTION */ static int prog_cb(void *p, double dltotal, double dlnow, double ult, double uln) @@ -346,7 +338,6 @@ static int prog_cb(void *p, double dltotal, double dlnow, double ult, return 0; } - /* Create a new easy handle, and add it to the global curl_multi */ static void new_conn(const char *url, struct GlobalInfo *g) { diff --git a/docs/examples/evhiperfifo.c b/docs/examples/evhiperfifo.c index b28f057c8242..364a0f42fefa 100644 --- a/docs/examples/evhiperfifo.c +++ b/docs/examples/evhiperfifo.c @@ -88,7 +88,6 @@ struct GlobalInfo { FILE *input; }; - /* Information associated with a specific easy handle */ struct ConnInfo { CURL *easy; @@ -97,7 +96,6 @@ struct ConnInfo { char error[CURL_ERROR_SIZE]; }; - /* Information associated with a specific socket */ struct SockInfo { curl_socket_t sockfd; @@ -164,7 +162,6 @@ static void mcode_or_die(const char *where, CURLMcode code) } } - /* Check for completed transfers, and remove their easy handles */ static void check_multi_info(struct GlobalInfo *g) { @@ -191,7 +188,6 @@ static void check_multi_info(struct GlobalInfo *g) } } - /* Called by libevent when we get action on a multi socket */ static void event_cb(EV_P_ struct ev_io *w, int revents) { @@ -240,7 +236,6 @@ static void remsock(struct SockInfo *f, struct GlobalInfo *g) } } - /* Assign information to a SockInfo structure */ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, struct GlobalInfo *g) @@ -261,7 +256,6 @@ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, ev_io_start(g->loop, &f->ev); } - /* Initialize a new SockInfo structure */ static void addsock(curl_socket_t s, CURL *easy, int action, struct GlobalInfo *g) @@ -304,7 +298,6 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) return 0; } - /* CURLOPT_WRITEFUNCTION */ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) { @@ -328,7 +321,6 @@ static int xferinfo_cb(void *p, curl_off_t dltotal, curl_off_t dlnow, return 0; } - /* Create a new easy handle, and add it to the global curl_multi */ static void new_conn(const char *url, struct GlobalInfo *g) { diff --git a/docs/examples/hiperfifo.c b/docs/examples/hiperfifo.c index 35a519b63e41..1af1eb0c72c3 100644 --- a/docs/examples/hiperfifo.c +++ b/docs/examples/hiperfifo.c @@ -88,7 +88,6 @@ struct GlobalInfo { int stopped; }; - /* Information associated with a specific easy handle */ struct ConnInfo { CURL *easy; @@ -97,7 +96,6 @@ struct ConnInfo { char error[CURL_ERROR_SIZE]; }; - /* Information associated with a specific socket */ struct SockInfo { curl_socket_t sockfd; @@ -134,7 +132,6 @@ static void mcode_or_die(const char *where, CURLMcode code) } } - /* Update the event timer after curl_multi library calls */ static int multi_timer_cb(CURLM *multi, long timeout_ms, struct GlobalInfo *g) { @@ -158,7 +155,6 @@ static int multi_timer_cb(CURLM *multi, long timeout_ms, struct GlobalInfo *g) return 0; } - /* Check for completed transfers, and remove their easy handles */ static void check_multi_info(struct GlobalInfo *g) { @@ -187,7 +183,6 @@ static void check_multi_info(struct GlobalInfo *g) event_base_loopbreak(g->evbase); } - /* Called by libevent when we get action on a multi socket */ static void event_cb(int fd, short kind, void *userp) { @@ -210,7 +205,6 @@ static void event_cb(int fd, short kind, void *userp) } } - /* Called by libevent when our timeout expires */ static void timer_cb(int fd, short kind, void *userp) { @@ -225,7 +219,6 @@ static void timer_cb(int fd, short kind, void *userp) check_multi_info(g); } - /* Clean up the SockInfo structure */ static void remsock(struct SockInfo *f) { @@ -237,7 +230,6 @@ static void remsock(struct SockInfo *f) } } - /* Assign information to a SockInfo structure */ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, struct GlobalInfo *g) @@ -256,7 +248,6 @@ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, event_add(&f->ev, NULL); } - /* Initialize a new SockInfo structure */ static void addsock(curl_socket_t s, CURL *easy, int action, struct GlobalInfo *g) @@ -296,7 +287,6 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) return 0; } - /* CURLOPT_WRITEFUNCTION */ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) { @@ -305,7 +295,6 @@ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) return size * nmemb; } - /* CURLOPT_PROGRESSFUNCTION */ static int xferinfo_cb(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ult, curl_off_t uln) @@ -319,7 +308,6 @@ static int xferinfo_cb(void *p, curl_off_t dltotal, curl_off_t dlnow, return 0; } - /* Create a new easy handle, and add it to the global curl_multi */ static void new_conn(const char *url, struct GlobalInfo *g) { diff --git a/lib/ftp.c b/lib/ftp.c index 29c2f789a3e9..6c710dceb962 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -430,6 +430,7 @@ static const struct Curl_cwtype ftp_cw_lc = { }; #endif /* CURL_PREFER_LF_LINEENDS */ + /*********************************************************************** * * ftp_check_ctrl_on_data_wait() @@ -629,7 +630,6 @@ static CURLcode ftp_readresp(struct Curl_easy *data, * from a server after a command. * */ - CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nreadp, /* return number of bytes read */ int *ftpcodep) /* return the ftp-code */ @@ -3494,7 +3494,6 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, * * BLOCKING */ - static CURLcode ftp_sendquote(struct Curl_easy *data, struct ftp_conn *ftpc, @@ -3617,7 +3616,6 @@ ftp_pasv_verbose(struct Curl_easy *data, * (which basically is only for when PASV is being sent to retry a failed * EPSV). */ - static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) { struct connectdata *conn = data->conn; @@ -3781,7 +3779,6 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) * This is the actual DO function for FTP. Get a file/directory according to * the options previously setup. */ - static CURLcode ftp_perform(struct Curl_easy *data, struct ftp_conn *ftpc, diff --git a/lib/md4.c b/lib/md4.c index b9c98d6c4aea..b30881213e95 100644 --- a/lib/md4.c +++ b/lib/md4.c @@ -342,7 +342,7 @@ static const void *my_md4_body(MD4_CTX *ctx, saved_c = c; saved_d = d; -/* Round 1 */ + /* Round 1 */ MD4_STEP(MD4_F, a, b, c, d, MD4_SET(0), 3) MD4_STEP(MD4_F, d, a, b, c, MD4_SET(1), 7) MD4_STEP(MD4_F, c, d, a, b, MD4_SET(2), 11) @@ -360,7 +360,7 @@ static const void *my_md4_body(MD4_CTX *ctx, MD4_STEP(MD4_F, c, d, a, b, MD4_SET(14), 11) MD4_STEP(MD4_F, b, c, d, a, MD4_SET(15), 19) -/* Round 2 */ + /* Round 2 */ MD4_STEP(MD4_G, a, b, c, d, MD4_GET(0) + 0x5a827999, 3) MD4_STEP(MD4_G, d, a, b, c, MD4_GET(4) + 0x5a827999, 5) MD4_STEP(MD4_G, c, d, a, b, MD4_GET(8) + 0x5a827999, 9) @@ -378,7 +378,7 @@ static const void *my_md4_body(MD4_CTX *ctx, MD4_STEP(MD4_G, c, d, a, b, MD4_GET(11) + 0x5a827999, 9) MD4_STEP(MD4_G, b, c, d, a, MD4_GET(15) + 0x5a827999, 13) -/* Round 3 */ + /* Round 3 */ MD4_STEP(MD4_H, a, b, c, d, MD4_GET(0) + 0x6ed9eba1, 3) MD4_STEP(MD4_H, d, a, b, c, MD4_GET(8) + 0x6ed9eba1, 9) MD4_STEP(MD4_H, c, d, a, b, MD4_GET(4) + 0x6ed9eba1, 11) diff --git a/lib/md5.c b/lib/md5.c index 625670965a1c..e5cc4088dac6 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -382,7 +382,7 @@ static const void *my_md5_body(my_md5_ctx *ctx, saved_c = c; saved_d = d; -/* Round 1 */ + /* Round 1 */ MD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7) MD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12) MD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17) @@ -400,7 +400,7 @@ static const void *my_md5_body(my_md5_ctx *ctx, MD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17) MD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22) -/* Round 2 */ + /* Round 2 */ MD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5) MD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9) MD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14) @@ -418,7 +418,7 @@ static const void *my_md5_body(my_md5_ctx *ctx, MD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14) MD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20) -/* Round 3 */ + /* Round 3 */ MD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4) MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11) MD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16) @@ -436,7 +436,7 @@ static const void *my_md5_body(my_md5_ctx *ctx, MD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16) MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23) -/* Round 4 */ + /* Round 4 */ MD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6) MD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10) MD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15) diff --git a/lib/memdebug.c b/lib/memdebug.c index c1121713ea34..0d8d39603c4d 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -321,9 +321,9 @@ curl_socket_t curl_dbg_socket(int domain, int type, int protocol, } SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, - SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, - SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line, - const char *source) + SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, + SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, + int line, const char *source) { SEND_TYPE_RETV rc; if(countcheck("send", line, source)) @@ -336,8 +336,8 @@ SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, } RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, - RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line, - const char *source) + RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, + int line, const char *source) { RECV_TYPE_RETV rc; if(countcheck("recv", line, source)) diff --git a/lib/url.c b/lib/url.c index 283da6d68b50..29702296a98d 100644 --- a/lib/url.c +++ b/lib/url.c @@ -361,9 +361,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) struct UserDefined *set = &data->set; CURLcode result = CURLE_OK; - set->out = stdout; /* default output to stdout */ + set->out = stdout; /* default output to stdout */ set->in_set = stdin; /* default input from stdin */ - set->err = stderr; /* default stderr to stderr */ + set->err = stderr; /* default stderr to stderr */ /* use fwrite as default function to store output */ set->fwrite_func = (curl_write_callback)fwrite; diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index c74b8f865397..861c4e1cb91b 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -195,9 +195,9 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, /* Generate our response message */ status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, - 0, 0, 0, &chlg_desc, 0, - &context, &resp_desc, &attrs, - &expiry); + 0, 0, 0, &chlg_desc, 0, + &context, &resp_desc, &attrs, + &expiry); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) @@ -591,11 +591,11 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, /* Generate our response message */ status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL, - spn, - ISC_REQ_USE_HTTP_STYLE, 0, 0, - &chlg_desc, 0, - digest->http_context, - &resp_desc, &attrs, &expiry); + spn, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, + digest->http_context, + &resp_desc, &attrs, &expiry); curlx_unicodefree(spn); if(status == SEC_I_COMPLETE_NEEDED || diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c index ea26f82750a6..6595ab977a79 100644 --- a/lib/vauth/krb5_sspi.c +++ b/lib/vauth/krb5_sspi.c @@ -282,8 +282,8 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, /* Get our response size information */ status = Curl_pSecFn->QueryContextAttributes(krb5->context, - SECPKG_ATTR_SIZES, - &sizes); + SECPKG_ATTR_SIZES, + &sizes); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; @@ -392,7 +392,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, /* Encrypt the data */ status = Curl_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, - &wrap_desc, 0); + &wrap_desc, 0); if(status != SEC_E_OK) { free(padding); free(message); diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index d45e2db38e1f..101eb8abd305 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -170,11 +170,11 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, /* Generate our type-1 message */ status = Curl_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, - ntlm->spn, - 0, 0, SECURITY_NETWORK_DREP, - NULL, 0, - ntlm->context, &type_1_desc, - &attrs, &expiry); + ntlm->spn, + 0, 0, SECURITY_NETWORK_DREP, + NULL, 0, + ntlm->context, &type_1_desc, + &attrs, &expiry); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) Curl_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); @@ -308,13 +308,13 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, /* Generate our type-3 message */ status = Curl_pSecFn->InitializeSecurityContext(ntlm->credentials, - ntlm->context, - ntlm->spn, - 0, 0, SECURITY_NETWORK_DREP, - &type_2_desc, - 0, ntlm->context, - &type_3_desc, - &attrs, &expiry); + ntlm->context, + ntlm->spn, + 0, 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, ntlm->context, + &type_3_desc, + &attrs, &expiry); if(status != SEC_E_OK) { infof(data, "NTLM handshake failure (type-3 message): Status=%lx", status); diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index 9c4812526121..af3a9c9798c2 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -270,7 +270,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, if(nego->status == SEC_I_COMPLETE_NEEDED || nego->status == SEC_I_COMPLETE_AND_CONTINUE) { nego->status = (DWORD)Curl_pSecFn->CompleteAuthToken(nego->context, - &resp_desc); + &resp_desc); if(GSS_ERROR(nego->status)) { char buffer[STRERROR_LEN]; failf(data, "CompleteAuthToken failed: %s", @@ -308,7 +308,7 @@ CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego, char **outptr, size_t *outlen) { /* Base64 encode the already generated response */ - CURLcode result = curlx_base64_encode((const char *) nego->output_token, + CURLcode result = curlx_base64_encode((const char *)nego->output_token, nego->output_token_length, outptr, outlen); if(!result && (!*outptr || !*outlen)) { diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 3f7c58d08af2..4191924b5ab9 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2433,9 +2433,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, CURLcode result; const struct Curl_sockaddr_ex *sockaddr = NULL; int qfd; -static const struct alpn_spec ALPN_SPEC_H3 = { - { "h3", "h3-29" }, 2 -}; + static const struct alpn_spec ALPN_SPEC_H3 = {{ "h3", "h3-29" }, 2}; DEBUGASSERT(ctx->initialized); ctx->dcid.datalen = NGTCP2_MAX_CIDLEN; diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 3586ad0d556a..e82cbf2a3eaa 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1161,9 +1161,7 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, const struct Curl_sockaddr_ex *peer_addr = NULL; BIO *bio = NULL; BIO_ADDR *baddr = NULL; -static const struct alpn_spec ALPN_SPEC_H3 = { - { "h3" }, 1 -}; + static const struct alpn_spec ALPN_SPEC_H3 = {{ "h3" }, 1}; DEBUGASSERT(ctx->initialized); diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 179ccf8aa1ac..8f0535d65d2a 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1256,9 +1256,7 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf, int rv; CURLcode result; const struct Curl_sockaddr_ex *sockaddr; -static const struct alpn_spec ALPN_SPEC_H3 = { - { "h3" }, 1 -}; + static const struct alpn_spec ALPN_SPEC_H3 = {{ "h3" }, 1}; DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD); DEBUGASSERT(ctx->initialized); diff --git a/lib/ws.c b/lib/ws.c index 3b654281604b..00fdeb3e97f8 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -1876,7 +1876,7 @@ CURL_EXTERN CURLcode curl_ws_start_frame(CURL *d, result = ws_enc_write_head(data, ws, &ws->enc, flags, frame_len, &ws->sendbuf); if(result) - CURL_TRC_WS(data, "curl_start_frame(), error adding frame head %d", + CURL_TRC_WS(data, "curl_start_frame(), error adding frame head %d", result); out: diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 43b819553791..574e03c13b24 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -936,7 +936,6 @@ sub scanfile { my $diff = $second - $first; checkwarn("INDENTATION", $line, length($1), $file, $ol, "not indented $indent steps (uses $diff)"); - } } } diff --git a/src/terminal.c b/src/terminal.c index 0150cd4a56ca..014e2df8c00b 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -66,7 +66,7 @@ unsigned int get_terminal_columns(void) cols = (int)ts.ws_col; #elif defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) { - HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE); + HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE); CONSOLE_SCREEN_BUFFER_INFO console_info; if((stderr_hnd != INVALID_HANDLE_VALUE) && diff --git a/tests/data/test1634 b/tests/data/test1634 index ad256348400b..ee7a50871aa7 100644 --- a/tests/data/test1634 +++ b/tests/data/test1634 @@ -48,7 +48,7 @@ http --retry with a 429 response and Retry-After: and --fail -http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 1 --fail +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 1 --fail diff --git a/tests/data/test1635 b/tests/data/test1635 index 399846c004fe..751d46232c8b 100644 --- a/tests/data/test1635 +++ b/tests/data/test1635 @@ -37,7 +37,7 @@ http --retry with a 429 response and Retry-After: and --fail-with-body -http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 1 --fail-with-body +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 1 --fail-with-body diff --git a/tests/data/test612 b/tests/data/test612 index 7ab5c80d65b3..899496146683 100644 --- a/tests/data/test612 +++ b/tests/data/test612 @@ -24,7 +24,7 @@ sftp SFTP post-quote remove file ---key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt -Q "-rm %SFTP_PWD/%LOGDIR/upload.%TESTNUMBER" sftp://%HOSTIP:%SSHPORT%SFTP_PWD/%LOGDIR/upload.%TESTNUMBER --insecure +--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt -Q "-rm %SFTP_PWD/%LOGDIR/upload.%TESTNUMBER" sftp://%HOSTIP:%SSHPORT%SFTP_PWD/%LOGDIR/upload.%TESTNUMBER --insecure Dummy test file for remove test diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c index 250a2ee3f61c..041ce42691dd 100644 --- a/tests/unit/unit1304.c +++ b/tests/unit/unit1304.c @@ -159,8 +159,8 @@ static CURLcode test_unit1304(const char *arg) * with login[0] != 0. */ free(password); - free(login); password = NULL; + free(login); login = NULL; Curl_netrc_init(&store); result = Curl_parsenetrc(&store, From ac24e0a80e80f7a5f06aacd4696b185856fdb3ec Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 15 Sep 2025 15:21:30 +0200 Subject: [PATCH 029/208] GHA/codeql: tidy up config names Before this patch there was a single C config detected, named `build:`. Closes #18555 --- .github/workflows/codeql.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e33540959543..8d23d6bac272 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ concurrency: permissions: {} jobs: - codeql: + gha_python: name: 'GHA and Python' runs-on: ubuntu-latest permissions: @@ -61,23 +61,19 @@ jobs: uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 c: - name: 'C (${{ matrix.build.name }})' - runs-on: ${{ matrix.build.image }} + name: 'C' + runs-on: ${{ matrix.platform == 'Linux' && 'ubuntu-latest' || 'windows-2022' }} permissions: security-events: write # To create/update security events strategy: fail-fast: false matrix: - build: - - name: 'Linux' - image: ubuntu-latest - - name: 'Windows' - image: windows-2022 + platform: [Linux, Windows] env: - MATRIX_IMAGE: '${{ matrix.build.image }}' + MATRIX_PLATFORM: '${{ matrix.platform }}' steps: - name: 'install prereqs' - if: ${{ contains(matrix.build.image, 'ubuntu') }} + if: ${{ matrix.platform == 'Linux' }} timeout-minutes: 5 run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list @@ -99,7 +95,7 @@ jobs: timeout-minutes: 10 shell: bash run: | - if [[ "${MATRIX_IMAGE}" = *'windows'* ]]; then + if [ "${MATRIX_PLATFORM}" = 'Windows' ]; then cmake -B . -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_VS_GLOBALS=TrackFileAccess=false \ -DCURL_USE_SCHANNEL=ON -DCURL_USE_LIBPSL=OFF -DUSE_WIN32_IDN=ON From 56d3bb78bedf200ac093b0ec8f75845b3f7cbb7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:56:28 +0000 Subject: [PATCH 030/208] GHA: bump actions/checkout from 4.2.2 to 5.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.2.2...08c6903cd8c0fde910a37f88322edcfb5dd907a8) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Closes #18556 --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8d23d6bac272..9993d92cacf1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -47,7 +47,7 @@ jobs: permissions: security-events: write # To create/update security events steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 with: persist-credentials: false @@ -81,7 +81,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 with: persist-credentials: false From 98d5321530e498d66756c1e2b2ef449b8cfc762c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 12:00:44 +0000 Subject: [PATCH 031/208] GHA: Update nghttp2/nghttp2 to v1.67.1 Closes #18552 --- .github/workflows/http3-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 195437182f11..2fe8b8cdbba6 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -60,7 +60,7 @@ env: # renovate: datasource=github-tags depName=ngtcp2/ngtcp2 versioning=semver registryUrl=https://github.com NGTCP2_VERSION: 1.15.1 # renovate: datasource=github-tags depName=nghttp2/nghttp2 versioning=semver registryUrl=https://github.com - NGHTTP2_VERSION: 1.67.0 + NGHTTP2_VERSION: 1.67.1 # renovate: datasource=github-tags depName=cloudflare/quiche versioning=semver registryUrl=https://github.com QUICHE_VERSION: 0.24.6 From af7d67d3c03329116e593d999851d2cc3ebbf119 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 16 Sep 2025 10:27:42 +0200 Subject: [PATCH 032/208] krb5: return appropriate error on send failures Closes #18561 --- lib/krb5.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/lib/krb5.c b/lib/krb5.c index 563d724bbbc8..b041d2f2277e 100644 --- a/lib/krb5.c +++ b/lib/krb5.c @@ -620,16 +620,16 @@ static CURLcode sec_recv(struct Curl_easy *data, int sockindex, /* Send |length| bytes from |from| to the |sockindex| socket taking care of encoding and negotiating with the server. |from| can be NULL. */ -static void do_sec_send(struct Curl_easy *data, struct connectdata *conn, - int sockindex, const char *from, size_t length) +static CURLcode do_sec_send(struct Curl_easy *data, struct connectdata *conn, + int sockindex, const char *from, size_t length) { int bytes, htonl_bytes; /* 32-bit integers for htonl */ char *buffer = NULL; char *cmd_buffer; size_t cmd_size = 0; - CURLcode error; enum protection_level prot_level = conn->data_prot; bool iscmd = (prot_level == PROT_CMD); + CURLcode result = CURLE_OK; DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); @@ -642,36 +642,40 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn, bytes = conn->mech->encode(conn->app_data, from, (int)length, (int)prot_level, (void **)&buffer); if(!buffer || bytes <= 0) - return; /* error */ + return CURLE_OUT_OF_MEMORY; /* error */ if(iscmd) { - error = curlx_base64_encode(buffer, curlx_sitouz(bytes), - &cmd_buffer, &cmd_size); - if(error) { + result = curlx_base64_encode(buffer, curlx_sitouz(bytes), + &cmd_buffer, &cmd_size); + if(result) { free(buffer); - return; /* error */ + return result; /* error */ } if(cmd_size > 0) { static const char *enc = "ENC "; static const char *mic = "MIC "; if(prot_level == PROT_PRIVATE) - socket_write(data, sockindex, enc, 4); + result = socket_write(data, sockindex, enc, 4); else - socket_write(data, sockindex, mic, 4); - - socket_write(data, sockindex, cmd_buffer, cmd_size); - socket_write(data, sockindex, "\r\n", 2); - infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic, - cmd_buffer); - free(cmd_buffer); + result = socket_write(data, sockindex, mic, 4); + if(!result) + result = socket_write(data, sockindex, cmd_buffer, cmd_size); + if(!result) + result = socket_write(data, sockindex, "\r\n", 2); + if(!result) + infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic, + cmd_buffer); } + free(cmd_buffer); } else { htonl_bytes = (int)htonl((OM_uint32)bytes); - socket_write(data, sockindex, &htonl_bytes, sizeof(htonl_bytes)); - socket_write(data, sockindex, buffer, curlx_sitouz(bytes)); + result = socket_write(data, sockindex, &htonl_bytes, sizeof(htonl_bytes)); + if(!result) + result = socket_write(data, sockindex, buffer, curlx_sitouz(bytes)); } free(buffer); + return result; } static CURLcode sec_write(struct Curl_easy *data, int sockindex, @@ -685,11 +689,13 @@ static CURLcode sec_write(struct Curl_easy *data, int sockindex, if(len <= 0) len = length; while(length) { + CURLcode result; if(length < len) len = length; - /* WTF: this ignores all errors writing to the socket */ - do_sec_send(data, conn, sockindex, buffer, len); + result = do_sec_send(data, conn, sockindex, buffer, len); + if(result) + return result; length -= len; buffer += len; *pnwritten += len; From a333fd4411b95fc0c3061b2d675de9287b6123e0 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 15 Sep 2025 21:03:52 +0200 Subject: [PATCH 033/208] GHA/codeql: enable more build options, build servers and tunits - add HTTP/3 build with OpenSSL 3.5, nghttp3 and ngtcp2. - enable GSASL, Heimdal, rtmp, SSLS-export. - make one build MultiSSL with GnuTLS, mbedTLS, Rustls, wolfSSL. - build servers (also on Windows), and tunits. - use Linuxbrew to install build dependencies missing from Ubuntu. Coverage is now 466 C files. (was: 446) Closes #18557 --- .github/workflows/codeql.yml | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9993d92cacf1..5ff3434442f8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -79,7 +79,9 @@ jobs: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev \ + libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev + /home/linuxbrew/.linuxbrew/bin/brew install gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 with: @@ -102,9 +104,27 @@ jobs: cmake --build . --verbose src/Debug/curl.exe --disable --version else - cmake -B . -G Ninja - cmake --build . --verbose - src/curl --disable --version + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + + # MultiSSL + export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" + cmake -B _bld1 -G Ninja \ + -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON + cmake --build _bld1 --verbose + cmake --build _bld1 --verbose --target servers + cmake --build _bld1 --verbose --target tunits + + # HTTP/3 + export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix libnghttp3)/lib/pkgconfig:$(brew --prefix libngtcp2)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" + cmake -B _bld2 -G Ninja \ + -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DUSE_NGTCP2=ON \ + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON + cmake --build _bld2 --verbose + cmake --build _bld2 --verbose --target servers + + _bld1/src/curl --disable --version + _bld2/src/curl --disable --version fi - name: 'perform analysis' From f6ddc1fc1e25ff8ea866f90942719af898d0ef0c Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 15 Sep 2025 15:01:54 +0200 Subject: [PATCH 034/208] Makefile.example: simplify and make it configurable - build in a single step. - allow overriding all variables: source, target, compiler, libpaths, libs, flags. Example: ```shell LIBS= LDFLAGS= SRC=altsvc.c make -f Makefile.example ``` Closes #18554 --- docs/examples/Makefile.example | 37 +++++++++++++++------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/docs/examples/Makefile.example b/docs/examples/Makefile.example index 9738e94bb82d..f2994e73e1e4 100644 --- a/docs/examples/Makefile.example +++ b/docs/examples/Makefile.example @@ -22,34 +22,29 @@ # ########################################################################### -# What to call the final executable -TARGET = example +SRC ?= ftpget.c -# Which object files that the executable consists of -OBJS = ftpget.o +# What to call the final executable +TARGET ?= example # What compiler to use -CC = gcc +CC ?= gcc -# Compiler flags, -g for debug, -c to make an object file -CFLAGS = -c -g +# Compiler flags, -g for debug +CFLAGS ?= -g -# This should point to a directory that holds libcurl, if it is not -# in the system's standard lib dir -# We also set a -L to include the directory where we have the OpenSSL -# libraries -LDFLAGS = -L/home/dast/lib -L/usr/local/ssl/lib +# This should point to a directory that holds libcurl, if it is not in the +# system's standard lib dir +# We also set a -L to include the directory where we have the OpenSSL libraries +LDFLAGS ?= -L/home/dast/lib -L/usr/local/ssl/lib -# We need -lcurl for the curl stuff # We need -lsocket and -lnsl when on Solaris -# We need -lssl and -lcrypto when using libcurl with SSL support +# We need -lssl and -lcrypto when using libcurl with TLS support # We need -lpthread for the pthread example -LIBS = -lcurl -lsocket -lnsl -lssl -lcrypto +LIBS ?= -lsocket -lnsl -lssl -lcrypto +# We need -lcurl for the curl stuff +LIBS := -lcurl $(LIBS) # Link the target with all objects and libraries -$(TARGET) : $(OBJS) - $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS) - -# Compile the source files into object files -ftpget.o : ftpget.c - $(CC) $(CFLAGS) $< +$(TARGET) : $(SRC) + $(CC) -o $(TARGET) $(CFLAGS) $(LDFLAGS) $(LIBS) $< From 619307feb09fb48feb9a24bbe5655dfcc8f17a3a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 16 Sep 2025 10:49:14 +0200 Subject: [PATCH 035/208] cmake: fix building docs when the base directory contains `.3` Fixing: ``` ninja: error: '<...>/basedir.md/_bld/docs/libcurl/libcurl-symbols.md', needed by 'docs/libcurl/curl_easy_cleanup.3', missing and no known rule to make it ``` Reported-by: Nir Azkiel Fixes #18560 Follow-up to 898b012a9bf388590c4be7f526815b5ab74feca1 #1288 Closes #18563 --- docs/libcurl/CMakeLists.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/libcurl/CMakeLists.txt b/docs/libcurl/CMakeLists.txt index 2102dd8ee3b5..bee1021f7256 100644 --- a/docs/libcurl/CMakeLists.txt +++ b/docs/libcurl/CMakeLists.txt @@ -52,11 +52,9 @@ function(curl_add_manual_pages _listname) endif() list(APPEND _rofffiles "${CMAKE_CURRENT_BINARY_DIR}/${_file}") - if(_file STREQUAL "libcurl-symbols.3") - # Special case, an auto-generated file. - string(REPLACE ".3" ".md" _mdfile "${CMAKE_CURRENT_BINARY_DIR}/${_file}") - else() - string(REPLACE ".3" ".md" _mdfile "${_file}") + string(REPLACE ".3" ".md" _mdfile "${_file}") + if(_file STREQUAL "libcurl-symbols.3") # Special case for auto-generated file + set(_mdfile "${CMAKE_CURRENT_BINARY_DIR}/${_mdfile}") endif() list(APPEND _mdfiles "${_mdfile}") endforeach() From ea752b575c6ee984fb2a4d16a9dbf0d4f1e26282 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 16 Sep 2025 12:47:27 +0200 Subject: [PATCH 036/208] sws: fix checking `sscanf()` return value Closes #18565 --- tests/server/sws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/server/sws.c b/tests/server/sws.c index 2b94e529383f..a512a7a31e26 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -330,7 +330,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) size_t npath = 0; /* httppath length */ if(sscanf(line, - "%" REQUEST_KEYWORD_SIZE_TXT"s ", request)) { + "%" REQUEST_KEYWORD_SIZE_TXT"s ", request) == 1) { http = strstr(line + strlen(request), "HTTP/"); if(http && sscanf(http, "HTTP/%d.%d", From ff8dfd315c155960836105ad719185c3b4d547bd Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 16 Sep 2025 15:49:58 +0200 Subject: [PATCH 037/208] aws-lc: re-enable large read-ahead with v1.61.0 again AWS-LC fixed a bug with large read ahead buffers in v1.61.0. Check a define introduced in that version to enable the large read ahead again. AWS-LC issue: https://github.com/aws/aws-lc/issues/2650 Closes #18568 --- lib/vtls/openssl.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 5c22ad25dc94..af890b6c5795 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -121,14 +121,11 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #endif -/* - * AWS-LC has `SSL_CTX_set_default_read_buffer_len()?` but runs into - * decryption failures with large buffers. Sporadic failures in - * test_10_08 with h2 proxy uploads, increased frequency - * with CURL_DBG_SOCK_RBLOCK=50. Looks like a bug on their part. - */ +/* AWS-LC fixed a bug with large buffers in v1.61.0 which also introduced + * X509_V_ERR_EC_KEY_EXPLICIT_PARAMS. */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) && !defined(HAVE_BORINGSSL_LIKE) + !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && \ + (!defined(OPENSSL_IS_AWSLC) || (defined(X509_V_ERR_EC_KEY_EXPLICIT_PARAMS))) #define HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN 1 #endif From cdb56c6666e79fff211d91ee88b0c0e9a5a0dd23 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 16 Sep 2025 16:30:08 +0200 Subject: [PATCH 038/208] docs/libcurl: clarify some timeout option behavior Closes #18569 --- docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md | 9 +++++++-- docs/libcurl/opts/CURLOPT_FTPPORT.md | 1 + .../libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md | 13 ++++++------- .../opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md | 10 +++++----- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md index 8fdbc9663247..5dd19a708b13 100644 --- a/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md +++ b/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md @@ -8,6 +8,7 @@ See-also: - CURLOPT_CONNECTTIMEOUT_MS (3) - CURLOPT_DEBUGFUNCTION (3) - CURLOPT_STDERR (3) + - CURLOPT_FTPPORT (3) Protocol: - FTP Added-in: 7.24.0 @@ -28,7 +29,11 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ACCEPTTIMEOUT_MS, long ms); # DESCRIPTION Pass a long telling libcurl the maximum number of milliseconds to wait for a -server to connect back to libcurl when an active FTP connection is used. +server to connect back to libcurl when an active FTP connection is used. When +active FTP is used, the client (libcurl) tells the server to do a TCP connect +back to the client, instead of vice versa for passive FTP. + +This option has no purpose for passive FTP. # DEFAULT @@ -45,7 +50,7 @@ int main(void) if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/path/file"); - /* wait no more than 5 seconds for FTP server responses */ + /* wait no more than 5 seconds for the FTP server to connect */ curl_easy_setopt(curl, CURLOPT_ACCEPTTIMEOUT_MS, 5000L); curl_easy_perform(curl); diff --git a/docs/libcurl/opts/CURLOPT_FTPPORT.md b/docs/libcurl/opts/CURLOPT_FTPPORT.md index c5eee3c0ac73..59e4419512c5 100644 --- a/docs/libcurl/opts/CURLOPT_FTPPORT.md +++ b/docs/libcurl/opts/CURLOPT_FTPPORT.md @@ -9,6 +9,7 @@ Protocol: See-also: - CURLOPT_FTP_USE_EPRT (3) - CURLOPT_FTP_USE_EPSV (3) + - CURLOPT_ACCEPTTIMEOUT_MS (3) Added-in: 7.1 --- diff --git a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md index 3d6ba1f9aad4..30ae25b42ac5 100644 --- a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md +++ b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md @@ -33,13 +33,12 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SERVER_RESPONSE_TIMEOUT, # DESCRIPTION -Pass a long. Causes libcurl to set a *timeout* period (in seconds) on the -amount of time that the server is allowed to take in order to send a response -message for a command before the session is considered dead. While libcurl is -waiting for a response, this value overrides CURLOPT_TIMEOUT(3). It is -recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set -CURLOPT_SERVER_RESPONSE_TIMEOUT(3) to a value smaller than -CURLOPT_TIMEOUT(3). +Pass a long. It tells libcurl to wait no longer than *timeout* seconds for +responses on sent commands. If no response is received within this period, the +connection is considered dead and the transfer fails. + +It is recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set +CURLOPT_SERVER_RESPONSE_TIMEOUT(3) to a value smaller than CURLOPT_TIMEOUT(3). This option was formerly known as CURLOPT_FTP_RESPONSE_TIMEOUT. diff --git a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md index 7acbd105ec87..267659cde2db 100644 --- a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md +++ b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md @@ -33,11 +33,11 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, # DESCRIPTION -Pass a long. Causes libcurl to set a *timeout* period (in milliseconds) on the -amount of time that the server is allowed to take in order to send a response -message for a command before the session is considered dead. While libcurl is -waiting for a response, this value overrides CURLOPT_TIMEOUT(3). It is -recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set +Pass a long. It tells libcurl to wait no longer than *timeout* milliseconds +for responses on sent commands. If no response is received within this period, +the connection is considered dead and the transfer fails. + +It is recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3) to a value smaller than CURLOPT_TIMEOUT(3). From 22ac7f30ad1075295234a8f74f59f9ce9b173b1c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:13:10 +0000 Subject: [PATCH 039/208] GHA: update openssl/openssl to v3.5.3 Closes #18566 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 2fe8b8cdbba6..4ad880ddf6dc 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -42,7 +42,7 @@ env: MAKEFLAGS: -j 5 CURL_CI: github # handled in renovate.json - OPENSSL_VERSION: 3.5.2 + OPENSSL_VERSION: 3.5.3 # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index ed206ec03c42..70a6a259ab8d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -52,7 +52,7 @@ env: # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # handled in renovate.json - OPENSSL_VERSION: 3.5.2 + OPENSSL_VERSION: 3.5.3 # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=rustls/rustls-ffi versioning=semver registryUrl=https://github.com From 3053a3e90f696dc1cfb481c61a2032dcc3b6c15c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 16 Sep 2025 16:49:54 +0200 Subject: [PATCH 040/208] docs/libcurl: use lowercase must To shout less. Use bold in some places. Closes #18570 --- docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md | 4 ++-- docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md | 6 +++--- docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md | 6 +++--- docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md | 6 +++--- docs/libcurl/opts/CURLINFO_LOCAL_IP.md | 6 +++--- docs/libcurl/opts/CURLINFO_PRIMARY_IP.md | 6 +++--- docs/libcurl/opts/CURLINFO_REFERER.md | 6 +++--- docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md | 6 +++--- docs/libcurl/opts/CURLINFO_SCHEME.md | 6 +++--- docs/libcurl/opts/CURLOPT_HEADERDATA.md | 6 +++--- docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md | 12 ++++++------ docs/libcurl/opts/CURLOPT_SHARE.md | 13 ++++++------- docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md | 2 +- docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md | 2 +- docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md | 4 ++-- docs/libcurl/opts/CURLOPT_WRITEDATA.md | 2 +- 16 files changed, 46 insertions(+), 47 deletions(-) diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md b/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md index 71e9c5122cf7..8a9093ced2ff 100644 --- a/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md +++ b/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md @@ -33,8 +33,8 @@ object. This is the value read from the Content-Type: field. If you get NULL, it means that the server did not send a valid Content-Type header or that the protocol used does not support this. -The **ct** pointer is set to NULL or pointing to private memory. You MUST -NOT free it - it gets freed when you call curl_easy_cleanup(3) on the +The **ct** pointer is NULL or points to private memory. You **must not** free +it. It gets freed automatically when you call curl_easy_cleanup(3) on the corresponding curl handle. The modern way to get this header from a response is to instead use the diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md index 0a748063c642..5299dab8c16e 100644 --- a/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md +++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md @@ -35,9 +35,9 @@ method. In cases when you have asked libcurl to follow redirects, the method may not be the same method the first request would use. -The **methodp** pointer is NULL or points to private memory. You MUST NOT -free - it gets freed when you call curl_easy_cleanup(3) on the -corresponding curl handle. +The **methodp** pointer is NULL or points to private memory. You +**must not** free it. The memory gets freed automatically when you call +curl_easy_cleanup(3) on the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md index aa5090183464..172f6de3d46b 100644 --- a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md +++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md @@ -32,9 +32,9 @@ Pass in a pointer to a char pointer and get the last used effective URL. In cases when you have asked libcurl to follow redirects, it may not be the same value you set with CURLOPT_URL(3). -The **urlp** pointer is NULL or points to private memory. You MUST NOT free -- it gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **urlp** pointer is NULL or points to private memory. You **must not** +free it. It memory gets freed automatically when you call curl_easy_cleanup(3) +on the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md index 08b5a6d336ba..db053e311e75 100644 --- a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md +++ b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md @@ -32,9 +32,9 @@ path of the entry path. That is the initial path libcurl ended up in when logging on to the remote FTP or SFTP server. This stores a NULL as pointer if something is wrong. -The **path** pointer is NULL or points to private memory. You MUST NOT free -- it gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **path** pointer is NULL or points to private memory. You **must not** +free it. The memory gets freed automatically when you call +curl_easy_cleanup(3) on the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_LOCAL_IP.md b/docs/libcurl/opts/CURLINFO_LOCAL_IP.md index a8b89914a0bc..c626815c9003 100644 --- a/docs/libcurl/opts/CURLINFO_LOCAL_IP.md +++ b/docs/libcurl/opts/CURLINFO_LOCAL_IP.md @@ -35,9 +35,9 @@ with this **curl** handle. This string may be IPv6 when that is enabled. Note that you get a pointer to a memory area that is reused at next request so you need to copy the string if you want to keep the information. -The **ip** pointer is NULL or points to private memory. You MUST NOT free - it -gets freed when you call curl_easy_cleanup(3) on the corresponding CURL -handle. +The **ip** pointer is NULL or points to private memory. You **must not** free +it. The memory gets freed automatically when you call curl_easy_cleanup(3) on +the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md b/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md index e87be53e3c73..1fdb130711e4 100644 --- a/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md +++ b/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md @@ -35,9 +35,9 @@ string holding the IP address of the most recent connection done with this get a pointer to a memory area that is reused at next request so you need to copy the string if you want to keep the information. -The **ip** pointer is NULL or points to private memory. You MUST NOT free - it -gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **ip** pointer is NULL or points to private memory. You **must not** free +it. The memory gets freed automatically when you call curl_easy_cleanup(3) on +the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_REFERER.md b/docs/libcurl/opts/CURLINFO_REFERER.md index bd278dd60348..17b9db1a18a3 100644 --- a/docs/libcurl/opts/CURLINFO_REFERER.md +++ b/docs/libcurl/opts/CURLINFO_REFERER.md @@ -31,9 +31,9 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REFERER, char **hdrp); Pass in a pointer to a char pointer and get the referrer header used in the most recent request. -The **hdrp** pointer is NULL or points to private memory you MUST NOT free - -it gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **hdrp** pointer is NULL or points to private memory. You **must not** +free it. The memory gets freed automatically when you call +curl_easy_cleanup(3) on the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md b/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md index c24f42b24d13..121642677b78 100644 --- a/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md +++ b/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md @@ -33,9 +33,9 @@ most recent RTSP Session ID. Applications wishing to resume an RTSP session on another connection should retrieve this info before closing the active connection. -The **id** pointer is NULL or points to private memory. You MUST NOT free - it -gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **id** pointer is NULL or points to private memory. You **must not** free +it. The memory gets freed automatically when you call curl_easy_cleanup(3) on +the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_SCHEME.md b/docs/libcurl/opts/CURLINFO_SCHEME.md index 0089531d012b..1c61849829af 100644 --- a/docs/libcurl/opts/CURLINFO_SCHEME.md +++ b/docs/libcurl/opts/CURLINFO_SCHEME.md @@ -33,9 +33,9 @@ Pass a pointer to a char pointer to receive the pointer to a null-terminated string holding the URL scheme used for the most recent connection done with this CURL **handle**. -The **scheme** pointer is NULL or points to private memory. You MUST NOT -free - it gets freed when you call curl_easy_cleanup(3) on the corresponding -curl handle. +The **scheme** pointer is NULL or points to private memory. You **must not** +free it. The memory gets freed automatically when you call +curl_easy_cleanup(3) on the corresponding curl handle. The returned scheme might be upper or lowercase. Do comparisons case insensitively. diff --git a/docs/libcurl/opts/CURLOPT_HEADERDATA.md b/docs/libcurl/opts/CURLOPT_HEADERDATA.md index bb3f2ed83474..f767961cdc37 100644 --- a/docs/libcurl/opts/CURLOPT_HEADERDATA.md +++ b/docs/libcurl/opts/CURLOPT_HEADERDATA.md @@ -36,9 +36,9 @@ If CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) is used, If neither of those options are set, *pointer* must be a valid FILE * and it is used by a plain fwrite() to write headers to. -If you are using libcurl as a Windows DLL, you **MUST** use a -CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) if you set -this option or you might experience crashes. +If you are using libcurl as a Windows DLL, you **must** use a +CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) if you set this option +or you might experience crashes. # DEFAULT diff --git a/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md b/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md index 29dc8bb4ff75..d2dda82dd8e3 100644 --- a/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md @@ -50,15 +50,15 @@ rewinding the read data stream is the only action it can request. The rewinding of the read data stream may be necessary when doing an HTTP PUT or POST with a multi-pass authentication method. -The callback MUST return *CURLIOE_UNKNOWNCMD* if the input *cmd* is -not *CURLIOCMD_RESTARTREAD*. +The callback **must** return *CURLIOE_UNKNOWNCMD* if the input *cmd* is not +*CURLIOCMD_RESTARTREAD*. -The *clientp* argument to the callback is set with the -CURLOPT_IOCTLDATA(3) option. +The *clientp* argument to the callback is set with the CURLOPT_IOCTLDATA(3) +option. **This option is deprecated**. Do not use it. Use CURLOPT_SEEKFUNCTION(3) -instead to provide seeking. If CURLOPT_SEEKFUNCTION(3) is set, this -parameter is ignored when seeking. +instead to provide seeking. If CURLOPT_SEEKFUNCTION(3) is set, this parameter +is ignored when seeking. # DEFAULT diff --git a/docs/libcurl/opts/CURLOPT_SHARE.md b/docs/libcurl/opts/CURLOPT_SHARE.md index c4488086a7e5..9b9a281e00be 100644 --- a/docs/libcurl/opts/CURLOPT_SHARE.md +++ b/docs/libcurl/opts/CURLOPT_SHARE.md @@ -26,13 +26,12 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SHARE, CURLSH *share); # DESCRIPTION -Pass a *share* handle as a parameter. The share handle must have been -created by a previous call to curl_share_init(3). Setting this option, -makes this curl handle use the data from the shared handle instead of keeping -the data to itself. This enables several curl handles to share data. If the -curl handles are used simultaneously in multiple threads, you **MUST** use -the locking methods in the share handle. See curl_share_setopt(3) for -details. +Pass a *share* handle as a parameter. The share handle must have been created +by a previous call to curl_share_init(3). Setting this option, makes this curl +handle use the data from the shared handle instead of keeping the data to +itself. This enables several curl handles to share data. If the curl handles +are used simultaneously in multiple threads, you **must** use the locking +methods in the share handle. See curl_share_setopt(3) for details. If you add a share that is set to share cookies, your easy handle uses that cookie cache and get the cookie engine enabled. If you stop sharing an object diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md index 89422e4ef65d..0f7e9996bd57 100644 --- a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md @@ -44,7 +44,7 @@ says what type it is, from the **CURLKHTYPE_*** series in the **clientp** is a custom pointer set with CURLOPT_SSH_HOSTKEYDATA(3). -The callback MUST return one of the following return codes to tell libcurl how +The callback must return one of the following return codes to tell libcurl how to act: ## CURLKHMATCH_OK diff --git a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md index 636b7a3609cc..1e21b614f136 100644 --- a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md @@ -68,7 +68,7 @@ called if CURLOPT_SSH_KNOWNHOSTS(3) is also set. This callback function gets passed the curl handle, the key from the known_hosts file *knownkey*, the key from the remote site *foundkey*, info from libcurl on the matching status and a custom pointer (set with -CURLOPT_SSH_KEYDATA(3)). It MUST return one of the following return codes to +CURLOPT_SSH_KEYDATA(3)). It must return one of the following return codes to tell libcurl how to act: ## CURLKHSTAT_FINE_REPLACE diff --git a/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md b/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md index 262c0897942e..07e7266da5c7 100644 --- a/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md +++ b/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md @@ -35,8 +35,8 @@ HTTP response sent using a compressed Transfer-Encoding that is automatically uncompressed by libcurl on reception. Transfer-Encoding differs slightly from the Content-Encoding you ask for with -CURLOPT_ACCEPT_ENCODING(3) in that a Transfer-Encoding is strictly meant -to be for the transfer and thus MUST be decoded before the data arrives in the +CURLOPT_ACCEPT_ENCODING(3) in that a Transfer-Encoding is strictly meant to be +for the transfer and thus must be decoded before the data arrives in the client. Traditionally, Transfer-Encoding has been much less used and supported by both HTTP clients and HTTP servers. diff --git a/docs/libcurl/opts/CURLOPT_WRITEDATA.md b/docs/libcurl/opts/CURLOPT_WRITEDATA.md index 5983de5d27fc..f6c6a2eeb9f1 100644 --- a/docs/libcurl/opts/CURLOPT_WRITEDATA.md +++ b/docs/libcurl/opts/CURLOPT_WRITEDATA.md @@ -36,7 +36,7 @@ to *fwrite(3)* when writing data. The internal CURLOPT_WRITEFUNCTION(3) writes the data to the FILE * given with this option, or to stdout if this option has not been set. -If you are using libcurl as a Windows DLL, you **MUST** use a +If you are using libcurl as a Windows DLL, you must also use CURLOPT_WRITEFUNCTION(3) if you set this option or you might experience crashes. From 92361999086712c7ae6ca59930cdac204e0db2a2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 08:25:42 +0200 Subject: [PATCH 041/208] setopt: make CURLOPT_MAXREDIRS accept -1 (again) Regression from b059f7d (shipped in 8.16.0) Reported-by: Adam Light Fixes #18571 Closes #18576 --- lib/setopt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/setopt.c b/lib/setopt.c index 6f98e7dce4e3..d7a7f6c52d89 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -955,7 +955,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, break; case CURLOPT_MAXREDIRS: - result = value_range(&arg, -1, 0, 0x7fff); + result = value_range(&arg, -1, -1, 0x7fff); if(result) return result; s->maxredirs = (short)arg; From 04e08664a8e392b05a79cd710ef43fe0de7c1797 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 10:30:31 +0200 Subject: [PATCH 042/208] RELEASE-NOTES: synced --- RELEASE-NOTES | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 58d8fe6d02d4..c6fb253c75f3 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,24 +4,39 @@ curl and libcurl 8.16.1 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3500 + Contributors: 3502 This release includes the following changes: This release includes the following bugfixes: + o asyn-thrdd: drop pthread_cancel [30] + o aws-lc: re-enable large read-ahead with v1.61.0 again [16] + o cmake: fix building docs when the base directory contains `.3` [18] + o cmdline-docs: extended, clarified, refreshed [28] o curl_easy_getinfo: error code on NULL arg [2] o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] o CURLOPT_MAXLIFETIME_CONN: make default 24 hours [10] + o CURLOPT_SSL_VERIFYHOST.md: add see-also to two other VERIFYHOST options [32] + o CURLOPT_TIMECONDITION.md: works for FILE and FTP as well [27] + o dist: do not distribute `CI.md` [29] + o docs/libcurl: clarify some timeout option behavior [15] o docs/libcurl: remove ancient version references [7] + o docs/libcurl: use lowercase must [5] o easy_getinfo: check magic, Curl_close safety [3] + o krb5: return appropriate error on send failures [22] o libcurl-security.md: mention long-running connections [6] + o Makefile.example: simplify and make it configurable [20] o ngtcp2: check error code on connect failure [13] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o setopt: accept *_SSL_VERIFYHOST set to 2L [31] + o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o ssl-sessions.md: mark option experimental [12] + o sws: fix checking `sscanf()` return value [17] + o TODO: remove already implemented or bad items [36] o urldata: FILE is not a list-only protocol [9] This release includes the following known bugs: @@ -46,16 +61,19 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Andrew Kirillov, Dan Fandrich, Daniel Stenberg, Emilio Pozuelo Monfort, - Ethan Everett, fds242 on github, renovate[bot], Stefan Eissing, + Adam Light, Andrew Kirillov, Dan Fandrich, Daniel Stenberg, dependabot[bot], + Emilio Pozuelo Monfort, Ethan Everett, fds242 on github, Javier Blazquez, + Jicea, Nir Azkiel, renovate[bot], Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats - (9 contributors) + (15 contributors) References to bug reports and discussions on issues: + [1] = https://curl.se/bug/?i=18571 [2] = https://curl.se/bug/?i=18512 [3] = https://curl.se/bug/?i=18511 [4] = https://curl.se/bug/?i=18505 + [5] = https://curl.se/bug/?i=18570 [6] = https://curl.se/bug/?i=18533 [7] = https://curl.se/bug/?i=18530 [8] = https://curl.se/bug/?i=18531 @@ -64,4 +82,17 @@ References to bug reports and discussions on issues: [12] = https://curl.se/bug/?i=18523 [13] = https://curl.se/bug/?i=18521 [14] = https://curl.se/bug/?i=18518 + [15] = https://curl.se/bug/?i=18569 + [16] = https://curl.se/bug/?i=18568 + [17] = https://curl.se/bug/?i=18565 + [18] = https://curl.se/bug/?i=18560 [19] = https://curl.se/bug/?i=18510 + [20] = https://curl.se/bug/?i=18554 + [22] = https://curl.se/bug/?i=18561 + [27] = https://curl.se/bug/?i=18551 + [28] = https://curl.se/bug/?i=18550 + [29] = https://curl.se/bug/?i=18549 + [30] = https://curl.se/bug/?i=18532 + [31] = https://curl.se/mail/lib-2025-09/0031.html + [32] = https://curl.se/bug/?i=18548 + [36] = https://curl.se/bug/?i=18542 From 0a27a506b1f1ff926dd94766434dcc8ff4c12bb4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 13:02:01 +0200 Subject: [PATCH 043/208] managen: ignore version mentions < 7.66.0 Only mention version specific details for versions from within the last six years. Closes #18583 --- scripts/managen | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/managen b/scripts/managen index 1eb536a0e6d7..768c632d4bdf 100755 --- a/scripts/managen +++ b/scripts/managen @@ -265,8 +265,8 @@ sub too_old { elsif($version =~ /^(\d+)\.(\d+)/) { $a = $1 * 1000 + $2 * 10; } - if($a < 7600) { - # we consider everything before 7.60.0 to be too old to mention + if($a < 7660) { + # we consider everything before 7.66.0 to be too old to mention # specific changes for return 1; } From dbe4e28d57f76b5ad96241bc5865d043679575d8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 11:53:33 +0200 Subject: [PATCH 044/208] managen: render better manpage references/links - When an option name is used in text, this script no longer outputs the short plus long version in the manpage output. It makes the text much more readable. This always showing both verions was previously done primarily to make sure roffit would linkify it correctly, but since roffit 0.17 it should link both long or short names correctly. - When managen outputs generic text about options at the end of the description it now highlights them properly so that they too get linkified correctly in the HTML version. For consistency. Closes #18580 --- scripts/managen | 55 ++++++++++++++++++++++++--------------------- tests/data/test1705 | 8 +++---- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/scripts/managen b/scripts/managen index 768c632d4bdf..929068067099 100755 --- a/scripts/managen +++ b/scripts/managen @@ -66,8 +66,7 @@ my $indent = 4; # get the long name version, return the manpage string sub manpageify { - my ($k)=@_; - my $l; + my ($k, $manpage)=@_; my $trail = ''; # the matching pattern might include a trailing dot that cannot be part of # the option name @@ -75,18 +74,15 @@ sub manpageify { # cut off trailing dot $trail = "."; } - my $klong = $k; - # quote "bare" minuses in the long name - $klong =~ s/-/\\-/g; - if($optlong{$k}) { - # both short + long - $l = "\\fI-".$optlong{$k}.", \\-\\-$klong\\fP$trail"; - } - else { + if($manpage) { + my $klong = $k; + # quote "bare" minuses in the long name + $klong =~ s/-/\\-/g; + # only long - $l = "\\fI\\-\\-$klong\\fP$trail"; + return "\\fI\\-\\-$klong\\fP$trail"; } - return $l; + return "--$k$trail"; } @@ -477,7 +473,7 @@ sub render { if($manpage) { if(!$quote && $d =~ /--/) { - $d =~ s/--([a-z0-9.-]+)/manpageify($1)/ge; + $d =~ s/--([a-z0-9.-]+)/manpageify($1, 1)/ge; } # quote minuses in the output @@ -741,7 +737,9 @@ sub single { } if($scope eq "global") { push @desc, "\n" if(!$manpage); - push @desc, "${pre}This option is global and does not need to be specified for each use of --next.\n"; + push @desc, + sprintf("${pre}This option is global and does not need to be specified for each use of %s.\n", + manpageify("next", $manpage)); } else { print STDERR "$f:$line:1:ERROR: unrecognized scope: '$scope'\n"; @@ -751,11 +749,15 @@ sub single { my @extra; if($multi eq "single") { - push @extra, "${pre}If --$long is provided several times, the last set ". - "value is used.\n"; + push @extra, + sprintf("${pre}If %s is provided several times, the last set ". + "value is used.\n", + manpageify($long, $manpage)); } elsif($multi eq "append") { - push @extra, "${pre}--$long can be used several times in a command line\n"; + push @extra, + sprintf("${pre}%s can be used several times in a command line\n", + manpageify($long, $manpage)); } elsif($multi eq "boolean") { my $rev = "no-$long"; @@ -767,20 +769,23 @@ sub single { } my $dashes = $manpage ? "\\-\\-" : "--"; push @extra, - "${pre}Providing --$long multiple times has no extra effect.\n". - "Disable it again with $dashes$rev.\n"; + sprintf("${pre}Providing %s multiple times has no extra effect.\n". + "Disable it again with $dashes$rev.\n", + manpageify($long, $manpage)); } elsif($multi eq "mutex") { push @extra, - "${pre}Providing --$long multiple times has no extra effect.\n"; + sprintf("${pre}Providing %s multiple times has no extra effect.\n", + manpageify($long, $manpage)); } elsif($multi eq "custom") { ; # left for the text to describe } elsif($multi eq "per-URL") { push @extra, - "${pre}--$long is associated with a single URL. Use it once per URL ". - "when you use several URLs in a command line.\n"; + sprintf("${pre}%s is associated with a single URL. Use it once per URL ". + "when you use several URLs in a command line.\n", + manpageify($long, $manpage)); } else { print STDERR "$f:$line:1:ERROR: unrecognized Multi: '$multi'\n"; @@ -804,7 +809,7 @@ sub single { if(!$helplong{$k}) { print STDERR "$f:$line:1:WARN: see-also a non-existing option: $k\n"; } - my $l = $manpage ? manpageify($k) : "--$k"; + my $l = manpageify($k, $manpage); my $sep = " and"; if($and && ($i < $and)) { $sep = ","; @@ -814,7 +819,7 @@ sub single { } if($requires) { - my $l = $manpage ? manpageify($long) : "--$long"; + my $l = manpageify($long, $manpage); push @foot, "$l requires that libcurl". " is built to support $requires.\n"; } @@ -827,7 +832,7 @@ sub single { if(!$helplong{$k}) { print STDERR "WARN: $f mutexes a non-existing option: $k\n"; } - my $l = $manpage ? manpageify($k) : "--$k"; + my $l = manpageify($k, $manpage); my $sep = ", "; if($count == ($num -1)) { $sep = " and "; diff --git a/tests/data/test1705 b/tests/data/test1705 index b56982ae40f5..7c21ffa34939 100644 --- a/tests/data/test1705 +++ b/tests/data/test1705 @@ -224,9 +224,9 @@ End with a quote hello .fi -This option is global and does not need to be specified for each use of --next. +This option is global and does not need to be specified for each use of \fI\-\-next\fP. -Providing --fakeitreal multiple times has no extra effect. +Providing \fI\-\-fakeitreal\fP multiple times has no extra effect. Disable it again with \-\-no-fakeitreal. Example: @@ -265,14 +265,14 @@ relying upon support for that protocol being built into curl to avoid an error. This option can be used multiple times, in which case the effect is the same as concatenating the protocols into one instance of the option. -If --proto is provided several times, the last set value is used. +If \fI\-\-proto\fP is provided several times, the last set value is used. Example: .nf curl --proto =http,https,sftp https://example.com .fi -See also \fI-v, \-\-fakeitreal\fP and \fI\-\-proto\-default\fP. +See also \fI\-\-fakeitreal\fP and \fI\-\-proto\-default\fP. .SH PROXY PROTOCOL PREFIXES The proxy string may be specified with a protocol:// prefix to specify alternative proxy protocols. From 0f067ba4aa30b681a0e92761e003936470340fd5 Mon Sep 17 00:00:00 2001 From: Christian Schmitz Date: Wed, 17 Sep 2025 11:04:47 +0200 Subject: [PATCH 045/208] libcurl-multi.md: added curl_multi_get_offt mention The multi interface page didn't mention the new curl_multi_get_offt function. Closes #18579 --- docs/libcurl/libcurl-multi.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/libcurl/libcurl-multi.md b/docs/libcurl/libcurl-multi.md index 3becb648defd..27f153b8ade3 100644 --- a/docs/libcurl/libcurl-multi.md +++ b/docs/libcurl/libcurl-multi.md @@ -166,7 +166,9 @@ get activity on the sockets you have been asked to wait on, or if the timeout timer expires. You can poll curl_multi_info_read(3) to see if any transfer has -completed, as it then has a message saying so. +completed, as it then has a message saying so. To know how many transfers are +currently queued, running, pending or done, you can use the +curl_multi_get_offt(3) function. # BLOCKING From 74fdc1185f40c2fe2253043ff3f563fbbd4b43ed Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Wed, 17 Sep 2025 20:33:25 +0200 Subject: [PATCH 046/208] configure: add "-mt" for pthread support on HP-UX HP-UX requires this compiler and linker flag to pass proper macros and add required libraries. Closes #18585 --- configure.ac | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index af005beffd12..3f02d037ef3d 100644 --- a/configure.ac +++ b/configure.ac @@ -4340,11 +4340,9 @@ if test "$want_threaded_resolver" = "yes" && test "$USE_THREADS_WIN32" != "1"; t AC_CHECK_FUNC(pthread_create, [USE_THREADS_POSIX=1] ) LIBS="$save_LIBS" - dnl on HP-UX, life is more complicated... case $host in *-hp-hpux*) - dnl it doesn't actually work without -lpthread - USE_THREADS_POSIX="" + CFLAGS="$CFLAGS -mt" ;; *) ;; From 3031fae3bd5135853133b95cd5396e93925a23bf Mon Sep 17 00:00:00 2001 From: Christian Schmitz Date: Wed, 17 Sep 2025 10:11:59 +0200 Subject: [PATCH 047/208] multi.h: add CURLMINFO_LASTENTRY For multiple enums, we use LASTENTRY values to do range checks when receiving an option as integer. So I added LASTENTRY, so the check will work, even if you add more options later. Closes #18578 --- include/curl/multi.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/curl/multi.h b/include/curl/multi.h index 782541f1abbd..99e4413c9fe9 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -464,7 +464,9 @@ typedef enum { * be read via `curl_multi_info_read()`. */ CURLMINFO_XFERS_DONE = 4, /* The total number of easy handles added to the multi handle, ever. */ - CURLMINFO_XFERS_ADDED = 5 + CURLMINFO_XFERS_ADDED = 5, + + CURLMINFO_LASTENTRY /* the last unused */ } CURLMinfo_offt; /* From a827e4294cee78e2169555d4d99c6c5d583d51bc Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 23:22:36 +0200 Subject: [PATCH 048/208] smtp: check EHLO responses case insensitively Adjust test 980 to announce starttls in lowercase. Fixes #18588 Reported-by: Joshua Rogers Closes #18589 --- lib/smtp.c | 8 ++++---- tests/data/test980 | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/smtp.c b/lib/smtp.c index 5dba1f9ea8c2..84ff693a3c4e 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -989,19 +989,19 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data, len -= 4; /* Does the server support the STARTTLS capability? */ - if(len >= 8 && !memcmp(line, "STARTTLS", 8)) + if(len >= 8 && curl_strnequal(line, "STARTTLS", 8)) smtpc->tls_supported = TRUE; /* Does the server support the SIZE capability? */ - else if(len >= 4 && !memcmp(line, "SIZE", 4)) + else if(len >= 4 && curl_strnequal(line, "SIZE", 4)) smtpc->size_supported = TRUE; /* Does the server support the UTF-8 capability? */ - else if(len >= 8 && !memcmp(line, "SMTPUTF8", 8)) + else if(len >= 8 && curl_strnequal(line, "SMTPUTF8", 8)) smtpc->utf8_supported = TRUE; /* Does the server support authentication? */ - else if(len >= 5 && !memcmp(line, "AUTH ", 5)) { + else if(len >= 5 && curl_strnequal(line, "AUTH ", 5)) { smtpc->auth_supported = TRUE; /* Advance past the AUTH keyword */ diff --git a/tests/data/test980 b/tests/data/test980 index 5811b437d411..8a52559472ba 100644 --- a/tests/data/test980 +++ b/tests/data/test980 @@ -10,7 +10,7 @@ STARTTLS # Server-side -CAPA STARTTLS +CAPA starttls AUTH PLAIN REPLY STARTTLS 454 currently unavailable\r\n235 Authenticated\r\n250 2.1.0 Sender ok\r\n250 2.1.5 Recipient ok\r\n354 Enter mail\r\n250 2.0.0 Accepted REPLY AUTH 535 5.7.8 Authentication credentials invalid From 20f757ef140a8466e888e6f395461a3ea73daf41 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Thu, 18 Sep 2025 06:45:12 +0500 Subject: [PATCH 049/208] tool_cb_hdr: fix fwrite check in header callback Compare fwrite result to nmemb (items), not cb (bytes). Closes #18593 --- src/tool_cb_hdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c index 6af9d1947e1e..3bb3c12dc806 100644 --- a/src/tool_cb_hdr.c +++ b/src/tool_cb_hdr.c @@ -116,7 +116,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) if(per->config->headerfile && heads->stream) { size_t rc = fwrite(ptr, size, nmemb, heads->stream); - if(rc != cb) + if(rc != nmemb) return rc; /* flush the stream to send off what we got earlier */ if(fflush(heads->stream)) { From 4e74b9f592b7e0775800f212052c18c44128f89b Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Thu, 18 Sep 2025 03:43:11 +0500 Subject: [PATCH 050/208] socks_sspi: restore non-blocking socket on error paths Closes #18592 --- lib/socks_sspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 49210585b0f0..c106fec0c8fb 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -559,6 +559,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, */ return CURLE_OK; error: + (void)curlx_nonblock(sock, TRUE); free(service_name); Curl_pSecFn->FreeCredentialsHandle(&cred_handle); Curl_pSecFn->DeleteSecurityContext(&sspi_context); From ca034e839c92570b6cece09b63624af41f39e77b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 08:49:22 +0200 Subject: [PATCH 051/208] tool: fix exponential retry delay Also, show retry delay with decimals since it might be not be integer seconds. Regression from da27db068fc888d7091d347080 (shipped in 8.16.0) Reported-by: Andrew Olsen Fixes #18591 Assisted-by: Jay Satiro Closes #18595 --- src/tool_cfgable.c | 1 - src/tool_cfgable.h | 3 ++- src/tool_operate.c | 21 ++++++++++++++------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 0321848b0d5a..675f4d2d9da9 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -52,7 +52,6 @@ struct OperationConfig *config_alloc(void) config->ftp_skip_ip = TRUE; config->file_clobber_mode = CLOBBER_DEFAULT; config->upload_flags = CURLULFLAG_SEEN; - config->retry_delay_ms = RETRY_SLEEP_DEFAULT; curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY); return config; } diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 5e7222a8a86d..3b2ac93a74de 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -209,7 +209,8 @@ struct OperationConfig { long httpversion; unsigned long socks5_auth;/* auth bitmask for socks5 proxies */ long req_retry; /* number of retries */ - long retry_delay_ms; /* delay between retries (in milliseconds) */ + long retry_delay_ms; /* delay between retries (in milliseconds), + 0 means increase exponentially */ long retry_maxtime_ms; /* maximum time to keep retrying */ unsigned long mime_options; /* Mime option flags. */ diff --git a/src/tool_operate.c b/src/tool_operate.c index 2c3030096f6a..4337cdee6006 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -437,7 +437,6 @@ static CURLcode retrycheck(struct OperationConfig *config, ": FTP error" }; - sleeptime = per->retry_sleep; if(RETRY_HTTP == retry) { curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after); if(retry_after) { @@ -464,20 +463,28 @@ static CURLcode retrycheck(struct OperationConfig *config, } } } + if(!sleeptime && !config->retry_delay_ms) { + if(!per->retry_sleep) + per->retry_sleep = RETRY_SLEEP_DEFAULT; + else + per->retry_sleep *= 2; + if(per->retry_sleep > RETRY_SLEEP_MAX) + per->retry_sleep = RETRY_SLEEP_MAX; + } + if(!sleeptime) + sleeptime = per->retry_sleep; warnf("Problem %s. " - "Will retry in %ld second%s. " + "Will retry in %ld%s%.*ld second%s. " "%ld retr%s left.", m[retry], sleeptime/1000L, + (sleeptime%1000L ? "." : ""), + (sleeptime%1000L ? 3 : 0), + sleeptime%1000L, (sleeptime/1000L == 1 ? "" : "s"), per->retry_remaining, (per->retry_remaining > 1 ? "ies" : "y")); per->retry_remaining--; - if(!config->retry_delay_ms) { - per->retry_sleep *= 2; - if(per->retry_sleep > RETRY_SLEEP_MAX) - per->retry_sleep = RETRY_SLEEP_MAX; - } if(outs->bytes && outs->filename && outs->stream) { #ifndef __MINGW32CE__ From 0f0821133095cf8b6efdfd98c71a09fccb34ac78 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 18 Sep 2025 11:10:45 +0200 Subject: [PATCH 052/208] cfilter: unlink and discard Rewrite the code that removes a filter from the connection and discards it. Always look at the connection, otherwise it will not work of the filter is at the top of the chain. Change QUIC filter setup code to always tear down the chain in construction when an error occured. HTTP proxy, do not remove the h1/h2 sub filter on close. Leave it to be discarded with the connection. Avoids keeping an additional pointer that might become dangling. Triggered by a reported on a code bug in discard method. Reported-by: Joshua Rogers Closes #18596 --- lib/cfilters.c | 37 +++++++++++++++++-------------------- lib/cfilters.h | 16 ++++++---------- lib/http_proxy.c | 28 ++++------------------------ lib/vquic/curl_ngtcp2.c | 20 +++++++++----------- lib/vquic/curl_osslq.c | 19 +++++++++---------- lib/vquic/curl_quiche.c | 19 +++++++++---------- lib/vtls/vtls.c | 2 +- 7 files changed, 55 insertions(+), 86 deletions(-) diff --git a/lib/cfilters.c b/lib/cfilters.c index efd2ac6f63d4..07f3c5f7b462 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -383,29 +383,26 @@ void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at, *pnext = tail; } -bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf, - struct Curl_cfilter *discard, - struct Curl_easy *data, - bool destroy_always) +bool Curl_conn_cf_discard(struct Curl_cfilter **pcf, + struct Curl_easy *data) { - struct Curl_cfilter **pprev = &cf->next; + struct Curl_cfilter *cf = pcf ? *pcf : NULL; bool found = FALSE; - - /* remove from sub-chain and destroy */ - DEBUGASSERT(cf); - while(*pprev) { - if(*pprev == cf) { - *pprev = discard->next; - discard->next = NULL; - found = TRUE; - break; + if(cf) { + if(cf->conn) { + /* unlink if present in connection filter chain */ + struct Curl_cfilter **pprev = &cf->conn->cfilter[cf->sockindex]; + while(*pprev) { + if(*pprev == *pcf) { + *pprev = (*pcf)->next; + cf->next = NULL; + found = TRUE; + break; + } + pprev = &((*pprev)->next); + } } - pprev = &((*pprev)->next); - } - if(found || destroy_always) { - discard->next = NULL; - discard->cft->destroy(discard, data); - free(discard); + Curl_conn_cf_discard_chain(pcf, data); } return found; } diff --git a/lib/cfilters.h b/lib/cfilters.h index 815b72a6e801..af38191a931d 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -297,16 +297,12 @@ void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at, struct Curl_cfilter *cf_new); /** - * Discard, e.g. remove and destroy `discard` iff - * it still is in the filter chain below `cf`. If `discard` - * is no longer found beneath `cf` return FALSE. - * if `destroy_always` is TRUE, will call `discard`s destroy - * function and free it even if not found in the subchain. - */ -bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf, - struct Curl_cfilter *discard, - struct Curl_easy *data, - bool destroy_always); + * Extract filter `*pcf` from its connection filter chain. + * Destroy `*pcf`, even if it was not part of the chain and NULL it. + * Returns TRUE of cf has been part of chain. + */ +bool Curl_conn_cf_discard(struct Curl_cfilter **pcf, + struct Curl_easy *data); /** * Discard all cfilters starting with `*pcf` and clearing it afterwards. diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 2d742856ce81..b756efe711b4 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -215,9 +215,8 @@ CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf, } struct cf_proxy_ctx { - /* the protocol specific sub-filter we install during connect */ - struct Curl_cfilter *cf_protocol; int httpversion; /* HTTP version used to CONNECT */ + BIT(sub_filter_installed); }; CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, @@ -317,8 +316,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, return result; *done = FALSE; - if(!ctx->cf_protocol) { - struct Curl_cfilter *cf_protocol = NULL; + if(!ctx->sub_filter_installed) { int httpversion = 0; const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data); @@ -332,7 +330,6 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, result = Curl_cf_h1_proxy_insert_after(cf, data); if(result) goto out; - cf_protocol = cf->next; httpversion = 10; } else if(!alpn || !strcmp(alpn, "http/1.1")) { @@ -340,7 +337,6 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, result = Curl_cf_h1_proxy_insert_after(cf, data); if(result) goto out; - cf_protocol = cf->next; /* Assume that without an ALPN, we are talking to an ancient one */ httpversion = 11; } @@ -350,7 +346,6 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, result = Curl_cf_h2_proxy_insert_after(cf, data); if(result) goto out; - cf_protocol = cf->next; httpversion = 20; } #endif @@ -360,7 +355,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, goto out; } - ctx->cf_protocol = cf_protocol; + ctx->sub_filter_installed = TRUE; ctx->httpversion = httpversion; /* after we installed the filter "below" us, we call connect * on out sub-chain again. @@ -371,7 +366,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, /* subchain connected and we had already installed the protocol filter. * This means the protocol tunnel is established, we are done. */ - DEBUGASSERT(ctx->cf_protocol); + DEBUGASSERT(ctx->sub_filter_installed); result = CURLE_OK; } @@ -419,23 +414,8 @@ static void http_proxy_cf_destroy(struct Curl_cfilter *cf, static void http_proxy_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct cf_proxy_ctx *ctx = cf->ctx; - CURL_TRC_CF(data, cf, "close"); cf->connected = FALSE; - if(ctx->cf_protocol) { - struct Curl_cfilter *f; - /* if someone already removed it, we assume he also - * took care of destroying it. */ - for(f = cf->next; f; f = f->next) { - if(f == ctx->cf_protocol) { - /* still in our sub-chain */ - Curl_conn_cf_discard_sub(cf, ctx->cf_protocol, data, FALSE); - break; - } - } - ctx->cf_protocol = NULL; - } if(cf->next) cf->next->cft->do_close(cf->next, data); } diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 4191924b5ab9..6cadc8fc58d1 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2767,7 +2767,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, const struct Curl_addrinfo *ai) { struct cf_ngtcp2_ctx *ctx = NULL; - struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + struct Curl_cfilter *cf = NULL; CURLcode result; (void)data; @@ -2781,23 +2781,21 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) goto out; + cf->conn = conn; - result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC); if(result) goto out; - - cf->conn = conn; - udp_cf->conn = cf->conn; - udp_cf->sockindex = cf->sockindex; - cf->next = udp_cf; + cf->next->conn = cf->conn; + cf->next->sockindex = cf->sockindex; out: *pcf = (!result) ? cf : NULL; if(result) { - if(udp_cf) - Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); - Curl_safefree(cf); - cf_ngtcp2_ctx_free(ctx); + if(cf) + Curl_conn_cf_discard_chain(&cf, data); + else if(ctx) + cf_ngtcp2_ctx_free(ctx); } return result; } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index e82cbf2a3eaa..c292072a65b6 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -2398,7 +2398,7 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, const struct Curl_addrinfo *ai) { struct cf_osslq_ctx *ctx = NULL; - struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + struct Curl_cfilter *cf = NULL; CURLcode result; (void)data; @@ -2412,23 +2412,22 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) goto out; + cf->conn = conn; - result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC); if(result) goto out; - cf->conn = conn; - udp_cf->conn = cf->conn; - udp_cf->sockindex = cf->sockindex; - cf->next = udp_cf; + cf->next->conn = cf->conn; + cf->next->sockindex = cf->sockindex; out: *pcf = (!result) ? cf : NULL; if(result) { - if(udp_cf) - Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); - Curl_safefree(cf); - cf_osslq_ctx_free(ctx); + if(cf) + Curl_conn_cf_discard_chain(&cf, data); + else if(ctx) + cf_osslq_ctx_free(ctx); } return result; } diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 8f0535d65d2a..c1563c4e6309 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1636,7 +1636,7 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, const struct Curl_addrinfo *ai) { struct cf_quiche_ctx *ctx = NULL; - struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + struct Curl_cfilter *cf = NULL; CURLcode result; (void)data; @@ -1651,22 +1651,21 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) goto out; + cf->conn = conn; - result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC); if(result) goto out; - - udp_cf->conn = cf->conn; - udp_cf->sockindex = cf->sockindex; - cf->next = udp_cf; + cf->next->conn = cf->conn; + cf->next->sockindex = cf->sockindex; out: *pcf = (!result) ? cf : NULL; if(result) { - if(udp_cf) - Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); - Curl_safefree(cf); - cf_quiche_ctx_free(ctx); + if(cf) + Curl_conn_cf_discard_chain(&cf, data); + else if(ctx) + cf_quiche_ctx_free(ctx); } return result; diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index f17f9142bed1..bfec585ce210 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1862,7 +1862,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, Curl_shutdown_clear(data, sockindex); if(!result && !done) /* blocking failed? */ result = CURLE_SSL_SHUTDOWN_FAILED; - Curl_conn_cf_discard_sub(head, cf, data, FALSE); + Curl_conn_cf_discard(&cf, data); CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result); break; } From 5cc2b8344675140efc660d7a67958274c9caf590 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 14:49:09 +0200 Subject: [PATCH 053/208] smb: adjust buffer size checks The checks did not account for the **two byte** 16bit read so risked reading one more byte than what actually was received. Reported-by: Joshua Rogers Closes #18599 --- lib/smb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/smb.c b/lib/smb.c index 81cf6e7cc1f4..bf02119ea1db 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -1104,7 +1104,7 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done) break; case SMB_DOWNLOAD: - if(h->status || smbc->got < sizeof(struct smb_header) + 14) { + if(h->status || smbc->got < sizeof(struct smb_header) + 15) { req->result = CURLE_RECV_ERROR; next_state = SMB_CLOSE; break; @@ -1133,7 +1133,7 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done) break; case SMB_UPLOAD: - if(h->status || smbc->got < sizeof(struct smb_header) + 6) { + if(h->status || smbc->got < sizeof(struct smb_header) + 7) { req->result = CURLE_UPLOAD_FAILED; next_state = SMB_CLOSE; break; From 232d5a2ed9c091c88e3b724a1e7d6d6e6cac0079 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 15:02:03 +0200 Subject: [PATCH 054/208] openldap: avoid indexing the result at -1 for blank responses Reported-by: Joshua Rogers Closes #18600 --- lib/openldap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/openldap.c b/lib/openldap.c index da26d4a78d06..1f8737f5243a 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -1172,7 +1172,8 @@ static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf, if(!binary) { /* check for leading or trailing whitespace */ if(ISBLANK(bvals[i].bv_val[0]) || - ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1])) + (bvals[i].bv_len && + ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))) binval = TRUE; else { /* check for unprintable characters */ From b4922b1295333dc6679eb1d588ddc2fb6b7fd5b7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 16 Sep 2025 11:47:38 +0200 Subject: [PATCH 055/208] GHA/codeql: enable cares, debug, build curlinfo, examples Also build examples, out of curiousity, as an experiment, possibly temporary. It needs around 40 seconds. Closes #18564 --- .github/workflows/codeql.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5ff3434442f8..2344f1d16fa9 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -79,7 +79,7 @@ jobs: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev \ + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libc-ares-dev \ libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev /home/linuxbrew/.linuxbrew/bin/brew install gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi @@ -108,12 +108,14 @@ jobs: # MultiSSL export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" - cmake -B _bld1 -G Ninja \ + cmake -B _bld1 -G Ninja -DENABLE_DEBUG=ON \ -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ - -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DENABLE_ARES=ON cmake --build _bld1 --verbose + cmake --build _bld1 --verbose --target curlinfo cmake --build _bld1 --verbose --target servers cmake --build _bld1 --verbose --target tunits + cmake --build _bld1 --verbose --target curl-examples-build # HTTP/3 export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix libnghttp3)/lib/pkgconfig:$(brew --prefix libngtcp2)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" From 44a586472b42a288836f730b4b3b7dd5490057f6 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 15:50:17 +0200 Subject: [PATCH 056/208] ldap: do not base64 encode zero length string Reported-by: Joshua Rogers Closes #18602 --- lib/ldap.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/ldap.c b/lib/ldap.c index c66a56d7bb24..4b232e2bb676 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -634,22 +634,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) if((attr_len > 7) && (strcmp(";binary", attr + (attr_len - 7)) == 0)) { /* Binary attribute, encode to base64. */ - result = curlx_base64_encode(vals[i]->bv_val, vals[i]->bv_len, - &val_b64, &val_b64_sz); - if(result) { - ldap_value_free_len(vals); - FREE_ON_WINLDAP(attr); - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - if(val_b64_sz > 0) { - result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64, - val_b64_sz); - free(val_b64); + if(vals[i]->bv_len) { + result = curlx_base64_encode(vals[i]->bv_val, vals[i]->bv_len, + &val_b64, &val_b64_sz); if(result) { ldap_value_free_len(vals); FREE_ON_WINLDAP(attr); @@ -659,6 +646,21 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } + + if(val_b64_sz > 0) { + result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64, + val_b64_sz); + free(val_b64); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + } } } else { From a80abc45a572132b7f425e526cd60c0cf49f28e2 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Tue, 16 Sep 2025 23:27:23 +0500 Subject: [PATCH 057/208] sasl: clear canceled mechanism instead of toggling it Use &= ~authused in SASL_CANCEL (was ^=) to actually remove the offending mechanism and avoid re-enabling a disabled mech on retry. Closes #18573 --- lib/curl_sasl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 8eb63fb94954..9c86f3ea086e 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -812,7 +812,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, case SASL_CANCEL: /* Remove the offending mechanism from the supported list */ - sasl->authmechs ^= sasl->authused; + sasl->authmechs &= (unsigned short)~sasl->authused; + sasl->authused = SASL_AUTH_NONE; + sasl->curmech = NULL; /* Start an alternative SASL authentication */ return Curl_sasl_start(sasl, data, sasl->force_ir, progress); From f8175b1536610ec60a9d2dce5a055d59287af4d5 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Thu, 18 Sep 2025 02:07:17 -0400 Subject: [PATCH 058/208] socks_sspi: Fix some memory cleanup calls - Ensure memory allocated by malloc() is freed by free(). Prior to this change SSPI's FreeContextBuffer() was sometimes used to free malloc'd memory. I can only assume the reason we have no crash reports about this is because the underlying heap free is probably the same for both. Reported-by: Joshua Rogers Fixes https://github.com/curl/curl/issues/18587 Closes https://github.com/curl/curl/pull/18594 --- lib/socks_sspi.c | 102 +++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index c106fec0c8fb..3ff3b723f9a2 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -90,6 +90,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; + char *etbuf; + size_t etbuf_size; /* GSS-API request looks like * +----+------+-----+----------------+ @@ -131,11 +133,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, wrap_desc.pBuffers = sspi_w_token; wrap_desc.ulVersion = SECBUFFER_VERSION; - cred_handle.dwLower = 0; - cred_handle.dwUpper = 0; + memset(&cred_handle, 0, sizeof(cred_handle)); + memset(&sspi_context, 0, sizeof(sspi_context)); names.sUserName = NULL; + etbuf = NULL; + etbuf_size = 0; + status = Curl_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)CURL_UNCONST(TEXT("Kerberos")), @@ -178,11 +183,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, curlx_unicodefree(sname); - if(sspi_recv_token.pvBuffer) { - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - sspi_recv_token.pvBuffer = NULL; - sspi_recv_token.cbBuffer = 0; - } + Curl_safefree(sspi_recv_token.pvBuffer); + sspi_recv_token.cbBuffer = 0; if(check_sspi_err(data, status, "InitializeSecurityContext")) { failf(data, "Failed to initialise security context."); @@ -220,10 +222,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } sspi_send_token.cbBuffer = 0; - if(sspi_recv_token.pvBuffer) { - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - sspi_recv_token.pvBuffer = NULL; - } + Curl_safefree(sspi_recv_token.pvBuffer); sspi_recv_token.cbBuffer = 0; if(status != SEC_I_CONTINUE_NEEDED) @@ -289,7 +288,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, status = Curl_pSecFn->QueryCredentialsAttributes(&cred_handle, SECPKG_CRED_ATTR_NAMES, &names); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); if(check_sspi_err(data, status, "QueryCredentialAttributes")) { failf(data, "Failed to determine username."); result = CURLE_COULDNT_CONNECT; @@ -303,6 +301,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, curlx_unicodefree(user_utf8); #endif Curl_pSecFn->FreeContextBuffer(names.sUserName); + names.sUserName = NULL; } /* Do encryption */ @@ -399,35 +398,30 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = CURLE_COULDNT_CONNECT; goto error; } - sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer + - sspi_w_token[1].cbBuffer + - sspi_w_token[2].cbBuffer; - sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); - if(!sspi_send_token.pvBuffer) { + + etbuf_size = sspi_w_token[0].cbBuffer + + sspi_w_token[1].cbBuffer + + sspi_w_token[2].cbBuffer; + etbuf = malloc(etbuf_size); + if(!etbuf) { result = CURLE_OUT_OF_MEMORY; goto error; } - memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer); - memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, + memcpy(etbuf, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); + memcpy(etbuf + sspi_w_token[0].cbBuffer, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); - memcpy((PUCHAR) sspi_send_token.pvBuffer + - sspi_w_token[0].cbBuffer + - sspi_w_token[1].cbBuffer, + memcpy(etbuf + sspi_w_token[0].cbBuffer + sspi_w_token[1].cbBuffer, sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - sspi_w_token[0].pvBuffer = NULL; + Curl_safefree(sspi_w_token[0].pvBuffer); sspi_w_token[0].cbBuffer = 0; - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - sspi_w_token[1].pvBuffer = NULL; + Curl_safefree(sspi_w_token[1].pvBuffer); sspi_w_token[1].cbBuffer = 0; - Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); - sspi_w_token[2].pvBuffer = NULL; + Curl_safefree(sspi_w_token[2].pvBuffer); sspi_w_token[2].cbBuffer = 0; - us_length = htons((unsigned short)sspi_send_token.cbBuffer); + us_length = htons((unsigned short)etbuf_size); memcpy(socksreq + 2, &us_length, sizeof(short)); } @@ -450,16 +444,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } } else { - code = Curl_conn_cf_send(cf->next, data, - (char *)sspi_send_token.pvBuffer, - sspi_send_token.cbBuffer, FALSE, &written); - if(code || (sspi_send_token.cbBuffer != (size_t)written)) { + code = Curl_conn_cf_send(cf->next, data, etbuf, etbuf_size, + FALSE, &written); + if(code || (etbuf_size != written)) { failf(data, "Failed to send SSPI encryption type."); result = CURLE_COULDNT_CONNECT; goto error; } - if(sspi_send_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + Curl_safefree(etbuf); } result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); @@ -514,8 +506,16 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, status = Curl_pSecFn->DecryptMessage(&sspi_context, &wrap_desc, 0, &qop); + /* since sspi_w_token[1].pvBuffer is allocated by the SSPI in this case, it + must be freed in this block using FreeContextBuffer() instead of + potentially in error cleanup using free(). */ + if(check_sspi_err(data, status, "DecryptMessage")) { failf(data, "Failed to query security context attributes."); + if(sspi_w_token[1].pvBuffer) { + Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + sspi_w_token[1].pvBuffer = NULL; + } result = CURLE_COULDNT_CONNECT; goto error; } @@ -523,13 +523,20 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(sspi_w_token[1].cbBuffer != 1) { failf(data, "Invalid SSPI encryption response length (%lu).", (unsigned long)sspi_w_token[1].cbBuffer); + if(sspi_w_token[1].pvBuffer) { + Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + sspi_w_token[1].pvBuffer = NULL; + } result = CURLE_COULDNT_CONNECT; goto error; } memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + Curl_safefree(sspi_w_token[0].pvBuffer); + sspi_w_token[0].cbBuffer = 0; Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + sspi_w_token[1].pvBuffer = NULL; + sspi_w_token[1].cbBuffer = 0; } else { if(sspi_w_token[0].cbBuffer != 1) { @@ -539,7 +546,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, goto error; } memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + Curl_safefree(sspi_w_token[0].pvBuffer); + sspi_w_token[0].cbBuffer = 0; } (void)curlx_nonblock(sock, TRUE); @@ -557,24 +565,24 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, conn->socks5_sspi_context = sspi_context; } */ + + Curl_pSecFn->DeleteSecurityContext(&sspi_context); + Curl_pSecFn->FreeCredentialsHandle(&cred_handle); return CURLE_OK; error: (void)curlx_nonblock(sock, TRUE); free(service_name); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); Curl_pSecFn->DeleteSecurityContext(&sspi_context); - if(sspi_recv_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + Curl_pSecFn->FreeCredentialsHandle(&cred_handle); + free(sspi_recv_token.pvBuffer); if(sspi_send_token.pvBuffer) Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); if(names.sUserName) Curl_pSecFn->FreeContextBuffer(names.sUserName); - if(sspi_w_token[0].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - if(sspi_w_token[1].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - if(sspi_w_token[2].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); + free(sspi_w_token[0].pvBuffer); + free(sspi_w_token[1].pvBuffer); + free(sspi_w_token[2].pvBuffer); + free(etbuf); return result; } #endif From ad147ec53de822a18b5dec63b72f43688ae53869 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Wed, 17 Sep 2025 00:52:28 +0500 Subject: [PATCH 059/208] tftp: propagate expired timer from tftp_state_timeout() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Curl_timeleft() < 0 we used to return 0, masking the expiry and skipping the caller’s (timeout_ms < 0) path. Now we set FIN and return the negative value so tftp_multi_statemach() aborts with CURLE_OPERATION_TIMEDOUT as intended. Closes #18574 --- lib/tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 4c2fadc2caf8..620ab1e70df8 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1184,7 +1184,7 @@ static timediff_t tftp_state_timeout(struct tftp_conn *state, if(timeout_ms < 0) { state->error = TFTP_ERR_TIMEOUT; state->state = TFTP_STATE_FIN; - return 0; + return timeout_ms; } current = time(NULL); if(current > state->rx_time + state->retry_time) { From 54aff4db3c620fd1fcd7c7a7f949fd8ca3773eb8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 17:32:39 +0200 Subject: [PATCH 060/208] tftp: check and act on tftp_set_timeouts() returning error Reported-by: Joshua Rogers Ref: https://github.com/curl/curl/pull/18574#issuecomment-3300183302 Closes #18603 --- lib/tftp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 620ab1e70df8..84b92ee48827 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -962,6 +962,7 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done) int need_blksize; struct connectdata *conn = data->conn; const struct Curl_sockaddr_ex *remote_addr = NULL; + CURLcode result; blksize = TFTP_BLKSIZE_DEFAULT; @@ -1013,7 +1014,9 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done) ((struct sockaddr *)&state->local_addr)->sa_family = (CURL_SA_FAMILY_T)(remote_addr->family); - tftp_set_timeouts(state); + result = tftp_set_timeouts(state); + if(result) + return result; if(!conn->bits.bound) { /* If not already bound, bind to any interface, random UDP port. If it is From ce354d0f4d251371f65f1770d95bba1d926de421 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Thu, 18 Sep 2025 11:38:20 -0400 Subject: [PATCH 061/208] tool_operate: Improve wording in retry message - Use the plural 'seconds' for anything other than exactly 1 second. Before: Will retry in 1.250 second. After: Will retry in 1.250 seconds. Follow-up to ca034e83. Closes https://github.com/curl/curl/pull/18604 --- src/tool_operate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tool_operate.c b/src/tool_operate.c index 4337cdee6006..75926d704ba4 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -480,7 +480,7 @@ static CURLcode retrycheck(struct OperationConfig *config, (sleeptime%1000L ? "." : ""), (sleeptime%1000L ? 3 : 0), sleeptime%1000L, - (sleeptime/1000L == 1 ? "" : "s"), + (sleeptime == 1000L ? "" : "s"), per->retry_remaining, (per->retry_remaining > 1 ? "ies" : "y")); From f13250edf11312ab8c0425cf39b182a31b53c6f7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Sep 2025 18:50:09 +0200 Subject: [PATCH 062/208] examples: fix two issues found by CodeQL - http2-upload: use `fstat()` to query file length to fix TOCTOU. - ftpuploadresume: fix checking `sscanf()` return value. Follow-up to b4922b1295333dc6679eb1d588ddc2fb6b7fd5b7 #18564 Closes #18605 --- docs/examples/ftpuploadresume.c | 2 +- docs/examples/http2-upload.c | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/examples/ftpuploadresume.c b/docs/examples/ftpuploadresume.c index b02ad928a6dc..67495aec6870 100644 --- a/docs/examples/ftpuploadresume.c +++ b/docs/examples/ftpuploadresume.c @@ -38,7 +38,7 @@ static size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, long len = 0; r = sscanf(ptr, "Content-Length: %ld\n", &len); - if(r) + if(r == 1) *((long *) stream) = len; return size * nmemb; diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index 482889ea1857..31f4ed56e1ba 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -45,6 +45,9 @@ #ifdef _WIN32 #undef stat #define stat _stat +#undef fstat +#define fstat _fstat +#define fileno _fileno #endif /* curl stuff */ @@ -223,24 +226,27 @@ static int setup(struct input *i, int num, const char *upload) curl_msnprintf(url, 256, "https://localhost:8443/upload-%d", num); - /* get the file size of the local file */ - if(stat(upload, &file_info)) { - fprintf(stderr, "error: could not stat file %s: %s\n", upload, + i->in = fopen(upload, "rb"); + if(!i->in) { + fprintf(stderr, "error: could not open file %s for reading: %s\n", upload, strerror(errno)); fclose(out); return 1; } - uploadsize = file_info.st_size; - - i->in = fopen(upload, "rb"); - if(!i->in) { - fprintf(stderr, "error: could not open file %s for reading: %s\n", upload, +#ifdef UNDER_CE + if(stat(upload, &file_info) != 0) { +#else + if(fstat(fileno(i->in), &file_info) != 0) { +#endif + fprintf(stderr, "error: could not stat file %s: %s\n", upload, strerror(errno)); fclose(out); return 1; } + uploadsize = file_info.st_size; + hnd = i->hnd = curl_easy_init(); /* write to this file */ From cec6c1cd9c3923e2b583ba2f0756a733ad25293e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Sep 2025 20:26:15 +0200 Subject: [PATCH 063/208] GHA/codeql: make it run on docs updates, to verify examples Follow-up to b4922b1295333dc6679eb1d588ddc2fb6b7fd5b7 #18564 --- .github/workflows/codeql.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2344f1d16fa9..7b2922e2bbdb 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,7 +13,6 @@ name: 'CodeQL' - '**/*.md' - '.circleci/**' - 'appveyor.*' - - 'docs/**' - 'packages/**' - 'plan9/**' - 'projects/**' @@ -26,7 +25,6 @@ name: 'CodeQL' - '**/*.md' - '.circleci/**' - 'appveyor.*' - - 'docs/**' - 'packages/**' - 'plan9/**' - 'projects/**' From 9f18cb6544bbf47e2e2fad6564bc03098273c7bc Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Sep 2025 14:02:51 +0200 Subject: [PATCH 064/208] libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() - null-terminate the result to match the other getter `libssh2_sftp_symlink_ex()` call. - check negative result and bail out early. Reported-by: Joshua Rogers Closes #18598 --- lib/vssh/libssh2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 5dfc377ec14e..73d48077b535 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -2405,6 +2405,12 @@ static CURLcode ssh_state_sftp_readdir_link(struct Curl_easy *data, curlx_dyn_free(&sshp->readdir_link); + if(rc < 0) + return CURLE_OUT_OF_MEMORY; + + /* It seems that this string is not always null-terminated */ + sshp->readdir_filename[rc] = '\0'; + /* append filename and extra output */ result = curlx_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename); if(result) From 9fb8d567ca96659dc0d35cc82f160a721adf6edd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 08:47:15 +0200 Subject: [PATCH 065/208] tool_operate: keep the progress meter for --out-null Fixes #18607 Closes #18609 --- src/tool_operate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tool_operate.c b/src/tool_operate.c index 75926d704ba4..8ca3c14e8f12 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1277,8 +1277,8 @@ static CURLcode single_transfer(struct OperationConfig *config, config->resume_from = -1; /* -1 will then force get-it-yourself */ } - if(output_expected(per->url, per->uploadfile) && outs->stream && - isatty(fileno(outs->stream))) + if(!outs->out_null && output_expected(per->url, per->uploadfile) && + outs->stream && isatty(fileno(outs->stream))) /* we send the output to a tty, therefore we switch off the progress meter */ per->noprogress = global->noprogress = global->isatty = TRUE; From 0d9a07abb731cc52a220f48430f66b546965594f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Sep 2025 23:25:28 +0200 Subject: [PATCH 066/208] libssh2: drop two redundant null-terminations The null-termination was first added in the initial SFTP commit in 2006: a634f644005cbe2b3dea2b84328d605ec3474054 At that time this was a reasonable concern because libssh2 started null-terminating this string just one year prior, in 2005: https://github.com/libssh2/libssh2/commit/efc3841fd2c2c945e96492e9089e4d1810709d53 This fix was released in libssh2 v0.13 (2006-03-02). curl requires libssh2 v1.2.8, making this workaround no longer necessary. Follow-up to 9f18cb6544bbf47e2e2fad6564bc03098273c7bc #18598 Closes #18606 --- lib/vssh/libssh2.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 73d48077b535..69284407ab98 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1995,8 +1995,6 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, return CURLE_AGAIN; if(rc > 0) { - /* It seems that this string is not always null-terminated */ - sshp->readdir_filename[rc] = '\0'; free(sshc->homedir); sshc->homedir = strdup(sshp->readdir_filename); if(!sshc->homedir) { @@ -2408,9 +2406,6 @@ static CURLcode ssh_state_sftp_readdir_link(struct Curl_easy *data, if(rc < 0) return CURLE_OUT_OF_MEMORY; - /* It seems that this string is not always null-terminated */ - sshp->readdir_filename[rc] = '\0'; - /* append filename and extra output */ result = curlx_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename); if(result) From 9618c337d1c876df04599462fbdb73d370162dbf Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 19 Sep 2025 10:19:29 +0200 Subject: [PATCH 067/208] GHA/codeql: try disabling the TRAP cache The `cpp` CodeQL job is adding a cache entry for each run on the master branch. One for Linux, another for Windows. Size: 68MB + 180MB = 248MB. In one week we got 50+ such entries, almost filling the available cache space. Following the recommendation in an open issue thread, this patch tries to disable this cache. Since it only affects master, the effect can only be verified after merging. The latest cache is picked up in PRs. The performance impact is also to be seen after merge. Bug: https://github.com/curl/curl/pull/18528#issuecomment-3288950880 Ref: https://github.com/github/codeql-action/pull/1172 Ref: https://github.com/github/codeql-action/issues/2030 Ref: https://github.com/github/codeql-action/issues/2885#issuecomment-2879069087 Follow-up to cc50f05370981e4933504e8aaec6b15880ff847f #18528 Closes #18613 --- .github/workflows/codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7b2922e2bbdb..ec41fcf6267e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -90,6 +90,7 @@ jobs: with: languages: cpp build-mode: manual + trap-caching: false - name: 'build' timeout-minutes: 10 From b2356a31974e137e304c35f2c0f7c7a4a988eeb6 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 19 Sep 2025 14:20:14 +0200 Subject: [PATCH 068/208] GHA: tidy up actions/checkout version in comments [ci skip] --- .github/workflows/checkdocs.yml | 2 +- .github/workflows/codeql.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index 36a4ff999e3a..f236ebc85013 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -39,7 +39,7 @@ jobs: # name: 'proselint' # runs-on: ubuntu-latest # steps: - # - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 + # - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 # with: # persist-credentials: false # diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ec41fcf6267e..b5e05efe4655 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -45,7 +45,7 @@ jobs: permissions: security-events: write # To create/update security events steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: persist-credentials: false @@ -81,7 +81,7 @@ jobs: libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev /home/linuxbrew/.linuxbrew/bin/brew install gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: persist-credentials: false From 4f5528675a1bc1008748c3c0f636ab4c1ec6d9c0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 13:35:23 +0200 Subject: [PATCH 069/208] libssh: react on errors from ssh_scp_read Reported in Joshua's sarif data Closes #18616 --- lib/vssh/libssh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 695532ff8514..2554468c4bf3 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -2889,7 +2889,7 @@ static CURLcode scp_recv(struct Curl_easy *data, int sockindex, { struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - ssize_t nread; + int nread; (void)sockindex; /* we only support SCP on the fixed known primary socket */ *pnread = 0; @@ -2899,7 +2899,8 @@ static CURLcode scp_recv(struct Curl_easy *data, int sockindex, /* libssh returns int */ nread = ssh_scp_read(sshc->scp_session, mem, len); - + if(nread == SSH_ERROR) + return CURLE_SSH; #if 0 /* The following code is misleading, mostly added as wishful thinking * that libssh at some point will implement non-blocking ssh_scp_write/read. From df60e8fe701e189e7629fd08b61950a0fb1b697a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 13:23:14 +0200 Subject: [PATCH 070/208] cf_socket_recv: don't count reading zero bytes as first byte Reported in Joshua's sarif data Closes #18615 --- lib/cf-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index f449ca36caf7..308325ccdc15 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1578,7 +1578,7 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *pnread = (size_t)nread; CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread); - if(!result && !ctx->got_first_byte) { + if(!result && !ctx->got_first_byte && nread) { ctx->first_byte_at = curlx_now(); ctx->got_first_byte = TRUE; } From 1055864b03beee1615c04421854e5e927a0cdb5d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 14:19:26 +0200 Subject: [PATCH 071/208] telnet: make printsub require another byte input Reported in Joshua's sarif data Closes #18618 --- lib/telnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/telnet.c b/lib/telnet.c index cc827c1b3e8a..05e5ebe60cc7 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -713,7 +713,7 @@ static void printsub(struct Curl_easy *data, else /* bad input */ return; } - if(length < 1) { + if(length <= 1) { infof(data, "(Empty suboption?)"); return; } From fd6eb8d6e77d95e71c0c55678b46173b21edd1e9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 15:59:57 +0200 Subject: [PATCH 072/208] cookie: avoid saving a cookie file if no transfer was done Because parts of the cookie loading happens on transfer start the in-memory cookie jar risks being incomplete and then a save might wrongly truncate the target file. Added test 1902 to verify. Reported-by: divinity76 on github Fixes #18621 Closes #18622 --- lib/cookie.c | 12 +++++----- tests/data/Makefile.am | 2 +- tests/data/test1902 | 43 ++++++++++++++++++++++++++++++++++ tests/libtest/Makefile.inc | 2 +- tests/libtest/lib1902.c | 48 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 tests/data/test1902 create mode 100644 tests/libtest/lib1902.c diff --git a/lib/cookie.c b/lib/cookie.c index 35d33268f966..90d375a7611b 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -1658,18 +1658,18 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup) { CURLcode res; - if(data->set.str[STRING_COOKIEJAR]) { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + /* only save the cookie file if a transfer was started (data->state.url is + set), as otherwise the cookies were not completely initialized and there + might be cookie files that weren't loaded so saving the file is the wrong + thing. */ + if(data->set.str[STRING_COOKIEJAR] && data->state.url) { /* if we have a destination file for all the cookies to get dumped to */ res = cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]); if(res) infof(data, "WARNING: failed to save cookies in %s: %s", data->set.str[STRING_COOKIEJAR], curl_easy_strerror(res)); } - else { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - } if(cleanup && (!data->share || (data->cookies != data->share->cookies))) { Curl_cookie_cleanup(data->cookies); diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 4523de48864f..dfff0122575c 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -232,7 +232,7 @@ test1708 test1709 test1710 \ \ test1800 test1801 \ \ -test1900 test1901 test1903 test1904 test1905 test1906 test1907 \ +test1900 test1901 test1902 test1903 test1904 test1905 test1906 test1907 \ test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \ test1916 test1917 test1918 test1919 \ \ diff --git a/tests/data/test1902 b/tests/data/test1902 new file mode 100644 index 000000000000..7bf70e9068fe --- /dev/null +++ b/tests/data/test1902 @@ -0,0 +1,43 @@ + + + +cookies + + + +# Client-side + + + +set COOKIEFILE and COOKIEJAR but make no transfer + + +cookies + + +lib%TESTNUMBER + + + +%LOGDIR/cookie%TESTNUMBER + + +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +example.com FALSE / FALSE 0 has_js 1 + + + +# Verify data after the test has been "shot" + + +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +example.com FALSE / FALSE 0 has_js 1 + + + diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index 40ec0d1559d5..00273f9e9d6a 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -90,7 +90,7 @@ TESTS_C = \ lib1591.c lib1592.c lib1593.c lib1594.c lib1597.c \ lib1598.c lib1599.c \ lib1662.c \ - lib1900.c lib1901.c lib1903.c lib1905.c lib1906.c lib1907.c \ + lib1900.c lib1901.c lib1902.c lib1903.c lib1905.c lib1906.c lib1907.c \ lib1908.c lib1910.c lib1911.c lib1912.c lib1913.c \ lib1915.c lib1916.c lib1918.c lib1919.c \ lib1933.c lib1934.c lib1935.c lib1936.c lib1937.c lib1938.c lib1939.c \ diff --git a/tests/libtest/lib1902.c b/tests/libtest/lib1902.c new file mode 100644 index 000000000000..8e5929e33827 --- /dev/null +++ b/tests/libtest/lib1902.c @@ -0,0 +1,48 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , 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 "first.h" + +#include "memdebug.h" + +static CURLcode test_lib1902(const char *URL) +{ + CURLcode res = CURLE_OK; + CURL *curl; + + curl_global_init(CURL_GLOBAL_ALL); + + curl = curl_easy_init(); + if(curl) { + easy_setopt(curl, CURLOPT_COOKIEFILE, URL); + easy_setopt(curl, CURLOPT_COOKIEJAR, URL); + + /* Do not perform any actual network operation, + the issue occur when not calling curl.*perform */ + } + +test_cleanup: + curl_easy_cleanup(curl); + curl_global_cleanup(); + return res; +} From b0c823b86fa00e6a41a61614b45999e94b573eaf Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 16:47:01 +0200 Subject: [PATCH 073/208] RELEASE-NOTES: synced and bump to 8.17.0 --- RELEASE-NOTES | 65 ++++++++++++++++++++++++++++++++++++++---- include/curl/curlver.h | 8 +++--- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index c6fb253c75f3..69b05b895a9f 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,10 +1,10 @@ -curl and libcurl 8.16.1 +curl and libcurl 8.17.0 Public curl releases: 271 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3502 + Contributors: 3504 This release includes the following changes: @@ -13,8 +13,12 @@ This release includes the following bugfixes: o asyn-thrdd: drop pthread_cancel [30] o aws-lc: re-enable large read-ahead with v1.61.0 again [16] + o cf_socket_recv: don't count reading zero bytes as first byte [23] + o cfilter: unlink and discard [46] o cmake: fix building docs when the base directory contains `.3` [18] o cmdline-docs: extended, clarified, refreshed [28] + o configure: add "-mt" for pthread support on HP-UX [52] + o cookie: avoid saving a cookie file if no transfer was done [11] o curl_easy_getinfo: error code on NULL arg [2] o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] @@ -26,17 +30,39 @@ This release includes the following bugfixes: o docs/libcurl: remove ancient version references [7] o docs/libcurl: use lowercase must [5] o easy_getinfo: check magic, Curl_close safety [3] + o examples: fix two issues found by CodeQL [35] o krb5: return appropriate error on send failures [22] + o ldap: do not base64 encode zero length string [42] + o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] + o libssh2: drop two redundant null-terminations [26] + o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh: react on errors from ssh_scp_read [24] o Makefile.example: simplify and make it configurable [20] + o managen: ignore version mentions < 7.66.0 [55] + o managen: render better manpage references/links [54] + o multi.h: add CURLMINFO_LASTENTRY [51] o ngtcp2: check error code on connect failure [13] + o openldap: avoid indexing the result at -1 for blank responses [44] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o sasl: clear canceled mechanism instead of toggling it [41] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] + o smb: adjust buffer size checks [45] + o smtp: check EHLO responses case insensitively [50] + o socks_sspi: fix memory cleanup calls [40] + o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] o sws: fix checking `sscanf()` return value [17] + o telnet: make printsub require another byte input [21] + o tftp: check and act on tftp_set_timeouts() returning error [38] + o tftp: propagate expired timer from tftp_state_timeout() [39] o TODO: remove already implemented or bad items [36] + o tool: fix exponential retry delay [47] + o tool_cb_hdr: fix fwrite check in header callback [49] + o tool_operate: improve wording in retry message [37] + o tool_operate: keep the progress meter for --out-null [33] o urldata: FILE is not a list-only protocol [9] This release includes the following known bugs: @@ -61,11 +87,12 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Adam Light, Andrew Kirillov, Dan Fandrich, Daniel Stenberg, dependabot[bot], + Adam Light, Andrew Kirillov, Andrew Olsen, Christian Schmitz, Dan Fandrich, + Daniel Stenberg, dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, fds242 on github, Javier Blazquez, - Jicea, Nir Azkiel, renovate[bot], Samuel Dionne-Riel, Stefan Eissing, - Viktor Szakats - (15 contributors) + Jicea, Joshua Rogers, Michael Osipov, Nir Azkiel, Ray Satiro, renovate[bot], + Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats + (21 contributors) References to bug reports and discussions on issues: @@ -79,6 +106,7 @@ References to bug reports and discussions on issues: [8] = https://curl.se/bug/?i=18531 [9] = https://curl.se/bug/?i=18525 [10] = https://curl.se/bug/?i=18527 + [11] = https://curl.se/bug/?i=18621 [12] = https://curl.se/bug/?i=18523 [13] = https://curl.se/bug/?i=18521 [14] = https://curl.se/bug/?i=18518 @@ -88,11 +116,36 @@ References to bug reports and discussions on issues: [18] = https://curl.se/bug/?i=18560 [19] = https://curl.se/bug/?i=18510 [20] = https://curl.se/bug/?i=18554 + [21] = https://curl.se/bug/?i=18618 [22] = https://curl.se/bug/?i=18561 + [23] = https://curl.se/bug/?i=18615 + [24] = https://curl.se/bug/?i=18616 + [26] = https://curl.se/bug/?i=18606 [27] = https://curl.se/bug/?i=18551 [28] = https://curl.se/bug/?i=18550 [29] = https://curl.se/bug/?i=18549 [30] = https://curl.se/bug/?i=18532 [31] = https://curl.se/mail/lib-2025-09/0031.html [32] = https://curl.se/bug/?i=18548 + [33] = https://curl.se/bug/?i=18607 + [34] = https://curl.se/bug/?i=18598 + [35] = https://curl.se/bug/?i=18605 [36] = https://curl.se/bug/?i=18542 + [37] = https://curl.se/bug/?i=18604 + [38] = https://curl.se/bug/?i=18603 + [39] = https://curl.se/bug/?i=18574 + [40] = https://curl.se/bug/?i=18587 + [41] = https://curl.se/bug/?i=18573 + [42] = https://curl.se/bug/?i=18602 + [44] = https://curl.se/bug/?i=18600 + [45] = https://curl.se/bug/?i=18599 + [46] = https://curl.se/bug/?i=18596 + [47] = https://curl.se/bug/?i=18591 + [48] = https://curl.se/bug/?i=18592 + [49] = https://curl.se/bug/?i=18593 + [50] = https://curl.se/bug/?i=18588 + [51] = https://curl.se/bug/?i=18578 + [52] = https://curl.se/bug/?i=18585 + [53] = https://curl.se/bug/?i=18579 + [54] = https://curl.se/bug/?i=18580 + [55] = https://curl.se/bug/?i=18583 diff --git a/include/curl/curlver.h b/include/curl/curlver.h index 03baeb4ae1d6..19b2bf87521b 100644 --- a/include/curl/curlver.h +++ b/include/curl/curlver.h @@ -32,13 +32,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "8.16.1-DEV" +#define LIBCURL_VERSION "8.17.0-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 8 -#define LIBCURL_VERSION_MINOR 16 -#define LIBCURL_VERSION_PATCH 1 +#define LIBCURL_VERSION_MINOR 17 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will always follow this syntax: @@ -58,7 +58,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x081001 +#define LIBCURL_VERSION_NUM 0x081100 /* * This is the date and time when the full source package was created. The From 58f071dbe4be8dfc95dad4ac4c9574502966d1dd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 17:36:29 +0200 Subject: [PATCH 074/208] tool_getparam/set_rate: skip the multiplication on overflow The code detected the problem but didn't avoid the calculation correctly. Fixes #18624 Reported-by: BobodevMm on github Closes #18625 --- src/tool_getparam.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tool_getparam.c b/src/tool_getparam.c index f2ad6daf2ef9..b8fec5f7ab3b 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -1012,8 +1012,9 @@ static ParameterError set_rate(const char *nextarg) errorf("too large --rate unit"); err = PARAM_NUMBER_TOO_LARGE; } - /* this typecast is okay based on the check above */ - numerator *= (long)numunits; + else + /* this typecast is okay based on the check above */ + numerator *= (long)numunits; } if(err) From a0369e1705b536279313c11dd54d490cf6f9ea3d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 14:59:17 +0200 Subject: [PATCH 075/208] gtls: avoid potential use of uninitialized variable in trace output Reported in Joshua's sarif data Closes #18620 --- lib/vtls/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index f38c90e66c34..eef64886e1e3 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -2195,7 +2195,7 @@ static CURLcode gtls_recv(struct Curl_cfilter *cf, } out: - CURL_TRC_CF(data, cf, "gtls_recv(len=%zu) -> 0, %zu", blen, *pnread); + CURL_TRC_CF(data, cf, "gtls_recv(len=%zu) -> 0, %zd", blen, nread); return result; } From 5e2d4d790575d4ad0381c4862f5e435a3b6532d1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 13:47:16 +0200 Subject: [PATCH 076/208] base64: accept zero length argument to base64_encode We used to treat 0 as "call strlen() to get the length" for curlx_base64_encode, but it turns out this is rather fragile as we easily do the mistake of passing in zero when the data is actually not there and then calling strlen() is wrong. Force the caller to pass in the correct size. A zero length input string now returns a zero length output and a NULL pointer. Closes #18617 --- lib/curlx/base64.c | 4 +--- tests/unit/unit1302.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/curlx/base64.c b/lib/curlx/base64.c index dc6e9c001ce0..5f6887bd5c4c 100644 --- a/lib/curlx/base64.c +++ b/lib/curlx/base64.c @@ -182,7 +182,7 @@ static CURLcode base64_encode(const char *table64, *outlen = 0; if(!insize) - insize = strlen(inputbuff); + return CURLE_OK; #if SIZEOF_SIZE_T == 4 if(insize > UINT_MAX/4) @@ -240,8 +240,6 @@ static CURLcode base64_encode(const char *table64, * encoded data. Size of encoded data is returned in variable pointed by * outlen. * - * Input length of 0 indicates input buffer holds a null-terminated string. - * * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * diff --git a/tests/unit/unit1302.c b/tests/unit/unit1302.c index 54693631ff54..a1676699f27d 100644 --- a/tests/unit/unit1302.c +++ b/tests/unit/unit1302.c @@ -172,7 +172,7 @@ static CURLcode test_unit1302(const char *arg) fprintf(stderr, "Test %u URL encoded output length %d instead of %d\n", i, (int)olen, (int)e->olen); } - if(memcmp(out, e->output, e->olen)) { + if(out && memcmp(out, e->output, e->olen)) { fprintf(stderr, "Test %u URL encoded badly. Got '%s', expected '%s'\n", i, out, e->output); unitfail++; From 8d004781a577fc2fae72873c4a45b2fb3f366d98 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 27 Jul 2025 13:50:03 +0200 Subject: [PATCH 077/208] build: drop the winbuild build system In favor of CMake. Closes #18040 --- .github/labeler.yml | 2 - .github/scripts/codespell.sh | 1 - .github/scripts/spacecheck.pl | 3 +- .github/scripts/typos.toml | 1 - .github/workflows/checksrc.yml | 2 - .github/workflows/curl-for-win.yml | 2 - .github/workflows/fuzz.yml | 2 - .github/workflows/http3-linux.yml | 2 - .github/workflows/linux-old.yml | 2 - .github/workflows/linux.yml | 2 - .github/workflows/macos.yml | 2 - .github/workflows/non-native.yml | 2 - .github/workflows/windows.yml | 2 - .gitignore | 1 - Makefile.am | 5 +- appveyor.sh | 23 - appveyor.yml | 51 -- docs/DEPRECATE.md | 8 +- docs/INSTALL-CMAKE.md | 60 +-- docs/INSTALL.md | 2 - projects/README.md | 3 - winbuild/.gitignore | 6 - winbuild/Makefile.vc | 308 ------------ winbuild/MakefileBuild.vc | 732 ----------------------------- winbuild/README.md | 207 -------- winbuild/makedebug.bat | 33 -- 26 files changed, 4 insertions(+), 1460 deletions(-) delete mode 100644 winbuild/.gitignore delete mode 100644 winbuild/Makefile.vc delete mode 100644 winbuild/MakefileBuild.vc delete mode 100644 winbuild/README.md delete mode 100644 winbuild/makedebug.bat diff --git a/.github/labeler.yml b/.github/labeler.yml index 42a891e62386..982055f16a3b 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -75,7 +75,6 @@ build: packages/**,\ plan9/**,\ projects/**,\ - winbuild/**,\ lib/libcurl.def,\ tests/cmake/**\ }" @@ -520,6 +519,5 @@ Windows: m4/curl-schannel.m4,\ projects/**,\ src/tool_doswin.c,\ - winbuild/**,\ lib/libcurl.def\ }" diff --git a/.github/scripts/codespell.sh b/.github/scripts/codespell.sh index 766eeeb87c6f..b373a7d210cc 100755 --- a/.github/scripts/codespell.sh +++ b/.github/scripts/codespell.sh @@ -14,7 +14,6 @@ codespell \ --skip 'docs/THANKS' \ --skip 'packages/*' \ --skip 'scripts/wcurl' \ - --skip 'winbuild/*' \ --ignore-regex '.*spellchecker:disable-line' \ --ignore-words '.github/scripts/codespell-ignore.txt' \ $(git ls-files) diff --git a/.github/scripts/spacecheck.pl b/.github/scripts/spacecheck.pl index e61d30b5b0c9..7caf52632761 100755 --- a/.github/scripts/spacecheck.pl +++ b/.github/scripts/spacecheck.pl @@ -30,7 +30,7 @@ "^m4/zz40-xc-ovr.m4", "Makefile\\.(am|example)\$", "/mkfile", - "\\.(sln|vc)\$", + "\\.sln\$", "^tests/data/test", ); @@ -40,7 +40,6 @@ my @need_crlf = ( "\\.(bat|sln)\$", - "^winbuild/.+\\.md\$", ); my @space_at_eol = ( diff --git a/.github/scripts/typos.toml b/.github/scripts/typos.toml index 46301615cd4f..73ecac136aca 100644 --- a/.github/scripts/typos.toml +++ b/.github/scripts/typos.toml @@ -25,5 +25,4 @@ extend-exclude = [ "docs/THANKS", "packages/*", "scripts/wcurl", - "winbuild/*", ] diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 061a192297d9..a0ff120becb3 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -18,7 +18,6 @@ name: 'Source' - 'Dockerfile' - 'plan9/**' - 'tests/data/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'Source' - 'Dockerfile' - 'plan9/**' - 'tests/data/**' - - 'winbuild/**' permissions: {} diff --git a/.github/workflows/curl-for-win.yml b/.github/workflows/curl-for-win.yml index 704a78d2cd28..0090c7d6e22e 100644 --- a/.github/workflows/curl-for-win.yml +++ b/.github/workflows/curl-for-win.yml @@ -17,7 +17,6 @@ name: 'curl-for-win' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'curl-for-win' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index d9cc43169e7a..1c466160fc77 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -20,7 +20,6 @@ name: 'Fuzzer' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' pull_request: branches: - master @@ -35,7 +34,6 @@ name: 'Fuzzer' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' permissions: {} diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 4ad880ddf6dc..3d3b35dee093 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -17,7 +17,6 @@ name: 'Linux HTTP/3' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'Linux HTTP/3' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: # Hardcoded workflow filename as workflow name above is just Linux again diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index 352986eb0473..e572c1745fb9 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -31,7 +31,6 @@ name: 'Old Linux' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -43,7 +42,6 @@ name: 'Old Linux' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' permissions: {} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 70a6a259ab8d..af2edf0e092b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -16,7 +16,6 @@ name: 'Linux' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -27,7 +26,6 @@ name: 'Linux' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 5e817dd4bdd1..be8565303eb8 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -17,7 +17,6 @@ name: 'macOS' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'macOS' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/non-native.yml b/.github/workflows/non-native.yml index 3c76ed9de852..2670c39078fd 100644 --- a/.github/workflows/non-native.yml +++ b/.github/workflows/non-native.yml @@ -17,7 +17,6 @@ name: 'non-native' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'non-native' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b519af47d66c..d45979c05ac2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -17,7 +17,6 @@ name: 'Windows' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'Windows' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.gitignore b/.gitignore index 9c901f9fffef..0ac100295697 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,6 @@ /.vs /bld/ /build/ -/builds/ /stats/ __pycache__ Debug diff --git a/Makefile.am b/Makefile.am index b5ab0442a81d..fd97e61d9df3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,9 +66,6 @@ CMAKE_DIST = \ VC_DIST = projects/README.md projects/generate.bat -WINBUILD_DIST = winbuild/README.md \ - winbuild/MakefileBuild.vc winbuild/Makefile.vc winbuild/makedebug.bat - PLAN9_DIST = plan9/include/mkfile \ plan9/include/mkfile \ plan9/mkfile.proto \ @@ -80,7 +77,7 @@ PLAN9_DIST = plan9/include/mkfile \ plan9/src/mkfile EXTRA_DIST = CHANGES.md COPYING RELEASE-NOTES Dockerfile .editorconfig \ - $(CMAKE_DIST) $(VC_DIST) $(WINBUILD_DIST) $(PLAN9_DIST) + $(CMAKE_DIST) $(VC_DIST) $(PLAN9_DIST) DISTCLEANFILES = buildinfo.txt diff --git a/appveyor.sh b/appveyor.sh index dea58c954542..4be76095ee4a 100644 --- a/appveyor.sh +++ b/appveyor.sh @@ -96,29 +96,6 @@ elif [ "${BUILD_SYSTEM}" = 'VisualStudioSolution' ]; then msbuild.exe -maxcpucount "-property:Configuration=${PRJ_CFG}" "Windows/${VC_VERSION}/curl-all.sln" ) curl="build/Win32/${VC_VERSION}/${PRJ_CFG}/curld.exe" -elif [ "${BUILD_SYSTEM}" = 'winbuild_vs2015' ]; then - ( - cd winbuild - cat << EOF > _make.bat - call "C:/Program Files/Microsoft SDKs/Windows/v7.1/Bin/SetEnv.cmd" /x64 - call "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat" x86_amd64 - nmake -f Makefile.vc mode=dll VC=14 "SSL_PATH=${openssl_root_win}" WITH_SSL=dll MACHINE=x64 DEBUG=${DEBUG} ENABLE_UNICODE=${ENABLE_UNICODE} WINBUILD_ACKNOWLEDGE_DEPRECATED=yes -EOF - ./_make.bat - rm _make.bat - ) - curl="builds/libcurl-vc14-x64-${PATHPART}-dll-ssl-dll-ipv6-sspi/bin/curl.exe" -elif [ "${BUILD_SYSTEM}" = 'winbuild_vs2017' ]; then - ( - cd winbuild - cat << EOF > _make.bat - call "C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvars64.bat" - nmake -f Makefile.vc mode=dll VC=14.10 "SSL_PATH=${openssl_root_win}" WITH_SSL=dll MACHINE=x64 DEBUG=${DEBUG} ENABLE_UNICODE=${ENABLE_UNICODE} WINBUILD_ACKNOWLEDGE_DEPRECATED=yes -EOF - ./_make.bat - rm _make.bat - ) - curl="builds/libcurl-vc14.10-x64-${PATHPART}-dll-ssl-dll-ipv6-sspi/bin/curl.exe" fi find . \( -name '*.exe' -o -name '*.dll' -o -name '*.lib' -o -name '*.pdb' \) -exec file '{}' \; diff --git a/appveyor.yml b/appveyor.yml index 42b580883c3b..af6ecd2c159b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -147,57 +147,6 @@ environment: PRJ_CFG: Debug HTTP_ONLY: 'ON' - # winbuild-based builds - - - job_name: 'winbuild, VS2015, Debug, x64, OpenSSL 1.1.1, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' - BUILD_SYSTEM: winbuild_vs2015 - DEBUG: 'yes' - PATHPART: debug - ENABLE_UNICODE: 'no' - - job_name: 'winbuild, VS2015, Release, x64, OpenSSL 1.1.1, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' - BUILD_SYSTEM: winbuild_vs2015 - DEBUG: 'no' - PATHPART: release - ENABLE_UNICODE: 'no' - - job_name: 'winbuild, VS2017, Debug, x64, OpenSSL 1.1.1, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - BUILD_SYSTEM: winbuild_vs2017 - DEBUG: 'yes' - PATHPART: debug - ENABLE_UNICODE: 'no' - - job_name: 'winbuild, VS2017, Release, x64, OpenSSL 1.1.1, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - BUILD_SYSTEM: winbuild_vs2017 - DEBUG: 'no' - PATHPART: release - ENABLE_UNICODE: 'no' - - job_name: 'winbuild, VS2015, Debug, x64, OpenSSL 1.1.1, Unicode, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' - BUILD_SYSTEM: winbuild_vs2015 - DEBUG: 'yes' - PATHPART: debug - ENABLE_UNICODE: 'yes' - - job_name: 'winbuild, VS2015, Release, x64, OpenSSL 1.1.1, Unicode, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' - BUILD_SYSTEM: winbuild_vs2015 - DEBUG: 'no' - PATHPART: release - ENABLE_UNICODE: 'yes' - - job_name: 'winbuild, VS2017, Debug, x64, OpenSSL 1.1.1, Unicode, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - BUILD_SYSTEM: winbuild_vs2017 - DEBUG: 'yes' - PATHPART: debug - ENABLE_UNICODE: 'yes' - - job_name: 'winbuild, VS2017, Release, x64, OpenSSL 1.1.1, Unicode, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - BUILD_SYSTEM: winbuild_vs2017 - DEBUG: 'no' - PATHPART: release - ENABLE_UNICODE: 'yes' - # generated VisualStudioSolution-based builds - job_name: 'VisualStudioSolution, VS2013, Debug, x86, Schannel, Build-only' diff --git a/docs/DEPRECATE.md b/docs/DEPRECATE.md index 65c630cbeebe..786b6a92c7e0 100644 --- a/docs/DEPRECATE.md +++ b/docs/DEPRECATE.md @@ -12,13 +12,6 @@ email the as soon as possible and explain to us why this is a problem for you and how your use case cannot be satisfied properly using a workaround. -## winbuild build system - -curl drops support for the winbuild build method after September 2025. - -We recommend migrating to CMake. See the migration guide in -`docs/INSTALL-CMAKE.md`. - ## Windows CE Windows CE "mainstream support" ended on October 9, 2018, and "Extended @@ -79,3 +72,4 @@ We remove support for this OpenSSL version from curl in June 2026. - Secure Transport (removed in 8.15.0) - BearSSL (removed in 8.15.0) - msh3 (removed in 8.16.0) + - winbuild build system (removed in 8.17.0) diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index ea761fa99a0e..b112e1f8b435 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -23,9 +23,7 @@ It consists of the following steps after you have unpacked the source. We recommend building with CMake on Windows. For instructions on migrating from the `projects/Windows` Visual Studio solution files, see -[this section](#migrating-from-visual-studio-ide-project-files). For -instructions on migrating from the winbuild builds, see -[the following section](#migrating-from-winbuild-builds). +[this section](#migrating-from-visual-studio-ide-project-files). ## Using `cmake` @@ -546,59 +544,3 @@ We do *not* specify `-DCMAKE_BUILD_TYPE=Debug` here as we might do for the `"NMake Makefiles"` generator because the Visual Studio generators are [multi-config generators](https://cmake.org/cmake/help/latest/prop_gbl/GENERATOR_IS_MULTI_CONFIG.html) and therefore ignore the value of `CMAKE_BUILD_TYPE`. - -# Migrating from winbuild builds - -We recommend CMake to build curl with MSVC. The winbuild build system is -deprecated and is going to be removed in September 2025 in favor of the CMake -build system. - -In CMake you can customize the path of dependencies by passing the absolute -header path and the full path of the library via `*_INCLUDE_DIR` and -`*_LIBRARY` options (see the complete list in the option listing above). -The full path to the library can point to a static library or an import -library, which defines if the dependency is linked as a dll or statically. -For OpenSSL this works -[differently](https://cmake.org/cmake/help/latest/module/FindOpenSSL.html): -You can pass the root directory of the OpenSSL installation via -`OPENSSL_ROOT_DIR`, then pass `OPENSSL_USE_STATIC_LIBS=ON` to select static -libs. - -winbuild options | Equivalent CMake options -:-------------------------------- | :-------------------------------- -`DEBUG` | `CMAKE_BUILD_TYPE=Debug` -`GEN_PDB` | `CMAKE_EXE_LINKER_FLAGS=/Fd`, `CMAKE_SHARED_LINKER_FLAGS=/Fd` -`LIB_NAME_DLL`, `LIB_NAME_STATIC` | `IMPORT_LIB_SUFFIX`, `LIBCURL_OUTPUT_NAME`, `STATIC_LIB_SUFFIX` -`VC`: `` | see the CMake [Visual Studio generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) -`MACHINE`: `x64`, `x86` | `-A x64`, `-A Win32` -`MODE`: `dll`, `static` | `BUILD_SHARED_LIBS=ON/OFF`, `BUILD_STATIC_LIBS=ON/OFF`, `BUILD_STATIC_CURL=ON/OFF` (default: dll) -`RTLIBCFG`: `static` | `CURL_STATIC_CRT=ON` -`ENABLE_IDN` | `USE_WIN32_IDN=ON` -`ENABLE_IPV6` | `ENABLE_IPV6=ON` -`ENABLE_NGHTTP2` | `USE_NGHTTP2=ON` -`ENABLE_OPENSSL_AUTO_LOAD_CONFIG` | `CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG=OFF` (default) -`ENABLE_SCHANNEL` | `CURL_USE_SCHANNEL=ON` -`ENABLE_SSPI` | `CURL_WINDOWS_SSPI=ON` (default with Schannel) -`ENABLE_UNICODE` | `ENABLE_UNICODE=ON` -`WITH_PREFIX` | `CMAKE_INSTALL_PREFIX=` -`WITH_DEVEL` | see individual `*_INCLUDE_DIR` and `*_LIBRARY` options and `OPENSSL_ROOT_DIR` -`WITH_CARES`, `CARES_PATH` | `ENABLE_ARES=ON`, optional: `CARES_INCLUDE_DIR`, `CARES_LIBRARY` -`WITH_MBEDTLS`, `MBEDTLS_PATH` | `CURL_USE_MBEDTLS=ON`, optional: `MBEDTLS_INCLUDE_DIR`, `MBEDTLS_LIBRARY`, `MBEDX509_LIBRARY`, `MBEDCRYPTO_LIBRARY` -`WITH_NGHTTP2`, `NGHTTP2_PATH` | `USE_NGHTTP2=ON`, optional: `NGHTTP2_INCLUDE_DIR`, `NGHTTP2_LIBRARY` -`WITH_SSH`, `SSH_PATH` | `CURL_USE_LIBSSH=ON`, optional: `LIBSSH_INCLUDE_DIR`, `LIBSSH_LIBRARY` -`WITH_SSH2`, `SSH2_PATH` | `CURL_USE_LIBSSH2=ON`, optional: `LIBSSH2_INCLUDE_DIR`, `LIBSSH2_LIBRARY` -`WITH_SSL`, `SSL_PATH` | `CURL_USE_OPENSSL=ON`, optional: `OPENSSL_ROOT_DIR`, `OPENSSL_USE_STATIC_LIBS=ON` -`WITH_WOLFSSL`, `WOLFSSL_PATH` | `CURL_USE_WOLFSSL=ON`, optional: `WOLFSSL_INCLUDE_DIR`, `WOLFSSL_LIBRARY` -`WITH_ZLIB`, `ZLIB_PATH` | `CURL_ZLIB=ON`, optional: `ZLIB_INCLUDE_DIR`, `ZLIB_LIBRARY` - -For example this command-line: - - > nmake -f Makefile.vc VC=17 MACHINE=x64 DEBUG=ON mode=dll SSL_PATH=C:\OpenSSL WITH_SSL=dll ENABLE_UNICODE=ON - -translates to: - - > cmake . -G "Visual Studio 17 2022" -A x64 -DBUILD_SHARED_LIBS=ON -DOPENSSL_ROOT_DIR=C:\OpenSSL -DCURL_USE_OPENSSL=ON -DENABLE_UNICODE=ON -DCURL_USE_LIBPSL=OFF - > cmake --build . --config Debug - -We use `--config` with `cmake --build` because the Visual Studio CMake -generators are multi-config and therefore ignore `CMAKE_BUILD_TYPE`. diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 0c53731710f1..ab20e9fde1df 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -347,7 +347,6 @@ If you want to set any of these defines you have the following options: - Modify `lib/config-win32.h` - Modify `lib/curl_setup.h` - - Modify `winbuild/Makefile.vc` - Modify the "Preprocessor Definitions" in the libcurl project Note: The pre-processor settings can be found using the Visual Studio IDE @@ -362,7 +361,6 @@ visible to libcurl and curl compilation processes. To set this definition you have the following alternatives: - Modify `lib/config-win32.h` - - Modify `winbuild/Makefile.vc` - Modify the "Preprocessor Definitions" in the libcurl project Note: The pre-processor settings can be found using the Visual Studio IDE diff --git a/projects/README.md b/projects/README.md index e587249dbb84..1777074c6d05 100644 --- a/projects/README.md +++ b/projects/README.md @@ -16,9 +16,6 @@ You need to generate the project files before using them. Please run "generate To generate project files for recent versions of Visual Studio instead, use cmake. Refer to INSTALL-CMAKE.md in the docs directory. -Another way to build curl using Visual Studio is without project files. Refer -to README in the winbuild directory. - ## Directory Structure The following directory structure is used for the legacy project files: diff --git a/winbuild/.gitignore b/winbuild/.gitignore deleted file mode 100644 index 0d7f2b276f76..000000000000 --- a/winbuild/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (C) Daniel Stenberg, , et al. -# -# SPDX-License-Identifier: curl - -*.idb -*.inc diff --git a/winbuild/Makefile.vc b/winbuild/Makefile.vc deleted file mode 100644 index 1a202cb559c6..000000000000 --- a/winbuild/Makefile.vc +++ /dev/null @@ -1,308 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) Daniel Stenberg, , 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 -# -#*************************************************************************** - -!MESSAGE -!MESSAGE WARNING: -!MESSAGE -!MESSAGE The winbuild build system is deprecated and will be removed in -!MESSAGE September 2025 in favor of the CMake build system. -!MESSAGE -!MESSAGE Please see docs/INSTALL-CMAKE.md : "Migrating from winbuild builds" -!MESSAGE -!MESSAGE To use the winbuild build system you must acknowledge this warning by -!MESSAGE setting command line option WINBUILD_ACKNOWLEDGE_DEPRECATED=yes -!MESSAGE -!IF "$(WINBUILD_ACKNOWLEDGE_DEPRECATED)"!="yes" -!ERROR The user must acknowledge the deprecation warning to continue. -!ENDIF - -!IF "$(MODE)"=="static" -TARGET = $(LIB_NAME_STATIC) -AS_DLL = false -CFGSET=true -!ELSEIF "$(MODE)"=="dll" -TARGET = $(LIB_NAME_DLL) -AS_DLL = true -CFGSET=true -!ELSE -!MESSAGE Invalid mode: $(MODE) - -####################### -# Usage -# - -!MESSAGE See winbuild/README.md for usage -!ERROR please choose a valid mode - -!ENDIF - -!INCLUDE "../lib/Makefile.inc" -CSOURCES=$(CSOURCES: = ) -LIBCURL_OBJS=$(CSOURCES:.c=.obj) - -!INCLUDE "../src/Makefile.inc" -CURL_CFILES=$(CURL_CFILES: = ) -CURL_OBJS=$(CURL_CFILES:.c=.obj) - - -# backwards compatible check for USE_SSPI -!IFDEF USE_SSPI -ENABLE_SSPI = $(USE_SSPI) -!ENDIF - -# default options - -!IFNDEF MACHINE -# Note: nmake magically changes the value of PROCESSOR_ARCHITECTURE from "AMD64" -# to "x86" when building in a 32 bit build environment on a 64 bit machine. -!IF "$(PROCESSOR_ARCHITECTURE)"=="AMD64" -MACHINE = x64 -!ELSE -MACHINE = x86 -!ENDIF -!ENDIF - -!IFNDEF ENABLE_IDN -USE_IDN = true -!ELSEIF "$(ENABLE_IDN)"=="yes" -USE_IDN = true -!ELSEIF "$(ENABLE_IDN)"=="no" -USE_IDN = false -!ENDIF - -!IFNDEF ENABLE_IPV6 -USE_IPV6 = true -!ELSEIF "$(ENABLE_IPV6)"=="yes" -USE_IPV6 = true -!ELSEIF "$(ENABLE_IPV6)"=="no" -USE_IPV6 = false -!ENDIF - -!IFNDEF ENABLE_SSPI -USE_SSPI = true -!ELSEIF "$(ENABLE_SSPI)"=="yes" -USE_SSPI = true -!ELSEIF "$(ENABLE_SSPI)"=="no" -USE_SSPI = false -!ENDIF - -!IFNDEF ENABLE_SCHANNEL -!IF DEFINED(WITH_SSL) || DEFINED(WITH_MBEDTLS) || DEFINED(WITH_WOLFSSL) -USE_SCHANNEL = false -!ELSE -USE_SCHANNEL = $(USE_SSPI) -!ENDIF -!ELSEIF "$(ENABLE_SCHANNEL)"=="yes" -USE_SCHANNEL = true -!ELSEIF "$(ENABLE_SCHANNEL)"=="no" -USE_SCHANNEL = false -!ENDIF - -!IFNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG -ENABLE_OPENSSL_AUTO_LOAD_CONFIG = true -!ELSEIF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="yes" -!UNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG -ENABLE_OPENSSL_AUTO_LOAD_CONFIG = true -!ELSEIF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="no" -!UNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG -ENABLE_OPENSSL_AUTO_LOAD_CONFIG = false -!ENDIF - -!IFNDEF ENABLE_UNICODE -USE_UNICODE = false -!ELSEIF "$(ENABLE_UNICODE)"=="yes" -USE_UNICODE = true -!ELSEIF "$(ENABLE_UNICODE)"=="no" -USE_UNICODE = false -!ENDIF - -CONFIG_NAME_LIB = libcurl - -!IF "$(WITH_SSL)"=="dll" -USE_SSL = true -SSL = dll -!ELSEIF "$(WITH_SSL)"=="static" -USE_SSL = true -SSL = static -!ENDIF - -!IF "$(ENABLE_NGHTTP2)"=="yes" -# compatibility bit, WITH_NGHTTP2 is the correct flag -WITH_NGHTTP2 = dll -USE_NGHTTP2 = true -NGHTTP2 = dll -!ELSEIF "$(WITH_NGHTTP2)"=="dll" -USE_NGHTTP2 = true -NGHTTP2 = dll -!ELSEIF "$(WITH_NGHTTP2)"=="static" -USE_NGHTTP2 = true -NGHTTP2 = static -!ENDIF - -!IFNDEF USE_NGHTTP2 -USE_NGHTTP2 = false -!ENDIF - -!IF "$(WITH_MBEDTLS)"=="dll" || "$(WITH_MBEDTLS)"=="static" -USE_MBEDTLS = true -MBEDTLS = $(WITH_MBEDTLS) -!ENDIF - -!IF "$(WITH_WOLFSSL)"=="dll" || "$(WITH_WOLFSSL)"=="static" -USE_WOLFSSL = true -WOLFSSL = $(WITH_WOLFSSL) -!ENDIF - -!IF "$(WITH_CARES)"=="dll" -USE_CARES = true -CARES = dll -!ELSEIF "$(WITH_CARES)"=="static" -USE_CARES = true -CARES = static -!ENDIF - -!IF "$(WITH_ZLIB)"=="dll" -USE_ZLIB = true -ZLIB = dll -!ELSEIF "$(WITH_ZLIB)"=="static" -USE_ZLIB = true -ZLIB = static -!ENDIF - -!IF "$(WITH_SSH2)"=="dll" -USE_SSH2 = true -SSH2 = dll -!ELSEIF "$(WITH_SSH2)"=="static" -USE_SSH2 = true -SSH2 = static -!ENDIF - -!IF "$(WITH_SSH)"=="dll" -USE_SSH = true -SSH = dll -!ELSEIF "$(WITH_SSH)"=="static" -USE_SSH = true -SSH = static -!ENDIF - -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-vc$(VC)-$(MACHINE) - -!IF "$(DEBUG)"=="yes" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-debug -!ELSE -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-release -!ENDIF - -!IF "$(AS_DLL)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-dll -!ELSE -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-static -!ENDIF - -!IF "$(USE_SSL)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ssl-$(SSL) -!ENDIF - -!IF "$(USE_MBEDTLS)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-mbedtls-$(MBEDTLS) -!ENDIF - -!IF "$(USE_WOLFSSL)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-wolfssl-$(WOLFSSL) -!ENDIF - -!IF "$(USE_CARES)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-cares-$(CARES) -!ENDIF - -!IF "$(USE_ZLIB)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-zlib-$(ZLIB) -!ENDIF - -!IF "$(USE_SSH2)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ssh2-$(SSH2) -!ENDIF - -!IF "$(USE_SSH)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ssh-$(SSH) -!ENDIF - -!IF "$(USE_IPV6)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ipv6 -!ENDIF - -!IF "$(USE_SSPI)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-sspi -!ENDIF - -!IF "$(USE_SCHANNEL)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-schannel -!ENDIF - -!IF "$(USE_NGHTTP2)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-nghttp2-$(NGHTTP2) -!ENDIF - -!MESSAGE configuration name: $(CONFIG_NAME_LIB) - -# Note these directories are removed by this makefile's 'clean' so they should -# not be changed to point to user-specified directories that may contain other -# data. MakefileBuild.vc uses the same variable names but allows some user -# changes and therefore does not remove the directories. -BUILD_DIR=../builds/$(CONFIG_NAME_LIB) -LIBCURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-lib -CURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-curl -DIRDIST = ..\builds\$(CONFIG_NAME_LIB)\ - -$(MODE): - @echo LIBCURL_OBJS = \> LIBCURL_OBJS.inc - @for %%i in ($(LIBCURL_OBJS)) do @echo $(LIBCURL_DIROBJ)/%%i \>> LIBCURL_OBJS.inc - @echo. >> LIBCURL_OBJS.inc - - @echo CURL_OBJS = \> CURL_OBJS.inc - @for %%i in ($(CURL_OBJS)) do @echo $(CURL_DIROBJ)/%%i \>> CURL_OBJS.inc - @echo. >> CURL_OBJS.inc - - @SET CONFIG_NAME_LIB=$(CONFIG_NAME_LIB) - @SET MACHINE=$(MACHINE) - @SET USE_NGHTTP2=$(USE_NGHTTP2) - @SET USE_IDN=$(USE_IDN) - @SET USE_IPV6=$(USE_IPV6) - @SET USE_SSPI=$(USE_SSPI) - @SET USE_SCHANNEL=$(USE_SCHANNEL) - @SET USE_UNICODE=$(USE_UNICODE) -# compatibility bit - @SET WITH_NGHTTP2=$(WITH_NGHTTP2) - - @$(MAKE) /NOLOGO /F MakefileBuild.vc - -copy_from_lib: - echo copying .c... - FOR %%i IN ($(CURLX_CFILES:/=\)) DO copy %%i ..\src\ - -clean: - @if exist $(LIBCURL_DIROBJ) rd /s /q $(LIBCURL_DIROBJ) - @if exist $(CURL_DIROBJ) rd /s /q $(CURL_DIROBJ) - @if exist $(DIRDIST) rd /s /q $(DIRDIST) - $(MAKE) /NOLOGO /F MakefileBuild.vc $@ diff --git a/winbuild/MakefileBuild.vc b/winbuild/MakefileBuild.vc deleted file mode 100644 index 509e43e263d7..000000000000 --- a/winbuild/MakefileBuild.vc +++ /dev/null @@ -1,732 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) Daniel Stenberg, , 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 -# -#*************************************************************************** - -########################################################################### -# -# Makefile for building libcurl with MSVC -# -# Usage: see README.md -# -############################################################## - -CFGSET=FALSE -WINBUILD_DIR=`cd` - -# Utilities. -# If a path is required that contains characters such as space, quote the path. -MT = mt.exe -RC = rc.exe -ZIP = zip.exe - -# Allow changing C compiler via environment variable CC (default cl.exe) -# This command macro is not set by default: https://msdn.microsoft.com/en-us/library/ms933742.aspx -!If "$(CC)" == "" -CC = cl.exe -!Endif - -!IF "$(VC)"=="6" -CC_NODEBUG = $(CC) /O2 /DNDEBUG -CC_DEBUG = $(CC) /Od /Gm /Zi /D_DEBUG /GZ -CFLAGS = /I. /I../lib /I../include /nologo /W4 /GX /YX /FD /c /DBUILDING_LIBCURL -!ELSE -CC_NODEBUG = $(CC) /O2 /DNDEBUG -CC_DEBUG = $(CC) /Od /D_DEBUG /RTC1 /Z7 /LDd -CFLAGS = /I. /I../lib /I../include /nologo /W4 /EHsc /FD /c /DBUILDING_LIBCURL -!ENDIF - -LFLAGS = /nologo /machine:$(MACHINE) -LNKDLL = link.exe /DLL -# Use lib.exe instead of link.exe as link.exe /lib has the following bad habits: -# - optimizing options like /opt:ref raises warnings (at least in Visual Studio 2015) -# - all (including Windows) dependencies are aggregated (as static parts) -# - link.exe /lib is not documented (anymore) at MSDN -# Instead of id: just create an archive, that contains all objects -LNKLIB = lib.exe - -CFLAGS_PDB = /Zi -LFLAGS_PDB = /incremental:no /opt:ref,icf /DEBUG - -CFLAGS_LIBCURL_STATIC = /DCURL_STATICLIB - -WIN_LIBS = ws2_32.lib wldap32.lib advapi32.lib crypt32.lib secur32.lib - -BASE_NAME = libcurl -BASE_NAME_DEBUG = $(BASE_NAME)_debug -BASE_NAME_STATIC = $(BASE_NAME)_a -BASE_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC)_debug - -LIB_NAME_STATIC = $(BASE_NAME_STATIC).lib -LIB_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC_DEBUG).lib -LIB_NAME_DLL = $(BASE_NAME).dll -LIB_NAME_IMP = $(BASE_NAME).lib -LIB_NAME_DLL_DEBUG = $(BASE_NAME_DEBUG).dll -LIB_NAME_IMP_DEBUG = $(BASE_NAME_DEBUG).lib - -PDB_NAME_STATIC = $(BASE_NAME_STATIC).pdb -PDB_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC_DEBUG).pdb -PDB_NAME_DLL = $(BASE_NAME).pdb -PDB_NAME_DLL_DEBUG = $(BASE_NAME_DEBUG).pdb - -# CURL Command section -PROGRAM_NAME = curl.exe -CURL_CFLAGS = /I../lib /I../lib/curlx /I../include /nologo /W4 /EHsc /FD /c -CURL_LFLAGS = /out:$(DIRDIST)\bin\$(PROGRAM_NAME) /subsystem:console $(LFLAGS) -CURL_RESFLAGS = /i../include - -############################################################# -## Nothing more to do below this line! -LIBCURL_SRC_DIR = ..\lib -CURL_SRC_DIR = ..\src - -!IF EXISTS($(CURL_SRC_DIR)\tool_hugehelp.c) -USE_MANUAL = true -CFLAGS = $(CFLAGS) /DUSE_MANUAL -!ENDIF - -!IFNDEF WITH_DEVEL -WITH_DEVEL = ../../deps -!ENDIF -DEVEL_INCLUDE= $(WITH_DEVEL)/include -DEVEL_LIB = $(WITH_DEVEL)/lib - -!IF EXISTS("$(DEVEL_INCLUDE)") -CFLAGS = $(CFLAGS) /I"$(DEVEL_INCLUDE)" -!ENDIF -!IF EXISTS("$(DEVEL_LIB)") -LFLAGS = $(LFLAGS) "/LIBPATH:$(DEVEL_LIB)" -!ENDIF - -!IFDEF SSL_PATH -SSL_INC_DIR = $(SSL_PATH)\include -SSL_LIB_DIR = $(SSL_PATH)\lib -SSL_LFLAGS = $(SSL_LFLAGS) "/LIBPATH:$(SSL_LIB_DIR)" -!ELSE -SSL_INC_DIR=$(DEVEL_INCLUDE)\openssl -SSL_LIB_DIR=$(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_SSL)"=="dll" || "$(WITH_SSL)"=="static" -!IF EXISTS("$(SSL_LIB_DIR)\libssl.lib") -SSL_LIBS = libssl.lib libcrypto.lib -!ELSE -SSL_LIBS = libeay32.lib ssleay32.lib -!ENDIF -USE_SSL = true -SSL = $(WITH_SSL) -!IF "$(WITH_SSL)"=="static" -WIN_LIBS = $(WIN_LIBS) gdi32.lib user32.lib crypt32.lib -!ENDIF -!ENDIF - -!IFDEF USE_SSL -SSL_CFLAGS = /DUSE_OPENSSL /I"$(SSL_INC_DIR)" -!IF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="false" -SSL_CFLAGS = $(SSL_CFLAGS) /DCURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG -!ENDIF -!ENDIF - -!IF "$(DISABLE_WEBSOCKETS)"=="true" -CFLAGS = $(CFLAGS) /DCURL_DISABLE_WEBSOCKETS=1 -!ENDIF - -!IFDEF NGHTTP2_PATH -NGHTTP2_INC_DIR = $(NGHTTP2_PATH)\include -NGHTTP2_LIB_DIR = $(NGHTTP2_PATH)\lib -NGHTTP2_LFLAGS = $(NGHTTP2_LFLAGS) "/LIBPATH:$(NGHTTP2_LIB_DIR)" -!ELSE -NGHTTP2_INC_DIR = $(DEVEL_INCLUDE) -NGHTTP2_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_NGHTTP2)"=="dll" -NGHTTP2_CFLAGS = /DUSE_NGHTTP2 /I"$(NGHTTP2_INC_DIR)" -NGHTTP2_LIBS = nghttp2.lib -!ELSEIF "$(WITH_NGHTTP2)"=="static" -NGHTTP2_CFLAGS = /DUSE_NGHTTP2 /DNGHTTP2_STATICLIB /I"$(NGHTTP2_INC_DIR)" -!IF EXISTS("$(NGHTTP2_LIB_DIR)\nghttp2_static.lib") -NGHTTP2_LIBS = nghttp2_static.lib -!ELSE -NGHTTP2_LIBS = nghttp2.lib -!ENDIF -!ENDIF - -!IFDEF MBEDTLS_PATH -MBEDTLS_INC_DIR = $(MBEDTLS_PATH)\include -MBEDTLS_LIB_DIR = $(MBEDTLS_PATH)\lib -MBEDTLS_LFLAGS = $(MBEDTLS_LFLAGS) "/LIBPATH:$(MBEDTLS_LIB_DIR)" -!ELSE -MBEDTLS_INC_DIR = $(DEVEL_INCLUDE) -MBEDTLS_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_MBEDTLS)"=="dll" || "$(WITH_MBEDTLS)"=="static" -USE_MBEDTLS = true -MBEDTLS = $(WITH_MBEDTLS) -MBEDTLS_CFLAGS = /DUSE_MBEDTLS /I"$(MBEDTLS_INC_DIR)" -MBEDTLS_LIBS = mbedtls.lib mbedcrypto.lib mbedx509.lib -!ENDIF - -!IFDEF WOLFSSL_PATH -WOLFSSL_INC_DIR = $(WOLFSSL_PATH)\include -WOLFSSL_LIB_DIR = $(WOLFSSL_PATH)\lib -WOLFSSL_LFLAGS = $(WOLFSSL_LFLAGS) "/LIBPATH:$(WOLFSSL_LIB_DIR)" -!ELSE -WOLFSSL_INC_DIR = $(DEVEL_INCLUDE) -WOLFSSL_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_WOLFSSL)"=="dll" || "$(WITH_WOLFSSL)"=="static" -USE_WOLFSSL = true -WOLFSSL = $(WITH_WOLFSSL) -WOLFSSL_CFLAGS = /DUSE_WOLFSSL /I"$(WOLFSSL_INC_DIR)" -WOLFSSL_LIBS = wolfssl.lib -!ENDIF - - -!IFDEF CARES_PATH -CARES_INC_DIR = $(CARES_PATH)\include -CARES_LIB_DIR = $(CARES_PATH)\lib -CARES_LFLAGS = $(CARES_LFLAGS) "/LIBPATH:$(CARES_LIB_DIR)" -!ELSE -CARES_INC_DIR = $(DEVEL_INCLUDE)/cares -CARES_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_CARES)"=="dll" -!IF "$(DEBUG)"=="yes" -CARES_LIBS = caresd.lib -!ELSE -CARES_LIBS = cares.lib -!ENDIF -USE_CARES = true -CARES = dll -!ELSEIF "$(WITH_CARES)"=="static" -!IF "$(DEBUG)"=="yes" -CARES_LIBS = libcaresd.lib -!ELSE -CARES_LIBS = libcares.lib -!ENDIF -USE_CARES = true -CARES = static -!ENDIF - -!IFDEF USE_CARES -CARES_CFLAGS = /DUSE_ARES /I"$(CARES_INC_DIR)" -!IF "$(CARES)"=="static" -CARES_CFLAGS = $(CARES_CFLAGS) /DCARES_STATICLIB -!ENDIF -!ENDIF - - -!IFDEF ZLIB_PATH -ZLIB_INC_DIR = $(ZLIB_PATH)\include -ZLIB_LIB_DIR = $(ZLIB_PATH)\lib -ZLIB_LFLAGS = $(ZLIB_LFLAGS) "/LIBPATH:$(ZLIB_LIB_DIR)" -!ELSE -ZLIB_INC_DIR = $(DEVEL_INCLUDE) -ZLIB_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -# Depending on how zlib is built the libraries have different names, we -# try to handle them all. -!IF "$(WITH_ZLIB)"=="dll" -!IF EXISTS("$(ZLIB_LIB_DIR)\zlibwapi.lib") -ZLIB_LIBS = zlibwapi.lib -ADDITIONAL_ZLIB_CFLAGS = /DZLIB_WINAPI -!ELSEIF EXISTS("$(ZLIB_LIB_DIR)\zdll.lib") -ZLIB_LIBS = zdll.lib -!ELSE -ZLIB_LIBS = zlib.lib -!ENDIF -USE_ZLIB = true -ZLIB = dll -!ELSEIF "$(WITH_ZLIB)"=="static" -!IF EXISTS("$(ZLIB_LIB_DIR)\zlibstat.lib") -ZLIB_LIBS = zlibstat.lib -ADDITIONAL_ZLIB_CFLAGS = /DZLIB_WINAPI -!ELSEIF EXISTS("$(ZLIB_LIB_DIR)\zlibstatic.lib") -ZLIB_LIBS = zlibstatic.lib -!ELSEIF EXISTS("$(ZLIB_LIB_DIR)\zlib.lib") -ZLIB_LIBS = zlib.lib -!ELSE -ZLIB_LIBS = zlib_a.lib -!ENDIF -USE_ZLIB = true -ZLIB = static -!ENDIF - -!IFDEF USE_ZLIB -ZLIB_CFLAGS = /DHAVE_LIBZ $(ADDITIONAL_ZLIB_CFLAGS) /I"$(ZLIB_INC_DIR)" -!ENDIF - - -!IFDEF SSH2_PATH -SSH2_INC_DIR= $(SSH2_PATH)\include -SSH2_LIB_DIR= $(SSH2_PATH)\lib -SSH2_LFLAGS = $(SSH2_LFLAGS) "/LIBPATH:$(SSH2_LIB_DIR)" -!ELSE -SSH2_LIB_DIR= $(DEVEL_LIB) -SSH2_INC_DIR= $(DEVEL_INCLUDE)/libssh2 -!ENDIF - -!IF "$(WITH_SSH2)"=="dll" -SSH2_LIBS = libssh2.lib -USE_SSH2 = true -SSH2 = dll -!ELSEIF "$(WITH_SSH2)"=="static" -# libssh2 NMakefile on Windows at default creates a static library without _a suffix -!IF EXISTS("$(SSH2_LIB_DIR)\libssh2.lib") -SSH2_LIBS = libssh2.lib -!ELSE -SSH2_LIBS = libssh2_a.lib -!ENDIF -WIN_LIBS = $(WIN_LIBS) user32.lib -USE_SSH2 = true -SSH2 = static -!ENDIF - -!IFDEF USE_SSH2 -SSH2_CFLAGS = /DUSE_LIBSSH2 -SSH2_CFLAGS = $(SSH2_CFLAGS) /I"$(SSH2_INC_DIR)" -!ENDIF - - -!IFDEF SSH_PATH -SSH_INC_DIR= $(SSH_PATH)\include -SSH_LIB_DIR= $(SSH_PATH)\lib -SSH_LFLAGS = $(SSH_LFLAGS) "/LIBPATH:$(SSH_LIB_DIR)" -!ELSE -SSH_LIB_DIR= $(DEVEL_LIB) -SSH_INC_DIR= $(DEVEL_INCLUDE) -!ENDIF - -!IF "$(WITH_SSH)"=="dll" || "$(WITH_SSH)"=="static" -SSH_LIBS = ssh.lib -USE_SSH = true -SSH = $(WITH_SSH) -!ENDIF - -!IFDEF USE_SSH -SSH_CFLAGS = /DUSE_LIBSSH -SSH_CFLAGS = $(SSH_CFLAGS) /I"$(SSH_INC_DIR)" -!ENDIF - - -!IFNDEF USE_IDN -USE_IDN = true -!ELSEIF "$(USE_IDN)"=="yes" -USE_IDN = true -!ENDIF - -!IF "$(USE_IDN)"=="true" -IDN_CFLAGS = $(IDN_CFLAGS) /DUSE_WIN32_IDN -WIN_LIBS = $(WIN_LIBS) Normaliz.lib -!ENDIF - - -!IFNDEF USE_IPV6 -USE_IPV6 = true -!ELSEIF "$(USE_IPV6)"=="yes" -USE_IPV6 = true -!ENDIF - -!IF "$(USE_IPV6)"=="true" -IPV6_CFLAGS = $(IPV6_CFLAGS) /DUSE_IPV6 -!ENDIF - - -!IFNDEF USE_SSPI -USE_SSPI = true -!ELSEIF "$(USE_SSPI)"=="yes" -USE_SSPI = true -!ENDIF - -!IF "$(USE_SSPI)"=="true" -SSPI_CFLAGS = $(SSPI_CFLAGS) /DUSE_WINDOWS_SSPI -!ENDIF - - -!IFNDEF USE_SCHANNEL -!IF "$(USE_SSL)"=="true" -USE_SCHANNEL = false -!ELSE -USE_SCHANNEL = $(USE_SSPI) -!ENDIF -!ELSEIF "$(USE_SCHANNEL)"=="yes" -USE_SCHANNEL = true -!ENDIF - - -!IF "$(USE_SCHANNEL)"=="true" -!IF "$(USE_SSPI)"!="true" -!ERROR cannot build with Schannel without SSPI -!ENDIF -SSPI_CFLAGS = $(SSPI_CFLAGS) /DUSE_SCHANNEL -WIN_LIBS = $(WIN_LIBS) Crypt32.lib -!ENDIF - - -!IF "$(GEN_PDB)"=="yes" -GEN_PDB = true -!ENDIF - - -!IFDEF EMBED_MANIFEST -MANIFESTTOOL = $(MT) -manifest $(DIRDIST)\bin\$(PROGRAM_NAME).manifest -outputresource:$(DIRDIST)\bin\$(PROGRAM_NAME);1 -!ENDIF - -# Runtime library configuration -!IF "$(RTLIBCFG)"=="static" -RTLIB = /MT -RTLIB_DEBUG = /MTd -!ELSE -RTLIB = /MD -RTLIB_DEBUG = /MDd -!ENDIF - -!IF "$(MODE)"=="static" -TARGET = $(LIB_NAME_STATIC) -CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC) -AS_DLL = false -CFGSET = true -!ELSEIF "$(MODE)"=="dll" -TARGET = $(LIB_NAME_DLL) -CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP) -AS_DLL = true -CFGSET = true -!ENDIF - -!IF "$(CFGSET)" == "FALSE" -!ERROR please choose a valid mode -!ENDIF - - -# CURL_XX macros are for the curl.exe command - -!IF "$(DEBUG)"=="yes" -RC_FLAGS = /d_DEBUG /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc -CURL_CC = $(CC_DEBUG) $(RTLIB_DEBUG) -CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /d_DEBUG /Fo $@ $(CURL_SRC_DIR)\curl.rc -!ELSE -RC_FLAGS = /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc -CURL_CC = $(CC_NODEBUG) $(RTLIB) -CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /Fo $@ $(CURL_SRC_DIR)\curl.rc -!ENDIF - -!IF "$(AS_DLL)" == "true" - -LNK = $(LNKDLL) $(LFLAGS) $(WIN_LIBS) /out:$(LIB_DIROBJ)\$(TARGET) -!IF "$(DEBUG)"=="yes" -TARGET = $(LIB_NAME_DLL_DEBUG) -LNK = $(LNK) /DEBUG /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) -PDB = $(PDB_NAME_DLL_DEBUG) -CURL_LIBS = /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) -!ELSE -TARGET = $(LIB_NAME_DLL) -LNK = $(LNK) /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP) -PDB = $(PDB_NAME_DLL) -CURL_LIBS = /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP) -!ENDIF -RESOURCE = $(LIB_DIROBJ)\libcurl.res - -# AS_DLL -!ELSE - -!IF "$(DEBUG)"=="yes" -TARGET = $(LIB_NAME_STATIC_DEBUG) -PDB = $(PDB_NAME_STATIC_DEBUG) -!ELSE -TARGET = $(LIB_NAME_STATIC) -PDB = $(PDB_NAME_STATIC) -!ENDIF -LNK = $(LNKLIB) /out:$(LIB_DIROBJ)\$(TARGET) -CURL_CC = $(CURL_CC) $(CFLAGS_LIBCURL_STATIC) - -# AS_DLL -!ENDIF - -!IF "$(USE_SSL)"=="true" -CFLAGS = $(CFLAGS) $(SSL_CFLAGS) -LFLAGS = $(LFLAGS) $(SSL_LFLAGS) $(SSL_LIBS) -!ENDIF - -!IF "$(USE_MBEDTLS)"=="true" -CFLAGS = $(CFLAGS) $(MBEDTLS_CFLAGS) -LFLAGS = $(LFLAGS) $(MBEDTLS_LFLAGS) $(MBEDTLS_LIBS) -!ENDIF - -!IF "$(USE_WOLFSSL)"=="true" -CFLAGS = $(CFLAGS) $(WOLFSSL_CFLAGS) -LFLAGS = $(LFLAGS) $(WOLFSSL_LFLAGS) $(WOLFSSL_LIBS) -!ENDIF - -!IF "$(USE_CARES)"=="true" -CFLAGS = $(CFLAGS) $(CARES_CFLAGS) -LFLAGS = $(LFLAGS) $(CARES_LFLAGS) $(CARES_LIBS) -!ENDIF - -!IF "$(USE_ZLIB)"=="true" -CFLAGS = $(CFLAGS) $(ZLIB_CFLAGS) -LFLAGS = $(LFLAGS) $(ZLIB_LFLAGS) $(ZLIB_LIBS) -!ENDIF - -!IF "$(USE_SSH2)"=="true" -CFLAGS = $(CFLAGS) $(SSH2_CFLAGS) -LFLAGS = $(LFLAGS) $(SSH2_LFLAGS) $(SSH2_LIBS) -!ENDIF - -!IF "$(USE_SSH)"=="true" -CFLAGS = $(CFLAGS) $(SSH_CFLAGS) -LFLAGS = $(LFLAGS) $(SSH_LFLAGS) $(SSH_LIBS) -!ENDIF - -!IF "$(USE_IDN)"=="true" -CFLAGS = $(CFLAGS) $(IDN_CFLAGS) -!ENDIF - -!IF "$(USE_IPV6)"=="true" -CFLAGS = $(CFLAGS) $(IPV6_CFLAGS) -!ENDIF - -!IF "$(USE_SSPI)"=="true" -CFLAGS = $(CFLAGS) $(SSPI_CFLAGS) -!ENDIF - -!IF "$(USE_NGHTTP2)"=="true" -CFLAGS = $(CFLAGS) $(NGHTTP2_CFLAGS) -LFLAGS = $(LFLAGS) $(NGHTTP2_LFLAGS) $(NGHTTP2_LIBS) -!ENDIF - -!IF "$(GEN_PDB)"=="true" -CFLAGS = $(CFLAGS) $(CFLAGS_PDB) /Fd"$(LIB_DIROBJ)\$(PDB)" -LFLAGS = $(LFLAGS) $(LFLAGS_PDB) -!ENDIF - -!IF ( "$(USE_SSL)"=="true" && "$(USE_SCHANNEL)"=="true" ) \ - || ( "$(USE_SSL)"=="true" && "$(USE_MBEDTLS)"=="true" ) \ - || ( "$(USE_SSL)"=="true" && "$(USE_WOLFSSL)"=="true" ) \ - || ( "$(USE_MBEDTLS)"=="true" && "$(USE_WOLFSSL)"=="true" ) \ - || ( "$(USE_MBEDTLS)"=="true" && "$(USE_SCHANNEL)"=="true" ) \ - || ( "$(USE_WOLFSSL)"=="true" && "$(USE_SCHANNEL)"=="true" ) -CFLAGS = $(CFLAGS) /DCURL_WITH_MULTI_SSL -!ENDIF - -!IF "$(USE_UNICODE)"=="true" -CFLAGS = $(CFLAGS) /DUNICODE /D_UNICODE -!ENDIF - -LIB_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-lib -CURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-curl - -!IFDEF WITH_PREFIX -DIRDIST = $(WITH_PREFIX) -!ELSE -DIRDIST = ..\builds\$(CONFIG_NAME_LIB)\ -!ENDIF - -# -# curl.exe -# -CURL_LINK = link.exe /incremental:no /libpath:"$(DIRDIST)\lib" - -!IF "$(CFGSET)" != "FALSE" -# A mode was provided, so the library can be built. -# -!include CURL_OBJS.inc -!include LIBCURL_OBJS.inc - -!IF "$(AS_DLL)" == "true" -LIB_OBJS = $(LIBCURL_OBJS) $(RESOURCE) -!ELSE -LIB_OBJS = $(LIBCURL_OBJS) -!ENDIF - -EXE_OBJS = $(CURL_OBJS) $(CURL_DIROBJ)\curl.res - -all : $(TARGET) $(PROGRAM_NAME) - -package: $(TARGET) - @cd $(DIRDIST) - @-$(ZIP) -9 -q -r ..\$(CONFIG_NAME_LIB).zip .>nul 2<&1 - @cd $(MAKEDIR) - -$(TARGET): $(LIB_OBJS) $(LIB_DIROBJ) $(DIRDIST) - @echo Using SSL: $(USE_SSL) - @echo Using NGHTTP2: $(USE_NGHTTP2) - @echo Using c-ares: $(USE_CARES) - @echo Using SSH2: $(USE_SSH2) - @echo Using SSH: $(USE_SSH) - @echo Using ZLIB: $(USE_ZLIB) - @echo Using IDN: $(USE_IDN) - @echo Using IPv6: $(USE_IPV6) - @echo Using SSPI: $(USE_SSPI) - @echo Using Schannel: $(USE_SCHANNEL) - @echo CFLAGS: $(CFLAGS) - @echo LFLAGS: $(LFLAGS) - @echo GenPDB: $(GEN_PDB) - @echo Debug: $(DEBUG) - @echo Machine: $(MACHINE) - $(LNK) $(LIB_OBJS) - @echo Copying libs... - @if exist $(LIB_DIROBJ)\$(LIB_NAME_DLL) copy $(LIB_DIROBJ)\$(LIB_NAME_DLL) $(DIRDIST)\bin\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_STATIC) copy $(LIB_DIROBJ)\$(LIB_NAME_STATIC) $(DIRDIST)\lib\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_DLL_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_DLL_DEBUG) $(DIRDIST)\bin\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_STATIC_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_STATIC_DEBUG) $(DIRDIST)\lib\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_IMP) copy $(LIB_DIROBJ)\$(LIB_NAME_IMP) $(DIRDIST)\lib\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) $(DIRDIST)\lib >nul 2<&1 - @-copy $(LIB_DIROBJ)\*.exp $(DIRDIST)\lib /y >nul 2<&1 - @-copy $(LIB_DIROBJ)\*.pdb $(DIRDIST)\lib /y >nul 2<&1 - @-copy ..\include\curl\*.h $(DIRDIST)\include\curl\ /y >nul 2<&1 - -$(LIB_OBJS): $(LIB_DIROBJ) $(DIRDIST) - -$(DIRDIST): - @if not exist "$(DIRDIST)\bin" mkdir $(DIRDIST)\bin - @if not exist "$(DIRDIST)\include" mkdir $(DIRDIST)\include - @if not exist "$(DIRDIST)\include\curl" mkdir $(DIRDIST)\include\curl - @if not exist "$(DIRDIST)\lib" mkdir $(DIRDIST)\lib - -$(LIB_DIROBJ): - @if not exist "$(LIB_DIROBJ)" mkdir $(LIB_DIROBJ) - @if not exist "$(LIB_DIROBJ)\vauth" mkdir $(LIB_DIROBJ)\vauth - @if not exist "$(LIB_DIROBJ)\vtls" mkdir $(LIB_DIROBJ)\vtls - @if not exist "$(LIB_DIROBJ)\vssh" mkdir $(LIB_DIROBJ)\vssh - @if not exist "$(LIB_DIROBJ)\vquic" mkdir $(LIB_DIROBJ)\vquic - @if not exist "$(LIB_DIROBJ)\curlx" mkdir $(LIB_DIROBJ)\curlx - -$(CURL_DIROBJ): - @if not exist "$(CURL_DIROBJ)" mkdir $(CURL_DIROBJ) -# we need a lib dir for the portability functions from libcurl -# we use the .c directly here - @if not exist "$(CURL_DIROBJ)" mkdir $(CURL_DIROBJ)\lib - -.SUFFIXES: .c .obj .res - -{$(LIBCURL_SRC_DIR)\}.c{$(LIB_DIROBJ)\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\\" $< - -{$(LIBCURL_SRC_DIR)\vauth\}.c{$(LIB_DIROBJ)\vauth\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\vauth\\" $< - -{$(LIBCURL_SRC_DIR)\vtls\}.c{$(LIB_DIROBJ)\vtls\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\vtls\\" $< - -{$(LIBCURL_SRC_DIR)\vssh\}.c{$(LIB_DIROBJ)\vssh\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\vssh\\" $< - -{$(LIBCURL_SRC_DIR)\vquic\}.c{$(LIB_DIROBJ)\vquic\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\vquic\\" $< - -{$(LIBCURL_SRC_DIR)\curlx\}.c{$(LIB_DIROBJ)\curlx\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\curlx\\" $< - -$(LIB_DIROBJ)\libcurl.res: $(LIBCURL_SRC_DIR)\libcurl.rc - $(RC) $(RC_FLAGS) - -# -# curl.exe -# - - -!IF "$(MODE)"=="static" -!IF "$(DEBUG)"=="yes" -CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC_DEBUG) -!ELSE -CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC) -!ENDIF -!ELSEIF "$(MODE)"=="dll" -!IF "$(DEBUG)"=="yes" -CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP_DEBUG) -!ELSE -CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP) -!ENDIF -!ENDIF - -CURL_FROM_LIBCURL=\ - $(CURL_DIROBJ)\nonblock.obj \ - $(CURL_DIROBJ)\strparse.obj \ - $(CURL_DIROBJ)\strcase.obj \ - $(CURL_DIROBJ)\timeval.obj \ - $(CURL_DIROBJ)\wait.obj \ - $(CURL_DIROBJ)\warnless.obj \ - $(CURL_DIROBJ)\multibyte.obj \ - $(CURL_DIROBJ)\version_win32.obj \ - $(CURL_DIROBJ)\dynbuf.obj \ - $(CURL_DIROBJ)\base64.obj - -!IFDEF USE_MANUAL -CURL_FROM_LIBCURL = $(CURL_FROM_LIBCURL) $(CURL_DIROBJ)\tool_hugehelp.obj -!ENDIF - -$(PROGRAM_NAME): $(CURL_DIROBJ) $(CURL_FROM_LIBCURL) $(EXE_OBJS) - $(CURL_LINK) $(CURL_LFLAGS) $(CURL_LIBCURL_LIBNAME) $(WIN_LIBS) $(CURL_FROM_LIBCURL) $(EXE_OBJS) - $(MANIFESTTOOL) - -{$(CURL_SRC_DIR)\}.c{$(CURL_DIROBJ)\}.obj:: - $(CURL_CC) $(CURL_CFLAGS) /Fo"$(CURL_DIROBJ)\\" $< - -!IFDEF USE_MANUAL -$(CURL_DIROBJ)\tool_hugehelp.obj: $(CURL_SRC_DIR)\tool_hugehelp.c - $(CURL_CC) $(CURL_CFLAGS) /Zm200 /Fo"$@" $(CURL_SRC_DIR)\tool_hugehelp.c -!ENDIF -$(CURL_DIROBJ)\nonblock.obj: ../lib/curlx/nonblock.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/nonblock.c -$(CURL_DIROBJ)\strparse.obj: ../lib/curlx/strparse.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/strparse.c -$(CURL_DIROBJ)\strcase.obj: ../lib/strcase.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strcase.c -$(CURL_DIROBJ)\timeval.obj: ../lib/curlx/timeval.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/timeval.c -$(CURL_DIROBJ)\multibyte.obj: ../lib/curlx/multibyte.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/multibyte.c -$(CURL_DIROBJ)\version_win32.obj: ../lib/curlx/version_win32.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/version_win32.c -$(CURL_DIROBJ)\wait.obj: ../lib/curlx/wait.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/wait.c -$(CURL_DIROBJ)\warnless.obj: ../lib/curlx/warnless.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/warnless.c -$(CURL_DIROBJ)\dynbuf.obj: ../lib/curlx/dynbuf.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/dynbuf.c -$(CURL_DIROBJ)\base64.obj: ../lib/curlx/base64.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/base64.c -$(CURL_DIROBJ)\curl.res: $(CURL_SRC_DIR)\curl.rc - $(RC) $(CURL_RC_FLAGS) - -!ENDIF # End of case where a config was provided. - -# Makefile.vc's clean removes (LIB)CURL_DIROBJ and DIRDIST dirs then calls -# this clean. Note those are the original directories we control and not the -# directories possibly modified by this makefile to point to user-specified -# directories. -# For example, don't remove DIRDIST here since it may contain user files if it -# has been changed by WITH_PREFIX to a different output dir (eg C:\usr\local). -clean: - @-erase /s *.dll 2> NUL - @-erase /s *.exp 2> NUL - @-erase /s *.idb 2> NUL - @-erase /s *.lib 2> NUL - @-erase /s *.obj 2> NUL - @-erase /s *.pch 2> NUL - @-erase /s *.pdb 2> NUL - @-erase /s *.res 2> NUL diff --git a/winbuild/README.md b/winbuild/README.md deleted file mode 100644 index 691e2dbc8d6b..000000000000 --- a/winbuild/README.md +++ /dev/null @@ -1,207 +0,0 @@ - - -# Deprecation warning - - This winbuild build system is deprecated and is going to be removed in - September 2025 in favor of the CMake build system. - - Please see docs/INSTALL-CMAKE.md : "Migrating from winbuild builds" - -# Building curl with Visual C++ - - This document describes how to compile, build and install curl and libcurl - from sources using the Visual C++ build tool. To build with VC++, you have to - first install VC++. The minimum required version of VC is 9 (part of Visual - Studio 2008). However using a more recent version is strongly recommended. - - VC++ is also part of the Windows Platform SDK. You do not have to install the - full Visual Studio or Visual C++ if all you want is to build curl. - - The latest Platform SDK can be downloaded freely from [Windows SDK and - emulator - archive](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive) - -## Prerequisites - - If you wish to support zlib, OpenSSL, c-ares, ssh2, you have to download them - separately and copy them to the `deps` directory as shown below: - - somedirectory\ - |_curl-src - | |_winbuild - | - |_deps - |_ lib - |_ include - |_ bin - - It is also possible to create the `deps` directory in some other random places - and tell the `Makefile` its location using the `WITH_DEVEL` option. - -## Open a command prompt - -Open a Visual Studio Command prompt: - - Using the **'VS [version] [platform] [type] Command Prompt'** menu entry: - where [version] is the Visual Studio version, [platform] is e.g. x64 and - [type] Native or Cross platform build. This type of command prompt may not - exist in all Visual Studio versions. For example, to build a 64-bit curl open - the x64 Native Tools prompt. - - See also: - - [How to: Enable a 64-Bit, x64 hosted MSVC toolset on the command line](https://docs.microsoft.com/en-us/cpp/build/how-to-enable-a-64-bit-visual-cpp-toolset-on-the-command-line) - - [Set the Path and Environment Variables for Command-Line Builds](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line) - - [Developer Command Prompt for Visual Studio](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs) - -## Build in the console - - Once you are in the console, go to the winbuild directory in the curl - sources: - - cd curl-src\winbuild - - Then you can call `nmake /f Makefile.vc` with the desired options (see - below). The builds are in the top src directory, `builds\` directory, in a - directory named using the options given to the nmake call. - - nmake /f Makefile.vc mode= - -where `` is one or many of: - - - `VC=` - VC version. 6 or later. - - `WITH_DEVEL=` - Paths for the development files (SSL, zlib, etc.) - Defaults to sibling directory: `../deps` - - `WITH_SSL=` - Enable OpenSSL support, DLL or static - - `WITH_NGHTTP2=` - Enable HTTP/2 support, DLL or static - - `WITH_MBEDTLS=` - Enable mbedTLS support, DLL or static - - `WITH_WOLFSSL=` - Enable wolfSSL support, DLL or static - - `WITH_CARES=` - Enable c-ares support, DLL or static - - `WITH_ZLIB=` - Enable zlib support, DLL or static - - `WITH_SSH=` - Enable libssh support, DLL or static - - `WITH_SSH2=` - Enable libssh2 support, DLL or static - - `WITH_PREFIX=` - Where to install the build - - `ENABLE_SSPI=` - Enable SSPI support, defaults to yes - - `ENABLE_IPV6=` - Enable IPv6, defaults to yes - - `ENABLE_IDN=` - Enable use of Windows IDN APIs, defaults to yes - Requires Windows Vista or later - - `ENABLE_SCHANNEL=` - Enable native Windows SSL support, defaults - to yes if SSPI and no other SSL library - - `ENABLE_OPENSSL_AUTO_LOAD_CONFIG=` - - Enable loading OpenSSL configuration - automatically, defaults to yes - - `ENABLE_UNICODE=` - Enable Unicode support, defaults to no - - `GEN_PDB=` - Generate External Program Database - (debug symbols for release build) - - `DEBUG=` - Debug builds - - `MACHINE=` - Target architecture (default is x86) - - `CARES_PATH=` - Custom path for c-ares - - `MBEDTLS_PATH=` - Custom path for mbedTLS - - `WOLFSSL_PATH=` - Custom path for wolfSSL - - `NGHTTP2_PATH=` - Custom path for nghttp2 - - `SSH_PATH=` - Custom path for libssh - - `SSH2_PATH=` - Custom path for libssh2 - - `SSL_PATH=` - Custom path for OpenSSL - - `ZLIB_PATH=` - Custom path for zlib - -## Cleaning a build - - For most build configurations you can remove a bad build by using the same - options with the added keyword "clean". For example: - - nmake /f Makefile.vc mode=static clean - - Build errors due to switching Visual Studio platform tools or mistakenly - specifying the wrong machine platform for the tools can usually be solved by - first cleaning the bad build. - -## Static linking of Microsoft's C runtime (CRT): - - If you are using mode=static, nmake creates and links to the static build of - libcurl but *not* the static CRT. If you must you can force nmake to link in - the static CRT by passing `RTLIBCFG=static`. Typically you shouldn't use that - option, and nmake defaults to the DLL CRT. `RTLIBCFG` is rarely used and - therefore rarely tested. When passing `RTLIBCFG` for a configuration that was - already built but not with that option, or if the option was specified - differently, you must destroy the build directory containing the - configuration so that nmake can build it from scratch. - - This option is not recommended unless you have enough development experience - to know how to match the runtime library for linking (that is, the CRT). If - `RTLIBCFG=static` then release builds use `/MT` and debug builds use `/MTd`. - -## Building your own application with libcurl (Visual Studio example) - - When you build curl and libcurl, nmake shows the relative path where the - output directory is. The output directory is named from the options nmake - used when building. You may also see temp directories of the same name but - with suffixes -obj-curl and -obj-lib. - - For example let's say you have built curl.exe and libcurl.dll from the Visual - Studio 2010 x64 Win64 Command Prompt: - - nmake /f Makefile.vc mode=dll VC=10 - - The output directory has a name similar to - `..\builds\libcurl-vc10-x64-release-dll-ipv6-sspi-schannel`. - - The output directory contains subdirectories bin, lib and include. Those are - the directories to set in your Visual Studio project. You can either copy the - output directory to your project or leave it in place. Following the example, - let's assume you leave it in place and your curl top source directory is - `C:\curl-7.82.0`. You would set these options for configurations using the - x64 platform: - -~~~ - - Configuration Properties > Debugging > Environment - PATH=C:\curl-7.82.0\builds\libcurl-vc10-x64-release-dll-ipv6-sspi-schannel\bin;%PATH% - - - C/C++ > General > Additional Include Directories - C:\curl-7.82.0\builds\libcurl-vc10-x64-release-dll-ipv6-sspi-schannel\include; - - - Linker > General > Additional Library Directories - C:\curl-7.82.0\builds\libcurl-vc10-x64-release-dll-ipv6-sspi-schannel\lib; - - - Linker > Input > Additional Dependencies - libcurl.lib; -~~~ - - For configurations using the x86 platform (aka Win32 platform) you would - need to make a separate x86 build of libcurl. - - If you build libcurl static (`mode=static`) or debug (`DEBUG=yes`) then the - library name varies and separate builds may be necessary for separate - configurations of your project within the same platform. This is discussed in - the next section. - -## Building your own application with a static libcurl - - When building an application that uses the static libcurl library on Windows, - you must define `CURL_STATICLIB`. Otherwise the linker looks for dynamic - import symbols. - - The static library name has an `_a` suffix in the basename and the debug - library name has a `_debug` suffix in the basename. For example, - `libcurl_a_debug.lib` is a static debug build of libcurl. - - You may need a separate build of libcurl for each VC configuration combination - (for example: Debug|Win32, Debug|x64, Release|Win32, Release|x64). - - You must specify any additional dependencies needed by your build of static - libcurl (for example: - `advapi32.lib;crypt32.lib;normaliz.lib;ws2_32.lib;wldap32.lib`). - -## Legacy Windows and SSL - - When you build curl using the build files in this directory the default SSL - backend is Schannel (Windows SSPI), the native SSL library that comes with - the Windows OS. Schannel in Windows 8 and earlier is not able to connect to - servers that no longer support the legacy handshakes and algorithms used by - those versions. If you are using curl in one of those earlier versions of - Windows you should choose another SSL backend like OpenSSL. diff --git a/winbuild/makedebug.bat b/winbuild/makedebug.bat deleted file mode 100644 index 6305537e3ded..000000000000 --- a/winbuild/makedebug.bat +++ /dev/null @@ -1,33 +0,0 @@ -@echo off -rem *************************************************************************** -rem * _ _ ____ _ -rem * Project ___| | | | _ \| | -rem * / __| | | | |_) | | -rem * | (__| |_| | _ <| |___ -rem * \___|\___/|_| \_\_____| -rem * -rem * Copyright (C) Daniel Stenberg, , et al. -rem * -rem * This software is licensed as described in the file COPYING, which -rem * you should have received as part of this distribution. The terms -rem * are also available at https://curl.se/docs/copyright.html. -rem * -rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell -rem * copies of the Software, and permit persons to whom the Software is -rem * furnished to do so, under the terms of the COPYING file. -rem * -rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -rem * KIND, either express or implied. -rem * -rem * SPDX-License-Identifier: curl -rem * -rem *************************************************************************** - -where.exe nmake.exe >nul 2>&1 - -if %ERRORLEVEL% EQU 1 ( - echo Error: Cannot find nmake.exe - be sure to run this script from within a Developer Command-Prompt -) else ( - nmake.exe /f Makefile.vc MODE=static DEBUG=yes GEN_PDB=yes - if %ERRORLEVEL% NEQ 0 echo Error: Build Failed -) From 1c49f2f26d0f200bb9de61f795f06a1bc56845e9 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 1 Aug 2025 21:09:52 +0200 Subject: [PATCH 078/208] windows: replace `_beginthreadex()` with `CreateThread()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace `_beginthreadex()` C runtime calls with native win32 API `CreateThread()`. The latter was already used in `src/tool_doswin.c` and in UWP and Windows CE builds before this patch. After this patch all Windows flavors use it. To drop PP logic and simplify code. While working on this it turned out that `src/tool_doswin.c` calls `TerminateThread()`, which isn't recommended by the documentation, except for "the most extreme cases". This patch makes no attempt to change that code. Ref: 9a2663322c330ff11275abafd612e9c99407a94a #17572 Ref: https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminatethread Also: - use `WaitForSingleObjectEx()` on all desktop Windows. Ref: 4be80d5109a340973dc6ce0221ec5c5761587df0 Ref: https://sourceforge.net/p/curl/feature-requests/82/ Ref: https://learn.microsoft.com/windows/win32/api/synchapi/nf-synchapi-waitforsingleobjectex - tests: drop redundant casts. - lib3207: fix to not rely on thread macros when building without thread support. Assisted-by: Jay Satiro Assisted-by: Marcel Raad Assisted-by: Michał Petryka Follow-up to 38029101e2d78ba125732b3bab6ec267b80a0e72 #11625 Closes #18451 --- lib/curl_threads.c | 26 +++++--------------------- lib/curl_threads.h | 12 +++--------- tests/libtest/lib3026.c | 24 +++++------------------- tests/libtest/lib3207.c | 4 ++++ tests/server/sockfilt.c | 11 +++++------ tests/server/util.c | 20 +++++++------------- 6 files changed, 29 insertions(+), 68 deletions(-) diff --git a/lib/curl_threads.c b/lib/curl_threads.c index 96fd0f8a7af9..94425d19fe8a 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -26,12 +26,8 @@ #include -#ifdef USE_THREADS_POSIX -# ifdef HAVE_PTHREAD_H -# include -# endif -#elif defined(USE_THREADS_WIN32) -# include +#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) +#include #endif #include "curl_threads.h" @@ -105,20 +101,8 @@ int Curl_thread_join(curl_thread_t *hnd) curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T (CURL_STDCALL *func) (void *), void *arg) { -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) - typedef HANDLE curl_win_thread_handle_t; -#else - typedef uintptr_t curl_win_thread_handle_t; -#endif - curl_thread_t t; - curl_win_thread_handle_t thread_handle; -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) - thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL); -#else - thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL); -#endif - t = (curl_thread_t)thread_handle; - if((t == 0) || (t == LongToHandle(-1L))) { + curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL); + if(!t) { #ifdef UNDER_CE DWORD gle = GetLastError(); /* !checksrc! disable ERRNOVAR 1 */ @@ -142,7 +126,7 @@ void Curl_thread_destroy(curl_thread_t *hnd) int Curl_thread_join(curl_thread_t *hnd) { -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < _WIN32_WINNT_VISTA) +#ifdef UNDER_CE int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); #else int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); diff --git a/lib/curl_threads.h b/lib/curl_threads.h index 82f08c5fbb56..241014cc6acb 100644 --- a/lib/curl_threads.h +++ b/lib/curl_threads.h @@ -26,6 +26,7 @@ #include "curl_setup.h" #ifdef USE_THREADS_POSIX +# define CURL_THREAD_RETURN_T unsigned int # define CURL_STDCALL # define curl_mutex_t pthread_mutex_t # define curl_thread_t pthread_t * @@ -35,7 +36,8 @@ # define Curl_mutex_release(m) pthread_mutex_unlock(m) # define Curl_mutex_destroy(m) pthread_mutex_destroy(m) #elif defined(USE_THREADS_WIN32) -# define CURL_STDCALL __stdcall +# define CURL_THREAD_RETURN_T DWORD +# define CURL_STDCALL WINAPI # define curl_mutex_t CRITICAL_SECTION # define curl_thread_t HANDLE # define curl_thread_t_null (HANDLE)0 @@ -47,14 +49,6 @@ # define Curl_mutex_acquire(m) EnterCriticalSection(m) # define Curl_mutex_release(m) LeaveCriticalSection(m) # define Curl_mutex_destroy(m) DeleteCriticalSection(m) -#else -# define CURL_STDCALL -#endif - -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) -#define CURL_THREAD_RETURN_T DWORD -#else -#define CURL_THREAD_RETURN_T unsigned int #endif #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) diff --git a/tests/libtest/lib3026.c b/tests/libtest/lib3026.c index 2b35a258417a..167fdd4d332f 100644 --- a/tests/libtest/lib3026.c +++ b/tests/libtest/lib3026.c @@ -26,12 +26,7 @@ #define NUM_THREADS 100 #ifdef _WIN32 -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) -static DWORD WINAPI t3026_run_thread(LPVOID ptr) -#else -#include -static unsigned int WINAPI t3026_run_thread(void *ptr) -#endif +static DWORD WINAPI t3026_run_thread(void *ptr) { CURLcode *result = ptr; @@ -44,13 +39,8 @@ static unsigned int WINAPI t3026_run_thread(void *ptr) static CURLcode test_lib3026(const char *URL) { -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) - typedef HANDLE curl_win_thread_handle_t; -#else - typedef uintptr_t curl_win_thread_handle_t; -#endif CURLcode results[NUM_THREADS]; - curl_win_thread_handle_t thread_handles[NUM_THREADS]; + HANDLE thread_handles[NUM_THREADS]; unsigned tid_count = NUM_THREADS, i; CURLcode test_failure = CURLE_OK; curl_version_info_data *ver; @@ -65,13 +55,9 @@ static CURLcode test_lib3026(const char *URL) } for(i = 0; i < tid_count; i++) { - curl_win_thread_handle_t th; + HANDLE th; results[i] = CURL_LAST; /* initialize with invalid value */ -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) th = CreateThread(NULL, 0, t3026_run_thread, &results[i], 0, NULL); -#else - th = _beginthreadex(NULL, 0, t3026_run_thread, &results[i], 0, NULL); -#endif if(!th) { curl_mfprintf(stderr, "%s:%d Couldn't create thread, errno %lu\n", __FILE__, __LINE__, GetLastError()); @@ -84,8 +70,8 @@ static CURLcode test_lib3026(const char *URL) cleanup: for(i = 0; i < tid_count; i++) { - WaitForSingleObject((HANDLE)thread_handles[i], INFINITE); - CloseHandle((HANDLE)thread_handles[i]); + WaitForSingleObject(thread_handles[i], INFINITE); + CloseHandle(thread_handles[i]); if(results[i] != CURLE_OK) { curl_mfprintf(stderr, "%s:%d thread[%u]: curl_global_init() failed," "with code %d (%s)\n", __FILE__, __LINE__, diff --git a/tests/libtest/lib3207.c b/tests/libtest/lib3207.c index 446d98a00083..e3b50ff40ff2 100644 --- a/tests/libtest/lib3207.c +++ b/tests/libtest/lib3207.c @@ -68,7 +68,11 @@ static size_t write_memory_callback(char *contents, size_t size, return realsize; } +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) static CURL_THREAD_RETURN_T CURL_STDCALL test_thread(void *ptr) +#else +static unsigned int test_thread(void *ptr) +#endif { struct Ctx *ctx = (struct Ctx *)ptr; CURLcode res = CURLE_OK; diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index c8b21beee90c..2785b751340e 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -412,8 +412,7 @@ struct select_ws_wait_data { HANDLE signal; /* internal event to signal handle trigger */ HANDLE abort; /* internal event to abort waiting threads */ }; -#include -static unsigned int WINAPI select_ws_wait_thread(void *lpParameter) +static DWORD WINAPI select_ws_wait_thread(void *lpParameter) { struct select_ws_wait_data *data; HANDLE signal, handle, handles[2]; @@ -557,25 +556,25 @@ static unsigned int WINAPI select_ws_wait_thread(void *lpParameter) static HANDLE select_ws_wait(HANDLE handle, HANDLE signal, HANDLE abort) { - typedef uintptr_t curl_win_thread_handle_t; struct select_ws_wait_data *data; - curl_win_thread_handle_t thread; /* allocate internal waiting data structure */ data = malloc(sizeof(struct select_ws_wait_data)); if(data) { + HANDLE thread; + data->handle = handle; data->signal = signal; data->abort = abort; /* launch waiting thread */ - thread = _beginthreadex(NULL, 0, &select_ws_wait_thread, data, 0, NULL); + thread = CreateThread(NULL, 0, &select_ws_wait_thread, data, 0, NULL); /* free data if thread failed to launch */ if(!thread) { free(data); } - return (HANDLE)thread; + return thread; } return NULL; } diff --git a/tests/server/util.c b/tests/server/util.c index 26a5dd17f708..02f91083e4f4 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -350,7 +350,7 @@ static SIGHANDLER_T old_sigbreak_handler = SIG_ERR; #endif #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) -static unsigned int thread_main_id = 0; +static DWORD thread_main_id = 0; static HANDLE thread_main_window = NULL; static HWND hidden_main_window = NULL; #endif @@ -487,8 +487,7 @@ static LRESULT CALLBACK main_window_proc(HWND hwnd, UINT uMsg, } /* Window message queue loop for hidden main window, details see above. */ -#include -static unsigned int WINAPI main_window_loop(void *lpParameter) +static DWORD WINAPI main_window_loop(void *lpParameter) { WNDCLASS wc; BOOL ret; @@ -509,7 +508,7 @@ static unsigned int WINAPI main_window_loop(void *lpParameter) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, (HWND)NULL, (HMENU)NULL, - wc.hInstance, (LPVOID)NULL); + wc.hInstance, NULL); if(!hidden_main_window) { win32_perror("CreateWindowEx failed"); return (DWORD)-1; @@ -623,15 +622,10 @@ void install_signal_handlers(bool keep_sigalrm) #endif #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) - { - typedef uintptr_t curl_win_thread_handle_t; - curl_win_thread_handle_t thread; - thread = _beginthreadex(NULL, 0, &main_window_loop, - (void *)GetModuleHandle(NULL), 0, &thread_main_id); - thread_main_window = (HANDLE)thread; - if(!thread_main_window || !thread_main_id) - logmsg("cannot start main window loop"); - } + thread_main_window = CreateThread(NULL, 0, &main_window_loop, + GetModuleHandle(NULL), 0, &thread_main_id); + if(!thread_main_window || !thread_main_id) + logmsg("cannot start main window loop"); #endif #endif } From dc3f4fd89b7700a920597630d43e6c2702c6cc46 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 3 Sep 2025 16:48:49 +0200 Subject: [PATCH 079/208] autotools: make `--enable-code-coverage` support llvm/clang Cherry-picked from #18468 Closes #18473 --- configure.ac | 5 ++--- m4/curl-functions.m4 | 32 +++++++++++++++++++------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index 3f02d037ef3d..6c33b561be37 100644 --- a/configure.ac +++ b/configure.ac @@ -128,9 +128,6 @@ CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)".*/\1/p' ${srcdir}/inc XC_CHECK_PROG_CC CURL_ATOMIC -dnl for --enable-code-coverage -CURL_COVERAGE - XC_AUTOMAKE AC_MSG_CHECKING([curl version]) AC_MSG_RESULT($CURLVERSION) @@ -523,6 +520,8 @@ dnl platform/compiler/architecture specific checks/flags dnl ********************************************************************** CURL_CHECK_COMPILER +dnl for --enable-code-coverage +CURL_COVERAGE CURL_CHECK_NATIVE_WINDOWS curl_cv_wince='no' diff --git a/m4/curl-functions.m4 b/m4/curl-functions.m4 index 83206dbc82f6..3640f0c84ebb 100644 --- a/m4/curl-functions.m4 +++ b/m4/curl-functions.m4 @@ -4290,25 +4290,31 @@ AC_DEFUN([CURL_COVERAGE],[ AS_HELP_STRING([--enable-code-coverage], [Provide code coverage]), coverage="$enableval") - dnl if not gcc switch off again - AS_IF([ test "$GCC" != "yes" ], coverage="no" ) + dnl if not gcc or clang switch off again + AS_IF([test "$compiler_id" != "GNU_C" -a "$compiler_id" != "CLANG" -a "$compiler_id" != "APPLECLANG"], coverage="no" ) AC_MSG_RESULT($coverage) if test "x$coverage" = "xyes"; then curl_coverage_msg="enabled" - AC_CHECK_TOOL([GCOV], [gcov], [gcov]) - if test -z "$GCOV"; then - AC_MSG_ERROR([needs gcov for code coverage]) - fi - AC_CHECK_PROG([LCOV], [lcov], [lcov]) - if test -z "$LCOV"; then - AC_MSG_ERROR([needs lcov for code coverage]) - fi - CPPFLAGS="$CPPFLAGS -DNDEBUG" - CFLAGS="$CFLAGS -O0 -g -fprofile-arcs -ftest-coverage" - LIBS="$LIBS -lgcov" + CFLAGS="$CFLAGS -O0 -g" + + if test "$compiler_id" = "GNU_C"; then + AC_CHECK_TOOL([GCOV], [gcov], [gcov]) + if test -z "$GCOV"; then + AC_MSG_ERROR([needs gcov for code coverage]) + fi + AC_CHECK_PROG([LCOV], [lcov], [lcov]) + if test -z "$LCOV"; then + AC_MSG_ERROR([needs lcov for code coverage]) + fi + CFLAGS="$CFLAGS -ftest-coverage -fprofile-arcs" + LIBS="$LIBS -lgcov" + else + CFLAGS="$CFLAGS -fprofile-instr-generate -fcoverage-mapping" + LDFLAGS="$LDFLAGS -fprofile-instr-generate -fcoverage-mapping" + fi fi ]) From 91720b620e802748d2e1629f43e29b76736542f9 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 3 Sep 2025 14:32:29 +0200 Subject: [PATCH 080/208] cmake: add `CURL_CODE_COVERAGE` option To sync up with the `--enable-code-coverage` `./configure` option. Ref: https://gcc.gnu.org/onlinedocs/gcc/Invoking-Gcov.html Ref: https://gcc.gnu.org/onlinedocs/gcc/Cross-profiling.html Ref: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html Closes #18468 --- CMakeLists.txt | 23 +++++++++++++++++++++++ docs/INSTALL-CMAKE.md | 1 + lib/CMakeLists.txt | 17 +++++++++++++++++ src/CMakeLists.txt | 10 ++++++++++ 4 files changed, 51 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0265162e74d3..ad78c58ed1db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -311,6 +311,26 @@ if(CURL_CLANG_TIDY) endif() endif() +option(CURL_CODE_COVERAGE "Enable code coverage build options" OFF) +if(CURL_CODE_COVERAGE) + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + set(CURL_COVERAGE_MACROS "NDEBUG") + set(CURL_COVERAGE_CFLAGS "-O0" "-g" "-fprofile-arcs") + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.1) + list(APPEND CURL_COVERAGE_CFLAGS "--coverage") + else() + list(APPEND CURL_COVERAGE_CFLAGS "-ftest-coverage") + endif() + set(CURL_COVERAGE_LIBS "gcov") + elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CURL_COVERAGE_MACROS "NDEBUG") + set(CURL_COVERAGE_CFLAGS "-O0" "-g" "-fprofile-instr-generate" "-fcoverage-mapping") + set(CURL_COVERAGE_LDFLAGS "-fprofile-instr-generate" "-fcoverage-mapping") + else() + set(CURL_CODE_COVERAGE OFF) + endif() +endif() + # For debug libs and exes, add "-d" postfix if(NOT DEFINED CMAKE_DEBUG_POSTFIX) set(CMAKE_DEBUG_POSTFIX "-d") @@ -1984,6 +2004,9 @@ if(WIN32) endif() list(APPEND CURL_LIBS ${CURL_NETWORK_AND_TIME_LIBS}) +if(CURL_CODE_COVERAGE) + list(APPEND CURL_LIBS ${CURL_COVERAGE_LIBS}) +endif() if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") # MSVC but exclude clang-cl set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-MP") # Parallel compilation diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index b112e1f8b435..94a19c71c749 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -227,6 +227,7 @@ target_link_libraries(my_target PRIVATE CURL::libcurl) - `BUILD_TESTING`: Build tests. Default: `ON` - `CURL_CLANG_TIDY`: Run the build through `clang-tidy`. Default: `OFF` - `CURL_CLANG_TIDYFLAGS`: Custom options to pass to `clang-tidy`. Default: (empty) +- `CURL_CODE_COVERAGE`: Enable code coverage build options. Default: `OFF` - `CURL_COMPLETION_FISH`: Install fish completions. Default: `OFF` - `CURL_COMPLETION_FISH_DIR`: Custom fish completion install directory. - `CURL_COMPLETION_ZSH`: Install zsh completions. Default: `OFF` diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 3476d55b096a..7dce3aea8770 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -124,6 +124,10 @@ if(SHARE_LIB_OBJECT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() + if(CURL_CODE_COVERAGE) + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) + endif() target_include_directories(${LIB_OBJECT} INTERFACE "$" @@ -162,6 +166,10 @@ if(BUILD_STATIC_LIBS) set_target_properties(${LIB_STATIC} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() + if(CURL_CODE_COVERAGE) + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) + endif() target_include_directories(${LIB_STATIC} INTERFACE "$" @@ -198,6 +206,15 @@ if(BUILD_SHARED_LIBS) set_target_properties(${LIB_SHARED} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() + if(CURL_CODE_COVERAGE) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) + target_link_options(${LIB_SHARED} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + else() + target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + endif() + endif() target_include_directories(${LIB_SHARED} INTERFACE "$" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37ca979bab99..c4b8ebb9346d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,6 +129,16 @@ if(ENABLE_UNICODE AND MINGW AND NOT MINGW32CE) endif() endif() +if(CURL_CODE_COVERAGE) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) + target_link_options(${EXE_NAME} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + else() + target_link_libraries(${EXE_NAME} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + endif() +endif() + ################################################################################ install(TARGETS ${EXE_NAME} EXPORT ${TARGETS_EXPORT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) From 096fc4325b895b507defd387aed0d021a3ea0a02 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 7 Sep 2025 17:30:05 +0200 Subject: [PATCH 081/208] digest_sspi: fix two memory leaks in error branches Closes #18488 --- lib/vauth/digest_sspi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index 861c4e1cb91b..cf297ff84dca 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -521,6 +521,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(!digest->user) { free(output_token); + Curl_sspi_free_identity(p_identity); return CURLE_OUT_OF_MEMORY; } } @@ -530,6 +531,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(!digest->passwd) { free(output_token); + Curl_sspi_free_identity(p_identity); Curl_safefree(digest->user); return CURLE_OUT_OF_MEMORY; } From ad26a6cb99b6a5a98cfb3856743f0cea14657895 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 5 Sep 2025 10:44:06 +0200 Subject: [PATCH 082/208] tidy-up: avoid using the reserved macro namespace To avoid hitting `-Wreserved-macro-identifier` where possible. - amigaos: introduce local macro instead of reusing `__request()`. - easy_lock: avoid redefining `__has_builtin()`. Follow-up to 33fd57b8fff8c0d873da2316a2a7f911caac2bae #9062 - rand: drop interim macro `_random()`. - windows: rename local macro `_tcsdup()` to `Curl_tcsdup()`. To avoid using the reserved macro namespace and to avoid colliding with `_tcsdup()` as defined by Windows headers. - checksrc: ban `_tcsdup()` in favor of `Curl_tcsdup()`. - tool_doswin: avoid redefining `_use_lfn()` (MS-DOS). - tool_findfile: limit `__NO_NET_API` hack to AmigaOS. Syncing this pattern with `lib/netrc.c`. Follow-up to 784a8ec2c1a3cc4bd676077a28a0d5f6ee7786a5 #16279 - examples/http2-upload: avoid reserved namespace for local macro. More cases will be removed when dropping WinCE support via #17927. Cases remain when defining external macros out of curl's control. Ref: #18477 Closes #18482 --- docs/examples/http2-upload.c | 4 ++-- docs/internals/CODE_STYLE.md | 1 + lib/amigaos.c | 7 ++++--- lib/curl_mem_undef.h | 2 +- lib/curl_memory.h | 6 +++--- lib/curl_setup.h | 2 +- lib/curl_sspi.c | 4 ++-- lib/easy_lock.h | 14 ++++++-------- lib/memdebug.h | 6 +++--- lib/rand.c | 12 +++++------- lib/vauth/digest_sspi.c | 2 +- lib/vauth/vauth.c | 2 +- lib/vtls/schannel.c | 2 +- scripts/checksrc.pl | 1 + src/tool_doswin.c | 7 ++++--- src/tool_findfile.c | 4 ++++ 16 files changed, 40 insertions(+), 36 deletions(-) diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index 31f4ed56e1ba..128a4b0beda1 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -71,14 +71,14 @@ int my_gettimeofday(struct timeval *tp, void *tzp) (void)tzp; if(tp) { /* Offset between 1601-01-01 and 1970-01-01 in 100 nanosec units */ - #define _WIN32_FT_OFFSET (116444736000000000) + #define WIN32_FT_OFFSET (116444736000000000) union { CURL_TYPEOF_CURL_OFF_T ns100; /* time since 1 Jan 1601 in 100ns units */ FILETIME ft; } _now; GetSystemTimeAsFileTime(&_now.ft); tp->tv_usec = (long)((_now.ns100 / 10) % 1000000); - tp->tv_sec = (long)((_now.ns100 - _WIN32_FT_OFFSET) / 10000000); + tp->tv_sec = (long)((_now.ns100 - WIN32_FT_OFFSET) / 10000000); } return 0; } diff --git a/docs/internals/CODE_STYLE.md b/docs/internals/CODE_STYLE.md index dadec934ddc4..aef5103fed6f 100644 --- a/docs/internals/CODE_STYLE.md +++ b/docs/internals/CODE_STYLE.md @@ -335,6 +335,7 @@ This is the full list of functions generally banned. _mbscat _mbsncat _tcscat + _tcsdup _tcsncat _waccess _wcscat diff --git a/lib/amigaos.c b/lib/amigaos.c index ac6d6b41937d..cc5d49f9b8e7 100644 --- a/lib/amigaos.c +++ b/lib/amigaos.c @@ -199,8 +199,9 @@ struct Library *SocketBase = NULL; #ifdef __libnix__ void __request(const char *msg); +#define CURL_AMIGA_REQUEST(msg) __request(msg) #else -# define __request(msg) Printf((const unsigned char *)(msg "\n\a"), 0) +#define CURL_AMIGA_REQUEST(msg) Printf((const unsigned char *)(msg "\n\a"), 0) #endif void Curl_amiga_cleanup(void) @@ -217,14 +218,14 @@ CURLcode Curl_amiga_init(void) SocketBase = OpenLibrary((const unsigned char *)"bsdsocket.library", 4); if(!SocketBase) { - __request("No TCP/IP Stack running!"); + CURL_AMIGA_REQUEST("No TCP/IP Stack running!"); return CURLE_FAILED_INIT; } if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", TAG_DONE)) { - __request("SocketBaseTags ERROR"); + CURL_AMIGA_REQUEST("SocketBaseTags ERROR"); return CURLE_FAILED_INIT; } diff --git a/lib/curl_mem_undef.h b/lib/curl_mem_undef.h index acc3a9226aef..f3cca294e9a5 100644 --- a/lib/curl_mem_undef.h +++ b/lib/curl_mem_undef.h @@ -30,7 +30,7 @@ #undef realloc #undef free #ifdef _WIN32 -#undef _tcsdup +#undef Curl_tcsdup #endif #ifdef CURLDEBUG diff --git a/lib/curl_memory.h b/lib/curl_memory.h index 07ef111ce78e..7793bb63a389 100644 --- a/lib/curl_memory.h +++ b/lib/curl_memory.h @@ -77,11 +77,11 @@ #define free(ptr) Curl_cfree(ptr) #ifdef _WIN32 -#undef _tcsdup +#undef Curl_tcsdup #ifdef UNICODE -#define _tcsdup(ptr) Curl_wcsdup(ptr) +#define Curl_tcsdup(ptr) Curl_wcsdup(ptr) #else -#define _tcsdup(ptr) Curl_cstrdup(ptr) +#define Curl_tcsdup(ptr) Curl_cstrdup(ptr) #endif #endif /* _WIN32 */ diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 72c118affcc0..93cbb570568d 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -46,7 +46,7 @@ fail. Fixed in 14.2.0_1. Disable the workaround if the fix is detected. */ #if defined(__APPLE__) && !defined(__clang__) && defined(__GNUC__) && \ defined(__has_attribute) -# if !defined(__has_feature) +# if !defined(__has_feature) /* Keep this PP check separate from others */ # define availability curl_pp_attribute_disabled # elif !__has_feature(attribute_availability) # define availability curl_pp_attribute_disabled diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index 635f560b68a3..c819b1c22ea5 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -138,7 +138,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, } /* Setup the identity's user and length */ - dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); + dup_user.tchar_ptr = Curl_tcsdup(user.tchar_ptr); if(!dup_user.tchar_ptr) { curlx_unicodefree(useranddomain.tchar_ptr); return CURLE_OUT_OF_MEMORY; @@ -165,7 +165,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, passwd.tchar_ptr = curlx_convert_UTF8_to_tchar(passwdp); if(!passwd.tchar_ptr) return CURLE_OUT_OF_MEMORY; - dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); + dup_passwd.tchar_ptr = Curl_tcsdup(passwd.tchar_ptr); if(!dup_passwd.tchar_ptr) { curlx_unicodefree(passwd.tchar_ptr); return CURLE_OUT_OF_MEMORY; diff --git a/lib/easy_lock.h b/lib/easy_lock.h index 909753f43aa3..f8998cc5472c 100644 --- a/lib/easy_lock.h +++ b/lib/easy_lock.h @@ -45,20 +45,18 @@ #define curl_simple_lock atomic_int #define CURL_SIMPLE_LOCK_INIT 0 -/* a clang-thing */ -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - #ifndef __INTEL_COMPILER /* The Intel compiler tries to look like GCC *and* clang *and* lies in its __has_builtin() function, so override it. */ /* if GCC on i386/x86_64 or if the built-in is present */ -#if ( (defined(__GNUC__) && !defined(__clang__)) && \ - (defined(__i386__) || defined(__x86_64__))) || \ - __has_builtin(__builtin_ia32_pause) +#if (defined(__GNUC__) && !defined(__clang__)) && \ + (defined(__i386__) || defined(__x86_64__)) #define HAVE_BUILTIN_IA32_PAUSE +#elif defined(__has_builtin) /* Keep this PP check separate from others */ +#if __has_builtin(__builtin_ia32_pause) +#define HAVE_BUILTIN_IA32_PAUSE +#endif #endif #endif diff --git a/lib/memdebug.h b/lib/memdebug.h index 30469b99a503..eabdd9c258cf 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -48,11 +48,11 @@ #define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) #ifdef _WIN32 -#undef _tcsdup +#undef Curl_tcsdup #ifdef UNICODE -#define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) +#define Curl_tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) #else -#define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) +#define Curl_tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) #endif #endif /* _WIN32 */ diff --git a/lib/rand.c b/lib/rand.c index a1a5e42c2bb0..f30f3de7c34d 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -149,12 +149,6 @@ static CURLcode weak_random(struct Curl_easy *data, } #endif -#ifdef USE_SSL -#define _random(x,y,z) Curl_ssl_random(x,y,z) -#else -#define _random(x,y,z) weak_random(x,y,z) -#endif - static CURLcode randit(struct Curl_easy *data, unsigned int *rnd, bool env_override) { @@ -185,7 +179,11 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd, #endif /* data may be NULL! */ - return _random(data, (unsigned char *)rnd, sizeof(*rnd)); +#ifdef USE_SSL + return Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd)); +#else + return weak_random(data, (unsigned char *)rnd, sizeof(*rnd)); +#endif } /* diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index cf297ff84dca..0a1fe84ddf41 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -277,7 +277,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, if(!domain.tchar_ptr) return CURLE_OUT_OF_MEMORY; - dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); + dup_domain.tchar_ptr = Curl_tcsdup(domain.tchar_ptr); if(!dup_domain.tchar_ptr) { curlx_unicodefree(domain.tchar_ptr); return CURLE_OUT_OF_MEMORY; diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c index 1b44aa6de1ad..c6cf4285725a 100644 --- a/lib/vauth/vauth.c +++ b/lib/vauth/vauth.c @@ -100,7 +100,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, free(utf8_spn); if(!tchar_spn) return NULL; - dupe_tchar_spn = _tcsdup(tchar_spn); + dupe_tchar_spn = Curl_tcsdup(tchar_spn); curlx_unicodefree(tchar_spn); return dupe_tchar_spn; } diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 1afc6790cc51..21dcf1371b32 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -433,7 +433,7 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, return CURLE_SSL_CERTPROBLEM; *sep = TEXT('\0'); - *store_path = _tcsdup(store_path_start); + *store_path = Curl_tcsdup(store_path_start); *sep = TEXT('\\'); if(!*store_path) return CURLE_OUT_OF_MEMORY; diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 574e03c13b24..c52b8258d7f0 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -62,6 +62,7 @@ "_mbscat" => 1, "_mbsncat" => 1, "_tcscat" => 1, + "_tcsdup" => 1, "_tcsncat" => 1, "_wcscat" => 1, "_wcsncat" => 1, diff --git a/src/tool_doswin.c b/src/tool_doswin.c index 4ed90ba8c50f..c0dcfed04e37 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -46,9 +46,10 @@ # undef PATH_MAX # define PATH_MAX MAX_PATH #elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */ -# define _use_lfn(f) (0) /* long filenames never available */ +# define CURL_USE_LFN(f) 0 /* long filenames never available */ #elif defined(__DJGPP__) -# include /* _use_lfn(f) prototype */ +# include /* for _use_lfn(f) prototype */ +# define CURL_USE_LFN(f) _use_lfn(f) #endif #ifdef MSDOS @@ -314,7 +315,7 @@ static SANITIZEcode msdosify(char **const sanitized, const char *file_name, return SANITIZE_ERR_INVALID_PATH; /* Support for Windows 9X VFAT systems, when available. */ - if(_use_lfn(file_name)) { + if(CURL_USE_LFN(file_name)) { illegal_aliens = illegal_chars_w95; len -= (illegal_chars_w95 - illegal_chars_dos); } diff --git a/src/tool_findfile.c b/src/tool_findfile.c index 72868f4b4f73..8b2be8414214 100644 --- a/src/tool_findfile.c +++ b/src/tool_findfile.c @@ -24,10 +24,14 @@ #include "tool_setup.h" #ifdef HAVE_PWD_H +#ifdef __AMIGA__ #undef __NO_NET_API /* required for AmigaOS to declare getpwuid() */ +#endif #include +#ifdef __AMIGA__ #define __NO_NET_API #endif +#endif #ifdef HAVE_FCNTL_H #include From 87cbeecee4118fa3dcc8a0179b1c3b43e4775cb4 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 7 Sep 2025 21:42:41 +0200 Subject: [PATCH 083/208] windows: stop passing unused, optional argument for Win9x compatibility Expiry timestamp in `AcquireCredentialsHandle()` (SSPI) and `InitializeSecurityContext()` (Schannel) calls. The argument is optional in both. The returned value was never used in curl. The reason for passing it was Windows 95 compatibility, according to comments in the SSPI code. curl no longer supports Windows 95. Ref: https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-acquirecredentialshandlea Ref: https://learn.microsoft.com/windows/win32/secauthn/initializesecuritycontext--schannel Ref: 3fe531196771c8e81f917eebca4a06e062ab3a19 Ref: aaa42aa0d594b95c6c670a373ba30c507aa0a5ed Closes #18490 --- lib/socks_sspi.c | 6 ++---- lib/vauth/digest_sspi.c | 10 ++++------ lib/vauth/krb5_sspi.c | 6 ++---- lib/vauth/ntlm_sspi.c | 8 +++----- lib/vauth/spnego_sspi.c | 6 ++---- lib/vtls/schannel.c | 13 +++++-------- lib/vtls/schannel_int.h | 2 -- 7 files changed, 18 insertions(+), 33 deletions(-) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 3ff3b723f9a2..cdc9ef864a9a 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -83,7 +83,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, CtxtHandle sspi_context; PCtxtHandle context_handle = NULL; SecPkgCredentials_Names names; - TimeStamp expiry; char *service_name = NULL; unsigned short us_length; unsigned long qop; @@ -146,7 +145,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, (TCHAR *)CURL_UNCONST(TEXT("Kerberos")), SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, - &cred_handle, &expiry); + &cred_handle, NULL); if(check_sspi_err(data, status, "AcquireCredentialsHandle")) { failf(data, "Failed to acquire credentials."); @@ -178,8 +177,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, &input_desc, 0, &sspi_context, &output_desc, - &sspi_ret_flags, - &expiry); + &sspi_ret_flags, NULL); curlx_unicodefree(sname); diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index 0a1fe84ddf41..2f4b8d4a1dca 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -112,7 +112,6 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ /* Ensure we have a valid challenge message */ if(!Curl_bufref_len(chlg)) { @@ -168,7 +167,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)), SECPKG_CRED_OUTBOUND, NULL, p_identity, NULL, NULL, - &credentials, &expiry); + &credentials, NULL); if(status != SEC_E_OK) { Curl_sspi_free_identity(p_identity); @@ -197,7 +196,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, 0, 0, 0, &chlg_desc, 0, &context, &resp_desc, &attrs, - &expiry); + NULL); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) @@ -488,7 +487,6 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, SecBuffer resp_buf; SecBufferDesc resp_desc; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ TCHAR *spn; /* free the copy of user/passwd used to make the previous identity */ @@ -542,7 +540,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)), SECPKG_CRED_OUTBOUND, NULL, p_identity, NULL, NULL, - &credentials, &expiry); + &credentials, NULL); if(status != SEC_E_OK) { Curl_sspi_free_identity(p_identity); free(output_token); @@ -597,7 +595,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, ISC_REQ_USE_HTTP_STYLE, 0, 0, &chlg_desc, 0, digest->http_context, - &resp_desc, &attrs, &expiry); + &resp_desc, &attrs, NULL); curlx_unicodefree(spn); if(status == SEC_I_COMPLETE_NEEDED || diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c index 6595ab977a79..985f1c38fc63 100644 --- a/lib/vauth/krb5_sspi.c +++ b/lib/vauth/krb5_sspi.c @@ -107,7 +107,6 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ if(!krb5->spn) { /* Generate our SPN */ @@ -162,7 +161,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_KERBEROS)), SECPKG_CRED_OUTBOUND, NULL, krb5->p_identity, NULL, NULL, - krb5->credentials, &expiry); + krb5->credentials, NULL); if(status != SEC_E_OK) return CURLE_LOGIN_DENIED; @@ -204,8 +203,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, 0, SECURITY_NATIVE_DREP, chlg ? &chlg_desc : NULL, 0, &context, - &resp_desc, &attrs, - &expiry); + &resp_desc, &attrs, NULL); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index 101eb8abd305..9127a9bb277d 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -98,7 +98,6 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, SecBufferDesc type_1_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ /* Clean up any former leftovers and initialise to defaults */ Curl_auth_cleanup_ntlm(ntlm); @@ -147,7 +146,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NTLM)), SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity, NULL, NULL, - ntlm->credentials, &expiry); + ntlm->credentials, NULL); if(status != SEC_E_OK) return CURLE_LOGIN_DENIED; @@ -174,7 +173,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, 0, 0, SECURITY_NETWORK_DREP, NULL, 0, ntlm->context, &type_1_desc, - &attrs, &expiry); + &attrs, NULL); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) Curl_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); @@ -255,7 +254,6 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, SecBufferDesc type_3_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; @@ -314,7 +312,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, &type_2_desc, 0, ntlm->context, &type_3_desc, - &attrs, &expiry); + &attrs, NULL); if(status != SEC_E_OK) { infof(data, "NTLM handshake failure (type-3 message): Status=%lx", status); diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index af3a9c9798c2..f21c66796f91 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -105,7 +105,6 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, SecBufferDesc chlg_desc; SecBufferDesc resp_desc; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; @@ -173,7 +172,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NEGOTIATE)), SECPKG_CRED_OUTBOUND, NULL, nego->p_identity, NULL, NULL, - nego->credentials, &expiry); + nego->credentials, NULL); if(nego->status != SEC_E_OK) return CURLE_AUTH_ERROR; @@ -250,8 +249,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, 0, SECURITY_NATIVE_DREP, chlg ? &chlg_desc : NULL, 0, nego->context, - &resp_desc, &attrs, - &expiry); + &resp_desc, &attrs, NULL); /* Free the decoded challenge as it is not required anymore */ free(chlg); diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 21dcf1371b32..fb9ef108226b 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -796,8 +796,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, (TCHAR *)CURL_UNCONST(UNISP_NAME), SECPKG_CRED_OUTBOUND, NULL, &credentials, NULL, NULL, - &backend->cred->cred_handle, - &backend->cred->time_stamp); + &backend->cred->cred_handle, NULL); } else { /* Pre-Windows 10 1809 or the user set a legacy algorithm list. @@ -835,8 +834,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, (TCHAR *)CURL_UNCONST(UNISP_NAME), SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL, - &backend->cred->cred_handle, - &backend->cred->time_stamp); + &backend->cred->cred_handle, NULL); } if(client_certs[0]) @@ -1050,7 +1048,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) backend->req_flags, 0, 0, (backend->use_alpn ? &inbuf_desc : NULL), 0, &backend->ctxt->ctxt_handle, - &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); + &outbuf_desc, &backend->ret_flags, NULL); if(sspi_status != SEC_I_CONTINUE_NEEDED) { char buffer[STRERROR_LEN]; @@ -1259,7 +1257,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) &backend->cred->cred_handle, &backend->ctxt->ctxt_handle, backend->cred->sni_hostname, backend->req_flags, 0, 0, &inbuf_desc, 0, NULL, - &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); + &outbuf_desc, &backend->ret_flags, NULL); /* free buffer for received handshake data */ Curl_safefree(inbuf[0].pvBuffer); @@ -2440,8 +2438,7 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, 0, &backend->ctxt->ctxt_handle, &outbuf_desc, - &backend->ret_flags, - &backend->ctxt->time_stamp); + &backend->ret_flags, NULL); if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { /* send close message which is in output buffer */ diff --git a/lib/vtls/schannel_int.h b/lib/vtls/schannel_int.h index 5483d12b5bb7..f9adb5829440 100644 --- a/lib/vtls/schannel_int.h +++ b/lib/vtls/schannel_int.h @@ -99,7 +99,6 @@ typedef struct _SCH_CREDENTIALS { struct Curl_schannel_cred { CredHandle cred_handle; - TimeStamp time_stamp; TCHAR *sni_hostname; HCERTSTORE client_cert_store; int refcount; @@ -107,7 +106,6 @@ struct Curl_schannel_cred { struct Curl_schannel_ctxt { CtxtHandle ctxt_handle; - TimeStamp time_stamp; }; struct schannel_ssl_backend_data { From 92f215fea1aa8bd5b1709d38f42aab77ab3fc662 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 4 Sep 2025 11:56:33 +0200 Subject: [PATCH 084/208] build: address some `-Weverything` warnings, update picky warnings `-Weverything` is not enabled by curl, and not recommended by LLVM, because it may enable experimental options, and will result in new fallouts after toolchain upgrades. This patch aims to fix/silence as much as possible as found with llvm/clang 21.1.0. It also permanently enables warnings that were fixed in source and deemed manageable in the future. `-Wformat` warnings are addressed separately via #18343. Fix/silence warnings in the source: - typecheck-gcc.h: fix `-Wreserved-identifier`. - lib: silence `-Wcast-function-type-strict`. For llvm 16+ or Apple clang 16+. - asyn-ares: limit `HAPPY_EYEBALLS_DNS_TIMEOUT` to old c-ares versions. - curl_trc: fix `-Wc++-hidden-decl`. - doh: fix `-Wc++-keyword`. - ftp: fix `-Wreserved-identifier`. - ldap: fix `-Wreserved-identifier`. - mqtt: comment unused macro to avoid warning. - multi_ev: drop unused macros to avoid warnings. - setopt: fix useless `break;` after `return;`. - gtls, mbedtls, rustls: silence `-Wconditional-uninitialized`. - socks_sspi, schannel, x509asn1: fix `-Wimplicit-int-enum-cast`. - x509asn1: fix `-Wc++-keyword`. - openssl: scope `OSSL_UI_METHOD_CAST` to avoid unused macro warning. - libssh2, wolfssl: drop unused macros. - curl_ngtcp2, curl_quiche, httpsrr, urlapi: drop/limit unused macros. - tool_getparam: fix useless `break;` after `return;` or `break;`. Not normally enabled because it doesn't work with unity. https://github.com/llvm/llvm-project/issues/71046 - tool_operate: fix `-Wc++-keyword`. - curlinfo: fix a `-Wunsafe-buffer-usage`. - tests: silence `-Wformat-non-iso`. - lib557: fix `-Wreserved-identifier`. - lib1565: silence `-Wconditional-uninitialized`. Enable the above clang warnings permanently in picky mode: - `-Wc++-hidden-decl` - `-Wc++-keyword` (except for Windows, where it collides with `wchar_t`) - `-Wcast-function-type-strict` - `-Wcast-function-type` - `-Wconditional-uninitialized` - `-Wformat-non-iso` (except for clang-cl) - `-Wreserved-identifier` - `-Wtentative-definition-compat` Silence problematic `-Weverything` warnings globally (in picky mode): - `-Wused-but-marked-unused` (88000+ hits) and `-Wdisabled-macro-expansion` (2600+ hits). Triggered by `typecheck-gcc.h` when building with clang 14+. Maybe there exists a way to fix within that header? Ref: https://discourse.llvm.org/t/removing-wused-but-marked-unused/55310 - `-Wunsafe-buffer-usage`. clang 16+. 7000+ hits. May be useful in theory, but such high volume of hits makes it impractical to review and possibly address. Meant for C++. Ref: https://clang.llvm.org/docs/SafeBuffers.html Ref: https://stackoverflow.com/questions/77017567/how-to-fix-code-to-avoid-warning-wunsafe-buffer-usage Ref: https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734 Ref: https://github.com/llvm/llvm-project/pull/111624 - `-Wimplicit-void-ptr-cast`. clang 21+. 1700+ hits. C++ warning, deemed pure noise. Ref: https://github.com/curl/curl/issues/18470#issuecomment-3253506266 - `-Wswitch-default` (180+ hits), `-Wswitch-enum` (190+ hits), `-Wcovered-switch-default` (20+ hits). Next to impossible to fix cleanly, esp. when the covered `case` branches depend on compile-time options. - `-Wdocumentation-unknown-command` (8+ hits). Triggered in a few sources. Seems arbitrary and bogus. - `-Wpadded` (550+ hits). - `-Wc++-keyword` on Windows, where it collides with `wchar_t`. (100+ hits) Ref: https://github.com/llvm/llvm-project/issues/155988 - `-Wreserved-macro-identifier`. clang 13+. 5+ hits. Sometimes it's necessary to set external macros that use the reserved namespace. E.g. `_CRT_NONSTDC_NO_DEPRECATE`, `__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__`, `__NO_NET_API`, possibly `_REENTRANT`, and more. It's not worth trying to silence them individually. - `-Wnonportable-system-include-path` with `clang-cl`. It'd be broken by doing what the warning suggests. - `-Wformat-non-iso` for clang-cl. CMake `PICKY_COMPILER=ON` (the default) or `./configure` `--enable-warnings` (not the default) is required to enable these silencing rules. Also: - autotools, cmake: fix Apple clang and mainline llvm version translations. Ref: https://en.wikipedia.org/wiki/Xcode#Toolchain_versions - autotools, cmake: enable `-Warray-compare` for clang 20+. Follow-up to 4b7accda5ae3f2e663aa3f3853805241ef87c2fe #17196 - cmake: fix to enable `-Wmissing-variable-declarations` at an earlier clang version. - cmake: update internal logic to handle warning options with `+` in them. - cmake: fix internal logic to match the whole option when looking into `CMAKE_C_FLAGS` for custom-disabled warnings. Follow-up to b85cb8cb4e143d1615d4fcc1ce8f2f7b66453995 #18485 Closes #18477 --- CMake/PickyWarnings.cmake | 120 ++++++++-- include/curl/typecheck-gcc.h | 418 +++++++++++++++++------------------ lib/asyn-ares.c | 22 +- lib/curl_trc.c | 2 - lib/curl_trc.h | 10 +- lib/curlx/version_win32.c | 7 + lib/doh.c | 10 +- lib/formdata.c | 7 + lib/ftp.c | 12 +- lib/httpsrr.c | 2 - lib/ldap.c | 43 ++-- lib/mqtt.c | 2 +- lib/multi_ev.c | 4 - lib/sendf.c | 7 + lib/setopt.c | 16 +- lib/socks_sspi.c | 23 +- lib/url.c | 7 + lib/urlapi.c | 2 + lib/vquic/curl_ngtcp2.c | 7 - lib/vquic/curl_quiche.c | 6 - lib/vssh/libssh2.c | 10 +- lib/vtls/gtls.c | 2 +- lib/vtls/mbedtls.c | 2 +- lib/vtls/openssl.c | 16 +- lib/vtls/rustls.c | 4 +- lib/vtls/schannel.c | 11 +- lib/vtls/wolfssl.c | 3 - lib/vtls/x509asn1.c | 4 +- lib/vtls/x509asn1.h | 2 +- m4/curl-compilers.m4 | 73 ++++-- src/curlinfo.c | 6 +- src/tool_getparam.c | 3 - src/tool_operate.c | 4 +- tests/libtest/lib1565.c | 2 +- tests/libtest/lib557.c | 13 +- tests/unit/unit1398.c | 9 + 36 files changed, 532 insertions(+), 359 deletions(-) diff --git a/CMake/PickyWarnings.cmake b/CMake/PickyWarnings.cmake index f67576d68123..bdd226e9246e 100644 --- a/CMake/PickyWarnings.cmake +++ b/CMake/PickyWarnings.cmake @@ -47,8 +47,8 @@ endif() if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.6) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.3)) - list(APPEND _picky "-Werror=partial-availability") # clang 3.6 appleclang 6.3 + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1)) + list(APPEND _picky "-Werror=partial-availability") # clang 3.6 appleclang 6.1 endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") @@ -87,6 +87,9 @@ if(PICKY_COMPILER) set(_picky_detect ) + # Notes: -Wno-* options should ideally be disabled at their precise cutoff versions, + # to suppress undesired warnings in case -Weverything is passed as a custom option. + # Assume these options always exist with both clang and gcc. # Require clang 3.0 / gcc 2.95 or later. list(APPEND _picky_enable @@ -121,13 +124,14 @@ if(PICKY_COMPILER) -Wmissing-field-initializers # clang 2.7 gcc 4.1 -Wmissing-noreturn # clang 2.7 gcc 4.1 -Wno-format-nonliteral # clang 1.0 gcc 2.96 (3.0) + -Wno-padded # clang 2.9 gcc 4.1 # Not used: We cannot change public structs -Wno-sign-conversion # clang 2.9 gcc 4.3 + -Wno-switch-default # clang 2.7 gcc 4.1 # Not used: Annoying to fix or silence + -Wno-switch-enum # clang 2.7 gcc 4.1 # Not used: It basically disallows default case -Wno-system-headers # clang 1.0 gcc 3.0 - # -Wpadded # clang 2.9 gcc 4.1 # Not used: We cannot change public structs -Wold-style-definition # clang 2.7 gcc 3.4 -Wredundant-decls # clang 2.7 gcc 4.1 -Wstrict-prototypes # clang 1.0 gcc 3.3 - # -Wswitch-enum # clang 2.7 gcc 4.1 # Not used: It basically disallows default case -Wtype-limits # clang 2.7 gcc 4.3 -Wunreachable-code # clang 2.7 gcc 4.1 # -Wunused-macros # clang 2.7 gcc 4.1 # Not practical @@ -139,6 +143,8 @@ if(PICKY_COMPILER) if(CMAKE_C_COMPILER_ID MATCHES "Clang") list(APPEND _picky_enable ${_picky_common_old} + -Wconditional-uninitialized # clang 3.0 + -Wno-used-but-marked-unused # clang 3.0 # Triggered by typecheck-gcc.h (with clang 14+) -Wshift-sign-overflow # clang 2.9 -Wshorten-64-to-32 # clang 1.0 -Wformat=2 # clang 3.0 gcc 4.8 @@ -149,39 +155,102 @@ if(PICKY_COMPILER) ) endif() # Enable based on compiler version + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.1) + list(APPEND _picky_enable + -Wno-covered-switch-default # clang 3.1 appleclang 3.1 # Annoying to fix or silence + -Wno-disabled-macro-expansion # clang 3.1 appleclang 3.1 # Triggered by typecheck-gcc.h (with clang 14+) + ) + if(MSVC) + list(APPEND _picky_enable + -Wno-format-non-iso # clang 3.1 appleclang 3.1 # 'q' length modifier is not supported by ISO C + ) + else() + list(APPEND _picky_enable + -Wformat-non-iso # clang 3.1 appleclang 3.1 + ) + endif() + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.3) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0)) + list(APPEND _picky_enable + -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.2 g++ 11.0 + -Wmissing-variable-declarations # clang 3.2 appleclang 4.2 + -Wno-documentation-unknown-command # clang 3.3 appleclang 5.0 + -Wsometimes-uninitialized # clang 3.2 appleclang 4.2 + ) + endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.6) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.3)) + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1)) list(APPEND _picky_enable - -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.3 - -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.6 g++ 11.0 + -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.1 -Wheader-guard # clang 3.4 appleclang 5.1 -Wpragmas # clang 3.5 gcc 4.1 appleclang 6.0 - -Wsometimes-uninitialized # clang 3.2 appleclang 4.6 # -Wunreachable-code-break # clang 3.5 appleclang 6.0 # Not used: Silent in "unity" builds -Wunused-const-variable # clang 3.4 gcc 6.0 appleclang 5.1 ) endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.9) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.3)) + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)) list(APPEND _picky_enable - -Wcomma # clang 3.9 appleclang 8.3 - -Wmissing-variable-declarations # clang 3.2 appleclang 4.6 + -Wcomma # clang 3.9 appleclang 8.1 ) + if(MSVC) + list(APPEND _picky_enable + -Wno-nonportable-system-include-path # clang 3.9 appleclang 8.1 # No truly portable solution to this + ) + endif() endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.3)) + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11)) list(APPEND _picky_enable - -Wassign-enum # clang 7.0 appleclang 10.3 - -Wextra-semi-stmt # clang 7.0 appleclang 10.3 + -Wassign-enum # clang 7.0 appleclang 11.0 + -Wextra-semi-stmt # clang 7.0 appleclang 11.0 ) endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.4)) + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12)) + list(APPEND _picky_enable + -Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 9.0 # We do silencing for clang 10.0 and above only + -Wxor-used-as-pow # clang 10.0 gcc 13.0 appleclang 12.0 + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1)) + list(APPEND _picky_enable + -Wcast-function-type # clang 13.0 appleclang 13.1 + -Wreserved-identifier # clang 13.0 appleclang 13.1 # Keep it before -Wno-reserved-macro-identifier + -Wno-reserved-macro-identifier # clang 13.0 appleclang 13.1 # External macros have to be set sometimes + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0)) + list(APPEND _picky_enable + -Wno-unsafe-buffer-usage # clang 16.0 appleclang 15.0 + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)) list(APPEND _picky_enable - -Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 12.4 # We do silencing for clang 10.0 and above only - -Wxor-used-as-pow # clang 10.0 gcc 13.0 + -Wcast-function-type-strict # clang 16.0 appleclang 16.0 ) endif() + if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 21.0) + list(APPEND _picky_enable + -Warray-compare # clang 20.0 gcc 12.0 appleclang ? + -Wc++-hidden-decl # clang 21.0 appleclang ? + -Wno-implicit-void-ptr-cast # clang 21.0 appleclang ? + -Wtentative-definition-compat # clang 21.0 appleclang ? + ) + if(WIN32) + list(APPEND _picky_enable + -Wno-c++-keyword # clang 21.0 appleclang ? # `wchar_t` triggers it on Windows + ) + else() + list(APPEND _picky_enable + -Wc++-keyword # clang 21.0 appleclang ? + ) + endif() + endif() else() # gcc # Enable based on compiler version if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.3) @@ -207,7 +276,7 @@ if(PICKY_COMPILER) endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.8) list(APPEND _picky_enable - -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.3 + -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.1 -Wformat=2 # clang 3.0 gcc 4.8 -Wtrampolines # gcc 4.6 ) @@ -232,21 +301,21 @@ if(PICKY_COMPILER) -Walloc-zero # gcc 7.0 -Wduplicated-branches # gcc 7.0 -Wformat-truncation=2 # gcc 7.0 - -Wimplicit-fallthrough # clang 4.0 gcc 7.0 + -Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 9.0 -Wrestrict # gcc 7.0 ) endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) list(APPEND _picky_enable -Warith-conversion # gcc 10.0 - -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.6 g++ 11.0 + -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.2 g++ 11.0 ) endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0) list(APPEND _picky_enable - -Warray-compare # clang 20.0 gcc 12.0 + -Warray-compare # clang 20.0 gcc 12.0 appleclang ? -Wenum-int-mismatch # gcc 13.0 - -Wxor-used-as-pow # clang 10.0 gcc 13.0 + -Wxor-used-as-pow # clang 10.0 gcc 13.0 appleclang 12.0 ) endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0) @@ -262,8 +331,11 @@ if(PICKY_COMPILER) set(_picky_skipped "") foreach(_ccopt IN LISTS _picky_enable) - string(REGEX MATCH "-W([a-z0-9-]+)" _ccmatch "${_ccopt}") - if(_ccmatch AND CMAKE_C_FLAGS MATCHES "-Wno-${CMAKE_MATCH_1}" AND NOT _ccopt STREQUAL "-Wall" AND NOT _ccopt MATCHES "^-Wno-") + string(REGEX MATCH "-W([a-z0-9+-]+)" _ccmatch "${_ccopt}") + string(REPLACE "+" "\\+" _cmake_match_1 "${CMAKE_MATCH_1}") # escape '+' to make it a valid regex + if(_ccmatch AND "${CMAKE_C_FLAGS} " MATCHES "-Wno-${_cmake_match_1} " AND + NOT _ccopt STREQUAL "-Wall" AND + NOT _ccopt MATCHES "^-Wno-") string(APPEND _picky_skipped " ${_ccopt}") else() list(APPEND _picky "${_ccopt}") diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index a0b41aeb2473..07fba246d4c4 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -29,9 +29,9 @@ /* To add a new kind of warning, add an * if(curlcheck_sometype_option(_curl_opt)) * if(!curlcheck_sometype(value)) - * _curl_easy_setopt_err_sometype(); + * Wcurl_easy_setopt_err_sometype(); * block and define curlcheck_sometype_option, curlcheck_sometype and - * _curl_easy_setopt_err_sometype below + * Wcurl_easy_setopt_err_sometype below * * NOTE: We use two nested 'if' statements here instead of the && operator, in * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x @@ -47,113 +47,113 @@ CURL_IGNORE_DEPRECATION( \ if(curlcheck_long_option(option)) \ if(!curlcheck_long(value)) \ - _curl_easy_setopt_err_long(); \ + Wcurl_easy_setopt_err_long(); \ if(curlcheck_off_t_option(option)) \ if(!curlcheck_off_t(value)) \ - _curl_easy_setopt_err_curl_off_t(); \ + Wcurl_easy_setopt_err_curl_off_t(); \ if(curlcheck_string_option(option)) \ if(!curlcheck_string(value)) \ - _curl_easy_setopt_err_string(); \ + Wcurl_easy_setopt_err_string(); \ if((option) == CURLOPT_PRIVATE) { } \ if(curlcheck_write_cb_option(option)) \ if(!curlcheck_write_cb(value)) \ - _curl_easy_setopt_err_write_callback(); \ + Wcurl_easy_setopt_err_write_callback(); \ if(curlcheck_curl_option(option)) \ if(!curlcheck_curl(value)) \ - _curl_easy_setopt_err_curl(); \ + Wcurl_easy_setopt_err_curl(); \ if((option) == CURLOPT_RESOLVER_START_FUNCTION) \ if(!curlcheck_resolver_start_callback(value)) \ - _curl_easy_setopt_err_resolver_start_callback(); \ + Wcurl_easy_setopt_err_resolver_start_callback(); \ if((option) == CURLOPT_READFUNCTION) \ if(!curlcheck_read_cb(value)) \ - _curl_easy_setopt_err_read_cb(); \ + Wcurl_easy_setopt_err_read_cb(); \ if((option) == CURLOPT_IOCTLFUNCTION) \ if(!curlcheck_ioctl_cb(value)) \ - _curl_easy_setopt_err_ioctl_cb(); \ + Wcurl_easy_setopt_err_ioctl_cb(); \ if((option) == CURLOPT_SOCKOPTFUNCTION) \ if(!curlcheck_sockopt_cb(value)) \ - _curl_easy_setopt_err_sockopt_cb(); \ + Wcurl_easy_setopt_err_sockopt_cb(); \ if((option) == CURLOPT_OPENSOCKETFUNCTION) \ if(!curlcheck_opensocket_cb(value)) \ - _curl_easy_setopt_err_opensocket_cb(); \ + Wcurl_easy_setopt_err_opensocket_cb(); \ if((option) == CURLOPT_PROGRESSFUNCTION) \ if(!curlcheck_progress_cb(value)) \ - _curl_easy_setopt_err_progress_cb(); \ + Wcurl_easy_setopt_err_progress_cb(); \ if((option) == CURLOPT_XFERINFOFUNCTION) \ if(!curlcheck_xferinfo_cb(value)) \ - _curl_easy_setopt_err_xferinfo_cb(); \ + Wcurl_easy_setopt_err_xferinfo_cb(); \ if((option) == CURLOPT_DEBUGFUNCTION) \ if(!curlcheck_debug_cb(value)) \ - _curl_easy_setopt_err_debug_cb(); \ + Wcurl_easy_setopt_err_debug_cb(); \ if((option) == CURLOPT_SSL_CTX_FUNCTION) \ if(!curlcheck_ssl_ctx_cb(value)) \ - _curl_easy_setopt_err_ssl_ctx_cb(); \ + Wcurl_easy_setopt_err_ssl_ctx_cb(); \ if(curlcheck_conv_cb_option(option)) \ if(!curlcheck_conv_cb(value)) \ - _curl_easy_setopt_err_conv_cb(); \ + Wcurl_easy_setopt_err_conv_cb(); \ if((option) == CURLOPT_SEEKFUNCTION) \ if(!curlcheck_seek_cb(value)) \ - _curl_easy_setopt_err_seek_cb(); \ + Wcurl_easy_setopt_err_seek_cb(); \ if((option) == CURLOPT_CHUNK_BGN_FUNCTION) \ if(!curlcheck_chunk_bgn_cb(value)) \ - _curl_easy_setopt_err_chunk_bgn_cb(); \ + Wcurl_easy_setopt_err_chunk_bgn_cb(); \ if((option) == CURLOPT_CHUNK_END_FUNCTION) \ if(!curlcheck_chunk_end_cb(value)) \ - _curl_easy_setopt_err_chunk_end_cb(); \ + Wcurl_easy_setopt_err_chunk_end_cb(); \ if((option) == CURLOPT_CLOSESOCKETFUNCTION) \ if(!curlcheck_close_socket_cb(value)) \ - _curl_easy_setopt_err_close_socket_cb(); \ + Wcurl_easy_setopt_err_close_socket_cb(); \ if((option) == CURLOPT_FNMATCH_FUNCTION) \ if(!curlcheck_fnmatch_cb(value)) \ - _curl_easy_setopt_err_fnmatch_cb(); \ + Wcurl_easy_setopt_err_fnmatch_cb(); \ if((option) == CURLOPT_HSTSREADFUNCTION) \ if(!curlcheck_hstsread_cb(value)) \ - _curl_easy_setopt_err_hstsread_cb(); \ + Wcurl_easy_setopt_err_hstsread_cb(); \ if((option) == CURLOPT_HSTSWRITEFUNCTION) \ if(!curlcheck_hstswrite_cb(value)) \ - _curl_easy_setopt_err_hstswrite_cb(); \ + Wcurl_easy_setopt_err_hstswrite_cb(); \ if((option) == CURLOPT_SSH_HOSTKEYFUNCTION) \ if(!curlcheck_ssh_hostkey_cb(value)) \ - _curl_easy_setopt_err_ssh_hostkey_cb(); \ + Wcurl_easy_setopt_err_ssh_hostkey_cb(); \ if((option) == CURLOPT_SSH_KEYFUNCTION) \ if(!curlcheck_ssh_key_cb(value)) \ - _curl_easy_setopt_err_ssh_key_cb(); \ + Wcurl_easy_setopt_err_ssh_key_cb(); \ if((option) == CURLOPT_INTERLEAVEFUNCTION) \ if(!curlcheck_interleave_cb(value)) \ - _curl_easy_setopt_err_interleave_cb(); \ + Wcurl_easy_setopt_err_interleave_cb(); \ if((option) == CURLOPT_PREREQFUNCTION) \ if(!curlcheck_prereq_cb(value)) \ - _curl_easy_setopt_err_prereq_cb(); \ + Wcurl_easy_setopt_err_prereq_cb(); \ if((option) == CURLOPT_TRAILERFUNCTION) \ if(!curlcheck_trailer_cb(value)) \ - _curl_easy_setopt_err_trailer_cb(); \ + Wcurl_easy_setopt_err_trailer_cb(); \ if(curlcheck_cb_data_option(option)) \ if(!curlcheck_cb_data(value)) \ - _curl_easy_setopt_err_cb_data(); \ + Wcurl_easy_setopt_err_cb_data(); \ if((option) == CURLOPT_ERRORBUFFER) \ if(!curlcheck_error_buffer(value)) \ - _curl_easy_setopt_err_error_buffer(); \ + Wcurl_easy_setopt_err_error_buffer(); \ if((option) == CURLOPT_CURLU) \ if(!curlcheck_ptr((value), CURLU)) \ - _curl_easy_setopt_err_curlu(); \ + Wcurl_easy_setopt_err_curlu(); \ if((option) == CURLOPT_STDERR) \ if(!curlcheck_FILE(value)) \ - _curl_easy_setopt_err_FILE(); \ + Wcurl_easy_setopt_err_FILE(); \ if(curlcheck_postfields_option(option)) \ if(!curlcheck_postfields(value)) \ - _curl_easy_setopt_err_postfields(); \ + Wcurl_easy_setopt_err_postfields(); \ if((option) == CURLOPT_HTTPPOST) \ if(!curlcheck_arr((value), struct curl_httppost)) \ - _curl_easy_setopt_err_curl_httpost(); \ + Wcurl_easy_setopt_err_curl_httpost(); \ if((option) == CURLOPT_MIMEPOST) \ if(!curlcheck_ptr((value), curl_mime)) \ - _curl_easy_setopt_err_curl_mimepost(); \ + Wcurl_easy_setopt_err_curl_mimepost(); \ if(curlcheck_slist_option(option)) \ if(!curlcheck_arr((value), struct curl_slist)) \ - _curl_easy_setopt_err_curl_slist(); \ + Wcurl_easy_setopt_err_curl_slist(); \ if((option) == CURLOPT_SHARE) \ if(!curlcheck_ptr((value), CURLSH)) \ - _curl_easy_setopt_err_CURLSH(); \ + Wcurl_easy_setopt_err_CURLSH(); \ ) \ } \ curl_easy_setopt(handle, option, value); \ @@ -166,28 +166,28 @@ CURL_IGNORE_DEPRECATION( \ if(curlcheck_string_info(info)) \ if(!curlcheck_arr((arg), char *)) \ - _curl_easy_getinfo_err_string(); \ + Wcurl_easy_getinfo_err_string(); \ if(curlcheck_long_info(info)) \ if(!curlcheck_arr((arg), long)) \ - _curl_easy_getinfo_err_long(); \ + Wcurl_easy_getinfo_err_long(); \ if(curlcheck_double_info(info)) \ if(!curlcheck_arr((arg), double)) \ - _curl_easy_getinfo_err_double(); \ + Wcurl_easy_getinfo_err_double(); \ if(curlcheck_slist_info(info)) \ if(!curlcheck_arr((arg), struct curl_slist *)) \ - _curl_easy_getinfo_err_curl_slist(); \ + Wcurl_easy_getinfo_err_curl_slist(); \ if(curlcheck_tlssessioninfo_info(info)) \ if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \ - _curl_easy_getinfo_err_curl_tlssessioninfo(); \ + Wcurl_easy_getinfo_err_curl_tlssessioninfo(); \ if(curlcheck_certinfo_info(info)) \ if(!curlcheck_arr((arg), struct curl_certinfo *)) \ - _curl_easy_getinfo_err_curl_certinfo(); \ + Wcurl_easy_getinfo_err_curl_certinfo(); \ if(curlcheck_socket_info(info)) \ if(!curlcheck_arr((arg), curl_socket_t)) \ - _curl_easy_getinfo_err_curl_socket(); \ + Wcurl_easy_getinfo_err_curl_socket(); \ if(curlcheck_off_t_info(info)) \ if(!curlcheck_arr((arg), curl_off_t)) \ - _curl_easy_getinfo_err_curl_off_t(); \ + Wcurl_easy_getinfo_err_curl_off_t(); \ ) \ } \ curl_easy_getinfo(handle, info, arg); \ @@ -198,25 +198,25 @@ if(__builtin_constant_p(option)) { \ if(curlcheck_long_option(option)) \ if(!curlcheck_long(value)) \ - _curl_multi_setopt_err_long(); \ + Wcurl_multi_setopt_err_long(); \ if(curlcheck_off_t_option(option)) \ if(!curlcheck_off_t(value)) \ - _curl_multi_setopt_err_curl_off_t(); \ + Wcurl_multi_setopt_err_curl_off_t(); \ if(curlcheck_multicb_data_option(option)) \ if(!curlcheck_cb_data(value)) \ - _curl_multi_setopt_err_cb_data(); \ + Wcurl_multi_setopt_err_cb_data(); \ if(curlcheck_charpp_option(option)) \ if(!curlcheck_ptrptr(value, char)) \ - _curl_multi_setopt_err_charpp(); \ + Wcurl_multi_setopt_err_charpp(); \ if((option) == CURLMOPT_PUSHFUNCTION) \ if(!curlcheck_multipush_cb(value)) \ - _curl_multi_setopt_err_pushcb(); \ + Wcurl_multi_setopt_err_pushcb(); \ if((option) == CURLMOPT_SOCKETFUNCTION) \ if(!curlcheck_multisocket_cb(value)) \ - _curl_multi_setopt_err_socketcb(); \ + Wcurl_multi_setopt_err_socketcb(); \ if((option) == CURLMOPT_TIMERFUNCTION) \ if(!curlcheck_multitimer_cb(value)) \ - _curl_multi_setopt_err_timercb(); \ + Wcurl_multi_setopt_err_timercb(); \ } \ curl_multi_setopt(handle, option, value); \ }) @@ -256,7 +256,7 @@ #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) -/* the actual warnings, triggered by calling the _curl_easy_setopt_err* +/* the actual warnings, triggered by calling the Wcurl_easy_setopt_err* * functions */ /* To define a new warning, use _CURL_WARNING(identifier, "message") */ @@ -265,117 +265,117 @@ __attribute__((__unused__)) __attribute__((__noinline__)) \ id(void) { __asm__(""); } -CURLWARNING(_curl_multi_setopt_err_long, +CURLWARNING(Wcurl_multi_setopt_err_long, "curl_multi_setopt expects a long argument") -CURLWARNING(_curl_multi_setopt_err_curl_off_t, +CURLWARNING(Wcurl_multi_setopt_err_curl_off_t, "curl_multi_setopt expects a curl_off_t argument") -CURLWARNING(_curl_multi_setopt_err_cb_data, +CURLWARNING(Wcurl_multi_setopt_err_cb_data, "curl_multi_setopt expects a 'void *' argument") -CURLWARNING(_curl_multi_setopt_err_charpp, +CURLWARNING(Wcurl_multi_setopt_err_charpp, "curl_multi_setopt expects a 'char **' argument") -CURLWARNING(_curl_multi_setopt_err_pushcb, +CURLWARNING(Wcurl_multi_setopt_err_pushcb, "curl_multi_setopt expects a curl_push_callback argument") -CURLWARNING(_curl_multi_setopt_err_socketcb, +CURLWARNING(Wcurl_multi_setopt_err_socketcb, "curl_multi_setopt expects a curl_socket_callback argument") -CURLWARNING(_curl_multi_setopt_err_timercb, +CURLWARNING(Wcurl_multi_setopt_err_timercb, "curl_multi_setopt expects a curl_multi_timer_callback argument") -CURLWARNING(_curl_easy_setopt_err_long, +CURLWARNING(Wcurl_easy_setopt_err_long, "curl_easy_setopt expects a long argument") -CURLWARNING(_curl_easy_setopt_err_curl_off_t, +CURLWARNING(Wcurl_easy_setopt_err_curl_off_t, "curl_easy_setopt expects a curl_off_t argument") -CURLWARNING(_curl_easy_setopt_err_string, +CURLWARNING(Wcurl_easy_setopt_err_string, "curl_easy_setopt expects a " "string ('char *' or char[]) argument") -CURLWARNING(_curl_easy_setopt_err_write_callback, +CURLWARNING(Wcurl_easy_setopt_err_write_callback, "curl_easy_setopt expects a curl_write_callback argument") -CURLWARNING(_curl_easy_setopt_err_resolver_start_callback, +CURLWARNING(Wcurl_easy_setopt_err_resolver_start_callback, "curl_easy_setopt expects a " "curl_resolver_start_callback argument") -CURLWARNING(_curl_easy_setopt_err_read_cb, +CURLWARNING(Wcurl_easy_setopt_err_read_cb, "curl_easy_setopt expects a curl_read_callback argument") -CURLWARNING(_curl_easy_setopt_err_ioctl_cb, +CURLWARNING(Wcurl_easy_setopt_err_ioctl_cb, "curl_easy_setopt expects a curl_ioctl_callback argument") -CURLWARNING(_curl_easy_setopt_err_sockopt_cb, +CURLWARNING(Wcurl_easy_setopt_err_sockopt_cb, "curl_easy_setopt expects a curl_sockopt_callback argument") -CURLWARNING(_curl_easy_setopt_err_opensocket_cb, +CURLWARNING(Wcurl_easy_setopt_err_opensocket_cb, "curl_easy_setopt expects a " "curl_opensocket_callback argument") -CURLWARNING(_curl_easy_setopt_err_progress_cb, +CURLWARNING(Wcurl_easy_setopt_err_progress_cb, "curl_easy_setopt expects a curl_progress_callback argument") -CURLWARNING(_curl_easy_setopt_err_xferinfo_cb, +CURLWARNING(Wcurl_easy_setopt_err_xferinfo_cb, "curl_easy_setopt expects a curl_xferinfo_callback argument") -CURLWARNING(_curl_easy_setopt_err_debug_cb, +CURLWARNING(Wcurl_easy_setopt_err_debug_cb, "curl_easy_setopt expects a curl_debug_callback argument") -CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb, +CURLWARNING(Wcurl_easy_setopt_err_ssl_ctx_cb, "curl_easy_setopt expects a curl_ssl_ctx_callback argument") -CURLWARNING(_curl_easy_setopt_err_conv_cb, +CURLWARNING(Wcurl_easy_setopt_err_conv_cb, "curl_easy_setopt expects a curl_conv_callback argument") -CURLWARNING(_curl_easy_setopt_err_seek_cb, +CURLWARNING(Wcurl_easy_setopt_err_seek_cb, "curl_easy_setopt expects a curl_seek_callback argument") -CURLWARNING(_curl_easy_setopt_err_cb_data, +CURLWARNING(Wcurl_easy_setopt_err_cb_data, "curl_easy_setopt expects a " "private data pointer as argument") -CURLWARNING(_curl_easy_setopt_err_chunk_bgn_cb, +CURLWARNING(Wcurl_easy_setopt_err_chunk_bgn_cb, "curl_easy_setopt expects a curl_chunk_bgn_callback argument") -CURLWARNING(_curl_easy_setopt_err_chunk_end_cb, +CURLWARNING(Wcurl_easy_setopt_err_chunk_end_cb, "curl_easy_setopt expects a curl_chunk_end_callback argument") -CURLWARNING(_curl_easy_setopt_err_close_socket_cb, +CURLWARNING(Wcurl_easy_setopt_err_close_socket_cb, "curl_easy_setopt expects a curl_closesocket_callback argument") -CURLWARNING(_curl_easy_setopt_err_fnmatch_cb, +CURLWARNING(Wcurl_easy_setopt_err_fnmatch_cb, "curl_easy_setopt expects a curl_fnmatch_callback argument") -CURLWARNING(_curl_easy_setopt_err_hstsread_cb, +CURLWARNING(Wcurl_easy_setopt_err_hstsread_cb, "curl_easy_setopt expects a curl_hstsread_callback argument") -CURLWARNING(_curl_easy_setopt_err_hstswrite_cb, +CURLWARNING(Wcurl_easy_setopt_err_hstswrite_cb, "curl_easy_setopt expects a curl_hstswrite_callback argument") -CURLWARNING(_curl_easy_setopt_err_ssh_key_cb, +CURLWARNING(Wcurl_easy_setopt_err_ssh_key_cb, "curl_easy_setopt expects a curl_sshkeycallback argument") -CURLWARNING(_curl_easy_setopt_err_ssh_hostkey_cb, +CURLWARNING(Wcurl_easy_setopt_err_ssh_hostkey_cb, "curl_easy_setopt expects a curl_sshhostkeycallback argument") -CURLWARNING(_curl_easy_setopt_err_interleave_cb, +CURLWARNING(Wcurl_easy_setopt_err_interleave_cb, "curl_easy_setopt expects a curl_interleave_callback argument") -CURLWARNING(_curl_easy_setopt_err_prereq_cb, +CURLWARNING(Wcurl_easy_setopt_err_prereq_cb, "curl_easy_setopt expects a curl_prereq_callback argument") -CURLWARNING(_curl_easy_setopt_err_trailer_cb, +CURLWARNING(Wcurl_easy_setopt_err_trailer_cb, "curl_easy_setopt expects a curl_trailerfunc_ok argument") -CURLWARNING(_curl_easy_setopt_err_error_buffer, +CURLWARNING(Wcurl_easy_setopt_err_error_buffer, "curl_easy_setopt expects a " "char buffer of CURL_ERROR_SIZE as argument") -CURLWARNING(_curl_easy_setopt_err_curlu, +CURLWARNING(Wcurl_easy_setopt_err_curlu, "curl_easy_setopt expects a 'CURLU *' argument") -CURLWARNING(_curl_easy_setopt_err_curl, +CURLWARNING(Wcurl_easy_setopt_err_curl, "curl_easy_setopt expects a 'CURL *' argument") -CURLWARNING(_curl_easy_setopt_err_FILE, +CURLWARNING(Wcurl_easy_setopt_err_FILE, "curl_easy_setopt expects a 'FILE *' argument") -CURLWARNING(_curl_easy_setopt_err_postfields, +CURLWARNING(Wcurl_easy_setopt_err_postfields, "curl_easy_setopt expects a 'void *' or 'char *' argument") -CURLWARNING(_curl_easy_setopt_err_curl_httpost, +CURLWARNING(Wcurl_easy_setopt_err_curl_httpost, "curl_easy_setopt expects a 'struct curl_httppost *' " "argument") -CURLWARNING(_curl_easy_setopt_err_curl_mimepost, +CURLWARNING(Wcurl_easy_setopt_err_curl_mimepost, "curl_easy_setopt expects a 'curl_mime *' " "argument") -CURLWARNING(_curl_easy_setopt_err_curl_slist, +CURLWARNING(Wcurl_easy_setopt_err_curl_slist, "curl_easy_setopt expects a 'struct curl_slist *' argument") -CURLWARNING(_curl_easy_setopt_err_CURLSH, +CURLWARNING(Wcurl_easy_setopt_err_CURLSH, "curl_easy_setopt expects a CURLSH* argument") -CURLWARNING(_curl_easy_getinfo_err_string, +CURLWARNING(Wcurl_easy_getinfo_err_string, "curl_easy_getinfo expects a pointer to 'char *'") -CURLWARNING(_curl_easy_getinfo_err_long, +CURLWARNING(Wcurl_easy_getinfo_err_long, "curl_easy_getinfo expects a pointer to long") -CURLWARNING(_curl_easy_getinfo_err_double, +CURLWARNING(Wcurl_easy_getinfo_err_double, "curl_easy_getinfo expects a pointer to double") -CURLWARNING(_curl_easy_getinfo_err_curl_slist, +CURLWARNING(Wcurl_easy_getinfo_err_curl_slist, "curl_easy_getinfo expects a pointer to 'struct curl_slist *'") -CURLWARNING(_curl_easy_getinfo_err_curl_tlssessioninfo, +CURLWARNING(Wcurl_easy_getinfo_err_curl_tlssessioninfo, "curl_easy_getinfo expects a pointer to " "'struct curl_tlssessioninfo *'") -CURLWARNING(_curl_easy_getinfo_err_curl_certinfo, +CURLWARNING(Wcurl_easy_getinfo_err_curl_certinfo, "curl_easy_getinfo expects a pointer to " "'struct curl_certinfo *'") -CURLWARNING(_curl_easy_getinfo_err_curl_socket, +CURLWARNING(Wcurl_easy_getinfo_err_curl_socket, "curl_easy_getinfo expects a pointer to curl_socket_t") -CURLWARNING(_curl_easy_getinfo_err_curl_off_t, +CURLWARNING(Wcurl_easy_getinfo_err_curl_off_t, "curl_easy_getinfo expects a pointer to curl_off_t") /* groups of curl_easy_setops options that take the same type of argument */ @@ -704,60 +704,60 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), __typeof__(fread) *) || \ curlcheck_cb_compatible((expr), curl_read_callback) || \ - curlcheck_cb_compatible((expr), _curl_read_callback1) || \ - curlcheck_cb_compatible((expr), _curl_read_callback2) || \ - curlcheck_cb_compatible((expr), _curl_read_callback3) || \ - curlcheck_cb_compatible((expr), _curl_read_callback4) || \ - curlcheck_cb_compatible((expr), _curl_read_callback5) || \ - curlcheck_cb_compatible((expr), _curl_read_callback6)) -typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); -typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); -typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); -typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); -typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); -typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); + curlcheck_cb_compatible((expr), Wcurl_read_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback4) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback5) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback6)) +typedef size_t (*Wcurl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (*Wcurl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (*Wcurl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (*Wcurl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (*Wcurl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (*Wcurl_read_callback6)(void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_write_callback or "similar" */ #define curlcheck_write_cb(expr) \ (curlcheck_read_cb(expr) || \ curlcheck_cb_compatible((expr), __typeof__(fwrite) *) || \ curlcheck_cb_compatible((expr), curl_write_callback) || \ - curlcheck_cb_compatible((expr), _curl_write_callback1) || \ - curlcheck_cb_compatible((expr), _curl_write_callback2) || \ - curlcheck_cb_compatible((expr), _curl_write_callback3) || \ - curlcheck_cb_compatible((expr), _curl_write_callback4) || \ - curlcheck_cb_compatible((expr), _curl_write_callback5) || \ - curlcheck_cb_compatible((expr), _curl_write_callback6)) -typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); -typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, + curlcheck_cb_compatible((expr), Wcurl_write_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback4) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback5) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback6)) +typedef size_t (*Wcurl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (*Wcurl_write_callback2)(const char *, size_t, size_t, const void *); -typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); -typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); -typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, +typedef size_t (*Wcurl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (*Wcurl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (*Wcurl_write_callback5)(const void *, size_t, size_t, const void *); -typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); +typedef size_t (*Wcurl_write_callback6)(const void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ #define curlcheck_ioctl_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_ioctl_callback) || \ - curlcheck_cb_compatible((expr), _curl_ioctl_callback1) || \ - curlcheck_cb_compatible((expr), _curl_ioctl_callback2) || \ - curlcheck_cb_compatible((expr), _curl_ioctl_callback3) || \ - curlcheck_cb_compatible((expr), _curl_ioctl_callback4)) -typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); -typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); -typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); -typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + curlcheck_cb_compatible((expr), Wcurl_ioctl_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_ioctl_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_ioctl_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_ioctl_callback4)) +typedef curlioerr (*Wcurl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (*Wcurl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (*Wcurl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (*Wcurl_ioctl_callback4)(CURL *, curliocmd, const void *); /* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ #define curlcheck_sockopt_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_sockopt_callback) || \ - curlcheck_cb_compatible((expr), _curl_sockopt_callback1) || \ - curlcheck_cb_compatible((expr), _curl_sockopt_callback2)) -typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); -typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, + curlcheck_cb_compatible((expr), Wcurl_sockopt_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_sockopt_callback2)) +typedef int (*Wcurl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (*Wcurl_sockopt_callback2)(const void *, curl_socket_t, curlsocktype); /* evaluates to true if expr is of type curl_opensocket_callback or @@ -765,28 +765,28 @@ typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, #define curlcheck_opensocket_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_opensocket_callback) || \ - curlcheck_cb_compatible((expr), _curl_opensocket_callback1) || \ - curlcheck_cb_compatible((expr), _curl_opensocket_callback2) || \ - curlcheck_cb_compatible((expr), _curl_opensocket_callback3) || \ - curlcheck_cb_compatible((expr), _curl_opensocket_callback4)) -typedef curl_socket_t (*_curl_opensocket_callback1) + curlcheck_cb_compatible((expr), Wcurl_opensocket_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_opensocket_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_opensocket_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_opensocket_callback4)) +typedef curl_socket_t (*Wcurl_opensocket_callback1) (void *, curlsocktype, struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback2) +typedef curl_socket_t (*Wcurl_opensocket_callback2) (void *, curlsocktype, const struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback3) +typedef curl_socket_t (*Wcurl_opensocket_callback3) (const void *, curlsocktype, struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback4) +typedef curl_socket_t (*Wcurl_opensocket_callback4) (const void *, curlsocktype, const struct curl_sockaddr *); /* evaluates to true if expr is of type curl_progress_callback or "similar" */ #define curlcheck_progress_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_progress_callback) || \ - curlcheck_cb_compatible((expr), _curl_progress_callback1) || \ - curlcheck_cb_compatible((expr), _curl_progress_callback2)) -typedef int (*_curl_progress_callback1)(void *, + curlcheck_cb_compatible((expr), Wcurl_progress_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_progress_callback2)) +typedef int (*Wcurl_progress_callback1)(void *, double, double, double, double); -typedef int (*_curl_progress_callback2)(const void *, +typedef int (*Wcurl_progress_callback2)(const void *, double, double, double, double); /* evaluates to true if expr is of type curl_xferinfo_callback */ @@ -798,29 +798,29 @@ typedef int (*_curl_progress_callback2)(const void *, #define curlcheck_debug_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_debug_callback) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback1) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback2) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback3) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback4) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback5) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback6) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback7) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback8)) -typedef int (*_curl_debug_callback1) (CURL *, + curlcheck_cb_compatible((expr), Wcurl_debug_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback4) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback5) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback6) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback7) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback8)) +typedef int (*Wcurl_debug_callback1) (CURL *, curl_infotype, char *, size_t, void *); -typedef int (*_curl_debug_callback2) (CURL *, +typedef int (*Wcurl_debug_callback2) (CURL *, curl_infotype, char *, size_t, const void *); -typedef int (*_curl_debug_callback3) (CURL *, +typedef int (*Wcurl_debug_callback3) (CURL *, curl_infotype, const char *, size_t, void *); -typedef int (*_curl_debug_callback4) (CURL *, +typedef int (*Wcurl_debug_callback4) (CURL *, curl_infotype, const char *, size_t, const void *); -typedef int (*_curl_debug_callback5) (CURL *, +typedef int (*Wcurl_debug_callback5) (CURL *, curl_infotype, unsigned char *, size_t, void *); -typedef int (*_curl_debug_callback6) (CURL *, +typedef int (*Wcurl_debug_callback6) (CURL *, curl_infotype, unsigned char *, size_t, const void *); -typedef int (*_curl_debug_callback7) (CURL *, +typedef int (*Wcurl_debug_callback7) (CURL *, curl_infotype, const unsigned char *, size_t, void *); -typedef int (*_curl_debug_callback8) (CURL *, +typedef int (*Wcurl_debug_callback8) (CURL *, curl_infotype, const unsigned char *, size_t, const void *); /* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ @@ -828,66 +828,66 @@ typedef int (*_curl_debug_callback8) (CURL *, #define curlcheck_ssl_ctx_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_ssl_ctx_callback) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback1) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback2) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback3) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback4) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback5) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback6) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback7) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback8)) -typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); -typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback4) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback5) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback6) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback7) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback8)) +typedef CURLcode (*Wcurl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback4)(CURL *, const void *, const void *); #ifdef HEADER_SSL_H /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX * this will of course break if we are included before OpenSSL headers... */ -typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *); -typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *, +typedef CURLcode (*Wcurl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback8)(CURL *, const SSL_CTX *, const void *); #else -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +typedef Wcurl_ssl_ctx_callback1 Wcurl_ssl_ctx_callback5; +typedef Wcurl_ssl_ctx_callback1 Wcurl_ssl_ctx_callback6; +typedef Wcurl_ssl_ctx_callback1 Wcurl_ssl_ctx_callback7; +typedef Wcurl_ssl_ctx_callback1 Wcurl_ssl_ctx_callback8; #endif /* evaluates to true if expr is of type curl_conv_callback or "similar" */ #define curlcheck_conv_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_conv_callback) || \ - curlcheck_cb_compatible((expr), _curl_conv_callback1) || \ - curlcheck_cb_compatible((expr), _curl_conv_callback2) || \ - curlcheck_cb_compatible((expr), _curl_conv_callback3) || \ - curlcheck_cb_compatible((expr), _curl_conv_callback4)) -typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); -typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); -typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); -typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + curlcheck_cb_compatible((expr), Wcurl_conv_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_conv_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_conv_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_conv_callback4)) +typedef CURLcode (*Wcurl_conv_callback1)(char *, size_t length); +typedef CURLcode (*Wcurl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*Wcurl_conv_callback3)(void *, size_t length); +typedef CURLcode (*Wcurl_conv_callback4)(const void *, size_t length); /* evaluates to true if expr is of type curl_seek_callback or "similar" */ #define curlcheck_seek_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_seek_callback) || \ - curlcheck_cb_compatible((expr), _curl_seek_callback1) || \ - curlcheck_cb_compatible((expr), _curl_seek_callback2)) -typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); -typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + curlcheck_cb_compatible((expr), Wcurl_seek_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_seek_callback2)) +typedef CURLcode (*Wcurl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*Wcurl_seek_callback2)(const void *, curl_off_t, int); /* evaluates to true if expr is of type curl_chunk_bgn_callback */ #define curlcheck_chunk_bgn_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_chunk_bgn_callback) || \ - curlcheck_cb_compatible((expr), _curl_chunk_bgn_callback1) || \ - curlcheck_cb_compatible((expr), _curl_chunk_bgn_callback2)) -typedef long (*_curl_chunk_bgn_callback1)(struct curl_fileinfo *, + curlcheck_cb_compatible((expr), Wcurl_chunk_bgn_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_chunk_bgn_callback2)) +typedef long (*Wcurl_chunk_bgn_callback1)(struct curl_fileinfo *, void *, int); -typedef long (*_curl_chunk_bgn_callback2)(void *, void *, int); +typedef long (*Wcurl_chunk_bgn_callback2)(void *, void *, int); /* evaluates to true if expr is of type curl_chunk_end_callback */ #define curlcheck_chunk_end_cb(expr) \ @@ -927,11 +927,11 @@ typedef long (*_curl_chunk_bgn_callback2)(void *, void *, int); /* evaluates to true if expr is of type curl_interleave_callback */ #define curlcheck_interleave_cb(expr) \ (curlcheck_NULL(expr) || \ - curlcheck_cb_compatible((expr), _curl_interleave_callback1) || \ - curlcheck_cb_compatible((expr), _curl_interleave_callback2)) -typedef size_t (*_curl_interleave_callback1)(void *p, size_t s, + curlcheck_cb_compatible((expr), Wcurl_interleave_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_interleave_callback2)) +typedef size_t (*Wcurl_interleave_callback1)(void *p, size_t s, size_t n, void *u); -typedef size_t (*_curl_interleave_callback2)(char *p, size_t s, +typedef size_t (*Wcurl_interleave_callback2)(char *p, size_t s, size_t n, void *u); /* evaluates to true if expr is of type curl_prereq_callback */ diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index e955990878ac..807ca5c0bd00 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -85,6 +85,17 @@ #if ARES_VERSION >= 0x011000 /* 1.16.0 or later has ares_getaddrinfo */ #define HAVE_CARES_GETADDRINFO 1 +#else +/* How long we are willing to wait for additional parallel responses after + obtaining a "definitive" one. For old c-ares without getaddrinfo. + + This is intended to equal the c-ares default timeout. cURL always uses that + default value. Unfortunately, c-ares does not expose its default timeout in + its API, but it is officially documented as 5 seconds. + + See query_completed_cb() for an explanation of how this is used. + */ +#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000 #endif #ifdef USE_HTTPSRR @@ -99,17 +110,6 @@ #include "curl_memory.h" #include "memdebug.h" -/* How long we are willing to wait for additional parallel responses after - obtaining a "definitive" one. For old c-ares without getaddrinfo. - - This is intended to equal the c-ares default timeout. cURL always uses that - default value. Unfortunately, c-ares does not expose its default timeout in - its API, but it is officially documented as 5 seconds. - - See query_completed_cb() for an explanation of how this is used. - */ -#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000 - #define CARES_TIMEOUT_PER_ATTEMPT 2000 static int ares_ver = 0; diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 52671f4eaeb4..9426adcede4f 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -640,8 +640,6 @@ void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf, (void)data; (void)cf; (void)fmt; } -struct curl_trc_feat; - void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...) { (void)data; (void)fmt; diff --git a/lib/curl_trc.h b/lib/curl_trc.h index fa0999250fbe..2819abe2dd48 100644 --- a/lib/curl_trc.h +++ b/lib/curl_trc.h @@ -95,6 +95,11 @@ void Curl_trc_read(struct Curl_easy *data, void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); +struct curl_trc_feat { + const char *name; + int log_level; +}; + #ifndef CURL_DISABLE_FTP extern struct curl_trc_feat Curl_trc_feat_ftp; void Curl_trc_ftp(struct Curl_easy *data, @@ -184,11 +189,6 @@ void Curl_trc_ws(struct Curl_easy *data, #endif /* !CURL_HAVE_C99 */ -struct curl_trc_feat { - const char *name; - int log_level; -}; - #ifndef CURL_DISABLE_VERBOSE_STRINGS /* informational messages enabled */ diff --git a/lib/curlx/version_win32.c b/lib/curlx/version_win32.c index 8d0af68fcfe0..4efe62b111ca 100644 --- a/lib/curlx/version_win32.c +++ b/lib/curlx/version_win32.c @@ -134,8 +134,15 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, static bool onetime = TRUE; /* safe because first call is during init */ if(onetime) { +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo"))); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif onetime = FALSE; } diff --git a/lib/doh.c b/lib/doh.c index 030b026fe297..069d5387eaf0 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -759,7 +759,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, ancount = doh_get16bit(doh, 6); while(ancount) { - unsigned short class; + unsigned short dnsclass; unsigned int ttl; rc = doh_skipqname(doh, dohlen, &index); @@ -779,8 +779,8 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; - class = doh_get16bit(doh, index); - if(DNS_CLASS_IN != class) + dnsclass = doh_get16bit(doh, index); + if(DNS_CLASS_IN != dnsclass) return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */ index += 2; @@ -816,7 +816,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, if(dohlen < (index + 8)) return DOH_DNS_OUT_OF_RANGE; - index += 2 + 2 + 4; /* type, class and ttl */ + index += 2 + 2 + 4; /* type, dnsclass and ttl */ if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; @@ -838,7 +838,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, if(dohlen < (index + 8)) return DOH_DNS_OUT_OF_RANGE; - index += 2 + 2 + 4; /* type, class and ttl */ + index += 2 + 2 + 4; /* type, dnsclass and ttl */ if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; diff --git a/lib/formdata.c b/lib/formdata.c index d8553e325694..475ca22fc864 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -868,10 +868,17 @@ CURLcode Curl_getformdata(CURL *data, particular, freopen(stdin) by the caller is not guaranteed to result as expected. This feature has been kept for backward compatibility: use of "-" pseudo filename should be avoided. */ +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif result = curl_mime_data_cb(part, (curl_off_t) -1, (curl_read_callback) fread, fseeko_wrapper, NULL, (void *) stdin); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif } else result = curl_mime_filedata(part, file->contents); diff --git a/lib/ftp.c b/lib/ftp.c index 6c710dceb962..6a33b6723cb8 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -142,11 +142,11 @@ static const char * const ftp_state_names[]={ #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ /* This is the ONLY way to change FTP state! */ -static void _ftp_state(struct Curl_easy *data, - struct ftp_conn *ftpc, - ftpstate newstate +static void ftp_state_low(struct Curl_easy *data, + struct ftp_conn *ftpc, + ftpstate newstate #ifdef DEBUGBUILD - , int lineno + , int lineno #endif ) { @@ -172,9 +172,9 @@ static void _ftp_state(struct Curl_easy *data, /* Local API functions */ #ifndef DEBUGBUILD -#define ftp_state(x,y,z) _ftp_state(x,y,z) +#define ftp_state(x,y,z) ftp_state_low(x,y,z) #else /* !DEBUGBUILD */ -#define ftp_state(x,y,z) _ftp_state(x,y,z,__LINE__) +#define ftp_state(x,y,z) ftp_state_low(x,y,z,__LINE__) #endif /* DEBUGBUILD */ static CURLcode ftp_sendquote(struct Curl_easy *data, diff --git a/lib/httpsrr.c b/lib/httpsrr.c index df93ac34ac04..26b8522cc964 100644 --- a/lib/httpsrr.c +++ b/lib/httpsrr.c @@ -38,8 +38,6 @@ #include "curl_memory.h" #include "memdebug.h" -#define MAX_ALPN_LENGTH 255 - static CURLcode httpsrr_decode_alpn(const char *cp, size_t len, unsigned char *alpns) { diff --git a/lib/ldap.c b/lib/ldap.c index 4b232e2bb676..66cf8916d689 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -119,30 +119,30 @@ struct ldap_urldesc { char *lud_filter; #endif char **lud_exts; - size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the - "real" struct so can only be used in code - without HAVE_LDAP_URL_PARSE defined */ + size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the + "real" struct so can only be used in code + without HAVE_LDAP_URL_PARSE defined */ }; #undef LDAPURLDesc #define LDAPURLDesc struct ldap_urldesc -static int _ldap_url_parse(struct Curl_easy *data, - const struct connectdata *conn, - LDAPURLDesc **ludp); -static void _ldap_free_urldesc(LDAPURLDesc *ludp); +static int ldap_url_parse_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc **ludp); +static void ldap_free_urldesc_low(LDAPURLDesc *ludp); #undef ldap_free_urldesc -#define ldap_free_urldesc _ldap_free_urldesc +#define ldap_free_urldesc ldap_free_urldesc_low #endif #ifdef DEBUG_LDAP #define LDAP_TRACE(x) do { \ - _ldap_trace("%u: ", __LINE__); \ - _ldap_trace x; \ + ldap_trace_low("%u: ", __LINE__); \ + ldap_trace_low x; \ } while(0) - static void _ldap_trace(const char *fmt, ...) CURL_PRINTF(1, 2); + static void ldap_trace_low(const char *fmt, ...) CURL_PRINTF(1, 2); #else #define LDAP_TRACE(x) Curl_nop_stmt #endif @@ -346,7 +346,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #ifdef HAVE_LDAP_URL_PARSE rc = ldap_url_parse(data->state.url, &ludp); #else - rc = _ldap_url_parse(data, conn, &ludp); + rc = ldap_url_parse_low(data, conn, &ludp); #endif if(rc) { failf(data, "Bad LDAP URL: %s", ldap_err2string((curl_ldap_num_t)rc)); @@ -728,7 +728,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) } #ifdef DEBUG_LDAP -static void _ldap_trace(const char *fmt, ...) +static void ldap_trace_low(const char *fmt, ...) { static int do_trace = -1; va_list args; @@ -795,8 +795,9 @@ static size_t num_entries(const char *s) * * Defined in RFC4516 section 2. */ -static int _ldap_url_parse2(struct Curl_easy *data, - const struct connectdata *conn, LDAPURLDesc *ludp) +static int ldap_url_parse2_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc *ludp) { int rc = LDAP_SUCCESS; char *p; @@ -999,9 +1000,9 @@ static int _ldap_url_parse2(struct Curl_easy *data, return rc; } -static int _ldap_url_parse(struct Curl_easy *data, - const struct connectdata *conn, - LDAPURLDesc **ludpp) +static int ldap_url_parse_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc **ludpp) { LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); int rc; @@ -1010,16 +1011,16 @@ static int _ldap_url_parse(struct Curl_easy *data, if(!ludp) return LDAP_NO_MEMORY; - rc = _ldap_url_parse2(data, conn, ludp); + rc = ldap_url_parse2_low(data, conn, ludp); if(rc != LDAP_SUCCESS) { - _ldap_free_urldesc(ludp); + ldap_free_urldesc_low(ludp); ludp = NULL; } *ludpp = ludp; return rc; } -static void _ldap_free_urldesc(LDAPURLDesc *ludp) +static void ldap_free_urldesc_low(LDAPURLDesc *ludp) { if(!ludp) return; diff --git a/lib/mqtt.c b/lib/mqtt.c index 35afe012075f..01dd4e0a0d44 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -54,7 +54,7 @@ #define MQTT_MSG_SUBSCRIBE 0x82 #define MQTT_MSG_SUBACK 0x90 #define MQTT_MSG_DISCONNECT 0xe0 -#define MQTT_MSG_PINGREQ 0xC0 +/* #define MQTT_MSG_PINGREQ 0xC0 */ #define MQTT_MSG_PINGRESP 0xD0 #define MQTT_CONNACK_LEN 2 diff --git a/lib/multi_ev.c b/lib/multi_ev.c index 61c639d9e48d..49e6e673a040 100644 --- a/lib/multi_ev.c +++ b/lib/multi_ev.c @@ -51,8 +51,6 @@ static void mev_in_callback(struct Curl_multi *multi, bool value) multi->in_callback = value; } -#define CURL_MEV_CONN_HASH_SIZE 3 - /* Information about a socket for which we inform the libcurl application * what to supervise (CURL_POLL_IN/CURL_POLL_OUT/CURL_POLL_REMOVE) */ @@ -636,8 +634,6 @@ void Curl_multi_ev_conn_done(struct Curl_multi *multi, Curl_conn_meta_remove(conn, CURL_META_MEV_POLLSET); } -#define CURL_MEV_PS_HASH_SLOTS (991) /* nice prime */ - void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize) { Curl_hash_init(&multi->ev.sh_entries, hashsize, mev_sh_entry_hash, diff --git a/lib/sendf.c b/lib/sendf.c index 551bb5ca81a6..f759fb61a4af 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -878,7 +878,14 @@ static CURLcode cr_in_rewind(struct Curl_easy *data, /* If no CURLOPT_READFUNCTION is used, we know that we operate on a given FILE * stream and we can actually attempt to rewind that ourselves with fseek() */ +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif if(data->state.fread_func == (curl_read_callback)fread) { +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif int err = fseek(data->state.in, 0, SEEK_SET); CURL_TRC_READ(data, "cr_in, rewind via fseek -> %d(%d)", (int)err, (int)errno); diff --git a/lib/setopt.c b/lib/setopt.c index d7a7f6c52d89..d958c5492a8d 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -818,10 +818,10 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, #if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ defined(TCP_FASTOPEN_CONNECT) s->tcp_fastopen = enabled; + break; #else return CURLE_NOT_BUILT_IN; #endif - break; case CURLOPT_SSL_ENABLE_ALPN: s->ssl_enable_alpn = enabled; break; @@ -2637,8 +2637,15 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, */ s->fwrite_func = va_arg(param, curl_write_callback); if(!s->fwrite_func) +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif /* When set to NULL, reset to our internal default function */ s->fwrite_func = (curl_write_callback)fwrite; +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif break; case CURLOPT_READFUNCTION: /* @@ -2647,8 +2654,15 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, s->fread_func_set = va_arg(param, curl_read_callback); if(!s->fread_func_set) { s->is_fread_set = 0; +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif /* When set to NULL, reset to our internal default function */ s->fread_func_set = (curl_read_callback)fread; +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif } else s->is_fread_set = 1; diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index cdc9ef864a9a..7af0b081e28e 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -71,7 +71,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, CURLcode code; size_t actualread; size_t written; - int result; + CURLcode result; + int err; /* Needs GSS-API authentication */ SECURITY_STATUS status; unsigned long sspi_ret_flags = 0; @@ -236,8 +237,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, * +----+------+-----+----------------+ */ - result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); - if(result || (actualread != 4)) { + err = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(err || (actualread != 4)) { failf(data, "Failed to receive SSPI authentication response."); result = CURLE_COULDNT_CONNECT; goto error; @@ -268,10 +269,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = CURLE_OUT_OF_MEMORY; goto error; } - result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, - sspi_recv_token.cbBuffer, &actualread); + err = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, + sspi_recv_token.cbBuffer, &actualread); - if(result || (actualread != us_length)) { + if(err || (actualread != us_length)) { failf(data, "Failed to receive SSPI authentication token."); result = CURLE_COULDNT_CONNECT; goto error; @@ -452,8 +453,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, Curl_safefree(etbuf); } - result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); - if(result || (actualread != 4)) { + err = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(err || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); result = CURLE_COULDNT_CONNECT; goto error; @@ -484,10 +485,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, goto error; } - result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer, &actualread); + err = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, + sspi_w_token[0].cbBuffer, &actualread); - if(result || (actualread != us_length)) { + if(err || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); result = CURLE_COULDNT_CONNECT; goto error; diff --git a/lib/url.c b/lib/url.c index 29702296a98d..3f792ec7655e 100644 --- a/lib/url.c +++ b/lib/url.c @@ -365,11 +365,18 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->in_set = stdin; /* default input from stdin */ set->err = stderr; /* default stderr to stderr */ +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif /* use fwrite as default function to store output */ set->fwrite_func = (curl_write_callback)fwrite; /* use fread as default function to read input */ set->fread_func_set = (curl_read_callback)fread; +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif set->is_fread_set = 0; set->seek_client = ZERO_NULL; diff --git a/lib/urlapi.c b/lib/urlapi.c index c89852794e05..7776645b4a0b 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -42,11 +42,13 @@ #include "curl_memory.h" #include "memdebug.h" +#ifdef _WIN32 /* MS-DOS/Windows style drive prefix, eg c: in c:foo */ #define STARTS_WITH_DRIVE_PREFIX(str) \ ((('a' <= str[0] && str[0] <= 'z') || \ ('A' <= str[0] && str[0] <= 'Z')) && \ (str[1] == ':')) +#endif /* MS-DOS/Windows style drive prefix, optionally with * a '|' instead of ':', followed by a slash or NUL */ diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 6cadc8fc58d1..246e0d51f661 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -80,7 +80,6 @@ #define QUIC_MAX_STREAMS (256*1024) -#define QUIC_MAX_DATA (1*1024*1024) #define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS) /* A stream window is the maximum amount we need to buffer for @@ -102,8 +101,6 @@ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2 /* Receive and Send max number of chunks just follows from the * chunk size and window size */ -#define H3_STREAM_RECV_CHUNKS \ - (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) #define H3_STREAM_SEND_CHUNKS \ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) @@ -1445,10 +1442,6 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, return (nghttp3_ssize)nvecs; } -/* Index where :authority header field will appear in request header - field list. */ -#define AUTHORITY_DST_IDX 3 - static CURLcode h3_stream_open(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index c1563c4e6309..b88b4e97bd3d 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -75,8 +75,6 @@ * chunk size and window size */ #define H3_STREAM_RECV_CHUNKS \ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) -#define H3_STREAM_SEND_CHUNKS \ - (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) /* * Store quiche version info in this buffer. @@ -955,10 +953,6 @@ static CURLcode cf_quiche_send_body(struct Curl_cfilter *cf, } } -/* Index where :authority header field will appear in request header - field list. */ -#define AUTHORITY_DST_IDX 3 - static CURLcode h3_open_stream(struct Curl_cfilter *cf, struct Curl_easy *data, const char *buf, size_t blen, bool eos, diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 69284407ab98..ebfd241e6c54 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1216,9 +1216,6 @@ sftp_upload_init(struct Curl_easy *data, return CURLE_OK; } -/* make sure that this does not collide with an actual libssh2 error code */ -#define ERROR_LIBBSH2 1 - static CURLcode ssh_state_pkey_init(struct Curl_easy *data, struct ssh_conn *sshc) { @@ -3411,12 +3408,19 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) */ #if LIBSSH2_VERSION_NUM >= 0x010b01 infof(data, "Uses HTTPS proxy"); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif libssh2_session_callback_set2(sshc->ssh_session, LIBSSH2_CALLBACK_RECV, (libssh2_cb_generic *)ssh_tls_recv); libssh2_session_callback_set2(sshc->ssh_session, LIBSSH2_CALLBACK_SEND, (libssh2_cb_generic *)ssh_tls_send); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif #else /* * This crazy union dance is here to avoid assigning a void pointer a diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index eef64886e1e3..e9252ec2a1d5 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -2064,7 +2064,7 @@ static CURLcode gtls_shutdown(struct Curl_cfilter *cf, (struct gtls_ssl_backend_data *)connssl->backend; char buf[1024]; CURLcode result = CURLE_OK; - ssize_t nread; + ssize_t nread = 0; size_t i; DEBUGASSERT(backend); diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 7b1a31e42f5b..a8abd0fe09a5 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -1160,7 +1160,7 @@ static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf, (struct mbed_ssl_backend_data *)connssl->backend; unsigned char buf[1024]; CURLcode result = CURLE_OK; - int ret; + int ret = 0; size_t i; DEBUGASSERT(backend); diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index af890b6c5795..66084a27c3dc 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -137,13 +137,13 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #if defined(USE_OPENSSL_ENGINE) || defined(OPENSSL_HAS_PROVIDERS) #include -#endif #if OPENSSL_VERSION_NUMBER >= 0x10100000L #define OSSL_UI_METHOD_CAST(x) (x) #else #define OSSL_UI_METHOD_CAST(x) CURL_UNCONST(x) #endif +#endif #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL 1.1.0+ and LibreSSL */ #define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ @@ -1631,7 +1631,14 @@ static int pkcs12load(struct Curl_easy *data, fail: EVP_PKEY_free(pri); X509_free(x509); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif sk_X509_pop_free(ca, X509_free); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif if(!cert_done) return 0; /* failure! */ return 1; @@ -3158,7 +3165,14 @@ static CURLcode load_cacert_from_memory(X509_STORE *store, } } +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif sk_X509_INFO_pop_free(inf, X509_INFO_free); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif BIO_free(cbio); /* if we did not end up importing anything, treat that as an error */ diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 221a7a6215ad..905d4f8a99e3 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -432,7 +432,7 @@ cr_get_selected_ciphers(struct Curl_easy *data, { const size_t supported_len = *selected_size; const size_t default_len = rustls_default_crypto_provider_ciphersuites_len(); - const struct rustls_supported_ciphersuite *entry; + const struct rustls_supported_ciphersuite *entry = NULL; const char *ciphers = ciphers12; size_t count = 0, default13_count = 0, i, j; const char *ptr, *end; @@ -1315,7 +1315,7 @@ cr_shutdown(struct Curl_cfilter *cf, struct rustls_ssl_backend_data *backend = (struct rustls_ssl_backend_data *)connssl->backend; CURLcode result = CURLE_OK; - size_t i, nread, nwritten; + size_t i, nread = 0, nwritten; DEBUGASSERT(backend); if(!backend->conn || cf->shutdown) { diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index fb9ef108226b..0cc34b138958 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -771,7 +771,9 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, SCH_CREDENTIALS credentials = { 0 }; TLS_PARAMETERS tls_parameters = { 0 }; - CRYPTO_SETTINGS crypto_settings[1] = { { 0 } }; + CRYPTO_SETTINGS crypto_settings[1]; + + memset(crypto_settings, 0, sizeof(crypto_settings)); tls_parameters.pDisabledCrypto = crypto_settings; @@ -2551,10 +2553,17 @@ static int schannel_init(void) { #if defined(HAS_ALPN_SCHANNEL) && !defined(UNDER_CE) typedef const char *(APIENTRY *WINE_GET_VERSION_FN)(void); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif WINE_GET_VERSION_FN p_wine_get_version = CURLX_FUNCTION_CAST(WINE_GET_VERSION_FN, (GetProcAddress(GetModuleHandleA("ntdll"), "wine_get_version"))); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif if(p_wine_get_version) { /* WINE detected */ const char *wine_version = p_wine_get_version(); /* e.g. "6.0.2" */ /* Assume ALPN support with WINE 6.0 or upper */ diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index afbb9b82182c..693cbdc92e21 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -1095,9 +1095,6 @@ static CURLcode ssl_version(struct Curl_easy *data, } -#define QUIC_CIPHERS \ - "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ - "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" #define QUIC_GROUPS "P-256:P-384:P-521" CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c index fe47e81a87d8..96b7f5bd630c 100644 --- a/lib/vtls/x509asn1.c +++ b/lib/vtls/x509asn1.c @@ -199,7 +199,7 @@ static const char *getASN1Element_(struct Curl_asn1Element *elem, elem->header = beg; b = (unsigned char) *beg++; elem->constructed = (b & 0x20) != 0; - elem->class = (b >> 6) & 3; + elem->eclass = (b >> 6) & 3; b &= 0x1F; if(b == 0x1F) return NULL; /* Long tag values not supported here. */ @@ -456,7 +456,7 @@ static CURLcode encodeOID(struct dynbuf *store, x = 0; do { if(x & 0xFF000000) - return 0; + return CURLE_OK; y = *(const unsigned char *) beg++; x = (x << 7) | (y & 0x7F); } while(y & 0x80); diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h index f9bd455b704e..51ea0c2cd668 100644 --- a/lib/vtls/x509asn1.h +++ b/lib/vtls/x509asn1.h @@ -42,7 +42,7 @@ struct Curl_asn1Element { const char *header; /* Pointer to header byte. */ const char *beg; /* Pointer to element data. */ const char *end; /* Pointer to 1st byte after element. */ - unsigned char class; /* ASN.1 element class. */ + unsigned char eclass; /* ASN.1 element class. */ unsigned char tag; /* ASN.1 element tag. */ BIT(constructed); /* Element is constructed. */ }; diff --git a/m4/curl-compilers.m4 b/m4/curl-compilers.m4 index dc6d3aa4cfa3..0e4c4e2655b0 100644 --- a/m4/curl-compilers.m4 +++ b/m4/curl-compilers.m4 @@ -120,16 +120,18 @@ AC_DEFUN([CURL_CHECK_COMPILER_CLANG], [ compiler_num=`(expr $clangvhi "*" 100 + $clangvlo) 2>/dev/null` if test "$appleclang" = '1' && test "$oldapple" = '0'; then dnl Starting with Xcode 7 / clang 3.7, Apple clang won't tell its upstream version - if test "$compiler_num" -ge '1300'; then compiler_num='1200' - elif test "$compiler_num" -ge '1205'; then compiler_num='1101' - elif test "$compiler_num" -ge '1204'; then compiler_num='1000' - elif test "$compiler_num" -ge '1107'; then compiler_num='900' - elif test "$compiler_num" -ge '1103'; then compiler_num='800' - elif test "$compiler_num" -ge '1003'; then compiler_num='700' - elif test "$compiler_num" -ge '1001'; then compiler_num='600' - elif test "$compiler_num" -ge '904'; then compiler_num='500' - elif test "$compiler_num" -ge '902'; then compiler_num='400' - elif test "$compiler_num" -ge '803'; then compiler_num='309' + if test "$compiler_num" -ge '1700'; then compiler_num='1901' + elif test "$compiler_num" -ge '1600'; then compiler_num='1700' + elif test "$compiler_num" -ge '1500'; then compiler_num='1600' + elif test "$compiler_num" -ge '1400'; then compiler_num='1400' + elif test "$compiler_num" -ge '1301'; then compiler_num='1300' + elif test "$compiler_num" -ge '1300'; then compiler_num='1200' + elif test "$compiler_num" -ge '1200'; then compiler_num='1000' + elif test "$compiler_num" -ge '1100'; then compiler_num='800' + elif test "$compiler_num" -ge '1000'; then compiler_num='600' + elif test "$compiler_num" -ge '901'; then compiler_num='500' + elif test "$compiler_num" -ge '900'; then compiler_num='400' + elif test "$compiler_num" -ge '801'; then compiler_num='309' elif test "$compiler_num" -ge '703'; then compiler_num='308' else compiler_num='307' fi @@ -827,9 +829,10 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [empty-body]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-field-initializers]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-noreturn]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-switch-default" + tmp_CFLAGS="$tmp_CFLAGS -Wno-switch-enum" # Not used because this basically disallows default case CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [old-style-definition]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [redundant-decls]) - # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [switch-enum]) # Not used because this basically disallows default case CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [type-limits]) # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-macros]) # Not practical # tmp_CFLAGS="$tmp_CFLAGS -Wno-error=unused-macros" @@ -845,15 +848,23 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ dnl Only clang 2.9 or later if test "$compiler_num" -ge "209"; then tmp_CFLAGS="$tmp_CFLAGS -Wno-sign-conversion" + tmp_CFLAGS="$tmp_CFLAGS -Wno-padded" # Not used because we cannot change public structs CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [shift-sign-overflow]) - # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [padded]) # Not used because we cannot change public structs fi # dnl Only clang 3.0 or later if test "$compiler_num" -ge "300"; then CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [cast-qual]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [conditional-uninitialized]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [language-extension-token]) tmp_CFLAGS="$tmp_CFLAGS -Wformat=2" + tmp_CFLAGS="$tmp_CFLAGS -Wno-used-but-marked-unused" # Triggered by typecheck-gcc.h (with clang 14+) + fi + dnl Only clang 3.1 or later + if test "$compiler_num" -ge "301"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [format-non-iso]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-covered-switch-default" # Annoying to fix or silence + tmp_CFLAGS="$tmp_CFLAGS -Wno-disabled-macro-expansion" # Triggered by typecheck-gcc.h (with clang 14+) fi # dnl Only clang 3.2 or later @@ -870,6 +881,10 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ ;; esac fi + dnl Only clang 3.3 or later + if test "$compiler_num" -ge "303"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-documentation-unknown-command" + fi # dnl Only clang 3.4 or later if test "$compiler_num" -ge "304"; then @@ -907,6 +922,35 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough" # we have silencing markup for clang 10.0 and above only CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [xor-used-as-pow]) fi + dnl clang 13 or later + if test "$compiler_num" -ge "1300"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [cast-function-type]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [reserved-identifier]) # Keep it before -Wno-reserved-macro-identifier + tmp_CFLAGS="$tmp_CFLAGS -Wno-reserved-macro-identifier" # Sometimes such external macros need to be set + fi + dnl clang 16 or later + if test "$compiler_num" -ge "1600"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-unsafe-buffer-usage" + fi + dnl clang 17 or later + if test "$compiler_num" -ge "1700"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [cast-function-type-strict]) # with Apple clang it requires 16.0 or above + fi + dnl clang 20 or later + if test "$compiler_num" -ge "2000"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [array-compare]) + fi + dnl clang 21 or later + if test "$compiler_num" -ge "2100"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [c++-hidden-decl]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-implicit-void-ptr-cast" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [tentative-definition-compat]) + if test "$curl_cv_native_windows" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-c++-keyword" # `wchar_t` triggers it on Windows + else + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [c++-keyword]) + fi + fi fi ;; # @@ -1015,10 +1059,11 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ ;; esac CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unreachable-code unused-parameter]) - # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [padded]) # Not used because we cannot change public structs + tmp_CFLAGS="$tmp_CFLAGS -Wno-padded" # Not used because we cannot change public structs + tmp_CFLAGS="$tmp_CFLAGS -Wno-switch-default" + tmp_CFLAGS="$tmp_CFLAGS -Wno-switch-enum" # Not used because this basically disallows default case CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [pragmas]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [redundant-decls]) - # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [switch-enum]) # Not used because this basically disallows default case # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-macros]) # Not practical # tmp_CFLAGS="$tmp_CFLAGS -Wno-error=unused-macros" fi diff --git a/src/curlinfo.c b/src/curlinfo.c index d601904f3eef..14eb2f88c3d8 100644 --- a/src/curlinfo.c +++ b/src/curlinfo.c @@ -236,18 +236,16 @@ static const char *disabled[]={ #else "OFF" #endif - , - NULL }; int main(int argc, char **argv) { - int i; + size_t i; (void)argc; (void)argv; - for(i = 0; disabled[i]; i++) + for(i = 0; i < CURL_ARRAYSIZE(disabled); i++) printf("%s\n", disabled[i]); return 0; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index b8fec5f7ab3b..43d30778de64 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -2109,7 +2109,6 @@ static ParameterError opt_bool(struct OperationConfig *config, break; case C_REMOTE_NAME: /* --remote-name */ return parse_remote_name(config, toggle); - break; case C_PROXYTUNNEL: /* --proxytunnel */ config->proxytunnel = toggle; break; @@ -2131,7 +2130,6 @@ static ParameterError opt_bool(struct OperationConfig *config, break; case C_VERBOSE: /* --verbose */ return parse_verbose(toggle); - break; case C_VERSION: /* --version */ if(toggle) /* --no-version yields no output! */ return PARAM_VERSION_INFO_REQUESTED; @@ -2801,7 +2799,6 @@ static ParameterError opt_string(struct OperationConfig *config, else global->parallel_host = (unsigned short)val; break; - break; case C_PARALLEL_MAX: /* --parallel-max */ err = str2unum(&val, nextarg); if(err) diff --git a/src/tool_operate.c b/src/tool_operate.c index 8ca3c14e8f12..14eff06e0630 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1934,7 +1934,7 @@ static CURLcode serial_transfers(CURLSH *share) return result; } -static CURLcode is_using_schannel(int *using) +static CURLcode is_using_schannel(int *pusing) { CURLcode result = CURLE_OK; static int using_schannel = -1; /* -1 = not checked @@ -1958,7 +1958,7 @@ static CURLcode is_using_schannel(int *using) if(result) return result; } - *using = using_schannel; + *pusing = using_schannel; return result; } diff --git a/tests/libtest/lib1565.c b/tests/libtest/lib1565.c index 3fecdd84ce48..1b218d37a773 100644 --- a/tests/libtest/lib1565.c +++ b/tests/libtest/lib1565.c @@ -95,7 +95,7 @@ static CURLcode test_lib1565(const char *URL) CURL *started_handles[CONN_NUM]; int started_num = 0; int finished_num = 0; - pthread_t tid; + pthread_t tid = 0; bool tid_valid = false; struct CURLMsg *message; diff --git a/tests/libtest/lib557.c b/tests/libtest/lib557.c index 9742272a4409..f831c9bfc252 100644 --- a/tests/libtest/lib557.c +++ b/tests/libtest/lib557.c @@ -42,6 +42,10 @@ #if !defined(__clang__) && __GNUC__ >= 7 #pragma GCC diagnostic ignored "-Wformat-overflow" #endif +#if defined(__clang__) && \ + (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) +#pragma clang diagnostic ignored "-Wformat-non-iso" +#endif #endif #define BUFSZ 256 @@ -1101,7 +1105,7 @@ static int test_curl_off_t_formatting(void) return failed; } -static int _string_check(int linenumber, char *buf, const char *buf2) +static int string_check_low(int linenumber, char *buf, const char *buf2) { if(strcmp(buf, buf2)) { /* they shouldn't differ */ @@ -1111,9 +1115,9 @@ static int _string_check(int linenumber, char *buf, const char *buf2) } return 0; } -#define string_check(x,y) _string_check(__LINE__, x, y) +#define string_check(x,y) string_check_low(__LINE__, x, y) -static int _strlen_check(int linenumber, char *buf, size_t len) +static int strlen_check_low(int linenumber, char *buf, size_t len) { size_t buflen = strlen(buf); if(len != buflen) { @@ -1124,8 +1128,7 @@ static int _strlen_check(int linenumber, char *buf, size_t len) } return 0; } - -#define strlen_check(x,y) _strlen_check(__LINE__, x, y) +#define strlen_check(x,y) strlen_check_low(__LINE__, x, y) /* * The output strings in this test need to have been verified with a system diff --git a/tests/unit/unit1398.c b/tests/unit/unit1398.c index fcdd3ec9bfd7..1b72bf1163b1 100644 --- a/tests/unit/unit1398.c +++ b/tests/unit/unit1398.c @@ -91,9 +91,18 @@ static CURLcode test_unit1398(const char *arg) fail_unless(rc == 15, "return code should be 15"); fail_unless(!strcmp(output, " 1234 567"), "wrong output"); +#if defined(__clang__) && \ + (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-non-iso" +#endif /* double precision */ rc = curl_msnprintf(output, 24, "%2$.*1$.99d", 3, 5678); fail_unless(rc == 0, "return code should be 0"); +#if defined(__clang__) && \ + (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) +#pragma clang diagnostic pop +#endif /* 129 input % flags */ rc = curl_msnprintf(output, 130, From 1429858bcea20a022ce7e21d0f6a9c826332b95e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 19 Sep 2025 22:22:14 +0200 Subject: [PATCH 085/208] tidy-up: update MS links, allow long URLs via `checksrc` - update Microsoft documentation links. (also drop language designator where present.) - checksrc: allow longer than 78 character lines if they contain a https URL. To make these links easier to use and parse. - merge links that were split into two lines. Closes #18626 --- docs/CIPHERS.md | 6 +++--- docs/INSTALL.md | 6 +++--- docs/TODO | 4 ++-- lib/cf-socket.c | 2 +- lib/cf-socket.h | 2 +- lib/curlx/multibyte.c | 2 +- lib/select.h | 2 +- lib/vauth/ntlm_sspi.c | 3 +-- lib/vauth/spnego_sspi.c | 3 +-- lib/vtls/openssl.c | 6 ++---- lib/vtls/schannel.c | 13 ++++++------- lib/vtls/schannel_verify.c | 2 +- scripts/checksrc.pl | 2 +- src/tool_doswin.c | 7 +++---- tests/server/sockfilt.c | 4 ++-- tests/server/util.c | 11 ++++------- 16 files changed, 33 insertions(+), 42 deletions(-) diff --git a/docs/CIPHERS.md b/docs/CIPHERS.md index 8ce938d9c2d9..7d9a1edf4762 100644 --- a/docs/CIPHERS.md +++ b/docs/CIPHERS.md @@ -163,11 +163,11 @@ for further information on that format. Schannel does not support setting individual TLS 1.2 cipher suites directly. It only allows the enabling and disabling of encryption algorithms. These are in the form of `CALG_xxx`, see the [Schannel `ALG_ID` -documentation](https://docs.microsoft.com/windows/desktop/SecCrypto/alg-id) +documentation](https://learn.microsoft.com/windows/win32/seccrypto/alg-id) for a list of these algorithms. Also, (since curl 7.77.0) `SCH_USE_STRONG_CRYPTO` can be given to pass that flag to Schannel, lookup the [documentation for the Windows version in -use](https://learn.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel) +use](https://learn.microsoft.com/windows/win32/secauthn/cipher-suites-in-schannel) to see how that affects the cipher suite selection. When not specifying the `--ciphers` and `--tls13-ciphers` options curl passes this flag by default. @@ -264,7 +264,7 @@ Restrict to only TLS 1.2 with the `CAMELLIA-128-GCM` cipher. - [OpenSSL cipher suite names documentation](https://docs.openssl.org/master/man1/openssl-ciphers/#cipher-suite-names) - [wolfSSL cipher support documentation](https://www.wolfssl.com/documentation/manuals/wolfssl/chapter04.html#cipher-support) - [mbedTLS cipher suites reference](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/ssl__ciphersuites_8h/) -- [Schannel cipher suites documentation](https://learn.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel) +- [Schannel cipher suites documentation](https://learn.microsoft.com/windows/win32/secauthn/cipher-suites-in-schannel) - [IANA cipher suites list](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4) - [Wikipedia cipher suite article](https://en.wikipedia.org/wiki/Cipher_suite) - [GnuTLS Priority Strings](https://gnutls.org/manual/html_node/Priority-Strings.html) diff --git a/docs/INSTALL.md b/docs/INSTALL.md index ab20e9fde1df..3972d242399f 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -193,9 +193,9 @@ You can build curl with: KB140584 is a must for any Windows developer. Especially important is full understanding if you are not going to follow the advice given above. - - [How To Use the C Runtime](https://support.microsoft.com/help/94248/how-to-use-the-c-run-time) - - [Runtime Library Compiler Options](https://docs.microsoft.com/cpp/build/reference/md-mt-ld-use-run-time-library) - - [Potential Errors Passing CRT Objects Across DLL Boundaries](https://docs.microsoft.com/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries) + - [How To Use the C Runtime](https://learn.microsoft.com/troubleshoot/developer/visualstudio/cpp/libraries/use-c-run-time) + - [Runtime Library Compiler Options](https://learn.microsoft.com/cpp/build/reference/md-mt-ld-use-run-time-library) + - [Potential Errors Passing CRT Objects Across DLL Boundaries](https://learn.microsoft.com/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries) If your app is misbehaving in some strange way, or it is suffering from memory corruption, before asking for further help, please try first to rebuild every diff --git a/docs/TODO b/docs/TODO index 6075577f318f..d7416f9c8e1b 100644 --- a/docs/TODO +++ b/docs/TODO @@ -860,14 +860,14 @@ The existing support for the -E/--cert and --key options could be extended by supplying a custom certificate and key in PEM format, see: - Getting a Certificate for Schannel - https://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx + https://learn.microsoft.com/windows/win32/secauthn/getting-a-certificate-for-schannel 15.2 Extend support for the --ciphers option The existing support for the --ciphers option could be extended by mapping the OpenSSL/GnuTLS cipher suites to the Schannel APIs, see - Specifying Schannel Ciphers and Cipher Strengths - https://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx + https://learn.microsoft.com/windows/win32/secauthn/specifying-schannel-ciphers-and-cipher-strengths 15.4 Add option to allow abrupt server closure diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 308325ccdc15..d7463345ad87 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -453,7 +453,7 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. - https://support.microsoft.com/kb/823764 + https://learn.microsoft.com/troubleshoot/windows-server/networking/slow-performance-copy-data-tcp-server-sockets-api Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size diff --git a/lib/cf-socket.h b/lib/cf-socket.h index 88c08fe7c0c0..083202fad900 100644 --- a/lib/cf-socket.h +++ b/lib/cf-socket.h @@ -80,7 +80,7 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. - https://support.microsoft.com/kb/823764 + https://learn.microsoft.com/troubleshoot/windows-server/networking/slow-performance-copy-data-tcp-server-sockets-api Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size diff --git a/lib/curlx/multibyte.c b/lib/curlx/multibyte.c index 30380275cc7e..1c81a71ec5b4 100644 --- a/lib/curlx/multibyte.c +++ b/lib/curlx/multibyte.c @@ -170,7 +170,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out) * \\?\c:\longpath ---> \\?\c:\longpath (unchanged) * \\server\c$\longpath ---> \\?\UNC\server\c$\longpath * - * https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats + * https://learn.microsoft.com/dotnet/standard/io/file-path-formats */ if(!wcsncmp(fbuf, L"\\\\?\\", 4)) ; /* do nothing */ diff --git a/lib/select.h b/lib/select.h index 47cdd31267f2..a23921ceb999 100644 --- a/lib/select.h +++ b/lib/select.h @@ -85,7 +85,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms); /* With Winsock the valid range is [0..INVALID_SOCKET-1] according to - https://docs.microsoft.com/en-us/windows/win32/winsock/socket-data-type-2 + https://learn.microsoft.com/windows/win32/winsock/socket-data-type-2 */ #ifdef USE_WINSOCK #define VALID_SOCK(s) ((s) < INVALID_SOCKET) diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index 9127a9bb277d..dff5fe8747d8 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -275,8 +275,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, * we have to pass a second SecBuffer to the SecBufferDesc * otherwise IIS will not pass the authentication (401 response). * Minimum supported version is Windows 7. - * https://docs.microsoft.com/en-us/security-updates - * /SecurityAdvisories/2009/973811 + * https://learn.microsoft.com/security-updates/SecurityAdvisories/2009/973811 */ if(ntlm->sslContext) { SEC_CHANNEL_BINDINGS channelBindings; diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index f21c66796f91..ae44523d328a 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -210,8 +210,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, * we have to pass a second SecBuffer to the SecBufferDesc * otherwise IIS will not pass the authentication (401 response). * Minimum supported version is Windows 7. - * https://docs.microsoft.com/en-us/security-updates - * /SecurityAdvisories/2009/973811 + * https://learn.microsoft.com/security-updates/SecurityAdvisories/2009/973811 */ if(nego->sslContext) { SEC_CHANNEL_BINDINGS channelBindings; diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 66084a27c3dc..49bc02230bea 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3462,8 +3462,7 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, problems with server-sent legacy intermediates. Newer versions of OpenSSL do alternate chain checking by default but we do not know how to determine that in a reliable manner. - https://web.archive.org/web/20190422050538/ - rt.openssl.org/Ticket/Display.html?id=3621 + https://web.archive.org/web/20190422050538/rt.openssl.org/Ticket/Display.html?id=3621 */ X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST); if(!ssl_config->no_partialchain && !ssl_crlfile) { @@ -4733,8 +4732,7 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, /* Begin Gyrations to get the subjectPublicKeyInfo */ /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ - /* https://groups.google.com/group/mailing.openssl.users/browse_thread - /thread/d61858dae102c6c7 */ + /* https://groups.google.com/group/mailing.openssl.users/browse_thread/thread/d61858dae102c6c7 */ len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); if(len1 < 1) break; /* failed */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 0cc34b138958..b511c43277e6 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -139,7 +139,7 @@ /* ALPN requires version 8.1 of the Windows SDK, which was shipped with Visual Studio 2013, aka _MSC_VER 1800: - https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx + https://learn.microsoft.com/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/hh831771 Or mingw-w64 9.0 or upper. */ #if (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 9) || \ @@ -585,8 +585,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if(fInCert || blob) { /* Reading a .P12 or .pfx file, like the example at bottom of - https://social.msdn.microsoft.com/Forums/windowsdesktop/ - en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 + https://learn.microsoft.com/archive/msdn-technet-forums/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 */ CRYPT_DATA_BLOB datablob; WCHAR* pszPassword; @@ -1039,7 +1038,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } /* Schannel InitializeSecurityContext: - https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx + https://learn.microsoft.com/windows/win32/api/rrascfg/nn-rrascfg-ieapproviderconfig At the moment we do not pass inbuf unless we are using ALPN since we only use it for that, and WINE (for which we currently disable ALPN) is giving @@ -1945,7 +1944,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* copy data into output buffer */ memcpy(outbuf[1].pvBuffer, buf, len); - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ + /* https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-encryptmessage */ sspi_status = Curl_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0, &outbuf_desc, 0); @@ -2164,7 +2163,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, inbuf, 4); - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx + /* https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-decryptmessage */ sspi_status = Curl_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); @@ -2373,7 +2372,7 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data, bool send_shutdown, bool *done) { - /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx + /* See https://learn.microsoft.com/windows/win32/secauthn/shutting-down-an-schannel-connection * Shutting Down an Schannel Connection */ struct ssl_connect_data *connssl = cf->ctx; diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index 17e42707631d..b19e1757d452 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -552,7 +552,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, * Right now we are only asking for the first preferred alternative name. * Instead we would need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG * (If Windows CE supports that?) and run this section in a loop for each. - * https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx + * https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certgetnamestringa * curl: (51) schannel: CertGetNameString() certificate hostname * (.google.com) did not match connection (google.com) */ diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index c52b8258d7f0..28ad6315ba4c 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -516,7 +516,7 @@ sub scanfile { } # detect long lines - if(length($l) > $max_column) { + if(length($l) > $max_column && $l !~ / https:\/\//) { checkwarn("LONGLINE", $line, length($l), $file, $l, "Longer than $max_column columns"); } diff --git a/src/tool_doswin.c b/src/tool_doswin.c index c0dcfed04e37..bfe013d8e56e 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -84,7 +84,7 @@ f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH) This function was implemented according to the guidelines in 'Naming Files, Paths, and Namespaces' section 'Naming Conventions'. -https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx +https://learn.microsoft.com/windows/win32/fileio/naming-a-file Flags ----- @@ -473,9 +473,8 @@ static SANITIZEcode rename_if_reserved_dos(char **const sanitized, /* Rename reserved device names that are known to be accessible without \\.\ Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS - https://web.archive.org/web/20160314141551/ - support.microsoft.com/en-us/kb/74496 - https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx + https://web.archive.org/web/20160314141551/support.microsoft.com/en-us/kb/74496 + https://learn.microsoft.com/windows/win32/fileio/naming-a-file */ for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) { size_t p_len; diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 2785b751340e..a52efe0a1bf6 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -404,8 +404,8 @@ static bool read_data_block(unsigned char *buffer, ssize_t maxlen, * other handle types supported by WaitForMultipleObjectsEx() as * well as disk files, anonymous and names pipes, and character input. * - * https://msdn.microsoft.com/en-us/library/windows/desktop/ms687028.aspx - * https://msdn.microsoft.com/en-us/library/windows/desktop/ms741572.aspx + * https://learn.microsoft.com/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjectsex + * https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-wsaenumnetworkevents */ struct select_ws_wait_data { HANDLE handle; /* actual handle to wait for during select */ diff --git a/tests/server/util.c b/tests/server/util.c index 02f91083e4f4..052effa89583 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -229,12 +229,9 @@ curl_off_t our_getpid(void) curl_off_t pid = (curl_off_t)t_getpid(); #ifdef _WIN32 /* store pid + MAX_PID to avoid conflict with Cygwin/msys PIDs, see also: - * - 2019-01-31: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; - * h=b5e1003722cb14235c4f166be72c09acdffc62ea - * - 2019-02-02: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; - * h=448cf5aa4b429d5a9cebf92a0da4ab4b5b6d23fe - * - 2024-12-19: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; - * h=363357c023ce01e936bdaedf0f479292a8fa4e0f + * - 2019-01-31: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;h=b5e1003722cb14235c4f166be72c09acdffc62ea + * - 2019-02-02: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;h=448cf5aa4b429d5a9cebf92a0da4ab4b5b6d23fe + * - 2024-12-19: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;h=363357c023ce01e936bdaedf0f479292a8fa4e0f */ pid += 4194304; #endif @@ -422,7 +419,7 @@ static void exit_signal_handler(int signum) * They are included for ANSI compatibility. Therefore, you can set * signal handlers for these signals by using signal, and you can also * explicitly generate these signals by calling raise. Source: - * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/signal + * https://learn.microsoft.com/cpp/c-runtime-library/reference/signal */ static BOOL WINAPI ctrl_event_handler(DWORD dwCtrlType) { From 7a26304a95baecc32405099c0628f0a76a700a20 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 11:11:35 +0200 Subject: [PATCH 086/208] curl_slist_append.md: clarify that a NULL pointer is not acceptable Closes #18627 --- docs/libcurl/curl_slist_append.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/libcurl/curl_slist_append.md b/docs/libcurl/curl_slist_append.md index 75c6a57afd50..b2766f728db0 100644 --- a/docs/libcurl/curl_slist_append.md +++ b/docs/libcurl/curl_slist_append.md @@ -28,9 +28,10 @@ struct curl_slist *curl_slist_append(struct curl_slist *list, curl_slist_append(3) appends a string to a linked list of strings. The existing **list** should be passed as the first argument and the new list is -returned from this function. Pass in NULL in the **list** argument to create -a new list. The specified **string** has been appended when this function -returns. curl_slist_append(3) copies the string. +returned from this function. Pass in NULL in the **list** argument to create a +new list. The specified **string** has been appended when this function +returns. curl_slist_append(3) copies the string. The **string** argument must +be a valid string pointer and cannot be NULL. The list should be freed again (after usage) with curl_slist_free_all(3). From 335d16e944c86a0f7d9c52e3932e1f0ccca39feb Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 11:25:38 +0200 Subject: [PATCH 087/208] libssh: error on bad chgrp number To avoid it continuing with a zero gid. Reported in Joshua's sarif data Closes #18629 --- lib/vssh/libssh.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 2554468c4bf3..be8336ad0a1e 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1808,10 +1808,7 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, if(!strncmp(cmd, "chgrp", 5)) { const char *p = sshc->quote_path1; curl_off_t gid; - (void)curlx_str_number(&p, &gid, UINT_MAX); - sshc->quote_attrs->gid = (uint32_t)gid; - if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { + if(curlx_str_number(&p, &gid, UINT_MAX)) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chgrp gid not a number"); @@ -1820,6 +1817,7 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, sshc->actualcode = CURLE_QUOTE_ERROR; return SSH_NO_ERROR; } + sshc->quote_attrs->gid = (uint32_t)gid; sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; } else if(!strncmp(cmd, "chmod", 5)) { From 0209e087c6989d7b6df49d3e090414eeccdda8ef Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 11:31:54 +0200 Subject: [PATCH 088/208] tool_cb_hdr: size is always 1 - add comment in the header that the argument 'size' is always 1, as guaranteed by the libcurl API - then fix the call to fwrite() to avoid using "size, etag_length" which would be wrong if size was something else than 1, and use a fixed number there instead. Reported in Joshua's sarif data Closes #18630 --- src/tool_cb_hdr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c index 3bb3c12dc806..7781e4dc3ccc 100644 --- a/src/tool_cb_hdr.c +++ b/src/tool_cb_hdr.c @@ -81,6 +81,8 @@ int tool_write_headers(struct HdrCbData *hdrcbdata, FILE *stream) /* ** callback for CURLOPT_HEADERFUNCTION +* +* 'size' is always 1 */ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) { @@ -164,7 +166,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) } #endif - fwrite(etag_h, size, etag_length, etag_save->stream); + fwrite(etag_h, 1, etag_length, etag_save->stream); /* terminate with newline */ fputc('\n', etag_save->stream); (void)fflush(etag_save->stream); From 2fe95cb0e320db0c6034d154ab175002d23b936d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 11:17:48 +0200 Subject: [PATCH 089/208] rustls: typecast variable for safer trace output This is a variadic function call with a mismatched argument type; on platforms where uintptr_t and size_t differ, this invokes undefined behavior. Reported in Joshua's sarif data Closes #18628 --- lib/vtls/rustls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 905d4f8a99e3..e5d85aa38f38 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -121,7 +121,7 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n) connssl->peer_closed = TRUE; *out_n = (uintptr_t)nread; CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %d, %zu", - len, result, nread); + (size_t)len, result, nread); return ret; } From bf7375ecc50e857760b0d0a668c436e208a400bd Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 9 Sep 2025 15:29:12 +0200 Subject: [PATCH 090/208] build: avoid overriding system symbols for socket functions Before this patch `accept4()`, `socket()`, `socketpair()`, `send()` and `recv()` system symbols were remapped via macros, using the same name, to local curl debug wrappers. This patch replaces these overrides by introducing curl-namespaced macros that map either to the system symbols or to their curl debug wrappers in `CURLDEBUG` (TrackMemory) builds. This follows a patch that implemented the same for `accept()`. The old method required tricks to make these redefines work in unity builds, and avoid them interfering with system headers. These tricks did not work for system symbols implemented as macros. The new method allows to setup these mappings once, without interfering with system headers, upstream macros, or unity builds. It makes builds more robust. Also: - checksrc: ban all mapped functions. - docs/examples: tidy up checksrc rules. Follow-up to 9863599d69b79d290928a89bf9160f4e4e023d4e #18502 Follow-up to 3bb5e58c105d7be450b667858d1b8e7ae3ded555 #17827 Closes #18503 --- REUSE.toml | 1 + docs/examples/.checksrc | 3 +++ docs/examples/Makefile.am | 2 +- docs/examples/http2-upload.c | 1 - docs/examples/synctime.c | 2 -- lib/cf-socket.c | 6 +++--- lib/curl_addrinfo.c | 4 ++++ lib/curl_mem_undef.h | 11 ----------- lib/curl_setup.h | 24 ++++++++++++++++++++++-- lib/hostip.c | 2 +- lib/if2ip.c | 2 +- lib/memdebug.c | 16 +++++++++++----- lib/memdebug.h | 18 ------------------ lib/multi.c | 2 +- lib/socketpair.c | 6 +++--- lib/vquic/vquic.c | 4 ++-- packages/OS400/os400sys.c | 1 + scripts/checksrc.pl | 8 ++++++++ src/tool_cb_rea.c | 2 +- src/tool_cb_soc.c | 2 +- src/tool_doswin.c | 4 ++-- tests/libtest/lib1960.c | 2 +- tests/libtest/lib500.c | 2 +- tests/server/.checksrc | 6 ++++++ 24 files changed, 74 insertions(+), 57 deletions(-) create mode 100644 docs/examples/.checksrc diff --git a/REUSE.toml b/REUSE.toml index 81c214863fcd..6e8a272e795c 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -40,6 +40,7 @@ path = [ "tests/data/test**", "tests/valgrind.supp", # checksrc control files + "docs/examples/.checksrc", "lib/.checksrc", "lib/curlx/.checksrc", "lib/vauth/.checksrc", diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc new file mode 100644 index 000000000000..0b626e65703d --- /dev/null +++ b/docs/examples/.checksrc @@ -0,0 +1,3 @@ +allowfunc gmtime +allowfunc localtime +allowfunc socket diff --git a/docs/examples/Makefile.am b/docs/examples/Makefile.am index 27d4ce741bd4..89ebcc9840f6 100644 --- a/docs/examples/Makefile.am +++ b/docs/examples/Makefile.am @@ -24,7 +24,7 @@ AUTOMAKE_OPTIONS = foreign nostdinc -EXTRA_DIST = CMakeLists.txt README.md Makefile.example $(COMPLICATED_EXAMPLES) +EXTRA_DIST = CMakeLists.txt .checksrc README.md Makefile.example $(COMPLICATED_EXAMPLES) # Specify our include paths here, and do it relative to $(top_srcdir) and # $(top_builddir), to ensure that these paths which belong to the library diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index 128a4b0beda1..d13c5e58063c 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -161,7 +161,6 @@ int my_trace(CURL *handle, curl_infotype type, known_offset = 1; } secs = epoch_offset + tv.tv_sec; - /* !checksrc! disable BANNEDFUNC 1 */ now = localtime(&secs); /* not thread safe but we do not care */ curl_msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld", now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index ba5f09cb075a..8d7af7c8c4c3 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -298,10 +298,8 @@ int main(int argc, char *argv[]) /* Calculating time diff between GMT and localtime */ tt = time(0); - /* !checksrc! disable BANNEDFUNC 1 */ lt = localtime(&tt); tt_local = mktime(lt); - /* !checksrc! disable BANNEDFUNC 1 */ gmt = gmtime(&tt); tt_gmt = mktime(gmt); tzonediffFloat = difftime(tt_local, tt_gmt); diff --git a/lib/cf-socket.c b/lib/cf-socket.c index d7463345ad87..365ddb62a144 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -369,7 +369,7 @@ static CURLcode socket_open(struct Curl_easy *data, } else { /* opensocket callback not set, so simply create the socket now */ - *sockfd = socket(addr->family, addr->socktype, addr->protocol); + *sockfd = CURL_SOCKET(addr->family, addr->socktype, addr->protocol); } if(*sockfd == CURL_SOCKET_BAD) @@ -2113,8 +2113,8 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, if(!getsockname(ctx->sock, (struct sockaddr *) &add, &size)) { size = sizeof(add); #ifdef HAVE_ACCEPT4 - s_accepted = accept4(ctx->sock, (struct sockaddr *) &add, &size, - SOCK_NONBLOCK | SOCK_CLOEXEC); + s_accepted = CURL_ACCEPT4(ctx->sock, (struct sockaddr *) &add, &size, + SOCK_NONBLOCK | SOCK_CLOEXEC); #else s_accepted = CURL_ACCEPT(ctx->sock, (struct sockaddr *) &add, &size); #endif diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 22212ac86f8e..c4ad71a02e1a 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -507,9 +507,11 @@ curl_dbg_freeaddrinfo(struct addrinfo *freethis, if(env) r_freeaddrinfo(freethis); else + /* !checksrc! disable BANNEDFUNC 1 */ freeaddrinfo(freethis); } #else + /* !checksrc! disable BANNEDFUNC 1 */ freeaddrinfo(freethis); #endif } @@ -540,8 +542,10 @@ curl_dbg_getaddrinfo(const char *hostname, if(env) res = r_getaddrinfo(hostname, service, hints, result); else + /* !checksrc! disable BANNEDFUNC 1 */ res = getaddrinfo(hostname, service, hints, result); #else + /* !checksrc! disable BANNEDFUNC 1 */ int res = getaddrinfo(hostname, service, hints, result); #endif if(res == 0) diff --git a/lib/curl_mem_undef.h b/lib/curl_mem_undef.h index f3cca294e9a5..a70a9fcf5379 100644 --- a/lib/curl_mem_undef.h +++ b/lib/curl_mem_undef.h @@ -35,17 +35,6 @@ #ifdef CURLDEBUG -#undef send -#undef recv - -#undef socket -#ifdef HAVE_ACCEPT4 -#undef accept4 -#endif -#ifdef HAVE_SOCKETPAIR -#undef socketpair -#endif - #undef fopen #ifdef CURL_FOPEN #define fopen(fname, mode) CURL_FOPEN(fname, mode) diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 93cbb570568d..e49c57231d2f 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -1083,9 +1083,21 @@ CURL_EXTERN ALLOC_FUNC curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #define CURL_FREEADDRINFO(data) \ curl_dbg_freeaddrinfo(data, __LINE__, __FILE__) - +#define CURL_SOCKET(domain,type,protocol) \ + curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__) +#ifdef HAVE_SOCKETPAIR +#define CURL_SOCKETPAIR(domain,type,protocol,socket_vector) \ + curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \ + __LINE__, __FILE__) +#endif #define CURL_ACCEPT(sock,addr,len) \ curl_dbg_accept(sock, addr, len, __LINE__, __FILE__) +#ifdef HAVE_ACCEPT4 +#define CURL_ACCEPT4(sock,addr,len,flags) \ + curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__) +#endif +#define CURL_SEND(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__) +#define CURL_RECV(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) #else /* !CURLDEBUG */ @@ -1094,8 +1106,16 @@ CURL_EXTERN ALLOC_FUNC #define CURL_GETADDRINFO getaddrinfo #define CURL_FREEADDRINFO freeaddrinfo - +#define CURL_SOCKET socket +#ifdef HAVE_SOCKETPAIR +#define CURL_SOCKETPAIR socketpair +#endif #define CURL_ACCEPT accept +#ifdef HAVE_ACCEPT4 +#define CURL_ACCEPT4 accept4 +#endif +#define CURL_SEND send +#define CURL_RECV recv #endif /* CURLDEBUG */ diff --git a/lib/hostip.c b/lib/hostip.c index b6be2ca1f275..fd8f706e7f25 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -709,7 +709,7 @@ bool Curl_ipv6works(struct Curl_easy *data) else { int ipv6_works = -1; /* probe to see if we have a working IPv6 stack */ - curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); + curl_socket_t s = CURL_SOCKET(PF_INET6, SOCK_DGRAM, 0); if(s == CURL_SOCKET_BAD) /* an IPv6 address was requested but we cannot get/use one */ ipv6_works = 0; diff --git a/lib/if2ip.c b/lib/if2ip.c index 91ee59c02a72..e501921d067b 100644 --- a/lib/if2ip.c +++ b/lib/if2ip.c @@ -208,7 +208,7 @@ if2ip_result_t Curl_if2ip(int af, if(len >= sizeof(req.ifr_name)) return IF2IP_NOT_FOUND; - dummy = socket(AF_INET, SOCK_STREAM, 0); + dummy = CURL_SOCKET(AF_INET, SOCK_STREAM, 0); if(CURL_SOCKET_BAD == dummy) return IF2IP_NOT_FOUND; diff --git a/lib/memdebug.c b/lib/memdebug.c index 0d8d39603c4d..cffd4b2cf61b 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -311,7 +311,8 @@ curl_socket_t curl_dbg_socket(int domain, int type, int protocol, if(countcheck("socket", line, source)) return CURL_SOCKET_BAD; - sockfd = (socket)(domain, type, protocol); + /* !checksrc! disable BANNEDFUNC 1 */ + sockfd = socket(domain, type, protocol); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log("FD %s:%d socket() = %" FMT_SOCKET_T "\n", @@ -328,7 +329,8 @@ SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, SEND_TYPE_RETV rc; if(countcheck("send", line, source)) return -1; - rc = (send)(sockfd, buf, len, flags); + /* !checksrc! disable BANNEDFUNC 1 */ + rc = send(sockfd, buf, len, flags); if(source) curl_dbg_log("SEND %s:%d send(%lu) = %ld\n", source, line, (unsigned long)len, (long)rc); @@ -342,7 +344,8 @@ RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, RECV_TYPE_RETV rc; if(countcheck("recv", line, source)) return -1; - rc = (recv)(sockfd, buf, len, flags); + /* !checksrc! disable BANNEDFUNC 1 */ + rc = recv(sockfd, buf, len, flags); if(source) curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n", source, line, (unsigned long)len, (long)rc); @@ -354,7 +357,8 @@ int curl_dbg_socketpair(int domain, int type, int protocol, curl_socket_t socket_vector[2], int line, const char *source) { - int res = (socketpair)(domain, type, protocol, socket_vector); + /* !checksrc! disable BANNEDFUNC 1 */ + int res = socketpair(domain, type, protocol, socket_vector); if(source && (res == 0)) curl_dbg_log("FD %s:%d socketpair() = " @@ -371,6 +375,7 @@ curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen, struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; + /* !checksrc! disable BANNEDFUNC 1 */ curl_socket_t sockfd = accept(s, addr, addrlen); if(source && (sockfd != CURL_SOCKET_BAD)) @@ -388,7 +393,8 @@ curl_socket_t curl_dbg_accept4(curl_socket_t s, void *saddr, void *saddrlen, struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; - curl_socket_t sockfd = (accept4)(s, addr, addrlen, flags); + /* !checksrc! disable BANNEDFUNC 1 */ + curl_socket_t sockfd = accept4(s, addr, addrlen, flags); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n", diff --git a/lib/memdebug.h b/lib/memdebug.h index eabdd9c258cf..96ceb61759e5 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -42,10 +42,6 @@ #define realloc(ptr,size) curl_dbg_realloc(ptr, size, __LINE__, __FILE__) #undef free #define free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__) -#undef send -#define send(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__) -#undef recv -#define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) #ifdef _WIN32 #undef Curl_tcsdup @@ -56,20 +52,6 @@ #endif #endif /* _WIN32 */ -#undef socket -#define socket(domain,type,protocol) \ - curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__) -#ifdef HAVE_ACCEPT4 -#undef accept4 /* for those with accept4 as a macro */ -#define accept4(sock,addr,len,flags) \ - curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__) -#endif -#ifdef HAVE_SOCKETPAIR -#define socketpair(domain,type,protocol,socket_vector) \ - curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \ - __LINE__, __FILE__) -#endif - #undef fopen #define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) #undef fdopen diff --git a/lib/multi.c b/lib/multi.c index 918928d03cc5..442956f84416 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1277,7 +1277,7 @@ static void reset_socket_fdwrite(curl_socket_t s) int t; int l = (int)sizeof(t); if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM) - send(s, NULL, 0, 0); + CURL_SEND(s, NULL, 0, 0); } #endif diff --git a/lib/socketpair.c b/lib/socketpair.c index 4151a9bb979a..d2fd41141b24 100644 --- a/lib/socketpair.c +++ b/lib/socketpair.c @@ -91,7 +91,7 @@ int Curl_socketpair(int domain, int type, int protocol, #ifdef SOCK_NONBLOCK type = nonblocking ? type | SOCK_NONBLOCK : type; #endif - if(socketpair(domain, type, protocol, socks)) + if(CURL_SOCKETPAIR(domain, type, protocol, socks)) return -1; #ifndef SOCK_NONBLOCK if(nonblocking) { @@ -154,7 +154,7 @@ int Curl_socketpair(int domain, int type, int protocol, (void)type; (void)protocol; - listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + listener = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(listener == CURL_SOCKET_BAD) return -1; @@ -188,7 +188,7 @@ int Curl_socketpair(int domain, int type, int protocol, goto error; if(listen(listener, 1) == -1) goto error; - socks[0] = socket(AF_INET, SOCK_STREAM, 0); + socks[0] = CURL_SOCKET(AF_INET, SOCK_STREAM, 0); if(socks[0] == CURL_SOCKET_BAD) goto error; if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1) diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 3a0ac872383f..47fbf63af05a 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -196,8 +196,8 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, *psent = 0; - while((sent = send(qctx->sockfd, - (const char *)pkt, (SEND_TYPE_ARG3)pktlen, 0)) == -1 && + while((sent = CURL_SEND(qctx->sockfd, (const char *)pkt, + (SEND_TYPE_ARG3)pktlen, 0)) == -1 && SOCKERRNO == SOCKEINTR) ; diff --git a/packages/OS400/os400sys.c b/packages/OS400/os400sys.c index 7be72085498b..bc227a0e69fc 100644 --- a/packages/OS400/os400sys.c +++ b/packages/OS400/os400sys.c @@ -333,6 +333,7 @@ Curl_getaddrinfo_a(const char *nodename, const char *servname, eservname[i] = '\0'; } + /* !checksrc! disable BANNEDFUNC 1 */ status = getaddrinfo(enodename, eservname, hints, res); free(enodename); free(eservname); diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 28ad6315ba4c..0eeab72323f9 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -77,6 +77,14 @@ "_waccess" => 1, "_access" => 1, "access" => 1, + "accept" => 1, + "accept4" => 1, + "freeaddrinfo" => 1, + "getaddrinfo" => 1, + "recv" => 1, + "send" => 1, + "socket" => 1, + "socketpair" => 1, ); my %warnings_extended = ( diff --git a/src/tool_cb_rea.c b/src/tool_cb_rea.c index 0a3e9ef0ee2c..b7bd9a722732 100644 --- a/src/tool_cb_rea.c +++ b/src/tool_cb_rea.c @@ -92,7 +92,7 @@ size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) execute */ if(per->uploadfile && !strcmp(per->uploadfile, ".") && per->infd > 0) { #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) - rc = recv(per->infd, buffer, curlx_uztosi(sz * nmemb), 0); + rc = CURL_RECV(per->infd, buffer, curlx_uztosi(sz * nmemb), 0); if(rc < 0) { if(SOCKERRNO == SOCKEWOULDBLOCK) { CURL_SETERRNO(0); diff --git a/src/tool_cb_soc.c b/src/tool_cb_soc.c index 22048ee6bbf9..d89870297cdb 100644 --- a/src/tool_cb_soc.c +++ b/src/tool_cb_soc.c @@ -54,5 +54,5 @@ curl_socket_t tool_socket_open_mptcp_cb(void *clientp, return CURL_SOCKET_BAD; #endif - return socket(addr->family, addr->socktype, protocol); + return CURL_SOCKET(addr->family, addr->socktype, protocol); } diff --git a/src/tool_doswin.c b/src/tool_doswin.c index bfe013d8e56e..0450e5707ba2 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -785,7 +785,7 @@ static DWORD WINAPI win_stdin_thread_func(void *thread_data) break; if(n == 0) break; - nwritten = send(socket_w, buffer, n, 0); + nwritten = CURL_SEND(socket_w, buffer, n, 0); if(nwritten == SOCKET_ERROR) break; if((DWORD)nwritten != n) @@ -889,7 +889,7 @@ curl_socket_t win32_stdin_read_thread(void) } /* Connect to the thread and rearrange our own STDIN handles */ - socket_r = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + socket_r = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(socket_r == CURL_SOCKET_BAD) { errorf("socket error: %08lx", GetLastError()); break; diff --git a/tests/libtest/lib1960.c b/tests/libtest/lib1960.c index 5cdc0224260c..1ee9277bef62 100644 --- a/tests/libtest/lib1960.c +++ b/tests/libtest/lib1960.c @@ -96,7 +96,7 @@ static CURLcode test_lib1960(const char *URL) * over this socket as "already connected" to libcurl and make sure that * this works. */ - client_fd = socket(AF_INET, SOCK_STREAM, 0); + client_fd = CURL_SOCKET(AF_INET, SOCK_STREAM, 0); if(client_fd == CURL_SOCKET_BAD) { curl_mfprintf(stderr, "socket creation error\n"); goto test_cleanup; diff --git a/tests/libtest/lib500.c b/tests/libtest/lib500.c index 0586c1407f9c..7081ec625d28 100644 --- a/tests/libtest/lib500.c +++ b/tests/libtest/lib500.c @@ -35,7 +35,7 @@ static curl_socket_t tst_opensocket(void *clientp, (void)clientp; (void)purpose; curl_mprintf("[OPEN] counter: %d\n", ++testcounter); - return socket(addr->family, addr->socktype, addr->protocol); + return CURL_SOCKET(addr->family, addr->socktype, addr->protocol); } static int tst_closesocket(void *clientp, curl_socket_t sock) diff --git a/tests/server/.checksrc b/tests/server/.checksrc index 8b1bcabe7789..be8f12cec014 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -1 +1,7 @@ +allowfunc accept +allowfunc freeaddrinfo +allowfunc getaddrinfo +allowfunc recv +allowfunc send +allowfunc socket allowfunc strtoul From ca75476a5c9ff3066cfcc3af0a2f33b936466501 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 15:07:15 +0200 Subject: [PATCH 091/208] GHA/codeql: drop winbuild references [ci skip] Follow-up to 8d004781a577fc2fae72873c4a45b2fb3f366d98 #18040 --- .github/workflows/codeql.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b5e05efe4655..bb3c07482163 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -17,7 +17,6 @@ name: 'CodeQL' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'CodeQL' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' schedule: - cron: '0 0 * * 4' From 2a5da01e422f0853a2ea3764cde5fa08189d5b91 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 14:29:44 +0200 Subject: [PATCH 092/208] socks: make Curl_blockread_all return CURLcode Reported in Joshua's sarif data Closes #18635 --- lib/socks.c | 27 +++++++++++++-------------- lib/socks.h | 10 +++++----- lib/socks_sspi.c | 33 ++++++++++++++++++--------------- 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/lib/socks.c b/lib/socks.c index fc6c9730f875..4cb8619d7bd5 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -98,14 +98,14 @@ struct socks_state { * * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions. */ -int Curl_blockread_all(struct Curl_cfilter *cf, - struct Curl_easy *data, /* transfer */ - char *buf, /* store read data here */ - size_t blen, /* space in buf */ - size_t *pnread) /* amount bytes read */ +CURLcode Curl_blockread_all(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, /* store read data here */ + size_t blen, /* space in buf */ + size_t *pnread) /* amount bytes read */ { size_t nread = 0; - CURLcode err; + CURLcode result; *pnread = 0; for(;;) { @@ -116,21 +116,20 @@ int Curl_blockread_all(struct Curl_cfilter *cf, } if(!timeout_ms) timeout_ms = TIMEDIFF_T_MAX; - if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) { - return ~CURLE_OK; - } - err = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread); - if(CURLE_AGAIN == err) + if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) + return CURLE_OPERATION_TIMEDOUT; + result = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread); + if(CURLE_AGAIN == result) continue; - else if(err) - return (int)err; + else if(result) + return result; if(blen == nread) { *pnread += nread; return CURLE_OK; } if(!nread) /* EOF */ - return ~CURLE_OK; + return CURLE_RECV_ERROR; buf += nread; blen -= nread; diff --git a/lib/socks.h b/lib/socks.h index d60796316f75..f76bddc5f4e1 100644 --- a/lib/socks.h +++ b/lib/socks.h @@ -37,11 +37,11 @@ * * This is STUPID BLOCKING behavior */ -int Curl_blockread_all(struct Curl_cfilter *cf, - struct Curl_easy *data, - char *buf, - size_t blen, - size_t *pnread); +CURLcode Curl_blockread_all(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, + size_t blen, + size_t *pnread); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 7af0b081e28e..6afc3eac3481 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -72,7 +72,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, size_t actualread; size_t written; CURLcode result; - int err; /* Needs GSS-API authentication */ SECURITY_STATUS status; unsigned long sspi_ret_flags = 0; @@ -237,10 +236,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, * +----+------+-----+----------------+ */ - err = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); - if(err || (actualread != 4)) { + result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI authentication response."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } @@ -269,12 +269,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = CURLE_OUT_OF_MEMORY; goto error; } - err = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, - sspi_recv_token.cbBuffer, &actualread); + result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, + sspi_recv_token.cbBuffer, &actualread); - if(err || (actualread != us_length)) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI authentication token."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } @@ -453,10 +454,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, Curl_safefree(etbuf); } - err = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); - if(err || (actualread != 4)) { + result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } @@ -485,12 +487,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, goto error; } - err = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer, &actualread); + result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, + sspi_w_token[0].cbBuffer, &actualread); - if(err || (actualread != us_length)) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } From 277ebca61009ac6618cd598aa81a9cf5f2b245f7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 14:45:47 +0200 Subject: [PATCH 093/208] ftp: fix port number range loop for PORT commands If the last port to test is 65535, the loop would previously wrongly wrap the counter and start over at 0, which was not intended. Reported in Joshua's sarif data Closes #18636 --- lib/ftp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/ftp.c b/lib/ftp.c index 6a33b6723cb8..1e2cd4d3cfeb 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -1121,14 +1121,16 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, else break; + /* check if port is the maximum value here, because it might be 0xffff and + then the increment below will wrap the 16 bit counter */ + if(port == port_max) { + /* maybe all ports were in use already */ + failf(data, "bind() failed, ran out of ports"); + goto out; + } port++; } - /* maybe all ports were in use already */ - if(port > port_max) { - failf(data, "bind() failed, we ran out of ports"); - goto out; - } /* get the name again after the bind() so that we can extract the port number it uses now */ From ca8ec6e033eb6b733d123495db18b5c99bf4208a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 14:56:03 +0200 Subject: [PATCH 094/208] tftp: handle tftp_multi_statemach() return code Previously just ignored. Reported in Joshua's sarif data Closes #18638 --- lib/tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 84b92ee48827..7dc06261b2c4 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1310,7 +1310,7 @@ static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done) if((state->state == TFTP_STATE_FIN) || result) return result; - tftp_multi_statemach(data, dophase_done); + result = tftp_multi_statemach(data, dophase_done); if(*dophase_done) DEBUGF(infof(data, "DO phase is complete")); From df8244c30fa80cc9310a096f9c4c024a76ad1bc6 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 15:00:37 +0200 Subject: [PATCH 095/208] libssh: error on bad chown number and store the value To avoid continuing with an unintended zero uid. Also actually use the value, which was omitted before! Reported in Joshua's sarif data Closes #18639 --- lib/vssh/libssh.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index be8336ad0a1e..56f21d85e99a 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1838,9 +1838,7 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, else if(!strncmp(cmd, "chown", 5)) { const char *p = sshc->quote_path1; curl_off_t uid; - (void)curlx_str_number(&p, &uid, UINT_MAX); - if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { + if(curlx_str_number(&p, &uid, UINT_MAX)) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chown uid not a number"); @@ -1849,6 +1847,7 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, sshc->actualcode = CURLE_QUOTE_ERROR; return SSH_NO_ERROR; } + sshc->quote_attrs->uid = (uint32_t)uid; sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; } else if(!strncmp(cmd, "atime", 5) || From 82eeda104144b23de1bc89641d5a41f8a57eba6e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 16:47:16 +0200 Subject: [PATCH 096/208] CURLOPT_HEADER/WRITEFUNCTION.md: drop '* size' since size is always 1 Closes #18640 --- docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md | 4 ++-- docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md b/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md index 2f4c00a03ca5..8e16b78d5552 100644 --- a/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md @@ -109,9 +109,9 @@ Nothing. static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { - /* received header is nitems * size long in 'buffer' NOT ZERO TERMINATED */ + /* received header is 'nitems' bytes in 'buffer' NOT ZERO TERMINATED */ /* 'userdata' is set with CURLOPT_HEADERDATA */ - return nitems * size; + return nitems; } int main(void) diff --git a/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md b/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md index 3ee11d8e476e..973a0aea754e 100644 --- a/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md @@ -40,13 +40,12 @@ delivered data, and the size of that data is *nmemb*; *size* is always 1. The data passed to this function is not null-terminated. The callback function is passed as much data as possible in all invokes, but -you must not make any assumptions. It may be one byte, it may be -thousands. The maximum amount of body data that is passed to the write -callback is defined in the curl.h header file: *CURL_MAX_WRITE_SIZE* (the -usual default is 16K). If CURLOPT_HEADER(3) is enabled, which makes header -data get passed to the write callback, you can get up to -*CURL_MAX_HTTP_HEADER* bytes of header data passed into it. This usually means -100K. +you must not make any assumptions. It may be one byte, it may be thousands. +The maximum amount of body data that is passed to the write callback is +defined in the curl.h header file: *CURL_MAX_WRITE_SIZE* (the usual default is +16K). If CURLOPT_HEADER(3) is enabled, which makes header data get passed to +the write callback, you can get up to *CURL_MAX_HTTP_HEADER* bytes of header +data passed into it. This usually means 100K. This function may be called with zero bytes data if the transferred file is empty. @@ -90,7 +89,7 @@ struct memory { static size_t cb(char *data, size_t size, size_t nmemb, void *clientp) { - size_t realsize = size * nmemb; + size_t realsize = nmemb; struct memory *mem = (struct memory *)clientp; char *ptr = realloc(mem->response, mem->size + realsize + 1); From 94eec0a788dbc80e87d7168be1bfb10d734d0ab3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 17:14:10 +0200 Subject: [PATCH 097/208] schannel: assign result before using it curl_easy_strerror(result) was called *before* result was assigned. Reported in Joshua's sarif data Closes #18642 --- lib/vtls/schannel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index b511c43277e6..8b7f1d9306c1 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -2451,9 +2451,9 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer); if(!result) { if(written < outbuf.cbBuffer) { + result = CURLE_SEND_ERROR; failf(data, "schannel: failed to send close msg: %s" " (bytes written: %zu)", curl_easy_strerror(result), written); - result = CURLE_SEND_ERROR; goto out; } backend->sent_shutdown = TRUE; @@ -2466,8 +2466,8 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, } else { if(!backend->recv_connection_closed) { - failf(data, "schannel: error sending close msg: %d", result); result = CURLE_SEND_ERROR; + failf(data, "schannel: error sending close msg: %d", result); goto out; } /* Looks like server already closed the connection. From d27d9c7ef1a37230ace8cc841027e6622c885df7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 16:56:14 +0200 Subject: [PATCH 098/208] cf-socket: use the right byte order for ports in bindlocal Reported in Joshua's sarif data Closes #18641 --- lib/cf-socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 365ddb62a144..2f0429efeae6 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -790,10 +790,10 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, infof(data, "Bind to local port %d failed, trying next", port - 1); /* We reuse/clobber the port variable here below */ if(sock->sa_family == AF_INET) - si4->sin_port = ntohs(port); + si4->sin_port = htons(port); #ifdef USE_IPV6 else - si6->sin6_port = ntohs(port); + si6->sin6_port = htons(port); #endif } else From e2d3b832445a05ed2e590fa5a40b0914f932bc42 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 14:51:01 +0200 Subject: [PATCH 099/208] libssh: return out of memory correctly if aprintf fails The code called set sshc->nextstate and returned SSH_OK without setting sshc->actualcode to an error code. Reported in Joshua's sarif data Closes #18637 --- lib/vssh/libssh.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 56f21d85e99a..eacc27a92110 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -765,7 +765,7 @@ static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data, #else #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64 #endif - CURLcode result; + CURLcode result = CURLE_OK; char *tmp = aprintf("statvfs:\n" "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" @@ -786,14 +786,13 @@ static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data, statvfs->f_namemax); sftp_statvfs_free(statvfs); - if(!tmp) { - myssh_to(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - return SSH_OK; - } + if(!tmp) + result = CURLE_OUT_OF_MEMORY; - result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); - free(tmp); + if(!result) { + result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + } if(result) { myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; From 66d6075af9c9bb5e4ef7985c7bc46942c9d4ae99 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 17:40:17 +0200 Subject: [PATCH 100/208] tftp: return error when sendto() fails The code just called failf() and then continued without returning error. Reported in Joshua's sarif data Closes #18643 --- lib/tftp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 7dc06261b2c4..8b6246a34265 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -535,11 +535,12 @@ static CURLcode tftp_send_first(struct tftp_conn *state, (SEND_TYPE_ARG3)sbytes, 0, CURL_SENDTO_ARG5(&remote_addr->curl_sa_addr), (curl_socklen_t)remote_addr->addrlen); + free(filename); if(senddata != (ssize_t)sbytes) { char buffer[STRERROR_LEN]; failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_SEND_ERROR; } - free(filename); break; case TFTP_EVENT_OACK: From 979366a62568ca2ea0f8bed19fd901499c8dc178 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 12:21:26 +0200 Subject: [PATCH 101/208] openldap: improve check for receiving blank data It can't access the first byte either unless it has length. Followup to 232d5a2ed9c091c88e3b724a1e7d6 Closes #18632 --- lib/openldap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/openldap.c b/lib/openldap.c index 1f8737f5243a..717739b68d89 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -1171,8 +1171,8 @@ static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf, if(!binary) { /* check for leading or trailing whitespace */ - if(ISBLANK(bvals[i].bv_val[0]) || - (bvals[i].bv_len && + if(bvals[i].bv_len && + (ISBLANK(bvals[i].bv_val[0]) || ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))) binval = TRUE; else { From 50968d0378ebf05c90e8f1d167592797bbd258ba Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 12:12:02 +0200 Subject: [PATCH 102/208] httpsrr: free old pointers when storing new In case we get "funny" input and the same field is provided several times, free the old pointer before stored a new memdup. Reported in Joshua's sarif data Closes #18631 --- lib/httpsrr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/httpsrr.c b/lib/httpsrr.c index 26b8522cc964..8aa7f3b26e47 100644 --- a/lib/httpsrr.c +++ b/lib/httpsrr.c @@ -98,6 +98,7 @@ CURLcode Curl_httpsrr_set(struct Curl_easy *data, case HTTPS_RR_CODE_IPV4: /* addr4 list */ if(!vlen || (vlen & 3)) /* the size must be 4-byte aligned */ return CURLE_BAD_FUNCTION_ARGUMENT; + free(hi->ipv4hints); hi->ipv4hints = Curl_memdup(val, vlen); if(!hi->ipv4hints) return CURLE_OUT_OF_MEMORY; @@ -107,6 +108,7 @@ CURLcode Curl_httpsrr_set(struct Curl_easy *data, case HTTPS_RR_CODE_ECH: if(!vlen) return CURLE_BAD_FUNCTION_ARGUMENT; + free(hi->echconfiglist); hi->echconfiglist = Curl_memdup(val, vlen); if(!hi->echconfiglist) return CURLE_OUT_OF_MEMORY; @@ -116,6 +118,7 @@ CURLcode Curl_httpsrr_set(struct Curl_easy *data, case HTTPS_RR_CODE_IPV6: /* addr6 list */ if(!vlen || (vlen & 15)) /* the size must be 16-byte aligned */ return CURLE_BAD_FUNCTION_ARGUMENT; + free(hi->ipv6hints); hi->ipv6hints = Curl_memdup(val, vlen); if(!hi->ipv6hints) return CURLE_OUT_OF_MEMORY; @@ -186,6 +189,7 @@ CURLcode Curl_httpsrr_from_ares(struct Curl_easy *data, is in ServiceMode */ target = ares_dns_rr_get_str(rr, ARES_RR_HTTPS_TARGET); if(target && target[0]) { + free(hinfo->target); hinfo->target = strdup(target); if(!hinfo->target) { result = CURLE_OUT_OF_MEMORY; From cf3b9657bcb7acd3525ca081b4ed16e860604d6d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 09:32:42 +0200 Subject: [PATCH 103/208] libssh2: up the minimum requirement to 1.9.0 Released on June 20 2019 --- .github/workflows/linux-old.yml | 10 +++--- configure.ac | 4 +-- docs/INTERNALS.md | 2 +- lib/vssh/libssh2.c | 59 ++------------------------------- 4 files changed, 10 insertions(+), 65 deletions(-) diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index e572c1745fb9..7e25cd213911 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -68,7 +68,7 @@ jobs: dpkg -i freexian-archive-keyring_2022.06.08_all.deb echo 'deb http://deb.freexian.com/extended-lts stretch-lts main contrib non-free' | tee /etc/apt/sources.list.d/extended-lts.list apt-get -o Dpkg::Use-Pty=0 update - apt-get -o Dpkg::Use-Pty=0 install -y --no-install-suggests --no-install-recommends cmake make automake autoconf libtool gcc pkg-config libpsl-dev libzstd-dev zlib1g-dev libgnutls28-dev libssh-dev libssh2-1-dev libc-ares-dev heimdal-dev libldap2-dev librtmp-dev stunnel4 groff + apt-get -o Dpkg::Use-Pty=0 install -y --no-install-suggests --no-install-recommends cmake make automake autoconf libtool gcc pkg-config libpsl-dev libzstd-dev zlib1g-dev libgnutls28-dev libc-ares-dev heimdal-dev libldap2-dev librtmp-dev stunnel4 groff # GitHub's actions/checkout needs newer glibc and libstdc++. The latter also depends on # gcc-8-base, but it doesn't actually seem used in our situation and isn't available in # the main repo, so force the install. @@ -80,12 +80,12 @@ jobs: with: persist-credentials: false - - name: 'cmake build-only (out-of-tree, libssh2)' + - name: 'cmake build-only (out-of-tree)' run: | mkdir bld-1 cd bld-1 cmake .. -DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON -DBUILD_SHARED_LIBS=ON \ - -DCURL_USE_GNUTLS=ON -DENABLE_ARES=OFF -DCURL_ZSTD=OFF -DCURL_USE_GSSAPI=OFF -DCURL_USE_LIBSSH2=ON -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON + -DCURL_USE_GNUTLS=ON -DENABLE_ARES=OFF -DCURL_ZSTD=OFF -DCURL_USE_GSSAPI=OFF -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON make install src/curl --disable --version @@ -129,12 +129,12 @@ jobs: - name: 'autoreconf' run: autoreconf -if - - name: 'configure (out-of-tree, c-ares, libssh2, zstd, gssapi)' + - name: 'configure (out-of-tree, c-ares, zstd, gssapi)' run: | mkdir bld-am cd bld-am ../configure --disable-dependency-tracking --enable-unity --enable-warnings --enable-werror \ - --with-gnutls --enable-ares --with-libssh2 --with-zstd --with-gssapi --with-librtmp \ + --with-gnutls --enable-ares --without-libssh2 --with-zstd --with-gssapi --with-librtmp \ --prefix="$PWD"/../curl-install-am - name: 'autotools curl_config.h' diff --git a/configure.ac b/configure.ac index 6c33b561be37..fa23eb09b1e4 100644 --- a/configure.ac +++ b/configure.ac @@ -2292,8 +2292,8 @@ if test X"$OPT_LIBSSH2" != Xno; then CPPFLAGS="$CPPFLAGS $CPP_SSH2" LIBS="$LIB_SSH2 $LIBS" - dnl check for function added in libssh2 version 1.2.8 - AC_CHECK_LIB(ssh2, libssh2_free) + dnl check for function added in libssh2 version 1.9.0 + AC_CHECK_LIB(ssh2, libssh2_agent_get_identity_path) AC_CHECK_HEADER(libssh2.h, curl_ssh_msg="enabled (libssh2)" diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index de993c3e4bcd..93546ebe4bbe 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -29,7 +29,7 @@ versions of libs and build tools. - GnuTLS 3.1.10 - mbedTLS 3.2.0 - zlib 1.2.5.2 - - libssh2 1.2.8 + - libssh2 1.9.0 - c-ares 1.6.0 - libssh 0.9.0 - libidn2 2.0.0 diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index ebfd241e6c54..f68e3ee168f8 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -464,26 +464,18 @@ static CURLcode ssh_knownhost(struct Curl_easy *data, case LIBSSH2_HOSTKEY_TYPE_DSS: keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS; break; -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256; break; -#endif -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384 case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384; break; -#endif -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521 case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521; break; -#endif -#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 case LIBSSH2_HOSTKEY_TYPE_ED25519: keybit = LIBSSH2_KNOWNHOST_KEY_ED25519; break; -#endif default: infof(data, "unsupported key type, cannot check knownhosts"); keybit = 0; @@ -606,22 +598,9 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data, size_t pub_pos = 0; size_t b64_pos = 0; -#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 /* The fingerprint points to static storage (!), do not free() it. */ fingerprint = libssh2_hostkey_hash(sshc->ssh_session, LIBSSH2_HOSTKEY_HASH_SHA256); -#else - const char *hostkey; - size_t len = 0; - unsigned char hash[32]; - - hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL); - if(hostkey) { - if(!Curl_sha256it(hash, (const unsigned char *) hostkey, len)) - fingerprint = (char *) hash; - } -#endif - if(!fingerprint) { failf(data, "Denied establishing ssh session: sha256 fingerprint " @@ -755,24 +734,14 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, { CURLcode result = CURLE_OK; -#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 static const char * const hostkey_method_ssh_ed25519 = "ssh-ed25519"; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 static const char * const hostkey_method_ssh_ecdsa_521 = "ecdsa-sha2-nistp521"; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 static const char * const hostkey_method_ssh_ecdsa_384 = "ecdsa-sha2-nistp384"; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 static const char * const hostkey_method_ssh_ecdsa_256 = "ecdsa-sha2-nistp256"; -#endif - static const char * const hostkey_method_ssh_rsa - = "ssh-rsa"; static const char * const hostkey_method_ssh_rsa_all = "rsa-sha2-256,rsa-sha2-512,ssh-rsa"; static const char * const hostkey_method_ssh_dss @@ -830,35 +799,20 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { -#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 case LIBSSH2_KNOWNHOST_KEY_ED25519: hostkey_method = hostkey_method_ssh_ed25519; break; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: hostkey_method = hostkey_method_ssh_ecdsa_521; break; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 case LIBSSH2_KNOWNHOST_KEY_ECDSA_384: hostkey_method = hostkey_method_ssh_ecdsa_384; break; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 case LIBSSH2_KNOWNHOST_KEY_ECDSA_256: hostkey_method = hostkey_method_ssh_ecdsa_256; break; -#endif case LIBSSH2_KNOWNHOST_KEY_SSHRSA: - if(libssh2_version(0x010900)) - /* since 1.9.0 libssh2_session_method_pref() works as expected */ - hostkey_method = hostkey_method_ssh_rsa_all; - else - /* old libssh2 which cannot correctly remove unsupported methods due - * to bug in src/kex.c or does not support the new methods anyways. - */ - hostkey_method = hostkey_method_ssh_rsa; + hostkey_method = hostkey_method_ssh_rsa_all; break; case LIBSSH2_KNOWNHOST_KEY_SSHDSS: hostkey_method = hostkey_method_ssh_dss; @@ -2428,18 +2382,9 @@ static CURLcode ssh_state_scp_download_init(struct Curl_easy *data, */ /* get a fresh new channel from the ssh layer */ -#if LIBSSH2_VERSION_NUM < 0x010700 - struct stat sb; - memset(&sb, 0, sizeof(struct stat)); - sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session, - sshp->path, &sb); -#else libssh2_struct_stat sb; memset(&sb, 0, sizeof(libssh2_struct_stat)); - sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, - sshp->path, &sb); -#endif - + sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, sshp->path, &sb); if(!sshc->ssh_channel) { int ssh_err; char *err_msg = NULL; From bb46d42407cd0503a9c499b4646af594a4db4947 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 22:49:46 +0200 Subject: [PATCH 104/208] openssl: make the asn1_object_dump name null terminated In case the buffer is too small. Reported in Joshua's sarif data Closes #18647 --- lib/vtls/openssl.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 49bc02230bea..4d37f5e77f20 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -293,20 +293,10 @@ do { \ } while(0) #endif -static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) +static int asn1_object_dump(const ASN1_OBJECT *a, char *buf, size_t len) { - int i, ilen; - - ilen = (int)len; - if(ilen < 0) - return 1; /* buffer too big */ - - i = i2t_ASN1_OBJECT(buf, ilen, a); - - if(i >= ilen) - return 1; /* buffer too small */ - - return 0; + int i = i2t_ASN1_OBJECT(buf, (int)len, a); + return (i >= (int)len); /* buffer too small */ } static CURLcode X509V3_ext(struct Curl_easy *data, @@ -337,7 +327,9 @@ static CURLcode X509V3_ext(struct Curl_easy *data, obj = X509_EXTENSION_get_object(ext); - asn1_object_dump(obj, namebuf, sizeof(namebuf)); + if(asn1_object_dump(obj, namebuf, sizeof(namebuf))) + /* make sure the name is null-terminated */ + namebuf [ sizeof(namebuf) - 1] = 0; if(!X509V3_EXT_print(bio_out, ext, 0, 0)) ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); From 5ab120bc4e6d9706efde14b37f8bd80c20981ac2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 08:32:39 +0200 Subject: [PATCH 105/208] krb5: drop support for Kerberos FTP It was accidentally broken in commit 0f4c439fc7347f499cf5, shipped since 8.8.0 (May 2024) and yet not a single person has noticed or reported, indicating that we might as well drop support for FTP Kerberos. Krb5 support was added in 54967d2a3ab55596314 (July 2007), and we have been carrying the extra license information around since then for this code. This commit removes the last traces of that code and thus we can remove the extra copyright notices along with it. Reported-by: Joshua Rogers Closes #18577 --- .github/scripts/spellcheck.words | 3 - LICENSES/BSD-3-Clause.txt | 11 - README | 6 - README.md | 6 - docs/cmdline-opts/krb.md | 8 +- docs/libcurl/curl_easy_setopt.md | 2 +- docs/libcurl/opts/CURLOPT_KRBLEVEL.md | 15 +- docs/libcurl/symbols-in-versions | 2 +- include/curl/curl.h | 3 +- lib/Makefile.inc | 2 - lib/curl_krb5.h | 54 -- lib/ftp.c | 68 +- lib/ftp.h | 3 - lib/krb5.c | 953 -------------------------- lib/pingpong.c | 29 +- lib/setopt.c | 9 +- lib/url.c | 11 +- lib/urldata.h | 39 -- src/config2setopts.c | 1 - src/tool_getparam.c | 11 +- src/tool_listhelp.c | 2 +- tests/data/test1282 | 5 +- 22 files changed, 43 insertions(+), 1200 deletions(-) delete mode 100644 LICENSES/BSD-3-Clause.txt delete mode 100644 lib/curl_krb5.h delete mode 100644 lib/krb5.c diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index 46c05b741bcf..aafaeff6d927 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -356,7 +356,6 @@ HTTPS https HTTPSRR hyper's -Högskolan IANA Icecast ICONV @@ -424,7 +423,6 @@ Krb krb Kubernetes Kuhrt -Kungliga Largefile LDAP ldap @@ -848,7 +846,6 @@ Tatsuhiro TBD TCP tcpdump -Tekniska testability testcurl TFTP diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt deleted file mode 100644 index 086d3992cb3a..000000000000 --- a/LICENSES/BSD-3-Clause.txt +++ /dev/null @@ -1,11 +0,0 @@ -Copyright (c) . - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README b/README index f5efbd70a69d..df320f94810e 100644 --- a/README +++ b/README @@ -47,9 +47,3 @@ SECURITY PROBLEMS Report suspected security problems via our HackerOne page and not in public. https://hackerone.com/curl - -NOTICE - - Curl contains pieces of source code that is Copyright (c) 1998, 1999 - Kungliga Tekniska Högskolan. This notice is included here to comply with the - distribution terms. diff --git a/README.md b/README.md index 3359818fd572..32a3c34fb0f2 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,6 @@ Download the latest source from the Git server: Report suspected security problems via [our HackerOne page](https://hackerone.com/curl) and not in public. -## Notice - -curl contains pieces of source code that is Copyright (c) 1998, 1999 Kungliga -Tekniska Högskolan. This notice is included here to comply with the -distribution terms. - ## Backers Thank you to all our backers :pray: [Become a backer](https://opencollective.com/curl#section-contribute). diff --git a/docs/cmdline-opts/krb.md b/docs/cmdline-opts/krb.md index c353a0c74009..6d47a76d6ec4 100644 --- a/docs/cmdline-opts/krb.md +++ b/docs/cmdline-opts/krb.md @@ -6,7 +6,7 @@ Arg: Help: Enable Kerberos with security Protocols: FTP Requires: Kerberos -Category: ftp +Category: deprecated Added: 7.3 Multi: single See-also: @@ -18,6 +18,8 @@ Example: # `--krb` +Deprecated option (added in 8.17.0). It has no function anymore. + Enable Kerberos authentication and use. The level must be entered and should -be one of 'clear', 'safe', 'confidential', or 'private'. Should you use a -level that is not one of these, 'private' is used. +be one of `clear`, `safe`, `confidential`, or `private`. Should you use a +level that is not one of these, `private` is used. diff --git a/docs/libcurl/curl_easy_setopt.md b/docs/libcurl/curl_easy_setopt.md index ccca56de6b24..430c3c14abbc 100644 --- a/docs/libcurl/curl_easy_setopt.md +++ b/docs/libcurl/curl_easy_setopt.md @@ -540,7 +540,7 @@ Client key password. See CURLOPT_KEYPASSWD(3) ## CURLOPT_KRBLEVEL -Kerberos security level. See CURLOPT_KRBLEVEL(3) +**OBSOLETE**. Kerberos security level. See CURLOPT_KRBLEVEL(3) ## CURLOPT_LOCALPORT diff --git a/docs/libcurl/opts/CURLOPT_KRBLEVEL.md b/docs/libcurl/opts/CURLOPT_KRBLEVEL.md index bdea064600cc..8dc5de7cee7c 100644 --- a/docs/libcurl/opts/CURLOPT_KRBLEVEL.md +++ b/docs/libcurl/opts/CURLOPT_KRBLEVEL.md @@ -5,7 +5,6 @@ Title: CURLOPT_KRBLEVEL Section: 3 Source: libcurl See-also: - - CURLOPT_KRBLEVEL (3) - CURLOPT_USE_SSL (3) Protocol: - FTP @@ -26,11 +25,13 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KRBLEVEL, char *level); # DESCRIPTION +Deprecated. It serves no purpose anymore. + Pass a char pointer as parameter. Set the kerberos security level for FTP; this also enables kerberos awareness. This is a string that should match one -of the following: &'clear', &'safe', &'confidential' or &'private'. If the -string is set but does not match one of these, 'private' is used. Set the -string to NULL to disable kerberos support for FTP. +of the following: `clear`, `safe`, `confidential` or `private`. If the string +is set but does not match one of these, `private` is used. Set the string to +NULL to disable kerberos support for FTP. The application does not have to keep the string around after setting this option. @@ -62,8 +63,14 @@ int main(void) # HISTORY +Functionality removed in 8.17.0 + This option was known as CURLOPT_KRB4LEVEL up to 7.16.3 +# DEPRECATED + +Deprecated since 8.17.0 + # %AVAILABILITY% # RETURN VALUE diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index bfcf357bf6fb..43435cb16b5b 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -704,7 +704,7 @@ CURLOPT_ISSUERCERT_BLOB 7.71.0 CURLOPT_KEEP_SENDING_ON_ERROR 7.51.0 CURLOPT_KEYPASSWD 7.17.0 CURLOPT_KRB4LEVEL 7.3 7.17.0 -CURLOPT_KRBLEVEL 7.16.4 +CURLOPT_KRBLEVEL 7.16.4 8.17.0 CURLOPT_LOCALPORT 7.15.2 CURLOPT_LOCALPORTRANGE 7.15.2 CURLOPT_LOGIN_OPTIONS 7.34.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index 6f4aa90f1349..49552558ddb7 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1357,7 +1357,8 @@ typedef enum { /* Set the krb4/5 security level, this also enables krb4/5 awareness. This * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string * is set but does not match one of these, 'private' will be used. */ - CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63), + CURLOPTDEPRECATED(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63, + 8.17.0, "removed"), /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64), diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 524fdcc53d5a..c17a8d9c3cad 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -209,7 +209,6 @@ LIB_CFILES = \ idn.c \ if2ip.c \ imap.c \ - krb5.c \ ldap.c \ llist.c \ macos.c \ @@ -292,7 +291,6 @@ LIB_HFILES = \ curl_gethostname.h \ curl_gssapi.h \ curl_hmac.h \ - curl_krb5.h \ curl_ldap.h \ curl_md4.h \ curl_md5.h \ diff --git a/lib/curl_krb5.h b/lib/curl_krb5.h deleted file mode 100644 index 574340fd3c58..000000000000 --- a/lib/curl_krb5.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef HEADER_CURL_KRB5_H -#define HEADER_CURL_KRB5_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, , 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 - * - ***************************************************************************/ - -struct Curl_sec_client_mech { - const char *name; - size_t size; - int (*init)(void *); - int (*auth)(void *, struct Curl_easy *data, struct connectdata *); - void (*end)(void *); - int (*check_prot)(void *, int); - int (*encode)(void *, const void *, int, int, void **); - int (*decode)(void *, void *, int, int, struct connectdata *); -}; - -#define AUTH_OK 0 -#define AUTH_CONTINUE 1 -#define AUTH_ERROR 2 - -#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) -void Curl_sec_conn_init(struct connectdata *); -void Curl_sec_conn_destroy(struct connectdata *); -int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *, - enum protection_level); -CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *); -int Curl_sec_request_prot(struct connectdata *conn, const char *level); -#else -#define Curl_sec_conn_init(x) Curl_nop_stmt -#define Curl_sec_conn_destroy(x) Curl_nop_stmt -#endif - -#endif /* HEADER_CURL_KRB5_H */ diff --git a/lib/ftp.c b/lib/ftp.c index 1e2cd4d3cfeb..df94ea5e6684 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -53,7 +53,6 @@ #include "fileinfo.h" #include "ftplistparser.h" #include "curl_range.h" -#include "curl_krb5.h" #include "strcase.h" #include "vtls/vtls.h" #include "cfilters.h" @@ -431,6 +430,9 @@ static const struct Curl_cwtype ftp_cw_lc = { #endif /* CURL_PREFER_LF_LINEENDS */ +static CURLcode getftpresponse(struct Curl_easy *data, ssize_t *nread, + int *ftpcode); + /*********************************************************************** * * ftp_check_ctrl_on_data_wait() @@ -450,7 +452,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data, if(curlx_dyn_len(&pp->recvbuf) && (*curlx_dyn_ptr(&pp->recvbuf) > '3')) { /* Data connection could not be established, let's return */ infof(data, "There is negative response in cache while serv connect"); - (void)Curl_GetFTPResponse(data, &nread, &ftpcode); + (void)getftpresponse(data, &nread, &ftpcode); return CURLE_FTP_ACCEPT_FAILED; } @@ -496,7 +498,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data, } } - (void)Curl_GetFTPResponse(data, &nread, &ftpcode); + (void)getftpresponse(data, &nread, &ftpcode); infof(data, "FTP code: %03d", ftpcode); @@ -578,28 +580,6 @@ static CURLcode ftp_readresp(struct Curl_easy *data, int code; CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size); DEBUGASSERT(ftpcodep); -#ifdef HAVE_GSSAPI - { - struct connectdata *conn = data->conn; - char * const buf = curlx_dyn_ptr(&ftpc->pp.recvbuf); - - /* handle the security-oriented responses 6xx ***/ - switch(code) { - case 631: - code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE); - break; - case 632: - code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE); - break; - case 633: - code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL); - break; - default: - /* normal ftp stuff we pass through! */ - break; - } - } -#endif /* store the latest code for later retrieval, except during shutdown */ if(!ftpc->shutdown) @@ -626,13 +606,14 @@ static CURLcode ftp_readresp(struct Curl_easy *data, /* --- parse FTP server responses --- */ /* - * Curl_GetFTPResponse() is a BLOCKING function to read the full response - * from a server after a command. + * getftpresponse() is a BLOCKING function to read the full response from a + * server after a command. * */ -CURLcode Curl_GetFTPResponse(struct Curl_easy *data, - ssize_t *nreadp, /* return number of bytes read */ - int *ftpcodep) /* return the ftp-code */ +static CURLcode getftpresponse(struct Curl_easy *data, + ssize_t *nreadp, /* return number of bytes + read */ + int *ftpcodep) /* return the ftp-code */ { /* * We cannot read just one byte per read() and then go back to select() as @@ -650,7 +631,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, int cache_skip = 0; DEBUGASSERT(ftpcodep); - CURL_TRC_FTP(data, "getFTPResponse start"); + CURL_TRC_FTP(data, "getftpresponse start"); *nreadp = 0; *ftpcodep = 0; /* 0 for errors */ @@ -733,7 +714,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, } /* while there is buffer left and loop is requested */ pp->pending_resp = FALSE; - CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d", + CURL_TRC_FTP(data, "getftpresponse -> result=%d, nread=%zd, ftpcode=%d", result, *nreadp, *ftpcodep); return result; @@ -2814,25 +2795,6 @@ static CURLcode ftp_wait_resp(struct Curl_easy *data, return CURLE_WEIRD_SERVER_REPLY; } - /* We have received a 220 response fine, now we proceed. */ -#ifdef HAVE_GSSAPI - if(data->set.krb) { - /* If not anonymous login, try a secure login. Note that this - procedure is still BLOCKING. */ - - Curl_sec_request_prot(conn, "private"); - /* We set private first as default, in case the line below fails to - set a valid level */ - Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); - - if(Curl_sec_login(data, conn)) { - failf(data, "secure login failed"); - return CURLE_WEIRD_SERVER_REPLY; - } - infof(data, "Authentication successful"); - } -#endif - if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { /* We do not have an SSL/TLS control connection yet, but FTPS is requested. Try an FTPS connection now */ @@ -3403,7 +3365,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, pp->response_time = 60*1000; /* give it only a minute for now */ pp->response = curlx_now(); /* timeout relative now */ - result = Curl_GetFTPResponse(data, &nread, &ftpcode); + result = getftpresponse(data, &nread, &ftpcode); pp->response_time = old_time; /* set this back to previous value */ @@ -3526,7 +3488,7 @@ CURLcode ftp_sendquote(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); if(!result) { pp->response = curlx_now(); /* timeout relative now */ - result = Curl_GetFTPResponse(data, &nread, &ftpcode); + result = getftpresponse(data, &nread, &ftpcode); } if(result) return result; diff --git a/lib/ftp.h b/lib/ftp.h index aba1db7f2d3d..fdbb4b0539f2 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -35,9 +35,6 @@ extern const struct Curl_handler Curl_handler_ftp; extern const struct Curl_handler Curl_handler_ftps; #endif -CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nread, - int *ftpcode); - bool ftp_conns_match(struct connectdata *needle, struct connectdata *conn); #endif /* CURL_DISABLE_FTP */ diff --git a/lib/krb5.c b/lib/krb5.c deleted file mode 100644 index b041d2f2277e..000000000000 --- a/lib/krb5.c +++ /dev/null @@ -1,953 +0,0 @@ -/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c - * - * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * Copyright (C) Daniel Stenberg - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ - -#include "curl_setup.h" - -#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) - -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#include "urldata.h" -#include "url.h" -#include "cfilters.h" -#include "cf-socket.h" -#include "curlx/base64.h" -#include "ftp.h" -#include "curl_gssapi.h" -#include "sendf.h" -#include "transfer.h" -#include "curl_krb5.h" -#include "curlx/warnless.h" -#include "strdup.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#if defined(__GNUC__) && defined(__APPLE__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - -static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn, - const char *cmd) -{ - size_t bytes_written; -#define SBUF_SIZE 1024 - char s[SBUF_SIZE]; - size_t write_len; - char *sptr = s; - CURLcode result = CURLE_OK; -#ifdef HAVE_GSSAPI - unsigned char data_sec = conn->data_prot; -#endif - - DEBUGASSERT(cmd); - - write_len = strlen(cmd); - if(!write_len || write_len > (sizeof(s) -3)) - return CURLE_BAD_FUNCTION_ARGUMENT; - - memcpy(&s, cmd, write_len); - strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ - write_len += 2; - bytes_written = 0; - - for(;;) { -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CMD; -#endif - result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written); -#ifdef HAVE_GSSAPI - DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); - conn->data_prot = data_sec; -#endif - - if(result) - break; - - Curl_debug(data, CURLINFO_HEADER_OUT, sptr, bytes_written); - - if(bytes_written != write_len) { - write_len -= bytes_written; - sptr += bytes_written; - } - else - break; - } - - return result; -} - -static int -krb5_init(void *app_data) -{ - gss_ctx_id_t *context = app_data; - /* Make sure our context is initialized for krb5_end. */ - *context = GSS_C_NO_CONTEXT; - return 0; -} - -static int -krb5_check_prot(void *app_data, int level) -{ - (void)app_data; - if(level == PROT_CONFIDENTIAL) - return -1; - return 0; -} - -static int -krb5_decode(void *app_data, void *buf, int len, - int level, struct connectdata *conn) -{ - gss_ctx_id_t *context = app_data; - OM_uint32 maj, min; - gss_buffer_desc enc, dec; - - (void)level; - (void)conn; - - enc.value = buf; - enc.length = len; - maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL); - if(maj != GSS_S_COMPLETE) - return -1; - - memcpy(buf, dec.value, dec.length); - len = curlx_uztosi(dec.length); - gss_release_buffer(&min, &dec); - - return len; -} - -static int -krb5_encode(void *app_data, const void *from, int length, int level, void **to) -{ - gss_ctx_id_t *context = app_data; - gss_buffer_desc dec, enc; - OM_uint32 maj, min; - int state; - int len; - - /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal - * libraries modify the input buffer in gss_wrap() - */ - dec.value = CURL_UNCONST(from); - dec.length = (size_t)length; - maj = gss_wrap(&min, *context, - level == PROT_PRIVATE, - GSS_C_QOP_DEFAULT, - &dec, &state, &enc); - - if(maj != GSS_S_COMPLETE) - return -1; - - /* malloc a new buffer, in case gss_release_buffer does not work as - expected */ - *to = malloc(enc.length); - if(!*to) - return -1; - memcpy(*to, enc.value, enc.length); - len = curlx_uztosi(enc.length); - gss_release_buffer(&min, &enc); - return len; -} - -static int -krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn) -{ - int ret = AUTH_OK; - char *p; - const char *host = conn->host.name; - ssize_t nread; - curl_socklen_t l = sizeof(conn->local_addr); - CURLcode result; - const char *service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : - "ftp"; - const char *srv_host = "host"; - gss_buffer_desc input_buffer, output_buffer, *gssresp; - gss_buffer_desc _gssresp = GSS_C_EMPTY_BUFFER; - OM_uint32 maj, min; - gss_name_t gssname; - gss_ctx_id_t *context = app_data; - struct gss_channel_bindings_struct chan; - size_t base64_sz = 0; - const struct Curl_sockaddr_ex *remote_addr = - Curl_conn_get_remote_addr(data, FIRSTSOCKET); - struct sockaddr_in *remote_in_addr = remote_addr ? - (struct sockaddr_in *)CURL_UNCONST(&remote_addr->curl_sa_addr) : NULL; - char *stringp; - struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); - - if(!ftpc || !remote_in_addr) - return -2; - - if(getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)&conn->local_addr, &l) < 0) - perror("getsockname()"); - - chan.initiator_addrtype = GSS_C_AF_INET; - chan.initiator_address.length = l - 4; - chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; - chan.acceptor_addrtype = GSS_C_AF_INET; - chan.acceptor_address.length = l - 4; - chan.acceptor_address.value = &remote_in_addr->sin_addr.s_addr; - chan.application_data.length = 0; - chan.application_data.value = NULL; - - /* this loop will execute twice (once for service, once for host) */ - for(;;) { - /* this really should not be repeated here, but cannot help it */ - if(service == srv_host) { - result = ftpsend(data, conn, "AUTH GSSAPI"); - if(result) - return -2; - - if(Curl_GetFTPResponse(data, &nread, NULL)) - return -1; - else { - char *line = curlx_dyn_ptr(&ftpc->pp.recvbuf); - if(line[0] != '3') - return -1; - } - } - - stringp = aprintf("%s@%s", service, host); - if(!stringp) - return -2; - - input_buffer.value = stringp; - input_buffer.length = strlen(stringp); - maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE, - &gssname); - free(stringp); - if(maj != GSS_S_COMPLETE) { - gss_release_name(&min, &gssname); - if(service == srv_host) { - failf(data, "Error importing service name %s@%s", service, host); - return AUTH_ERROR; - } - service = srv_host; - continue; - } - /* We pass NULL as |output_name_type| to avoid a leak. */ - gss_display_name(&min, gssname, &output_buffer, NULL); - infof(data, "Trying against %s", (char *)output_buffer.value); - gssresp = GSS_C_NO_BUFFER; - *context = GSS_C_NO_CONTEXT; - - do { - /* Release the buffer at each iteration to avoid leaking: the first time - we are releasing the memory from gss_display_name. The last item is - taken care by a final gss_release_buffer. */ - gss_release_buffer(&min, &output_buffer); - ret = AUTH_OK; - maj = Curl_gss_init_sec_context(data, - &min, - context, - gssname, - &Curl_krb5_mech_oid, - &chan, - gssresp, - &output_buffer, - TRUE, - NULL); - - if(gssresp) { - free(_gssresp.value); - gssresp = NULL; - } - - if(GSS_ERROR(maj)) { - infof(data, "Error creating security context"); - ret = AUTH_ERROR; - break; - } - - if(output_buffer.length) { - char *cmd; - - result = curlx_base64_encode((char *)output_buffer.value, - output_buffer.length, &p, &base64_sz); - if(result) { - infof(data, "base64-encoding: %s", curl_easy_strerror(result)); - ret = AUTH_ERROR; - break; - } - - cmd = aprintf("ADAT %s", p); - if(cmd) - result = ftpsend(data, conn, cmd); - else - result = CURLE_OUT_OF_MEMORY; - - free(p); - free(cmd); - - if(result) { - ret = -2; - break; - } - - if(Curl_GetFTPResponse(data, &nread, NULL)) { - ret = -1; - break; - } - else { - size_t len = curlx_dyn_len(&ftpc->pp.recvbuf); - p = curlx_dyn_ptr(&ftpc->pp.recvbuf); - if((len < 4) || (p[0] != '2' && p[0] != '3')) { - infof(data, "Server did not accept auth data"); - ret = AUTH_ERROR; - break; - } - } - - _gssresp.value = NULL; /* make sure it is initialized */ - _gssresp.length = 0; - p += 4; /* over '789 ' */ - p = strstr(p, "ADAT="); - if(p) { - unsigned char *outptr; - size_t outlen; - result = curlx_base64_decode(p + 5, &outptr, &outlen); - if(result) { - failf(data, "base64-decoding: %s", curl_easy_strerror(result)); - ret = AUTH_CONTINUE; - break; - } - _gssresp.value = outptr; - _gssresp.length = outlen; - } - - gssresp = &_gssresp; - } - } while(maj == GSS_S_CONTINUE_NEEDED); - - gss_release_name(&min, &gssname); - gss_release_buffer(&min, &output_buffer); - - if(gssresp) - free(_gssresp.value); - - if(ret == AUTH_OK || service == srv_host) - break; - - service = srv_host; - } - return ret; -} - -static void krb5_end(void *app_data) -{ - OM_uint32 min; - gss_ctx_id_t *context = app_data; - if(*context != GSS_C_NO_CONTEXT) { - OM_uint32 maj = Curl_gss_delete_sec_context(&min, context, - GSS_C_NO_BUFFER); - (void)maj; - DEBUGASSERT(maj == GSS_S_COMPLETE); - } -} - -static const struct Curl_sec_client_mech Curl_krb5_client_mech = { - "GSSAPI", - sizeof(gss_ctx_id_t), - krb5_init, - krb5_auth, - krb5_end, - krb5_check_prot, - - krb5_encode, - krb5_decode -}; - -static const struct { - unsigned char level; - const char *name; -} level_names[] = { - { PROT_CLEAR, "clear" }, - { PROT_SAFE, "safe" }, - { PROT_CONFIDENTIAL, "confidential" }, - { PROT_PRIVATE, "private" } -}; - -static unsigned char name_to_level(const char *name) -{ - int i; - for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++) - if(curl_strequal(name, level_names[i].name)) - return level_names[i].level; - return PROT_NONE; -} - -/* Convert a protocol |level| to its char representation. - We take an int to catch programming mistakes. */ -static char level_to_char(int level) -{ - switch(level) { - case PROT_CLEAR: - return 'C'; - case PROT_SAFE: - return 'S'; - case PROT_CONFIDENTIAL: - return 'E'; - case PROT_PRIVATE: - return 'P'; - case PROT_CMD: - default: - /* Those 2 cases should not be reached! */ - break; - } - DEBUGASSERT(0); - /* Default to the most secure alternative. */ - return 'P'; -} - -/* Send an FTP command defined by |message| and the optional arguments. The - function returns the ftp_code. If an error occurs, -1 is returned. */ -static int ftp_send_command(struct Curl_easy *data, const char *message, ...) - CURL_PRINTF(2, 3); - -static int ftp_send_command(struct Curl_easy *data, const char *message, ...) -{ - int ftp_code; - ssize_t nread = 0; - va_list args; - char print_buffer[50]; - - va_start(args, message); - mvsnprintf(print_buffer, sizeof(print_buffer), message, args); - va_end(args); - - if(ftpsend(data, data->conn, print_buffer)) { - ftp_code = -1; - } - else { - if(Curl_GetFTPResponse(data, &nread, &ftp_code)) - ftp_code = -1; - } - - (void)nread; - return ftp_code; -} - -/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode - saying whether an error occurred or CURLE_OK if |len| was read. */ -static CURLcode -socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len) -{ - char *to_p = to; - CURLcode result; - size_t nread = 0; - - while(len > 0) { - result = Curl_conn_recv(data, sockindex, to_p, len, &nread); - if(result == CURLE_AGAIN) - continue; - if(result) - return result; - if(nread > len) - return CURLE_RECV_ERROR; - len -= nread; - to_p += nread; - } - return CURLE_OK; -} - - -/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a - CURLcode saying whether an error occurred or CURLE_OK if |len| was - written. */ -static CURLcode -socket_write(struct Curl_easy *data, int sockindex, const void *to, - size_t len) -{ - const char *to_p = to; - CURLcode result; - size_t written; - - while(len > 0) { - result = Curl_conn_send(data, sockindex, to_p, len, FALSE, &written); - if(!result && written > 0) { - len -= written; - to_p += written; - } - else { - if(result == CURLE_AGAIN) - continue; - return result; - } - } - return CURLE_OK; -} - -static CURLcode krb5_read_data(struct Curl_easy *data, int sockindex, - struct krb5buffer *buf) -{ - struct connectdata *conn = data->conn; - int len; - CURLcode result; - int nread; - - result = socket_read(data, sockindex, &len, sizeof(len)); - if(result) - return result; - - if(len) { - len = (int)ntohl((uint32_t)len); - if(len > CURL_MAX_INPUT_LENGTH) - return CURLE_TOO_LARGE; - - curlx_dyn_reset(&buf->buf); - } - else - return CURLE_RECV_ERROR; - - do { - char buffer[1024]; - nread = CURLMIN(len, (int)sizeof(buffer)); - result = socket_read(data, sockindex, buffer, (size_t)nread); - if(result) - return result; - result = curlx_dyn_addn(&buf->buf, buffer, nread); - if(result) - return result; - len -= nread; - } while(len); - /* this decodes the dynbuf *in place* */ - nread = conn->mech->decode(conn->app_data, - curlx_dyn_ptr(&buf->buf), - len, conn->data_prot, conn); - if(nread < 0) - return CURLE_RECV_ERROR; - curlx_dyn_setlen(&buf->buf, nread); - buf->index = 0; - return CURLE_OK; -} - -static size_t -buffer_read(struct krb5buffer *buf, void *data, size_t len) -{ - size_t size = curlx_dyn_len(&buf->buf); - if(size - buf->index < len) - len = size - buf->index; - memcpy(data, curlx_dyn_ptr(&buf->buf) + buf->index, len); - buf->index += len; - return len; -} - -/* Matches Curl_recv signature */ -static CURLcode sec_recv(struct Curl_easy *data, int sockindex, - char *buffer, size_t len, size_t *pnread) -{ - struct connectdata *conn = data->conn; - CURLcode result = CURLE_OK; - size_t bytes_read; - - /* Handle clear text response. */ - if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) - return Curl_conn_recv(data, sockindex, buffer, len, pnread); - - if(conn->in_buffer.eof_flag) { - conn->in_buffer.eof_flag = 0; - *pnread = 0; - return CURLE_OK; - } - - bytes_read = buffer_read(&conn->in_buffer, buffer, len); - buffer += bytes_read; - len -= bytes_read; - *pnread += bytes_read; - - while(len > 0) { - result = krb5_read_data(data, sockindex, &conn->in_buffer); - if(result) - return result; - if(curlx_dyn_len(&conn->in_buffer.buf) == 0) { - if(*pnread > 0) - conn->in_buffer.eof_flag = 1; - return result; - } - bytes_read = buffer_read(&conn->in_buffer, buffer, len); - buffer += bytes_read; - len -= bytes_read; - *pnread += bytes_read; - } - return result; -} - -/* Send |length| bytes from |from| to the |sockindex| socket taking care of - encoding and negotiating with the server. |from| can be NULL. */ -static CURLcode do_sec_send(struct Curl_easy *data, struct connectdata *conn, - int sockindex, const char *from, size_t length) -{ - int bytes, htonl_bytes; /* 32-bit integers for htonl */ - char *buffer = NULL; - char *cmd_buffer; - size_t cmd_size = 0; - enum protection_level prot_level = conn->data_prot; - bool iscmd = (prot_level == PROT_CMD); - CURLcode result = CURLE_OK; - - DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); - - if(iscmd) { - if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5)) - prot_level = PROT_PRIVATE; - else - prot_level = conn->command_prot; - } - bytes = conn->mech->encode(conn->app_data, from, (int)length, - (int)prot_level, (void **)&buffer); - if(!buffer || bytes <= 0) - return CURLE_OUT_OF_MEMORY; /* error */ - - if(iscmd) { - result = curlx_base64_encode(buffer, curlx_sitouz(bytes), - &cmd_buffer, &cmd_size); - if(result) { - free(buffer); - return result; /* error */ - } - if(cmd_size > 0) { - static const char *enc = "ENC "; - static const char *mic = "MIC "; - if(prot_level == PROT_PRIVATE) - result = socket_write(data, sockindex, enc, 4); - else - result = socket_write(data, sockindex, mic, 4); - if(!result) - result = socket_write(data, sockindex, cmd_buffer, cmd_size); - if(!result) - result = socket_write(data, sockindex, "\r\n", 2); - if(!result) - infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic, - cmd_buffer); - } - free(cmd_buffer); - } - else { - htonl_bytes = (int)htonl((OM_uint32)bytes); - result = socket_write(data, sockindex, &htonl_bytes, sizeof(htonl_bytes)); - if(!result) - result = socket_write(data, sockindex, buffer, curlx_sitouz(bytes)); - } - free(buffer); - return result; -} - -static CURLcode sec_write(struct Curl_easy *data, int sockindex, - const char *buffer, size_t length, - size_t *pnwritten) -{ - struct connectdata *conn = data->conn; - size_t len = conn->buffer_size; - - *pnwritten = 0; - if(len <= 0) - len = length; - while(length) { - CURLcode result; - if(length < len) - len = length; - - result = do_sec_send(data, conn, sockindex, buffer, len); - if(result) - return result; - length -= len; - buffer += len; - *pnwritten += len; - } - return CURLE_OK; -} - -/* Matches Curl_send signature */ -static CURLcode sec_send(struct Curl_easy *data, int sockindex, - const void *buffer, size_t len, bool eos, - size_t *pnwritten) -{ - (void)eos; - return sec_write(data, sockindex, buffer, len, pnwritten); -} - -int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, - char *buffer, enum protection_level level) -{ - /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an - int */ - int decoded_len; - char *buf; - int ret_code = 0; - size_t decoded_sz = 0; - CURLcode error; - - (void)data; - - if(!conn->mech) - /* not initialized, return error */ - return -1; - - DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - - error = curlx_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); - if(error || decoded_sz == 0) - return -1; - - if(decoded_sz > (size_t)INT_MAX) { - free(buf); - return -1; - } - decoded_len = curlx_uztosi(decoded_sz); - - decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len, - (int)level, conn); - if(decoded_len <= 0) { - free(buf); - return -1; - } - - { - buf[decoded_len] = '\n'; - Curl_debug(data, CURLINFO_HEADER_IN, buf, decoded_len + 1); - } - - buf[decoded_len] = '\0'; - if(decoded_len <= 3) - /* suspiciously short */ - return 0; - - if(buf[3] != '-') - ret_code = atoi(buf); - - if(buf[decoded_len - 1] == '\n') - buf[decoded_len - 1] = '\0'; - strcpy(buffer, buf); - free(buf); - return ret_code; -} - -static int sec_set_protection_level(struct Curl_easy *data) -{ - int code; - struct connectdata *conn = data->conn; - unsigned char level = conn->request_data_prot; - - DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - - if(!conn->sec_complete) { - infof(data, "Trying to change the protection level after the" - " completion of the data exchange."); - return -1; - } - - /* Bail out if we try to set up the same level */ - if(conn->data_prot == level) - return 0; - - if(level) { - char *pbsz; - unsigned int buffer_size = 1 << 20; /* 1048576 */ - struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); - char *line; - - if(!ftpc) - return -2; - - code = ftp_send_command(data, "PBSZ %u", buffer_size); - if(code < 0) - return -1; - - if(code/100 != 2) { - failf(data, "Failed to set the protection's buffer size."); - return -1; - } - conn->buffer_size = buffer_size; - - line = curlx_dyn_ptr(&ftpc->pp.recvbuf); - pbsz = strstr(line, "PBSZ="); - if(pbsz) { - /* stick to default value if the check fails */ - if(ISDIGIT(pbsz[5])) - buffer_size = (unsigned int)atoi(&pbsz[5]); - if(buffer_size < conn->buffer_size) - conn->buffer_size = buffer_size; - } - } - - /* Now try to negotiate the protection level. */ - code = ftp_send_command(data, "PROT %c", level_to_char(level)); - - if(code < 0) - return -1; - - if(code/100 != 2) { - failf(data, "Failed to set the protection level."); - return -1; - } - - conn->data_prot = level; - if(level == PROT_PRIVATE) - conn->command_prot = level; - - return 0; -} - -int -Curl_sec_request_prot(struct connectdata *conn, const char *level) -{ - unsigned char l = name_to_level(level); - if(l == PROT_NONE) - return -1; - DEBUGASSERT(l > PROT_NONE && l < PROT_LAST); - conn->request_data_prot = l; - return 0; -} - -static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn) -{ - int ret; - void *tmp_allocation; - const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; - - tmp_allocation = realloc(conn->app_data, mech->size); - if(!tmp_allocation) { - failf(data, "Failed realloc of size %zu", mech->size); - mech = NULL; - return CURLE_OUT_OF_MEMORY; - } - conn->app_data = tmp_allocation; - - if(mech->init) { - ret = mech->init(conn->app_data); - if(ret) { - infof(data, "Failed initialization for %s. Skipping it.", - mech->name); - return CURLE_FAILED_INIT; - } - } - - infof(data, "Trying mechanism %s...", mech->name); - ret = ftp_send_command(data, "AUTH %s", mech->name); - if(ret < 0) - return CURLE_COULDNT_CONNECT; - - if(ret/100 != 3) { - switch(ret) { - case 504: - infof(data, "Mechanism %s is not supported by the server (server " - "returned ftp code: 504).", mech->name); - break; - case 534: - infof(data, "Mechanism %s was rejected by the server (server returned " - "ftp code: 534).", mech->name); - break; - default: - if(ret/100 == 5) { - infof(data, "server does not support the security extensions"); - return CURLE_USE_SSL_FAILED; - } - break; - } - return CURLE_LOGIN_DENIED; - } - - /* Authenticate */ - ret = mech->auth(conn->app_data, data, conn); - - if(ret != AUTH_CONTINUE) { - if(ret != AUTH_OK) { - /* Mechanism has dumped the error to stderr, do not error here. */ - return CURLE_USE_SSL_FAILED; - } - DEBUGASSERT(ret == AUTH_OK); - - conn->mech = mech; - conn->sec_complete = 1; - conn->recv[FIRSTSOCKET] = sec_recv; - conn->send[FIRSTSOCKET] = sec_send; - conn->recv[SECONDARYSOCKET] = sec_recv; - conn->send[SECONDARYSOCKET] = sec_send; - conn->command_prot = PROT_SAFE; - /* Set the requested protection level */ - /* BLOCKING */ - (void)sec_set_protection_level(data); - } - - return CURLE_OK; -} - -CURLcode -Curl_sec_login(struct Curl_easy *data, struct connectdata *conn) -{ - return choose_mech(data, conn); -} - -void -Curl_sec_conn_init(struct connectdata *conn) -{ - curlx_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH); - conn->in_buffer.index = 0; - conn->in_buffer.eof_flag = 0; -} - -void -Curl_sec_conn_destroy(struct connectdata *conn) -{ - if(conn->mech && conn->mech->end) - conn->mech->end(conn->app_data); - Curl_safefree(conn->app_data); - curlx_dyn_free(&conn->in_buffer.buf); - conn->in_buffer.index = 0; - conn->in_buffer.eof_flag = 0; - conn->sec_complete = 0; - conn->data_prot = PROT_CLEAR; - conn->mech = NULL; -} - -#if defined(__GNUC__) && defined(__APPLE__) -#pragma GCC diagnostic pop -#endif - -#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */ diff --git a/lib/pingpong.c b/lib/pingpong.c index 003ad58441c7..195e059ed1f4 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -182,10 +182,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data, CURLcode result; struct connectdata *conn = data->conn; -#ifdef HAVE_GSSAPI - enum protection_level data_sec; -#endif - DEBUGASSERT(pp->sendleft == 0); DEBUGASSERT(pp->sendsize == 0); DEBUGASSERT(pp->sendthis == NULL); @@ -208,9 +204,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data, write_len = curlx_dyn_len(&pp->sendbuf); s = curlx_dyn_ptr(&pp->sendbuf); -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CMD; -#endif result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, FALSE, &bytes_written); if(result == CURLE_AGAIN) { @@ -218,11 +211,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data, } else if(result) return result; -#ifdef HAVE_GSSAPI - data_sec = conn->data_prot; - DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); - conn->data_prot = (unsigned char)data_sec; -#endif Curl_debug(data, CURLINFO_HEADER_OUT, s, bytes_written); @@ -272,17 +260,7 @@ static CURLcode pingpong_read(struct Curl_easy *data, size_t buflen, size_t *nread) { - CURLcode result; -#ifdef HAVE_GSSAPI - enum protection_level prot = data->conn->data_prot; - data->conn->data_prot = PROT_CLEAR; -#endif - result = Curl_conn_recv(data, sockindex, buffer, buflen, nread); -#ifdef HAVE_GSSAPI - DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); - data->conn->data_prot = (unsigned char)prot; -#endif - return result; + return Curl_conn_recv(data, sockindex, buffer, buflen, nread); } /* @@ -348,10 +326,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, size_t length = nl - line + 1; /* output debug output if that is requested */ -#ifdef HAVE_GSSAPI - if(!conn->sec_complete) -#endif - Curl_debug(data, CURLINFO_HEADER_IN, line, length); + Curl_debug(data, CURLINFO_HEADER_IN, line, length); /* * Pass all response-lines to the callback function registered for diff --git a/lib/setopt.c b/lib/setopt.c index d958c5492a8d..3f628c443ca4 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -1967,15 +1967,8 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, case CURLOPT_FTP_ALTERNATIVE_TO_USER: return Curl_setstropt(&s->str[STRING_FTP_ALTERNATIVE_TO_USER], ptr); -#ifdef HAVE_GSSAPI case CURLOPT_KRBLEVEL: - /* - * A string that defines the kerberos security level. - */ - result = Curl_setstropt(&s->str[STRING_KRB_LEVEL], ptr); - s->krb = !!(s->str[STRING_KRB_LEVEL]); - break; -#endif + return CURLE_NOT_BUILT_IN; /* removed in 8.17.0 */ #endif case CURLOPT_URL: /* diff --git a/lib/url.c b/lib/url.c index 3f792ec7655e..a03a111995e2 100644 --- a/lib/url.c +++ b/lib/url.c @@ -98,7 +98,6 @@ #include "hsts.h" #include "noproxy.h" #include "cfilters.h" -#include "curl_krb5.h" #include "idn.h" /* And now for the protocols */ @@ -606,7 +605,6 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn) Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ #endif - Curl_sec_conn_destroy(conn); Curl_safefree(conn->user); Curl_safefree(conn->passwd); Curl_safefree(conn->sasl_authzid); @@ -1455,10 +1453,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) /* Initialize the attached xfers bitset */ Curl_uint_spbset_init(&conn->xfers_attached); -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CLEAR; -#endif - /* Store the local bind parameters that will be used for this connection */ if(data->set.str[STRING_DEVICE]) { conn->localdev = strdup(data->set.str[STRING_DEVICE]); @@ -3473,10 +3467,7 @@ static CURLcode create_conn(struct Curl_easy *data, /* Do the unfailable inits first, before checks that may early return */ Curl_hash_init(&conn->meta_hash, 23, - Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry); - - /* GSSAPI related inits */ - Curl_sec_conn_init(conn); + Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry); result = parseurlandfillconn(data, conn); if(result) diff --git a/lib/urldata.h b/lib/urldata.h index 4f00c8c9a093..b2e83c4a0eef 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -234,25 +234,6 @@ typedef CURLcode (Curl_recv)(struct Curl_easy *data, /* transfer */ ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) #endif -#ifdef HAVE_GSSAPI -/* Types needed for krb5-ftp connections */ -struct krb5buffer { - struct dynbuf buf; - size_t index; - BIT(eof_flag); -}; - -enum protection_level { - PROT_NONE, /* first in list */ - PROT_CLEAR, - PROT_SAFE, - PROT_CONFIDENTIAL, - PROT_PRIVATE, - PROT_CMD, - PROT_LAST /* last in list */ -}; -#endif - /* SSL backend-specific data; declared differently by each SSL backend */ struct ssl_backend_data; struct Curl_ssl_scache_entry; @@ -703,20 +684,6 @@ struct connectdata { was used on this connection. */ struct curltime keepalive; - /**** curl_get() phase fields */ - -#ifdef HAVE_GSSAPI - BIT(sec_complete); /* if Kerberos is enabled for this connection */ - unsigned char command_prot; /* enum protection_level */ - unsigned char data_prot; /* enum protection_level */ - unsigned char request_data_prot; /* enum protection_level */ - size_t buffer_size; - struct krb5buffer in_buffer; - void *app_data; - const struct Curl_sec_client_mech *mech; - struct sockaddr_in local_addr; -#endif - struct uint_spbset xfers_attached; /* mids of attached transfers */ /* A connection cache from a SHARE might be used in several multi handles. * We MUST not reuse connections that are running in another multi, @@ -1239,9 +1206,6 @@ enum dupstring { STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ STRING_FTPPORT, /* port to send with the FTP PORT command */ #endif -#ifdef HAVE_GSSAPI - STRING_KRB_LEVEL, /* krb security level */ -#endif #ifndef CURL_DISABLE_NETRC STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find $HOME/.netrc */ @@ -1604,9 +1568,6 @@ struct UserDefined { location: */ BIT(opt_no_body); /* as set with CURLOPT_NOBODY */ BIT(verbose); /* output verbosity */ -#ifdef HAVE_GSSAPI - BIT(krb); /* Kerberos connection requested */ -#endif BIT(reuse_forbid); /* forbidden to be reused, close after use */ BIT(reuse_fresh); /* do not reuse an existing connection */ BIT(no_signal); /* do not use any signal/alarm handler */ diff --git a/src/config2setopts.c b/src/config2setopts.c index e8f4b0a407ae..533fe992d34b 100644 --- a/src/config2setopts.c +++ b/src/config2setopts.c @@ -973,7 +973,6 @@ CURLcode config2setopts(struct OperationConfig *config, customrequest_helper(config->httpreq, config->customrequest); my_setopt(curl, CURLOPT_STDERR, tool_stderr); my_setopt_str(curl, CURLOPT_INTERFACE, config->iface); - my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel); progressbarinit(&per->progressbar, config); my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers); my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface); diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 43d30778de64..d7bdadb5d6d3 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -196,8 +196,8 @@ static const struct LongShort aliases[]= { {"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME}, {"key", ARG_FILE, ' ', C_KEY}, {"key-type", ARG_STRG|ARG_TLS, ' ', C_KEY_TYPE}, - {"krb", ARG_STRG, ' ', C_KRB}, - {"krb4", ARG_STRG, ' ', C_KRB4}, + {"krb", ARG_STRG|ARG_DEPR, ' ', C_KRB}, + {"krb4", ARG_STRG|ARG_DEPR, ' ', C_KRB4}, {"libcurl", ARG_STRG, ' ', C_LIBCURL}, {"limit-rate", ARG_STRG, ' ', C_LIMIT_RATE}, {"list-only", ARG_BOOL, 'l', C_LIST_ONLY}, @@ -2371,13 +2371,6 @@ static ParameterError opt_string(struct OperationConfig *config, /* interface */ err = getstr(&config->iface, nextarg, DENY_BLANK); break; - case C_KRB: /* --krb */ - /* kerberos level string */ - if(!feature_spnego) - err = PARAM_LIBCURL_DOESNT_SUPPORT; - else - err = getstr(&config->krblevel, nextarg, DENY_BLANK); - break; case C_HAPROXY_CLIENTIP: /* --haproxy-clientip */ err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK); break; diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c index ecbd8bf4595e..bd72dbe15c51 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -343,7 +343,7 @@ const struct helptxt helptext[] = { CURLHELP_TLS}, {" --krb ", "Enable Kerberos with security ", - CURLHELP_FTP}, + CURLHELP_DEPRECATED}, {" --libcurl ", "Generate libcurl code for this command line", CURLHELP_CURL | CURLHELP_GLOBAL}, diff --git a/tests/data/test1282 b/tests/data/test1282 index f57275187f2e..a54166be9661 100644 --- a/tests/data/test1282 +++ b/tests/data/test1282 @@ -18,11 +18,8 @@ REPLY PASS 633 XXXXXXXX\x00\x00XXXXXXXX ftp - -GSS-API - -FTP with 633 response before gss initialized +FTP with 633 response to auth ftp://%HOSTIP:%FTPPORT/%TESTNUMBER From 3dad0cfd779413866a2a0a8353ee9a98212673f8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 8 Sep 2025 00:18:52 +0200 Subject: [PATCH 106/208] write-out: make %header{} able to output *all* occurances of a header By appending `:all:[separator]` to the header name. The `[separator]` string is output between each header value if there are more than one to output. Test 764 and 765 verify Idea-by: kapsiR on github Ref: #18449 Closes #18491 --- docs/cmdline-opts/write-out.md | 8 +++ src/tool_writeout.c | 122 ++++++++++++++++++++++++++++----- tests/data/Makefile.am | 2 +- tests/data/test764 | 67 ++++++++++++++++++ tests/data/test765 | 67 ++++++++++++++++++ 5 files changed, 249 insertions(+), 17 deletions(-) create mode 100644 tests/data/test764 create mode 100644 tests/data/test765 diff --git a/docs/cmdline-opts/write-out.md b/docs/cmdline-opts/write-out.md index b365eeb22de3..9946349c1552 100644 --- a/docs/cmdline-opts/write-out.md +++ b/docs/cmdline-opts/write-out.md @@ -93,6 +93,14 @@ The value of header `name` from the transfer's most recent server response. Unlike other variables, the variable name `header` is not in braces. For example `%header{date}`. Refer to --write-out remarks. (Added in 7.84.0) +Starting with 8.17.0, output the contents of *all* header fields using a +specific name - even for a whole redirect "chain" by appending +`:all:[separator]` to the header name. The `[separator]` string (if not blank) +is output between the headers if there are more than one. When more than one +header is shown, they are output in the chronological order of appearance over +the wire. To include a close brace (`}`) in the separator, escape it with a +backslash: `\}`. + ## `header_json` A JSON object with all HTTP response headers from the recent transfer. Values are provided as arrays, since in the case of multiple headers there can be diff --git a/src/tool_writeout.c b/src/tool_writeout.c index 225cf91fd4e6..cdde28c90950 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -615,6 +615,111 @@ static const char *outtime(const char *ptr, /* %time{ ... */ return ptr; } +static void separator(const char *sep, size_t seplen, FILE *stream) +{ + while(seplen) { + if(*sep == '\\') { + switch(sep[1]) { + case 'r': + fputc('\r', stream); + break; + case 'n': + fputc('\n', stream); + break; + case 't': + fputc('\t', stream); + break; + case '}': + fputc('}', stream); + break; + case '\0': + break; + default: + /* unknown, just output this */ + fputc(sep[0], stream); + fputc(sep[1], stream); + break; + } + sep += 2; + seplen -= 2; + } + else { + fputc(*sep, stream); + sep++; + seplen--; + } + } +} + +static void output_header(struct per_transfer *per, + FILE *stream, + const char **pptr) +{ + const char *ptr = *pptr; + const char *end; + end = strchr(ptr, '}'); + do { + if(!end || (end[-1] != '\\')) + break; + end = strchr(&end[1], '}'); + } while(end); + if(end) { + char hname[256]; /* holds the longest header field name */ + struct curl_header *header; + const char *instr; + const char *sep = NULL; + size_t seplen = 0; + size_t vlen = end - ptr; + instr = memchr(ptr, ':', vlen); + if(instr) { + /* instructions follow */ + if(!strncmp(&instr[1], "all:", 4)) { + sep = &instr[5]; + seplen = end - sep; + vlen -= (seplen + 5); + } + } + if(vlen < sizeof(hname)) { + memcpy(hname, ptr, vlen); + hname[vlen] = 0; + if(sep) { + /* get headers from all requests */ + int reqno = 0; + size_t indno = 0; + bool output = FALSE; + do { + if(CURLHE_OK == curl_easy_header(per->curl, hname, indno, + CURLH_HEADER, reqno, + &header)) { + if(output) + /* output separator */ + separator(sep, seplen, stream); + fputs(header->value, stream); + output = TRUE; + } + else + break; + if((header->index + 1) < header->amount) + indno++; + else { + ++reqno; + indno = 0; + } + } while(1); + } + else { + if(CURLHE_OK == curl_easy_header(per->curl, hname, 0, + CURLH_HEADER, -1, &header)) + fputs(header->value, stream); + } + } + ptr = end + 1; + } + else + fputs("%header{", stream); + *pptr = ptr; +} + void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, CURLcode per_result) { @@ -699,22 +804,7 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, } else if(!strncmp("header{", &ptr[1], 7)) { ptr += 8; - end = strchr(ptr, '}'); - if(end) { - char hname[256]; /* holds the longest header field name */ - struct curl_header *header; - vlen = end - ptr; - if(vlen < sizeof(hname)) { - memcpy(hname, ptr, vlen); - hname[vlen] = 0; - if(CURLHE_OK == curl_easy_header(per->curl, hname, 0, - CURLH_HEADER, -1, &header)) - fputs(header->value, stream); - } - ptr = end + 1; - } - else - fputs("%header{", stream); + output_header(per, stream, &ptr); } else if(!strncmp("time{", &ptr[1], 5)) { ptr = outtime(ptr, stream); diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index dfff0122575c..854791fba0e9 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -109,7 +109,7 @@ test727 test728 test729 test730 test731 test732 test733 test734 test735 \ test736 test737 test738 test739 test740 test741 test742 test743 test744 \ test745 test746 test747 test748 test749 test750 test751 test752 test753 \ test754 test755 test756 test757 test758 test759 test760 test761 test762 \ -test763 \ +test763 test764 test765 \ \ test780 test781 test782 test783 test784 test785 test786 test787 test788 \ test789 test790 test791 test792 test793 test794 test796 test797 \ diff --git a/tests/data/test764 b/tests/data/test764 new file mode 100644 index 000000000000..dd138e108432 --- /dev/null +++ b/tests/data/test764 @@ -0,0 +1,67 @@ + + + +HTTP +HTTP GET +-w +%header + + + +# +# Server-side + + +HTTP/1.1 301 Redirect +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 +This: one +This: two +Content-Length: 6 +Location: %TESTNUMBER0002 +Content-Type: text/html +Funny-head: yesyes + +-foo- + + +HTTP/1.1 200 Not a redirect +Accept-Ranges: bytes +This: three +This: four +Content-Length: 6 +Funny-head: yesyes + +-foo- + + + + +# +# Client-side + + +headers-api + + +http + + +-w with multiple header output + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER -L -w '%header{this:all:***}\n' -o %LOGDIR/%TESTNUMBER.out + + + +# +# Verify data after the test has been "shot" + + +one***two***three***four + + + diff --git a/tests/data/test765 b/tests/data/test765 new file mode 100644 index 000000000000..2a868620c806 --- /dev/null +++ b/tests/data/test765 @@ -0,0 +1,67 @@ + + + +HTTP +HTTP GET +-w +%header + + + +# +# Server-side + + +HTTP/1.1 301 Redirect +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 +This: one +This: two +Content-Length: 6 +Location: %TESTNUMBER0002 +Content-Type: text/html +Funny-head: yesyes + +-foo- + + +HTTP/1.1 200 Not a redirect +Accept-Ranges: bytes +This: three +This: four +Content-Length: 6 +Funny-head: yesyes + +-foo- + + + + +# +# Client-side + + +headers-api + + +http + + +-w with multiple header output using } in separator + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER -L -w '%header{this:all:-{\}-}\n' -o %LOGDIR/%TESTNUMBER.out + + + +# +# Verify data after the test has been "shot" + + +one-{}-two-{}-three-{}-four + + + From 4189c2c0fe15b3a6afecadb56fd50b6875d7170b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 00:05:55 +0200 Subject: [PATCH 107/208] RELEASE-NOTES: synced --- RELEASE-NOTES | 78 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 69b05b895a9f..0fb4e0be115e 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,66 +4,97 @@ curl and libcurl 8.17.0 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3504 + Contributors: 3505 This release includes the following changes: + o build: drop the winbuild build system [81] + o krb5: drop support for Kerberos FTP [43] + o libssh2: up the minimum requirement to 1.9.0 [85] + o write-out: make %header{} able to output *all* occurances of a header [25] This release includes the following bugfixes: o asyn-thrdd: drop pthread_cancel [30] + o autotools: make `--enable-code-coverage` support llvm/clang [79] o aws-lc: re-enable large read-ahead with v1.61.0 again [16] + o base64: accept zero length argument to base64_encode [82] + o build: address some `-Weverything` warnings, update picky warnings [74] + o build: avoid overriding system symbols for socket functions [68] + o cf-socket: use the right byte order for ports in bindlocal [61] o cf_socket_recv: don't count reading zero bytes as first byte [23] o cfilter: unlink and discard [46] + o cmake: add `CURL_CODE_COVERAGE` option [78] o cmake: fix building docs when the base directory contains `.3` [18] o cmdline-docs: extended, clarified, refreshed [28] o configure: add "-mt" for pthread support on HP-UX [52] o cookie: avoid saving a cookie file if no transfer was done [11] o curl_easy_getinfo: error code on NULL arg [2] o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] + o curl_slist_append.md: clarify that a NULL pointer is not acceptable [72] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] + o CURLOPT_HEADER/WRITEFUNCTION.md: drop '* size' since size is always 1 [63] o CURLOPT_MAXLIFETIME_CONN: make default 24 hours [10] o CURLOPT_SSL_VERIFYHOST.md: add see-also to two other VERIFYHOST options [32] o CURLOPT_TIMECONDITION.md: works for FILE and FTP as well [27] + o digest_sspi: fix two memory leaks in error branches [77] o dist: do not distribute `CI.md` [29] o docs/libcurl: clarify some timeout option behavior [15] o docs/libcurl: remove ancient version references [7] o docs/libcurl: use lowercase must [5] o easy_getinfo: check magic, Curl_close safety [3] o examples: fix two issues found by CodeQL [35] + o ftp: fix port number range loop for PORT commands [66] + o gtls: avoid potential use of uninitialized variable in trace output [83] + o httpsrr: free old pointers when storing new [57] o krb5: return appropriate error on send failures [22] o ldap: do not base64 encode zero length string [42] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh: error on bad chgrp number [71] + o libssh: error on bad chown number and store the value [64] o libssh: react on errors from ssh_scp_read [24] + o libssh: return out of memory correctly if aprintf fails [60] o Makefile.example: simplify and make it configurable [20] o managen: ignore version mentions < 7.66.0 [55] o managen: render better manpage references/links [54] o multi.h: add CURLMINFO_LASTENTRY [51] o ngtcp2: check error code on connect failure [13] o openldap: avoid indexing the result at -1 for blank responses [44] + o openssl: make the asn1_object_dump name null terminated [56] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o rustls: typecast variable for safer trace output [69] o sasl: clear canceled mechanism instead of toggling it [41] + o schannel: assign result before using it [62] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] + o socks: make Curl_blockread_all return CURLcode [67] o socks_sspi: fix memory cleanup calls [40] o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] o sws: fix checking `sscanf()` return value [17] o telnet: make printsub require another byte input [21] o tftp: check and act on tftp_set_timeouts() returning error [38] + o tftp: handle tftp_multi_statemach() return code [65] o tftp: propagate expired timer from tftp_state_timeout() [39] + o tftp: return error when sendto() fails [59] + o tidy-up: avoid using the reserved macro namespace [76] + o tidy-up: update MS links, allow long URLs via `checksrc` [73] o TODO: remove already implemented or bad items [36] o tool: fix exponential retry delay [47] o tool_cb_hdr: fix fwrite check in header callback [49] + o tool_cb_hdr: size is always 1 [70] + o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_operate: improve wording in retry message [37] o tool_operate: keep the progress meter for --out-null [33] o urldata: FILE is not a list-only protocol [9] + o windows: replace `_beginthreadex()` with `CreateThread()` [80] + o windows: stop passing unused, optional argument for Win9x compatibility [75] This release includes the following known bugs: @@ -79,7 +110,6 @@ Planned upcoming removals include: o OpenSSL 1.x support o Support for c-ares versions before 1.16.0 o Support for Windows XP/2003 - o The winbuild build system o Windows CE support See https://curl.se/dev/deprecate.html @@ -87,12 +117,13 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Adam Light, Andrew Kirillov, Andrew Olsen, Christian Schmitz, Dan Fandrich, - Daniel Stenberg, dependabot[bot], divinity76 on github, - Emilio Pozuelo Monfort, Ethan Everett, fds242 on github, Javier Blazquez, - Jicea, Joshua Rogers, Michael Osipov, Nir Azkiel, Ray Satiro, renovate[bot], - Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats - (21 contributors) + Adam Light, Andrew Kirillov, Andrew Olsen, BobodevMm on github, + Christian Schmitz, Dan Fandrich, Daniel Stenberg, dependabot[bot], + divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, + fds242 on github, Javier Blazquez, Jicea, Joshua Rogers, kapsiR on github, + Marcel Raad, Michael Osipov, Michał Petryka, Nir Azkiel, Ray Satiro, + renovate[bot], Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats + (25 contributors) References to bug reports and discussions on issues: @@ -120,6 +151,7 @@ References to bug reports and discussions on issues: [22] = https://curl.se/bug/?i=18561 [23] = https://curl.se/bug/?i=18615 [24] = https://curl.se/bug/?i=18616 + [25] = https://curl.se/bug/?i=18491 [26] = https://curl.se/bug/?i=18606 [27] = https://curl.se/bug/?i=18551 [28] = https://curl.se/bug/?i=18550 @@ -137,6 +169,7 @@ References to bug reports and discussions on issues: [40] = https://curl.se/bug/?i=18587 [41] = https://curl.se/bug/?i=18573 [42] = https://curl.se/bug/?i=18602 + [43] = https://curl.se/bug/?i=18577 [44] = https://curl.se/bug/?i=18600 [45] = https://curl.se/bug/?i=18599 [46] = https://curl.se/bug/?i=18596 @@ -149,3 +182,32 @@ References to bug reports and discussions on issues: [53] = https://curl.se/bug/?i=18579 [54] = https://curl.se/bug/?i=18580 [55] = https://curl.se/bug/?i=18583 + [56] = https://curl.se/bug/?i=18647 + [57] = https://curl.se/bug/?i=18631 + [59] = https://curl.se/bug/?i=18643 + [60] = https://curl.se/bug/?i=18637 + [61] = https://curl.se/bug/?i=18641 + [62] = https://curl.se/bug/?i=18642 + [63] = https://curl.se/bug/?i=18640 + [64] = https://curl.se/bug/?i=18639 + [65] = https://curl.se/bug/?i=18638 + [66] = https://curl.se/bug/?i=18636 + [67] = https://curl.se/bug/?i=18635 + [68] = https://curl.se/bug/?i=18503 + [69] = https://curl.se/bug/?i=18628 + [70] = https://curl.se/bug/?i=18630 + [71] = https://curl.se/bug/?i=18629 + [72] = https://curl.se/bug/?i=18627 + [73] = https://curl.se/bug/?i=18626 + [74] = https://curl.se/bug/?i=18477 + [75] = https://curl.se/bug/?i=18490 + [76] = https://curl.se/bug/?i=18482 + [77] = https://curl.se/bug/?i=18488 + [78] = https://curl.se/bug/?i=18468 + [79] = https://curl.se/bug/?i=18473 + [80] = https://curl.se/bug/?i=18451 + [81] = https://curl.se/bug/?i=18040 + [82] = https://curl.se/bug/?i=18617 + [83] = https://curl.se/bug/?i=18620 + [84] = https://curl.se/bug/?i=18624 + [85] = https://curl.se/bug/?i=18612 From 0513f9f8786e0cc4246e05d56bd264d0292d9c92 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 19:04:21 +0200 Subject: [PATCH 108/208] build: show llvm/clang in platform flags and `buildinfo.txt` Show these flags: - `LLVM-CLANG` for mainline llvm/clang. - `APPLE-CLANG` for Apple clang. - `CLANG-CL` for clang-cl. (cmake only) Also: - GHA/linux: fix a job to build with clang, to match its descriptions. Closes #18645 --- .github/workflows/linux.yml | 1 + CMakeLists.txt | 9 +++++++++ acinclude.m4 | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index af2edf0e092b..c9f090a969e3 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -179,6 +179,7 @@ jobs: - name: 'openssl clang krb5 LTO' install_packages: zlib1g-dev libkrb5-dev clang install_steps: skiprun + CC: clang generate: -DCURL_USE_OPENSSL=ON -DCURL_USE_GSSAPI=ON -DENABLE_DEBUG=ON -DCURL_LTO=ON - name: 'openssl !ipv6 !--libcurl !--digest-auth' diff --git a/CMakeLists.txt b/CMakeLists.txt index ad78c58ed1db..a0587327db5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,15 @@ endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU") string(APPEND _target_flags " GCC") endif() +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + string(APPEND _target_flags " APPLE-CLANG") + elseif(MSVC) + string(APPEND _target_flags " CLANG-CL") + else() + string(APPEND _target_flags " LLVM-CLANG") + endif() +endif() if(MINGW) string(APPEND _target_flags " MINGW") endif() diff --git a/acinclude.m4 b/acinclude.m4 index fe10c2ec9715..f6a785277969 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1492,6 +1492,11 @@ AC_DEFUN([CURL_PREPARE_BUILDINFO], [ if test "x$compiler_id" = 'xGNU_C'; then curl_pflags="${curl_pflags} GCC" fi + if "$compiler_id" = "APPLECLANG"; then + curl_pflags="${curl_pflags} APPLE-CLANG" + elif test "$compiler_id" = "CLANG"; then + curl_pflags="${curl_pflags} LLVM-CLANG" + fi case $host_os in mingw*) curl_pflags="${curl_pflags} MINGW";; esac From 4e8dfe2093c83c708d4ee0b6952a8495608d708d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 09:39:58 +0200 Subject: [PATCH 109/208] RELEASE-NOTES: spellcheck! --- RELEASE-NOTES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 0fb4e0be115e..698c81d3a868 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -11,7 +11,7 @@ This release includes the following changes: o build: drop the winbuild build system [81] o krb5: drop support for Kerberos FTP [43] o libssh2: up the minimum requirement to 1.9.0 [85] - o write-out: make %header{} able to output *all* occurances of a header [25] + o write-out: make %header{} able to output *all* occurrences of a header [25] This release includes the following bugfixes: From fd61ed062bdad9ad9abdcc839f1c6c51b88e1c05 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 00:09:09 +0200 Subject: [PATCH 110/208] ws: clarify an error message Instead of: "[WS] frame length longer than 64 signed not supported" Use: "[WS] frame length longer than 63 bit not supported" Closes #18654 --- lib/ws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ws.c b/lib/ws.c index 00fdeb3e97f8..c840961d1017 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -453,7 +453,7 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, break; case 10: if(dec->head[2] > 127) { - failf(data, "[WS] frame length longer than 64 signed not supported"); + failf(data, "[WS] frame length longer than 63 bit not supported"); return CURLE_RECV_ERROR; } dec->payload_len = ((curl_off_t)dec->head[2] << 56) | From 3d8e15650ccc02cb7384f3b991478363e9498f3f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 17:44:32 +0200 Subject: [PATCH 111/208] vtls_int.h: clarify data_pending Suggested-by: Joseph Birr-Pixton Closes #18644 --- lib/vtls/vtls_int.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h index de0b735e22bf..8bf6c6c64be9 100644 --- a/lib/vtls/vtls_int.h +++ b/lib/vtls/vtls_int.h @@ -153,6 +153,10 @@ struct Curl_ssl { size_t (*version)(char *buffer, size_t size); CURLcode (*shut_down)(struct Curl_cfilter *cf, struct Curl_easy *data, bool send_shutdown, bool *done); + + /* data_pending() shall return TRUE when it wants to get called again to + drain internal buffers and deliver data instead of waiting for the socket + to get readable */ bool (*data_pending)(struct Curl_cfilter *cf, const struct Curl_easy *data); From 3b22ed999ef046cbd7a3503746bf9acf927623e7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 22:55:50 +0200 Subject: [PATCH 112/208] telnet: return error on crazy TTYPE or XDISPLOC lengths Also use the packet size msnprintf() stores instead of calculating it separately. Reported in Joshua's sarif data Closes #18648 --- lib/telnet.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/telnet.c b/lib/telnet.c index 05e5ebe60cc7..b475910baf6e 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -164,7 +164,7 @@ static void set_remote_option(struct Curl_easy *data, struct TELNET *tn, static void printsub(struct Curl_easy *data, int direction, unsigned char *pointer, size_t length); -static void suboption(struct Curl_easy *data, struct TELNET *tn); +static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn); static void sendsuboption(struct Curl_easy *data, struct TELNET *tn, int option); @@ -932,7 +932,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, * side. */ -static void suboption(struct Curl_easy *data, struct TELNET *tn) +static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) { struct curl_slist *v; unsigned char temp[2048]; @@ -944,22 +944,30 @@ static void suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: - len = strlen(tn->subopt_ttype) + 4 + 2; - msnprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, - CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + if(strlen(tn->subopt_ttype) > 1000) { + failf(data, "Tool long telnet TTYPE"); + return CURLE_SEND_ERROR; + } + len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { err = SOCKERRNO; - failf(data,"Sending data failed (%d)",err); + failf(data, "Sending data failed (%d)", err); + return CURLE_SEND_ERROR; } printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_XDISPLOC: - len = strlen(tn->subopt_xdisploc) + 4 + 2; - msnprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, - CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + if(strlen(tn->subopt_xdisploc) > 1000) { + failf(data, "Tool long telnet XDISPLOC"); + return CURLE_SEND_ERROR; + } + len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { err = SOCKERRNO; @@ -968,11 +976,9 @@ static void suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_NEW_ENVIRON: - msnprintf((char *)temp, sizeof(temp), - "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, - CURL_TELQUAL_IS); - len = 4; - + len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); for(v = tn->telnet_vars; v; v = v->next) { size_t tmplen = (strlen(v->data) + 1); /* Add the variable if it fits */ @@ -1000,7 +1006,7 @@ static void suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '>', &temp[2], len-2); break; } - return; + return CURLE_OK; } @@ -1204,7 +1210,9 @@ CURLcode telrcv(struct Curl_easy *data, CURL_SB_TERM(tn); printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); - suboption(data, tn); /* handle sub-option */ + result = suboption(data, tn); /* handle sub-option */ + if(result) + return result; tn->telrcv_state = CURL_TS_IAC; goto process_iac; } @@ -1216,7 +1224,9 @@ CURLcode telrcv(struct Curl_easy *data, CURL_SB_ACCUM(tn, CURL_SE); tn->subpointer -= 2; CURL_SB_TERM(tn); - suboption(data, tn); /* handle sub-option */ + result = suboption(data, tn); /* handle sub-option */ + if(result) + return result; tn->telrcv_state = CURL_TS_DATA; } break; From a9baf82a9b4291a948c908bce3f843c556d67deb Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 23:23:07 +0200 Subject: [PATCH 113/208] ftp: fix ftp_do_more returning with *completep unset Specifically, when ftpc->wait_data_conn was true and Curl_conn_connect(...) returned with serv_conned == false the code called ftp_check_ctrl_on_data_wait and returned without setting *completep. Now set it to 0 at function start to avoid this happening again. Reported in Joshua's sarif data Closes #18650 --- lib/ftp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ftp.c b/lib/ftp.c index df94ea5e6684..13b613bc1e86 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -3594,6 +3594,9 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) if(!ftpc || !ftp) return CURLE_FAILED_INIT; + + *completep = 0; /* default to stay in the state */ + /* if the second connection has been set up, try to connect it fully * to the remote host. This may not complete at this time, for several * reasons: @@ -3612,7 +3615,6 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) /* this is a EPSV connect failing, try PASV instead */ return ftp_epsv_disable(data, ftpc, conn); } - *completep = (int)complete; return result; } } From 05930f304bbf1492951b71d828f0de9fe253d4ea Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 23:33:05 +0200 Subject: [PATCH 114/208] rustls: use %zu for size_t in failf() format string Reported in Joshua's sarif data Closes #18651 --- lib/vtls/rustls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index e5d85aa38f38..c89fadf96665 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -1231,8 +1231,8 @@ cr_connect(struct Curl_cfilter *cf, size_t errorlen; rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); failf(data, - "Failed getting DER of server certificate #%ld: %.*s", i, - (int)errorlen, errorbuf); + "Failed getting DER of server certificate #%zu: %.*s", i, + (int)errorlen, errorbuf); return map_error(rresult); } { From ab3a293fd0cca2045cc2e3bf1a73f75b1bd7d4bc Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 23:38:04 +0200 Subject: [PATCH 115/208] libssh: fix range parsing error handling mistake The range-parsing returned CURLE_RANGE_ERROR directly on one error instead of calling myssh_to_ERROR() like it should and like it does for all other errors. Reported in Joshua's sarif data Closes #18652 --- lib/vssh/libssh.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index eacc27a92110..cb2e8cde4d43 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1319,8 +1319,7 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, if(size < 0) { failf(data, "Bad file size (%" FMT_OFF_T ")", size); - rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); - return rc; + return myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); } if(data->state.use_range) { curl_off_t from, to; @@ -1328,16 +1327,15 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, int from_t, to_t; from_t = curlx_str_number(&p, &from, CURL_OFF_T_MAX); - if(from_t == STRE_OVERFLOW) { - rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); - return rc; - } + if(from_t == STRE_OVERFLOW) + return myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); + curlx_str_passblanks(&p); (void)curlx_str_single(&p, '-'); to_t = curlx_str_numblanks(&p, &to); if(to_t == STRE_OVERFLOW) - return CURLE_RANGE_ERROR; + return myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); if((to_t == STRE_NO_NUM) || (to >= size)) { to = size - 1; @@ -1353,26 +1351,21 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, if(from > size) { failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", from, size); - rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); - return rc; + return myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); } if(from > to) { from = to; size = 0; } else { - if((to - from) == CURL_OFF_T_MAX) { - rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); - return rc; - } + if((to - from) == CURL_OFF_T_MAX) + return myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); size = to - from + 1; } rc = sftp_seek64(sshc->sftp_file, from); - if(rc) { - rc = myssh_to_SFTP_CLOSE(data, sshc); - return rc; - } + if(rc) + return myssh_to_SFTP_CLOSE(data, sshc); } data->req.size = size; data->req.maxdownload = size; @@ -1386,8 +1379,7 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, if((curl_off_t)size < -data->state.resume_from) { failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", data->state.resume_from, size); - rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); - return rc; + return myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); } /* download from where? */ data->state.resume_from += size; @@ -1397,8 +1389,7 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", data->state.resume_from, size); - rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); - return rc; + return myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); } } /* Now store the number of bytes we are expected to download */ @@ -1408,10 +1399,8 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, size - data->state.resume_from); rc = sftp_seek64(sshc->sftp_file, data->state.resume_from); - if(rc) { - rc = myssh_to_SFTP_CLOSE(data, sshc); - return rc; - } + if(rc) + return myssh_to_SFTP_CLOSE(data, sshc); } /* Setup the actual download */ From 0c53a5e5dcca82dfa57a209c350c77db1572a7c6 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 23:53:52 +0200 Subject: [PATCH 116/208] openldap: check ldap_get_option() return codes Do not just assume that they always work. Reported in Joshua's sarif data Closes #18653 --- lib/openldap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/openldap.c b/lib/openldap.c index 717739b68d89..7d25d1842112 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -538,7 +538,8 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate) Sockbuf *sb; /* Install the libcurl SSL handlers into the sockbuf. */ - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + return CURLE_FAILED_INIT; ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); li->recv = conn->recv[FIRSTSOCKET]; li->send = conn->send[FIRSTSOCKET]; @@ -951,7 +952,8 @@ static CURLcode oldap_disconnect(struct Curl_easy *data, #ifdef USE_SSL if(ssl_installed(conn)) { Sockbuf *sb; - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + return CURLE_FAILED_INIT; ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); } #endif @@ -986,7 +988,8 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) if(ssl_installed(conn)) { Sockbuf *sb; /* re-install the libcurl SSL handlers into the sockbuf. */ - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + return CURLE_FAILED_INIT; ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); } #endif From d57e7cf20d805032740a8b173ea53ea0da1cce62 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 10:18:13 +0200 Subject: [PATCH 117/208] ws: reject curl_ws_recv called with NULL buffer with a buflen Arguably this is just a bad application. Reported in Joshua's sarif data Closes #18656 --- lib/ws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ws.c b/lib/ws.c index c840961d1017..b6ab28a35ad0 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -1502,7 +1502,7 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, *nread = 0; *metap = NULL; - if(!GOOD_EASY_HANDLE(data)) + if(!GOOD_EASY_HANDLE(data) || (buflen && !buffer)) return CURLE_BAD_FUNCTION_ARGUMENT; conn = data->conn; From c23d7e7a980d172e2134225933440b05404a1f14 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 11:35:01 +0200 Subject: [PATCH 118/208] GHA/codeql: enable ECH and HTTPS-RR Switch to Linuxbrew c-ares to hit the minimum version. (Ubuntu offers 1.27.0, HTTPS-RR requires 1.28.0.) Closes #18661 --- .github/workflows/codeql.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bb3c07482163..808ee0b63a91 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -75,9 +75,9 @@ jobs: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libc-ares-dev \ + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev \ libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev - /home/linuxbrew/.linuxbrew/bin/brew install gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi + /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: @@ -104,10 +104,10 @@ jobs: eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" # MultiSSL - export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" + export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix c-ares)/lib/pkgconfig:$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" cmake -B _bld1 -G Ninja -DENABLE_DEBUG=ON \ -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ - -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DENABLE_ARES=ON + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DUSE_ECH=ON -DENABLE_ARES=ON cmake --build _bld1 --verbose cmake --build _bld1 --verbose --target curlinfo cmake --build _bld1 --verbose --target servers From 06d00e3879bbfe167972ee45f1dad0ec591a04fb Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 13:31:35 +0200 Subject: [PATCH 119/208] cmake: clang detection tidy-ups Follow-up to 0513f9f8786e0cc4246e05d56bd264d0292d9c92 #18645 Follow-up to fe5225b5eaf3a1a0ce149023d38a9922a114798b #18209 Closes #18659 --- CMakeLists.txt | 14 ++++++-------- docs/examples/CMakeLists.txt | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0587327db5f..083c2f37b9c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,14 +148,12 @@ endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU") string(APPEND _target_flags " GCC") endif() -if(CMAKE_C_COMPILER_ID MATCHES "Clang") - if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") - string(APPEND _target_flags " APPLE-CLANG") - elseif(MSVC) - string(APPEND _target_flags " CLANG-CL") - else() - string(APPEND _target_flags " LLVM-CLANG") - endif() +if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + string(APPEND _target_flags " APPLE-CLANG") +elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND MSVC) + string(APPEND _target_flags " CLANG-CL") +elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") + string(APPEND _target_flags " LLVM-CLANG") endif() if(MINGW) string(APPEND _target_flags " MINGW") diff --git a/docs/examples/CMakeLists.txt b/docs/examples/CMakeLists.txt index cb1d983890c6..bc0f3ce359b8 100644 --- a/docs/examples/CMakeLists.txt +++ b/docs/examples/CMakeLists.txt @@ -37,7 +37,7 @@ foreach(_target IN LISTS check_PROGRAMS _all) # keep '_all' last set(_examples_c "${check_PROGRAMS}") list(TRANSFORM _examples_c APPEND ".c") add_library(${_target_name} OBJECT EXCLUDE_FROM_ALL ${_examples_c}) - if(MSVC AND NOT CMAKE_C_COMPILER_ID STREQUAL "Clang") + if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") # MSVC but exclude clang-cl # CMake generates a static library for the OBJECT target. Silence these 'lib.exe' warnings: # warning LNK4006: main already defined in ....obj; second definition ignored # warning LNK4221: This object file does not define any previously undefined public symbols, From e5d9c871f0b54c8382b2f417b5923ac78d6a4e12 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 21 Aug 2025 22:27:41 +0200 Subject: [PATCH 120/208] tidy-up: assortment of small fixes - examples/headerapi: fix wrong cast. - curl_ngtcp2: delete stray character from error message. - rustls: fix inline variable declaration. - sendf: drop redundant `int` cast. - libtest/cli_ws_data: drop cast with mismatched signedness. Cherry-picked from #18343 Closes #18664 --- docs/examples/headerapi.c | 2 +- lib/sendf.c | 2 +- lib/vquic/curl_ngtcp2.c | 2 +- lib/vtls/rustls.c | 3 ++- tests/libtest/cli_ws_data.c | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/examples/headerapi.c b/docs/examples/headerapi.c index 95c366884a42..ede0c5cbdaed 100644 --- a/docs/examples/headerapi.c +++ b/docs/examples/headerapi.c @@ -69,7 +69,7 @@ int main(void) do { h = curl_easy_nextheader(curl, CURLH_HEADER, -1, prev); if(h) - printf(" %s: %s (%u)\n", h->name, h->value, (int)h->amount); + printf(" %s: %s (%u)\n", h->name, h->value, (unsigned int)h->amount); prev = h; } while(h); diff --git a/lib/sendf.c b/lib/sendf.c index f759fb61a4af..a262d9036fd9 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -857,7 +857,7 @@ static CURLcode cr_in_rewind(struct Curl_easy *data, Curl_set_in_callback(data, FALSE); CURL_TRC_READ(data, "cr_in, rewind via set.seek_func -> %d", err); if(err) { - failf(data, "seek callback returned error %d", (int)err); + failf(data, "seek callback returned error %d", err); return CURLE_SEND_FAIL_REWIND; } } diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 246e0d51f661..f902c190ef58 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -1337,7 +1337,7 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, result = Curl_1st_err(result, cf_progress_egress(cf, data, &pktx)); result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %dm, %zu", + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %d, %zu", stream ? stream->id : -1, blen, result, *pnread); CF_DATA_RESTORE(cf, save); return result; diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index c89fadf96665..87c23544ef4c 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -1212,13 +1212,14 @@ cr_connect(struct Curl_cfilter *cf, } if(data->set.ssl.certinfo) { size_t num_certs = 0; + size_t i; while(rustls_connection_get_peer_certificate(rconn, (int)num_certs)) { num_certs++; } result = Curl_ssl_init_certinfo(data, (int)num_certs); if(result) return result; - for(size_t i = 0; i < num_certs; i++) { + for(i = 0; i < num_certs; i++) { const rustls_certificate *cert; const unsigned char *der_data; size_t der_len; diff --git a/tests/libtest/cli_ws_data.c b/tests/libtest/cli_ws_data.c index 36d5dea25b1c..32356552a807 100644 --- a/tests/libtest/cli_ws_data.c +++ b/tests/libtest/cli_ws_data.c @@ -106,7 +106,7 @@ static CURLcode test_ws_data_m2_echo(const char *url, curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */ r = curl_easy_perform(curl); - curl_mfprintf(stderr, "curl_easy_perform() returned %u\n", (int)r); + curl_mfprintf(stderr, "curl_easy_perform() returned %u\n", r); if(r != CURLE_OK) goto out; From e21cc7844db33fe6b77e8dbe687cd720ec9d738e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 17:51:34 +0200 Subject: [PATCH 121/208] autotools: fix silly mistake in clang detection for `buildinfo.txt` Follow-up to 0513f9f8786e0cc4246e05d56bd264d0292d9c92 #18645 Closes #18666 --- acinclude.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acinclude.m4 b/acinclude.m4 index f6a785277969..febb8961cca3 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1492,7 +1492,7 @@ AC_DEFUN([CURL_PREPARE_BUILDINFO], [ if test "x$compiler_id" = 'xGNU_C'; then curl_pflags="${curl_pflags} GCC" fi - if "$compiler_id" = "APPLECLANG"; then + if test "$compiler_id" = "APPLECLANG"; then curl_pflags="${curl_pflags} APPLE-CLANG" elif test "$compiler_id" = "CLANG"; then curl_pflags="${curl_pflags} LLVM-CLANG" From 374c23c617322ecd76794d058461f69b8abbef0e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 18:02:21 +0200 Subject: [PATCH 122/208] autotools: fix duplicate `UNIX` and `BSD` flags in `buildinfo.txt` Follow-up to 2a292c39846107228201674d686be5b3ed96674d #15975 Closes #18667 --- acinclude.m4 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index febb8961cca3..7b26dfd466a3 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1474,14 +1474,6 @@ AC_DEFUN([CURL_PREPARE_BUILDINFO], [ if test "$curl_cv_winuwp" = 'yes'; then curl_pflags="${curl_pflags} UWP" fi - case $host in - *-*-*bsd*|*-*-aix*|*-*-hpux*|*-*-interix*|*-*-irix*|*-*-linux*|*-*-solaris*|*-*-sunos*|*-apple-*|*-*-cygwin*|*-*-msys*) - curl_pflags="${curl_pflags} UNIX";; - esac - case $host in - *-*-*bsd*) - curl_pflags="${curl_pflags} BSD";; - esac if test "$curl_cv_cygwin" = 'yes'; then curl_pflags="${curl_pflags} CYGWIN" fi From 989a274e45318b290b7ddf28d7562ff6ec0cba4a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 20:25:04 +0200 Subject: [PATCH 123/208] autotools: add support for libgsasl auto-detection via pkg-config Enable with `--with-gsasl`, as before. Cherry-picked from #18660 Closes #18669 --- configure.ac | 71 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index fa23eb09b1e4..1aa0c2759651 100644 --- a/configure.ac +++ b/configure.ac @@ -2204,20 +2204,67 @@ dnl ********************************************************************** dnl Check for libgsasl dnl ********************************************************************** -AC_ARG_WITH(libgsasl, - AS_HELP_STRING([--without-libgsasl], - [disable libgsasl support for SCRAM]), - with_libgsasl=$withval, - with_libgsasl=yes) -if test $with_libgsasl != "no"; then - AC_SEARCH_LIBS(gsasl_init, gsasl, - [curl_gsasl_msg="enabled"; - AC_DEFINE([USE_GSASL], [1], [GSASL support enabled]) - LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libgsasl" +OPT_LIBGSASL=no +AC_ARG_WITH(libgsasl,dnl +AS_HELP_STRING([--with-libgsasl=PATH],[Where to look for libgsasl, PATH points to the libgsasl installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AS_HELP_STRING([--without-libgsasl], [disable libgsasl support for SCRAM]), + OPT_LIBGSASL=$withval) + +if test "$OPT_LIBGSASL" != no; then + dnl backup the pre-libgsasl variables + CLEANLDFLAGS="$LDFLAGS" + CLEANLDFLAGSPC="$LDFLAGSPC" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBGSASL" in + yes) + dnl --with-libgsasl (without path) used + CURL_CHECK_PKGCONFIG(libgsasl) + + if test "$PKGCONFIG" != "no"; then + LIB_GSASL=`$PKGCONFIG --libs-only-l libgsasl` + LD_GSASL=`$PKGCONFIG --libs-only-L libgsasl` + CPP_GSASL=`$PKGCONFIG --cflags-only-I libgsasl` + else + dnl no libgsasl pkg-config found + LIB_GSASL="-lgsasl" + fi + ;; + *) + dnl use the given --with-libgsasl spot + PREFIX_GSASL=$OPT_LIBGSASL + ;; + esac + + dnl if given with a prefix, we set -L and -I based on that + if test -n "$PREFIX_GSASL"; then + LIB_GSASL="-lgsasl" + LD_GSASL=-L${PREFIX_GSASL}/lib$libsuff + CPP_GSASL=-I${PREFIX_GSASL}/include + fi + + LDFLAGS="$LDFLAGS $LD_GSASL" + LDFLAGSPC="$LDFLAGSPC $LD_GSASL" + CPPFLAGS="$CPPFLAGS $CPP_GSASL" + LIBS="$LIB_GSASL $LIBS" + + AC_CHECK_LIB(gsasl, gsasl_init, + [ + AC_CHECK_HEADERS(gsasl.h, + curl_gsasl_msg="enabled" + AC_DEFINE(USE_GSASL, 1, [GSASL support enabled]) + USE_LIBGSASL=1 + LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libgsasl" + ) ], - [curl_gsasl_msg="no (libgsasl not found)"; + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + LDFLAGSPC=$CLEANLDFLAGSPC + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + curl_gsasl_msg="no (libgsasl not found)" AC_MSG_WARN([libgsasl was not found]) - ] ) fi AM_CONDITIONAL([USE_GSASL], [test "$curl_gsasl_msg" = "enabled"]) From a72e1552f224f3785d8aafc9819cd4ad0821c01d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 10:48:00 +0200 Subject: [PATCH 124/208] telnet: refuse IAC codes in content Ban the use of IAC (0xff) in telnet options set by the application. They need to be escaped when sent but I can't see any valid reason for an application to send them. Of course, an application sending such data basically ask for trouble. Reported in Joshua's sarif data Closes #18657 --- lib/telnet.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/telnet.c b/lib/telnet.c index b475910baf6e..f2226a7f7dd8 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -925,6 +925,14 @@ static CURLcode check_telnet_options(struct Curl_easy *data, return result; } +/* if the option contains an IAC code, it should be escaped in the output, but + as we cannot think of any legit way to send that as part of the content we + rather just ban its use instead */ +static bool bad_option(const char *data) +{ + return !!strchr(data, CURL_IAC); +} + /* * suboption() * @@ -944,6 +952,8 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: + if(bad_option(tn->subopt_ttype)) + return CURLE_BAD_FUNCTION_ARGUMENT; if(strlen(tn->subopt_ttype) > 1000) { failf(data, "Tool long telnet TTYPE"); return CURLE_SEND_ERROR; @@ -961,6 +971,8 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_XDISPLOC: + if(bad_option(tn->subopt_xdisploc)) + return CURLE_BAD_FUNCTION_ARGUMENT; if(strlen(tn->subopt_xdisploc) > 1000) { failf(data, "Tool long telnet XDISPLOC"); return CURLE_SEND_ERROR; @@ -981,6 +993,8 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) CURL_TELQUAL_IS); for(v = tn->telnet_vars; v; v = v->next) { size_t tmplen = (strlen(v->data) + 1); + if(bad_option(v->data)) + return CURLE_BAD_FUNCTION_ARGUMENT; /* Add the variable if it fits */ if(len + tmplen < (int)sizeof(temp)-6) { char *s = strchr(v->data, ','); From c4f9977c66bbb05a837a7eb03004dd79c3cc9b44 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 11:07:31 +0200 Subject: [PATCH 125/208] tftp: pin the first used address Store the used remote address on the first receive call and then make sure that it remains the same address on subsequent calls to reduce the risk of tampering. Doesn't make the transfer secure because it is still unauthenticated and clear text. Reported in Joshua's sarif data Closes #18658 --- lib/tftp.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/tftp.c b/lib/tftp.c index 8b6246a34265..736b14b67364 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -126,6 +126,10 @@ struct tftp_packet { #define CURL_META_TFTP_CONN "meta:proto:tftp:conn" struct tftp_conn { + struct Curl_sockaddr_storage local_addr; + struct Curl_sockaddr_storage remote_addr; + struct tftp_packet rpacket; + struct tftp_packet spacket; tftp_state_t state; tftp_mode_t mode; tftp_error_t error; @@ -136,16 +140,13 @@ struct tftp_conn { int retry_time; int retry_max; time_t rx_time; - struct Curl_sockaddr_storage local_addr; - struct Curl_sockaddr_storage remote_addr; curl_socklen_t remote_addrlen; int rbytes; size_t sbytes; unsigned int blksize; unsigned int requested_blksize; unsigned short block; - struct tftp_packet rpacket; - struct tftp_packet spacket; + BIT(remote_pinned); }; @@ -1094,18 +1095,31 @@ static CURLcode tftp_pollset(struct Curl_easy *data, static CURLcode tftp_receive_packet(struct Curl_easy *data, struct tftp_conn *state) { - curl_socklen_t fromlen; - CURLcode result = CURLE_OK; + CURLcode result = CURLE_OK; + struct Curl_sockaddr_storage remote_addr; + curl_socklen_t fromlen = sizeof(remote_addr); /* Receive the packet */ - fromlen = sizeof(state->remote_addr); state->rbytes = (int)recvfrom(state->sockfd, (void *)state->rpacket.data, (RECV_TYPE_ARG3)state->blksize + 4, 0, - (struct sockaddr *)&state->remote_addr, + (struct sockaddr *)&remote_addr, &fromlen); - state->remote_addrlen = fromlen; + if(state->remote_pinned) { + /* pinned, verify that it comes from the same address */ + if((state->remote_addrlen != fromlen) || + memcmp(&remote_addr, &state->remote_addr, fromlen)) { + failf(data, "Data received from another address"); + return CURLE_RECV_ERROR; + } + } + else { + /* pin address on first use */ + state->remote_pinned = TRUE; + state->remote_addrlen = fromlen; + memcpy(&state->remote_addr, &remote_addr, fromlen); + } /* Sanity check packet length */ if(state->rbytes < 4) { From 1f0f0bdb192a71b6b8b654115ee2c08f8411e356 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 08:33:20 +0200 Subject: [PATCH 126/208] managen: strict protocol check - protocols MUST match one in the accept-list - protocols are typically all uppercase - drop All - use SCP and SFTP instead of SSH - add Protocols: to some options previously missing one Closes #18675 --- docs/cmdline-opts/doh-cert-status.md | 1 + docs/cmdline-opts/doh-insecure.md | 1 + docs/cmdline-opts/doh-url.md | 1 + docs/cmdline-opts/follow.md | 1 + docs/cmdline-opts/form-escape.md | 2 +- docs/cmdline-opts/ip-tos.md | 1 - docs/cmdline-opts/key.md | 2 +- docs/cmdline-opts/pass.md | 2 +- docs/cmdline-opts/sasl-authzid.md | 1 + docs/cmdline-opts/sasl-ir.md | 1 + docs/cmdline-opts/socks5-gssapi-nec.md | 1 + docs/cmdline-opts/socks5-gssapi.md | 1 + docs/cmdline-opts/telnet-option.md | 1 + docs/cmdline-opts/upload-flags.md | 1 + docs/cmdline-opts/url-query.md | 1 - docs/cmdline-opts/vlan-priority.md | 1 - scripts/managen | 34 ++++++++++++++++++++++++-- 17 files changed, 45 insertions(+), 8 deletions(-) diff --git a/docs/cmdline-opts/doh-cert-status.md b/docs/cmdline-opts/doh-cert-status.md index 7c497cf16f42..445eb3dcd04c 100644 --- a/docs/cmdline-opts/doh-cert-status.md +++ b/docs/cmdline-opts/doh-cert-status.md @@ -5,6 +5,7 @@ Long: doh-cert-status Help: Verify DoH server cert status OCSP-staple Added: 7.76.0 Category: dns tls +Protocols: DNS Multi: boolean See-also: - doh-insecure diff --git a/docs/cmdline-opts/doh-insecure.md b/docs/cmdline-opts/doh-insecure.md index 72f3cb77252b..ee1602a242fd 100644 --- a/docs/cmdline-opts/doh-insecure.md +++ b/docs/cmdline-opts/doh-insecure.md @@ -5,6 +5,7 @@ Long: doh-insecure Help: Allow insecure DoH server connections Added: 7.76.0 Category: dns tls +Protocols: DNS Multi: boolean See-also: - doh-url diff --git a/docs/cmdline-opts/doh-url.md b/docs/cmdline-opts/doh-url.md index dcc6e52f8a4f..60cf6caab016 100644 --- a/docs/cmdline-opts/doh-url.md +++ b/docs/cmdline-opts/doh-url.md @@ -6,6 +6,7 @@ Arg: Help: Resolve hostnames over DoH Added: 7.62.0 Category: dns +Protocols: DNS Multi: single See-also: - doh-insecure diff --git a/docs/cmdline-opts/follow.md b/docs/cmdline-opts/follow.md index 47d912844180..e791e36adf34 100644 --- a/docs/cmdline-opts/follow.md +++ b/docs/cmdline-opts/follow.md @@ -4,6 +4,7 @@ SPDX-License-Identifier: curl Long: follow Help: Follow redirects per spec Category: http +Protocols: HTTP Added: 8.16.0 Multi: boolean See-also: diff --git a/docs/cmdline-opts/form-escape.md b/docs/cmdline-opts/form-escape.md index 0f93fde7eb26..7cf1cb7403db 100644 --- a/docs/cmdline-opts/form-escape.md +++ b/docs/cmdline-opts/form-escape.md @@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: form-escape Help: Escape form fields using backslash -Protocols: HTTP imap smtp +Protocols: HTTP IMAP SMTP Added: 7.81.0 Category: http upload post Multi: single diff --git a/docs/cmdline-opts/ip-tos.md b/docs/cmdline-opts/ip-tos.md index 3d6473f31282..f5ef589e2354 100644 --- a/docs/cmdline-opts/ip-tos.md +++ b/docs/cmdline-opts/ip-tos.md @@ -6,7 +6,6 @@ Arg: Help: Set IP Type of Service or Traffic Class Added: 8.9.0 Category: connection -Protocols: All Multi: single See-also: - tcp-nodelay diff --git a/docs/cmdline-opts/key.md b/docs/cmdline-opts/key.md index 967119a8b50e..cc4bc73fa5b3 100644 --- a/docs/cmdline-opts/key.md +++ b/docs/cmdline-opts/key.md @@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: key Arg: -Protocols: TLS SSH +Protocols: TLS SCP SFTP Help: Private key filename Category: tls ssh Added: 7.9.3 diff --git a/docs/cmdline-opts/pass.md b/docs/cmdline-opts/pass.md index 0527334f2ab9..79c2f8738a13 100644 --- a/docs/cmdline-opts/pass.md +++ b/docs/cmdline-opts/pass.md @@ -4,7 +4,7 @@ SPDX-License-Identifier: curl Long: pass Arg: Help: Passphrase for the private key -Protocols: SSH TLS +Protocols: TLS SCP SFTP Category: ssh tls auth Added: 7.9.3 Multi: single diff --git a/docs/cmdline-opts/sasl-authzid.md b/docs/cmdline-opts/sasl-authzid.md index 4c4282d14dd3..4e92a2054152 100644 --- a/docs/cmdline-opts/sasl-authzid.md +++ b/docs/cmdline-opts/sasl-authzid.md @@ -4,6 +4,7 @@ SPDX-License-Identifier: curl Long: sasl-authzid Arg: Help: Identity for SASL PLAIN authentication +Protocols: LDAP IMAP POP3 SMTP Added: 7.66.0 Category: auth Multi: single diff --git a/docs/cmdline-opts/sasl-ir.md b/docs/cmdline-opts/sasl-ir.md index 0f759c6d1005..206bf29317a8 100644 --- a/docs/cmdline-opts/sasl-ir.md +++ b/docs/cmdline-opts/sasl-ir.md @@ -3,6 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: sasl-ir Help: Initial response in SASL authentication +Protocols: LDAP IMAP POP3 SMTP Added: 7.31.0 Category: auth Multi: boolean diff --git a/docs/cmdline-opts/socks5-gssapi-nec.md b/docs/cmdline-opts/socks5-gssapi-nec.md index eef6b2de9df1..9cd91b96150f 100644 --- a/docs/cmdline-opts/socks5-gssapi-nec.md +++ b/docs/cmdline-opts/socks5-gssapi-nec.md @@ -5,6 +5,7 @@ Long: socks5-gssapi-nec Help: Compatibility with NEC SOCKS5 server Added: 7.19.4 Category: proxy auth +Protocols: GSS/kerberos Multi: boolean See-also: - socks5 diff --git a/docs/cmdline-opts/socks5-gssapi.md b/docs/cmdline-opts/socks5-gssapi.md index e17425431b30..b8520b22cc72 100644 --- a/docs/cmdline-opts/socks5-gssapi.md +++ b/docs/cmdline-opts/socks5-gssapi.md @@ -5,6 +5,7 @@ Long: socks5-gssapi Help: Enable GSS-API auth for SOCKS5 proxies Added: 7.55.0 Category: proxy auth +Protocols: GSS/kerberos Multi: boolean See-also: - socks5 diff --git a/docs/cmdline-opts/telnet-option.md b/docs/cmdline-opts/telnet-option.md index a332b1a5cddb..ca82a4ceb8e5 100644 --- a/docs/cmdline-opts/telnet-option.md +++ b/docs/cmdline-opts/telnet-option.md @@ -6,6 +6,7 @@ Short: t Arg: Help: Set telnet option Category: telnet +Protocols: TELNET Added: 7.7 Multi: append See-also: diff --git a/docs/cmdline-opts/upload-flags.md b/docs/cmdline-opts/upload-flags.md index e30fb3dbdb9f..d17614876836 100644 --- a/docs/cmdline-opts/upload-flags.md +++ b/docs/cmdline-opts/upload-flags.md @@ -4,6 +4,7 @@ SPDX-License-Identifier: curl Long: upload-flags Arg: Help: IMAP upload behavior +Protocols: IMAP Category: curl output Added: 8.13.0 Multi: single diff --git a/docs/cmdline-opts/url-query.md b/docs/cmdline-opts/url-query.md index 43bf43d9325c..3953eda4c72f 100644 --- a/docs/cmdline-opts/url-query.md +++ b/docs/cmdline-opts/url-query.md @@ -4,7 +4,6 @@ SPDX-License-Identifier: curl Long: url-query Arg: Help: Add a URL query part -Protocols: all Added: 7.87.0 Category: http post upload Multi: append diff --git a/docs/cmdline-opts/vlan-priority.md b/docs/cmdline-opts/vlan-priority.md index 34dc8ce06613..c49c659e5c46 100644 --- a/docs/cmdline-opts/vlan-priority.md +++ b/docs/cmdline-opts/vlan-priority.md @@ -6,7 +6,6 @@ Arg: Help: Set VLAN priority Added: 8.9.0 Category: connection -Protocols: All Multi: single See-also: - ip-tos diff --git a/scripts/managen b/scripts/managen index 929068067099..4849fe8378db 100755 --- a/scripts/managen +++ b/scripts/managen @@ -241,8 +241,38 @@ sub overrides { } } +my %protexists = ( + 'DNS' => 1, + 'FILE' => 1, + 'FTP' => 1, + 'FTPS' => 1, + 'GSS/kerberos' => 1, + 'HTTP' => 1, + 'HTTPS' => 1, + 'IMAP' => 1, + 'IPFS' => 1, + 'LDAP' => 1, + 'MQTT' => 1, + 'POP3' => 1, + 'SCP' => 1, + 'SFTP' => 1, + 'SMTP' => 1, + 'SSL' => 2, # deprecated + 'TELNET' => 1, + 'TFTP' => 1, + 'TLS' => 1, + ); + sub protocols { - my ($manpage, $standalone, $data)=@_; + my ($f, $line, $manpage, $standalone, $data)=@_; + my @e = split(/ +/, $data); + for my $pr (@e) { + if(!$protexists{$pr}) { + + print STDERR "$f:$line:1:ERROR: unrecognized protocol: $pr\n"; + exit 2; + } + } if($standalone) { return ".SH \"PROTOCOLS\"\n$data\n"; } @@ -716,7 +746,7 @@ sub single { } my @leading; if($protocols) { - push @leading, protocols($manpage, $standalone, $protocols); + push @leading, protocols($f, $line, $manpage, $standalone, $protocols); } if($standalone) { From c9eff26c179222e7de077c0f59a6dfd9ba6dcce8 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 13:34:08 +0200 Subject: [PATCH 127/208] tool_doswin: fix to use curl socket functions Replace `WSASocketW()` with `CURL_SOCKET()`. Also replace a call to `socketclose()` with `sclose()`. According to a comment, `socketclose()` was chosen to silence test 1498 (and 2300) reporting `MEMORY FAILURE`. These reports were accurate, and were caused by calling `WSASocketW()` instead of `socket()` (now `CURL_SOCKET()`). This also fixes the curl `sclose()` call on an error branch, which is now correctly paired with a curl socket open. The mismatched open/close calls caused an issue in TrackMemory-enabled (aka `CURLDEBUG`) builds. Docs confirm that `socket()` is defaulting to overlapped I/O, matching the replaced `WSASocketW()` call: https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-socket#remarks Also: - checksrc: ban `WSASocket*()` functions. - report `SOCKERRNO` instead of `GetLastError()` for socket calls, to match the rest of the codebase. Follow-up to 9a2663322c330ff11275abafd612e9c99407a94a #17572 Closes #18633 --- scripts/checksrc.pl | 3 +++ src/tool_doswin.c | 24 +++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 0eeab72323f9..0012ccdae1ad 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -74,6 +74,9 @@ "LoadLibraryEx" => 1, "LoadLibraryExA" => 1, "LoadLibraryExW" => 1, + "WSASocket" => 1, + "WSASocketA" => 1, + "WSASocketW" => 1, "_waccess" => 1, "_access" => 1, "access" => 1, diff --git a/src/tool_doswin.c b/src/tool_doswin.c index 0450e5707ba2..29f8cecbd799 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -769,14 +769,14 @@ static DWORD WINAPI win_stdin_thread_func(void *thread_data) &clientAddrLen); if(socket_w == CURL_SOCKET_BAD) { - errorf("accept error: %08lx", GetLastError()); + errorf("accept error: %d", SOCKERRNO); goto ThreadCleanup; } - closesocket(tdata->socket_l); /* sclose here fails test 1498 */ + sclose(tdata->socket_l); tdata->socket_l = CURL_SOCKET_BAD; if(shutdown(socket_w, SD_RECEIVE) == SOCKET_ERROR) { - errorf("shutdown error: %08lx", GetLastError()); + errorf("shutdown error: %d", SOCKERRNO); goto ThreadCleanup; } for(;;) { @@ -835,11 +835,9 @@ curl_socket_t win32_stdin_read_thread(void) } /* Create the listening socket for the thread. When it starts, it will * accept our connection and begin writing STDIN data to the connection. */ - tdata->socket_l = WSASocketW(AF_INET, SOCK_STREAM, - IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); - + tdata->socket_l = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(tdata->socket_l == CURL_SOCKET_BAD) { - errorf("WSASocketW error: %08lx", GetLastError()); + errorf("socket() error: %d", SOCKERRNO); break; } @@ -850,20 +848,20 @@ curl_socket_t win32_stdin_read_thread(void) /* Bind to any available loopback port */ result = bind(tdata->socket_l, (SOCKADDR*)&selfaddr, socksize); if(result == SOCKET_ERROR) { - errorf("bind error: %08lx", GetLastError()); + errorf("bind error: %d", SOCKERRNO); break; } /* Bind to any available loopback port */ result = getsockname(tdata->socket_l, (SOCKADDR*)&selfaddr, &socksize); if(result == SOCKET_ERROR) { - errorf("getsockname error: %08lx", GetLastError()); + errorf("getsockname error: %d", SOCKERRNO); break; } result = listen(tdata->socket_l, 1); if(result == SOCKET_ERROR) { - errorf("listen error: %08lx", GetLastError()); + errorf("listen error: %d", SOCKERRNO); break; } @@ -891,7 +889,7 @@ curl_socket_t win32_stdin_read_thread(void) /* Connect to the thread and rearrange our own STDIN handles */ socket_r = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(socket_r == CURL_SOCKET_BAD) { - errorf("socket error: %08lx", GetLastError()); + errorf("socket error: %d", SOCKERRNO); break; } @@ -899,12 +897,12 @@ curl_socket_t win32_stdin_read_thread(void) setsockopt(socket_r, SOL_SOCKET, SO_DONTLINGER, 0, 0); if(connect(socket_r, (SOCKADDR*)&selfaddr, socksize) == SOCKET_ERROR) { - errorf("connect error: %08lx", GetLastError()); + errorf("connect error: %d", SOCKERRNO); break; } if(shutdown(socket_r, SD_SEND) == SOCKET_ERROR) { - errorf("shutdown error: %08lx", GetLastError()); + errorf("shutdown error: %d", SOCKERRNO); break; } From aa9fa4d68e1f0e059c3df8d01838a650136e6f6f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 21:55:30 +0200 Subject: [PATCH 128/208] rustls: fix clang-tidy warning Seen with v21.1.1, non-debug-enabled build: ``` lib/vtls/rustls.c:415:23: error: File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior [clang-analyzer-unix.Stream,-warnings-as-errors] 415 | const size_t rr = fread(buf, 1, sizeof(buf), f); | ^ ``` Ref: https://github.com/curl/curl/actions/runs/17898248031/job/50887746633?pr=18660#step:11:174 Cherry-picked from #18660 Closes #18670 --- lib/vtls/rustls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 87c23544ef4c..e081c4651ac8 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -410,7 +410,7 @@ read_file_into(const char *filename, return 0; } - while(!feof(f)) { + for(;;) { uint8_t buf[256]; const size_t rr = fread(buf, 1, sizeof(buf), f); if(rr == 0 || @@ -418,6 +418,8 @@ read_file_into(const char *filename, fclose(f); return 0; } + if(rr < sizeof(buf)) + break; } return fclose(f) == 0; From 7f5ff8f2769a0d771bbc0f5cad513cd07de79d08 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 22 Sep 2025 02:03:08 +0200 Subject: [PATCH 129/208] autotools: capitalize 'Rustls' in the log output To match the rest of the codebase. Follow-up to 548d8a842123c854ba92aac90a24c6191e2a8bd4 Cherry-picked from #18660 Closes #18671 --- configure.ac | 4 ++-- m4/curl-rustls.m4 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 1aa0c2759651..922978bfc106 100644 --- a/configure.ac +++ b/configure.ac @@ -272,8 +272,8 @@ AC_ARG_WITH(rustls,dnl AS_HELP_STRING([--with-rustls=PATH],[where to look for Rustls, PATH points to the installation root]),[ OPT_RUSTLS=$withval if test X"$withval" != Xno; then - TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }rustls" - experimental="$experimental rustls" + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }Rustls" + experimental="$experimental Rustls" fi ]) diff --git a/m4/curl-rustls.m4 b/m4/curl-rustls.m4 index 13022f3963b1..8abcc6544bc5 100644 --- a/m4/curl-rustls.m4 +++ b/m4/curl-rustls.m4 @@ -132,7 +132,7 @@ if test "x$OPT_RUSTLS" != xno; then dnl don't need any. LIBS="$SSL_LIBS $LIBS" link_pkgconfig=1 - ssl_msg="rustls" + ssl_msg="Rustls" AC_DEFINE(USE_RUSTLS, 1, [if Rustls is enabled]) USE_RUSTLS="yes" RUSTLS_ENABLED=1 @@ -176,7 +176,7 @@ if test "x$OPT_RUSTLS" != xno; then AC_DEFINE(USE_RUSTLS, 1, [if Rustls is enabled]) RUSTLS_ENABLED=1 USE_RUSTLS="yes" - ssl_msg="rustls" + ssl_msg="Rustls" test rustls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes ], AC_MSG_ERROR([--with-rustls was specified but could not find compatible Rustls.]), From 330129c836b3ff9d904d4c0083ec4d71ac2c67c6 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 19:48:22 +0200 Subject: [PATCH 130/208] GHA/linux: install zlib in all jobs by default Cherry-picked from #18660 Closes #18672 --- .github/workflows/linux.yml | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index c9f090a969e3..7aa7bc5707f4 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -74,27 +74,26 @@ jobs: matrix: build: - name: 'libressl heimdal' - install_packages: zlib1g-dev libidn2-dev libnghttp2-dev libldap-dev heimdal-dev + install_packages: libidn2-dev libnghttp2-dev libldap-dev heimdal-dev install_steps: libressl pytest codeset-test configure: LDFLAGS=-Wl,-rpath,/home/runner/libressl/lib --with-openssl=/home/runner/libressl --with-gssapi --enable-debug - name: 'libressl heimdal valgrind' - install_packages: zlib1g-dev libnghttp2-dev libldap-dev heimdal-dev valgrind + install_packages: libnghttp2-dev libldap-dev heimdal-dev valgrind install_steps: libressl generate: -DOPENSSL_ROOT_DIR=/home/runner/libressl -DCURL_USE_GSSAPI=ON -DENABLE_DEBUG=ON -DCURL_LIBCURL_VERSIONED_SYMBOLS=ON - name: 'libressl clang' - install_packages: zlib1g-dev clang + install_packages: clang install_steps: libressl configure: CC=clang LDFLAGS=-Wl,-rpath,/home/runner/libressl/lib --with-openssl=/home/runner/libressl --enable-debug - name: 'wolfssl-all' - install_packages: zlib1g-dev install_steps: wolfssl-all configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-all/lib --with-wolfssl=/home/runner/wolfssl-all --enable-ech --enable-debug - name: 'wolfssl-opensslextra valgrind' - install_packages: zlib1g-dev valgrind + install_packages: valgrind install_steps: wolfssl-opensslextra wolfssh configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --with-wolfssh=/home/runner/wolfssh --enable-ech --enable-debug @@ -133,17 +132,15 @@ jobs: -DCURL_COMPLETION_FISH=ON -DCURL_COMPLETION_ZSH=ON - name: 'awslc' - install_packages: zlib1g-dev install_steps: awslc pytest configure: LDFLAGS=-Wl,-rpath,/home/runner/awslc/lib --with-openssl=/home/runner/awslc --enable-ech - name: 'awslc' - install_packages: zlib1g-dev libidn2-dev + install_packages: libidn2-dev install_steps: awslc generate: -DOPENSSL_ROOT_DIR=/home/runner/awslc -DUSE_ECH=ON -DCMAKE_UNITY_BUILD=OFF - name: 'boringssl' - install_packages: zlib1g-dev install_steps: boringssl pytest generate: -DOPENSSL_ROOT_DIR=/home/runner/boringssl -DUSE_ECH=ON @@ -152,32 +149,30 @@ jobs: configure: --with-openssl --enable-debug --disable-unity - name: 'openssl libssh2 sync-resolver valgrind' - install_packages: zlib1g-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev valgrind + install_packages: libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev valgrind generate: -DENABLE_DEBUG=ON -DENABLE_THREADED_RESOLVER=OFF -DCURL_USE_LIBSSH2=ON - name: 'openssl' - install_packages: zlib1g-dev install_steps: pytest configure: CFLAGS=-std=gnu89 --with-openssl --enable-debug - name: 'openssl arm' - install_packages: zlib1g-dev install_steps: pytest configure: CFLAGS=-std=gnu89 --with-openssl --enable-debug image: 'ubuntu-24.04-arm' - name: 'openssl -O3 libssh valgrind' - install_packages: zlib1g-dev libssh-dev valgrind + install_packages: libssh-dev valgrind CFLAGS: -O3 generate: -DENABLE_DEBUG=ON -DCURL_USE_LIBSSH=ON -DCMAKE_UNITY_BUILD_BATCH_SIZE=50 - name: 'openssl clang krb5 openldap static' install_steps: openldap-static - install_packages: zlib1g-dev libidn2-dev libkrb5-dev clang libssl-dev + install_packages: libidn2-dev libkrb5-dev clang libssl-dev configure: CC=clang --disable-shared --with-openssl --with-gssapi --enable-debug --disable-docs --disable-manual --with-ldap=/home/runner/openldap-static --with-ldap-lib=ldap --with-lber-lib=lber - name: 'openssl clang krb5 LTO' - install_packages: zlib1g-dev libkrb5-dev clang + install_packages: libkrb5-dev clang install_steps: skiprun CC: clang generate: -DCURL_USE_OPENSSL=ON -DCURL_USE_GSSAPI=ON -DENABLE_DEBUG=ON -DCURL_LTO=ON @@ -195,13 +190,13 @@ jobs: --disable-tftp --disable-ftp --disable-file --disable-smb - name: 'openssl torture !FTP' - install_packages: zlib1g-dev libnghttp2-dev libssh2-1-dev libc-ares-dev + install_packages: libnghttp2-dev libssh2-1-dev libc-ares-dev generate: -DCURL_USE_OPENSSL=ON -DENABLE_DEBUG=ON -DENABLE_ARES=ON tflags: -t --shallow=25 !FTP torture: true - name: 'openssl torture FTP' - install_packages: zlib1g-dev libnghttp2-dev libssh2-1-dev libc-ares-dev + install_packages: libnghttp2-dev libssh2-1-dev libc-ares-dev generate: -DCURL_USE_OPENSSL=ON -DENABLE_DEBUG=ON -DENABLE_ARES=ON tflags: -t --shallow=20 FTP torture: true @@ -220,7 +215,7 @@ jobs: configure: --without-ssl --enable-debug --disable-http --disable-smtp --disable-imap --disable-unity - name: 'clang-tidy' - install_packages: clang-tidy zlib1g-dev libssl-dev libkrb5-dev + install_packages: clang-tidy libkrb5-dev install_steps: skipall wolfssl-opensslextra wolfssh configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --with-wolfssh=/home/runner/wolfssh --with-openssl --enable-ech --with-gssapi --enable-ssls-export make-custom-target: tidy @@ -234,7 +229,7 @@ jobs: make-prefix: scan-build --status-bugs - name: 'address-sanitizer' - install_packages: zlib1g-dev libssh2-1-dev clang libssl-dev libubsan1 libasan8 libtsan2 + install_packages: libssh2-1-dev clang libssl-dev libubsan1 libasan8 libtsan2 install_steps: pytest randcurl CFLAGS: -fsanitize=address,undefined,signed-integer-overflow -fno-sanitize-recover=undefined,integer -Wformat -Werror=format-security -Werror=array-bounds -g LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer @@ -242,7 +237,7 @@ jobs: configure: CC=clang --with-openssl --enable-debug - name: 'thread-sanitizer' - install_packages: zlib1g-dev clang libtsan2 + install_packages: clang libtsan2 install_steps: pytest openssl-tsan CFLAGS: -fsanitize=thread -g LDFLAGS: -fsanitize=thread @@ -278,7 +273,7 @@ jobs: configure: --with-rustls --enable-ech --enable-debug - name: 'IntelC openssl' - install_packages: zlib1g-dev libssl-dev + install_packages: libssl-dev install_steps: intel configure: CC=icc --enable-debug --with-openssl @@ -311,7 +306,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install \ libtool autoconf automake pkgconf \ - libpsl-dev libbrotli-dev libzstd-dev \ + libpsl-dev zlib1g-dev libbrotli-dev libzstd-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} python3 -m venv ~/venv From cd20f7b6532198162ddd5bfa816a284c1ad66a7e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 22 Sep 2025 11:27:10 +0200 Subject: [PATCH 131/208] libssh: drop two unused assigments Reported in macOS clang-tidy v21.1.1 build, after enabling libssh in it: ``` lib/vssh/libssh.c lib/vssh/libssh.c:1342:9: error: Value stored to 'to_t' is never read [clang-analyzer-deadcode.DeadStores,-warnings-as-errors] 1342 | to_t = STRE_OK; | ^ lib/vssh/libssh.c:1342:9: note: Value stored to 'to_t' is never read lib/vssh/libssh.c:1349:9: error: Value stored to 'from_t' is never read [clang-analyzer-deadcode.DeadStores,-warnings-as-errors] 1349 | from_t = STRE_OK; | ^ lib/vssh/libssh.c:1349:9: note: Value stored to 'from_t' is never read 2 warnings generated. ``` Ref: https://github.com/curl/curl/actions/runs/17909917954/job/50918955923?pr=18660#step:11:182 Cherry-picked from #18660 Closes #18684 --- lib/vssh/libssh.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index cb2e8cde4d43..576ac3b0c042 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1339,14 +1339,12 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, if((to_t == STRE_NO_NUM) || (to >= size)) { to = size - 1; - to_t = STRE_OK; } if(from_t == STRE_NO_NUM) { /* from is relative to end of file */ from = size - to; to = size - 1; - from_t = STRE_OK; } if(from > size) { failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" From d75785c7dea214d12525beb659694d3fcc483731 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 11:43:59 +0200 Subject: [PATCH 132/208] GHA: enable more options in static analyzer jobs This is an effort to pass more code through clang-tidt and scan-build static analyzers. Following CodeQL Linux jobs. GHA/codeql: - also build with libssh. - disable verbose output in build steps. GHA/linux: - enable more build options for the clang-tidy and scan-build jobs: libidn2, nghttp2, ldap, kerberos, rtmp, gnutls, gsasl, rustls, mbedtls, wolfssl Use Linuxbrew where necessary. - also enable ECH, gssapi in the scan-build job. - fix 'scanbuild' to be 'scan-build' in the job name. GHA/macos: - build with Rustls in the clang-tidy job. - add a new clang-tidy job to test HTTP/3 (with openssl + ngtcp2). - build with libssh in one of the clang-tidy jobs. - build with LibreSSL in the MultiSSL clang-tidy job. - build with heimdal and kerberos in the clang-tidy jobs respectively. - build with OpenLDAP in one clang-tidy job. - add support for `skipall`, `skiprun` job options, and use it. Closes #18660 --- .github/workflows/codeql.yml | 17 +++++++++-------- .github/workflows/linux.yml | 31 +++++++++++++++++++++++-------- .github/workflows/macos.yml | 34 ++++++++++++++++++++++++++-------- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 808ee0b63a91..97b0ddd42c5c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -75,7 +75,7 @@ jobs: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev \ + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libssh-dev \ libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi @@ -108,19 +108,20 @@ jobs: cmake -B _bld1 -G Ninja -DENABLE_DEBUG=ON \ -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DUSE_ECH=ON -DENABLE_ARES=ON - cmake --build _bld1 --verbose - cmake --build _bld1 --verbose --target curlinfo - cmake --build _bld1 --verbose --target servers - cmake --build _bld1 --verbose --target tunits - cmake --build _bld1 --verbose --target curl-examples-build + cmake --build _bld1 + cmake --build _bld1 --target curlinfo + cmake --build _bld1 --target servers + cmake --build _bld1 --target tunits + cmake --build _bld1 --target curl-examples-build # HTTP/3 export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix libnghttp3)/lib/pkgconfig:$(brew --prefix libngtcp2)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" cmake -B _bld2 -G Ninja \ -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DUSE_NGTCP2=ON \ + -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON \ -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON - cmake --build _bld2 --verbose - cmake --build _bld2 --verbose --target servers + cmake --build _bld2 + cmake --build _bld2 --target servers _bld1/src/curl --disable --version _bld2/src/curl --disable --version diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 7aa7bc5707f4..969b460d1dd4 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -215,18 +215,31 @@ jobs: configure: --without-ssl --enable-debug --disable-http --disable-smtp --disable-imap --disable-unity - name: 'clang-tidy' - install_packages: clang-tidy libkrb5-dev - install_steps: skipall wolfssl-opensslextra wolfssh - configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --with-wolfssh=/home/runner/wolfssh --with-openssl --enable-ech --with-gssapi --enable-ssls-export + install_packages: clang-tidy libssl-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev libkrb5-dev librtmp-dev libgnutls28-dev + install_steps: skipall mbedtls rustls wolfssl-opensslextra + install_steps_brew: gsasl make-custom-target: tidy - - - name: 'scanbuild' - install_packages: clang-tools clang libssl-dev libssh2-1-dev - install_steps: skipall - configure: --with-openssl --enable-debug --with-libssh2 --disable-unity + PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/opt/gsasl/lib/pkgconfig + LDFLAGS: -Wl,-rpath,/home/runner/wolfssl-opensslextra/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/gsasl/lib + configure: >- + --with-wolfssl=/home/runner/wolfssl-opensslextra --with-openssl --with-rustls --with-mbedtls=/home/runner/mbedtls --with-gnutls --with-libgsasl + --with-librtmp --with-libssh2 --with-libidn2 + --enable-ech --with-gssapi --enable-ssls-export + + - name: 'scan-build' + install_packages: clang-tools clang libssl-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev libkrb5-dev librtmp-dev libgnutls28-dev + install_steps: skipall mbedtls rustls wolfssl-opensslextra + install_steps_brew: gsasl CC: clang configure-prefix: scan-build make-prefix: scan-build --status-bugs + PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/opt/gsasl/lib/pkgconfig + LDFLAGS: -Wl,-rpath,/home/runner/wolfssl-opensslextra/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/gsasl/lib + configure: >- + --with-wolfssl=/home/runner/wolfssl-opensslextra --with-openssl --with-rustls --with-mbedtls=/home/runner/mbedtls --with-gnutls --with-libgsasl + --with-librtmp --with-libssh2 --with-libidn2 + --enable-ech --with-gssapi --enable-ssls-export + --disable-debug --disable-unity - name: 'address-sanitizer' install_packages: libssh2-1-dev clang libssl-dev libubsan1 libasan8 libtsan2 @@ -296,6 +309,7 @@ jobs: - name: 'install prereqs' if: ${{ matrix.build.container == null && !contains(matrix.build.name, 'i686') }} env: + INSTALL_PACKAGES_BREW: '${{ matrix.build.install_steps_brew }}' INSTALL_PACKAGES: >- ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'stunnel4' || '' }} ${{ contains(matrix.build.install_steps, 'pytest') && 'apache2 apache2-dev libnghttp2-dev vsftpd dante-server' || '' }} @@ -309,6 +323,7 @@ jobs: libpsl-dev zlib1g-dev libbrotli-dev libzstd-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} + [ -n "${INSTALL_PACKAGES_BREW}" ] && /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} python3 -m venv ~/venv - name: 'install prereqs' diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index be8565303eb8..0fd9d20f5b38 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -281,10 +281,27 @@ jobs: generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_NGTCP2=ON - name: 'MultiSSL AppleIDN clang-tidy +examples' compiler: clang - install: llvm brotli zstd gnutls nettle mbedtls gsasl rtmpdump fish - install_steps: clang-tidy - generate: -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_DEFAULT_SSL_BACKEND=openssl -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DENABLE_ARES=ON -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_SSLS_EXPORT=ON -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy -DCURL_COMPLETION_FISH=ON -DCURL_COMPLETION_ZSH=ON + install: llvm brotli zstd gnutls nettle libressl krb5 mbedtls gsasl rustls-ffi rtmpdump libssh fish + install_steps: clang-tidy skiprun chkprefill: _chkprefill + generate: >- + -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/libressl -DCURL_DEFAULT_SSL_BACKEND=openssl + -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DENABLE_ARES=ON -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON + -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON -DUSE_APPLE_IDN=ON -DUSE_SSLS_EXPORT=ON + -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5 + -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy + -DCURL_COMPLETION_FISH=ON -DCURL_COMPLETION_ZSH=ON + + - name: 'HTTP/3 clang-tidy' + compiler: clang + install: llvm brotli zstd libnghttp3 libngtcp2 openldap heimdal + install_steps: clang-tidy skipall + generate: >- + -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DUSE_NGTCP2=ON + -DLDAP_INCLUDE_DIR=/opt/homebrew/opt/openldap/include -DLDAP_LIBRARY=/opt/homebrew/opt/openldap/lib/libldap.dylib -DLDAP_LBER_LIBRARY=/opt/homebrew/opt/openldap/lib/liblber.dylib + -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/heimdal + -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy + - name: 'quictls +static libssh +examples' install: quictls libssh generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/quictls -DBUILD_STATIC_LIBS=ON -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON @@ -340,7 +357,7 @@ jobs: env: INSTALL_PACKAGES: >- ${{ matrix.build.generate && 'ninja' || 'automake libtool' }} - ${{ !contains(matrix.build.install_steps, 'clang-tidy') && 'nghttp2 stunnel' || '' }} + ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'nghttp2 stunnel' || '' }} ${{ contains(matrix.build.install_steps, 'pytest') && 'caddy httpd vsftpd' || '' }} run: | @@ -459,6 +476,7 @@ jobs: fi - name: 'build tests' + if: ${{ !contains(matrix.build.install_steps, 'skipall') }} run: | if [ "${MATRIX_BUILD}" = 'cmake' ]; then cmake --build bld --verbose --target testdeps @@ -467,14 +485,14 @@ jobs: fi - name: 'install test prereqs' - if: ${{ !contains(matrix.build.install_steps, 'clang-tidy') }} + if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} run: | python3 -m venv ~/venv source ~/venv/bin/activate python3 -m pip install -r tests/requirements.txt - name: 'run tests' - if: ${{ !contains(matrix.build.install_steps, 'clang-tidy') }} + if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} timeout-minutes: ${{ contains(matrix.build.install_steps, 'torture') && 20 || 10 }} env: TEST_TARGET: ${{ contains(matrix.build.install_steps, 'torture') && 'test-torture' || 'test-ci' }} @@ -496,13 +514,13 @@ jobs: fi - name: 'install pytest prereqs' - if: ${{ !contains(matrix.build.install_steps, 'clang-tidy') && contains(matrix.build.install_steps, 'pytest') }} + if: ${{ contains(matrix.build.install_steps, 'pytest') }} run: | source ~/venv/bin/activate python3 -m pip install -r tests/http/requirements.txt - name: 'run pytest' - if: ${{ !contains(matrix.build.install_steps, 'clang-tidy') && contains(matrix.build.install_steps, 'pytest') }} + if: ${{ contains(matrix.build.install_steps, 'pytest') }} env: PYTEST_ADDOPTS: '--color=yes' PYTEST_XDIST_AUTO_NUM_WORKERS: 4 From f833d5d1fb0cabaaf646e4c630a2cf7b80f55d0f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 22 Sep 2025 18:02:49 +0200 Subject: [PATCH 133/208] cmake: use modern alternatives for `get_filename_component()` - use `cmake_path()` to query filenames, with CMake 3.20 or upper. https://cmake.org/cmake/help/v4.1/command/cmake_path.html#query - use `cmake_host_system_information()` to query the registry, with CMake 3.24 or upper. https://cmake.org/cmake/help/v4.1/command/cmake_host_system_information.html#query-windows-registry Replacing the undocumented method. - also quote the value passed to `get_filename_component()` where missing. (Could not cause an actual issue as used in the code.) Closes #18688 --- CMake/FindGSS.cmake | 15 ++++++++++++--- CMake/FindNGTCP2.cmake | 6 +++++- CMakeLists.txt | 9 +++++++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 9000445acb3f..172259e28253 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -230,7 +230,11 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr if(GSS_FLAVOUR) set(_gss_libdir_suffixes "") set(_gss_libdir_hints ${_gss_root_hints}) - get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _gss_INCLUDE_DIRS PARENT_PATH _gss_calculated_potential_root) + else() + get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY) + endif() list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root}) if(WIN32) @@ -323,8 +327,13 @@ if(GSS_FLAVOUR) set(GSS_VERSION "Heimdal Unknown") endif() elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT") - get_filename_component(_mit_version "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME - CACHE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) + cmake_host_system_information(RESULT _mit_version QUERY WINDOWS_REGISTRY + "HKLM/SOFTWARE/MIT/Kerberos/SDK/CurrentVersion" VALUE "VersionString") + else() + get_filename_component(_mit_version + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE) + endif() if(WIN32 AND _mit_version) set(GSS_VERSION "${_mit_version}") else() diff --git a/CMake/FindNGTCP2.cmake b/CMake/FindNGTCP2.cmake index 700017f859f7..eb4358ef00a7 100644 --- a/CMake/FindNGTCP2.cmake +++ b/CMake/FindNGTCP2.cmake @@ -104,7 +104,11 @@ else() endif() if(_ngtcp2_crypto_backend) - get_filename_component(_ngtcp2_library_dir "${NGTCP2_LIBRARY}" DIRECTORY) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET NGTCP2_LIBRARY PARENT_PATH _ngtcp2_library_dir) + else() + get_filename_component(_ngtcp2_library_dir "${NGTCP2_LIBRARY}" DIRECTORY) + endif() find_library(${_crypto_library_upper}_LIBRARY NAMES ${_crypto_library_lower} HINTS ${_ngtcp2_library_dir}) if(${_crypto_library_upper}_LIBRARY) diff --git a/CMakeLists.txt b/CMakeLists.txt index 083c2f37b9c0..f817b61a81e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2339,8 +2339,13 @@ if(NOT CURL_DISABLE_INSTALL) elseif(_lib MATCHES "/") # This gets a bit more complex, because we want to specify the # directory separately, and only once per directory - get_filename_component(_libdir ${_lib} DIRECTORY) - get_filename_component(_libname ${_lib} NAME_WE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _lib PARENT_PATH _libdir) + cmake_path(GET _lib STEM _libname) + else() + get_filename_component(_libdir "${_lib}" DIRECTORY) + get_filename_component(_libname "${_lib}" NAME_WE) + endif() if(_libname MATCHES "^lib") if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) cmake_path(SET _libdir NORMALIZE "${_libdir}") From 051839eb8fcac5ed384e9c3911cb2511119c2c8a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 22 Sep 2025 23:58:41 +0200 Subject: [PATCH 134/208] tidy-up: URLs Closes #18689 --- docs/BINDINGS.md | 6 +++--- docs/BUG-BOUNTY.md | 4 ++-- docs/ECH.md | 4 ++-- docs/HTTP-COOKIES.md | 2 +- docs/HTTPSRR.md | 2 +- docs/INSTALL.md | 9 +++++---- docs/RUSTLS.md | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/BINDINGS.md b/docs/BINDINGS.md index 8bba1d9c9a8d..a72482cf8dfd 100644 --- a/docs/BINDINGS.md +++ b/docs/BINDINGS.md @@ -22,7 +22,7 @@ libcurl bindings [Basic](https://scriptbasic.com/) ScriptBasic bindings written by Peter Verhas -C++: [curlpp](https://github.com/jpbarrette/curlpp/) Written by Jean-Philippe Barrette-LaPierre, +C++: [curlpp](https://github.com/jpbarrette/curlpp) Written by Jean-Philippe Barrette-LaPierre, [curlcpp](https://github.com/JosephP91/curlcpp) by Giuseppe Persico and [C++ Requests](https://github.com/libcpr/cpr) by Huu Nguyen @@ -75,7 +75,7 @@ Go: [go-curl](https://github.com/andelf/go-curl) by ShuYu Wang Lua: [luacurl](https://web.archive.org/web/20201205052437/luacurl.luaforge.net/) by Alexander Marinov, [Lua-cURL](https://github.com/Lua-cURL) by Jürgen Hötzel -[Mono](https://web.archive.org/web/20070606064500/https://forge.novell.com/modules/xfmod/project/?libcurl-mono) Written by Jeffrey Phillips +[Mono](https://web.archive.org/web/20070606064500/forge.novell.com/modules/xfmod/project/?libcurl-mono) Written by Jeffrey Phillips [.NET](https://sourceforge.net/projects/libcurl-net/) libcurl-net by Jeffrey Phillips @@ -121,7 +121,7 @@ Ruby: [curb](https://github.com/taf2/curb) written by Ross Bamford, [Rust](https://github.com/alexcrichton/curl-rust) curl-rust - by Carl Lerche -[Scheme](https://www.metapaper.net/lisovsky/web/curl/) Bigloo binding by Kirill Lisovsky +[Scheme](https://metapaper.net/lisovsky/web/curl/) Bigloo binding by Kirill Lisovsky [Scilab](https://help.scilab.org/docs/current/fr_FR/getURL.html) binding by Sylvestre Ledru diff --git a/docs/BUG-BOUNTY.md b/docs/BUG-BOUNTY.md index 6933c61b3470..d75ea28e0248 100644 --- a/docs/BUG-BOUNTY.md +++ b/docs/BUG-BOUNTY.md @@ -7,8 +7,8 @@ SPDX-License-Identifier: curl # The curl bug bounty The curl project runs a bug bounty program in association with -[HackerOne](https://www.hackerone.com) and the [Internet Bug -Bounty](https://internetbugbounty.org). +[HackerOne](https://www.hackerone.com/) and the [Internet Bug +Bounty](https://internetbugbounty.org/). ## How does it work? diff --git a/docs/ECH.md b/docs/ECH.md index 969bbfa27f54..712bf2d774f0 100644 --- a/docs/ECH.md +++ b/docs/ECH.md @@ -375,8 +375,8 @@ There are some known issues with the ECH implementation in wolfSSL: - The main issue is that the client currently handles HelloRetryRequest incorrectly. [HRR issue](https://github.com/wolfSSL/wolfssl/issues/6802).) The HRR issue means that the client does not work for - [this ECH test web site](https://tls-ech.dev) and any other similarly configured - sites. + [this ECH test web site](https://tls-ech.dev/) and any other similarly + configured sites. - There is also an issue related to so-called middlebox compatibility mode. [middlebox compatibility issue](https://github.com/wolfSSL/wolfssl/issues/6774) diff --git a/docs/HTTP-COOKIES.md b/docs/HTTP-COOKIES.md index 62905dbc6c19..41faecdcb9ec 100644 --- a/docs/HTTP-COOKIES.md +++ b/docs/HTTP-COOKIES.md @@ -23,7 +23,7 @@ SPDX-License-Identifier: curl For a long time, the only spec explaining how to use cookies was the original [Netscape spec from 1994](https://curl.se/rfc/cookie_spec.html). - In 2011, [RFC 6265](https://www.ietf.org/rfc/rfc6265.txt) was finally + In 2011, [RFC 6265](https://datatracker.ietf.org/doc/html/rfc6265) was finally published and details how cookies work within HTTP. In 2016, an update which added support for prefixes was [proposed](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-prefixes-00), diff --git a/docs/HTTPSRR.md b/docs/HTTPSRR.md index 22184a253e68..7e828063481e 100644 --- a/docs/HTTPSRR.md +++ b/docs/HTTPSRR.md @@ -6,7 +6,7 @@ SPDX-License-Identifier: curl # HTTPS RR -[RFC 9460](https://www.rfc-editor.org/rfc/rfc9460.html) documents the HTTPS +[RFC 9460](https://datatracker.ietf.org/doc/html/rfc9460) documents the HTTPS DNS Resource Record. curl features **experimental** support for HTTPS RR. diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 3972d242399f..ff0a36d3658c 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -15,7 +15,8 @@ libcurl from [source code](https://curl.se/download.html). ## Building using vcpkg -You can download and install curl and libcurl using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: +You can download and install curl and libcurl using +the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: git clone https://github.com/Microsoft/vcpkg.git cd vcpkg @@ -30,8 +31,8 @@ or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. ## Building from git If you get your code off a git repository instead of a release tarball, see -the [GIT-INFO.md](https://github.com/curl/curl/blob/master/GIT-INFO.md) file in the root directory for specific instructions on how -to proceed. +the [GIT-INFO.md](https://github.com/curl/curl/blob/master/GIT-INFO.md) file in +the root directory for specific instructions on how to proceed. # Unix @@ -217,7 +218,7 @@ executable in `/bin/` or you see the configure fail toward the end. Download the setup installer from [`cygwin`](https://cygwin.com/) to begin. Additional `cygwin` packages are needed for the install. For more on installing packages visit -[`cygwin setup`](https://www.cygwin.com/faq/faq.html#faq.setup.cli). +[`cygwin setup`](https://cygwin.com/faq/faq.html#faq.setup.cli). Either run setup-x86_64.exe, then search and select packages individually, or try: diff --git a/docs/RUSTLS.md b/docs/RUSTLS.md index e46e1d802516..4f904a97e082 100644 --- a/docs/RUSTLS.md +++ b/docs/RUSTLS.md @@ -8,7 +8,7 @@ SPDX-License-Identifier: curl [Rustls is a TLS backend written in Rust](https://docs.rs/rustls/). curl can be built to use it as an alternative to OpenSSL or other TLS backends. We use -the [rustls-ffi C bindings](https://github.com/rustls/rustls-ffi/). This +the [rustls-ffi C bindings](https://github.com/rustls/rustls-ffi). This version of curl is compatible with `rustls-ffi` v0.15.x. ## Getting rustls-ffi From 71fc11e6bbf530b90bf6e93a02cb32bdaecc933b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 11:19:18 +0200 Subject: [PATCH 135/208] GHA/codeql: build `units` on Linux Closes #18695 --- .github/workflows/codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 97b0ddd42c5c..8cc7e9f48c2c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -112,6 +112,7 @@ jobs: cmake --build _bld1 --target curlinfo cmake --build _bld1 --target servers cmake --build _bld1 --target tunits + cmake --build _bld1 --target units cmake --build _bld1 --target curl-examples-build # HTTP/3 From b326293619996ff88f965cc3baf90cee2038ba36 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 11:50:23 +0200 Subject: [PATCH 136/208] GHA/linux: fix address sanitizer error output Same issue as seen earlier in the tsan job. Fix it the same way, by switching to cmake to avoid autotools' libtool confusing the analyzer. Ref: 2a46df31fdb91851895bc46d81f0065e6cafc80b #18274 Configuration remains identical. I removed libssh2 from the installed packages, because it was unused before, but cmake enabled it by default and libssh2 has memory leaks: Ref: https://github.com/curl/curl/actions/runs/17941312820/job/51018425159 Fixing: ``` /usr/bin/llvm-symbolizer-18: /home/runner/work/curl/curl/bld/lib/.libs/libcurl.so.4: no version information available (required by /usr/bin/llvm-symbolizer-18) /usr/bin/llvm-symbolizer-18: symbol lookup error: /home/runner/work/curl/curl/bld/lib/.libs/libcurl.so.4: undefined symbol: __asan_option_detect_stack_use_after_return ==33900==WARNING: Can't read from symbolizer at fd 3 [..] ==33900==WARNING: Can't write to symbolizer at fd 6 ==33900==WARNING: Failed to use and restart external symbolizer ``` Ref: https://github.com/curl/curl/actions/runs/17939949191/job/51013953675?pr=18693 Cherry-picked from #18693 Closes #18696 --- .github/workflows/linux.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 969b460d1dd4..4badcad40773 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -242,12 +242,12 @@ jobs: --disable-debug --disable-unity - name: 'address-sanitizer' - install_packages: libssh2-1-dev clang libssl-dev libubsan1 libasan8 libtsan2 + install_packages: clang libssl-dev libubsan1 libasan8 libtsan2 install_steps: pytest randcurl CFLAGS: -fsanitize=address,undefined,signed-integer-overflow -fno-sanitize-recover=undefined,integer -Wformat -Werror=format-security -Werror=array-bounds -g - LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer - LIBS: -ldl -lubsan - configure: CC=clang --with-openssl --enable-debug + LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer -ldl -lubsan + CC: clang + generate: -DENABLE_DEBUG=ON - name: 'thread-sanitizer' install_packages: clang libtsan2 From 67de9924eb9dfcff009271b1fe9c901fc8a52807 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 12:47:45 +0200 Subject: [PATCH 137/208] GHA/linux: enable libidn2 and libssh in asan job Closes #18697 --- .github/workflows/linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 4badcad40773..dbdccf61ffd7 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -242,12 +242,12 @@ jobs: --disable-debug --disable-unity - name: 'address-sanitizer' - install_packages: clang libssl-dev libubsan1 libasan8 libtsan2 + install_packages: clang libssl-dev libssh-dev libidn2-dev libnghttp2-dev libubsan1 libasan8 libtsan2 install_steps: pytest randcurl CFLAGS: -fsanitize=address,undefined,signed-integer-overflow -fno-sanitize-recover=undefined,integer -Wformat -Werror=format-security -Werror=array-bounds -g LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer -ldl -lubsan CC: clang - generate: -DENABLE_DEBUG=ON + generate: -DENABLE_DEBUG=ON -DCURL_USE_LIBSSH=ON - name: 'thread-sanitizer' install_packages: clang libtsan2 From 1acdf3bd64b6344ff818621155acf4cf5c3d1f50 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 15:45:49 +0200 Subject: [PATCH 138/208] GHA/macos: add macos-26, llvm20, gcc15, drop macos-14, gcc14 Number of combo jobs down to 22 from 24. Also: - update the version matrix. - update exclusion matrix. - include verbose compiler configuration dump. It makes the Apple-included, default `-I/usr/local/include` visible. Ref: #18683 Closes #18698 --- .github/workflows/macos.yml | 45 ++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 0fd9d20f5b38..0eb8f7e8423e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -104,6 +104,7 @@ jobs: xcodebuild -sdk -version | grep '^Path:' || true xcrun --sdk iphoneos --show-sdk-path 2>/dev/null || true xcrun --sdk iphoneos --show-sdk-version || true + echo '::group::compiler defaults'; echo 'int main(void) {}' | "${CC}" -v -x c -; echo '::endgroup::' echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' echo '::group::brew packages installed'; ls -l /opt/homebrew/opt; echo '::endgroup::' @@ -555,18 +556,24 @@ jobs: strategy: fail-fast: false matrix: - compiler: [gcc-12, gcc-13, gcc-14, llvm@15, llvm@18, clang] + # Sources: + # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-arm64-Readme.md + # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md + # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md + # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md + compiler: [gcc-12, gcc-13, gcc-15, llvm@15, llvm@18, llvm@20, clang] # Xcode support matrix as of 2024-07, with default macOS SDK versions and OS names, years: # * = default Xcode on the runner. # macos-13: 14.1, 14.2, 14.3.1, 15.0.1, 15.1,*15.2 # macos-14: 15.0.1, 15.1, 15.2, 15.3,*15.4 - # macos-15: *16.0, 16.1 - # macOSSDK: 13.0, 13.1, 13.3, 14.0, 14.2, 14.2, 14.4, 14.5, 15.0, 15.1 - # Ventura (2022) Sonoma (2023) Sequoia (2024) + # macos-15: 16.0, 16.1, 16.2, 16.3,*16.4, 26.0 + # macos-26: 16.4 *26.0 + # macOSSDK: 13.0, 13.1, 13.3, 14.0, 14.2, 14.2, 14.4, 14.5, 15.0, 15.1, 15.2, 15.4, 15.5, 26.0 + # Ventura (2022) Sonoma (2023) Sequoia (2024) Tahoe (2025) # https://github.com/actions/runner-images/tree/main/images/macos # https://en.wikipedia.org/wiki/MacOS_version_history # TODO when dropping macos-13: replace '$(brew --prefix ...' with /opt/homebrew - image: [macos-13, macos-14, macos-15] + image: [macos-13, macos-15, macos-26] # Can skip these to reduce jobs: # 15.1 has the same default macOS SDK as 15.2 and identical test results. # 14.1, 15.4 not revealing new fallouts. @@ -582,11 +589,19 @@ jobs: - { image: macos-13, xcode: '15.4' } - { image: macos-13, xcode: '16.0' } - { image: macos-13, xcode: '16.1' } + - { image: macos-13, xcode: '16.2' } + - { image: macos-13, xcode: '16.3' } + - { image: macos-13, xcode: '16.4' } + - { image: macos-13, xcode: '26.0' } - { image: macos-14, xcode: '14.1' } - { image: macos-14, xcode: '14.2' } - { image: macos-14, xcode: '14.3.1' } - { image: macos-14, xcode: '16.0' } - { image: macos-14, xcode: '16.1' } + - { image: macos-14, xcode: '16.2' } + - { image: macos-14, xcode: '16.3' } + - { image: macos-14, xcode: '16.4' } + - { image: macos-14, xcode: '26.0' } - { image: macos-15, xcode: '14.1' } - { image: macos-15, xcode: '14.2' } - { image: macos-15, xcode: '14.3.1' } @@ -595,12 +610,31 @@ jobs: - { image: macos-15, xcode: '15.2' } - { image: macos-15, xcode: '15.3' } - { image: macos-15, xcode: '15.4' } + - { image: macos-26, xcode: '14.1' } + - { image: macos-26, xcode: '14.2' } + - { image: macos-26, xcode: '14.3.1' } + - { image: macos-26, xcode: '15.0.1' } + - { image: macos-26, xcode: '15.1' } + - { image: macos-26, xcode: '15.2' } + - { image: macos-26, xcode: '15.3' } + - { image: macos-26, xcode: '15.4' } + - { image: macos-26, xcode: '16.0' } + - { image: macos-26, xcode: '16.1' } + - { image: macos-26, xcode: '16.2' } + - { image: macos-26, xcode: '16.3' } - { image: macos-13, compiler: 'llvm@18' } + - { image: macos-13, compiler: 'llvm@20' } - { image: macos-14, compiler: 'llvm@18' } + - { image: macos-14, compiler: 'llvm@20' } - { image: macos-15, compiler: 'llvm@15' } + - { image: macos-15, compiler: 'llvm@20' } + - { image: macos-26, compiler: 'llvm@15' } + - { image: macos-26, compiler: 'llvm@18' } + - { image: macos-26, compiler: 'gcc-12' } # Reduce build combinations, by dropping less interesting ones - { compiler: gcc-13, build: cmake } - { compiler: gcc-14, build: autotools } + - { compiler: gcc-15, build: autotools } steps: - name: 'install autotools' if: ${{ matrix.build == 'autotools' }} @@ -617,6 +651,7 @@ jobs: xcrun --sdk macosx --show-sdk-path 2>/dev/null || true xcrun --sdk macosx --show-sdk-version || true ls -l /Library/Developer/CommandLineTools/SDKs || true + echo '::group::compiler defaults'; echo 'int main(void) {}' | "${CC}" -v -x c -; echo '::endgroup::' echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' echo '::group::brew packages preinstalled'; ls -l "$(brew --prefix)/opt"; echo '::endgroup::' From 135e4ec1ddd664d3274447553db71f4959331858 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 22:35:46 +0000 Subject: [PATCH 139/208] GHA: update dependency awslabs/aws-lc to v1.61.3 Closes #18690 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 3d3b35dee093..03e978565d19 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -46,7 +46,7 @@ env: # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com LIBRESSL_VERSION: 4.1.0 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.60.0 + AWSLC_VERSION: 1.61.3 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # renovate: datasource=github-tags depName=gnutls/gnutls versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index dbdccf61ffd7..7598137a9548 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -46,7 +46,7 @@ env: # renovate: datasource=github-tags depName=Mbed-TLS/mbedtls versioning=semver registryUrl=https://github.com MBEDTLS_VERSION: 3.6.4 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.60.0 + AWSLC_VERSION: 1.61.3 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # handled in renovate.json From bdbb50a63e0d713102ffb3a29fd4d3544ff7d90d Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 10:29:30 +0200 Subject: [PATCH 140/208] GHA/dist: fix number of parallel jobs on macos runner It was using the global parallel value in cmake integration tests, while on macos runners, this should be lower by one, as used in other macos jobs. Performance impact is minimal. Follow-up to fb70812437ad28b74dbdc1031e46c1d86bc9db3c #16126 Closes #18701 --- .github/workflows/distcheck.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index 9d893481bcfd..de06f5aeab7c 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -258,6 +258,7 @@ jobs: shell: ${{ contains(matrix.image, 'windows') && 'msys2 {0}' || 'bash' }} env: CC: ${{ !contains(matrix.image, 'windows') && 'clang' || '' }} + MAKEFLAGS: ${{ contains(matrix.image, 'macos') && '-j 4' || '-j 5' }} MATRIX_IMAGE: '${{ matrix.image }}' TESTOPTS: ${{ contains(matrix.image, 'macos') && '-D_CURL_PREFILL=ON' || '' }} ${{ contains(matrix.image, 'windows') && '-DCMAKE_UNITY_BUILD_BATCH_SIZE=30' || '' }} OLD_CMAKE_VERSION: 3.11.4 From cc157b49635f3d8d16f445d7af3c8152ff47ae18 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 10:16:05 +0200 Subject: [PATCH 141/208] GHA/distcheck: bump timeout for the cmake integration It may take 1.5 minutes to find the C compiler on macos with old cmake. The build is also slow due to no unity and Ninja support. ``` Wed, 24 Sep 2025 04:56:51 GMT -- Using CMake version 3.11.4 Wed, 24 Sep 2025 04:58:01 GMT -- The C compiler identification is AppleClang 17.0.0.17000013 Wed, 24 Sep 2025 04:58:02 GMT -- Check for working C compiler: /Applications/Xcode_16.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang Wed, 24 Sep 2025 04:59:33 GMT -- Check for working C compiler: /Applications/Xcode_16.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -- works Wed, 24 Sep 2025 04:59:33 GMT -- Detecting C compiler ABI info Wed, 24 Sep 2025 04:59:35 GMT -- Detecting C compiler ABI info - done ``` Ref: https://github.com/curl/curl/actions/runs/17966736478/job/51100678487?pr=18700#step:10:50 Closes #18702 --- .github/workflows/distcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index de06f5aeab7c..da65bf4bd0cf 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -252,7 +252,7 @@ jobs: cmake-integration: name: 'CM integration ${{ matrix.image }}' runs-on: ${{ matrix.image }} - timeout-minutes: 10 + timeout-minutes: 15 defaults: run: shell: ${{ contains(matrix.image, 'windows') && 'msys2 {0}' || 'bash' }} From a99d79616b5df3442dac5598303179e33163a851 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:26:19 +0000 Subject: [PATCH 142/208] GHA: update ngtcp2/nghttp3 to v1.12.0 Closes #18705 --- .github/workflows/http3-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 03e978565d19..cd2d381092d0 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -54,7 +54,7 @@ env: # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com WOLFSSL_VERSION: 5.8.2 # renovate: datasource=github-tags depName=ngtcp2/nghttp3 versioning=semver registryUrl=https://github.com - NGHTTP3_VERSION: 1.11.0 + NGHTTP3_VERSION: 1.12.0 # renovate: datasource=github-tags depName=ngtcp2/ngtcp2 versioning=semver registryUrl=https://github.com NGTCP2_VERSION: 1.15.1 # renovate: datasource=github-tags depName=nghttp2/nghttp2 versioning=semver registryUrl=https://github.com From f8f84b40ccf6e73b89f6f27e2831d6ba1c70e334 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:26:25 +0000 Subject: [PATCH 143/208] GHA: Update ngtcp2/ngtcp2 to v1.16.0 Closes #18706 --- .github/workflows/http3-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index cd2d381092d0..780320e383aa 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -56,7 +56,7 @@ env: # renovate: datasource=github-tags depName=ngtcp2/nghttp3 versioning=semver registryUrl=https://github.com NGHTTP3_VERSION: 1.12.0 # renovate: datasource=github-tags depName=ngtcp2/ngtcp2 versioning=semver registryUrl=https://github.com - NGTCP2_VERSION: 1.15.1 + NGTCP2_VERSION: 1.16.0 # renovate: datasource=github-tags depName=nghttp2/nghttp2 versioning=semver registryUrl=https://github.com NGHTTP2_VERSION: 1.67.1 # renovate: datasource=github-tags depName=cloudflare/quiche versioning=semver registryUrl=https://github.com From 976a08985a93e105cdffc1a581e8b0a7f9ebc4c8 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 23 Sep 2025 09:55:11 +0200 Subject: [PATCH 144/208] ares: fix leak in tracing When DNS tracing is enabled, a string allocated by ares was not freed. Reported-by: jmaggard10 on github Bug: https://github.com/curl/curl/pull/18251#pullrequestreview-3255785083 Closes #18691 --- lib/asyn-ares.c | 7 +++++-- lib/curl_trc.h | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 807ca5c0bd00..0a04f4cc367f 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -747,8 +747,11 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, ares->result = CURLE_OK; #if ARES_VERSION >= 0x011800 /* >= v1.24.0 */ - CURL_TRC_DNS(data, "asyn-ares: servers=%s", - ares_get_servers_csv(ares->channel)); + if(CURL_TRC_DNS_is_verbose(data)) { + char *csv = ares_get_servers_csv(ares->channel); + CURL_TRC_DNS(data, "asyn-ares: servers=%s", csv); + ares_free_string(csv); + } #endif #ifdef HAVE_CARES_GETADDRINFO diff --git a/lib/curl_trc.h b/lib/curl_trc.h index 2819abe2dd48..37a373e4a6a6 100644 --- a/lib/curl_trc.h +++ b/lib/curl_trc.h @@ -123,6 +123,8 @@ void Curl_trc_ws(struct Curl_easy *data, #define CURL_TRC_M_is_verbose(data) \ Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi) +#define CURL_TRC_DNS_is_verbose(data) \ + Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns) #if defined(CURL_HAVE_C99) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #define infof(data, ...) \ @@ -141,7 +143,7 @@ void Curl_trc_ws(struct Curl_easy *data, do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) \ Curl_trc_read(data, __VA_ARGS__); } while(0) #define CURL_TRC_DNS(data, ...) \ - do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) \ + do { if(CURL_TRC_DNS_is_verbose(data)) \ Curl_trc_dns(data, __VA_ARGS__); } while(0) #ifndef CURL_DISABLE_FTP From 7cb5e39f3682daf99d21a25c61841e1bf05ea693 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 11:08:43 +0200 Subject: [PATCH 145/208] socks_gssapi: reject too long tokens If GSS returns a token to use that is longer than 65535 bytes, it can't be transmitted since the length field is an unisgned 16 bit field and thus needs to trigger an error. Reported in Joshua's sarif data Closes #18681 --- lib/socks_gssapi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 0a7ddd5ff1dc..037515e576f6 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -195,7 +195,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(gss_token != GSS_C_NO_BUFFER) gss_release_buffer(&gss_status, &gss_recv_token); if(check_gss_err(data, gss_major_status, - gss_minor_status, "gss_init_sec_context")) { + gss_minor_status, "gss_init_sec_context") || + /* the size needs to fit in a 16 bit field */ + (gss_send_token.length > 0xffff)) { gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); From 66c7e92ae4ab824d5c838a207f742af1df6edaec Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 09:10:39 +0200 Subject: [PATCH 146/208] Revert "cf_socket_recv: don't count reading zero bytes as first byte" This reverts commit df60e8fe701e189e7629fd08b61950a0fb1b697a. The "first byte" checkpoint is not strictly the first byte received, but the sign of first traffic from the server, which a closed connection also is. Closes #18676 --- lib/cf-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 2f0429efeae6..d5add9723f0d 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1578,7 +1578,7 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *pnread = (size_t)nread; CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread); - if(!result && !ctx->got_first_byte && nread) { + if(!result && !ctx->got_first_byte) { ctx->first_byte_at = curlx_now(); ctx->got_first_byte = TRUE; } From 470611d76c118995c64d3b738f02b89b76da6c43 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 10:30:15 +0200 Subject: [PATCH 147/208] hostip: remove unnecessary leftover INT_MAX check in Curl_dnscache_prune The math already uses timediff_t so no need for the extra logic Ref: #18678 Closes #18680 --- lib/hostip.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/hostip.c b/lib/hostip.c index fd8f706e7f25..da260d713009 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -279,13 +279,9 @@ void Curl_dnscache_prune(struct Curl_easy *data) /* Remove outdated and unused entries from the hostcache */ timediff_t oldest_ms = dnscache_prune(&dnscache->entries, timeout_ms, now); - if(Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE) { - if(oldest_ms < INT_MAX) - /* prune the ones over half this age */ - timeout_ms = (int)oldest_ms / 2; - else - timeout_ms = INT_MAX/2; - } + if(Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE) + /* prune the ones over half this age */ + timeout_ms = oldest_ms / 2; else break; From acd0aa2c9d58c4aa849aa17ad6ff3f76ace02692 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 14:53:18 +0200 Subject: [PATCH 148/208] docs: fix/tidy code fences - INSTALL.md: fence code to avoid wrong rendering. Reported-by: rinsuki on github Fixes: https://github.com/curl/curl-www/issues/480 - use `sh` instead of `bash` as fence language, for less visual noise. - INSTALL.md: drop stray shebang. - ECH.md: drop indent from fenced code. - minor tidy-ups. Ref: https://curl.se/docs/install.html Closes #18707 --- docs/ECH.md | 234 ++++++++++++++++++++++++------------------------ docs/INSTALL.md | 139 +++++++++++++++------------- 2 files changed, 193 insertions(+), 180 deletions(-) diff --git a/docs/ECH.md b/docs/ECH.md index 712bf2d774f0..d39f4b2f36a2 100644 --- a/docs/ECH.md +++ b/docs/ECH.md @@ -20,31 +20,31 @@ discussion about a good path forward for ECH support in curl. To build the OpenSSL project's ECH feature branch: -```bash - cd $HOME/code - git clone https://github.com/openssl/openssl - cd openssl - git checkout feature/ech - ./config --libdir=lib --prefix=$HOME/code/openssl-local-inst - ...stuff... - make -j8 - ...more stuff... - make install_sw - ...a little bit of stuff... +```sh +cd $HOME/code +git clone https://github.com/openssl/openssl +cd openssl +git checkout feature/ech +./config --libdir=lib --prefix=$HOME/code/openssl-local-inst +...stuff... +make -j8 +...more stuff... +make install_sw +...a little bit of stuff... ``` To build curl ECH-enabled, making use of the above: -```bash - cd $HOME/code - git clone https://github.com/curl/curl - cd curl - autoreconf -fi - LDFLAGS="-Wl,-rpath,$HOME/code/openssl-local-inst/lib/" ./configure --with-ssl=$HOME/code/openssl-local-inst --enable-ech - ...lots of output... - WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL... - make - ...lots more output... +```sh +cd $HOME/code +git clone https://github.com/curl/curl +cd curl +autoreconf -fi +LDFLAGS="-Wl,-rpath,$HOME/code/openssl-local-inst/lib/" ./configure --with-ssl=$HOME/code/openssl-local-inst --enable-ech +...lots of output... +WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL... +make +...lots more output... ``` If you do not get that WARNING at the end of the ``configure`` command, then @@ -63,24 +63,24 @@ not be the best solution. curl supports using DoH for A/AAAA lookups so it was relatively easy to add retrieval of HTTPS RRs in that situation. To use ECH and DoH together: -```bash - cd $HOME/code/curl - LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech true --doh-url https://one.one.one.one/dns-query https://defo.ie/ech-check.php - ... - SSL_ECH_STATUS: success good
- ... +```sh +cd $HOME/code/curl +LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech true --doh-url https://one.one.one.one/dns-query https://defo.ie/ech-check.php +... +SSL_ECH_STATUS: success good
+... ``` The output snippet above is within the HTML for the webpage, when things work. The above works for these test sites: -```bash - https://defo.ie/ech-check.php - https://draft-13.esni.defo.ie:8413/stats - https://draft-13.esni.defo.ie:8414/stats - https://crypto.cloudflare.com/cdn-cgi/trace - https://tls-ech.dev +```sh +https://defo.ie/ech-check.php +https://draft-13.esni.defo.ie:8413/stats +https://draft-13.esni.defo.ie:8414/stats +https://crypto.cloudflare.com/cdn-cgi/trace +https://tls-ech.dev ``` The list above has 4 different server technologies, implemented by 3 different @@ -107,18 +107,18 @@ reasons. To supply the ECHConfigList on the command line, you might need a bit of cut-and-paste, e.g.: -```bash - dig +short https defo.ie - 1 . ipv4hint=213.108.108.101 ech=AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA ipv6hint=2a00:c6c0:0:116:5::10 +```sh +dig +short https defo.ie +1 . ipv4hint=213.108.108.101 ech=AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA ipv6hint=2a00:c6c0:0:116:5::10 ``` Then paste the base64 encoded ECHConfigList onto the curl command line: -```bash - LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech ecl:AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php - ... - SSL_ECH_STATUS: success good
- ... +```sh +LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech ecl:AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php +... +SSL_ECH_STATUS: success good
+... ``` The output snippet above is within the HTML for the webpage. @@ -126,11 +126,11 @@ The output snippet above is within the HTML for the webpage. If you paste in the wrong ECHConfigList (it changes hourly for ``defo.ie``) you should get an error like this: -```bash - LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php - ... - * OpenSSL/3.3.0: error:0A00054B:SSL routines::ech required - ... +```sh +LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php +... +* OpenSSL/3.3.0: error:0A00054B:SSL routines::ech required +... ``` There is a reason to want this command line option - for use before publishing @@ -141,12 +141,12 @@ If you do use a wrong ECHConfigList value, then the server might return a good value, via the ``retry_configs`` mechanism. You can see that value in the verbose output, e.g.: -```bash - LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php - ... +```sh +LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php +... * ECH: retry_configs AQD+DQA8DAAgACBvYqJy+Hgk33wh/ZLBzKSPgwxeop7gvojQzfASq7zeZQAEAAEAAQANY292ZXIuZGVmby5pZQAA/g0APEMAIAAgXkT5r4cYs8z19q5rdittyIX8gfQ3ENW4wj1fVoiJZBoABAABAAEADWNvdmVyLmRlZm8uaWUAAP4NADw2ACAAINXSE9EdXzEQIJZA7vpwCIQsWqsFohZARXChgPsnfI1kAAQAAQABAA1jb3Zlci5kZWZvLmllAAD+DQA8cQAgACASeiD5F+UoSnVoHvA2l1EifUVMFtbVZ76xwDqmMPraHQAEAAEAAQANY292ZXIuZGVmby5pZQAA * ECH: retry_configs for defo.ie from cover.defo.ie, 319 - ... +... ``` At that point, you could copy the base64 encoded value above and try again. @@ -157,11 +157,11 @@ For now, this only works for the OpenSSL and BoringSSL/AWS-LC builds. curl has various ways to configure default settings, e.g. in ``$HOME/.curlrc``, so one can set the DoH URL and enable ECH that way: -```bash - cat ~/.curlrc - doh-url=https://one.one.one.one/dns-query - silent - ech=true +```sh +cat ~/.curlrc +doh-url=https://one.one.one.one/dns-query +silent +ech=true ``` Note that when you use the system's curl command (rather than our ECH-enabled @@ -176,27 +176,27 @@ now that seems to cause a problem, so that the following line(s) are ignored. If you want to always use our OpenSSL build you can set ``LD_LIBRARY_PATH`` in the environment: -```bash - export LD_LIBRARY_PATH=$HOME/code/openssl +```sh +export LD_LIBRARY_PATH=$HOME/code/openssl ``` When you do the above, there can be a mismatch between OpenSSL versions for applications that check that. A ``git push`` for example fails so you should unset ``LD_LIBRARY_PATH`` before doing that or use a different shell. -```bash - git push - OpenSSL version mismatch. Built against 30000080, you have 30200000 - ... +```sh +git push +OpenSSL version mismatch. Built against 30000080, you have 30200000 +... ``` With all that setup as above the command line gets simpler: -```bash - ./src/curl https://defo.ie/ech-check.php - ... - SSL_ECH_STATUS: success good
- ... +```sh +./src/curl https://defo.ie/ech-check.php +... +SSL_ECH_STATUS: success good
+... ``` The ``--ech true`` option is opportunistic, so tries to do ECH but does not fail if @@ -291,17 +291,17 @@ produce spurious failures. To build with cmake, assuming our ECH-enabled OpenSSL is as before: -```bash - cd $HOME/code - git clone https://github.com/curl/curl - cd curl - mkdir build - cd build - cmake -DOPENSSL_ROOT_DIR=$HOME/code/openssl -DUSE_ECH=1 .. - ... - make - ... - [100%] Built target curl +```sh +cd $HOME/code +git clone https://github.com/curl/curl +cd curl +mkdir build +cd build +cmake -DOPENSSL_ROOT_DIR=$HOME/code/openssl -DUSE_ECH=1 .. +... +make +... +[100%] Built target curl ``` The binary produced by the cmake build does not need any ECH-specific @@ -312,27 +312,27 @@ The binary produced by the cmake build does not need any ECH-specific BoringSSL is also supported by curl and also supports ECH, so to build with that, instead of our ECH-enabled OpenSSL: -```bash - cd $HOME/code - git clone https://boringssl.googlesource.com/boringssl - cd boringssl - cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/code/boringssl/inst -DBUILD_SHARED_LIBS=1 - make - ... - make install +```sh +cd $HOME/code +git clone https://boringssl.googlesource.com/boringssl +cd boringssl +cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/code/boringssl/inst -DBUILD_SHARED_LIBS=1 +make +... +make install ``` Then: -```bash - cd $HOME/code - git clone https://github.com/curl/curl - cd curl - autoreconf -fi - LDFLAGS="-Wl,-rpath,$HOME/code/boringssl/inst/lib" ./configure --with-ssl=$HOME/code/boringssl/inst --enable-ech - ...lots of output... - WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL. Use with caution. - make +```sh +cd $HOME/code +git clone https://github.com/curl/curl +cd curl +autoreconf -fi +LDFLAGS="-Wl,-rpath,$HOME/code/boringssl/inst/lib" ./configure --with-ssl=$HOME/code/boringssl/inst --enable-ech +...lots of output... +WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL. Use with caution. +make ``` The BoringSSL/AWS-LC APIs are fairly similar to those in our ECH-enabled @@ -346,14 +346,14 @@ line variant as of now. wolfSSL also supports ECH and can be used by curl, so here's how: -```bash - cd $HOME/code - git clone https://github.com/wolfSSL/wolfssl - cd wolfssl - ./autogen.sh - ./configure --prefix=$HOME/code/wolfssl/inst --enable-ech --enable-debug --enable-opensslextra - make - make install +```sh +cd $HOME/code +git clone https://github.com/wolfSSL/wolfssl +cd wolfssl +./autogen.sh +./configure --prefix=$HOME/code/wolfssl/inst --enable-ech --enable-debug --enable-opensslextra +make +make install ``` The install prefix (``inst``) in the above causes wolfSSL to be installed there @@ -361,13 +361,13 @@ and we seem to need that for the curl configure command to work out. The ``--enable-opensslextra`` turns out (after much faffing about;-) to be important or else we get build problems with curl below. -```bash - cd $HOME/code - git clone https://github.com/curl/curl - cd curl - autoreconf -fi - ./configure --with-wolfssl=$HOME/code/wolfssl/inst --enable-ech - make +```sh +cd $HOME/code +git clone https://github.com/curl/curl +cd curl +autoreconf -fi +./configure --with-wolfssl=$HOME/code/wolfssl/inst --enable-ech +make ``` There are some known issues with the ECH implementation in wolfSSL: @@ -439,7 +439,7 @@ this for now. Just a note to self as remembering this is a nuisance: -```bash +```sh LD_LIBRARY_PATH=$HOME/code/openssl:./lib/.libs gdb ./src/.libs/curl ``` @@ -451,10 +451,10 @@ for testing. We have published instructions for such in another repository. Once you have that set up, you can start a server and then run curl against that: -```bash - cd $HOME/code/ech-dev-utils - ./scripts/echsvr.sh -d - ... +```sh +cd $HOME/code/ech-dev-utils +./scripts/echsvr.sh -d +... ``` The ``echsvr.sh`` script supports many ECH-related options. Use ``echsvr.sh -h`` @@ -462,9 +462,9 @@ for details. In another window: -```bash - cd $HOME/code/curl/ - ./src/curl -vvv --insecure --connect-to foo.example.com:8443:localhost:8443 --ech ecl:AD7+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAA== +```sh +cd $HOME/code/curl/ +./src/curl -vvv --insecure --connect-to foo.example.com:8443:localhost:8443 --ech ecl:AD7+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAA== ``` ### Automated use of ``retry_configs`` not supported so far... diff --git a/docs/INSTALL.md b/docs/INSTALL.md index ff0a36d3658c..80fcb9321613 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -275,28 +275,32 @@ If any error occurs during curl installation, try: You can use either autotools or cmake: - ./configure \ - CC=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \ - AR=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ar \ - RANLIB=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ranlib \ - WATT_ROOT=/path/to/djgpp/net/watt \ - --host=i586-pc-msdosdjgpp \ - --with-openssl=/path/to/djgpp \ - --with-zlib=/path/to/djgpp \ - --without-libpsl \ - --disable-shared - - cmake . \ - -DCMAKE_SYSTEM_NAME=DOS \ - -DCMAKE_C_COMPILER_TARGET=i586-pc-msdosdjgpp \ - -DCMAKE_C_COMPILER=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \ - -DWATT_ROOT=/path/to/djgpp/net/watt \ - -DOPENSSL_INCLUDE_DIR=/path/to/djgpp/include \ - -DOPENSSL_SSL_LIBRARY=/path/to/djgpp/lib/libssl.a \ - -DOPENSSL_CRYPTO_LIBRARY=/path/to/djgpp/lib/libcrypto.a \ - -DZLIB_INCLUDE_DIR=/path/to/djgpp/include \ - -DZLIB_LIBRARY=/path/to/djgpp/lib/libz.a \ - -DCURL_USE_LIBPSL=OFF +```sh +./configure \ + CC=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \ + AR=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ar \ + RANLIB=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ranlib \ + WATT_ROOT=/path/to/djgpp/net/watt \ + --host=i586-pc-msdosdjgpp \ + --with-openssl=/path/to/djgpp \ + --with-zlib=/path/to/djgpp \ + --without-libpsl \ + --disable-shared +``` + +```sh +cmake . \ + -DCMAKE_SYSTEM_NAME=DOS \ + -DCMAKE_C_COMPILER_TARGET=i586-pc-msdosdjgpp \ + -DCMAKE_C_COMPILER=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \ + -DWATT_ROOT=/path/to/djgpp/net/watt \ + -DOPENSSL_INCLUDE_DIR=/path/to/djgpp/include \ + -DOPENSSL_SSL_LIBRARY=/path/to/djgpp/lib/libssl.a \ + -DOPENSSL_CRYPTO_LIBRARY=/path/to/djgpp/lib/libcrypto.a \ + -DZLIB_INCLUDE_DIR=/path/to/djgpp/include \ + -DZLIB_LIBRARY=/path/to/djgpp/lib/libz.a \ + -DCURL_USE_LIBPSL=OFF +``` Notes: @@ -310,29 +314,33 @@ Notes: You can use either autotools or cmake: - ./configure \ - CC=/opt/amiga/bin/m68k-amigaos-gcc \ - AR=/opt/amiga/bin/m68k-amigaos-ar \ - RANLIB=/opt/amiga/bin/m68k-amigaos-ranlib \ - --host=m68k-amigaos \ - --with-amissl \ - CFLAGS='-O0 -msoft-float -mcrt=clib2' \ - CPPFLAGS=-I/path/to/AmiSSL/Developer/include \ - LDFLAGS=-L/path/to/AmiSSL/Developer/lib/AmigaOS3 \ - LIBS='-lnet -lm -latomic' \ - --without-libpsl \ - --disable-shared - - cmake . \ - -DAMIGA=1 \ - -DCMAKE_SYSTEM_NAME=Generic \ - -DCMAKE_C_COMPILER_TARGET=m68k-unknown-amigaos \ - -DCMAKE_C_COMPILER=/opt/amiga/bin/m68k-amigaos-gcc \ - -DCMAKE_C_FLAGS='-O0 -msoft-float -mcrt=clib2' \ - -DAMISSL_INCLUDE_DIR=/path/to/AmiSSL/Developer/include \ - -DAMISSL_STUBS_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslstubs.a \ - -DAMISSL_AUTO_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslauto.a \ - -DCURL_USE_LIBPSL=OFF +```sh +./configure \ + CC=/opt/amiga/bin/m68k-amigaos-gcc \ + AR=/opt/amiga/bin/m68k-amigaos-ar \ + RANLIB=/opt/amiga/bin/m68k-amigaos-ranlib \ + --host=m68k-amigaos \ + --with-amissl \ + CFLAGS='-O0 -msoft-float -mcrt=clib2' \ + CPPFLAGS=-I/path/to/AmiSSL/Developer/include \ + LDFLAGS=-L/path/to/AmiSSL/Developer/lib/AmigaOS3 \ + LIBS='-lnet -lm -latomic' \ + --without-libpsl \ + --disable-shared +``` + +```sh +cmake . \ + -DAMIGA=1 \ + -DCMAKE_SYSTEM_NAME=Generic \ + -DCMAKE_C_COMPILER_TARGET=m68k-unknown-amigaos \ + -DCMAKE_C_COMPILER=/opt/amiga/bin/m68k-amigaos-gcc \ + -DCMAKE_C_FLAGS='-O0 -msoft-float -mcrt=clib2' \ + -DAMISSL_INCLUDE_DIR=/path/to/AmiSSL/Developer/include \ + -DAMISSL_STUBS_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslstubs.a \ + -DAMISSL_AUTO_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslauto.a \ + -DCURL_USE_LIBPSL=OFF +``` ## Disabling Specific Protocols in Windows builds @@ -408,18 +416,22 @@ Examples to compile for `aarch64` and API level 29: with CMake, where `ANDROID_NDK_HOME` points into your NDK: - cmake . \ - -DANDROID_ABI=arm64-v8a \ - -DANDROID_PLATFORM=android-29 \ - -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \ - -DCURL_ENABLE_SSL=OFF \ - -DCURL_USE_LIBPSL=OFF +```sh +cmake . \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=android-29 \ + -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \ + -DCURL_ENABLE_SSL=OFF \ + -DCURL_USE_LIBPSL=OFF +``` with `configure`, on macOS: -```bash +```sh export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/25.1.8937393 # Point into your NDK. -export HOST_TAG=darwin-x86_64 # Same tag for Apple Silicon. Other OS values here: https://developer.android.com/ndk/guides/other_build_systems#overview +# Same tag for Apple Silicon. Other OS values here: +# https://developer.android.com/ndk/guides/other_build_systems#overview +export HOST_TAG=darwin-x86_64 export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG export AR=$TOOLCHAIN/bin/llvm-ar export AS=$TOOLCHAIN/bin/llvm-as @@ -443,8 +455,10 @@ install `libssl.a` and `libcrypto.a` to `$TOOLCHAIN/sysroot/usr/lib` and copy `include/openssl` to `$TOOLCHAIN/sysroot/usr/include`. Now you can build curl for Android using OpenSSL like this: -```bash -LIBS="-lssl -lcrypto -lc++" # For OpenSSL/BoringSSL. In general, you need to the SSL/TLS layer's transitive dependencies if you are linking statically. +```sh +# For OpenSSL/BoringSSL. In general, you need to the SSL/TLS layer's transitive +# dependencies if you are linking statically. +LIBS='-lssl -lcrypto -lc++' ./configure --host aarch64-linux-android --with-pic --disable-shared --with-openssl="$TOOLCHAIN/sysroot/usr" ``` @@ -493,9 +507,7 @@ configure with any options you need. Be sure and specify the `--host` and of cross-compiling for the IBM 405GP PowerPC processor using the toolchain on Linux. -```bash -#! /bin/sh - +```sh export PATH=$PATH:/opt/hardhat/devkit/ppc/405/bin export CPPFLAGS="-I/opt/hardhat/devkit/ppc/405/target/usr/include" export AR=ppc_405-ar @@ -505,11 +517,12 @@ export RANLIB=ppc_405-ranlib export CC=ppc_405-gcc export NM=ppc_405-nm -./configure --target=powerpc-hardhat-linux - --host=powerpc-hardhat-linux - --build=i586-pc-linux-gnu - --prefix=/opt/hardhat/devkit/ppc/405/target/usr/local - --exec-prefix=/usr/local +./configure \ + --target=powerpc-hardhat-linux + --host=powerpc-hardhat-linux + --build=i586-pc-linux-gnu + --prefix=/opt/hardhat/devkit/ppc/405/target/usr/local + --exec-prefix=/usr/local ``` The `--prefix` parameter specifies where curl gets installed. If `configure` From 22b9f77e38cda5d7721059664140b37c74ed1d3f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 17:44:47 +0200 Subject: [PATCH 149/208] GHA/curl-for-win: use `DOCKER_IMAGE_STABLE` Replacing the hard-wired stable image. After this patch, it will automatically follow upstream updates. Follow-up to https://github.com/curl/curl-for-win/commit/6870bc1b35baff03168af1d0506ec8610851a819 Follow-up to https://github.com/curl/curl-for-win/commit/5a25df253da4f68de52b14a2e612df5fc60b8aa6 Closes #18709 --- .github/workflows/curl-for-win.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/curl-for-win.yml b/.github/workflows/curl-for-win.yml index 0090c7d6e22e..e29a2a66e85d 100644 --- a/.github/workflows/curl-for-win.yml +++ b/.github/workflows/curl-for-win.yml @@ -58,17 +58,17 @@ jobs: mv curl-for-win/* . export CW_CONFIG='-main-werror-unitybatch-linux-a64-x64-gcc' export CW_REVISION="${GITHUB_SHA}" - DOCKER_IMAGE='debian:bookworm-slim' + . ./_versions.sh export CW_CCSUFFIX='-15' export CW_GCCSUFFIX='-12' sudo podman image trust set --type reject default sudo podman image trust set --type accept docker.io/library - time podman pull "${DOCKER_IMAGE}" + time podman pull "${DOCKER_IMAGE_STABLE}" podman images --digests time podman run --volume "$(pwd):$(pwd)" --workdir "$(pwd)" \ --env-file <(env | grep -a -E \ '^(CW_|GITHUB_)') \ - "${DOCKER_IMAGE}" \ + "${DOCKER_IMAGE_STABLE}" \ sh -c ./_ci-linux-debian.sh linux-musl-llvm: From b011e3fcfb06d6c0278595ee2ee297036fbe9793 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 24 Sep 2025 06:52:52 +0200 Subject: [PATCH 150/208] vssh: drop support for wolfSSH The implementation was incomplete and lesser than the other backends. No one ever reported a bug or requested enhancements for this, indicating that this backend was never used. Closes #18700 --- .circleci/config.yml | 38 - .github/scripts/cmp-config.pl | 2 - .github/workflows/linux.yml | 34 +- .github/workflows/macos.yml | 2 +- CMake/FindWolfSSH.cmake | 65 -- CMakeLists.txt | 21 +- Makefile.am | 1 - configure.ac | 31 - docs/INSTALL-CMAKE.md | 3 - docs/KNOWN_BUGS | 16 - docs/tests/FILEFORMAT.md | 1 - lib/Makefile.inc | 3 +- lib/curl_config.h.cmake | 3 - lib/curl_setup.h | 2 +- lib/url.c | 2 +- lib/version.c | 4 +- lib/vssh/ssh.h | 11 - lib/vssh/wolfssh.c | 1225 --------------------------------- packages/OS400/ccsidcurl.c | 2 +- scripts/schemetable.c | 2 +- tests/runtests.pl | 3 - 21 files changed, 13 insertions(+), 1458 deletions(-) delete mode 100644 CMake/FindWolfSSH.cmake delete mode 100644 lib/vssh/wolfssh.c diff --git a/.circleci/config.yml b/.circleci/config.yml index c67f572c527e..1603e7f7d0f0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -61,20 +61,6 @@ commands: ./configure --disable-dependency-tracking --enable-tls13 --enable-all --enable-harden --prefix=$HOME/wssl make install - install-wolfssh: - steps: - - run: - command: | - # renovate: datasource=github-tags depName=wolfSSL/wolfssh versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com - WOLFSSH_VERSION=1.4.19 - echo "Installing wolfSSH $WOLFSSH_VERSION" - curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - --location "https://github.com/wolfSSL/wolfssh/archive/v$WOLFSSH_VERSION-stable.tar.gz" | tar -xz - cd wolfssh-$WOLFSSH_VERSION-stable - ./autogen.sh - ./configure --disable-dependency-tracking --with-wolfssl=$HOME/wssl --prefix=$HOME/wssh --enable-scp --enable-sftp --disable-term --disable-examples - make install - configure: steps: - run: @@ -120,16 +106,6 @@ commands: --with-openssl --enable-ares \ || { tail -1000 config.log; false; } - configure-wolfssh: - steps: - - run: - command: | - autoreconf -fi - LDFLAGS="-Wl,-rpath,$HOME/wssh/lib" \ - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-warnings \ - --with-wolfssl=$HOME/wssl --with-wolfssh=$HOME/wssh \ - || { tail -1000 config.log; false; } - configure-cares-debug: steps: - run: @@ -171,16 +147,6 @@ jobs: - configure-openssl-no-verbose - build - wolfssh: - executor: ubuntu - steps: - - checkout - - install-deps - - install-wolfssl - - install-wolfssh - - configure-wolfssh - - build - no-proxy: executor: ubuntu steps: @@ -254,10 +220,6 @@ workflows: jobs: - no-verbose - wolfssl-wolfssh: - jobs: - - wolfssh - arm-openssl: jobs: - arm diff --git a/.github/scripts/cmp-config.pl b/.github/scripts/cmp-config.pl index 88df37b795bb..5fb8c0abdcaf 100755 --- a/.github/scripts/cmp-config.pl +++ b/.github/scripts/cmp-config.pl @@ -56,7 +56,6 @@ '#define HAVE_LIBSSH' => 1, '#define HAVE_LIBSSH2 1' => 1, '#define HAVE_LIBSSL 1' => 1, - '#define HAVE_LIBWOLFSSH' => 1, '#define HAVE_LIBZSTD 1' => 1, '#define HAVE_NGHTTP2_NGHTTP2_H 1' => 1, '#define HAVE_NGHTTP3_NGHTTP3_H 1' => 1, @@ -78,7 +77,6 @@ '#define HAVE_SYS_STAT_H 1' => 1, '#define HAVE_SYS_XATTR_H 1' => 1, '#define HAVE_UNICODE_UIDNA_H 1' => 1, - '#define HAVE_WOLFSSH_SSH_H 1' => 1, '#define HAVE_WOLFSSL_SET_QUIC_USE_LEGACY_CODEPOINT 1' => 1, '#define HAVE_ZSTD 1' => 1, '#define HAVE_ZSTD_H 1' => 1, diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 7598137a9548..20a5849d4dbd 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -41,8 +41,6 @@ env: LIBRESSL_VERSION: 4.1.0 # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com WOLFSSL_VERSION: 5.8.2 - # renovate: datasource=github-tags depName=wolfSSL/wolfssh versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com - WOLFSSH_VERSION: 1.4.19 # renovate: datasource=github-tags depName=Mbed-TLS/mbedtls versioning=semver registryUrl=https://github.com MBEDTLS_VERSION: 3.6.4 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com @@ -94,8 +92,8 @@ jobs: - name: 'wolfssl-opensslextra valgrind' install_packages: valgrind - install_steps: wolfssl-opensslextra wolfssh - configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --with-wolfssh=/home/runner/wolfssh --enable-ech --enable-debug + install_steps: wolfssl-opensslextra + configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --enable-ech --enable-debug - name: 'mbedtls valgrind' install_packages: libnghttp2-dev libidn2-dev libldap-dev valgrind @@ -186,7 +184,7 @@ jobs: --disable-dict --disable-gopher --disable-ldap --disable-telnet --disable-imap --disable-pop3 --disable-smtp --without-librtmp --disable-rtsp - --without-libssh2 --without-libssh --without-wolfssh + --without-libssh2 --without-libssh --disable-tftp --disable-ftp --disable-file --disable-smb - name: 'openssl torture !FTP' @@ -405,31 +403,10 @@ jobs: --location "https://github.com/wolfSSL/wolfssl/archive/v${WOLFSSL_VERSION}-stable.tar.gz" | tar -xz cd "wolfssl-${WOLFSSL_VERSION}-stable" ./autogen.sh - ./configure --disable-dependency-tracking --enable-tls13 --enable-harden --enable-wolfssh --enable-ech --enable-opensslextra \ + ./configure --disable-dependency-tracking --enable-tls13 --enable-harden --enable-ech --enable-opensslextra \ --disable-benchmark --disable-crypttests --disable-examples --prefix=/home/runner/wolfssl-opensslextra make install - - name: 'cache wolfssh' - if: ${{ contains(matrix.build.install_steps, 'wolfssh') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - id: cache-wolfssh - env: - cache-name: cache-wolfssh - with: - path: ~/wolfssh - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.WOLFSSH_VERSION }}-${{ env.WOLFSSL_VERSION }} - - - name: 'build wolfssh' - if: ${{ contains(matrix.build.install_steps, 'wolfssh') && steps.cache-wolfssh.outputs.cache-hit != 'true' }} - run: | - curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - --location "https://github.com/wolfSSL/wolfssh/archive/v${WOLFSSH_VERSION}-stable.tar.gz" | tar -xz - cd "wolfssh-${WOLFSSH_VERSION}-stable" - ./autogen.sh - ./configure --disable-dependency-tracking --with-wolfssl=/home/runner/wolfssl-opensslextra --enable-scp --enable-sftp --disable-term \ - --disable-examples --prefix=/home/runner/wolfssh - make install - - name: 'cache mbedtls' if: ${{ contains(matrix.build.install_steps, 'mbedtls') }} uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 @@ -691,9 +668,6 @@ jobs: TFLAGS: '${{ matrix.build.tflags }}' run: | if [ "${TEST_TARGET}" = 'test-ci' ]; then - if [[ "${MATRIX_INSTALL_STEPS}" = *'wolfssh'* ]]; then - TFLAGS+=' ~SFTP' # curl: (79) wolfssh SFTP connect error -1051 / WS_MATCH_KEY_ALGO_E / cannot match key algo with peer - fi if [[ "${MATRIX_INSTALL_PACKAGES}" = *'valgrind'* ]]; then TFLAGS+=' -j6' if [[ "${MATRIX_INSTALL_PACKAGES}" = *'heimdal-dev'* ]]; then diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 0eb8f7e8423e..ee8cec7d70bb 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -253,7 +253,7 @@ jobs: --disable-ldap --disable-pop3 --without-librtmp --disable-rtsp --disable-shared --disable-smb --disable-smtp --disable-telnet --disable-tftp --disable-unix-sockets --without-brotli --without-gssapi --without-libidn2 --without-libpsl --without-librtmp - --without-libssh2 --without-libssh --without-wolfssh + --without-libssh2 --without-libssh --without-nghttp2 --disable-ntlm --without-ssl --without-zlib --without-zstd macos-version-min: '10.15' # Catalina (2019) diff --git a/CMake/FindWolfSSH.cmake b/CMake/FindWolfSSH.cmake deleted file mode 100644 index 98de656b923a..000000000000 --- a/CMake/FindWolfSSH.cmake +++ /dev/null @@ -1,65 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) Daniel Stenberg, , 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 -# -########################################################################### -# Find the wolfSSH library -# -# Input variables: -# -# - `WOLFSSH_INCLUDE_DIR`: The wolfSSH include directory. -# - `WOLFSSH_LIBRARY`: Path to `wolfssh` library. -# -# Result variables: -# -# - `WOLFSSH_FOUND`: System has wolfSSH. -# - `WOLFSSH_INCLUDE_DIRS`: The wolfSSH include directories. -# - `WOLFSSH_LIBRARIES`: The wolfSSH library names. -# - `WOLFSSH_VERSION`: Version of wolfSSH. - -find_path(WOLFSSH_INCLUDE_DIR NAMES "wolfssh/ssh.h") -find_library(WOLFSSH_LIBRARY NAMES "wolfssh" "libwolfssh") - -unset(WOLFSSH_VERSION CACHE) -if(WOLFSSH_INCLUDE_DIR AND EXISTS "${WOLFSSH_INCLUDE_DIR}/wolfssh/version.h") - set(_version_regex "#[\t ]*define[\t ]+LIBWOLFSSH_VERSION_STRING[\t ]+\"([^\"]*)\"") - file(STRINGS "${WOLFSSH_INCLUDE_DIR}/wolfssh/version.h" _version_str REGEX "${_version_regex}") - string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}") - set(WOLFSSH_VERSION "${_version_str}") - unset(_version_regex) - unset(_version_str) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(WolfSSH - REQUIRED_VARS - WOLFSSH_INCLUDE_DIR - WOLFSSH_LIBRARY - VERSION_VAR - WOLFSSH_VERSION -) - -if(WOLFSSH_FOUND) - set(WOLFSSH_INCLUDE_DIRS ${WOLFSSH_INCLUDE_DIR}) - set(WOLFSSH_LIBRARIES ${WOLFSSH_LIBRARY}) -endif() - -mark_as_advanced(WOLFSSH_INCLUDE_DIR WOLFSSH_LIBRARY) diff --git a/CMakeLists.txt b/CMakeLists.txt index f817b61a81e9..115eaa5f3419 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1391,23 +1391,6 @@ if(NOT USE_LIBSSH2 AND CURL_USE_LIBSSH) set(USE_LIBSSH ON) endif() -# wolfSSH -option(CURL_USE_WOLFSSH "Use wolfSSH" OFF) -mark_as_advanced(CURL_USE_WOLFSSH) -set(USE_WOLFSSH OFF) -if(NOT USE_LIBSSH2 AND NOT USE_LIBSSH AND CURL_USE_WOLFSSH) - if(USE_WOLFSSL) - find_package(WolfSSH) - if(WOLFSSH_FOUND) - set(CURL_LIBS ${WOLFSSH_LIBRARIES} ${CURL_LIBS}) # keep it before TLS-crypto, compression - include_directories(SYSTEM ${WOLFSSH_INCLUDE_DIRS}) - set(USE_WOLFSSH ON) - endif() - else() - message(WARNING "wolfSSH requires wolfSSL. Skipping.") - endif() -endif() - option(CURL_USE_GSASL "Use libgsasl" OFF) mark_as_advanced(CURL_USE_GSASL) if(CURL_USE_GSASL) @@ -2144,8 +2127,8 @@ curl_add_if("SMBS" NOT CURL_DISABLE_SMB AND _ssl_enabled AND _use_curl_ntlm_core AND (SIZEOF_CURL_OFF_T GREATER 4)) curl_add_if("SMTP" NOT CURL_DISABLE_SMTP) curl_add_if("SMTPS" NOT CURL_DISABLE_SMTP AND _ssl_enabled) -curl_add_if("SCP" USE_LIBSSH2 OR USE_LIBSSH OR USE_WOLFSSH) -curl_add_if("SFTP" USE_LIBSSH2 OR USE_LIBSSH OR USE_WOLFSSH) +curl_add_if("SCP" USE_LIBSSH2 OR USE_LIBSSH) +curl_add_if("SFTP" USE_LIBSSH2 OR USE_LIBSSH) curl_add_if("IPFS" NOT CURL_DISABLE_IPFS) curl_add_if("IPNS" NOT CURL_DISABLE_IPFS) curl_add_if("RTSP" NOT CURL_DISABLE_RTSP) diff --git a/Makefile.am b/Makefile.am index fd97e61d9df3..76873854160c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,7 +50,6 @@ CMAKE_DIST = \ CMake/FindNettle.cmake \ CMake/FindQuiche.cmake \ CMake/FindRustls.cmake \ - CMake/FindWolfSSH.cmake \ CMake/FindWolfSSL.cmake \ CMake/FindZstd.cmake \ CMake/Macros.cmake \ diff --git a/configure.ac b/configure.ac index 922978bfc106..56ac66de2369 100644 --- a/configure.ac +++ b/configure.ac @@ -2290,12 +2290,6 @@ AS_HELP_STRING([--with-libssh=PATH],[Where to look for libssh, PATH points to th AS_HELP_STRING([--with-libssh], [enable libssh]), OPT_LIBSSH=$withval, OPT_LIBSSH=no) -OPT_WOLFSSH=off -AC_ARG_WITH(wolfssh,dnl -AS_HELP_STRING([--with-wolfssh=PATH],[Where to look for wolfssh, PATH points to the wolfSSH installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) -AS_HELP_STRING([--with-wolfssh], [enable wolfssh]), - OPT_WOLFSSH=$withval, OPT_WOLFSSH=no) - if test X"$OPT_LIBSSH2" != Xno; then dnl backup the pre-libssh2 variables CLEANLDFLAGS="$LDFLAGS" @@ -2453,28 +2447,6 @@ elif test X"$OPT_LIBSSH" != Xno; then CPPFLAGS=$CLEANCPPFLAGS LIBS=$CLEANLIBS fi -elif test X"$OPT_WOLFSSH" != Xno; then - dnl backup the pre-wolfssh variables - CLEANLDFLAGS="$LDFLAGS" - CLEANLDFLAGSPC="$LDFLAGSPC" - CLEANCPPFLAGS="$CPPFLAGS" - CLEANLIBS="$LIBS" - - if test "$OPT_WOLFSSH" != yes; then - WOLFCONFIG="$OPT_WOLFSSH/bin/wolfssh-config" - WOLFSSH_LIBS=`$WOLFCONFIG --libs` - LDFLAGS="$LDFLAGS $WOLFSSH_LIBS" - LDFLAGSPC="$LDFLAGSPC $WOLFSSH_LIBS" - CPPFLAGS="$CPPFLAGS `$WOLFCONFIG --cflags`" - fi - - AC_CHECK_LIB(wolfssh, wolfSSH_Init) - - AC_CHECK_HEADERS(wolfssh/ssh.h, - curl_ssh_msg="enabled (wolfSSH)" - AC_DEFINE(USE_WOLFSSH, 1, [if wolfSSH is in use]) - USE_WOLFSSH=1 - ) fi dnl ********************************************************************** @@ -5501,9 +5473,6 @@ if test "x$USE_LIBSSH" = "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" fi -if test "x$USE_WOLFSSH" = "x1"; then - SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" -fi if test "x$CURL_DISABLE_IPFS" != "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS IPFS IPNS" fi diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index 94a19c71c749..566fee742314 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -363,7 +363,6 @@ Details via CMake - `CURL_USE_PKGCONFIG`: Enable `pkg-config` to detect dependencies. Default: `ON` for Unix (except Android, Apple devices), vcpkg, MinGW if not cross-compiling. - `CURL_USE_RUSTLS`: Enable Rustls for SSL/TLS. Default: `OFF` - `CURL_USE_SCHANNEL`: Enable Windows native SSL/TLS (Schannel). Default: `OFF` -- `CURL_USE_WOLFSSH`: Use wolfSSH. Default: `OFF` - `CURL_USE_WOLFSSL`: Enable wolfSSL for SSL/TLS. Default: `OFF` - `CURL_ZLIB`: Use zlib (`ON`, `OFF` or `AUTO`). Default: `AUTO` - `CURL_ZSTD`: Use zstd (`ON`, `OFF` or `AUTO`). Default: `AUTO` @@ -447,8 +446,6 @@ Details via CMake - `RUSTLS_INCLUDE_DIR`: The Rustls include directory. - `RUSTLS_LIBRARY`: Path to `rustls` library. - `WATT_ROOT`: Set this variable to the root installation of Watt-32. -- `WOLFSSH_INCLUDE_DIR`: The wolfSSH include directory. -- `WOLFSSH_LIBRARY`: Path to `wolfssh` library. - `WOLFSSL_INCLUDE_DIR`: The wolfSSL include directory. - `WOLFSSL_LIBRARY`: Path to `wolfssl` library. - `ZSTD_INCLUDE_DIR`: The zstd include directory. diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 170132f507d3..1eb5716f8b94 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -60,11 +60,9 @@ problems may have been fixed or changed somewhat since this was written. 9. SFTP and SCP 9.1 SFTP does not do CURLOPT_POSTQUOTE correct - 9.2 wolfssh: publickey auth does not work 9.3 Remote recursive folder creation with SFTP 9.4 libssh blocking and infinite loop problem 9.5 Cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" - 9.6 wolfssh: all tests fail 10. Connection 10.1 --interface with link-scoped IPv6 address @@ -400,14 +398,6 @@ problems may have been fixed or changed somewhat since this was written. report but it cannot be accepted as-is. See https://curl.se/bug/view.cgi?id=748 -9.2 wolfssh: publickey auth does not work - - When building curl to use the wolfSSH backend for SFTP, the publickey - authentication does not work. This is simply functionality not written for curl - yet, the necessary API for make this work is provided by wolfSSH. - - See https://github.com/curl/curl/issues/4820 - 9.3 Remote recursive folder creation with SFTP On this servers, the curl fails to create directories on the remote server @@ -429,12 +419,6 @@ problems may have been fixed or changed somewhat since this was written. https://github.com/curl/curl/issues/11244 -9.6 wolfssh: all tests fail - - Something fundamental stops them all from working properly. - - https://github.com/curl/curl/issues/16794 - 10. Connection 10.1 --interface with link-scoped IPv6 address diff --git a/docs/tests/FILEFORMAT.md b/docs/tests/FILEFORMAT.md index b28e819ebe3a..91aa9a587028 100644 --- a/docs/tests/FILEFORMAT.md +++ b/docs/tests/FILEFORMAT.md @@ -513,7 +513,6 @@ Features testable here are: - `wakeup` - `win32` - `WinIDN` -- `wolfssh` - `wolfssl` - `xattr` - `zstd` diff --git a/lib/Makefile.inc b/lib/Makefile.inc index c17a8d9c3cad..6391eb2c4351 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -127,8 +127,7 @@ LIB_VQUIC_HFILES = \ LIB_VSSH_CFILES = \ vssh/libssh.c \ vssh/libssh2.c \ - vssh/curl_path.c \ - vssh/wolfssh.c + vssh/curl_path.c LIB_VSSH_HFILES = \ vssh/curl_path.h \ diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index ca516710e42c..30183c20092f 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -706,9 +706,6 @@ ${SIZEOF_TIME_T_CODE} /* if libssh2 is in use */ #cmakedefine USE_LIBSSH2 1 -/* if wolfssh is in use */ -#cmakedefine USE_WOLFSSH 1 - /* if libpsl is in use */ #cmakedefine USE_LIBPSL 1 diff --git a/lib/curl_setup.h b/lib/curl_setup.h index e49c57231d2f..55c65c99f696 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -776,7 +776,7 @@ # endif #endif -#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH) +#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) #define USE_SSH #endif diff --git a/lib/url.c b/lib/url.c index a03a111995e2..6af2b7fb8b75 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1611,7 +1611,7 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme, #else NULL, #endif -#if defined(USE_SSH) && !defined(USE_WOLFSSH) +#if defined(USE_SSH) &Curl_handler_scp, #else NULL, diff --git a/lib/version.c b/lib/version.c index a2d486720091..8158f26e735b 100644 --- a/lib/version.c +++ b/lib/version.c @@ -368,10 +368,8 @@ static const char * const supported_protocols[] = { #ifndef CURL_DISABLE_RTSP "rtsp", #endif -#if defined(USE_SSH) && !defined(USE_WOLFSSH) - "scp", -#endif #ifdef USE_SSH + "scp", "sftp", #endif #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) diff --git a/lib/vssh/ssh.h b/lib/vssh/ssh.h index 75b31bd931f5..9a5f1b7e3187 100644 --- a/lib/vssh/ssh.h +++ b/lib/vssh/ssh.h @@ -34,9 +34,6 @@ #define SSH_SUPPRESS_DEPRECATED #include #include -#elif defined(USE_WOLFSSH) -#include -#include #endif #include "curl_path.h" @@ -211,14 +208,6 @@ struct ssh_conn { struct libssh2_agent_publickey *sshagent_identity; struct libssh2_agent_publickey *sshagent_prev_identity; LIBSSH2_KNOWNHOSTS *kh; -#elif defined(USE_WOLFSSH) - CURLcode actualcode; /* the actual error code */ - WOLFSSH *ssh_session; - WOLFSSH_CTX *ctx; - word32 handleSz; - byte handle[WOLFSSH_MAX_HANDLE]; - curl_off_t offset; - BIT(initialised); #endif /* USE_LIBSSH */ BIT(authed); /* the connection has been authenticated fine */ BIT(acceptfail); /* used by the SFTP_QUOTE (continue if diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c deleted file mode 100644 index 7cd0402a99d2..000000000000 --- a/lib/vssh/wolfssh.c +++ /dev/null @@ -1,1225 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, , 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 "../curl_setup.h" - -#ifdef USE_WOLFSSH - -#include - -#include "../urldata.h" -#include "../url.h" -#include "../cfilters.h" -#include "../connect.h" -#include "../sendf.h" -#include "../progress.h" -#include "curl_path.h" -#include "../transfer.h" -#include "../speedcheck.h" -#include "../select.h" -#include "../multiif.h" -#include "../curlx/warnless.h" -#include "../strdup.h" - -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" -#include "../curl_memory.h" -#include "../memdebug.h" - -static CURLcode wssh_connect(struct Curl_easy *data, bool *done); -static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done); -static CURLcode wssh_do(struct Curl_easy *data, bool *done); -#if 0 -static CURLcode wscp_done(struct Curl_easy *data, - CURLcode, bool premature); -static CURLcode wscp_doing(struct Curl_easy *data, - bool *dophase_done); -static CURLcode wscp_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead_connection); -#endif -static CURLcode wsftp_done(struct Curl_easy *data, - CURLcode, bool premature); -static CURLcode wsftp_doing(struct Curl_easy *data, - bool *dophase_done); -static CURLcode wsftp_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead); -static CURLcode wssh_pollset(struct Curl_easy *data, - struct easy_pollset *ps); -static CURLcode wssh_setup_connection(struct Curl_easy *data, - struct connectdata *conn); -static void wssh_sshc_cleanup(struct ssh_conn *sshc); - -#if 0 -/* - * SCP protocol handler. - */ - -const struct Curl_handler Curl_handler_scp = { - "SCP", /* scheme */ - wssh_setup_connection, /* setup_connection */ - wssh_do, /* do_it */ - wscp_done, /* done */ - ZERO_NULL, /* do_more */ - wssh_connect, /* connect_it */ - wssh_multi_statemach, /* connecting */ - wscp_doing, /* doing */ - wssh_pollset, /* proto_pollset */ - wssh_pollset, /* doing_pollset */ - ZERO_NULL, /* domore_pollset */ - wssh_pollset, /* perform_pollset */ - wscp_disconnect, /* disconnect */ - ZERO_NULL, /* write_resp */ - ZERO_NULL, /* write_resp_hd */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - ZERO_NULL, /* follow */ - PORT_SSH, /* defport */ - CURLPROTO_SCP, /* protocol */ - PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION - | PROTOPT_NOURLQUERY /* flags */ -}; - -#endif - -/* - * SFTP protocol handler. - */ - -const struct Curl_handler Curl_handler_sftp = { - "SFTP", /* scheme */ - wssh_setup_connection, /* setup_connection */ - wssh_do, /* do_it */ - wsftp_done, /* done */ - ZERO_NULL, /* do_more */ - wssh_connect, /* connect_it */ - wssh_multi_statemach, /* connecting */ - wsftp_doing, /* doing */ - wssh_pollset, /* proto_pollset */ - wssh_pollset, /* doing_pollset */ - ZERO_NULL, /* domore_pollset */ - wssh_pollset, /* perform_pollset */ - wsftp_disconnect, /* disconnect */ - ZERO_NULL, /* write_resp */ - ZERO_NULL, /* write_resp_hd */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - ZERO_NULL, /* follow */ - PORT_SSH, /* defport */ - CURLPROTO_SFTP, /* protocol */ - CURLPROTO_SFTP, /* family */ - PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION - | PROTOPT_NOURLQUERY /* flags */ -}; - -/* - * SSH State machine related code - */ -/* This is the ONLY way to change SSH state! */ -static void wssh_state(struct Curl_easy *data, - struct ssh_conn *sshc, - sshstate nowstate) -{ -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ - static const char * const names[] = { - "SSH_STOP", - "SSH_INIT", - "SSH_S_STARTUP", - "SSH_HOSTKEY", - "SSH_AUTHLIST", - "SSH_AUTH_PKEY_INIT", - "SSH_AUTH_PKEY", - "SSH_AUTH_PASS_INIT", - "SSH_AUTH_PASS", - "SSH_AUTH_AGENT_INIT", - "SSH_AUTH_AGENT_LIST", - "SSH_AUTH_AGENT", - "SSH_AUTH_HOST_INIT", - "SSH_AUTH_HOST", - "SSH_AUTH_KEY_INIT", - "SSH_AUTH_KEY", - "SSH_AUTH_GSSAPI", - "SSH_AUTH_DONE", - "SSH_SFTP_INIT", - "SSH_SFTP_REALPATH", - "SSH_SFTP_QUOTE_INIT", - "SSH_SFTP_POSTQUOTE_INIT", - "SSH_SFTP_QUOTE", - "SSH_SFTP_NEXT_QUOTE", - "SSH_SFTP_QUOTE_STAT", - "SSH_SFTP_QUOTE_SETSTAT", - "SSH_SFTP_QUOTE_SYMLINK", - "SSH_SFTP_QUOTE_MKDIR", - "SSH_SFTP_QUOTE_RENAME", - "SSH_SFTP_QUOTE_RMDIR", - "SSH_SFTP_QUOTE_UNLINK", - "SSH_SFTP_QUOTE_STATVFS", - "SSH_SFTP_GETINFO", - "SSH_SFTP_FILETIME", - "SSH_SFTP_TRANS_INIT", - "SSH_SFTP_UPLOAD_INIT", - "SSH_SFTP_CREATE_DIRS_INIT", - "SSH_SFTP_CREATE_DIRS", - "SSH_SFTP_CREATE_DIRS_MKDIR", - "SSH_SFTP_READDIR_INIT", - "SSH_SFTP_READDIR", - "SSH_SFTP_READDIR_LINK", - "SSH_SFTP_READDIR_BOTTOM", - "SSH_SFTP_READDIR_DONE", - "SSH_SFTP_DOWNLOAD_INIT", - "SSH_SFTP_DOWNLOAD_STAT", - "SSH_SFTP_CLOSE", - "SSH_SFTP_SHUTDOWN", - "SSH_SCP_TRANS_INIT", - "SSH_SCP_UPLOAD_INIT", - "SSH_SCP_DOWNLOAD_INIT", - "SSH_SCP_DOWNLOAD", - "SSH_SCP_DONE", - "SSH_SCP_SEND_EOF", - "SSH_SCP_WAIT_EOF", - "SSH_SCP_WAIT_CLOSE", - "SSH_SCP_CHANNEL_FREE", - "SSH_SESSION_DISCONNECT", - "SSH_SESSION_FREE", - "QUIT" - }; - - /* a precaution to make sure the lists are in sync */ - DEBUGASSERT(CURL_ARRAYSIZE(names) == SSH_LAST); - - if(sshc->state != nowstate) { - infof(data, "wolfssh %p state change from %s to %s", - (void *)sshc, names[sshc->state], names[nowstate]); - } -#endif - (void)data; - sshc->state = nowstate; -} - -static CURLcode wscp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, - size_t *pnwritten) -{ - (void)data; - (void)sockindex; /* we only support SCP on the fixed known primary socket */ - (void)mem; - (void)len; - (void)eos; - *pnwritten = 0; - return CURLE_OK; -} - -static CURLcode wscp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, size_t *pnread) -{ - (void)data; - (void)sockindex; /* we only support SCP on the fixed known primary socket */ - (void)mem; - (void)len; - *pnread = 0; - - return CURLE_OK; -} - -/* return number of sent bytes */ -static CURLcode wsftp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, - size_t *pnwritten) -{ - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - word32 offset[2]; - int rc; - (void)sockindex; - (void)eos; - - *pnwritten = 0; - if(!sshc) - return CURLE_FAILED_INIT; - - offset[0] = (word32)sshc->offset & 0xFFFFFFFF; - offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF; - - rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle, - sshc->handleSz, - &offset[0], - (byte *)CURL_UNCONST(mem), (word32)len); - - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - conn->waitfor = KEEP_RECV; - return CURLE_AGAIN; - } - else if(rc == WS_WANT_WRITE) { - conn->waitfor = KEEP_SEND; - return CURLE_AGAIN; - } - if(rc < 0) { - failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc); - return CURLE_SEND_ERROR; - } - DEBUGASSERT(rc == (int)len); - *pnwritten = (size_t)rc; - sshc->offset += *pnwritten; - infof(data, "sent %zu bytes SFTP from offset %" FMT_OFF_T, - *pnwritten, sshc->offset); - return CURLE_OK; -} - -/* - * Return number of received (decrypted) bytes - * or <0 on error - */ -static CURLcode wsftp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, size_t *pnread) -{ - int rc; - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - word32 offset[2]; - (void)sockindex; - - *pnread = 0; - if(!sshc) - return CURLE_FAILED_INIT; - - offset[0] = (word32)sshc->offset & 0xFFFFFFFF; - offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF; - - rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle, - sshc->handleSz, - &offset[0], - (byte *)mem, (word32)len); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - conn->waitfor = KEEP_RECV; - return CURLE_AGAIN; - } - else if(rc == WS_WANT_WRITE) { - conn->waitfor = KEEP_SEND; - return CURLE_AGAIN; - } - - DEBUGASSERT(rc <= (int)len); - - if(rc < 0) { - failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc); - return CURLE_RECV_ERROR; - } - *pnread = (size_t)rc; - sshc->offset += *pnread; - return CURLE_OK; -} - -static void wssh_easy_dtor(void *key, size_t klen, void *entry) -{ - struct SSHPROTO *sshp = entry; - (void)key; - (void)klen; - Curl_safefree(sshp->path); - free(sshp); -} - -static void wssh_conn_dtor(void *key, size_t klen, void *entry) -{ - struct ssh_conn *sshc = entry; - (void)key; - (void)klen; - wssh_sshc_cleanup(sshc); - free(sshc); -} - -/* - * SSH setup and connection - */ -static CURLcode wssh_setup_connection(struct Curl_easy *data, - struct connectdata *conn) -{ - struct ssh_conn *sshc; - struct SSHPROTO *sshp; - (void)conn; - - sshc = calloc(1, sizeof(*sshc)); - if(!sshc) - return CURLE_OUT_OF_MEMORY; - - sshc->initialised = TRUE; - if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, wssh_conn_dtor)) - return CURLE_OUT_OF_MEMORY; - - sshp = calloc(1, sizeof(*sshp)); - if(!sshp || - Curl_meta_set(data, CURL_META_SSH_EASY, sshp, wssh_easy_dtor)) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; -} - -static int userauth(byte authtype, - WS_UserAuthData* authdata, - void *ctx) -{ - struct Curl_easy *data = ctx; - DEBUGF(infof(data, "wolfssh callback: type %s", - authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" : - "PUBLICCKEY")); - if(authtype == WOLFSSH_USERAUTH_PASSWORD) { - authdata->sf.password.password = (byte *)data->conn->passwd; - authdata->sf.password.passwordSz = (word32) strlen(data->conn->passwd); - } - - return 0; -} - -static CURLcode wssh_connect(struct Curl_easy *data, bool *done) -{ - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc; - - if(!sshc || !sshp) - return CURLE_FAILED_INIT; - - /* We default to persistent connections. We set this already in this connect - function to make the reuse checks properly be able to check this bit. */ - connkeep(conn, "SSH default"); - - if(conn->handler->protocol & CURLPROTO_SCP) { - conn->recv[FIRSTSOCKET] = wscp_recv; - conn->send[FIRSTSOCKET] = wscp_send; - } - else { - conn->recv[FIRSTSOCKET] = wsftp_recv; - conn->send[FIRSTSOCKET] = wsftp_send; - } - sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); - if(!sshc->ctx) { - failf(data, "No wolfSSH context"); - goto error; - } - - sshc->ssh_session = wolfSSH_new(sshc->ctx); - if(!sshc->ssh_session) { - failf(data, "No wolfSSH session"); - goto error; - } - - rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user); - if(rc != WS_SUCCESS) { - failf(data, "wolfSSH failed to set username"); - goto error; - } - - /* set callback for authentication */ - wolfSSH_SetUserAuth(sshc->ctx, userauth); - wolfSSH_SetUserAuthCtx(sshc->ssh_session, data); - - rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock); - if(rc) { - failf(data, "wolfSSH failed to set socket"); - goto error; - } - -#if 0 - wolfSSH_Debugging_ON(); -#endif - - *done = TRUE; - if(conn->handler->protocol & CURLPROTO_SCP) - wssh_state(data, sshc, SSH_INIT); - else - wssh_state(data, sshc, SSH_SFTP_INIT); - - return wssh_multi_statemach(data, done); -error: - wssh_sshc_cleanup(sshc); - return CURLE_FAILED_INIT; -} - -static CURLcode wssh_sftp_upload_init(struct Curl_easy *data, - struct ssh_conn *sshc, - struct SSHPROTO *sftp_scp, - bool *block) -{ - word32 flags; - WS_SFTP_FILEATRB createattrs; - struct connectdata *conn = data->conn; - int rc; - if(data->state.resume_from) { - WS_SFTP_FILEATRB attrs; - if(data->state.resume_from < 0) { - rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, - &attrs); - if(rc != WS_SUCCESS) - return CURLE_SSH; - - if(rc) { - data->state.resume_from = 0; - } - else { - curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; - if(size < 0) { - failf(data, "Bad file size (%" FMT_OFF_T ")", size); - return CURLE_BAD_DOWNLOAD_RESUME; - } - data->state.resume_from = size; - } - } - } - - if(data->set.remote_append) - /* Try to open for append, but create if nonexisting */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND; - else if(data->state.resume_from > 0) - /* If we have restart position then open for append */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND; - else - /* Clear file before writing (normal behavior) */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC; - - memset(&createattrs, 0, sizeof(createattrs)); - createattrs.per = (word32)data->set.new_file_perms; - sshc->handleSz = sizeof(sshc->handle); - rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, - flags, &createattrs, - sshc->handle, &sshc->handleSz); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh SFTP open succeeded"); - } - else { - failf(data, "wolfssh SFTP upload open failed: %d", rc); - return CURLE_SSH; - } - wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); - - /* If we have a restart point then we need to seek to the correct - position. */ - if(data->state.resume_from > 0) { - /* Let's read off the proper amount of bytes from the input. */ - int seekerr = CURL_SEEKFUNC_OK; - if(data->set.seek_func) { - Curl_set_in_callback(data, TRUE); - seekerr = data->set.seek_func(data->set.seek_client, - data->state.resume_from, SEEK_SET); - Curl_set_in_callback(data, FALSE); - } - - if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed = 0; - - if(seekerr != CURL_SEEKFUNC_CANTSEEK) { - failf(data, "Could not seek stream"); - return CURLE_FTP_COULDNT_USE_REST; - } - /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */ - do { - char scratch[4*1024]; - size_t readthisamountnow = - (data->state.resume_from - passed > - (curl_off_t)sizeof(scratch)) ? - sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread; - Curl_set_in_callback(data, TRUE); - actuallyread = data->state.fread_func(scratch, 1, - readthisamountnow, - data->state.in); - Curl_set_in_callback(data, FALSE); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Failed to read data"); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed < data->state.resume_from); - } - - /* now, decrease the size of the read */ - if(data->state.infilesize > 0) { - data->state.infilesize -= data->state.resume_from; - data->req.size = data->state.infilesize; - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - - sshc->offset += data->state.resume_from; - } - if(data->state.infilesize > 0) { - data->req.size = data->state.infilesize; - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - /* upload data */ - Curl_xfer_setup_send(data, FIRSTSOCKET); - - /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->recv_idx = FIRSTSOCKET; - - /* store this original bitmask setup to use later on if we cannot - figure out a "real" bitmask */ - sshc->orig_waitfor = data->req.keepon; - - /* since we do not really wait for anything at this point, we want the state - machine to move on as soon as possible */ - Curl_multi_mark_dirty(data); - - wssh_state(data, sshc, SSH_STOP); - - return CURLE_OK; -} - -/* - * wssh_statemach_act() runs the SSH state machine as far as it can without - * blocking and without reaching the end. The data the pointer 'block' points - * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it - * wants to be called again when the socket is ready - */ - -static CURLcode wssh_statemach_act(struct Curl_easy *data, - struct ssh_conn *sshc, - bool *block) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - struct SSHPROTO *sftp_scp = Curl_meta_get(data, CURL_META_SSH_EASY); - WS_SFTPNAME *name; - int rc = 0; - *block = FALSE; /* we are not blocking by default */ - - if(!sftp_scp) - return CURLE_FAILED_INIT; - - do { - switch(sshc->state) { - case SSH_INIT: - wssh_state(data, sshc, SSH_S_STARTUP); - break; - - case SSH_S_STARTUP: - rc = wolfSSH_connect(sshc->ssh_session); - if(rc != WS_SUCCESS) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc != WS_SUCCESS) { - wssh_state(data, sshc, SSH_STOP); - return CURLE_SSH; - } - infof(data, "wolfssh connected"); - wssh_state(data, sshc, SSH_STOP); - break; - case SSH_STOP: - break; - - case SSH_SFTP_INIT: - rc = wolfSSH_SFTP_connect(sshc->ssh_session); - if(rc != WS_SUCCESS) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh SFTP connected"); - wssh_state(data, sshc, SSH_SFTP_REALPATH); - } - else { - failf(data, "wolfssh SFTP connect error %d", rc); - return CURLE_SSH; - } - break; - case SSH_SFTP_REALPATH: - name = wolfSSH_SFTP_RealPath(sshc->ssh_session, - (char *)CURL_UNCONST(".")); - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(name && (rc == WS_SUCCESS)) { - sshc->homedir = Curl_memdup0(name->fName, name->fSz); - if(!sshc->homedir) - sshc->actualcode = CURLE_OUT_OF_MEMORY; - wolfSSH_SFTPNAME_list_free(name); - wssh_state(data, sshc, SSH_STOP); - return CURLE_OK; - } - failf(data, "wolfssh SFTP realpath %d", rc); - return CURLE_SSH; - - case SSH_SFTP_QUOTE_INIT: - result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path); - if(result) { - sshc->actualcode = result; - wssh_state(data, sshc, SSH_STOP); - break; - } - - if(data->set.quote) { - infof(data, "Sending quote commands"); - sshc->quote_item = data->set.quote; - wssh_state(data, sshc, SSH_SFTP_QUOTE); - } - else { - wssh_state(data, sshc, SSH_SFTP_GETINFO); - } - break; - case SSH_SFTP_GETINFO: - if(data->set.get_filetime) { - wssh_state(data, sshc, SSH_SFTP_FILETIME); - } - else { - wssh_state(data, sshc, SSH_SFTP_TRANS_INIT); - } - break; - case SSH_SFTP_TRANS_INIT: - if(data->state.upload) - wssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); - else { - if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') - wssh_state(data, sshc, SSH_SFTP_READDIR_INIT); - else - wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT); - } - break; - case SSH_SFTP_UPLOAD_INIT: - result = wssh_sftp_upload_init(data, sshc, sftp_scp, block); - break; - - case SSH_SFTP_DOWNLOAD_INIT: - sshc->handleSz = sizeof(sshc->handle); - rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, - WOLFSSH_FXF_READ, NULL, - sshc->handle, &sshc->handleSz); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh SFTP open succeeded"); - wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); - return CURLE_OK; - } - - failf(data, "wolfssh SFTP open failed: %d", rc); - return CURLE_SSH; - - case SSH_SFTP_DOWNLOAD_STAT: { - WS_SFTP_FILEATRB attrs; - curl_off_t size; - - rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh STAT succeeded"); - } - else { - failf(data, "wolfssh SFTP open failed: %d", rc); - data->req.size = -1; - data->req.maxdownload = -1; - Curl_pgrsSetDownloadSize(data, -1); - return CURLE_SSH; - } - - size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; - - data->req.size = size; - data->req.maxdownload = size; - Curl_pgrsSetDownloadSize(data, size); - - infof(data, "SFTP download %" FMT_OFF_T " bytes", size); - - /* We cannot seek with wolfSSH so resuming and range requests are not - possible */ - if(data->state.use_range || data->state.resume_from) { - infof(data, "wolfSSH cannot do range/seek on SFTP"); - return CURLE_BAD_DOWNLOAD_RESUME; - } - - /* Setup the actual download */ - if(data->req.size == 0) { - /* no data to transfer */ - Curl_xfer_setup_nop(data); - infof(data, "File already completely downloaded"); - wssh_state(data, sshc, SSH_STOP); - break; - } - Curl_xfer_setup_recv(data, FIRSTSOCKET, data->req.size); - - /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->send_idx = 0; - - if(result) { - /* this should never occur; the close state should be entered - at the time the error occurs */ - wssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->actualcode = result; - } - else { - wssh_state(data, sshc, SSH_STOP); - } - break; - } - case SSH_SFTP_CLOSE: - if(sshc->handleSz) { - rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle, - sshc->handleSz); - if(rc != WS_SUCCESS) - rc = wolfSSH_get_error(sshc->ssh_session); - } - else { - rc = WS_SUCCESS; /* directory listing */ - } - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - wssh_state(data, sshc, SSH_STOP); - return CURLE_OK; - } - - failf(data, "wolfssh SFTP CLOSE failed: %d", rc); - return CURLE_SSH; - - case SSH_SFTP_READDIR_INIT: - Curl_pgrsSetDownloadSize(data, -1); - if(data->req.no_body) { - wssh_state(data, sshc, SSH_STOP); - break; - } - wssh_state(data, sshc, SSH_SFTP_READDIR); - break; - - case SSH_SFTP_READDIR: - name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path); - if(!name) - rc = wolfSSH_get_error(sshc->ssh_session); - else - rc = WS_SUCCESS; - - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(name && (rc == WS_SUCCESS)) { - WS_SFTPNAME *origname = name; - result = CURLE_OK; - while(name) { - char *line = aprintf("%s\n", - data->set.list_only ? - name->fName : name->lName); - if(!line) { - wssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - result = Curl_client_write(data, CLIENTWRITE_BODY, - line, strlen(line)); - free(line); - if(result) { - sshc->actualcode = result; - break; - } - name = name->next; - } - wolfSSH_SFTPNAME_list_free(origname); - wssh_state(data, sshc, SSH_STOP); - return result; - } - failf(data, "wolfssh SFTP ls failed: %d", rc); - return CURLE_SSH; - - case SSH_SFTP_SHUTDOWN: - wssh_sshc_cleanup(sshc); - wssh_state(data, sshc, SSH_STOP); - return CURLE_OK; - default: - break; - } - } while(!rc && (sshc->state != SSH_STOP)); - return result; -} - -/* called repeatedly until done from multi.c */ -static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done) -{ - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - CURLcode result = CURLE_OK; - bool block; /* we store the status and use that to provide a ssh_pollset() - implementation */ - if(!sshc) - return CURLE_FAILED_INIT; - - do { - result = wssh_statemach_act(data, sshc, &block); - *done = (sshc->state == SSH_STOP); - /* if there is no error, it is not done and it did not EWOULDBLOCK, then - try again */ - if(*done) { - DEBUGF(infof(data, "wssh_statemach_act says DONE")); - } - } while(!result && !*done && !block); - - return result; -} - -static -CURLcode wscp_perform(struct Curl_easy *data, - bool *connected, - bool *dophase_done) -{ - (void)data; - (void)connected; - (void)dophase_done; - return CURLE_OK; -} - -static -CURLcode wsftp_perform(struct Curl_easy *data, - struct ssh_conn *sshc, - bool *connected, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - - DEBUGF(infof(data, "DO phase starts")); - - *dophase_done = FALSE; /* not done yet */ - - /* start the first command in the DO phase */ - wssh_state(data, sshc, SSH_SFTP_QUOTE_INIT); - - /* run the state-machine */ - result = wssh_multi_statemach(data, dophase_done); - - *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); - - if(*dophase_done) { - DEBUGF(infof(data, "DO phase is complete")); - } - - return result; -} - -/* - * The DO function is generic for both protocols. - */ -static CURLcode wssh_do(struct Curl_easy *data, bool *done) -{ - CURLcode result; - bool connected = FALSE; - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - - *done = FALSE; /* default to false */ - if(!sshc) - return CURLE_FAILED_INIT; - - data->req.size = -1; /* make sure this is unknown at this point */ - sshc->actualcode = CURLE_OK; /* reset error code */ - sshc->secondCreateDirs = 0; /* reset the create dir attempt state - variable */ - - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, -1); - Curl_pgrsSetDownloadSize(data, -1); - - if(conn->handler->protocol & CURLPROTO_SCP) - result = wscp_perform(data, &connected, done); - else - result = wsftp_perform(data, sshc, &connected, done); - - return result; -} - -static CURLcode wssh_block_statemach(struct Curl_easy *data, - struct ssh_conn *sshc, - bool disconnect) -{ - struct connectdata *conn = data->conn; - CURLcode result = CURLE_OK; - - while((sshc->state != SSH_STOP) && !result) { - bool block; - timediff_t left = 1000; - struct curltime now = curlx_now(); - - result = wssh_statemach_act(data, sshc, &block); - if(result) - break; - - if(!disconnect) { - if(Curl_pgrsUpdate(data)) - return CURLE_ABORTED_BY_CALLBACK; - - result = Curl_speedcheck(data, now); - if(result) - break; - - left = Curl_timeleft(data, NULL, FALSE); - if(left < 0) { - failf(data, "Operation timed out"); - return CURLE_OPERATION_TIMEDOUT; - } - } - - if(!result) { - int dir = conn->waitfor; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - curl_socket_t fd_read = CURL_SOCKET_BAD; - curl_socket_t fd_write = CURL_SOCKET_BAD; - if(dir == KEEP_RECV) - fd_read = sock; - else if(dir == KEEP_SEND) - fd_write = sock; - - /* wait for the socket to become ready */ - (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, - left > 1000 ? 1000 : left); /* ignore result */ - } - } - - return result; -} - -/* generic done function for both SCP and SFTP called from their specific - done functions */ -static CURLcode wssh_done(struct Curl_easy *data, - struct ssh_conn *sshc, - CURLcode status) -{ - CURLcode result = CURLE_OK; - - if(!status) { - /* run the state-machine */ - result = wssh_block_statemach(data, sshc, FALSE); - } - else - result = status; - - if(Curl_pgrsDone(data)) - return CURLE_ABORTED_BY_CALLBACK; - - data->req.keepon = 0; /* clear all bits */ - return result; -} - -static void wssh_sshc_cleanup(struct ssh_conn *sshc) -{ - if(sshc->ssh_session) { - wolfSSH_free(sshc->ssh_session); - sshc->ssh_session = NULL; - } - if(sshc->ctx) { - wolfSSH_CTX_free(sshc->ctx); - sshc->ctx = NULL; - } - Curl_safefree(sshc->homedir); -} - -#if 0 -static CURLcode wscp_done(struct Curl_easy *data, - CURLcode code, bool premature) -{ - CURLcode result = CURLE_OK; - (void)conn; - (void)code; - (void)premature; - - return result; -} - -static CURLcode wscp_doing(struct Curl_easy *data, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - (void)conn; - (void)dophase_done; - - return result; -} - -static CURLcode wscp_disconnect(struct Curl_easy *data, - struct connectdata *conn, bool dead_connection) -{ - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - CURLcode result = CURLE_OK; - (void)dead_connection; - if(sshc) - wssh_sshc_cleanup(sshc); - return result; -} -#endif - -static CURLcode wsftp_done(struct Curl_easy *data, - CURLcode code, bool premature) -{ - struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); - (void)premature; - if(!sshc) - return CURLE_FAILED_INIT; - - wssh_state(data, sshc, SSH_SFTP_CLOSE); - - return wssh_done(data, sshc, code); -} - -static CURLcode wsftp_doing(struct Curl_easy *data, - bool *dophase_done) -{ - CURLcode result = wssh_multi_statemach(data, dophase_done); - - if(*dophase_done) { - DEBUGF(infof(data, "DO phase is complete")); - } - return result; -} - -static CURLcode wsftp_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead) -{ - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - CURLcode result = CURLE_OK; - (void)dead; - - DEBUGF(infof(data, "SSH DISCONNECT starts now")); - - if(sshc && sshc->ssh_session) { - /* only if there is a session still around to use! */ - wssh_state(data, sshc, SSH_SFTP_SHUTDOWN); - result = wssh_block_statemach(data, sshc, TRUE); - } - - if(sshc) - wssh_sshc_cleanup(sshc); - DEBUGF(infof(data, "SSH DISCONNECT is done")); - return result; -} - -static CURLcode wssh_pollset(struct Curl_easy *data, - struct easy_pollset *ps) -{ - int flags = 0; - if(data->conn->waitfor & KEEP_RECV) - flags |= CURL_POLL_IN; - if(data->conn->waitfor & KEEP_SEND) - flags |= CURL_POLL_OUT; - return flags ? - Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) : - CURLE_OK; -} - -void Curl_ssh_version(char *buffer, size_t buflen) -{ - (void)msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING); -} - -CURLcode Curl_ssh_init(void) -{ - if(WS_SUCCESS != wolfSSH_Init()) { - DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n")); - return CURLE_FAILED_INIT; - } - - return CURLE_OK; -} -void Curl_ssh_cleanup(void) -{ - (void)wolfSSH_Cleanup(); -} - -#endif /* USE_WOLFSSH */ diff --git a/packages/OS400/ccsidcurl.c b/packages/OS400/ccsidcurl.c index a9c04d5a420e..101cf9024705 100644 --- a/packages/OS400/ccsidcurl.c +++ b/packages/OS400/ccsidcurl.c @@ -1213,8 +1213,8 @@ curl_easy_setopt_ccsid(CURL *easy, CURLoption tag, ...) if(!s) { result = CURLE_OUT_OF_MEMORY; break; - } } + } else { /* Data length specified. */ size_t len; diff --git a/scripts/schemetable.c b/scripts/schemetable.c index 7da4613212cc..e65c462f7b36 100644 --- a/scripts/schemetable.c +++ b/scripts/schemetable.c @@ -60,7 +60,7 @@ static const struct detail scheme[] = { {"rtmps", "#ifdef USE_LIBRTMP" }, {"rtmpts", "#ifdef USE_LIBRTMP" }, {"rtsp", "#ifndef CURL_DISABLE_RTSP" }, - {"scp", "#if defined(USE_SSH) && !defined(USE_WOLFSSH)" }, + {"scp", "#ifdef USE_SSH" }, {"sftp", "#ifdef USE_SSH" }, {"smb", "#if !defined(CURL_DISABLE_SMB) && \\\n" " defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)" }, diff --git a/tests/runtests.pl b/tests/runtests.pl index 4945e94cdabb..6b6e5b076191 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -639,9 +639,6 @@ sub checksystemfeatures { } } } - if($libcurl =~ /wolfssh/i) { - $feature{"wolfssh"} = 1; - } } elsif($_ =~ /^Protocols: (.*)/i) { $proto = $1; From 9a5810f6c1ebac17dae149c517cb520d4abaa4bf Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 24 Sep 2025 23:03:03 +0200 Subject: [PATCH 151/208] RELEASE-NOTES: synced --- RELEASE-NOTES | 69 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 698c81d3a868..fadadb8c87d1 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,28 +4,36 @@ curl and libcurl 8.17.0 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3505 + Contributors: 3508 This release includes the following changes: o build: drop the winbuild build system [81] o krb5: drop support for Kerberos FTP [43] o libssh2: up the minimum requirement to 1.9.0 [85] + o vssh: drop support for wolfSSH [58] o write-out: make %header{} able to output *all* occurrences of a header [25] This release includes the following bugfixes: + o ares: fix leak in tracing [91] o asyn-thrdd: drop pthread_cancel [30] + o autotools: add support for libgsasl auto-detection via pkg-config [112] + o autotools: capitalize 'Rustls' in the log output [106] + o autotools: fix duplicate `UNIX` and `BSD` flags in `buildinfo.txt` [113] + o autotools: fix silly mistake in clang detection for `buildinfo.txt` [114] o autotools: make `--enable-code-coverage` support llvm/clang [79] o aws-lc: re-enable large read-ahead with v1.61.0 again [16] o base64: accept zero length argument to base64_encode [82] o build: address some `-Weverything` warnings, update picky warnings [74] o build: avoid overriding system symbols for socket functions [68] + o build: show llvm/clang in platform flags and `buildinfo.txt` [126] o cf-socket: use the right byte order for ports in bindlocal [61] - o cf_socket_recv: don't count reading zero bytes as first byte [23] o cfilter: unlink and discard [46] o cmake: add `CURL_CODE_COVERAGE` option [78] + o cmake: clang detection tidy-ups [116] o cmake: fix building docs when the base directory contains `.3` [18] + o cmake: use modern alternatives for `get_filename_component()` [102] o cmdline-docs: extended, clarified, refreshed [28] o configure: add "-mt" for pthread support on HP-UX [52] o cookie: avoid saving a cookie file if no transfer was done [11] @@ -42,10 +50,13 @@ This release includes the following bugfixes: o docs/libcurl: clarify some timeout option behavior [15] o docs/libcurl: remove ancient version references [7] o docs/libcurl: use lowercase must [5] + o docs: fix/tidy code fences [87] o easy_getinfo: check magic, Curl_close safety [3] o examples: fix two issues found by CodeQL [35] + o ftp: fix ftp_do_more returning with *completep unset [122] o ftp: fix port number range loop for PORT commands [66] o gtls: avoid potential use of uninitialized variable in trace output [83] + o hostip: remove leftover INT_MAX check in Curl_dnscache_prune [88] o httpsrr: free old pointers when storing new [57] o krb5: return appropriate error on send failures [22] o ldap: do not base64 encode zero length string [42] @@ -53,20 +64,26 @@ This release includes the following bugfixes: o libcurl-security.md: mention long-running connections [6] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh: drop two unused assigments [104] o libssh: error on bad chgrp number [71] o libssh: error on bad chown number and store the value [64] + o libssh: fix range parsing error handling mistake [120] o libssh: react on errors from ssh_scp_read [24] o libssh: return out of memory correctly if aprintf fails [60] o Makefile.example: simplify and make it configurable [20] o managen: ignore version mentions < 7.66.0 [55] o managen: render better manpage references/links [54] + o managen: strict protocol check [109] o multi.h: add CURLMINFO_LASTENTRY [51] o ngtcp2: check error code on connect failure [13] o openldap: avoid indexing the result at -1 for blank responses [44] + o openldap: check ldap_get_option() return codes [119] o openssl: make the asn1_object_dump name null terminated [56] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o rustls: fix clang-tidy warning [107] o rustls: typecast variable for safer trace output [69] + o rustls: use %zu for size_t in failf() format string [121] o sasl: clear canceled mechanism instead of toggling it [41] o schannel: assign result before using it [62] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] @@ -74,27 +91,37 @@ This release includes the following bugfixes: o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] o socks: make Curl_blockread_all return CURLcode [67] + o socks_gssapi: reject too long tokens [90] o socks_sspi: fix memory cleanup calls [40] o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] o sws: fix checking `sscanf()` return value [17] o telnet: make printsub require another byte input [21] + o telnet: refuse IAC codes in content [111] + o telnet: return error on crazy TTYPE or XDISPLOC lengths [123] o tftp: check and act on tftp_set_timeouts() returning error [38] o tftp: handle tftp_multi_statemach() return code [65] + o tftp: pin the first used address [110] o tftp: propagate expired timer from tftp_state_timeout() [39] o tftp: return error when sendto() fails [59] + o tidy-up: assortment of small fixes [115] o tidy-up: avoid using the reserved macro namespace [76] o tidy-up: update MS links, allow long URLs via `checksrc` [73] + o tidy-up: URLs [101] o TODO: remove already implemented or bad items [36] o tool: fix exponential retry delay [47] o tool_cb_hdr: fix fwrite check in header callback [49] o tool_cb_hdr: size is always 1 [70] + o tool_doswin: fix to use curl socket functions [108] o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_operate: improve wording in retry message [37] o tool_operate: keep the progress meter for --out-null [33] o urldata: FILE is not a list-only protocol [9] + o vtls_int.h: clarify data_pending [124] o windows: replace `_beginthreadex()` with `CreateThread()` [80] o windows: stop passing unused, optional argument for Win9x compatibility [75] + o ws: clarify an error message [125] + o ws: reject curl_ws_recv called with NULL buffer with a buflen [118] This release includes the following known bugs: @@ -120,10 +147,11 @@ advice from friends like these: Adam Light, Andrew Kirillov, Andrew Olsen, BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, - fds242 on github, Javier Blazquez, Jicea, Joshua Rogers, kapsiR on github, - Marcel Raad, Michael Osipov, Michał Petryka, Nir Azkiel, Ray Satiro, - renovate[bot], Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats - (25 contributors) + fds242 on github, Javier Blazquez, Jicea, jmaggard10 on github, + Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, Marcel Raad, + Michael Osipov, Michał Petryka, Nir Azkiel, Ray Satiro, renovate[bot], + rinsuki on github, Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats + (28 contributors) References to bug reports and discussions on issues: @@ -149,7 +177,6 @@ References to bug reports and discussions on issues: [20] = https://curl.se/bug/?i=18554 [21] = https://curl.se/bug/?i=18618 [22] = https://curl.se/bug/?i=18561 - [23] = https://curl.se/bug/?i=18615 [24] = https://curl.se/bug/?i=18616 [25] = https://curl.se/bug/?i=18491 [26] = https://curl.se/bug/?i=18606 @@ -184,6 +211,7 @@ References to bug reports and discussions on issues: [55] = https://curl.se/bug/?i=18583 [56] = https://curl.se/bug/?i=18647 [57] = https://curl.se/bug/?i=18631 + [58] = https://curl.se/bug/?i=18700 [59] = https://curl.se/bug/?i=18643 [60] = https://curl.se/bug/?i=18637 [61] = https://curl.se/bug/?i=18641 @@ -211,3 +239,30 @@ References to bug reports and discussions on issues: [83] = https://curl.se/bug/?i=18620 [84] = https://curl.se/bug/?i=18624 [85] = https://curl.se/bug/?i=18612 + [87] = https://curl.se/bug/?i=18707 + [88] = https://curl.se/bug/?i=18680 + [90] = https://curl.se/bug/?i=18681 + [91] = https://curl.se/bug/?i=18251 + [101] = https://curl.se/bug/?i=18689 + [102] = https://curl.se/bug/?i=18688 + [104] = https://curl.se/bug/?i=18684 + [106] = https://curl.se/bug/?i=18671 + [107] = https://curl.se/bug/?i=18670 + [108] = https://curl.se/bug/?i=18633 + [109] = https://curl.se/bug/?i=18675 + [110] = https://curl.se/bug/?i=18658 + [111] = https://curl.se/bug/?i=18657 + [112] = https://curl.se/bug/?i=18669 + [113] = https://curl.se/bug/?i=18667 + [114] = https://curl.se/bug/?i=18666 + [115] = https://curl.se/bug/?i=18664 + [116] = https://curl.se/bug/?i=18659 + [118] = https://curl.se/bug/?i=18656 + [119] = https://curl.se/bug/?i=18653 + [120] = https://curl.se/bug/?i=18652 + [121] = https://curl.se/bug/?i=18651 + [122] = https://curl.se/bug/?i=18650 + [123] = https://curl.se/bug/?i=18648 + [124] = https://curl.se/bug/?i=18644 + [125] = https://curl.se/bug/?i=18654 + [126] = https://curl.se/bug/?i=18645 From 977595772c6e650b538da965cde676c9bc15cfd8 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 23:48:13 +0200 Subject: [PATCH 152/208] RELEASE-NOTES: codespell --- RELEASE-NOTES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index fadadb8c87d1..da62171c7198 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -64,7 +64,7 @@ This release includes the following bugfixes: o libcurl-security.md: mention long-running connections [6] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] - o libssh: drop two unused assigments [104] + o libssh: drop two unused assignments [104] o libssh: error on bad chgrp number [71] o libssh: error on bad chown number and store the value [64] o libssh: fix range parsing error handling mistake [120] From 9d3f878e59d155ee2b916550bdca531424643710 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 21:01:05 +0000 Subject: [PATCH 153/208] GHA: update actions/cache digest to 0057852 Closes #18710 --- .github/workflows/http3-linux.yml | 46 +++++++++++++++---------------- .github/workflows/linux.yml | 20 +++++++------- .github/workflows/macos.yml | 2 +- .github/workflows/windows.yml | 10 +++---- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 780320e383aa..61164913ad28 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -69,7 +69,7 @@ jobs: steps: - name: 'cache openssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-openssl-http3 env: cache-name: cache-openssl-http3 @@ -78,7 +78,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }} - name: 'cache libressl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-libressl env: cache-name: cache-libressl @@ -87,7 +87,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.LIBRESSL_VERSION }} - name: 'cache awslc' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-awslc env: cache-name: cache-awslc @@ -96,7 +96,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.AWSLC_VERSION }} - name: 'cache boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-boringssl env: cache-name: cache-boringssl @@ -105,7 +105,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.BORINGSSL_VERSION }} - name: 'cache quictls' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-quictls-no-deprecated env: cache-name: cache-quictls-no-deprecated @@ -114,7 +114,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.QUICTLS_VERSION }}-quic1 - name: 'cache gnutls' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-gnutls env: cache-name: cache-gnutls @@ -123,7 +123,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.GNUTLS_VERSION }} - name: 'cache wolfssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-wolfssl env: cache-name: cache-wolfssl @@ -132,7 +132,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.WOLFSSL_VERSION }} - name: 'cache nghttp3' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-nghttp3 env: cache-name: cache-nghttp3 @@ -141,7 +141,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGHTTP3_VERSION }} - name: 'cache ngtcp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-ngtcp2 env: cache-name: cache-ngtcp2 @@ -150,7 +150,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.AWSLC_VERSION }}-${{ env.QUICTLS_VERSION }}-${{ env.GNUTLS_VERSION }}-${{ env.WOLFSSL_VERSION }} - name: 'cache ngtcp2 boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-ngtcp2-boringssl env: cache-name: cache-ngtcp2-boringssl @@ -159,7 +159,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.BORINGSSL_VERSION }} - name: 'cache nghttp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-nghttp2 env: cache-name: cache-nghttp2 @@ -518,7 +518,7 @@ jobs: - name: 'cache openssl' if: ${{ matrix.build.name == 'openssl' || matrix.build.name == 'openssl-quic' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-openssl-http3 env: cache-name: cache-openssl-http3 @@ -528,7 +528,7 @@ jobs: fail-on-cache-miss: true - name: 'cache libressl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-libressl env: cache-name: cache-libressl @@ -538,7 +538,7 @@ jobs: fail-on-cache-miss: true - name: 'cache awslc' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-awslc env: cache-name: cache-awslc @@ -548,7 +548,7 @@ jobs: fail-on-cache-miss: true - name: 'cache boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-boringssl env: cache-name: cache-boringssl @@ -558,7 +558,7 @@ jobs: fail-on-cache-miss: true - name: 'cache quictls' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-quictls-no-deprecated env: cache-name: cache-quictls-no-deprecated @@ -569,7 +569,7 @@ jobs: - name: 'cache gnutls' if: ${{ matrix.build.name == 'gnutls' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-gnutls env: cache-name: cache-gnutls @@ -580,7 +580,7 @@ jobs: - name: 'cache wolfssl' if: ${{ matrix.build.name == 'wolfssl' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-wolfssl env: cache-name: cache-wolfssl @@ -590,7 +590,7 @@ jobs: fail-on-cache-miss: true - name: 'cache nghttp3' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-nghttp3 env: cache-name: cache-nghttp3 @@ -600,7 +600,7 @@ jobs: fail-on-cache-miss: true - name: 'cache ngtcp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-ngtcp2 env: cache-name: cache-ngtcp2 @@ -610,7 +610,7 @@ jobs: fail-on-cache-miss: true - name: 'cache ngtcp2 boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-ngtcp2-boringssl env: cache-name: cache-ngtcp2-boringssl @@ -620,7 +620,7 @@ jobs: fail-on-cache-miss: true - name: 'cache nghttp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-nghttp2 env: cache-name: cache-nghttp2 @@ -631,7 +631,7 @@ jobs: - name: 'cache quiche' if: ${{ matrix.build.name == 'quiche' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-quiche env: cache-name: cache-quiche diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 20a5849d4dbd..4f164382672a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -348,7 +348,7 @@ jobs: - name: 'cache libressl' if: ${{ contains(matrix.build.install_steps, 'libressl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-libressl env: cache-name: cache-libressl @@ -367,7 +367,7 @@ jobs: - name: 'cache wolfssl (all)' if: ${{ contains(matrix.build.install_steps, 'wolfssl-all') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-wolfssl-all env: cache-name: cache-wolfssl-all @@ -388,7 +388,7 @@ jobs: - name: 'cache wolfssl (opensslextra)' # does support `OPENSSL_COEXIST` if: ${{ contains(matrix.build.install_steps, 'wolfssl-opensslextra') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-wolfssl-opensslextra env: cache-name: cache-wolfssl-opensslextra @@ -409,7 +409,7 @@ jobs: - name: 'cache mbedtls' if: ${{ contains(matrix.build.install_steps, 'mbedtls') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-mbedtls env: cache-name: cache-mbedtls-threadsafe @@ -432,7 +432,7 @@ jobs: - name: 'cache openldap-static' if: ${{ contains(matrix.build.install_steps, 'openldap-static') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-openldap-static env: cache-name: cache-openldap-static @@ -452,7 +452,7 @@ jobs: - name: 'cache openssl (thread sanitizer)' if: ${{ contains(matrix.build.install_steps, 'openssl-tsan') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-openssl-tsan env: cache-name: cache-openssl-tsan @@ -471,7 +471,7 @@ jobs: - name: 'cache quictls' if: ${{ contains(matrix.build.install_steps, 'quictls') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-quictls env: cache-name: cache-quictls @@ -490,7 +490,7 @@ jobs: - name: 'cache awslc' if: ${{ contains(matrix.build.install_steps, 'awslc') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-awslc env: cache-name: cache-awslc @@ -511,7 +511,7 @@ jobs: - name: 'cache boringssl' if: ${{ contains(matrix.build.install_steps, 'boringssl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-boringssl env: cache-name: cache-boringssl @@ -532,7 +532,7 @@ jobs: - name: 'cache rustls' if: ${{ contains(matrix.build.install_steps, 'rustls') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-rustls env: cache-name: cache-rustls diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ee8cec7d70bb..c111eaf4193e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -110,7 +110,7 @@ jobs: - name: 'cache libressl' if: ${{ contains(matrix.build.install_steps, 'libressl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-libressl env: cache-name: cache-libressl diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d45979c05ac2..0f802b690257 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -62,7 +62,7 @@ jobs: run: perl --version | tee "$GITHUB_WORKSPACE"/perlversion - name: 'cache perl packages' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -433,7 +433,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' && matrix.sys != 'msys' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -570,7 +570,7 @@ jobs: ${{ matrix.install }} - name: 'cache compiler (gcc ${{ matrix.ver }}-${{ matrix.env }})' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-compiler with: path: D:\my-cache @@ -663,7 +663,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -1057,7 +1057,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs From 97e5a471e0d7a6ade6476c71801ae2a89961919b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 10:09:18 +0200 Subject: [PATCH 154/208] KNOWN_BUGS: Access violation sending client cert with SChannel It seems we can select between crashing or leaking sensitive files because Schannel is buggy. Closes #17626 Closes #18679 --- docs/KNOWN_BUGS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 1eb5716f8b94..3785d73aa49e 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -15,6 +15,7 @@ problems may have been fixed or changed somewhat since this was written. 2. TLS 2.1 IMAPS connection fails with Rustls error + 2.2 Access violation sending client cert with Schannel 2.5 Client cert handling with Issuer DN differs between backends 2.7 Client cert (MTLS) issues with Schannel 2.11 Schannel TLS 1.2 handshake bug in old Windows versions @@ -120,6 +121,14 @@ problems may have been fixed or changed somewhat since this was written. https://github.com/curl/curl/issues/10457 +2.2 Access violation sending client cert with Schannel + + When using Schannel to do client certs, curl sets PKCS12_NO_PERSIST_KEY to + avoid leaking the private key into the filesystem. Unfortunately that flag + instead seems to trigger a crash. + + See https://github.com/curl/curl/issues/17626 + 2.5 Client cert handling with Issuer DN differs between backends When the specified client certificate does not match any of the From 0f1657ca75fcca4dbdbccf31d9d6cf4fae4a98e5 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 11:27:27 +0200 Subject: [PATCH 155/208] mbedtls: handle WANT_WRITE from mbedtls_ssl_read() The mbedtls_ssl_read() function is documented to be able to also return MBEDTLS_ERR_SSL_WANT_WRITE, so act on that accordingly instead of returning error for it. Assisted-by: Stefan Eissing Reported in Joshua's sarif data Closes #18682 --- lib/vtls/mbedtls.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index a8abd0fe09a5..0a62da2b58bf 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -1113,8 +1113,9 @@ static CURLcode mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, int nwritten; (void)data; - *pnwritten = 0; DEBUGASSERT(backend); + *pnwritten = 0; + connssl->io_need = CURL_SSL_IO_NEED_NONE; /* mbedtls is picky when a mbedtls_ssl_write) was previously blocked. * It requires to be called with the same amount of bytes again, or it * will lose bytes, e.g. reporting all was sent but they were not. @@ -1135,11 +1136,22 @@ static CURLcode mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, else { CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X", len, -nwritten); - result = ((nwritten == MBEDTLS_ERR_SSL_WANT_WRITE) + switch(nwritten) { #ifdef MBEDTLS_SSL_PROTO_TLS1_3 - || (nwritten == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) + case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET: #endif - ) ? CURLE_AGAIN : CURLE_SEND_ERROR; + case MBEDTLS_ERR_SSL_WANT_READ: + connssl->io_need = CURL_SSL_IO_NEED_RECV; + result = CURLE_AGAIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + connssl->io_need = CURL_SSL_IO_NEED_SEND; + result = CURLE_AGAIN; + break; + default: + result = CURLE_SEND_ERROR; + break; + } if((result == CURLE_AGAIN) && !backend->send_blocked) { backend->send_blocked = TRUE; backend->send_blocked_len = len; @@ -1280,6 +1292,7 @@ static CURLcode mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, (void)data; DEBUGASSERT(backend); *pnread = 0; + connssl->io_need = CURL_SSL_IO_NEED_NONE; nread = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, buffersize); if(nread > 0) @@ -1294,6 +1307,11 @@ static CURLcode mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, FALLTHROUGH(); #endif case MBEDTLS_ERR_SSL_WANT_READ: + connssl->io_need = CURL_SSL_IO_NEED_RECV; + result = CURLE_AGAIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + connssl->io_need = CURL_SSL_IO_NEED_SEND; result = CURLE_AGAIN; break; case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: From aaa39873ea7cd2a5031cfaa16b54fa3b09af7ff1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 08:45:53 +0200 Subject: [PATCH 156/208] socks_gssapi: make the gss_context a local variable Reported-by: Stanislav Fort Closes #18711 --- lib/socks_gssapi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 037515e576f6..b6530d5d7d55 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -49,8 +49,6 @@ #define MAX_GSS_LEN 1024 -static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; - /* * Helper GSS-API error functions. */ @@ -134,6 +132,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; const size_t serviceptr_length = strlen(serviceptr); + gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; + /* GSS-API request looks like * +----+------+-----+----------------+ From 98dae1d992aa1b048230f9d4934aefe8128b2f6c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 23:34:37 +0200 Subject: [PATCH 157/208] socks_gssapi: remove the forced "no protection" If a protected connection is requested, don't claim to drop down to "no protection". Reported in Joshua's sarif data Closes #18712 --- lib/socks_gssapi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index b6530d5d7d55..0aa6f7245fe3 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -359,8 +359,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, infof(data, "SOCKS5 server supports GSS-API %s data protection.", (gss_enc == 0) ? "no" : ((gss_enc == 1) ? "integrity" : "confidentiality")); - /* force for the moment to no data protection */ - gss_enc = 0; + /* * Sending the encryption type in clear seems wrong. It should be * protected with gss_seal()/gss_wrap(). See RFC1961 extract below From 7f38bf51ad42506b5e4bf3a4c8ad6075a61b566b Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Thu, 25 Sep 2025 01:14:19 +0200 Subject: [PATCH 158/208] OS400: fix a use-after-free/double-free case Closes #18713 --- packages/OS400/ccsidcurl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/OS400/ccsidcurl.c b/packages/OS400/ccsidcurl.c index 101cf9024705..b40367fd960b 100644 --- a/packages/OS400/ccsidcurl.c +++ b/packages/OS400/ccsidcurl.c @@ -1246,6 +1246,7 @@ curl_easy_setopt_ccsid(CURL *easy, CURLoption tag, ...) data->set.postfieldsize = pfsize; /* Replace data size. */ s = cp; + cp = NULL; } result = curl_easy_setopt(easy, CURLOPT_POSTFIELDS, s); From 7d5f8be532c19ec73063aaa4f27057047bdae5ac Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 17:22:52 +0200 Subject: [PATCH 159/208] GHA: use pip `requirements.txt` with pins, and more venv - requirements.txt: shorten copyright headers. - requirements.txt: pin packages to versions. - GHA/windows: use `tests/requirements.txt`. Pick a `cryptography` package version that satifies both `impacket` and pytests dependencies. - GHA/checksrc: move pip deps into a new `requirements.txt`. To make Dependabot detect and bump them. - GHA/checksrc: replace apt packages for python test deps with pip install `tests/**/requirements.txt` to a venv. - GHA/checksrc: use venv and drop `--break-system-packages`. - GHA/linux: fix to actually activate venvs. Follow-up to 2638570241cb9e68240d7621f0213916334a4765 #15578 - GHA/linux: fixup (did not cause an issue) Follow-up to d75785c7dea214d12525beb659694d3fcc483731 #18660 - GHA: create venvs later, simplify commands. - GHA: sync pip command-line options, e.g. drop progress-bar, everywhere. Assisted-by: Dan Fandrich Closes #18708 --- .github/scripts/requirements.txt | 8 +++++++ .github/workflows/checksrc.yml | 27 +++++++++++++----------- .github/workflows/http3-linux.yml | 9 ++++---- .github/workflows/linux.yml | 18 ++++++++-------- .github/workflows/macos.yml | 7 +++---- .github/workflows/windows.yml | 4 ++-- tests/http/requirements.txt | 35 +++++++------------------------ tests/requirements.txt | 25 ++-------------------- 8 files changed, 50 insertions(+), 83 deletions(-) create mode 100644 .github/scripts/requirements.txt diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt new file mode 100644 index 000000000000..f94a9d93a8bd --- /dev/null +++ b/.github/scripts/requirements.txt @@ -0,0 +1,8 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +cmakelang == 0.6.13 +codespell == 2.4.1 +pytype == 2024.10.11 +ruff == 0.11.9 diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index a0ff120becb3..5aca2f941a78 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -55,18 +55,15 @@ jobs: env: DEBIAN_FRONTEND: noninteractive run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo apt-get -o Dpkg::Use-Pty=0 update - sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install \ - python3-pip python3-networkx python3-pydot python3-yaml \ - python3-toml python3-markupsafe python3-jinja2 python3-tabulate \ - python3-typing-extensions python3-libcst python3-impacket \ - python3-websockets python3-pytest python3-filelock python3-pytest-xdist - python3 -m pip install --break-system-packages cmakelang==0.6.13 pytype==2024.10.11 ruff==0.11.9 codespell==2.4.1 + python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary \ + -r .github/scripts/requirements.txt \ + -r tests/http/requirements.txt \ + -r tests/requirements.txt - name: 'codespell' run: | + source ~/venv/bin/activate codespell --version .github/scripts/codespell.sh @@ -78,13 +75,19 @@ jobs: .github/scripts/typos.sh - name: 'cmakelint' - run: scripts/cmakelint.sh + run: | + source ~/venv/bin/activate + scripts/cmakelint.sh - name: 'pytype' - run: find . -name '*.py' -exec pytype -j auto -k {} + + run: | + source ~/venv/bin/activate + find . -name '*.py' -exec pytype -j auto -k {} + - name: 'ruff' - run: scripts/pythonlint.sh + run: | + source ~/venv/bin/activate + scripts/pythonlint.sh reuse: name: 'REUSE' diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 61164913ad28..019790b68e5d 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -512,7 +512,6 @@ jobs: libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libidn2-0-dev libldap-dev libuv1-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} - python3 -m venv ~/venv echo 'CC=gcc-12' >> "$GITHUB_ENV" echo 'CXX=g++-12' >> "$GITHUB_ENV" @@ -726,8 +725,8 @@ jobs: - name: 'install test prereqs' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} run: | - source ~/venv/bin/activate - python3 -m pip install -r tests/requirements.txt + python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt - name: 'run tests' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} @@ -744,8 +743,8 @@ jobs: - name: 'install pytest prereqs' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} run: | - source ~/venv/bin/activate - python3 -m pip install -r tests/http/requirements.txt + [ -d ~/venv ] || python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/http/requirements.txt - name: 'run pytest event based' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 4f164382672a..556ff8df1ec9 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -321,8 +321,9 @@ jobs: libpsl-dev zlib1g-dev libbrotli-dev libzstd-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} - [ -n "${INSTALL_PACKAGES_BREW}" ] && /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} - python3 -m venv ~/venv + if [ -n "${INSTALL_PACKAGES_BREW}" ]; then + /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} + fi - name: 'install prereqs' if: ${{ contains(matrix.build.name, 'i686') }} @@ -335,7 +336,6 @@ jobs: libtool autoconf automake pkgconf stunnel4 \ libpsl-dev:i386 libbrotli-dev:i386 libzstd-dev:i386 \ ${MATRIX_INSTALL_PACKAGES} - python3 -m venv ~/venv - name: 'install dependencies' if: ${{ startsWith(matrix.build.container, 'alpine') }} @@ -657,8 +657,8 @@ jobs: - name: 'install test prereqs' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && matrix.build.container == null }} run: | - [ -x ~/venv/bin/activate ] && source ~/venv/bin/activate - python3 -m pip install -r tests/requirements.txt + python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt - name: 'run tests' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} @@ -675,7 +675,7 @@ jobs: fi fi fi - [ -x ~/venv/bin/activate ] && source ~/venv/bin/activate + [ -f ~/venv/bin/activate ] && source ~/venv/bin/activate if [[ "${MATRIX_INSTALL_STEPS}" = *'codeset-test'* ]]; then locale || true export LC_ALL=C @@ -691,8 +691,8 @@ jobs: - name: 'install pytest prereqs' if: ${{ contains(matrix.build.install_steps, 'pytest') }} run: | - [ -x ~/venv/bin/activate ] && source ~/venv/bin/activate - python3 -m pip install -r tests/http/requirements.txt + [ -d ~/venv ] || python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/http/requirements.txt - name: 'run pytest' if: ${{ contains(matrix.build.install_steps, 'pytest') }} @@ -700,7 +700,7 @@ jobs: PYTEST_ADDOPTS: '--color=yes' PYTEST_XDIST_AUTO_NUM_WORKERS: 4 run: | - [ -x ~/venv/bin/activate ] && source ~/venv/bin/activate + [ -f ~/venv/bin/activate ] && source ~/venv/bin/activate if [ "${MATRIX_BUILD}" = 'cmake' ]; then cmake --build bld --verbose --target curl-pytest-ci else diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index c111eaf4193e..88b7ee880062 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -489,8 +489,7 @@ jobs: if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} run: | python3 -m venv ~/venv - source ~/venv/bin/activate - python3 -m pip install -r tests/requirements.txt + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt - name: 'run tests' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} @@ -517,8 +516,8 @@ jobs: - name: 'install pytest prereqs' if: ${{ contains(matrix.build.install_steps, 'pytest') }} run: | - source ~/venv/bin/activate - python3 -m pip install -r tests/http/requirements.txt + [ -d ~/venv ] || python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/http/requirements.txt - name: 'run pytest' if: ${{ contains(matrix.build.install_steps, 'pytest') }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0f802b690257..e5d66ccc87fc 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -658,7 +658,7 @@ jobs: timeout-minutes: 5 run: | /c/ProgramData/chocolatey/choco.exe install --yes --no-progress --limit-output --timeout 180 --force stunnel || true - python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary impacket + python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt perl --version | tee "$GITHUB_WORKSPACE"/perlversion - name: 'cache perl packages' @@ -1051,7 +1051,7 @@ jobs: fi /c/ProgramData/chocolatey/choco.exe install --yes --no-progress --limit-output --timeout 180 --force stunnel || true if [ "${MATRIX_IMAGE}" != 'windows-11-arm' ]; then # save 30-60 seconds, to counteract the slower test run step - python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary impacket + python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt fi perl --version | tee "$GITHUB_WORKSPACE"/perlversion diff --git a/tests/http/requirements.txt b/tests/http/requirements.txt index c87960560864..8dddcd1e1c24 100644 --- a/tests/http/requirements.txt +++ b/tests/http/requirements.txt @@ -1,31 +1,10 @@ -# -*- coding: utf-8 -*- -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# # Copyright (C) Daniel Stenberg, , 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 -# -########################################################################### -# -pytest -cryptography -filelock -websockets -psutil -pytest-xdist + +cryptography == 42.0.8 +filelock == 3.19.1 +psutil == 7.1.0 +pytest == 8.4.2 +pytest-xdist == 3.8.0 +websockets == 15.0.1 diff --git a/tests/requirements.txt b/tests/requirements.txt index 706043ac395f..dab4784c5fa1 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,26 +1,5 @@ -# -*- coding: utf-8 -*- -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# # Copyright (C) Daniel Stenberg, , 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 -# -########################################################################### -# -impacket + +impacket == 0.12.0 From c9fce97dcb190eac5591ecab683d49ffd30b1c71 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 10:42:24 +0200 Subject: [PATCH 160/208] cf-h2-proxy: break loop on edge case nghttp2 always consumes the memory, but be safe in case it ever decideds to not to. Fixes J2 Reported in Joshua's sarif data Closes #18715 --- lib/cf-h2-proxy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index d67bbd55adfb..17a15c1d2ada 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -433,6 +433,11 @@ static int proxy_h2_process_pending_input(struct Curl_cfilter *cf, *err = CURLE_RECV_ERROR; return -1; } + else if(!rv) { + /* nghttp2 does not want to process more, but has no error. This + * probably cannot happen, but be safe. */ + break; + } Curl_bufq_skip(&ctx->inbufq, (size_t)rv); if(Curl_bufq_is_empty(&ctx->inbufq)) { CURL_TRC_CF(data, cf, "[0] all data in connection buffer processed"); From 20d1c6e92ebb19a78e9b6848a210cac15cc14540 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 10:35:40 +0200 Subject: [PATCH 161/208] socks_gssapi: remove superfluous releases of the gss_recv_token Reported in Joshua's sarif data Closes #18714 --- lib/socks_gssapi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 0aa6f7245fe3..a88b6f7b75f7 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -199,7 +199,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, /* the size needs to fit in a 16 bit field */ (gss_send_token.length > 0xffff)) { gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to initial GSS-API token."); @@ -217,7 +216,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(code || (nwritten != 4)) { failf(data, "Failed to send GSS-API authentication request."); gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -229,7 +227,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(code || (gss_send_token.length != nwritten)) { failf(data, "Failed to send GSS-API authentication token."); gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -238,7 +235,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } gss_release_buffer(&gss_status, &gss_send_token); - gss_release_buffer(&gss_status, &gss_recv_token); if(gss_major_status != GSS_S_CONTINUE_NEEDED) break; From 8e13e4258373e8f58f269f62f38637302a46f8f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 08:48:20 +0000 Subject: [PATCH 162/208] GHA: update dependency ruff to v0.13.1 --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index f94a9d93a8bd..dd66a5ef454d 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,4 +5,4 @@ cmakelang == 0.6.13 codespell == 2.4.1 pytype == 2024.10.11 -ruff == 0.11.9 +ruff == 0.13.1 From 6796147910168476a5ca9c22fbf297e544b577a7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 11:53:47 +0200 Subject: [PATCH 163/208] GHA/checksrc: run `reuse` directly, merge into the linters workflow To eliminate dependencies on an Action, Docker Hub and to simplify. Closes #18721 --- .github/scripts/requirements.txt | 1 + .github/workflows/checksrc.yml | 20 +++++++------------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index dd66a5ef454d..5e876b0cb2b8 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,4 +5,5 @@ cmakelang == 0.6.13 codespell == 2.4.1 pytype == 2024.10.11 +reuse == 5.1.1 ruff == 0.13.1 diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 5aca2f941a78..59fc930fa76d 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -43,8 +43,8 @@ jobs: - name: 'check' run: scripts/checksrc-all.pl - spellcheck-cmakelint-pytype-ruff: - name: 'spellcheck, cmakelint, pytype, ruff' + linters: + name: 'spellcheck, linters, REUSE' runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 @@ -61,6 +61,11 @@ jobs: -r tests/http/requirements.txt \ -r tests/requirements.txt + - name: 'REUSE check' + run: | + source ~/venv/bin/activate + reuse lint + - name: 'codespell' run: | source ~/venv/bin/activate @@ -89,17 +94,6 @@ jobs: source ~/venv/bin/activate scripts/pythonlint.sh - reuse: - name: 'REUSE' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - persist-credentials: false - - - name: 'check' - uses: fsfe/reuse-action@bb774aa972c2a89ff34781233d275075cbddf542 # v5 - complexity: name: 'complexity' runs-on: ubuntu-latest From 943166fed3d1b8ce6a73b6a1de5de5338dda1428 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 11:30:24 +0200 Subject: [PATCH 164/208] socks_sspi: bail out on too long fields A probably unnecessary precaution but since the field sizes are 16 bit in the protocol this makes sure to fail if they would ever be larger as that would go wrong. Reported in Joshua's sarif data Closes #18719 --- lib/socks_sspi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 6afc3eac3481..16e22d1f39f5 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -193,6 +193,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(sspi_send_token.cbBuffer) { socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 1; /* authentication message type */ + if(sspi_send_token.cbBuffer > 0xffff) { + /* needs to fit in an unsigned 16 bit field */ + result = CURLE_COULDNT_CONNECT; + goto error; + } us_length = htons((unsigned short)sspi_send_token.cbBuffer); memcpy(socksreq + 2, &us_length, sizeof(short)); @@ -399,9 +404,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, goto error; } - etbuf_size = sspi_w_token[0].cbBuffer + - sspi_w_token[1].cbBuffer + - sspi_w_token[2].cbBuffer; + etbuf_size = sspi_w_token[0].cbBuffer + sspi_w_token[1].cbBuffer + + sspi_w_token[2].cbBuffer; + if(etbuf_size > 0xffff) { + /* needs to fit in an unsigned 16 bit field */ + result = CURLE_COULDNT_CONNECT; + goto error; + } etbuf = malloc(etbuf_size); if(!etbuf) { result = CURLE_OUT_OF_MEMORY; From b3fc692568ad3f01528e726223126e3fe870b1c1 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 8 Aug 2025 12:15:25 +0200 Subject: [PATCH 165/208] lib: upgrade/multiplex handling Improvements around HTTP Upgrade: and multiplex hanndling: * add `Curl_conn_set_multiplex()` to set connection's multiplex bit and trigger "connchanged" events * call `Curl_conn_set_multiplex()` in filters' `CF_CTRL_CONN_INFO_UPDATE` implementation where other connection properties are updated. This prevents connection updates before the final filter chain is chosen. * rename enum `UPGR101_INIT` to `UPGR101_NONE` * rename connection bit `asks_multiplex` to `upgrade_in_progress` * trigger "connchanged" when `upgrade_in_progress` clears * rename `WebSockets` to `WebSocket` as it is the common term used in documentation Closes #18227 --- lib/connect.c | 10 ++++++ lib/connect.h | 3 ++ lib/curl_config.h.cmake | 2 +- lib/http.c | 71 ++++++++++++++++++++++------------------- lib/http2.c | 27 +++++++++------- lib/request.c | 2 +- lib/request.h | 7 ++-- lib/url.c | 5 +-- lib/urldata.h | 2 +- lib/vquic/curl_ngtcp2.c | 5 +-- lib/vquic/curl_osslq.c | 7 ++-- lib/vquic/curl_quiche.c | 7 ++-- lib/ws.c | 7 ++-- 13 files changed, 90 insertions(+), 65 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index f0628d6206ed..1182a42d31fa 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -621,3 +621,13 @@ CURLcode Curl_conn_setup(struct Curl_easy *data, Curl_resolv_unlink(data, &data->state.dns[sockindex]); return result; } + +void Curl_conn_set_multiplex(struct connectdata *conn) +{ + if(!conn->bits.multiplex) { + conn->bits.multiplex = TRUE; + if(conn->attached_multi) { + Curl_multi_connchanged(conn->attached_multi); + } + } +} diff --git a/lib/connect.h b/lib/connect.h index 6a2487ff5383..cb185b2c571b 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -123,6 +123,9 @@ CURLcode Curl_conn_setup(struct Curl_easy *data, struct Curl_dns_entry *dns, int ssl_mode); +/* Set conn to allow multiplexing. */ +void Curl_conn_set_multiplex(struct connectdata *conn); + extern struct Curl_cftype Curl_cft_setup; #endif /* HEADER_CURL_CONNECT_H */ diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 30183c20092f..bc8c1cd487cc 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -148,7 +148,7 @@ /* disables SMTP */ #cmakedefine CURL_DISABLE_SMTP 1 -/* disabled WebSockets */ +/* disabled WebSocket */ #cmakedefine CURL_DISABLE_WEBSOCKETS 1 /* disables use of socketpair for curl_multi_poll */ diff --git a/lib/http.c b/lib/http.c index e01de6f4772c..ce31e6dff005 100644 --- a/lib/http.c +++ b/lib/http.c @@ -2289,7 +2289,7 @@ static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r, *announced_exp100 = FALSE; /* Avoid Expect: 100-continue if Upgrade: is used */ - if(data->req.upgr101 != UPGR101_INIT) + if(data->req.upgr101 != UPGR101_NONE) return CURLE_OK; /* For really small puts we do not use Expect: headers at all, and for @@ -2622,6 +2622,7 @@ static CURLcode http_check_new_conn(struct Curl_easy *data) info_version = "HTTP/2"; /* There is no ALPN here, but the connection is now definitely h2 */ conn->httpversion_seen = 20; + Curl_conn_set_multiplex(conn); } else info_version = "HTTP/1.x"; @@ -3571,10 +3572,6 @@ static CURLcode http_statusline(struct Curl_easy *data, infof(data, "HTTP 1.0, assume close after body"); connclose(conn, "HTTP/1.0 close after body"); } - else if(k->httpversion == 20 || - (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) { - DEBUGF(infof(data, "HTTP/2 found, allow multiplexing")); - } k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200; switch(k->httpcode) { @@ -3717,6 +3714,7 @@ static CURLcode http_on_response(struct Curl_easy *data, struct connectdata *conn = data->conn; CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; + bool conn_changed = FALSE; (void)buf; /* not used without HTTP2 enabled */ *pconsumed = 0; @@ -3757,47 +3755,54 @@ static CURLcode http_on_response(struct Curl_easy *data, */ http_exp100_got100(data); break; - case 101: - /* Switching Protocols only allowed from HTTP/1.1 */ + case 101: { + int upgr101_requested = k->upgr101; + if(k->httpversion_sent != 11) { /* invalid for other HTTP versions */ - failf(data, "unexpected 101 response code"); + failf(data, "server sent 101 response while not talking HTTP/1.1"); result = CURLE_WEIRD_SERVER_REPLY; goto out; } - if(k->upgr101 == UPGR101_H2) { - /* Switching to HTTP/2, where we will get more responses */ + + /* Whatever the success, upgrade was selected. */ + k->upgr101 = UPGR101_RECEIVED; + data->conn->bits.upgrade_in_progress = FALSE; + conn_changed = TRUE; + + /* To be fully conform, we would check the "Upgrade:" response header + * to mention the protocol we requested. */ + switch(upgr101_requested) { + case UPGR101_H2: + /* Switch to HTTP/2, where we will get more responses. + * blen bytes in bug are already h2 protocol bytes */ infof(data, "Received 101, Switching to HTTP/2"); - k->upgr101 = UPGR101_RECEIVED; - data->conn->bits.asks_multiplex = FALSE; - /* We expect more response from HTTP/2 later */ - k->header = TRUE; - k->headerline = 0; /* restart the header line counter */ - k->httpversion_sent = 20; /* It's an HTTP/2 request now */ - /* Any remaining `buf` bytes are already HTTP/2 and passed to - * be processed. */ result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen); if(result) goto out; *pconsumed += blen; - } + break; #ifndef CURL_DISABLE_WEBSOCKETS - else if(k->upgr101 == UPGR101_WS) { - /* verify the response. Any passed `buf` bytes are already in - * WebSockets format and taken in by the protocol handler. */ + case UPGR101_WS: + /* Switch to WebSocket, where we now stream ws frames. + * blen bytes in bug are already ws protocol bytes */ + infof(data, "Received 101, Switching to WebSocket"); result = Curl_ws_accept(data, buf, blen); if(result) goto out; *pconsumed += blen; /* ws accept handled the data */ - } + break; #endif - else { + default: /* We silently accept this as the final response. What are we * switching to if we did not ask for an Upgrade? Maybe the * application provided an `Upgrade: xxx` header? */ k->header = FALSE; + break; } + /* processed 101 */ break; + } default: /* The server may send us other 1xx responses, like informative * 103. This have no influence on request processing and we expect @@ -3809,12 +3814,10 @@ static CURLcode http_on_response(struct Curl_easy *data, /* k->httpcode >= 200, final response */ k->header = FALSE; - - if(k->upgr101 == UPGR101_H2) { - /* A requested upgrade was denied, poke the multi handle to possibly - allow a pending pipewait to continue */ - data->conn->bits.asks_multiplex = FALSE; - Curl_multi_connchanged(data->multi); + if(data->conn->bits.upgrade_in_progress) { + /* Asked for protocol upgrade, but it was not selected by the server */ + data->conn->bits.upgrade_in_progress = FALSE; + conn_changed = TRUE; } if((k->size == -1) && !k->chunk && !conn->bits.close && @@ -3863,9 +3866,9 @@ static CURLcode http_on_response(struct Curl_easy *data, #endif #ifndef CURL_DISABLE_WEBSOCKETS - /* All >=200 HTTP status codes are errors when wanting WebSockets */ + /* All >=200 HTTP status codes are errors when wanting WebSocket */ if(data->req.upgr101 == UPGR101_WS) { - failf(data, "Refused WebSockets upgrade: %d", k->httpcode); + failf(data, "Refused WebSocket upgrade: %d", k->httpcode); result = CURLE_HTTP_RETURNED_ERROR; goto out; } @@ -3985,6 +3988,10 @@ static CURLcode http_on_response(struct Curl_easy *data, result = Curl_1st_err( result, http_write_header(data, last_hd, last_hd_len)); } + if(conn_changed) { + /* poke the multi handle to allow any pending pipewait to retry now */ + Curl_multi_connchanged(data->multi); + } return result; } diff --git a/lib/http2.c b/lib/http2.c index e2cdc9181f5f..c526bf0fa4c3 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -1829,7 +1829,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, free(base64); k->upgr101 = UPGR101_H2; - data->conn->bits.asks_multiplex = TRUE; + data->conn->bits.upgrade_in_progress = TRUE; return result; } @@ -2696,6 +2696,12 @@ static CURLcode cf_h2_cntrl(struct Curl_cfilter *cf, case CF_CTRL_DATA_DONE: http2_data_done(cf, data); break; + case CF_CTRL_CONN_INFO_UPDATE: + if(!cf->sockindex && cf->connected) { + cf->conn->httpversion_seen = 20; + Curl_conn_set_multiplex(cf->conn); + } + break; default: break; } @@ -2895,9 +2901,6 @@ CURLcode Curl_http2_switch(struct Curl_easy *data) return result; CURL_TRC_CF(data, cf, "switching connection to HTTP/2"); - data->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - Curl_multi_connchanged(data->multi); - if(cf->next) { bool done; return Curl_conn_cf_connect(cf, data, &done); @@ -2917,8 +2920,6 @@ CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data) return result; cf_h2 = cf->next; - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - Curl_multi_connchanged(data->multi); if(cf_h2->next) { bool done; @@ -2936,7 +2937,6 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, CURLcode result; DEBUGASSERT(Curl_conn_http_version(data, conn) < 20); - DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED); result = http2_cfilter_add(&cf, data, conn, sockindex, TRUE); if(result) @@ -2946,6 +2946,10 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, DEBUGASSERT(cf->cft == &Curl_cft_nghttp2); ctx = cf->ctx; + data->req.httpversion_sent = 20; /* it is an h2 request now */ + data->req.header = TRUE; /* we expect the real response to come in h2 */ + data->req.headerline = 0; /* restart the header line counter */ + if(nread > 0) { /* Remaining data from the protocol switch reply is already using * the switched protocol, ie. HTTP/2. We add that to the network @@ -2968,14 +2972,13 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, " after upgrade: len=%zu", nread); } - conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - Curl_multi_connchanged(data->multi); - if(cf->next) { bool done; - return Curl_conn_cf_connect(cf, data, &done); + result = Curl_conn_cf_connect(cf, data, &done); + if(!result) + cf->cft->cntrl(cf, data, CF_CTRL_CONN_INFO_UPDATE, 0, NULL); } - return CURLE_OK; + return result; } /* Only call this function for a transfer that already got an HTTP/2 diff --git a/lib/request.c b/lib/request.c index 8751ada55987..2d5ad9521209 100644 --- a/lib/request.c +++ b/lib/request.c @@ -139,7 +139,7 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data) req->offset = 0; req->httpcode = 0; req->keepon = 0; - req->upgr101 = UPGR101_INIT; + req->upgr101 = UPGR101_NONE; req->sendbuf_hds_len = 0; req->timeofdoc = 0; req->location = NULL; diff --git a/lib/request.h b/lib/request.h index bce34de8ba9e..e12d5efdcb23 100644 --- a/lib/request.h +++ b/lib/request.h @@ -42,11 +42,10 @@ enum expect100 { }; enum upgrade101 { - UPGR101_INIT, /* default state */ - UPGR101_WS, /* upgrade to WebSockets requested */ + UPGR101_NONE, /* default state */ + UPGR101_WS, /* upgrade to WebSocket requested */ UPGR101_H2, /* upgrade to HTTP/2 requested */ - UPGR101_RECEIVED, /* 101 response received */ - UPGR101_WORKING /* talking upgraded protocol */ + UPGR101_RECEIVED /* 101 response received */ }; diff --git a/lib/url.c b/lib/url.c index 6af2b7fb8b75..41a63890e6ef 100644 --- a/lib/url.c +++ b/lib/url.c @@ -907,8 +907,8 @@ static bool url_match_fully_connected(struct connectdata *conn, struct url_conn_match *m) { if(!Curl_conn_is_connected(conn, FIRSTSOCKET) || - conn->bits.asks_multiplex) { - /* Not yet connected, or not yet decided if it multiplexes. The later + conn->bits.upgrade_in_progress) { + /* Not yet connected, or a protocol upgrade is in progress. The later * happens for HTTP/2 Upgrade: requests that need a response. */ if(m->may_multiplex) { m->seen_pending_conn = TRUE; @@ -1268,6 +1268,7 @@ static bool url_match_conn(struct connectdata *conn, void *userdata) if(!url_match_connect_config(conn, m)) return FALSE; + /* match for destination and protocol? */ if(!url_match_destination(conn, m)) return FALSE; diff --git a/lib/urldata.h b/lib/urldata.h index b2e83c4a0eef..3c7e634b0008 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -389,7 +389,7 @@ struct ConnectBits { #endif BIT(bound); /* set true if bind() has already been done on this socket/ connection */ - BIT(asks_multiplex); /* connection asks for multiplexing, but is not yet */ + BIT(upgrade_in_progress); /* protocol upgrade is in progress */ BIT(multiplex); /* connection is multiplexed */ BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index f902c190ef58..0e05694992a0 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -464,7 +464,6 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) ctx->handshake_at = curlx_now(); ctx->tls_handshake_complete = TRUE; - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ Curl_vquic_report_handshake(&ctx->tls, cf, data); ctx->tls_vrfy_result = Curl_vquic_tls_verify_peer(&ctx->tls, cf, @@ -1989,8 +1988,10 @@ static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, break; } case CF_CTRL_CONN_INFO_UPDATE: - if(!cf->sockindex && cf->connected) + if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; + Curl_conn_set_multiplex(cf->conn); + } break; default: break; diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index c292072a65b6..5e9b0727360b 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -564,9 +564,6 @@ static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_osslq_ctx *ctx = cf->ctx; - - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); } @@ -2205,8 +2202,10 @@ static CURLcode cf_osslq_cntrl(struct Curl_cfilter *cf, break; } case CF_CTRL_CONN_INFO_UPDATE: - if(!cf->sockindex && cf->connected) + if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; + Curl_conn_set_multiplex(cf->conn); + } break; default: break; diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index b88b4e97bd3d..523f04e33bd9 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1234,8 +1234,10 @@ static CURLcode cf_quiche_cntrl(struct Curl_cfilter *cf, break; } case CF_CTRL_CONN_INFO_UPDATE: - if(!cf->sockindex && cf->connected) + if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; + Curl_conn_set_multiplex(cf->conn); + } break; default: break; @@ -1350,9 +1352,6 @@ static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_quiche_ctx *ctx = cf->ctx; - - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); } diff --git a/lib/ws.c b/lib/ws.c index b6ab28a35ad0..6a265fccc700 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -582,7 +582,7 @@ static void update_meta(struct websocket *ws, ws->recvframe.bytesleft = bytesleft; } -/* WebSockets decoding client writer */ +/* WebSocket decoding client writer */ struct ws_cw_ctx { struct Curl_cwriter super; struct bufq buf; @@ -1268,6 +1268,7 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req) } data->state.http_hd_upgrade = TRUE; k->upgr101 = UPGR101_WS; + data->conn->bits.upgrade_in_progress = TRUE; return result; } @@ -1359,6 +1360,8 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, goto out; ws_dec_writer = NULL; /* owned by transfer now */ + k->header = FALSE; /* we will not get more response headers */ + if(data->set.connect_only) { size_t nwritten; /* In CONNECT_ONLY setup, the payloads from `mem` need to be received @@ -1806,7 +1809,7 @@ CURLcode curl_ws_send(CURL *d, const void *buffer_arg, static CURLcode ws_setup_conn(struct Curl_easy *data, struct connectdata *conn) { - /* WebSockets is 1.1 only (for now) */ + /* WebSocket is 1.1 only (for now) */ data->state.http_neg.accept_09 = FALSE; data->state.http_neg.only_10 = FALSE; data->state.http_neg.wanted = CURL_HTTP_V1x; From ccd2b03b0d32536c909ca056ba84216b3c5efaf5 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 26 Aug 2025 15:54:32 +0200 Subject: [PATCH 166/208] socks: rewwork, cleaning up socks state handling Restructured the code in the following ways: * add terminal states SUCCESS and FAILED * split SOCK4 and SOCK5 states to be more clear * use `bufq` for send/recv of SOCK messages * reduce SOCKS4 states, more speaking names * for most states, move code into static function * reduce SOCKS5 states, more speaking names * add helpers for traversing to FAILED state * add helper to flush bufq * add hepler to read minimum amount into bufq Closes #18401 --- lib/bufq.h | 2 +- lib/socks.c | 1755 +++++++++++++++++++++------------------- tests/libtest/lib564.c | 6 + 3 files changed, 950 insertions(+), 813 deletions(-) diff --git a/lib/bufq.h b/lib/bufq.h index 7cd1826a955c..ad8e6435fae1 100644 --- a/lib/bufq.h +++ b/lib/bufq.h @@ -225,7 +225,7 @@ typedef CURLcode Curl_bufq_reader(void *reader_ctx, size_t *pnread); /** - * Read date and append it to the end of the buffer queue until the + * Read bytes and append them to the end of the buffer queue until the * reader returns blocking or the queue is full. A reader returns * CURLE_AGAIN to indicate blocking. * Returns the total amount of buf read (may be 0) in `pnread` on success. diff --git a/lib/socks.c b/lib/socks.c index 4cb8619d7bd5..6927e32c3ecb 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -34,6 +34,7 @@ #endif #include "urldata.h" +#include "bufq.h" #include "sendf.h" #include "select.h" #include "cfilters.h" @@ -49,46 +50,74 @@ #include "curl_memory.h" #include "memdebug.h" +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +#define DEBUG_AND_VERBOSE +#endif + /* for the (SOCKS) connect state machine */ -enum connect_t { - CONNECT_INIT, - CONNECT_SOCKS_INIT, /* 1 */ - CONNECT_SOCKS_SEND, /* 2 waiting to send more first data */ - CONNECT_SOCKS_READ_INIT, /* 3 set up read */ - CONNECT_SOCKS_READ, /* 4 read server response */ - CONNECT_GSSAPI_INIT, /* 5 */ - CONNECT_AUTH_INIT, /* 6 setup outgoing auth buffer */ - CONNECT_AUTH_SEND, /* 7 send auth */ - CONNECT_AUTH_READ, /* 8 read auth response */ - CONNECT_REQ_INIT, /* 9 init SOCKS "request" */ - CONNECT_RESOLVING, /* 10 */ - CONNECT_RESOLVED, /* 11 */ - CONNECT_RESOLVE_REMOTE, /* 12 */ - CONNECT_REQ_SEND, /* 13 */ - CONNECT_REQ_SENDING, /* 14 */ - CONNECT_REQ_READ, /* 15 */ - CONNECT_REQ_READ_MORE, /* 16 */ - CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */ +enum socks_state_t { + SOCKS_ST_INIT, + /* SOCKS Version 4 states */ + SOCKS4_ST_START, + SOCKS4_ST_RESOLVING, + SOCKS4_ST_SEND, + SOCKS4_ST_RECV, + /* SOCKS Version 5 states */ + SOCKS5_ST_START, + SOCKS5_ST_REQ0_SEND, + SOCKS5_ST_RESP0_RECV, /* set up read */ + SOCKS5_ST_GSSAPI_INIT, + SOCKS5_ST_AUTH_INIT, /* setup outgoing auth buffer */ + SOCKS5_ST_AUTH_SEND, /* send auth */ + SOCKS5_ST_AUTH_RECV, /* read auth response */ + SOCKS5_ST_REQ1_INIT, /* init SOCKS "request" */ + SOCKS5_ST_RESOLVING, + SOCKS5_ST_REQ1_SEND, + SOCKS5_ST_RESP1_RECV, + /* Terminal states, all SOCKS versions */ + SOCKS_ST_SUCCESS, + SOCKS_ST_FAILED }; -#define CURL_SOCKS_BUF_SIZE 600 - -/* make sure we configure it not too low */ -#if CURL_SOCKS_BUF_SIZE < 600 -#error CURL_SOCKS_BUF_SIZE must be at least 600 +#ifdef DEBUG_AND_VERBOSE +static const char * const cf_socks_statename[] = { + "SOCKS_INIT", + "SOCKS4_START", + "SOCKS4_RESOLVING", + "SOCKS4_SEND", + "SOCKS4_RECV", + "SOCKS5_START", + "SOCKS5_REQ0_SEND", + "SOCKS5_RESP0_RECV", + "SOCKS5_GSSAPI_INIT", + "SOCKS5_AUTH_INIT", + "SOCKS5_AUTH_SEND", + "SOCKS5_AUTH_RECV", + "SOCKS5_REQ1_INIT", + "SOCKS5_RESOLVING", + "SOCKS5_REQ1_SEND", + "SOCKS5_RESP1_RECV", + "SOCKS_SUCCESS", + "SOCKS_FAILED" +}; #endif +#define SOCKS_CHUNK_SIZE 1024 +#define SOCKS_CHUNKS 1 -struct socks_state { - enum connect_t state; - size_t outstanding; /* send this many bytes more */ - unsigned char buffer[CURL_SOCKS_BUF_SIZE]; - unsigned char *outp; /* send from this pointer */ +struct socks_state { + enum socks_state_t state; + struct bufq iobuf; const char *hostname; int remote_port; const char *proxy_user; const char *proxy_password; + CURLproxycode presult; + unsigned char version; + BIT(resolve_local); + BIT(start_resolving); + BIT(socks4a); }; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) @@ -149,37 +178,13 @@ CURLcode Curl_blockread_all(struct Curl_cfilter *cf, static void socksstate(struct socks_state *sx, struct Curl_cfilter *cf, struct Curl_easy *data, - enum connect_t state + enum socks_state_t state #ifdef DEBUG_AND_VERBOSE , int lineno #endif ) { - enum connect_t oldstate = sx->state; -#ifdef DEBUG_AND_VERBOSE - /* synced with the state list in urldata.h */ - static const char * const socks_statename[] = { - "INIT", - "SOCKS_INIT", - "SOCKS_SEND", - "SOCKS_READ_INIT", - "SOCKS_READ", - "GSSAPI_INIT", - "AUTH_INIT", - "AUTH_SEND", - "AUTH_READ", - "REQ_INIT", - "RESOLVING", - "RESOLVED", - "RESOLVE_REMOTE", - "REQ_SEND", - "REQ_SENDING", - "REQ_READ", - "REQ_READ_MORE", - "DONE" - }; -#endif - + enum socks_state_t oldstate = sx->state; (void)cf; (void)data; if(oldstate == state) @@ -190,274 +195,209 @@ static void socksstate(struct socks_state *sx, #ifdef DEBUG_AND_VERBOSE CURL_TRC_CF(data, cf, "[%s] -> [%s] (line %d)", - socks_statename[oldstate], socks_statename[sx->state], lineno); + cf_socks_statename[oldstate], + cf_socks_statename[sx->state], lineno); #endif } -static CURLproxycode socks_state_send(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data, - CURLproxycode failcode, - const char *description) +static CURLproxycode socks_failed(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + CURLproxycode presult) +{ + sxstate(sx, cf, data, SOCKS_ST_FAILED); + sx->presult = presult; + return presult; +} + +static CURLproxycode socks_flush(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { - size_t nwritten; CURLcode result; + size_t nwritten; - result = Curl_conn_cf_send(cf->next, data, (char *)sx->outp, - sx->outstanding, FALSE, &nwritten); - if(result) { - if(CURLE_AGAIN == result) + *done = FALSE; + while(!Curl_bufq_is_empty(&sx->iobuf)) { + result = Curl_cf_send_bufq(cf->next, data, &sx->iobuf, NULL, 0, + &nwritten); + if(result == CURLE_AGAIN) return CURLPX_OK; - - failf(data, "Failed to send %s: %s", description, - curl_easy_strerror(result)); - return failcode; - } - else if(!nwritten) { - /* connection closed */ - failf(data, "connection to proxy closed"); - return CURLPX_CLOSED; + else if(result) { + failf(data, "Failed to send SOCKS request: %s", + curl_easy_strerror(result)); + return socks_failed(sx, cf, data, CURLPX_SEND_CONNECT); + } } - - DEBUGASSERT(sx->outstanding >= nwritten); - /* not done, remain in state */ - sx->outstanding -= nwritten; - sx->outp += nwritten; + *done = TRUE; return CURLPX_OK; } -static CURLproxycode socks_state_recv(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data, - CURLproxycode failcode, - const char *description) +static CURLproxycode socks_recv(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + size_t min_bytes, + bool *done) { - size_t nread; CURLcode result; + size_t nread; - result = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp, - sx->outstanding, &nread); - if(result) { - if(CURLE_AGAIN == result) + *done = FALSE; + while(Curl_bufq_len(&sx->iobuf) < min_bytes) { + result = Curl_cf_recv_bufq(cf->next, data, &sx->iobuf, + min_bytes - Curl_bufq_len(&sx->iobuf), + &nread); + if(result == CURLE_AGAIN) return CURLPX_OK; - - failf(data, "SOCKS: Failed receiving %s: %s", description, - curl_easy_strerror(result)); - return failcode; - } - else if(!nread) { - /* connection closed */ - failf(data, "connection to proxy closed"); - return CURLPX_CLOSED; + else if(result) { + failf(data, "Failed to receive SOCKS response: %s", + curl_easy_strerror(result)); + return CURLPX_RECV_CONNECT; + } + else if(!nread) /* EOF */ + break; } - /* remain in reading state */ - DEBUGASSERT(sx->outstanding >= nread); - sx->outstanding -= nread; - sx->outp += nread; + *done = TRUE; return CURLPX_OK; } -/* -* This function logs in to a SOCKS4 proxy and sends the specifics to the final -* destination server. -* -* Reference : -* https://www.openssh.com/txt/socks4.protocol -* -* Note : -* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" -* Nonsupport "Identification Protocol (RFC1413)" -*/ -static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data) +static CURLproxycode socks4_req_add_hd(struct socks_state *sx, + struct Curl_easy *data) { - struct connectdata *conn = cf->conn; - const bool protocol4a = - (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A); - unsigned char *socksreq = sx->buffer; + unsigned char buf[4]; + size_t nwritten; CURLcode result; - CURLproxycode presult; - struct Curl_dns_entry *dns = NULL; - - switch(sx->state) { - case CONNECT_SOCKS_INIT: - /* SOCKS4 can only do IPv4, insist! */ - conn->ip_version = CURL_IPRESOLVE_V4; - CURL_TRC_CF(data, cf, "SOCKS4%s communication to%s %s:%d", - protocol4a ? "a" : "", - conn->bits.httpproxy ? " HTTP proxy" : "", - sx->hostname, sx->remote_port); - /* - * Compose socks4 request - * - * Request format - * - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * | VN | CD | DSTPORT | DSTIP | USERID |NULL| - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * # of bytes: 1 1 2 4 variable 1 - */ + (void)data; + buf[0] = 4; /* version (SOCKS4) */ + buf[1] = 1; /* connect */ + buf[2] = (unsigned char)((sx->remote_port >> 8) & 0xffu); /* MSB */ + buf[3] = (unsigned char)(sx->remote_port & 0xffu); /* LSB */ + + result = Curl_bufq_write(&sx->iobuf, buf, 4, &nwritten); + if(result || (nwritten != 4)) + return CURLPX_SEND_REQUEST; + return CURLPX_OK; +} - socksreq[0] = 4; /* version (SOCKS4) */ - socksreq[1] = 1; /* connect */ - socksreq[2] = (unsigned char)((sx->remote_port >> 8) & 0xff); /* MSB */ - socksreq[3] = (unsigned char)(sx->remote_port & 0xff); /* LSB */ +static CURLproxycode socks4_req_add_user(struct socks_state *sx, + struct Curl_easy *data) +{ + CURLcode result; + size_t nwritten; - /* DNS resolve only for SOCKS4, not SOCKS4a */ - if(!protocol4a) { - result = Curl_resolv(data, sx->hostname, sx->remote_port, - cf->conn->ip_version, TRUE, &dns); - - if(result == CURLE_AGAIN) { - sxstate(sx, cf, data, CONNECT_RESOLVING); - CURL_TRC_CF(data, cf, "SOCKS4 non-blocking resolve of %s", - sx->hostname); - return CURLPX_OK; - } - else if(result) - return CURLPX_RESOLVE_HOST; - sxstate(sx, cf, data, CONNECT_RESOLVED); - goto CONNECT_RESOLVED; + if(sx->proxy_user) { + size_t plen = strlen(sx->proxy_user); + if(plen > 255) { + /* there is no real size limit to this field in the protocol, but + SOCKS5 limits the proxy user field to 255 bytes and it seems likely + that a longer field is either a mistake or malicious input */ + failf(data, "Too long SOCKS proxy username"); + return CURLPX_LONG_USER; } + /* add proxy name WITH trailing zero */ + result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_user, plen + 1, + &nwritten); + if(result || (nwritten != (plen + 1))) + return CURLPX_SEND_REQUEST; + } + else { + /* empty user name */ + unsigned char b = 0; + result = Curl_bufq_write(&sx->iobuf, &b, 1, &nwritten); + if(result || (nwritten != 1)) + return CURLPX_SEND_REQUEST; + } + return CURLPX_OK; +} + +static CURLproxycode socks4_resolving(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + struct Curl_dns_entry *dns = NULL; + struct Curl_addrinfo *hp = NULL; + CURLcode result; + size_t nwritten; - /* socks4a does not resolve anything locally */ - sxstate(sx, cf, data, CONNECT_REQ_INIT); - goto CONNECT_REQ_INIT; + *done = FALSE; + if(sx->start_resolving) { + /* need to resolve hostname to add destination address */ + sx->start_resolving = FALSE; - case CONNECT_RESOLVING: + result = Curl_resolv(data, sx->hostname, sx->remote_port, + cf->conn->ip_version, TRUE, &dns); + if(result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "SOCKS4 non-blocking resolve of %s", + sx->hostname); + return CURLPX_OK; + } + else if(result) + return CURLPX_RESOLVE_HOST; + } + else { /* check if we have the name resolved by now */ result = Curl_resolv_check(data, &dns); - if(!dns) { - if(result) - return CURLPX_RESOLVE_HOST; + if(!result && !dns) return CURLPX_OK; - } - FALLTHROUGH(); - case CONNECT_RESOLVED: -CONNECT_RESOLVED: - { - struct Curl_addrinfo *hp = NULL; - /* - * We cannot use 'hostent' as a struct that Curl_resolv() returns. It - * returns a Curl_addrinfo pointer that may not always look the same. - */ - if(dns) { - hp = dns->addr; - - /* scan for the first IPv4 address */ - while(hp && (hp->ai_family != AF_INET)) - hp = hp->ai_next; - - if(hp) { - struct sockaddr_in *saddr_in; - char buf[64]; - Curl_printable_address(hp, buf, sizeof(buf)); - - saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; - socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0]; - socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1]; - socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2]; - socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3]; - - CURL_TRC_CF(data, cf, "SOCKS4 connect to IPv4 %s (locally resolved)", - buf); - Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ - } - else - failf(data, "SOCKS4 connection to %s not supported", sx->hostname); - } - else - failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", - sx->hostname); + } - if(!hp) - return CURLPX_RESOLVE_HOST; + if(result || !dns) { + failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", + sx->hostname); + return CURLPX_RESOLVE_HOST; } - FALLTHROUGH(); - case CONNECT_REQ_INIT: -CONNECT_REQ_INIT: - /* - * This is currently not supporting "Identification Protocol (RFC1413)". - */ - socksreq[8] = 0; /* ensure empty userid is null-terminated */ - if(sx->proxy_user) { - size_t plen = strlen(sx->proxy_user); - if(plen > 255) { - /* there is no real size limit to this field in the protocol, but - SOCKS5 limits the proxy user field to 255 bytes and it seems likely - that a longer field is either a mistake or malicious input */ - failf(data, "Too long SOCKS proxy username"); - return CURLPX_LONG_USER; - } - /* copy the proxy name WITH trailing zero */ - memcpy(socksreq + 8, sx->proxy_user, plen + 1); - } - /* - * Make connection - */ - { - size_t packetsize = 9 + - strlen((char *)socksreq + 8); /* size including NUL */ - - /* If SOCKS4a, set special invalid IP address 0.0.0.x */ - if(protocol4a) { - size_t hostnamelen = 0; - socksreq[4] = 0; - socksreq[5] = 0; - socksreq[6] = 0; - socksreq[7] = 1; - /* append hostname */ - hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */ - if((hostnamelen <= 255) && - (packetsize + hostnamelen < sizeof(sx->buffer))) - strcpy((char *)socksreq + packetsize, sx->hostname); - else { - failf(data, "SOCKS4: too long hostname"); - return CURLPX_LONG_HOSTNAME; - } - packetsize += hostnamelen; - } - sx->outp = socksreq; - DEBUGASSERT(packetsize <= sizeof(sx->buffer)); - sx->outstanding = packetsize; - sxstate(sx, cf, data, CONNECT_REQ_SENDING); - } - FALLTHROUGH(); - case CONNECT_REQ_SENDING: - /* Send request */ - presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, - "SOCKS4 connect request"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in sending state */ - return CURLPX_OK; - } - /* done sending! */ - sx->outstanding = 8; /* receive data size */ - sx->outp = socksreq; - sxstate(sx, cf, data, CONNECT_SOCKS_READ); + /* + * We cannot use 'hostent' as a struct that Curl_resolv() returns. It + * returns a Curl_addrinfo pointer that may not always look the same. + */ + /* scan for the first IPv4 address */ + hp = dns->addr; + while(hp && (hp->ai_family != AF_INET)) + hp = hp->ai_next; - FALLTHROUGH(); - case CONNECT_SOCKS_READ: - /* Receive response */ - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, - "connect request ack"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ - return CURLPX_OK; - } - sxstate(sx, cf, data, CONNECT_DONE); - break; - default: /* lots of unused states in SOCKS4 */ - break; + if(hp) { + struct sockaddr_in *saddr_in; + char ipbuf[64]; + + Curl_printable_address(hp, ipbuf, sizeof(ipbuf)); + CURL_TRC_CF(data, cf, "SOCKS4 connect to IPv4 %s (locally resolved)", + ipbuf); + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + result = Curl_bufq_write(&sx->iobuf, + (unsigned char *)&saddr_in->sin_addr.s_addr, 4, + &nwritten); + + Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ + if(result || (nwritten != 4)) + return CURLPX_SEND_REQUEST; + } + else { + failf(data, "SOCKS4 connection to %s not supported", sx->hostname); + return CURLPX_RESOLVE_HOST; + } + + *done = TRUE; + return CURLPX_OK; +} + +static CURLproxycode socks4_check_resp(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + const unsigned char *resp; + size_t rlen; + + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < 8) { + failf(data, "SOCKS4 reply is incomplete."); + return CURLPX_RECV_CONNECT; } + DEBUGASSERT(rlen == 8); /* * Response format * @@ -478,72 +418,194 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, */ /* wrong version ? */ - if(socksreq[0]) { - failf(data, - "SOCKS4 reply has wrong version, version should be 0."); + if(resp[0]) { + failf(data, "SOCKS4 reply has wrong version, version should be 0."); return CURLPX_BAD_VERSION; } /* Result */ - switch(socksreq[1]) { + switch(resp[1]) { case 90: - CURL_TRC_CF(data, cf, "SOCKS4%s request granted.", protocol4a ? "a" : ""); - break; + CURL_TRC_CF(data, cf, "SOCKS4%s request granted.", sx->socks4a ? "a" : ""); + Curl_bufq_reset(&sx->iobuf); + return CURLPX_OK; case 91: failf(data, - "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %u.%u.%u.%u:%u. (%u)" ", request rejected or failed.", - socksreq[4], socksreq[5], socksreq[6], socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); + resp[4], resp[5], resp[6], resp[7], + ((resp[2] << 8) | resp[3]), resp[1]); return CURLPX_REQUEST_FAILED; case 92: failf(data, - "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %u.%u.%u.%u:%u. (%u)" ", request rejected because SOCKS server cannot connect to " "identd on the client.", - socksreq[4], socksreq[5], socksreq[6], socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); + resp[4], resp[5], resp[6], resp[7], + ((resp[2] << 8) | resp[3]), resp[1]); return CURLPX_IDENTD; case 93: failf(data, - "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %u.%u.%u.%u:%u. (%u)" ", request rejected because the client program and identd " "report different user-ids.", - socksreq[4], socksreq[5], socksreq[6], socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); + resp[4], resp[5], resp[6], resp[7], + ((resp[2] << 8) | resp[3]), resp[1]); return CURLPX_IDENTD_DIFFER; default: failf(data, - "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %u.%u.%u.%u:%u. (%u)" ", Unknown.", - socksreq[4], socksreq[5], socksreq[6], socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); + resp[4], resp[5], resp[6], resp[7], + ((resp[2] << 8) | resp[3]), resp[1]); return CURLPX_UNKNOWN_FAIL; } - - return CURLPX_OK; /* Proxy was successful! */ } -static CURLproxycode socks5_init(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data, - const bool socks5_resolve_local, - const size_t hostname_len) +/* +* This function logs in to a SOCKS4 proxy and sends the specifics to the final +* destination server. +* +* Reference : +* https://www.openssh.com/txt/socks4.protocol +* +* Note : +* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" +* Nonsupport "Identification Protocol (RFC1413)" +*/ +static CURLproxycode socks4_connect(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) { - struct connectdata *conn = cf->conn; - const unsigned char auth = data->set.socks5auth; - unsigned char *socksreq = sx->buffer; + size_t nwritten; + CURLproxycode presult; + CURLcode result; + bool done; + +process_state: + switch(sx->state) { + case SOCKS_ST_INIT: + sx->version = 4; + sxstate(sx, cf, data, SOCKS4_ST_START); + FALLTHROUGH(); - if(conn->bits.httpproxy) - CURL_TRC_CF(data, cf, "SOCKS5: connecting to HTTP proxy %s port %d", + case SOCKS4_ST_START: + Curl_bufq_reset(&sx->iobuf); + sx->start_resolving = FALSE; + sx->socks4a = (cf->conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A); + sx->resolve_local = !sx->socks4a; + sx->presult = CURLPX_OK; + + /* SOCKS4 can only do IPv4, insist! */ + cf->conn->ip_version = CURL_IPRESOLVE_V4; + CURL_TRC_CF(data, cf, "SOCKS4%s communication to%s %s:%d", + sx->socks4a ? "a" : "", + cf->conn->bits.httpproxy ? " HTTP proxy" : "", sx->hostname, sx->remote_port); + /* + * Compose socks4 request + * + * Request format + * + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * | VN | CD | DSTPORT | DSTIP | USERID |NULL| + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * # of bytes: 1 1 2 4 variable 1 + */ + presult = socks4_req_add_hd(sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + + /* DNS resolve only for SOCKS4, not SOCKS4a */ + if(!sx->resolve_local) { + /* socks4a, not resolving locally, sends the hostname. + * add an invalid address + user + hostname */ + unsigned char buf[4] = { 0, 0, 0, 1 }; + size_t hlen = strlen(sx->hostname) + 1; /* including NUL */ + + if(hlen > 255) { + failf(data, "SOCKS4: too long hostname"); + return socks_failed(sx, cf, data, CURLPX_LONG_HOSTNAME); + } + result = Curl_bufq_write(&sx->iobuf, buf, 4, &nwritten); + if(result || (nwritten != 4)) + return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST); + presult = socks4_req_add_user(sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + result = Curl_bufq_cwrite(&sx->iobuf, sx->hostname, hlen, &nwritten); + if(result || (nwritten != hlen)) + return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST); + /* request complete */ + sxstate(sx, cf, data, SOCKS4_ST_SEND); + goto process_state; + } + sx->start_resolving = TRUE; + sxstate(sx, cf, data, SOCKS4_ST_RESOLVING); + FALLTHROUGH(); + + case SOCKS4_ST_RESOLVING: + presult = socks4_resolving(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + if(!done) + return CURLPX_OK; + /* append user */ + presult = socks4_req_add_user(sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + sxstate(sx, cf, data, SOCKS4_ST_SEND); + FALLTHROUGH(); + + case SOCKS4_ST_SEND: + presult = socks_flush(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; + sxstate(sx, cf, data, SOCKS4_ST_RECV); + FALLTHROUGH(); + + case SOCKS4_ST_RECV: + /* Receive 8 byte response */ + presult = socks_recv(sx, cf, data, 8, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; + presult = socks4_check_resp(sx, cf, data); + if(presult) + return socks_failed(sx, cf, data, presult); + sxstate(sx, cf, data, SOCKS_ST_SUCCESS); + FALLTHROUGH(); + + case SOCKS_ST_SUCCESS: + return CURLPX_OK; + + case SOCKS_ST_FAILED: + DEBUGASSERT(sx->presult); + return sx->presult; + + default: + DEBUGASSERT(0); + return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST); + } +} + +static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + const unsigned char auth = data->set.socks5auth; + unsigned char req[5]; /* version + len + 3 possible auth methods */ + unsigned char nauths; + size_t req_len, nwritten; + CURLcode result; + + (void)cf; /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ - if(!socks5_resolve_local && hostname_len > 255) { + if(!sx->resolve_local && strlen(sx->hostname) > 255) { failf(data, "SOCKS5: the destination hostname is too long to be " "resolved remotely by the proxy."); return CURLPX_LONG_HOSTNAME; @@ -556,27 +618,73 @@ static CURLproxycode socks5_init(struct Curl_cfilter *cf, /* disable username/password auth */ sx->proxy_user = NULL; - if(!sx->outstanding) { - size_t idx = 0; - socksreq[idx++] = 5; /* version */ - idx++; /* number of authentication methods */ - socksreq[idx++] = 0; /* no authentication */ + req[0] = 5; /* version */ + nauths = 1; + req[1 + nauths] = 0; /* 1. no authentication */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(auth & CURLAUTH_GSSAPI) - socksreq[idx++] = 1; /* GSS-API */ + if(auth & CURLAUTH_GSSAPI) { + ++nauths; + req[1 + nauths] = 1; /* GSS-API */ + } #endif - if(sx->proxy_user) - socksreq[idx++] = 2; /* username/password */ - /* write the number of authentication methods */ - socksreq[1] = (unsigned char) (idx - 2); - - sx->outp = socksreq; - DEBUGASSERT(idx <= sizeof(sx->buffer)); - sx->outstanding = idx; + if(sx->proxy_user) { + ++nauths; + req[1 + nauths] = 2; /* username/password */ } + req[1] = nauths; + req_len = 2 + nauths; + + result = Curl_bufq_write(&sx->iobuf, req, req_len, &nwritten); + if(result || (nwritten != req_len)) + return CURLPX_SEND_REQUEST; + return CURLPX_OK; +} + +static CURLproxycode socks5_check_resp0(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + const unsigned char *resp; + unsigned char auth_mode; + size_t rlen; - return socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, - "initial SOCKS5 request"); + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < 2) { + failf(data, "SOCKS5 initial reply is incomplete."); + return CURLPX_RECV_CONNECT; + } + + if(resp[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLPX_BAD_VERSION; + } + + auth_mode = resp[1]; + Curl_bufq_reset(&sx->iobuf); + + switch(auth_mode) { + case 0: + /* DONE! No authentication needed. Send request. */ + sxstate(sx, cf, data, SOCKS5_ST_REQ1_INIT); + return CURLPX_OK; + case 1: + if(data->set.socks5auth & CURLAUTH_GSSAPI) { + sxstate(sx, cf, data, SOCKS5_ST_GSSAPI_INIT); + return CURLPX_OK; + } + failf(data, + "SOCKS5 GSSAPI per-message authentication is not enabled."); + return CURLPX_GSSAPI_PERMSG; + case 2: + /* regular name + password authentication */ + sxstate(sx, cf, data, SOCKS5_ST_AUTH_INIT); + return CURLPX_OK; + case 255: + failf(data, "No authentication method was acceptable."); + return CURLPX_NO_AUTH; + default: + failf(data, "Unknown SOCKS5 mode attempted to be used by server."); + return CURLPX_UNKNOWN_MODE; + } } static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf, @@ -584,17 +692,22 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf, struct Curl_easy *data) { /* Needs username and password */ - size_t proxy_user_len, proxy_password_len; - size_t len = 0; - unsigned char *socksreq = sx->buffer; + size_t ulen = 0, plen = 0, nwritten; + unsigned char buf[2]; + CURLcode result; if(sx->proxy_user && sx->proxy_password) { - proxy_user_len = strlen(sx->proxy_user); - proxy_password_len = strlen(sx->proxy_password); - } - else { - proxy_user_len = 0; - proxy_password_len = 0; + ulen = strlen(sx->proxy_user); + plen = strlen(sx->proxy_password); + /* the lengths must fit in a single byte */ + if(ulen > 255) { + failf(data, "Excessive username length for proxy auth"); + return CURLPX_LONG_USER; + } + if(plen > 255) { + failf(data, "Excessive password length for proxy auth"); + return CURLPX_LONG_PASSWD; + } } /* username/password request looks like @@ -604,499 +717,494 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf, * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | * +----+------+----------+------+----------+ */ - socksreq[len++] = 1; /* username/pw subnegotiation version */ - socksreq[len++] = (unsigned char) proxy_user_len; - if(sx->proxy_user && proxy_user_len) { - /* the length must fit in a single byte */ - if(proxy_user_len > 255) { - failf(data, "Excessive username length for proxy auth"); - return CURLPX_LONG_USER; - } - memcpy(socksreq + len, sx->proxy_user, proxy_user_len); + buf[0] = 1; /* username/pw subnegotiation version */ + buf[1] = (unsigned char)ulen; + result = Curl_bufq_write(&sx->iobuf, buf, 2, &nwritten); + if(result || (nwritten != 2)) + return CURLPX_SEND_REQUEST; + if(ulen) { + result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_user, ulen, &nwritten); + if(result || (nwritten != ulen)) + return CURLPX_SEND_REQUEST; } - len += proxy_user_len; - socksreq[len++] = (unsigned char) proxy_password_len; - if(sx->proxy_password && proxy_password_len) { - /* the length must fit in a single byte */ - if(proxy_password_len > 255) { - failf(data, "Excessive password length for proxy auth"); - return CURLPX_LONG_PASSWD; - } - memcpy(socksreq + len, sx->proxy_password, proxy_password_len); + buf[0] = (unsigned char) plen; + result = Curl_bufq_write(&sx->iobuf, buf, 1, &nwritten); + if(result || (nwritten != 1)) + return CURLPX_SEND_REQUEST; + if(plen) { + result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_password, plen, &nwritten); + if(result || (nwritten != plen)) + return CURLPX_SEND_REQUEST; } - len += proxy_password_len; - sxstate(sx, cf, data, CONNECT_AUTH_SEND); - DEBUGASSERT(len <= sizeof(sx->buffer)); - sx->outstanding = len; - sx->outp = socksreq; + sxstate(sx, cf, data, SOCKS5_ST_AUTH_SEND); return CURLPX_OK; } -/* - * This function logs in to a SOCKS5 proxy and sends the specifics to the final - * destination server. - */ -static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data) +static CURLproxycode socks5_check_auth_resp(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data) { - /* - According to the RFC1928, section "6. Replies". This is what a SOCK5 - replies: + const unsigned char *resp; + unsigned char auth_status; + size_t rlen; - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ + (void)cf; + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < 2) { + failf(data, "SOCKS5 sub-negotiation response incomplete."); + return CURLPX_RECV_CONNECT; + } - Where: + /* ignore the first (VER) byte */ + auth_status = resp[1]; + Curl_bufq_reset(&sx->iobuf); - o VER protocol version: X'05' - o REP Reply field: - o X'00' succeeded - */ - struct connectdata *conn = cf->conn; - unsigned char *socksreq = sx->buffer; + if(auth_status) { + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + resp[0], resp[1]); + return CURLPX_USER_REJECTED; + } + return CURLPX_OK; +} + +static CURLproxycode socks5_req1_init(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + unsigned char req[5]; + unsigned char ipbuf[16]; + const unsigned char *destination; + unsigned char desttype, destlen, hdlen; + size_t nwritten; CURLcode result; - CURLproxycode presult; - bool socks5_resolve_local = - (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5); - const size_t hostname_len = strlen(sx->hostname); - size_t len = 0; - bool allow_gssapi = FALSE; - struct Curl_dns_entry *dns = NULL; - switch(sx->state) { - case CONNECT_SOCKS_INIT: - presult = socks5_init(cf, sx, data, socks5_resolve_local, hostname_len); - if(presult || sx->outstanding) - return presult; - sxstate(sx, cf, data, CONNECT_SOCKS_READ); - goto CONNECT_SOCKS_READ_INIT; - case CONNECT_SOCKS_SEND: - presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, - "initial SOCKS5 request"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in sending state */ - return CURLPX_OK; - } - FALLTHROUGH(); - case CONNECT_SOCKS_READ_INIT: -CONNECT_SOCKS_READ_INIT: - sx->outstanding = 2; /* expect two bytes */ - sx->outp = socksreq; /* store it here */ - FALLTHROUGH(); - case CONNECT_SOCKS_READ: - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, - "initial SOCKS5 response"); -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(data->set.socks5auth & CURLAUTH_GSSAPI) - allow_gssapi = TRUE; -#endif - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ - return CURLPX_OK; - } - else if(socksreq[0] != 5) { - failf(data, "Received invalid version in initial SOCKS5 response."); - return CURLPX_BAD_VERSION; - } - else if(socksreq[1] == 0) { - /* DONE! No authentication needed. Send request. */ - sxstate(sx, cf, data, CONNECT_REQ_INIT); - goto CONNECT_REQ_INIT; - } - else if(socksreq[1] == 2) { - /* regular name + password authentication */ - sxstate(sx, cf, data, CONNECT_AUTH_INIT); - goto CONNECT_AUTH_INIT; - } -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - else if(allow_gssapi && (socksreq[1] == 1)) { - sxstate(sx, cf, data, CONNECT_GSSAPI_INIT); - result = Curl_SOCKS5_gssapi_negotiate(cf, data); - if(result) { - failf(data, "Unable to negotiate SOCKS5 GSS-API context."); - return CURLPX_GSSAPI; - } - } -#endif - else { - /* error */ - if(!allow_gssapi && (socksreq[1] == 1)) { - failf(data, - "SOCKS5 GSSAPI per-message authentication is not supported."); - return CURLPX_GSSAPI_PERMSG; - } - else if(socksreq[1] == 255) { - failf(data, "No authentication method was acceptable."); - return CURLPX_NO_AUTH; - } - } - failf(data, - "Undocumented SOCKS5 mode attempted to be used by server."); - return CURLPX_UNKNOWN_MODE; -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - case CONNECT_GSSAPI_INIT: - /* GSSAPI stuff done non-blocking */ - break; + req[0] = 5; /* version (SOCKS5) */ + req[1] = 1; /* connect */ + req[2] = 0; /* must be zero */ + if(sx->resolve_local) { + /* rest of request is added after resolving */ + result = Curl_bufq_write(&sx->iobuf, req, 3, &nwritten); + if(result || (nwritten != 3)) + return CURLPX_SEND_REQUEST; + return CURLPX_OK; + } + + /* remote resolving, send what type+addr/string to resolve */ +#ifdef USE_IPV6 + if(cf->conn->bits.ipv6_ip) { + desttype = 4; + destination = ipbuf; + destlen = 16; + if(curlx_inet_pton(AF_INET6, sx->hostname, ipbuf) != 1) + return CURLPX_BAD_ADDRESS_TYPE; + } + else #endif + if(curlx_inet_pton(AF_INET, sx->hostname, ipbuf) == 1) { + desttype = 1; + destination = ipbuf; + destlen = 4; + } + else { + const size_t hostname_len = strlen(sx->hostname); + desttype = 3; + destination = (const unsigned char *)sx->hostname; + destlen = (unsigned char) hostname_len; /* one byte length */ + } - default: /* do nothing! */ - break; + req[3] = desttype; + req[4] = destlen; + hdlen = (desttype == 3) ? 5 : 4; /* no length byte for ip addresses */ + result = Curl_bufq_write(&sx->iobuf, req, hdlen, &nwritten); + if(result || (nwritten != hdlen)) + return CURLPX_SEND_REQUEST; + result = Curl_bufq_write(&sx->iobuf, destination, destlen, &nwritten); + if(result || (nwritten != destlen)) + return CURLPX_SEND_REQUEST; + /* PORT MSB+LSB */ + req[0] = (unsigned char)((sx->remote_port >> 8) & 0xff); + req[1] = (unsigned char)(sx->remote_port & 0xff); + result = Curl_bufq_write(&sx->iobuf, req, 2, &nwritten); + if(result || (nwritten != 2)) + return CURLPX_SEND_REQUEST; + CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (remotely resolved)", + sx->hostname, sx->remote_port); + return CURLPX_OK; +} -CONNECT_AUTH_INIT: - case CONNECT_AUTH_INIT: - presult = socks5_auth_init(cf, sx, data); - if(presult) - return presult; - FALLTHROUGH(); - case CONNECT_AUTH_SEND: - presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, - "SOCKS5 sub-negotiation request"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in sending state */ - return CURLPX_OK; - } - sx->outp = socksreq; - sx->outstanding = 2; - sxstate(sx, cf, data, CONNECT_AUTH_READ); - FALLTHROUGH(); - case CONNECT_AUTH_READ: - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, - "SOCKS5 sub-negotiation response"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ - return CURLPX_OK; - } - /* ignore the first (VER) byte */ - else if(socksreq[1]) { /* status */ - failf(data, "User was rejected by the SOCKS5 server (%d %d).", - socksreq[0], socksreq[1]); - return CURLPX_USER_REJECTED; - } +static CURLproxycode socks5_resolving(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + struct Curl_dns_entry *dns = NULL; + struct Curl_addrinfo *hp = NULL; + char dest[MAX_IPADR_LEN]; /* printable address */ + unsigned char *destination = NULL; + unsigned char desttype = 1, destlen = 4; + unsigned char req[2]; + CURLcode result; + CURLproxycode presult = CURLPX_OK; + size_t nwritten; - /* Everything is good so far, user was authenticated! */ - sxstate(sx, cf, data, CONNECT_REQ_INIT); - FALLTHROUGH(); - case CONNECT_REQ_INIT: -CONNECT_REQ_INIT: - if(socks5_resolve_local) { - result = Curl_resolv(data, sx->hostname, sx->remote_port, - cf->conn->ip_version, TRUE, &dns); - - if(result == CURLE_AGAIN) { - sxstate(sx, cf, data, CONNECT_RESOLVING); - return CURLPX_OK; - } - else if(result) - return CURLPX_RESOLVE_HOST; - sxstate(sx, cf, data, CONNECT_RESOLVED); - goto CONNECT_RESOLVED; - } - goto CONNECT_RESOLVE_REMOTE; + *done = FALSE; + if(sx->start_resolving) { + /* need to resolve hostname to add destination address */ + sx->start_resolving = FALSE; - case CONNECT_RESOLVING: + result = Curl_resolv(data, sx->hostname, sx->remote_port, + cf->conn->ip_version, TRUE, &dns); + if(result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "SOCKS5 non-blocking resolve of %s", + sx->hostname); + return CURLPX_OK; + } + else if(result) + return CURLPX_RESOLVE_HOST; + } + else { /* check if we have the name resolved by now */ result = Curl_resolv_check(data, &dns); - if(!dns) { - if(result) - return CURLPX_RESOLVE_HOST; + if(!result && !dns) return CURLPX_OK; - } - FALLTHROUGH(); - case CONNECT_RESOLVED: -CONNECT_RESOLVED: - { - char dest[MAX_IPADR_LEN]; /* printable address */ - struct Curl_addrinfo *hp = NULL; - if(dns) - hp = dns->addr; + } + + if(result || !dns) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + presult = CURLPX_RESOLVE_HOST; + goto out; + } + + if(dns) + hp = dns->addr; #ifdef USE_IPV6 - if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) { - int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ? - AF_INET : AF_INET6; - /* scan for the first proper address */ - while(hp && (hp->ai_family != wanted_family)) - hp = hp->ai_next; - } + if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) { + int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ? + AF_INET : AF_INET6; + /* scan for the first proper address */ + while(hp && (hp->ai_family != wanted_family)) + hp = hp->ai_next; + } #endif - if(!hp) { - failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", - sx->hostname); - return CURLPX_RESOLVE_HOST; - } + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + presult = CURLPX_RESOLVE_HOST; + goto out; + } - Curl_printable_address(hp, dest, sizeof(dest)); + Curl_printable_address(hp, dest, sizeof(dest)); - len = 0; - socksreq[len++] = 5; /* version (SOCKS5) */ - socksreq[len++] = 1; /* connect */ - socksreq[len++] = 0; /* must be zero */ - if(hp->ai_family == AF_INET) { - int i; - struct sockaddr_in *saddr_in; - socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + if(hp->ai_family == AF_INET) { + struct sockaddr_in *saddr_in; + desttype = 1; /* ATYP: IPv4 = 1 */ + destlen = 4; + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + destination = (unsigned char *)&saddr_in->sin_addr.s_addr; + CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (locally resolved)", + dest, sx->remote_port); + } +#ifdef USE_IPV6 + else if(hp->ai_family == AF_INET6) { + struct sockaddr_in6 *saddr_in6; + desttype = 4; /* ATYP: IPv6 = 4 */ + destlen = 16; + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; + destination = (unsigned char *)&saddr_in6->sin6_addr.s6_addr; + CURL_TRC_CF(data, cf, "SOCKS5 connect to [%s]:%d (locally resolved)", + dest, sx->remote_port); + } +#endif - saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; - for(i = 0; i < 4; i++) { - socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; - } + if(!destination) { + failf(data, "SOCKS5 connection to %s not supported", dest); + presult = CURLPX_RESOLVE_HOST; + goto out; + } - CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (locally resolved)", - dest, sx->remote_port); - } -#ifdef USE_IPV6 - else if(hp->ai_family == AF_INET6) { - int i; - struct sockaddr_in6 *saddr_in6; - socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ - - saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; - for(i = 0; i < 16; i++) { - socksreq[len++] = - ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; - } + req[0] = desttype; + result = Curl_bufq_write(&sx->iobuf, req, 1, &nwritten); + if(result || (nwritten != 1)) { + presult = CURLPX_SEND_REQUEST; + goto out; + } + result = Curl_bufq_write(&sx->iobuf, destination, destlen, &nwritten); + if(result || (nwritten != destlen)) { + presult = CURLPX_SEND_REQUEST; + goto out; + } + /* PORT MSB+LSB */ + req[0] = (unsigned char)((sx->remote_port >> 8) & 0xffu); + req[1] = (unsigned char)(sx->remote_port & 0xffu); + result = Curl_bufq_write(&sx->iobuf, req, 2, &nwritten); + if(result || (nwritten != 2)) { + presult = CURLPX_SEND_REQUEST; + goto out; + } - CURL_TRC_CF(data, cf, "SOCKS5 connect to [%s]:%d (locally resolved)", - dest, sx->remote_port); - } -#endif - else { - hp = NULL; /* fail! */ - failf(data, "SOCKS5 connection to %s not supported", dest); +out: + if(dns) + Curl_resolv_unlink(data, &dns); + *done = (presult == CURLPX_OK); + return presult; +} + +static CURLproxycode socks5_recv_resp1(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + const unsigned char *resp; + size_t rlen, resp_len = 8; /* minimum response length */ + CURLproxycode presult; + + presult = socks_recv(sx, cf, data, resp_len, done); + if(presult) + return presult; + else if(!*done) + return CURLPX_OK; + + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < resp_len) { + failf(data, "SOCKS5 response is incomplete."); + return CURLPX_RECV_CONNECT; + } + + /* Response packet includes BND.ADDR is variable length parameter by RFC + 1928, so the response packet MUST be read until the end to avoid errors + at subsequent protocol level. + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + ATYP: + o IP v4 address: X'01', BND.ADDR = 4 byte + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o IP v6 address: X'04', BND.ADDR = 16 byte + */ + if(resp[0] != 5) { /* version */ + failf(data, "SOCKS5 reply has wrong version, version should be 5."); + return CURLPX_BAD_VERSION; + } + else if(resp[1]) { /* Anything besides 0 is an error */ + CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; + int code = resp[1]; + failf(data, "cannot complete SOCKS5 connection to %s. (%d)", + sx->hostname, code); + if(code < 9) { + /* RFC 1928 section 6 lists: */ + static const CURLproxycode lookup[] = { + CURLPX_OK, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + }; + rc = lookup[code]; } + return rc; + } - Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ - goto CONNECT_REQ_SEND; + /* Calculate real packet size */ + switch(resp[3]) { + case 1: /* IPv4 */ + resp_len = 4 + 4 + 2; + break; + case 3: /* domain name */ + resp_len = 4 + 1 + resp[4] + 2; /* header, var length, var bytes, port */ + break; + case 4: /* IPv6 */ + resp_len = 4 + 16 + 2; + break; + default: + failf(data, "SOCKS5 reply has wrong address type."); + return CURLPX_BAD_ADDRESS_TYPE; } -CONNECT_RESOLVE_REMOTE: - case CONNECT_RESOLVE_REMOTE: - /* Authentication is complete, now specify destination to the proxy */ - len = 0; - socksreq[len++] = 5; /* version (SOCKS5) */ - socksreq[len++] = 1; /* connect */ - socksreq[len++] = 0; /* must be zero */ - - if(!socks5_resolve_local) { - /* ATYP: domain name = 3, - IPv6 == 4, - IPv4 == 1 */ - unsigned char ip4[4]; -#ifdef USE_IPV6 - if(conn->bits.ipv6_ip) { - char ip6[16]; - if(curlx_inet_pton(AF_INET6, sx->hostname, ip6) != 1) - return CURLPX_BAD_ADDRESS_TYPE; - socksreq[len++] = 4; - memcpy(&socksreq[len], ip6, sizeof(ip6)); - len += sizeof(ip6); - } - else -#endif - if(curlx_inet_pton(AF_INET, sx->hostname, ip4) == 1) { - socksreq[len++] = 1; - memcpy(&socksreq[len], ip4, sizeof(ip4)); - len += sizeof(ip4); - } - else { - socksreq[len++] = 3; - socksreq[len++] = (unsigned char) hostname_len; /* one byte length */ - memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ - len += hostname_len; - } - CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (remotely resolved)", + + /* receive the rest of the response */ + presult = socks_recv(sx, cf, data, resp_len, done); + if(presult) + return presult; + else if(!*done) + return CURLPX_OK; + + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < resp_len) { + failf(data, "SOCKS5 response is incomplete."); + return CURLPX_RECV_CONNECT; + } + /* got it all */ + *done = TRUE; + return CURLPX_OK; +} + +/* + * This function logs in to a SOCKS5 proxy and sends the specifics to the final + * destination server. + */ +static CURLproxycode socks5_connect(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + CURLproxycode presult; + bool done; + +process_state: + switch(sx->state) { + case SOCKS_ST_INIT: + sx->version = 5; + sx->resolve_local = (cf->conn->socks_proxy.proxytype == CURLPROXY_SOCKS5); + sxstate(sx, cf, data, SOCKS5_ST_START); + FALLTHROUGH(); + + case SOCKS5_ST_START: + if(cf->conn->bits.httpproxy) + CURL_TRC_CF(data, cf, "SOCKS5: connecting to HTTP proxy %s port %d", sx->hostname, sx->remote_port); - } + presult = socks5_req0_init(cf, sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + sxstate(sx, cf, data, SOCKS5_ST_REQ0_SEND); FALLTHROUGH(); - case CONNECT_REQ_SEND: -CONNECT_REQ_SEND: - /* PORT MSB */ - socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff); - /* PORT LSB */ - socksreq[len++] = (unsigned char)(sx->remote_port & 0xff); + case SOCKS5_ST_REQ0_SEND: + presult = socks_flush(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; + /* done sending! */ + sxstate(sx, cf, data, SOCKS5_ST_RESP0_RECV); + FALLTHROUGH(); + + case SOCKS5_ST_RESP0_RECV: + presult = socks_recv(sx, cf, data, 2, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; + presult = socks5_check_resp0(sx, cf, data); + if(presult) + return socks_failed(sx, cf, data, presult); + /* socks5_check_resp0() sets next socks state */ + goto process_state; + case SOCKS5_ST_GSSAPI_INIT: { #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 GSS-API protection not yet implemented."); - return CURLPX_GSSAPI_PROTECTION; + /* GSSAPI stuff done non-blocking */ + CURLcode result = Curl_SOCKS5_gssapi_negotiate(cf, data); + if(result) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + return CURLPX_GSSAPI; } + sxstate(sx, cf, data, SOCKS5_ST_REQ1_INIT); + goto process_state; +#else + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return socks_failed(sx, cf, data, CURLPX_GSSAPI_PERMSG); #endif - sx->outp = socksreq; - DEBUGASSERT(len <= sizeof(sx->buffer)); - sx->outstanding = len; - sxstate(sx, cf, data, CONNECT_REQ_SENDING); + } + + case SOCKS5_ST_AUTH_INIT: + presult = socks5_auth_init(cf, sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + sxstate(sx, cf, data, SOCKS5_ST_AUTH_SEND); FALLTHROUGH(); - case CONNECT_REQ_SENDING: - presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, - "SOCKS5 connect request"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in send state */ + + case SOCKS5_ST_AUTH_SEND: + presult = socks_flush(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) return CURLPX_OK; - } -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 GSS-API protection not yet implemented."); - return CURLPX_GSSAPI_PROTECTION; - } -#endif - sx->outstanding = 10; /* minimum packet size is 10 */ - sx->outp = socksreq; - sxstate(sx, cf, data, CONNECT_REQ_READ); + sxstate(sx, cf, data, SOCKS5_ST_AUTH_RECV); FALLTHROUGH(); - case CONNECT_REQ_READ: - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, - "SOCKS5 connect request ack"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ + + case SOCKS5_ST_AUTH_RECV: + presult = socks_recv(sx, cf, data, 2, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) return CURLPX_OK; - } - else if(socksreq[0] != 5) { /* version */ - failf(data, - "SOCKS5 reply has wrong version, version should be 5."); - return CURLPX_BAD_VERSION; - } - else if(socksreq[1]) { /* Anything besides 0 is an error */ - CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; - int code = socksreq[1]; - failf(data, "cannot complete SOCKS5 connection to %s. (%d)", - sx->hostname, (unsigned char)socksreq[1]); - if(code < 9) { - /* RFC 1928 section 6 lists: */ - static const CURLproxycode lookup[] = { - CURLPX_OK, - CURLPX_REPLY_GENERAL_SERVER_FAILURE, - CURLPX_REPLY_NOT_ALLOWED, - CURLPX_REPLY_NETWORK_UNREACHABLE, - CURLPX_REPLY_HOST_UNREACHABLE, - CURLPX_REPLY_CONNECTION_REFUSED, - CURLPX_REPLY_TTL_EXPIRED, - CURLPX_REPLY_COMMAND_NOT_SUPPORTED, - CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, - }; - rc = lookup[code]; - } - return rc; - } + presult = socks5_check_auth_resp(sx, cf, data); + if(presult) + return socks_failed(sx, cf, data, presult); + /* Everything is good so far, user was authenticated! */ + sxstate(sx, cf, data, SOCKS5_ST_REQ1_INIT); + FALLTHROUGH(); - /* Fix: in general, returned BND.ADDR is variable length parameter by RFC - 1928, so the reply packet should be read until the end to avoid errors - at subsequent protocol level. - - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ - - ATYP: - o IP v4 address: X'01', BND.ADDR = 4 byte - o domain name: X'03', BND.ADDR = [ 1 byte length, string ] - o IP v6 address: X'04', BND.ADDR = 16 byte - */ - - /* Calculate real packet size */ - if(socksreq[3] == 3) { - /* domain name */ - int addrlen = (int) socksreq[4]; - len = 5 + addrlen + 2; - } - else if(socksreq[3] == 4) { - /* IPv6 */ - len = 4 + 16 + 2; - } - else if(socksreq[3] == 1) { - len = 4 + 4 + 2; - } - else { - failf(data, "SOCKS5 reply has wrong address type."); - return CURLPX_BAD_ADDRESS_TYPE; + case SOCKS5_ST_REQ1_INIT: + presult = socks5_req1_init(sx, cf, data); + if(presult) + return socks_failed(sx, cf, data, presult); + if(!sx->resolve_local) { + /* we do not resolve, request is complete */ + sxstate(sx, cf, data, SOCKS5_ST_REQ1_SEND); + goto process_state; } + sx->start_resolving = TRUE; + sxstate(sx, cf, data, SOCKS5_ST_RESOLVING); + FALLTHROUGH(); - /* At this point we already read first 10 bytes */ -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(!conn->socks5_gssapi_enctype) { - /* decrypt_gssapi_blockread already read the whole packet */ -#endif - if(len > 10) { - DEBUGASSERT(len <= sizeof(sx->buffer)); - sx->outstanding = len - 10; /* get the rest */ - sx->outp = &socksreq[10]; - sxstate(sx, cf, data, CONNECT_REQ_READ_MORE); - } - else { - sxstate(sx, cf, data, CONNECT_DONE); - break; - } + case SOCKS5_ST_RESOLVING: + presult = socks5_resolving(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + if(!done) + return CURLPX_OK; + sxstate(sx, cf, data, SOCKS5_ST_REQ1_SEND); + FALLTHROUGH(); + + case SOCKS5_ST_REQ1_SEND: + presult = socks_flush(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(cf->conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; } #endif + sxstate(sx, cf, data, SOCKS5_ST_RESP1_RECV); FALLTHROUGH(); - case CONNECT_REQ_READ_MORE: - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS, - "SOCKS5 connect request address"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ - return CURLPX_OK; - } - sxstate(sx, cf, data, CONNECT_DONE); - } - CURL_TRC_CF(data, cf, "SOCKS5 request granted."); - return CURLPX_OK; /* Proxy was successful! */ -} - -static CURLcode connect_SOCKS(struct Curl_cfilter *cf, - struct socks_state *sxstate, - struct Curl_easy *data) -{ - CURLcode result = CURLE_OK; - CURLproxycode pxresult = CURLPX_OK; - struct connectdata *conn = cf->conn; + case SOCKS5_ST_RESP1_RECV: + presult = socks5_recv_resp1(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + if(!done) + return CURLPX_OK; + CURL_TRC_CF(data, cf, "SOCKS5 request granted."); + sxstate(sx, cf, data, SOCKS_ST_SUCCESS); + FALLTHROUGH(); - switch(conn->socks_proxy.proxytype) { - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: - pxresult = do_SOCKS5(cf, sxstate, data); - break; + case SOCKS_ST_SUCCESS: + return CURLPX_OK; - case CURLPROXY_SOCKS4: - case CURLPROXY_SOCKS4A: - pxresult = do_SOCKS4(cf, sxstate, data); - break; + case SOCKS_ST_FAILED: + DEBUGASSERT(sx->presult); + return sx->presult; default: - failf(data, "unknown proxytype option given"); - result = CURLE_COULDNT_CONNECT; - } /* switch proxytype */ - if(pxresult) { - result = CURLE_PROXY; - data->info.pxcode = pxresult; + DEBUGASSERT(0); + return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST); } - - return result; } static void socks_proxy_cf_free(struct Curl_cfilter *cf) { struct socks_state *sxstate = cf->ctx; if(sxstate) { + Curl_bufq_free(&sxstate->iobuf); free(sxstate); cf->ctx = NULL; } @@ -1117,6 +1225,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, struct connectdata *conn = cf->conn; int sockindex = cf->sockindex; struct socks_state *sx = cf->ctx; + CURLproxycode pxresult = CURLPX_OK; if(cf->connected) { *done = TRUE; @@ -1128,17 +1237,13 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, return result; if(!sx) { - sx = calloc(1, sizeof(*sx)); + cf->ctx = sx = calloc(1, sizeof(*sx)); if(!sx) return CURLE_OUT_OF_MEMORY; - cf->ctx = sx; - } - if(sx->state == CONNECT_INIT) { /* for the secondary socket (FTP), use the "connect to host" * but ignore the "connect to port" (use the secondary port) */ - sxstate(sx, cf, data, CONNECT_SOCKS_INIT); sx->hostname = conn->bits.httpproxy ? conn->http_proxy.host.name : @@ -1153,29 +1258,54 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, conn->remote_port; sx->proxy_user = conn->socks_proxy.user; sx->proxy_password = conn->socks_proxy.passwd; + Curl_bufq_init2(&sx->iobuf, SOCKS_CHUNK_SIZE, SOCKS_CHUNKS, + BUFQ_OPT_SOFT_LIMIT); + } + + switch(conn->socks_proxy.proxytype) { + case CURLPROXY_SOCKS5: + case CURLPROXY_SOCKS5_HOSTNAME: + pxresult = socks5_connect(cf, sx, data); + break; + + case CURLPROXY_SOCKS4: + case CURLPROXY_SOCKS4A: + pxresult = socks4_connect(cf, sx, data); + break; + + default: + failf(data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + goto out; + } + + if(pxresult) { + result = CURLE_PROXY; + data->info.pxcode = pxresult; + goto out; } + else if(sx->state != SOCKS_ST_SUCCESS) + goto out; - result = connect_SOCKS(cf, sx, data); - if(!result && sx->state == CONNECT_DONE) { - cf->connected = TRUE; #ifndef CURL_DISABLE_VERBOSE_STRINGS - if(Curl_trc_is_verbose(data)) { - struct ip_quadruple ipquad; - bool is_ipv6; - result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad); - if(result) - return result; - infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " - "(via %s port %u)", - (sockindex == SECONDARYSOCKET) ? "2nd " : "", - ipquad.local_ip, ipquad.local_port, - sx->hostname, sx->remote_port, - ipquad.remote_ip, ipquad.remote_port); - } -#endif - socks_proxy_cf_free(cf); + if(Curl_trc_is_verbose(data)) { + struct ip_quadruple ipquad; + bool is_ipv6; + result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad); + if(result) + return result; + infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " + "(via %s port %u)", + (sockindex == SECONDARYSOCKET) ? "2nd " : "", + ipquad.local_ip, ipquad.local_port, + sx->hostname, sx->remote_port, + ipquad.remote_ip, ipquad.remote_port); } +#endif + socks_proxy_cf_free(cf); + cf->connected = TRUE; +out: *done = cf->connected; return result; } @@ -1192,15 +1322,16 @@ static CURLcode socks_cf_adjust_pollset(struct Curl_cfilter *cf, * to wait on, we determine what to wait for. */ curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); switch(sx->state) { - case CONNECT_RESOLVING: - case CONNECT_SOCKS_READ: - case CONNECT_AUTH_READ: - case CONNECT_REQ_READ: - case CONNECT_REQ_READ_MORE: - result = Curl_pollset_set_in_only(data, ps, sock); + case SOCKS4_ST_SEND: + case SOCKS5_ST_REQ0_SEND: + case SOCKS5_ST_AUTH_SEND: + case SOCKS5_ST_REQ1_SEND: + CURL_TRC_CF(data, cf, "adjust pollset out (%d)", sx->state); + result = Curl_pollset_set_out_only(data, ps, sock); break; default: - result = Curl_pollset_set_out_only(data, ps, sock); + CURL_TRC_CF(data, cf, "adjust pollset in (%d)", sx->state); + result = Curl_pollset_set_in_only(data, ps, sock); break; } } diff --git a/tests/libtest/lib564.c b/tests/libtest/lib564.c index 86e4f9ed06c3..3fc86015044b 100644 --- a/tests/libtest/lib564.c +++ b/tests/libtest/lib564.c @@ -23,6 +23,7 @@ ***************************************************************************/ #include "first.h" +#include "testtrace.h" #include "memdebug.h" static CURLcode test_lib564(const char *URL) @@ -32,6 +33,9 @@ static CURLcode test_lib564(const char *URL) int running; CURLM *m = NULL; + debug_config.nohex = TRUE; + debug_config.tracetime = TRUE; + start_test_timing(); global_init(CURL_GLOBAL_ALL); @@ -39,6 +43,8 @@ static CURLcode test_lib564(const char *URL) easy_init(curl); easy_setopt(curl, CURLOPT_URL, URL); + easy_setopt(curl, CURLOPT_DEBUGDATA, &debug_config); + easy_setopt(curl, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); easy_setopt(curl, CURLOPT_VERBOSE, 1L); easy_setopt(curl, CURLOPT_PROXY, libtest_arg2); easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); From cbc30d4ed2720a18ccf86a24eb3659a9cff74a1b Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 11:15:15 +0200 Subject: [PATCH 167/208] vtls: alpn setting, check proto parameter When setting the negotiated alpn protocol, either then length must be 0 or a pointer must be passed. Reported in Joshua's sarif data Closes #18717 --- lib/vtls/vtls.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index bfec585ce210..9872e4c24d42 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1993,6 +1993,11 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, result = CURLE_SSL_CONNECT_ERROR; goto out; } + else if(!proto) { + DEBUGASSERT(0); /* with length, we need a pointer */ + result = CURLE_SSL_CONNECT_ERROR; + goto out; + } else if((strlen(connssl->negotiated.alpn) != proto_len) || memcmp(connssl->negotiated.alpn, proto, proto_len)) { failf(data, "ALPN: asked for '%s' from previous session, but server " From 9e8b05fb995ed36dee08e19953faa2ab48d9304b Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 11:25:17 +0200 Subject: [PATCH 168/208] wolfssl: check BIO read parameters Check parameters passed more thoroughly and assure that current 'data' also exists. Reported in Joshua's sarif data Closes #18718 --- lib/vtls/wolfssl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 693cbdc92e21..0cf6e0e4a57a 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -362,8 +362,11 @@ static int wssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) CURLcode result = CURLE_OK; DEBUGASSERT(data); - /* OpenSSL catches this case, so should we. */ - if(!buf) + if(!data || (blen < 0)) { + wssl->io_result = CURLE_FAILED_INIT; + return -1; + } + if(!buf || !blen) return 0; if((connssl->connecting_state == ssl_connect_2) && From b0f65932191df13148032fed307c15557723da48 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 11:49:45 +0200 Subject: [PATCH 169/208] openssl-quic: check results better Fail on errors from SSL_handle_events(). Force quit Caddy test instance that is left hanging longer with openssl-quic tests for unknown reasons. Reported in Joshua's sarif data Closes #18720 --- lib/vquic/curl_osslq.c | 6 +++++- tests/http/testenv/caddy.py | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 5e9b0727360b..b4cc052ec243 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1421,12 +1421,16 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, if(!snew) break; - (void)cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data); + result = cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data); + if(result) + goto out; } if(!SSL_handle_events(ctx->tls.ossl.ssl)) { int detail = SSL_get_error(ctx->tls.ossl.ssl, 0); result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR); + if(result) + goto out; } if(ctx->h3.conn) { diff --git a/tests/http/testenv/caddy.py b/tests/http/testenv/caddy.py index ad56ce13c86b..d7f6a0d7291a 100644 --- a/tests/http/testenv/caddy.py +++ b/tests/http/testenv/caddy.py @@ -117,7 +117,10 @@ def stop(self, wait_dead=True): self._mkpath(self._tmp_dir) if self._process: self._process.terminate() - self._process.wait(timeout=2) + try: + self._process.wait(timeout=1) + except Exception: + self._process.kill() self._process = None return not wait_dead or self.wait_dead(timeout=timedelta(seconds=5)) return True From 5f4f70e06d688e34a6079a81db1794d76c465fdb Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:07:25 +0200 Subject: [PATCH 170/208] ngtcp2: fix early return On a failed tls handshake, the receive function returned without restoring the current data. Reported in Joshua's sarif data Closes #18723 --- lib/vquic/curl_ngtcp2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 0e05694992a0..4998400d96aa 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -1303,8 +1303,10 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *pnread = 0; /* handshake verification failed in callback, do not recv anything */ - if(ctx->tls_vrfy_result) - return ctx->tls_vrfy_result; + if(ctx->tls_vrfy_result) { + result = ctx->tls_vrfy_result; + goto out; + } pktx_init(&pktx, cf, data); From 887b863b00b9893c20eb9e1f3987ceaeade1f774 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:11:15 +0200 Subject: [PATCH 171/208] openssl: clear retry flag on x509 error When loading the trust anchors and encountering an error, clear a possibly set retry flag. Reported in Joshua's sarif data Closes #18724 --- lib/vtls/openssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 4d37f5e77f20..1048bf5751c1 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -741,6 +741,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen) if(!octx->x509_store_setup) { r2 = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx); if(r2) { + BIO_clear_retry_flags(bio); octx->io_result = r2; return -1; } From ee2dd2d6cb9b50dbf7ffd3ada106ba5c09229fa5 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:38:02 +0200 Subject: [PATCH 172/208] openssl-quic: handle error in SSL_get_stream_read_error_code The return code of SSL_get_stream_read_error_code() was not checked in one location, but others. Make that consistent. Reported in Joshua's sarif data Closes #18725 --- lib/vquic/curl_osslq.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index b4cc052ec243..e6278ad961a9 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1264,12 +1264,16 @@ static CURLcode h3_quic_recv(void *reader_ctx, else if(SSL_get_stream_read_state(x->s->ssl) == SSL_STREAM_STATE_RESET_REMOTE) { uint64_t app_error_code = NGHTTP3_H3_NO_ERROR; - SSL_get_stream_read_error_code(x->s->ssl, &app_error_code); - CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> RESET, " - "rv=%d, app_err=%" FMT_PRIu64, - x->s->id, rv, (curl_uint64_t)app_error_code); - if(app_error_code != NGHTTP3_H3_NO_ERROR) { + if(!SSL_get_stream_read_error_code(x->s->ssl, &app_error_code)) { x->s->reset = TRUE; + return CURLE_RECV_ERROR; + } + else { + CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> RESET, " + "rv=%d, app_err=%" FMT_PRIu64, + x->s->id, rv, (curl_uint64_t)app_error_code); + if(app_error_code != NGHTTP3_H3_NO_ERROR) + x->s->reset = TRUE; } x->s->recvd_eos = TRUE; return CURLE_OK; From 36eb26381c1c46098a7c0e4b8a12e7102001c721 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:46:09 +0200 Subject: [PATCH 173/208] quiche: fix verbose message when ip quadruple cannot be obtained. Reported in Joshua's sarif data Closes #18726 --- lib/vquic/curl_quiche.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 523f04e33bd9..e096c63fe98f 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1432,9 +1432,11 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, if(result && result != CURLE_AGAIN) { struct ip_quadruple ip; - Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); - infof(data, "connect to %s port %u failed: %s", - ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); + if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) + infof(data, "connect to %s port %u failed: %s", + ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); + else + infof(data, "connect failed: %s", curl_easy_strerror(result)); } #endif return result; From e02cbe94ff92310b2bb4ba3ad622063b0d34ce0a Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:53:37 +0200 Subject: [PATCH 174/208] mbedtls: check result of setting ALPN The result of setting the negotiated ALPN was not checked, leading to reporting success when it should not have. Reported in Joshua's sarif data Closes #18727 --- lib/vtls/mbedtls.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 0a62da2b58bf..aa7e8d67ef4d 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -918,6 +918,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) static CURLcode mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) { + CURLcode result; int ret; struct ssl_connect_data *connssl = cf->ctx; struct mbed_ssl_backend_data *backend = @@ -968,7 +969,6 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) if(pinnedpubkey) { int size; - CURLcode result; const mbedtls_x509_crt *peercert; mbedtls_x509_crt *p = NULL; unsigned char *pubkey = NULL; @@ -1018,17 +1018,19 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) mbedtls_x509_crt_free(p); free(p); free(pubkey); - if(result) { + if(result) return result; - } } #ifdef HAS_ALPN_MBEDTLS if(connssl->alpn) { const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl); - Curl_alpn_set_negotiated(cf, data, connssl, (const unsigned char *)proto, - proto ? strlen(proto) : 0); + result = Curl_alpn_set_negotiated(cf, data, connssl, + (const unsigned char *)proto, + proto ? strlen(proto) : 0); + if(result) + return result; } #endif From 15b4b9618879318ffcd7d8b95f9b2692b14c8e8b Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:59:36 +0200 Subject: [PATCH 175/208] rustls: fix comment describing cr_recv() The comments on `cf_recv()` function were outdated and described calling conventions that no longer are true. Reported in Joshua's sarif data Closes #18728 --- lib/vtls/rustls.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index e081c4651ac8..a6d8a4652d88 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -188,16 +188,8 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf, } /* - * On each run: - * - Read a chunk of bytes from the socket into Rustls' TLS input buffer. - * - Tell Rustls to process any new packets. - * - Read out as many plaintext bytes from Rustls as possible, until hitting - * error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up. - * - * it is okay to call this function with plainbuf == NULL and plainlen == 0. In - * that case, it will copy bytes from the socket into Rustls' TLS input - * buffer, and process packets, but will not consume bytes from Rustls' - * plaintext output buffer. + * Filter receive method implementation. `plainbuf` and `plainlen` + * are always not NULL/0. */ static CURLcode cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, From dec661c81cb0bc55e089b67112ab995eeba350eb Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 13:11:58 +0200 Subject: [PATCH 176/208] wolfssl: fix error check in shutdown When trying to send the TLS shutdown, use the return code to check for the cause. Reported in Joshua's sarif data Closes #18729 --- lib/vtls/wolfssl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 0cf6e0e4a57a..ed024356766e 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -1921,7 +1921,8 @@ static CURLcode wssl_shutdown(struct Curl_cfilter *cf, * was not complete, we are lacking the close notify from the server. */ if(send_shutdown) { wolfSSL_ERR_clear_error(); - if(wolfSSL_shutdown(wctx->ssl) == 1) { + nread = wolfSSL_shutdown(wctx->ssl); + if(nread == 1) { CURL_TRC_CF(data, cf, "SSL shutdown finished"); *done = TRUE; goto out; From 771dd9d9e7cda15be4d99a4c50a04b4d6c46b765 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 13:17:48 +0200 Subject: [PATCH 177/208] quiche: when ingress processing fails, return that error code Instead of a general CURLE_RECV_ERROR. Reported in Joshua's sarif data Closes #18730 --- lib/vquic/curl_quiche.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index e096c63fe98f..5fb67f69f42c 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -865,9 +865,9 @@ static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data, goto out; } - if(cf_process_ingress(cf, data)) { + result = cf_process_ingress(cf, data); + if(result) { CURL_TRC_CF(data, cf, "cf_recv, error on ingress"); - result = CURLE_RECV_ERROR; goto out; } From 221b7dda3837940532b03fbc5f7c54d8a6edd266 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 13:25:29 +0200 Subject: [PATCH 178/208] transfer: avoid busy loop with tiny speed limit When a transfer has a speed limit less than 4, the receive loop early exits without receiving anything, causing a busy loop for that transfer. Perform that check only after the first receive has been done. Reported in Joshua's sarif data Closes #18732 --- lib/transfer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/transfer.c b/lib/transfer.c index 1297a3e82d26..62528d227577 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -283,7 +283,7 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, * a quarter of the quota, break out. We want to stutter a bit * to keep in the limit, but too small receives will just cost * cpu unnecessarily. */ - if(total_received >= (data->set.max_recv_speed / 4)) + if(total_received && (total_received >= (data->set.max_recv_speed / 4))) break; if(data->set.max_recv_speed < (curl_off_t)bytestoread) bytestoread = (size_t)data->set.max_recv_speed; From 442943fb8e9a0e7bd9ae0e5976e4e52792af9739 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 13:31:17 +0200 Subject: [PATCH 179/208] openssl: set io_need always When OpenSSL reports SSL_ERROR_WANT_READ, set the io_need explicitly. It should have already been set by the BIO, but be safe. Reported in Joshua's sarif data Closes #18733 --- lib/vtls/openssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 1048bf5751c1..d07c1bf773da 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -5369,6 +5369,7 @@ static CURLcode ossl_recv(struct Curl_cfilter *cf, connclose(conn, "TLS close_notify"); break; case SSL_ERROR_WANT_READ: + connssl->io_need = CURL_SSL_IO_NEED_RECV; result = CURLE_AGAIN; goto out; case SSL_ERROR_WANT_WRITE: From e08211b1ca35b9d6fbc5e4a898af0738516ad1ec Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 13:14:36 +0200 Subject: [PATCH 180/208] GHA: bump pip `cryptography`, relax `impacket` version requirement Bump `cryptography` to a newer version that fixes two known OpenSSL vulnerabilities reported by Dependabot. To make it work, also allow `impacket` 0.11.0, because it allows any pyOpenSSL version, while 0.12.0 pinned it to a single version that happens to be incompatible with the bugfixed `cryptography` version. Also: drop spaces from `requirements.txt` files. Bots don't add them, though they seem to be preferred in the official documentation: https://pip.pypa.io/en/stable/reference/requirements-file-format/ https://github.com/fortra/impacket/blob/impacket_0_11_0/requirements.txt https://github.com/fortra/impacket/blob/impacket_0_12_0/requirements.txt Follow-up to 7d5f8be532c19ec73063aaa4f27057047bdae5ac #18708 Closes #18731 --- .github/scripts/requirements.txt | 10 +++++----- tests/http/requirements.txt | 12 ++++++------ tests/requirements.txt | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 5e876b0cb2b8..ac858451d59f 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -2,8 +2,8 @@ # # SPDX-License-Identifier: curl -cmakelang == 0.6.13 -codespell == 2.4.1 -pytype == 2024.10.11 -reuse == 5.1.1 -ruff == 0.13.1 +cmakelang==0.6.13 +codespell==2.4.1 +pytype==2024.10.11 +reuse==5.1.1 +ruff==0.13.1 diff --git a/tests/http/requirements.txt b/tests/http/requirements.txt index 8dddcd1e1c24..6a98723ac208 100644 --- a/tests/http/requirements.txt +++ b/tests/http/requirements.txt @@ -2,9 +2,9 @@ # # SPDX-License-Identifier: curl -cryptography == 42.0.8 -filelock == 3.19.1 -psutil == 7.1.0 -pytest == 8.4.2 -pytest-xdist == 3.8.0 -websockets == 15.0.1 +cryptography==44.0.1 +filelock==3.19.1 +psutil==7.1.0 +pytest==8.4.2 +pytest-xdist==3.8.0 +websockets==15.0.1 diff --git a/tests/requirements.txt b/tests/requirements.txt index dab4784c5fa1..501c1fc69359 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,4 +2,4 @@ # # SPDX-License-Identifier: curl -impacket == 0.12.0 +impacket>=0.11.0,<=0.12.0 From 882293cc81c0c384c30288c24111e45e6de4cd39 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 13:40:54 +0200 Subject: [PATCH 181/208] KNOWN_BUGS: telnet code does not handle partial writes properly Reported in Joshua's sarif data Closes #18735 --- docs/KNOWN_BUGS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 3785d73aa49e..5b7df42bdab9 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -86,6 +86,7 @@ problems may have been fixed or changed somewhat since this was written. 12.4 LDAPS requests to ActiveDirectory server hang 13. TCP/IP + 13.1 telnet code does not handle partial writes properly 13.2 Trying local ports fails on Windows 15. CMake @@ -547,6 +548,11 @@ problems may have been fixed or changed somewhat since this was written. 13. TCP/IP +13.1 telnet code does not handle partial writes properly + + It probably does not happen too easily because of how slow and infrequent + sends are normally performed. + 13.2 Trying local ports fails on Windows This makes '--local-port [range]' to not work since curl cannot properly From 5b8c80684b5b39c4d4fde2a7c4f2e3247c391fac Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 14:34:46 +0200 Subject: [PATCH 182/208] GHA/checksrc: drop no longer used `DEBIAN_FRONTEND` env Follow-up to 7d5f8be532c19ec73063aaa4f27057047bdae5ac #18708 Cherry-picked from #18736 --- .github/workflows/checksrc.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 59fc930fa76d..0e7d4ed326c8 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -52,8 +52,6 @@ jobs: persist-credentials: false - name: 'install' - env: - DEBIAN_FRONTEND: noninteractive run: | python3 -m venv ~/venv ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary \ From edbf610c6a55ee9776f85352f9ad182cd52559b0 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 14:38:48 +0200 Subject: [PATCH 183/208] GHA: set `HOMEBREW_NO_AUTO_UPDATE=1` for Linuxbrew In an attempt to make `brew install` commands initialize faster. Often this command started with 20-50 seconds of delay before this patch. This is an attempt to make it launch faster. Cherry-picked from #18736 --- .github/workflows/checksrc.yml | 4 ++-- .github/workflows/codeql.yml | 2 +- .github/workflows/linux.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 0e7d4ed326c8..b101a822c545 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -72,7 +72,7 @@ jobs: - name: 'typos' run: | - /home/linuxbrew/.linuxbrew/bin/brew install typos-cli + HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install typos-cli eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" typos --version .github/scripts/typos.sh @@ -118,7 +118,7 @@ jobs: timeout-minutes: 5 steps: - name: 'install prereqs' - run: /home/linuxbrew/.linuxbrew/bin/brew install shellcheck zizmor + run: HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install shellcheck zizmor - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8cc7e9f48c2c..f271d26b149b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -77,7 +77,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libssh-dev \ libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev - /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi + HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 556ff8df1ec9..2724901324cf 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -322,7 +322,7 @@ jobs: ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} if [ -n "${INSTALL_PACKAGES_BREW}" ]; then - /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} + HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} fi - name: 'install prereqs' From bebc8df0f733468377fbb5cc2a68dbb1239a4b73 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 14:52:38 +0200 Subject: [PATCH 184/208] schannel_verify: use more human friendly error messages Closes #18737 --- lib/vtls/schannel_verify.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index b19e1757d452..f73d758ba196 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -889,7 +889,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, NULL, &pChainContext)) { char buffer[WINAPI_ERROR_LEN]; - failf(data, "schannel: CertGetCertificateChain failed: %s", + failf(data, "schannel: failed to get the certificate chain: %s", curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); pChainContext = NULL; result = CURLE_PEER_FAILED_VERIFICATION; @@ -910,23 +910,20 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, if(dwTrustErrorMask) { if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_REVOKED"); + failf(data, "schannel: trust for this certificate or one of " + "the certificates in the certificate chain has been revoked"); else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_PARTIAL_CHAIN"); + failf(data, "schannel: the certificate chain is incomplete"); else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_UNTRUSTED_ROOT"); + failf(data, "schannel: the certificate or certificate chain is " + "based on an untrusted root"); else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_NOT_TIME_VALID"); + failf(data, "schannel: this certificate or one of the certificates " + "in the certificate chain is not time valid"); else if(dwTrustErrorMask & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_REVOCATION_STATUS_UNKNOWN"); + failf(data, "schannel: the revocation status is unknown"); else - failf(data, "schannel: CertGetCertificateChain error mask: 0x%08lx", - dwTrustErrorMask); + failf(data, "schannel: error 0x%08lx", dwTrustErrorMask); result = CURLE_PEER_FAILED_VERIFICATION; } } From 9f75603d4fefacceed2e368638a1f7f12194d3ed Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 16:19:56 +0200 Subject: [PATCH 185/208] tftp: only check address if it was stored If recvfrom() fails, it might not have stored an address. Follow-up to c4f9977c66bbb05a837a7eb03004dd79c3cc9b44 Pointed out by CodeSonar Closes #18738 --- lib/tftp.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/tftp.c b/lib/tftp.c index 736b14b67364..ad2c84e6608d 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1106,19 +1106,21 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data, 0, (struct sockaddr *)&remote_addr, &fromlen); - if(state->remote_pinned) { - /* pinned, verify that it comes from the same address */ - if((state->remote_addrlen != fromlen) || - memcmp(&remote_addr, &state->remote_addr, fromlen)) { - failf(data, "Data received from another address"); - return CURLE_RECV_ERROR; + if(fromlen) { + if(state->remote_pinned) { + /* pinned, verify that it comes from the same address */ + if((state->remote_addrlen != fromlen) || + memcmp(&remote_addr, &state->remote_addr, fromlen)) { + failf(data, "Data received from another address"); + return CURLE_RECV_ERROR; + } + } + else { + /* pin address on first use */ + state->remote_pinned = TRUE; + state->remote_addrlen = fromlen; + memcpy(&state->remote_addr, &remote_addr, fromlen); } - } - else { - /* pin address on first use */ - state->remote_pinned = TRUE; - state->remote_addrlen = fromlen; - memcpy(&state->remote_addr, &remote_addr, fromlen); } /* Sanity check packet length */ From f5bae285f321063a3d48774915bb38187b4511ac Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:00:57 +0200 Subject: [PATCH 186/208] socks: handle error in verbose trace gracefully Adjust the flow to always succeed in verbose trace of connect. Reported in Joshua's sarif data Closes #18722 --- lib/socks.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/socks.c b/lib/socks.c index 6927e32c3ecb..da974ad6d8d7 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -1291,15 +1291,16 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, if(Curl_trc_is_verbose(data)) { struct ip_quadruple ipquad; bool is_ipv6; - result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad); - if(result) - return result; - infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " - "(via %s port %u)", - (sockindex == SECONDARYSOCKET) ? "2nd " : "", - ipquad.local_ip, ipquad.local_port, - sx->hostname, sx->remote_port, - ipquad.remote_ip, ipquad.remote_port); + if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) + infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " + "(via %s port %u)", + (sockindex == SECONDARYSOCKET) ? "2nd " : "", + ipquad.local_ip, ipquad.local_port, + sx->hostname, sx->remote_port, + ipquad.remote_ip, ipquad.remote_port); + else + infof(data, "Opened %sSOCKS connection", + (sockindex == SECONDARYSOCKET) ? "2nd " : ""); } #endif socks_proxy_cf_free(cf); From e48c1ea415d5076082bd2349d066c0df16dc9993 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 14:50:15 +0200 Subject: [PATCH 187/208] GHA: use `pyspelling` directly To avoid depending on Docker Hub, an Docker image and a GitHub Action. Also to simplify running this check on a local machine. Pending question if Dependabot and Mend/Renovate will automatically pick up `requirements-docs.txt`. Also: - enable parallel spellchecking. (also to win back the time lost with installing components directly from Debian and pip.) - pin `pyspelling`. - link to official `pyspelling` docs. Closes #18736 --- .github/scripts/requirements-docs.txt | 5 +++++ .github/scripts/spellcheck.yaml | 1 + .github/workflows/checkdocs.yml | 23 ++++++++++++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 .github/scripts/requirements-docs.txt diff --git a/.github/scripts/requirements-docs.txt b/.github/scripts/requirements-docs.txt new file mode 100644 index 000000000000..bd50e5010efb --- /dev/null +++ b/.github/scripts/requirements-docs.txt @@ -0,0 +1,5 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +pyspelling==2.11 diff --git a/.github/scripts/spellcheck.yaml b/.github/scripts/spellcheck.yaml index 05ddf0d937f1..8e26b76189bc 100644 --- a/.github/scripts/spellcheck.yaml +++ b/.github/scripts/spellcheck.yaml @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: curl # +# Docs: https://facelessuser.github.io/pyspelling/configuration/ # Docs: https://github.com/UnicornGlobal/spellcheck-github-actions matrix: - name: Markdown diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index f236ebc85013..a34a341a636f 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -113,13 +113,22 @@ jobs: # shellcheck disable=SC2046 .github/scripts/cleancmd.pl $(find docs -name '*.md') - - name: 'setup the custom wordlist' - run: grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt - - - name: 'check Spelling' - uses: rojopolis/spellcheck-github-actions@739a1e3ceb79a98a5d4a9bf76f351137f9d78892 # v0 - with: - config_path: .github/scripts/spellcheck.yaml + - name: 'install' + run: | + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get -o Dpkg::Use-Pty=0 update + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get -o Dpkg::Use-Pty=0 install aspell aspell-en + python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r .github/scripts/requirements-docs.txt + + - name: 'check spelling' + run: | + source ~/venv/bin/activate + grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt + aspell --version + pyspelling --version + pyspelling --verbose --jobs 5 --config .github/scripts/spellcheck.yaml badwords-synopsis: name: 'badwords, synopsis' From 9595921b06c911af278a645be1d298cb83e32df0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 16:32:18 +0200 Subject: [PATCH 188/208] libssh: clarify myssh_block2waitfor Fixed misleading comment. Simplified the bit setup. Reported in Joshua's sarif data Closes #18739 --- lib/vssh/libssh.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 576ac3b0c042..e1e660b4b3ae 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -2392,19 +2392,16 @@ static void myssh_block2waitfor(struct connectdata *conn, struct ssh_conn *sshc, bool block) { - /* If it did not block, or nothing was returned by ssh_get_poll_flags - * have the original set */ - conn->waitfor = sshc->orig_waitfor; - if(block) { int dir = ssh_get_poll_flags(sshc->ssh_session); - conn->waitfor = 0; /* translate the libssh define bits into our own bit defines */ - if(dir & SSH_READ_PENDING) - conn->waitfor |= KEEP_RECV; - if(dir & SSH_WRITE_PENDING) - conn->waitfor |= KEEP_SEND; + conn->waitfor = + ((dir & SSH_READ_PENDING) ? KEEP_RECV : 0) | + ((dir & SSH_WRITE_PENDING) ? KEEP_SEND : 0); } + else + /* if it did not block, use the original set */ + conn->waitfor = sshc->orig_waitfor; } /* called repeatedly until done from multi.c */ From b8f10be4f205665552a2dfd276889896e0c3116b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 16:38:49 +0200 Subject: [PATCH 189/208] libssh: acknowledge SSH_AGAIN in the SFTP state machine Reported in Joshua's sarif data Closes #18740 --- lib/vssh/libssh.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index e1e660b4b3ae..0f51137e8c72 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1959,6 +1959,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_SETSTAT: rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2, sshc->quote_attrs); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -1978,6 +1980,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_SYMLINK: rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2, sshc->quote_path1); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -1994,6 +1998,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_MKDIR: rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1, (mode_t)data->set.new_directory_perms); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "mkdir command failed: %s", @@ -2009,6 +2015,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_RENAME: rc = sftp_rename(sshc->sftp_session, sshc->quote_path1, sshc->quote_path2); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -2024,6 +2032,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_RMDIR: rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "rmdir command failed: %s", @@ -2038,6 +2048,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_UNLINK: rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "rm command failed: %s", From e27853d36b964e91baaa03d4a87802a2c4ba6eca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 15:03:08 +0000 Subject: [PATCH 190/208] GHA: update dependency ruff and github/codeql-action - update github/codeql-action digest to 303c0ae - update dependency ruff to v0.13.2 Closes #18716 Closes #18734 --- .github/scripts/requirements.txt | 2 +- .github/workflows/codeql.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index ac858451d59f..7cb10c47f866 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -6,4 +6,4 @@ cmakelang==0.6.13 codespell==2.4.1 pytype==2024.10.11 reuse==5.1.1 -ruff==0.13.1 +ruff==0.13.2 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f271d26b149b..53505673a473 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -48,13 +48,13 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3 + uses: github/codeql-action/init@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 with: languages: actions, python queries: security-extended - name: 'perform analysis' - uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 + uses: github/codeql-action/analyze@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 c: name: 'C' @@ -84,7 +84,7 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3 + uses: github/codeql-action/init@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 with: languages: cpp build-mode: manual @@ -129,4 +129,4 @@ jobs: fi - name: 'perform analysis' - uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 + uses: github/codeql-action/analyze@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 From 16e0a2098d91c87ab77ce568acdeda724baf753a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 22:32:23 +0200 Subject: [PATCH 191/208] openssl: fail the transfer if ossl_certchain() fails Since it would indicate errors to the degree that continuing would just risk hiding the earlier errors or make things weird. Inspired by a report in Joshua's sarif data Closes #18646 --- lib/vtls/openssl.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index d07c1bf773da..37cdd5574714 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -355,9 +355,8 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl) DEBUGASSERT(ssl); sk = SSL_get_peer_cert_chain(ssl); - if(!sk) { - return CURLE_OUT_OF_MEMORY; - } + if(!sk) + return CURLE_SSL_CONNECT_ERROR; numcerts = sk_X509_num(sk); @@ -4856,9 +4855,15 @@ CURLcode Curl_ossl_check_peer_cert(struct Curl_cfilter *cf, return CURLE_OUT_OF_MEMORY; } - if(data->set.ssl.certinfo) - /* asked to gather certificate info */ - (void)ossl_certchain(data, octx->ssl); + if(data->set.ssl.certinfo && !octx->reused_session) { + /* asked to gather certificate info. Reused sessions don't have cert + chains */ + result = ossl_certchain(data, octx->ssl); + if(result) { + BIO_free(mem); + return result; + } + } octx->server_cert = SSL_get1_peer_certificate(octx->ssl); if(!octx->server_cert) { From 500ea90829c825e9c19d2d4290d4d130e9ac42bd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 23:35:31 +0200 Subject: [PATCH 192/208] RELEASE-NOTES: synced --- RELEASE-NOTES | 63 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index da62171c7198..511be250eb03 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,7 +4,7 @@ curl and libcurl 8.17.0 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3508 + Contributors: 3509 This release includes the following changes: @@ -28,6 +28,7 @@ This release includes the following bugfixes: o build: address some `-Weverything` warnings, update picky warnings [74] o build: avoid overriding system symbols for socket functions [68] o build: show llvm/clang in platform flags and `buildinfo.txt` [126] + o cf-h2-proxy: break loop on edge case [140] o cf-socket: use the right byte order for ports in bindlocal [61] o cfilter: unlink and discard [46] o cmake: add `CURL_CODE_COVERAGE` option [78] @@ -60,10 +61,13 @@ This release includes the following bugfixes: o httpsrr: free old pointers when storing new [57] o krb5: return appropriate error on send failures [22] o ldap: do not base64 encode zero length string [42] + o lib: upgrade/multiplex handling [136] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh: acknowledge SSH_AGAIN in the SFTP state machine [89] + o libssh: clarify myssh_block2waitfor [92] o libssh: drop two unused assignments [104] o libssh: error on bad chgrp number [71] o libssh: error on bad chown number and store the value [64] @@ -74,24 +78,43 @@ This release includes the following bugfixes: o managen: ignore version mentions < 7.66.0 [55] o managen: render better manpage references/links [54] o managen: strict protocol check [109] + o mbedtls: check result of setting ALPN [127] + o mbedtls: handle WANT_WRITE from mbedtls_ssl_read() [145] o multi.h: add CURLMINFO_LASTENTRY [51] o ngtcp2: check error code on connect failure [13] + o ngtcp2: fix early return [131] o openldap: avoid indexing the result at -1 for blank responses [44] o openldap: check ldap_get_option() return codes [119] + o openssl-quic: check results better [132] + o openssl-quic: handle error in SSL_get_stream_read_error_code [129] + o openssl: clear retry flag on x509 error [130] + o openssl: fail the transfer if ossl_certchain() fails [23] o openssl: make the asn1_object_dump name null terminated [56] + o openssl: set io_need always [99] + o OS400: fix a use-after-free/double-free case [142] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o quiche: fix verbose message when ip quadruple cannot be obtained. [128] + o quiche: when ingress processing fails, return that error code [103] o rustls: fix clang-tidy warning [107] + o rustls: fix comment describing cr_recv() [117] o rustls: typecast variable for safer trace output [69] o rustls: use %zu for size_t in failf() format string [121] o sasl: clear canceled mechanism instead of toggling it [41] o schannel: assign result before using it [62] + o schannel_verify: use more human friendly error messages [96] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] + o socks: handle error in verbose trace gracefully [94] o socks: make Curl_blockread_all return CURLcode [67] + o socks: rewwork, cleaning up socks state handling [135] + o socks_gssapi: make the gss_context a local variable [144] o socks_gssapi: reject too long tokens [90] + o socks_gssapi: remove superfluous releases of the gss_recv_token [139] + o socks_gssapi: remove the forced "no protection" [143] + o socks_sspi: bail out on too long fields [137] o socks_sspi: fix memory cleanup calls [40] o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] @@ -116,10 +139,14 @@ This release includes the following bugfixes: o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_operate: improve wording in retry message [37] o tool_operate: keep the progress meter for --out-null [33] + o transfer: avoid busy loop with tiny speed limit [100] o urldata: FILE is not a list-only protocol [9] + o vtls: alpn setting, check proto parameter [134] o vtls_int.h: clarify data_pending [124] o windows: replace `_beginthreadex()` with `CreateThread()` [80] o windows: stop passing unused, optional argument for Win9x compatibility [75] + o wolfssl: check BIO read parameters [133] + o wolfssl: fix error check in shutdown [105] o ws: clarify an error message [125] o ws: reject curl_ws_recv called with NULL buffer with a buflen [118] @@ -149,9 +176,10 @@ advice from friends like these: divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, fds242 on github, Javier Blazquez, Jicea, jmaggard10 on github, Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, Marcel Raad, - Michael Osipov, Michał Petryka, Nir Azkiel, Ray Satiro, renovate[bot], - rinsuki on github, Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats - (28 contributors) + Michael Osipov, Michał Petryka, Nir Azkiel, Patrick Monnerat, Ray Satiro, + renovate[bot], rinsuki on github, Samuel Dionne-Riel, Stanislav Fort, + Stefan Eissing, Viktor Szakats + (30 contributors) References to bug reports and discussions on issues: @@ -177,6 +205,7 @@ References to bug reports and discussions on issues: [20] = https://curl.se/bug/?i=18554 [21] = https://curl.se/bug/?i=18618 [22] = https://curl.se/bug/?i=18561 + [23] = https://curl.se/bug/?i=18646 [24] = https://curl.se/bug/?i=18616 [25] = https://curl.se/bug/?i=18491 [26] = https://curl.se/bug/?i=18606 @@ -241,11 +270,19 @@ References to bug reports and discussions on issues: [85] = https://curl.se/bug/?i=18612 [87] = https://curl.se/bug/?i=18707 [88] = https://curl.se/bug/?i=18680 + [89] = https://curl.se/bug/?i=18740 [90] = https://curl.se/bug/?i=18681 [91] = https://curl.se/bug/?i=18251 + [92] = https://curl.se/bug/?i=18739 + [94] = https://curl.se/bug/?i=18722 + [96] = https://curl.se/bug/?i=18737 + [99] = https://curl.se/bug/?i=18733 + [100] = https://curl.se/bug/?i=18732 [101] = https://curl.se/bug/?i=18689 [102] = https://curl.se/bug/?i=18688 + [103] = https://curl.se/bug/?i=18730 [104] = https://curl.se/bug/?i=18684 + [105] = https://curl.se/bug/?i=18729 [106] = https://curl.se/bug/?i=18671 [107] = https://curl.se/bug/?i=18670 [108] = https://curl.se/bug/?i=18633 @@ -257,6 +294,7 @@ References to bug reports and discussions on issues: [114] = https://curl.se/bug/?i=18666 [115] = https://curl.se/bug/?i=18664 [116] = https://curl.se/bug/?i=18659 + [117] = https://curl.se/bug/?i=18728 [118] = https://curl.se/bug/?i=18656 [119] = https://curl.se/bug/?i=18653 [120] = https://curl.se/bug/?i=18652 @@ -266,3 +304,20 @@ References to bug reports and discussions on issues: [124] = https://curl.se/bug/?i=18644 [125] = https://curl.se/bug/?i=18654 [126] = https://curl.se/bug/?i=18645 + [127] = https://curl.se/bug/?i=18727 + [128] = https://curl.se/bug/?i=18726 + [129] = https://curl.se/bug/?i=18725 + [130] = https://curl.se/bug/?i=18724 + [131] = https://curl.se/bug/?i=18723 + [132] = https://curl.se/bug/?i=18720 + [133] = https://curl.se/bug/?i=18718 + [134] = https://curl.se/bug/?i=18717 + [135] = https://curl.se/bug/?i=18401 + [136] = https://curl.se/bug/?i=18227 + [137] = https://curl.se/bug/?i=18719 + [139] = https://curl.se/bug/?i=18714 + [140] = https://curl.se/bug/?i=18715 + [142] = https://curl.se/bug/?i=18713 + [143] = https://curl.se/bug/?i=18712 + [144] = https://curl.se/bug/?i=18711 + [145] = https://curl.se/bug/?i=18682 From 061e265502fc2f605f0d87453b8b1167ba16839d Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 22 Sep 2025 15:48:07 +0200 Subject: [PATCH 193/208] http: handle user-defined connection headers When there is more than one user-supplied 'Connection: ' header, add values that curl needs internally to the first one and emit all subsequent ones thereafter. Fixes #18662 Reported-by: Evgeny Grin (Karlson2k) Closes #18686 --- docs/libcurl/opts/CURLOPT_HTTPHEADER.md | 4 ++ lib/http.c | 64 +++++++++++++++++---- tests/data/Makefile.am | 2 +- tests/data/test1617 | 75 +++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 tests/data/test1617 diff --git a/docs/libcurl/opts/CURLOPT_HTTPHEADER.md b/docs/libcurl/opts/CURLOPT_HTTPHEADER.md index 4440b4ec4b61..c7a705bedc82 100644 --- a/docs/libcurl/opts/CURLOPT_HTTPHEADER.md +++ b/docs/libcurl/opts/CURLOPT_HTTPHEADER.md @@ -55,6 +55,10 @@ without content (no data on the right side of the colon) as in `Accept:`, the internally used header is removed. To forcibly add a header without content (nothing after the colon), use the form `name;` (using a trailing semicolon). +There are exceptions when suppressing headers. The `Connection:` header in +HTTP/1.1 cannot be overridden. You can provide values for it, but should a +request require specific ones, they are always added to your own. + The headers included in the linked list **must not** be CRLF-terminated, since libcurl adds CRLF after each header item itself. Failure to comply with this might result in strange behavior. libcurl passes on the verbatim strings you diff --git a/lib/http.c b/lib/http.c index ce31e6dff005..3479bb4ec976 100644 --- a/lib/http.c +++ b/lib/http.c @@ -263,6 +263,19 @@ char *Curl_checkProxyheaders(struct Curl_easy *data, #define Curl_checkProxyheaders(x,y,z,a) NULL #endif +static bool http_header_is_empty(const char *header) +{ + struct Curl_str out; + + if(!curlx_str_cspn(&header, &out, ";:") && + (!curlx_str_single(&header, ':') || !curlx_str_single(&header, ';'))) { + curlx_str_untilnl(&header, &out, MAX_HTTP_RESP_HEADER_SIZE); + curlx_str_trimblanks(&out); + return curlx_strlen(&out) == 0; + } + return TRUE; /* invalid head format, treat as empty */ +} + /* * Strip off leading and trailing whitespace from the value in the given HTTP * header line and return a strdup()ed copy. Returns NULL in case of @@ -1702,7 +1715,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, curlx_str_casecompare(&name, "Content-Length")) ; else if(curlx_str_casecompare(&name, "Connection")) - /* Normal Connection: header generation takes care of this */ + /* Connection headers are handled specially */ ; else if((httpversion >= 20) && curlx_str_casecompare(&name, "Transfer-Encoding")) @@ -2636,17 +2649,29 @@ static CURLcode http_check_new_conn(struct Curl_easy *data) static CURLcode http_add_connection_hd(struct Curl_easy *data, struct dynbuf *req) { - char *custom = Curl_checkheaders(data, STRCONST("Connection")); - char *custom_val = custom ? Curl_copy_header_value(custom) : NULL; - const char *sep = (custom_val && *custom_val) ? ", " : "Connection: "; + struct curl_slist *head; + const char *sep = "Connection: "; CURLcode result = CURLE_OK; size_t rlen = curlx_dyn_len(req); + char *value; + bool skip; + + /* Add the 1st custom "Connection: " header, if there is one */ + for(head = data->set.headers; head; head = head->next) { + if(curl_strnequal(head->data, "Connection", 10) && + Curl_headersep(head->data[10]) && + !http_header_is_empty(head->data)) { + value = Curl_copy_header_value(head->data); + if(!value) + return CURLE_OUT_OF_MEMORY; + result = curlx_dyn_addf(req, "%s%s", sep, value); + sep = ", "; + free(value); + break; /* leave, having added 1st one */ + } + } - if(custom && !custom_val) - return CURLE_OUT_OF_MEMORY; - - if(custom_val && *custom_val) - result = curlx_dyn_addf(req, "Connection: %s", custom_val); + /* add our internal Connection: header values, if we have any */ if(!result && data->state.http_hd_te) { result = curlx_dyn_addf(req, "%s%s", sep, "TE"); sep = ", "; @@ -2660,9 +2685,26 @@ static CURLcode http_add_connection_hd(struct Curl_easy *data, } if(!result && (rlen < curlx_dyn_len(req))) result = curlx_dyn_addn(req, STRCONST("\r\n")); + if(result) + return result; - free(custom_val); - return result; + /* Add all user-defined Connection: headers after the first */ + skip = TRUE; + for(head = data->set.headers; head; head = head->next) { + if(curl_strnequal(head->data, "Connection", 10) && + Curl_headersep(head->data[10]) && + !http_header_is_empty(head->data)) { + if(skip) { + skip = FALSE; + continue; + } + result = curlx_dyn_addf(req, "%s\r\n", head->data); + if(result) + return result; + } + } + + return CURLE_OK; } /* Header identifier in order we send them by default */ diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 854791fba0e9..5063e0210f42 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -214,7 +214,7 @@ test1580 test1581 \ test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \ test1598 test1599 test1600 test1601 test1602 test1603 test1604 test1605 \ test1606 test1607 test1608 test1609 test1610 test1611 test1612 test1613 \ -test1614 test1615 test1616 \ +test1614 test1615 test1616 test1617 \ test1620 test1621 \ \ test1630 test1631 test1632 test1633 test1634 test1635 \ diff --git a/tests/data/test1617 b/tests/data/test1617 new file mode 100644 index 000000000000..0fe967bd27a7 --- /dev/null +++ b/tests/data/test1617 @@ -0,0 +1,75 @@ + + + +HTTP +HTTP GET +compressed +Transfer-Encoding + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Mon, 29 Nov 2004 21:56:53 GMT +Server: Apache/1.3.31 (Debian GNU/Linux) mod_gzip/1.3.26.1a PHP/4.3.9-1 mod_ssl/2.8.20 OpenSSL/0.9.7d mod_perl/1.29 +Vary: Accept-Encoding +Content-Type: text/html; charset=ISO-8859-1 +Transfer-Encoding: gzip, chunked + +2c +%hex[%1f%8b%08%08%79%9e%ab%41%00%03%6c%61%6c%61%6c%61%00%cb%c9%cc%4b%55%30%e4%52%c8%01%d1%46%5c]hex% +%hex[%10%86%31%17%00]hex% +%hex[%02%71%60%18%00%00%00]hex% +0 + + + + +HTTP/1.1 200 OK +Date: Mon, 29 Nov 2004 21:56:53 GMT +Server: Apache/1.3.31 (Debian GNU/Linux) mod_gzip/1.3.26.1a PHP/4.3.9-1 mod_ssl/2.8.20 OpenSSL/0.9.7d mod_perl/1.29 +Vary: Accept-Encoding +Content-Type: text/html; charset=ISO-8859-1 +Transfer-Encoding: gzip, chunked + +line 1 + line 2 + line 3 + + + + +# +# Client-side + + +libz + + +http + + +HTTP GET transfer-encoding with two user Connection: headers + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --tr-encoding -H "Connection: this" -H "Connection: that" + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* +TE: gzip +Connection: this, TE +Connection: that + + + + From 84d96275319869e1f0e6c374e39b54a7d892d146 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 26 Sep 2025 09:43:19 +0200 Subject: [PATCH 194/208] tool_progress: handle possible integer overflows The progress meters max out at 2^63 bytes. Reported-by: BobodevMm on github Fixes #18744 Closes #18746 --- src/tool_progress.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/tool_progress.c b/src/tool_progress.c index 666fe9869cd7..aae2ff68b184 100644 --- a/src/tool_progress.c +++ b/src/tool_progress.c @@ -144,6 +144,15 @@ static unsigned int speedindex; static bool indexwrapped; static struct speedcount speedstore[SPEEDCNT]; +static void add_offt(curl_off_t *val, curl_off_t add) +{ + if(CURL_OFF_T_MAX - *val < add) + /* maxed out! */ + *val = CURL_OFF_T_MAX; + else + *val += add; +} + /* |DL% UL% Dled Uled Xfers Live Total Current Left Speed | 6 -- 9.9G 0 2 2 0:00:40 0:00:02 0:00:37 4087M @@ -189,24 +198,24 @@ bool progress_meter(CURLM *multi, stamp = now; /* first add the amounts of the already completed transfers */ - all_dlnow += all_dlalready; - all_ulnow += all_ulalready; + add_offt(&all_dlnow, all_dlalready); + add_offt(&all_ulnow, all_ulalready); for(per = transfers; per; per = per->next) { - all_dlnow += per->dlnow; - all_ulnow += per->ulnow; + add_offt(&all_dlnow, per->dlnow); + add_offt(&all_ulnow, per->ulnow); if(!per->dltotal) dlknown = FALSE; else if(!per->dltotal_added) { /* only add this amount once */ - all_dltotal += per->dltotal; + add_offt(&all_dltotal, per->dltotal); per->dltotal_added = TRUE; } if(!per->ultotal) ulknown = FALSE; else if(!per->ultotal_added) { /* only add this amount once */ - all_ultotal += per->ultotal; + add_offt(&all_ultotal, per->ultotal); per->ultotal_added = TRUE; } } @@ -306,14 +315,14 @@ bool progress_meter(CURLM *multi, void progress_finalize(struct per_transfer *per) { /* get the numbers before this transfer goes away */ - all_dlalready += per->dlnow; - all_ulalready += per->ulnow; + add_offt(&all_dlalready, per->dlnow); + add_offt(&all_ulalready, per->ulnow); if(!per->dltotal_added) { - all_dltotal += per->dltotal; + add_offt(&all_dltotal, per->dltotal); per->dltotal_added = TRUE; } if(!per->ultotal_added) { - all_ultotal += per->ultotal; + add_offt(&all_ultotal, per->ultotal); per->ultotal_added = TRUE; } } From 72f72f678d1669d9758ad3f948321ee4dfc71330 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 26 Sep 2025 13:53:04 +0200 Subject: [PATCH 195/208] openldap: check ber_sockbuf_add_io() return code The man page says nothing about what the return code means but Howard Chu tells me it is 0 on success, -1 on fail. Help-by: Howard Chu Closes #18747 --- lib/openldap.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/lib/openldap.c b/lib/openldap.c index 7d25d1842112..6aa74e028f8b 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -531,19 +531,19 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate) if(!li) return CURLE_FAILED_INIT; result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); - if(!result) { - oldap_state(data, li, newstate); + if(result) + return result; + oldap_state(data, li, newstate); - if(ssldone) { - Sockbuf *sb; + if(ssldone) { + Sockbuf *sb; - /* Install the libcurl SSL handlers into the sockbuf. */ - if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) - return CURLE_FAILED_INIT; - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); - li->recv = conn->recv[FIRSTSOCKET]; - li->send = conn->send[FIRSTSOCKET]; - } + /* Install the libcurl SSL handlers into the sockbuf. */ + if((ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) || + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data)) + return CURLE_FAILED_INIT; + li->recv = conn->recv[FIRSTSOCKET]; + li->send = conn->send[FIRSTSOCKET]; } return result; @@ -947,19 +947,18 @@ static CURLcode oldap_disconnect(struct Curl_easy *data, (void)data; #endif - if(li) { - if(li->ld) { + if(li && li->ld) { #ifdef USE_SSL - if(ssl_installed(conn)) { - Sockbuf *sb; - if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) - return CURLE_FAILED_INIT; - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); - } -#endif - ldap_unbind_ext(li->ld, NULL, NULL); - li->ld = NULL; + if(ssl_installed(conn)) { + Sockbuf *sb; + if((ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + || + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data)) + return CURLE_FAILED_INIT; } +#endif + ldap_unbind_ext(li->ld, NULL, NULL); + li->ld = NULL; } return CURLE_OK; } @@ -988,9 +987,9 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) if(ssl_installed(conn)) { Sockbuf *sb; /* re-install the libcurl SSL handlers into the sockbuf. */ - if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + if((ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) || + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data)) return CURLE_FAILED_INIT; - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); } #endif From 34b1e146e42f2dbac5c89414a2a0458a8729a255 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 01:54:28 +0200 Subject: [PATCH 196/208] perlcheck: add script, run in CI, fix fallouts Add script to run all Perl sources through `perl -c` to ensure no issues, and run this script via GHA/checksrc in CI. Fallouts: - fix two repeated declarations. - move `shell_quote()` from `testutil.pm` to `pathhelp.pm`, to avoid circular dependency in `globalconfig.pm`. Closes #18745 --- .github/workflows/checksrc.yml | 4 +++ scripts/Makefile.am | 3 ++- scripts/perlcheck.sh | 47 ++++++++++++++++++++++++++++++++++ tests/globalconfig.pm | 4 +-- tests/pathhelp.pm | 20 +++++++++++++++ tests/runner.pm | 2 +- tests/runtests.pl | 1 + tests/servers.pm | 2 +- tests/test745.pl | 5 ++-- tests/testcurl.pl | 6 +++-- tests/testutil.pm | 20 --------------- 11 files changed, 84 insertions(+), 30 deletions(-) create mode 100755 scripts/perlcheck.sh diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index b101a822c545..71ee031d68a8 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -82,6 +82,10 @@ jobs: source ~/venv/bin/activate scripts/cmakelint.sh + - name: 'perlcheck' + run: | + scripts/perlcheck.sh + - name: 'pytype' run: | source ~/venv/bin/activate diff --git a/scripts/Makefile.am b/scripts/Makefile.am index cfa3d3e740a9..a52581155d46 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -25,7 +25,8 @@ EXTRA_DIST = coverage.sh completion.pl firefox-db2pem.sh checksrc.pl checksrc-all.pl \ mk-ca-bundle.pl mk-unity.pl schemetable.c cd2nroff nroff2cd cdall cd2cd managen \ dmaketgz maketgz release-tools.sh verify-release cmakelint.sh mdlinkcheck \ - CMakeLists.txt pythonlint.sh randdisable wcurl top-complexity extract-unit-protos + CMakeLists.txt perlcheck.sh pythonlint.sh randdisable wcurl top-complexity \ + extract-unit-protos dist_bin_SCRIPTS = wcurl diff --git a/scripts/perlcheck.sh b/scripts/perlcheck.sh new file mode 100755 index 000000000000..be0c0e1c870f --- /dev/null +++ b/scripts/perlcheck.sh @@ -0,0 +1,47 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Dan Fandrich, , Viktor Szakats, 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 +# +########################################################################### + +# The xargs invocation is portable, but does not preserve spaces in file names. +# If such a file is ever added, then this can be portably fixed by switching to +# "xargs -I{}" and appending {} to the end of the xargs arguments (which will +# call cmakelint once per file) or by using the GNU extension "xargs -d'\n'". + +set -eu + +cd "$(dirname "$0")"/.. + +{ + if [ -n "${1:-}" ]; then + for A in "$@"; do printf "%s\n" "$A"; done + elif git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + { + git ls-files | grep -E '\.(pl|pm)$' + git grep -l -E '^#!/usr/bin/env perl' + } | sort -u + else + # strip off the leading ./ to make the grep regexes work properly + find . -type f \( -name '*.pl' -o -name '*.pm' \) | sed 's@^\./@@' + fi +} | xargs -n 1 perl -c -Itests diff --git a/tests/globalconfig.pm b/tests/globalconfig.pm index de9abab34c2a..8635dea55b58 100644 --- a/tests/globalconfig.pm +++ b/tests/globalconfig.pm @@ -78,11 +78,9 @@ BEGIN { use pathhelp qw( exe_ext dirsepadd - ); -use Cwd qw(getcwd); -use testutil qw( shell_quote ); +use Cwd qw(getcwd); use File::Spec; diff --git a/tests/pathhelp.pm b/tests/pathhelp.pm index 169582518848..49987f745388 100644 --- a/tests/pathhelp.pm +++ b/tests/pathhelp.pm @@ -60,6 +60,7 @@ BEGIN { os_is_win exe_ext dirsepadd + shell_quote sys_native_abs_path sys_native_current_path build_sys_abs_path @@ -192,4 +193,23 @@ sub dirsepadd { return $dir . '/'; } +####################################################################### +# Quote an argument for passing safely to a Bourne shell +# This does the same thing as String::ShellQuote but doesn't need a package. +# +sub shell_quote { + my ($s)=@_; + if($^O eq 'MSWin32') { + $s = '"' . $s . '"'; + } + else { + if($s !~ m/^[-+=.,_\/:a-zA-Z0-9]+$/) { + # string contains a "dangerous" character--quote it + $s =~ s/'/'"'"'/g; + $s = "'" . $s . "'"; + } + } + return $s; +} + 1; # End of module diff --git a/tests/runner.pm b/tests/runner.pm index 62f722f319bc..1eef1f5b9d3f 100644 --- a/tests/runner.pm +++ b/tests/runner.pm @@ -84,6 +84,7 @@ use Storable qw( use pathhelp qw( exe_ext + shell_quote ); use servers qw( checkcmd @@ -100,7 +101,6 @@ use testutil qw( logmsg runclient exerunner - shell_quote subbase64 subsha256base64file substrippemfile diff --git a/tests/runtests.pl b/tests/runtests.pl index 6b6e5b076191..d836841a296d 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -91,6 +91,7 @@ BEGIN use pathhelp qw( exe_ext sys_native_current_path + shell_quote ); use appveyor; diff --git a/tests/servers.pm b/tests/servers.pm index e62505887076..e5505886f6af 100644 --- a/tests/servers.pm +++ b/tests/servers.pm @@ -105,6 +105,7 @@ use pathhelp qw( os_is_win build_sys_abs_path sys_native_abs_path + shell_quote ); use processhelp; @@ -114,7 +115,6 @@ use testutil qw( runclient runclientoutput exerunner - shell_quote ); diff --git a/tests/test745.pl b/tests/test745.pl index faddda429f39..4395eb9681ab 100755 --- a/tests/test745.pl +++ b/tests/test745.pl @@ -45,7 +45,8 @@ sub gettypecheck { } sub getinclude { - open(my $f, "<", "$root/include/curl/curl.h") + my $f; + open($f, "<", "$root/include/curl/curl.h") || die "no curl.h"; while(<$f>) { if($_ =~ /\((CURLOPT[^,]*), (CURLOPTTYPE_[^,]*)/) { @@ -61,7 +62,7 @@ sub getinclude { $enum{"CURLOPT_CONV_TO_NETWORK_FUNCTION"}++; close($f); - open(my $f, "<", "$root/include/curl/multi.h") + open($f, "<", "$root/include/curl/multi.h") || die "no curl.h"; while(<$f>) { if($_ =~ /\((CURLMOPT[^,]*), (CURLOPTTYPE_[^,]*)/) { diff --git a/tests/testcurl.pl b/tests/testcurl.pl index 8d6183102bbf..4f3eade70347 100755 --- a/tests/testcurl.pl +++ b/tests/testcurl.pl @@ -584,8 +584,10 @@ sub findinpath { } } +my $f; + logit_spaced "display lib/$confheader"; -open(my $f, "<", "lib/$confheader") or die "lib/$confheader: $!"; +open($f, "<", "lib/$confheader") or die "lib/$confheader: $!"; while(<$f>) { print if /^ *#/; } @@ -660,7 +662,7 @@ sub findinpath { my $mkcmd = "$make -i" . ($targetos && !$configurebuild ? " $targetos" : ""); logit "$mkcmd"; -open(my $f, "-|", "$mkcmd 2>&1") or die; +open($f, "-|", "$mkcmd 2>&1") or die; while(<$f>) { s/$pwd//g; print; diff --git a/tests/testutil.pm b/tests/testutil.pm index e84cc45fde2c..3477d5bb57f8 100644 --- a/tests/testutil.pm +++ b/tests/testutil.pm @@ -38,7 +38,6 @@ BEGIN { runclientoutput setlogfunc exerunner - shell_quote subbase64 subnewlines subsha256base64file @@ -219,25 +218,6 @@ sub exerunner { return ''; } -####################################################################### -# Quote an argument for passing safely to a Bourne shell -# This does the same thing as String::ShellQuote but doesn't need a package. -# -sub shell_quote { - my ($s)=@_; - if($^O eq 'MSWin32') { - $s = '"' . $s . '"'; - } - else { - if($s !~ m/^[-+=.,_\/:a-zA-Z0-9]+$/) { - # string contains a "dangerous" character--quote it - $s =~ s/'/'"'"'/g; - $s = "'" . $s . "'"; - } - } - return $s; -} - sub get_sha256_base64 { my ($file_path) = @_; return encode_base64(sha256(do { local $/; open my $fh, '<:raw', $file_path or die $!; <$fh> }), ""); From b5ffe30e5b7e79d51ec96c266538eb5586c6a0dd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 26 Sep 2025 16:30:34 +0200 Subject: [PATCH 197/208] cf-ip-happy: mention unix domain path, not port number In the connect error message if a unix domain socket was used. Reported-by: kuchara on github Ref: #18748 Closes #18749 --- lib/cf-ip-happy.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index 5e4c20444e79..0a1364e4b3f5 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -627,26 +627,35 @@ static CURLcode is_connected(struct Curl_cfilter *cf, { const char *hostname, *proxy_name = NULL; - int port; + char viamsg[160]; #ifndef CURL_DISABLE_PROXY if(conn->bits.socksproxy) proxy_name = conn->socks_proxy.host.name; else if(conn->bits.httpproxy) proxy_name = conn->http_proxy.host.name; #endif - hostname = conn->bits.conn_to_host ? - conn->conn_to_host.name : conn->host.name; + hostname = conn->bits.conn_to_host ? conn->conn_to_host.name : + conn->host.name; - if(cf->sockindex == SECONDARYSOCKET) - port = conn->secondary_port; - else if(cf->conn->bits.conn_to_port) - port = conn->conn_to_port; +#ifdef USE_UNIX_SOCKETS + if(conn->unix_domain_socket) + msnprintf(viamsg, sizeof(viamsg), "over %s", conn->unix_domain_socket); else - port = conn->remote_port; +#endif + { + int port; + if(cf->sockindex == SECONDARYSOCKET) + port = conn->secondary_port; + else if(cf->conn->bits.conn_to_port) + port = conn->conn_to_port; + else + port = conn->remote_port; + msnprintf(viamsg, sizeof(viamsg), "port %u", port); + } - failf(data, "Failed to connect to %s port %u %s%s%safter " + failf(data, "Failed to connect to %s %s %s%s%safter " "%" FMT_TIMEDIFF_T " ms: %s", - hostname, port, + hostname, viamsg, proxy_name ? "via " : "", proxy_name ? proxy_name : "", proxy_name ? " " : "", From 8538856662460fdcb38bafde3218ee3022e64807 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 26 Sep 2025 20:57:16 +0200 Subject: [PATCH 198/208] perlcheck: parallelize Follow-up to 34b1e146e42f2dbac5c89414a2a0458a8729a255 #18745 Closes #18750 --- scripts/perlcheck.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/perlcheck.sh b/scripts/perlcheck.sh index be0c0e1c870f..7de0f6dbb559 100755 --- a/scripts/perlcheck.sh +++ b/scripts/perlcheck.sh @@ -32,6 +32,10 @@ set -eu cd "$(dirname "$0")"/.. +procs=6 +command -v nproc >/dev/null && procs="$(nproc)" +echo "parallel: ${procs}" + { if [ -n "${1:-}" ]; then for A in "$@"; do printf "%s\n" "$A"; done @@ -44,4 +48,4 @@ cd "$(dirname "$0")"/.. # strip off the leading ./ to make the grep regexes work properly find . -type f \( -name '*.pl' -o -name '*.pm' \) | sed 's@^\./@@' fi -} | xargs -n 1 perl -c -Itests +} | xargs -n 1 -P "${procs}" perl -c -Itests From 95e50ad69473d8229b85478a3f2138b7e632fbe8 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 16 Sep 2025 19:28:27 +0200 Subject: [PATCH 199/208] tidy-up: miscellaneous - GHA/checkdocs: rename `spellcheck` job to `pyspelling` to say the exact tool used. - GHA/checkdocs: restore a comment. - GHA/linux: add `-B .` to a cmake configure to avoid warning, and future breakage. - autotools: use correct casing for `Schannel`. - doh: update RFC URL. - drop redundant parenthesis. - fix indentation, whitespace. Closes #18756 --- .github/workflows/checkdocs.yml | 5 +++-- configure.ac | 6 +++--- docs/libcurl/libcurl.m4 | 2 +- lib/curl_threads.c | 1 - lib/curlx/version_win32.c | 2 +- lib/doh.c | 2 +- lib/system_win32.c | 6 +++--- lib/telnet.c | 22 +++++++++------------- lib/vtls/openssl.c | 2 +- lib/vtls/schannel.c | 4 ++-- lib/ws.c | 12 ++++++------ 11 files changed, 30 insertions(+), 34 deletions(-) diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index a34a341a636f..3f802b5c4edc 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -100,8 +100,8 @@ jobs: - name: 'mdlinkcheck' run: ./scripts/mdlinkcheck - spellcheck: - name: 'spellcheck' + pyspelling: + name: 'pyspelling' runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 @@ -125,6 +125,7 @@ jobs: - name: 'check spelling' run: | source ~/venv/bin/activate + # setup the custom wordlist grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt aspell --version pyspelling --version diff --git a/configure.ac b/configure.ac index 56ac66de2369..fddae6a630d1 100644 --- a/configure.ac +++ b/configure.ac @@ -208,7 +208,7 @@ OPT_SCHANNEL=no AC_ARG_WITH(schannel,dnl AS_HELP_STRING([--with-schannel],[enable Windows native SSL/TLS]), OPT_SCHANNEL=$withval - TLSCHOICE="schannel") + TLSCHOICE="Schannel") OPT_AMISSL=no AC_ARG_WITH(amissl,dnl @@ -5033,8 +5033,8 @@ if test "x$want_ech" != "xno"; then ECH_ENABLED_WOLFSSL=1) fi if test "x$RUSTLS_ENABLED" = "x1"; then - ECH_SUPPORT="$ECH_SUPPORT rustls-ffi" - ECH_ENABLED_RUSTLS=1 + ECH_SUPPORT="$ECH_SUPPORT rustls-ffi" + ECH_ENABLED_RUSTLS=1 fi dnl now deal with whatever we found diff --git a/docs/libcurl/libcurl.m4 b/docs/libcurl/libcurl.m4 index 4c89511f06ce..973493f03af5 100644 --- a/docs/libcurl/libcurl.m4 +++ b/docs/libcurl/libcurl.m4 @@ -178,7 +178,7 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG], x=CURLOPT_ERRORBUFFER; x=CURLOPT_STDERR; x=CURLOPT_VERBOSE; - if (x) {;} + if(x) {;} ]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) CPPFLAGS=$_libcurl_save_cppflags diff --git a/lib/curl_threads.c b/lib/curl_threads.c index 94425d19fe8a..a585d26d3fac 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -134,7 +134,6 @@ int Curl_thread_join(curl_thread_t *hnd) Curl_thread_destroy(hnd); - return ret; } diff --git a/lib/curlx/version_win32.c b/lib/curlx/version_win32.c index 4efe62b111ca..7e415dfe89d9 100644 --- a/lib/curlx/version_win32.c +++ b/lib/curlx/version_win32.c @@ -139,7 +139,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, #pragma clang diagnostic ignored "-Wcast-function-type-strict" #endif pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, - (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo"))); + GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")); #if defined(__clang__) && __clang_major__ >= 16 #pragma clang diagnostic pop #endif diff --git a/lib/doh.c b/lib/doh.c index 069d5387eaf0..a76f42207d60 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -1062,7 +1062,7 @@ UNITTEST void de_cleanup(struct dohentry *d) * @return is 1 for success, error otherwise * * The encoding here is defined in - * https://tools.ietf.org/html/rfc1035#section-3.1 + * https://datatracker.ietf.org/doc/html/rfc1035#section-3.1 * * The input buffer pointer will be modified so it points to * just after the end of the DNS name encoding on output. (And diff --git a/lib/system_win32.c b/lib/system_win32.c index a890a0ea9896..cd01fd2ebfe3 100644 --- a/lib/system_win32.c +++ b/lib/system_win32.c @@ -106,8 +106,8 @@ CURLcode Curl_win32_init(long flags) #endif IF_NAMETOINDEX_FN pIfNameToIndex = CURLX_FUNCTION_CAST(IF_NAMETOINDEX_FN, - (GetProcAddress(s_hIpHlpApiDll, - CURL_TEXT("if_nametoindex")))); + GetProcAddress(s_hIpHlpApiDll, + CURL_TEXT("if_nametoindex"))); if(pIfNameToIndex) Curl_if_nametoindex = pIfNameToIndex; @@ -202,7 +202,7 @@ static HMODULE curl_load_library(LPCTSTR filename) and above */ pLoadLibraryEx = CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN, - (GetProcAddress(hKernel32, LOADLIBARYEX))); + GetProcAddress(hKernel32, LOADLIBARYEX)); /* Detect if there is already a path in the filename and load the library if there is. Note: Both back slashes and forward slashes have been supported diff --git a/lib/telnet.c b/lib/telnet.c index f2226a7f7dd8..66585d6f2a30 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -108,15 +108,15 @@ */ typedef enum { - CURL_TS_DATA = 0, - CURL_TS_IAC, - CURL_TS_WILL, - CURL_TS_WONT, - CURL_TS_DO, - CURL_TS_DONT, - CURL_TS_CR, - CURL_TS_SB, /* sub-option collection */ - CURL_TS_SE /* looking for sub-option end */ + CURL_TS_DATA = 0, + CURL_TS_IAC, + CURL_TS_WILL, + CURL_TS_WONT, + CURL_TS_DO, + CURL_TS_DONT, + CURL_TS_CR, + CURL_TS_SB, /* sub-option collection */ + CURL_TS_SE /* looking for sub-option end */ } TelnetReceive; struct TELNET { @@ -939,7 +939,6 @@ static bool bad_option(const char *data) * Look at the sub-option buffer, and try to be helpful to the other * side. */ - static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) { struct curl_slist *v; @@ -1023,13 +1022,11 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) return CURLE_OK; } - /* * sendsuboption() * * Send suboption information to the server side. */ - static void sendsuboption(struct Curl_easy *data, struct TELNET *tn, int option) { @@ -1084,7 +1081,6 @@ static void sendsuboption(struct Curl_easy *data, } } - static CURLcode telrcv(struct Curl_easy *data, struct TELNET *tn, diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 37cdd5574714..36818daa9e17 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -125,7 +125,7 @@ static void ossl_provider_cleanup(struct Curl_easy *data); * X509_V_ERR_EC_KEY_EXPLICIT_PARAMS. */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && \ - (!defined(OPENSSL_IS_AWSLC) || (defined(X509_V_ERR_EC_KEY_EXPLICIT_PARAMS))) + (!defined(OPENSSL_IS_AWSLC) || defined(X509_V_ERR_EC_KEY_EXPLICIT_PARAMS)) #define HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN 1 #endif diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 8b7f1d9306c1..8ff8029e3b3e 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -2558,8 +2558,8 @@ static int schannel_init(void) #endif WINE_GET_VERSION_FN p_wine_get_version = CURLX_FUNCTION_CAST(WINE_GET_VERSION_FN, - (GetProcAddress(GetModuleHandleA("ntdll"), - "wine_get_version"))); + GetProcAddress(GetModuleHandleA("ntdll"), + "wine_get_version")); #if defined(__clang__) && __clang_major__ >= 16 #pragma clang diagnostic pop #endif diff --git a/lib/ws.c b/lib/ws.c index 6a265fccc700..36c9c91f6542 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -545,7 +545,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, const unsigned char tmp = '\0'; /* special case of a 0 length frame, need to write once */ result = write_cb(&tmp, 0, dec->frame_age, dec->frame_flags, - 0, 0, write_ctx, &nwritten); + 0, 0, write_ctx, &nwritten); if(result) return result; dec->state = WS_DEC_INIT; @@ -680,8 +680,8 @@ static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen, payload_len, buflen); result = Curl_cwriter_write(data, ctx->next_writer, - (ctx->cw_type | CLIENTWRITE_0LEN), - (const char *)buf, buflen); + (ctx->cw_type | CLIENTWRITE_0LEN), + (const char *)buf, buflen); if(result) return result; } @@ -1579,9 +1579,9 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, *metap = &ws->recvframe; *nread = ws->recvframe.len; CURL_TRC_WS(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %" - FMT_OFF_T ", %" FMT_OFF_T " left)", - buflen, *nread, ws->recvframe.offset, - ws->recvframe.bytesleft); + FMT_OFF_T ", %" FMT_OFF_T " left)", + buflen, *nread, ws->recvframe.offset, + ws->recvframe.bytesleft); /* all's well, try to send any pending control. we do not know * when the application will call `curl_ws_send()` again. */ if(!data->set.ws_raw_mode && ws->pending.type) { From 16f721443aee235014f3d17e623c5c5eeb24b83e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 27 Sep 2025 13:02:12 +0200 Subject: [PATCH 200/208] GHA/linux: tidy up AWS-LC local build To sync with other builds and to use `-B` to avoid a cmake warning and future breakage. Closes #18757 --- .github/workflows/linux.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 2724901324cf..463ea7eb58a4 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -503,9 +503,8 @@ jobs: run: | curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ --location "https://github.com/awslabs/aws-lc/archive/refs/tags/v${AWSLC_VERSION}.tar.gz" | tar -xz - mkdir "aws-lc-${AWSLC_VERSION}-build" - cd "aws-lc-${AWSLC_VERSION}-build" - cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/home/runner/awslc "../aws-lc-${AWSLC_VERSION}" -DBUILD_TOOL=OFF -DBUILD_TESTING=OFF + cd "aws-lc-${AWSLC_VERSION}" + cmake -B . -G Ninja -DCMAKE_INSTALL_PREFIX=/home/runner/awslc -DBUILD_TOOL=OFF -DBUILD_TESTING=OFF cmake --build . cmake --install . From b5c9c858d53072ae6e5a2388d488d2f691f7cd32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 21:53:21 +0000 Subject: [PATCH 201/208] GHA: update dependency awslabs/aws-lc to v1.61.4 Closes #18752 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 019790b68e5d..6ed393465ebf 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -46,7 +46,7 @@ env: # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com LIBRESSL_VERSION: 4.1.0 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.61.3 + AWSLC_VERSION: 1.61.4 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # renovate: datasource=github-tags depName=gnutls/gnutls versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 463ea7eb58a4..dd1e88ed0cd8 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -44,7 +44,7 @@ env: # renovate: datasource=github-tags depName=Mbed-TLS/mbedtls versioning=semver registryUrl=https://github.com MBEDTLS_VERSION: 3.6.4 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.61.3 + AWSLC_VERSION: 1.61.4 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # handled in renovate.json From 75d5424979a8effac331c4924edb1a8be458cdce Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 27 Sep 2025 17:58:29 +0200 Subject: [PATCH 202/208] GHA/windows: tidy up Cygwin jobs - drop unnecessary installed packages. - sync built type name with other jobs. Closes #18758 --- .github/workflows/windows.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e5d66ccc87fc..b866bdacd622 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -110,8 +110,8 @@ jobs: strategy: matrix: include: - - { build: 'automake', platform: 'x86_64', tflags: 'skiprun', config: '--with-openssl', install: 'libssl-devel libssh2-devel', name: 'openssl R' } - - { build: 'cmake' , platform: 'x86_64', tflags: '' , config: '-DENABLE_DEBUG=ON -DCURL_USE_OPENSSL=ON -DENABLE_THREADED_RESOLVER=OFF', install: 'libssl-devel libssh2-devel', name: 'openssl' } + - { build: 'autotools', platform: 'x86_64', tflags: 'skiprun', config: '--with-openssl', install: 'libssl-devel libssh2-devel', name: 'openssl R' } + - { build: 'cmake' , platform: 'x86_64', tflags: '' , config: '-DENABLE_DEBUG=ON -DCURL_USE_OPENSSL=ON -DENABLE_THREADED_RESOLVER=OFF', install: 'libssl-devel libssh2-devel', name: 'openssl' } fail-fast: false steps: - run: git config --global core.autocrlf input @@ -123,8 +123,8 @@ jobs: work-vol: 'D:' # https://cygwin.com/cgi-bin2/package-grep.cgi packages: >- - autoconf libtool gcc-core gcc-g++ binutils - ${{ matrix.build }} make ninja + ${{ matrix.build == 'autotools' && 'autoconf automake libtool make' || 'cmake ninja' }} + gcc-core binutils perl openssh libpsl-devel zlib-devel @@ -138,7 +138,7 @@ jobs: persist-credentials: false - name: 'autoreconf' - if: ${{ matrix.build == 'automake' }} + if: ${{ matrix.build == 'autotools' }} timeout-minutes: 2 run: | PATH=/usr/bin From 660d915ebda4ea44c4422a647e09693d6fb6a9ee Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 27 Sep 2025 23:51:46 +0200 Subject: [PATCH 203/208] ci: use `--enable-option-checking=fatal` in autotools jobs To avoid typos and non-existing options passed to `./configure` in CI builds. Also delete obsolete option `--enable-test-bundles` from Circle CI jobs. Closes #18759 --- .circleci/config.yml | 12 ++++++------ .github/workflows/distcheck.yml | 10 +++++----- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- .github/workflows/macos.yml | 6 +++--- .github/workflows/non-native.yml | 4 ++-- .github/workflows/windows.yml | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1603e7f7d0f0..21b88054d5d3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -66,7 +66,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-warnings \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror --enable-warnings \ --with-openssl \ || { tail -1000 config.log; false; } @@ -75,7 +75,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror \ --with-openssl --disable-verbose \ || { tail -1000 config.log; false; } @@ -84,7 +84,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror \ --with-openssl --disable-proxy \ || { tail -1000 config.log; false; } @@ -93,7 +93,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-warnings \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror --enable-warnings \ --with-openssl --with-libssh \ || { tail -1000 config.log; false; } @@ -102,7 +102,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-warnings \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror --enable-warnings \ --with-openssl --enable-ares \ || { tail -1000 config.log; false; } @@ -111,7 +111,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-debug \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror --enable-debug \ --with-openssl --enable-ares \ || { tail -1000 config.log; false; } diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index da65bf4bd0cf..7a1a4dad844f 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -60,7 +60,7 @@ jobs: echo "::stop-commands::$(uuidgen)" tar xvf curl-99.98.97.tar.gz pushd curl-99.98.97 - ./configure --prefix="$HOME"/temp --enable-werror --without-ssl --without-libpsl + ./configure --prefix="$HOME"/temp --enable-option-checking=fatal --enable-werror --without-ssl --without-libpsl make make test-ci make install @@ -86,7 +86,7 @@ jobs: touch curl-99.98.97/docs/{cmdline-opts,libcurl}/Makefile.inc mkdir build pushd build - ../curl-99.98.97/configure --enable-werror --without-ssl --without-libpsl + ../curl-99.98.97/configure --enable-option-checking=fatal --enable-werror --without-ssl --without-libpsl make make test-ci popd @@ -110,7 +110,7 @@ jobs: pushd curl-99.98.97 mkdir build pushd build - ../configure --prefix="$PWD"/curl-install --enable-werror --without-ssl --enable-debug --without-libpsl + ../configure --prefix="$PWD"/curl-install --enable-option-checking=fatal --enable-werror --without-ssl --enable-debug --without-libpsl make make test-ci make install @@ -136,7 +136,7 @@ jobs: pushd curl-99.98.97 mkdir build pushd build - ../configure --prefix="$PWD"/curl-install --enable-werror --without-ssl --without-libpsl ac_cv_path_PERL= + ../configure --prefix="$PWD"/curl-install --enable-option-checking=fatal --enable-werror --without-ssl --without-libpsl ac_cv_path_PERL= make make install curl-install/bin/curl --disable --version @@ -158,7 +158,7 @@ jobs: echo "::stop-commands::$(uuidgen)" tar xvf curl-99.98.97.tar.gz pushd curl-99.98.97 - ./configure --prefix="$PWD"/curl-install --enable-werror --without-ssl --without-libpsl ac_cv_path_PERL= + ./configure --prefix="$PWD"/curl-install --enable-option-checking=fatal --enable-werror --without-ssl --without-libpsl ac_cv_path_PERL= make make install curl-install/bin/curl --disable --version diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 6ed393465ebf..05d71b6f107a 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -686,7 +686,7 @@ jobs: mkdir bld && cd bld && ../configure --enable-warnings --enable-werror --enable-debug \ --with-libuv \ --with-test-nghttpx=/home/runner/nghttp2/build/bin/nghttpx \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${MATRIX_CONFIGURE} fi diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index dd1e88ed0cd8..1d38c50db64d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -595,7 +595,7 @@ jobs: mkdir bld && cd bld && \ ${MATRIX_CONFIGURE_PREFIX} \ ../configure --prefix="$HOME"/curl-install --enable-unity --enable-warnings --enable-werror \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${MATRIX_CONFIGURE} fi diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 88b7ee880062..6777f3aa924f 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -160,7 +160,7 @@ jobs: ${MATRIX_GENERATE} ${options} else mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ CFLAGS="-isysroot $(xcrun --sdk iphoneos --show-sdk-path 2>/dev/null)" \ --host=aarch64-apple-darwin \ --with-apple-idn \ @@ -440,7 +440,7 @@ jobs: [ -n "${MATRIX_MACOS_VERSION_MIN}" ] && CFLAGS+=" -mmacosx-version-min=${MATRIX_MACOS_VERSION_MIN}" [[ "${MATRIX_INSTALL_STEPS}" = *'pytest'* ]] && options+=' --with-test-vsftpd=no' # Skip ~20 tests that stretch run time by 7x on macOS mkdir bld && cd bld && ../configure --prefix="$PWD"/curl-install --enable-unity --enable-warnings --enable-werror \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ --with-libpsl=/opt/homebrew/opt/libpsl \ ${MATRIX_CONFIGURE} ${options} fi @@ -706,7 +706,7 @@ jobs: [ -n "${MATRIX_MACOS_VERSION_MIN}" ] && CFLAGS+=" -mmacosx-version-min=${MATRIX_MACOS_VERSION_MIN}" # would pick up nghttp2, libidn2, but libssh2 is disabled by default mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ --disable-docs --disable-manual \ --with-openssl="$(brew --prefix openssl)" \ --without-nghttp2 --without-libidn2 \ diff --git a/.github/workflows/non-native.yml b/.github/workflows/non-native.yml index 2670c39078fd..03abced26eb4 100644 --- a/.github/workflows/non-native.yml +++ b/.github/workflows/non-native.yml @@ -192,7 +192,7 @@ jobs: --prefix="$HOME"/curl-install \ --with-openssl \ --with-brotli --enable-ldap --enable-ldaps --with-libidn2 --with-libssh2 --with-nghttp2 --with-gssapi \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${options} \ ${MATRIX_OPTIONS} \ || { tail -n 1000 config.log; false; } @@ -284,7 +284,7 @@ jobs: ${MATRIX_OPTIONS} else TOOLCHAIN="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64" - mkdir bld && cd bld && ../configure --disable-dependency-tracking --enable-unity --enable-warnings --enable-werror \ + mkdir bld && cd bld && ../configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-warnings --enable-werror \ CC="$TOOLCHAIN/bin/aarch64-linux-android${MATRIX_PLATFORM}-clang" \ AR="$TOOLCHAIN/bin/llvm-ar" \ RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \ diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b866bdacd622..e1219dfadc48 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -160,7 +160,7 @@ jobs: mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \ --prefix="$HOME"/curl-install \ --with-libssh2 \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${MATRIX_CONFIG} fi @@ -367,7 +367,7 @@ jobs: mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \ --prefix="$HOME"/curl-install \ --with-libssh2 \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${MATRIX_CONFIG} fi @@ -756,7 +756,7 @@ jobs: --host="${TRIPLET}" \ --with-schannel --with-winidn \ --without-libpsl \ - --disable-dependency-tracking + --disable-dependency-tracking --enable-option-checking=fatal fi - name: 'configure log' From a6182865d0c8cfb9dbfe8d6444b428d17ecc677c Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 28 Sep 2025 00:32:49 +0200 Subject: [PATCH 204/208] CI: make pip use `tests/requirements.txt` in Circle CI Also sync `pip` options with those used in GHA. Closes #18760 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 21b88054d5d3..39201708e81b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,7 +45,7 @@ commands: - run: command: | sudo apt-get update && sudo apt-get install -y libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev python3-pip libpsl-dev - sudo python3 -m pip install impacket + sudo python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt install-wolfssl: steps: From 81a9197102472a03a873c0d59d150223f5ed8840 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 28 Sep 2025 11:54:57 +0200 Subject: [PATCH 205/208] GHA/linux-old: make one cmake v3.7.2 job verbose To show the details in cmake builds using the oldest supported version. Use a legacy method. `--verbose` became supported later, in 3.14. Closes #18764 --- .github/workflows/linux-old.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index 7e25cd213911..e7aad3c3e73a 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -86,7 +86,7 @@ jobs: cd bld-1 cmake .. -DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON -DBUILD_SHARED_LIBS=ON \ -DCURL_USE_GNUTLS=ON -DENABLE_ARES=OFF -DCURL_ZSTD=OFF -DCURL_USE_GSSAPI=OFF -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON - make install + VERBOSE=1 make install src/curl --disable --version - name: 'cmake build-only curl_config.h' From e17aa98bfe3799723cec978661cad4079bfa4dd7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 28 Sep 2025 02:34:13 +0200 Subject: [PATCH 206/208] cmake: use more `COMPILER_OPTIONS`, `LINK_OPTIONS` / `LINK_FLAGS` - replace `COMPILE_FLAGS` with `COMPILE_OPTIONS` that superceded it. Follow-up to 6140dfcf3e7845f11dee755de6865379aa96dab7 https://cmake.org/cmake/help/v4.1/prop_sf/COMPILE_FLAGS.html - replace `target_link_libraries()` with `LINK_FLAGS` property for CMake <=3.12, because we are passing linker options (not libs). Follow-up to 91720b620e802748d2e1629f43e29b76736542f9 #18468 Follow-up to 548873921cde197aa1d40216c594c76738031374 #17670 Follow-up to 95aea798dbd785c4daee2b2e24f2c8c94f3e3cf4 #5843 https://cmake.org/cmake/help/v3.7/command/target_link_libraries.html https://cmake.org/cmake/help/v3.7/prop_tgt/LINK_FLAGS.html - replace `target_link_options()` with `LINK_OPTIONS` propery for CMake 3.13+, to use the modern style. Follow-up to 91720b620e802748d2e1629f43e29b76736542f9 #18468 Follow-up to 548873921cde197aa1d40216c594c76738031374 #17670 https://cmake.org/cmake/help/v3.13/command/target_link_options.html https://cmake.org/cmake/help/v3.13/prop_tgt/LINK_OPTIONS.html Also: - fix to append to, not override, previously set linker options when using `CURL_LIBCURL_VERSIONED_SYMBOLS=ON`. Before this patch, it was overwriting linker options when using `CURL_CODE_COVERAGE=ON`. Follow-up to 91720b620e802748d2e1629f43e29b76736542f9 #18468 Closes #18762 --- lib/CMakeLists.txt | 14 +++++++------- src/CMakeLists.txt | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 7dce3aea8770..d9857a50c27f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -112,7 +112,7 @@ if(SHARE_LIB_OBJECT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) set_target_properties(${LIB_OBJECT} PROPERTIES POSITION_INDEPENDENT_CODE ON) if(CURL_HIDES_PRIVATE_SYMBOLS) - set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}") set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) @@ -154,7 +154,7 @@ if(BUILD_STATIC_LIBS) INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB" INTERFACE_LINK_DIRECTORIES "${CURL_LIBDIRS}") if(CURL_HIDES_PRIVATE_SYMBOLS) - set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}") set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) @@ -194,7 +194,7 @@ if(BUILD_SHARED_LIBS) IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}" POSITION_INDEPENDENT_CODE ON) if(CURL_HIDES_PRIVATE_SYMBOLS) - set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}") set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) @@ -210,9 +210,9 @@ if(BUILD_SHARED_LIBS) set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - target_link_options(${LIB_SHARED} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_OPTIONS ${CURL_COVERAGE_LDFLAGS}) else() - target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_FLAGS ${CURL_COVERAGE_LDFLAGS}) endif() endif() @@ -289,9 +289,9 @@ if(BUILD_SHARED_LIBS) check_c_source_compiles("int main(void) { return 0; }" HAVE_VERSIONED_SYMBOLS) if(HAVE_VERSIONED_SYMBOLS) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - set_target_properties(${LIB_SHARED} PROPERTIES LINK_OPTIONS "${CMAKE_REQUIRED_LINK_OPTIONS}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_OPTIONS "${CMAKE_REQUIRED_LINK_OPTIONS}") else() - set_target_properties(${LIB_SHARED} PROPERTIES LINK_FLAGS "${CMAKE_REQUIRED_LINK_OPTIONS}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_FLAGS "${CMAKE_REQUIRED_LINK_OPTIONS}") endif() else() message(WARNING "Versioned symbols requested, but not supported by the toolchain.") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4b8ebb9346d..a70c96b7650f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,9 +123,9 @@ endif() if(ENABLE_UNICODE AND MINGW AND NOT MINGW32CE) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - target_link_options(${EXE_NAME} PRIVATE "-municode") + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_OPTIONS "-municode") else() - target_link_libraries(${EXE_NAME} PRIVATE "-municode") + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_FLAGS "-municode") endif() endif() @@ -133,9 +133,9 @@ if(CURL_CODE_COVERAGE) set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - target_link_options(${EXE_NAME} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_OPTIONS ${CURL_COVERAGE_LDFLAGS}) else() - target_link_libraries(${EXE_NAME} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_FLAGS ${CURL_COVERAGE_LDFLAGS}) endif() endif() From 10bac43b873fe45869e15b36aac1c1e5bc89b6e0 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 29 Sep 2025 22:48:55 +0200 Subject: [PATCH 207/208] tests/server: drop unsafe `open()` override in signal handler (Windows) Turns out the signal handler on Windows still wasn't signal safe after the previous round of fix. There is an `open()` call made from there, and `open` happens to be unconditionally overridden via `curl_setup.h` on Windows, to its local implementation (`curlx_win32_open()`), which does memory allocations and potentially other things that are not signal safe. This is a temporary fix, till avoiding the override of system symbols `open` and `stat` on Windows. FTR this did not fix the CI 2304 errors, diskspace fail or job hangs due to 0xC0000142 fork failure (it's rare all three occurs in the same run): https://github.com/curl/curl/actions/runs/18110523584?pr=18774 Ref: #18634 Follow-up e95f509c66abdd88ae02e3243cdc217f19c4a330 #16852 Closes #18774 --- tests/server/util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/server/util.c b/tests/server/util.c index 052effa89583..41f42ca42e09 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -373,12 +373,12 @@ static void exit_signal_handler(int signum) (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1); } else { + int fd; #ifdef _WIN32 -#define OPENMODE S_IREAD | S_IWRITE + fd = _open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, S_IREAD | S_IWRITE); #else -#define OPENMODE S_IRUSR | S_IWUSR + fd = open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR | S_IWUSR); #endif - int fd = open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, OPENMODE); if(fd != -1) { static const char msg[] = "exit_signal_handler: called\n"; (void)!write(fd, msg, sizeof(msg) - 1); From 20142f5d06f7120ba94cbcc25c998e8d81aec85b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 15:34:18 +0200 Subject: [PATCH 208/208] build: avoid overriding system symbols for fopen functions By introducing wrappers for them in the curlx namespace: `curlx_fopen()`, `curlx_fdopen()`, `curlx_fclose()`. The undefine/redefine/`(function)()` methods broke on systems implementing these functions as macros. E.g. AIX 32-bit's `fopen()`. Also: - rename `lib/fopen.*` to `lib/curl_fopen.*` (for `Curl_fopen()`) to make room for the newly added `curlx/fopen.h`. - curlx: move file-related functions from `multibyte.c` to `fopen.c`. - tests/server: stop using the curl-specific `fopen()` implementation on Windows. Unicode isn't used by runtests, and it isn't critical to run tests on longs path. It can be re-enabled if this becomes necessary, or if the wrapper receives a feature that's critical for test servers. Reported-by: Andrew Kirillov Bug: https://github.com/curl/curl/issues/18510#issuecomment-3274393640 Follow-up to bf7375ecc50e857760b0d0a668c436e208a400bd #18503 Follow-up to 9863599d69b79d290928a89bf9160f4e4e023d4e #18502 Follow-up to 3bb5e58c105d7be450b667858d1b8e7ae3ded555 #17827 Closes #18634 --- .github/scripts/verify-examples.pl | 4 +- docs/examples/.checksrc | 3 + docs/internals/CHECKSRC.md | 2 +- lib/Makefile.inc | 6 +- lib/altsvc.c | 8 +- lib/cookie.c | 10 +- lib/{fopen.c => curl_fopen.c} | 8 +- lib/{fopen.h => curl_fopen.h} | 2 + lib/curl_mem_undef.h | 11 - lib/curl_setup.h | 3 - lib/curlx/curlx.h | 3 + lib/curlx/fopen.c | 310 +++++++++++++++++++++++++++++ lib/curlx/fopen.h | 48 +++++ lib/curlx/multibyte.c | 273 ------------------------- lib/hsts.c | 8 +- lib/memdebug.c | 24 +-- lib/memdebug.h | 7 - lib/mime.c | 15 +- lib/netrc.c | 5 +- lib/vtls/gtls.c | 5 +- lib/vtls/keylog.c | 7 +- lib/vtls/rustls.c | 7 +- lib/vtls/schannel.c | 5 +- lib/vtls/vtls.c | 5 +- scripts/checksrc.pl | 7 +- src/Makefile.inc | 2 + src/tool_cb_dbg.c | 2 +- src/tool_cb_wrt.c | 4 +- src/tool_cfgable.c | 2 +- src/tool_easysrc.c | 4 +- src/tool_formparse.c | 4 +- src/tool_getparam.c | 24 +-- src/tool_ipfs.c | 6 +- src/tool_operate.c | 34 ++-- src/tool_parsecfg.c | 6 +- src/tool_ssls.c | 8 +- src/tool_stderr.c | 4 +- src/tool_util.c | 2 +- src/tool_writeout.c | 12 +- src/var.c | 4 +- tests/data/test1185 | 4 +- tests/libtest/Makefile.inc | 1 + tests/libtest/cli_h2_serverpush.c | 10 +- tests/libtest/cli_hx_download.c | 4 +- tests/libtest/cli_hx_upload.c | 4 +- tests/libtest/lib500.c | 4 +- tests/libtest/lib505.c | 16 +- tests/libtest/lib518.c | 4 +- tests/libtest/lib525.c | 8 +- tests/libtest/lib537.c | 4 +- tests/libtest/lib541.c | 12 +- tests/libtest/lib566.c | 4 +- tests/libtest/lib568.c | 6 +- tests/libtest/lib569.c | 8 +- tests/libtest/lib571.c | 8 +- tests/libtest/lib572.c | 6 +- tests/libtest/lib578.c | 4 +- tests/libtest/lib579.c | 8 +- tests/libtest/lib582.c | 8 +- tests/libtest/lib591.c | 6 +- tests/libtest/lib599.c | 4 +- tests/libtest/lib678.c | 4 +- tests/server/.checksrc | 2 + tests/server/Makefile.inc | 1 + tests/unit/unit3200.c | 8 +- 65 files changed, 568 insertions(+), 484 deletions(-) rename lib/{fopen.c => curl_fopen.c} (96%) rename lib/{fopen.h => curl_fopen.h} (97%) create mode 100644 lib/curlx/fopen.c create mode 100644 lib/curlx/fopen.h diff --git a/.github/scripts/verify-examples.pl b/.github/scripts/verify-examples.pl index 27c4de6db855..a8dd08d1827a 100755 --- a/.github/scripts/verify-examples.pl +++ b/.github/scripts/verify-examples.pl @@ -63,9 +63,9 @@ sub extract { elsif($syn == 1) { if(/^~~~/) { $syn++; - print O "/* !checksrc! disable UNUSEDIGNORE all */\n"; + print O "/* !checksrc! disable BANNEDFUNC all */\n"; # for fopen() print O "/* !checksrc! disable COPYRIGHT all */\n"; - print O "/* !checksrc! disable FOPENMODE all */\n"; + print O "/* !checksrc! disable UNUSEDIGNORE all */\n"; printf O "#line %d \"$f\"\n", $iline+1; } } diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc index 0b626e65703d..e0b6c43da939 100644 --- a/docs/examples/.checksrc +++ b/docs/examples/.checksrc @@ -1,3 +1,6 @@ +allowfunc fclose +allowfunc fdopen +allowfunc fopen allowfunc gmtime allowfunc localtime allowfunc socket diff --git a/docs/internals/CHECKSRC.md b/docs/internals/CHECKSRC.md index 16eb96c75bfc..9c4f1428791e 100644 --- a/docs/internals/CHECKSRC.md +++ b/docs/internals/CHECKSRC.md @@ -76,7 +76,7 @@ warnings are: - `EXCLAMATIONSPACE`: space found after exclamations mark -- `FOPENMODE`: `fopen()` needs a macro for the mode string, use it +- `FOPENMODE`: `curlx_fopen()` needs a macro for the mode string, use it - `INDENTATION`: detected a wrong start column for code. Note that this warning only checks some specific places and can certainly miss many bad diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 6391eb2c4351..1447e53a1e5b 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -26,6 +26,7 @@ LIB_CURLX_CFILES = \ curlx/base64.c \ curlx/dynbuf.c \ + curlx/fopen.c \ curlx/inet_ntop.c \ curlx/inet_pton.c \ curlx/multibyte.c \ @@ -43,6 +44,7 @@ LIB_CURLX_HFILES = \ curlx/base64.h \ curlx/curlx.h \ curlx/dynbuf.h \ + curlx/fopen.h \ curlx/inet_ntop.h \ curlx/inet_pton.h \ curlx/multibyte.h \ @@ -157,6 +159,7 @@ LIB_CFILES = \ curl_des.c \ curl_endian.c \ curl_fnmatch.c \ + curl_fopen.c \ curl_get_line.c \ curl_gethostname.c \ curl_gssapi.c \ @@ -181,7 +184,6 @@ LIB_CFILES = \ fake_addrinfo.c \ file.c \ fileinfo.c \ - fopen.c \ formdata.c \ ftp.c \ ftplistparser.c \ @@ -286,6 +288,7 @@ LIB_HFILES = \ curl_des.h \ curl_endian.h \ curl_fnmatch.h \ + curl_fopen.h \ curl_get_line.h \ curl_gethostname.h \ curl_gssapi.h \ @@ -320,7 +323,6 @@ LIB_HFILES = \ fake_addrinfo.h \ file.h \ fileinfo.h \ - fopen.h \ formdata.h \ ftp.h \ ftplistparser.h \ diff --git a/lib/altsvc.c b/lib/altsvc.c index c7448692fb56..7e4c4b5c25a7 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -31,11 +31,11 @@ #include #include "urldata.h" #include "altsvc.h" +#include "curl_fopen.h" #include "curl_get_line.h" #include "parsedate.h" #include "sendf.h" #include "curlx/warnless.h" -#include "fopen.h" #include "rename.h" #include "strdup.h" #include "curlx/inet_pton.h" @@ -227,7 +227,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) if(!asi->filename) return CURLE_OUT_OF_MEMORY; - fp = fopen(file, FOPEN_READTEXT); + fp = curlx_fopen(file, FOPEN_READTEXT); if(fp) { struct dynbuf buf; curlx_dyn_init(&buf, MAX_ALTSVC_LINE); @@ -238,7 +238,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) altsvc_add(asi, lineptr); } curlx_dyn_free(&buf); /* free the line buffer */ - fclose(fp); + curlx_fclose(fp); } return result; } @@ -391,7 +391,7 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data, if(result) break; } - fclose(out); + curlx_fclose(out); if(!result && tempstore && Curl_rename(tempstore, file)) result = CURLE_WRITE_ERROR; diff --git a/lib/cookie.c b/lib/cookie.c index 90d375a7611b..c5fbe1344dd6 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -80,11 +80,11 @@ Example set of cookies: #include "slist.h" #include "share.h" #include "strcase.h" +#include "curl_fopen.h" #include "curl_get_line.h" #include "curl_memrchr.h" #include "parsedate.h" #include "rename.h" -#include "fopen.h" #include "strdup.h" #include "llist.h" #include "curlx/strparse.h" @@ -1195,7 +1195,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, if(!strcmp(file, "-")) fp = stdin; else { - fp = fopen(file, "rb"); + fp = curlx_fopen(file, "rb"); if(!fp) infof(data, "WARNING: failed to open cookie file \"%s\"", file); else @@ -1228,7 +1228,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, remove_expired(ci); if(handle) - fclose(handle); + curlx_fclose(handle); } data->state.cookie_engine = TRUE; } @@ -1583,7 +1583,7 @@ static CURLcode cookie_output(struct Curl_easy *data, } if(!use_stdout) { - fclose(out); + curlx_fclose(out); out = NULL; if(tempstore && Curl_rename(tempstore, filename)) { unlink(tempstore); @@ -1602,7 +1602,7 @@ static CURLcode cookie_output(struct Curl_easy *data, error: if(out && !use_stdout) - fclose(out); + curlx_fclose(out); free(tempstore); return error; } diff --git a/lib/fopen.c b/lib/curl_fopen.c similarity index 96% rename from lib/fopen.c rename to lib/curl_fopen.c index b28977317a8b..13acd299c0dd 100644 --- a/lib/fopen.c +++ b/lib/curl_fopen.c @@ -33,7 +33,7 @@ #include "urldata.h" #include "rand.h" -#include "fopen.h" +#include "curl_fopen.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -102,7 +102,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, char *dir = NULL; *tempname = NULL; - *fh = fopen(filename, FOPEN_WRITETEXT); + *fh = curlx_fopen(filename, FOPEN_WRITETEXT); if(!*fh) goto fail; if( @@ -114,7 +114,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, || !S_ISREG(sb.st_mode)) { return CURLE_OK; } - fclose(*fh); + curlx_fclose(*fh); *fh = NULL; result = Curl_rand_alnum(data, randbuf, sizeof(randbuf)); @@ -144,7 +144,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, if(fd == -1) goto fail; - *fh = fdopen(fd, FOPEN_WRITETEXT); + *fh = curlx_fdopen(fd, FOPEN_WRITETEXT); if(!*fh) goto fail; diff --git a/lib/fopen.h b/lib/curl_fopen.h similarity index 97% rename from lib/fopen.h rename to lib/curl_fopen.h index e3a919d07367..a3dc1382bca8 100644 --- a/lib/fopen.h +++ b/lib/curl_fopen.h @@ -24,6 +24,8 @@ * ***************************************************************************/ +#include "curlx/fopen.h" + CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, FILE **fh, char **tempname); diff --git a/lib/curl_mem_undef.h b/lib/curl_mem_undef.h index a70a9fcf5379..2be114cbd5e6 100644 --- a/lib/curl_mem_undef.h +++ b/lib/curl_mem_undef.h @@ -33,16 +33,5 @@ #undef Curl_tcsdup #endif -#ifdef CURLDEBUG - -#undef fopen -#ifdef CURL_FOPEN -#define fopen(fname, mode) CURL_FOPEN(fname, mode) -#endif -#undef fdopen -#undef fclose - -#endif /* CURLDEBUG */ - #undef HEADER_CURL_MEMORY_H #undef HEADER_CURL_MEMDEBUG_H diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 55c65c99f696..b3c19a95efb5 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -509,11 +509,8 @@ # ifndef UNDER_CE int curlx_win32_stat(const char *path, struct_stat *buffer); int curlx_win32_open(const char *filename, int oflag, ...); - FILE *curlx_win32_fopen(const char *filename, const char *mode); # define stat(fname, stp) curlx_win32_stat(fname, stp) # define open curlx_win32_open -# define CURL_FOPEN(fname, mode) curlx_win32_fopen(fname, mode) -# define fopen(fname, mode) CURL_FOPEN(fname, mode) # endif #elif defined(__DJGPP__) /* Requires DJGPP 2.04 */ diff --git a/lib/curlx/curlx.h b/lib/curlx/curlx.h index 9f7bd3a975ea..33ac72e8e19b 100644 --- a/lib/curlx/curlx.h +++ b/lib/curlx/curlx.h @@ -64,6 +64,9 @@ #include "dynbuf.h" /* The curlx_dyn_* functions */ +#include "fopen.h" +/* The curlx_f* functions */ + #include "base64.h" #include "timeval.h" #include "timediff.h" diff --git a/lib/curlx/fopen.c b/lib/curlx/fopen.c new file mode 100644 index 000000000000..22c7259c70dd --- /dev/null +++ b/lib/curlx/fopen.c @@ -0,0 +1,310 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , 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 + * + ***************************************************************************/ + +/* + * This file is 'mem-include-scan' clean, which means its memory allocations + * are not tracked by the curl memory tracker memdebug, so they must not use + * `CURLDEBUG` macro replacements in memdebug.h for free, malloc, etc. To avoid + * these macro replacements, wrap the names in parentheses to call the original + * versions: `ptr = (malloc)(123)`, `(free)(ptr)`, etc. + */ + +#include "../curl_setup.h" + +#if defined(_WIN32) && !defined(UNDER_CE) + +#include "fopen.h" +#include "multibyte.h" + +/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */ +#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \ + (_WIN32_WINNT < _WIN32_WINNT_WIN10) +WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *); +#endif + +/* Fix excessive paths (paths that exceed MAX_PATH length of 260). + * + * This is a helper function to fix paths that would exceed the MAX_PATH + * limitation check done by Windows APIs. It does so by normalizing the passed + * in filename or path 'in' to its full canonical path, and if that path is + * longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path. + * + * For example 'in' filename255chars in current directory C:\foo\bar is + * fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows + * it is ok to access that filename even though the actual full path is longer + * than 260 chars. + * + * For non-Unicode builds this function may fail sometimes because only the + * Unicode versions of some Windows API functions can access paths longer than + * MAX_PATH, for example GetFullPathNameW which is used in this function. When + * the full path is then converted from Unicode to multibyte that fails if any + * directories in the path contain characters not in the current codepage. + */ +static bool fix_excessive_path(const TCHAR *in, TCHAR **out) +{ + size_t needed, count; + const wchar_t *in_w; + wchar_t *fbuf = NULL; + + /* MS documented "approximate" limit for the maximum path length */ + const size_t max_path_len = 32767; + +#ifndef _UNICODE + wchar_t *ibuf = NULL; + char *obuf = NULL; +#endif + + *out = NULL; + + /* skip paths already normalized */ + if(!_tcsncmp(in, _T("\\\\?\\"), 4)) + goto cleanup; + +#ifndef _UNICODE + /* convert multibyte input to unicode */ + needed = mbstowcs(NULL, in, 0); + if(needed == (size_t)-1 || needed >= max_path_len) + goto cleanup; + ++needed; /* for NUL */ + ibuf = (malloc)(needed * sizeof(wchar_t)); + if(!ibuf) + goto cleanup; + count = mbstowcs(ibuf, in, needed); + if(count == (size_t)-1 || count >= needed) + goto cleanup; + in_w = ibuf; +#else + in_w = in; +#endif + + /* GetFullPathNameW returns the normalized full path in unicode. It converts + forward slashes to backslashes, processes .. to remove directory segments, + etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */ + needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL); + if(!needed || needed > max_path_len) + goto cleanup; + /* skip paths that are not excessive and do not need modification */ + if(needed <= MAX_PATH) + goto cleanup; + fbuf = (malloc)(needed * sizeof(wchar_t)); + if(!fbuf) + goto cleanup; + count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL); + if(!count || count >= needed) + goto cleanup; + + /* prepend \\?\ or \\?\UNC\ to the excessively long path. + * + * c:\longpath ---> \\?\c:\longpath + * \\.\c:\longpath ---> \\?\c:\longpath + * \\?\c:\longpath ---> \\?\c:\longpath (unchanged) + * \\server\c$\longpath ---> \\?\UNC\server\c$\longpath + * + * https://learn.microsoft.com/dotnet/standard/io/file-path-formats + */ + if(!wcsncmp(fbuf, L"\\\\?\\", 4)) + ; /* do nothing */ + else if(!wcsncmp(fbuf, L"\\\\.\\", 4)) + fbuf[2] = '?'; + else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) { + /* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */ + goto cleanup; + } + else { + wchar_t *temp; + + if(!wcsncmp(fbuf, L"\\\\", 2)) { + /* "\\?\UNC\" + full path without "\\" + null */ + needed = 8 + (count - 2) + 1; + if(needed > max_path_len) + goto cleanup; + + temp = (malloc)(needed * sizeof(wchar_t)); + if(!temp) + goto cleanup; + + wcsncpy(temp, L"\\\\?\\UNC\\", 8); + wcscpy(temp + 8, fbuf + 2); + } + else { + /* "\\?\" + full path + null */ + needed = 4 + count + 1; + if(needed > max_path_len) + goto cleanup; + + temp = (malloc)(needed * sizeof(wchar_t)); + if(!temp) + goto cleanup; + + wcsncpy(temp, L"\\\\?\\", 4); + wcscpy(temp + 4, fbuf); + } + + (free)(fbuf); + fbuf = temp; + } + +#ifndef _UNICODE + /* convert unicode full path to multibyte output */ + needed = wcstombs(NULL, fbuf, 0); + if(needed == (size_t)-1 || needed >= max_path_len) + goto cleanup; + ++needed; /* for NUL */ + obuf = (malloc)(needed); + if(!obuf) + goto cleanup; + count = wcstombs(obuf, fbuf, needed); + if(count == (size_t)-1 || count >= needed) + goto cleanup; + *out = obuf; + obuf = NULL; +#else + *out = fbuf; + fbuf = NULL; +#endif + +cleanup: + (free)(fbuf); +#ifndef _UNICODE + (free)(ibuf); + (free)(obuf); +#endif + return *out ? true : false; +} + +int curlx_win32_open(const char *filename, int oflag, ...) +{ + int pmode = 0; + int result = -1; + TCHAR *fixed = NULL; + const TCHAR *target = NULL; + +#ifdef _UNICODE + wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); +#endif + + va_list param; + va_start(param, oflag); + if(oflag & O_CREAT) + pmode = va_arg(param, int); + va_end(param); + +#ifdef _UNICODE + if(filename_w) { + if(fix_excessive_path(filename_w, &fixed)) + target = fixed; + else + target = filename_w; + result = _wopen(target, oflag, pmode); + curlx_unicodefree(filename_w); + } + else + /* !checksrc! disable ERRNOVAR 1 */ + CURL_SETERRNO(EINVAL); +#else + if(fix_excessive_path(filename, &fixed)) + target = fixed; + else + target = filename; + result = _open(target, oflag, pmode); +#endif + + (free)(fixed); + return result; +} + +FILE *curlx_win32_fopen(const char *filename, const char *mode) +{ + FILE *result = NULL; + TCHAR *fixed = NULL; + const TCHAR *target = NULL; + +#ifdef _UNICODE + wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); + wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode); + if(filename_w && mode_w) { + if(fix_excessive_path(filename_w, &fixed)) + target = fixed; + else + target = filename_w; + result = _wfopen(target, mode_w); + } + else + /* !checksrc! disable ERRNOVAR 1 */ + CURL_SETERRNO(EINVAL); + curlx_unicodefree(filename_w); + curlx_unicodefree(mode_w); +#else + if(fix_excessive_path(filename, &fixed)) + target = fixed; + else + target = filename; + /* !checksrc! disable BANNEDFUNC 1 */ + result = fopen(target, mode); +#endif + + (free)(fixed); + return result; +} + +int curlx_win32_stat(const char *path, struct_stat *buffer) +{ + int result = -1; + TCHAR *fixed = NULL; + const TCHAR *target = NULL; + +#ifdef _UNICODE + wchar_t *path_w = curlx_convert_UTF8_to_wchar(path); + if(path_w) { + if(fix_excessive_path(path_w, &fixed)) + target = fixed; + else + target = path_w; +#ifndef USE_WIN32_LARGE_FILES + result = _wstat(target, buffer); +#else + result = _wstati64(target, buffer); +#endif + curlx_unicodefree(path_w); + } + else + /* !checksrc! disable ERRNOVAR 1 */ + CURL_SETERRNO(EINVAL); +#else + if(fix_excessive_path(path, &fixed)) + target = fixed; + else + target = path; +#ifndef USE_WIN32_LARGE_FILES + result = _stat(target, buffer); +#else + result = _stati64(target, buffer); +#endif +#endif + + (free)(fixed); + return result; +} + +#endif /* _WIN32 && !UNDER_CE */ diff --git a/lib/curlx/fopen.h b/lib/curlx/fopen.h new file mode 100644 index 000000000000..2a2b07963789 --- /dev/null +++ b/lib/curlx/fopen.h @@ -0,0 +1,48 @@ +#ifndef HEADER_CURLX_FOPEN_H +#define HEADER_CURLX_FOPEN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , 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 "../curl_setup.h" + +#include "multibyte.h" + +#if defined(_WIN32) && !defined(UNDER_CE) +FILE *curlx_win32_fopen(const char *filename, const char *mode); +#define CURLX_FOPEN_LOW(fname, mode) curlx_win32_fopen(fname, mode) +#else +#define CURLX_FOPEN_LOW fopen +#endif + +#ifdef CURLDEBUG +#define curlx_fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) +#define curlx_fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__) +#define curlx_fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) +#else +#define curlx_fopen CURLX_FOPEN_LOW +#define curlx_fdopen fdopen +#define curlx_fclose fclose +#endif + +#endif /* HEADER_CURLX_FOPEN_H */ diff --git a/lib/curlx/multibyte.c b/lib/curlx/multibyte.c index 1c81a71ec5b4..9e60edf7e3e2 100644 --- a/lib/curlx/multibyte.c +++ b/lib/curlx/multibyte.c @@ -84,277 +84,4 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w) return str_utf8; } -#ifndef UNDER_CE - -/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */ -#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \ - (_WIN32_WINNT < _WIN32_WINNT_WIN10) -WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *); -#endif - -/* Fix excessive paths (paths that exceed MAX_PATH length of 260). - * - * This is a helper function to fix paths that would exceed the MAX_PATH - * limitation check done by Windows APIs. It does so by normalizing the passed - * in filename or path 'in' to its full canonical path, and if that path is - * longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path. - * - * For example 'in' filename255chars in current directory C:\foo\bar is - * fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows - * it is ok to access that filename even though the actual full path is longer - * than 260 chars. - * - * For non-Unicode builds this function may fail sometimes because only the - * Unicode versions of some Windows API functions can access paths longer than - * MAX_PATH, for example GetFullPathNameW which is used in this function. When - * the full path is then converted from Unicode to multibyte that fails if any - * directories in the path contain characters not in the current codepage. - */ -static bool fix_excessive_path(const TCHAR *in, TCHAR **out) -{ - size_t needed, count; - const wchar_t *in_w; - wchar_t *fbuf = NULL; - - /* MS documented "approximate" limit for the maximum path length */ - const size_t max_path_len = 32767; - -#ifndef _UNICODE - wchar_t *ibuf = NULL; - char *obuf = NULL; -#endif - - *out = NULL; - - /* skip paths already normalized */ - if(!_tcsncmp(in, _T("\\\\?\\"), 4)) - goto cleanup; - -#ifndef _UNICODE - /* convert multibyte input to unicode */ - needed = mbstowcs(NULL, in, 0); - if(needed == (size_t)-1 || needed >= max_path_len) - goto cleanup; - ++needed; /* for NUL */ - ibuf = (malloc)(needed * sizeof(wchar_t)); - if(!ibuf) - goto cleanup; - count = mbstowcs(ibuf, in, needed); - if(count == (size_t)-1 || count >= needed) - goto cleanup; - in_w = ibuf; -#else - in_w = in; -#endif - - /* GetFullPathNameW returns the normalized full path in unicode. It converts - forward slashes to backslashes, processes .. to remove directory segments, - etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */ - needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL); - if(!needed || needed > max_path_len) - goto cleanup; - /* skip paths that are not excessive and do not need modification */ - if(needed <= MAX_PATH) - goto cleanup; - fbuf = (malloc)(needed * sizeof(wchar_t)); - if(!fbuf) - goto cleanup; - count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL); - if(!count || count >= needed) - goto cleanup; - - /* prepend \\?\ or \\?\UNC\ to the excessively long path. - * - * c:\longpath ---> \\?\c:\longpath - * \\.\c:\longpath ---> \\?\c:\longpath - * \\?\c:\longpath ---> \\?\c:\longpath (unchanged) - * \\server\c$\longpath ---> \\?\UNC\server\c$\longpath - * - * https://learn.microsoft.com/dotnet/standard/io/file-path-formats - */ - if(!wcsncmp(fbuf, L"\\\\?\\", 4)) - ; /* do nothing */ - else if(!wcsncmp(fbuf, L"\\\\.\\", 4)) - fbuf[2] = '?'; - else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) { - /* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */ - goto cleanup; - } - else { - wchar_t *temp; - - if(!wcsncmp(fbuf, L"\\\\", 2)) { - /* "\\?\UNC\" + full path without "\\" + null */ - needed = 8 + (count - 2) + 1; - if(needed > max_path_len) - goto cleanup; - - temp = (malloc)(needed * sizeof(wchar_t)); - if(!temp) - goto cleanup; - - wcsncpy(temp, L"\\\\?\\UNC\\", 8); - wcscpy(temp + 8, fbuf + 2); - } - else { - /* "\\?\" + full path + null */ - needed = 4 + count + 1; - if(needed > max_path_len) - goto cleanup; - - temp = (malloc)(needed * sizeof(wchar_t)); - if(!temp) - goto cleanup; - - wcsncpy(temp, L"\\\\?\\", 4); - wcscpy(temp + 4, fbuf); - } - - (free)(fbuf); - fbuf = temp; - } - -#ifndef _UNICODE - /* convert unicode full path to multibyte output */ - needed = wcstombs(NULL, fbuf, 0); - if(needed == (size_t)-1 || needed >= max_path_len) - goto cleanup; - ++needed; /* for NUL */ - obuf = (malloc)(needed); - if(!obuf) - goto cleanup; - count = wcstombs(obuf, fbuf, needed); - if(count == (size_t)-1 || count >= needed) - goto cleanup; - *out = obuf; - obuf = NULL; -#else - *out = fbuf; - fbuf = NULL; -#endif - -cleanup: - (free)(fbuf); -#ifndef _UNICODE - (free)(ibuf); - (free)(obuf); -#endif - return *out ? true : false; -} - -int curlx_win32_open(const char *filename, int oflag, ...) -{ - int pmode = 0; - int result = -1; - TCHAR *fixed = NULL; - const TCHAR *target = NULL; - -#ifdef _UNICODE - wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); -#endif - - va_list param; - va_start(param, oflag); - if(oflag & O_CREAT) - pmode = va_arg(param, int); - va_end(param); - -#ifdef _UNICODE - if(filename_w) { - if(fix_excessive_path(filename_w, &fixed)) - target = fixed; - else - target = filename_w; - result = _wopen(target, oflag, pmode); - curlx_unicodefree(filename_w); - } - else - /* !checksrc! disable ERRNOVAR 1 */ - CURL_SETERRNO(EINVAL); -#else - if(fix_excessive_path(filename, &fixed)) - target = fixed; - else - target = filename; - result = _open(target, oflag, pmode); -#endif - - (free)(fixed); - return result; -} - -FILE *curlx_win32_fopen(const char *filename, const char *mode) -{ - FILE *result = NULL; - TCHAR *fixed = NULL; - const TCHAR *target = NULL; - -#ifdef _UNICODE - wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); - wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode); - if(filename_w && mode_w) { - if(fix_excessive_path(filename_w, &fixed)) - target = fixed; - else - target = filename_w; - result = _wfopen(target, mode_w); - } - else - /* !checksrc! disable ERRNOVAR 1 */ - CURL_SETERRNO(EINVAL); - curlx_unicodefree(filename_w); - curlx_unicodefree(mode_w); -#else - if(fix_excessive_path(filename, &fixed)) - target = fixed; - else - target = filename; - result = (fopen)(target, mode); -#endif - - (free)(fixed); - return result; -} - -int curlx_win32_stat(const char *path, struct_stat *buffer) -{ - int result = -1; - TCHAR *fixed = NULL; - const TCHAR *target = NULL; - -#ifdef _UNICODE - wchar_t *path_w = curlx_convert_UTF8_to_wchar(path); - if(path_w) { - if(fix_excessive_path(path_w, &fixed)) - target = fixed; - else - target = path_w; -#ifndef USE_WIN32_LARGE_FILES - result = _wstat(target, buffer); -#else - result = _wstati64(target, buffer); -#endif - curlx_unicodefree(path_w); - } - else - /* !checksrc! disable ERRNOVAR 1 */ - CURL_SETERRNO(EINVAL); -#else - if(fix_excessive_path(path, &fixed)) - target = fixed; - else - target = path; -#ifndef USE_WIN32_LARGE_FILES - result = _stat(target, buffer); -#else - result = _stati64(target, buffer); -#endif -#endif - - (free)(fixed); - return result; -} - -#endif /* UNDER_CE */ - #endif /* _WIN32 */ diff --git a/lib/hsts.c b/lib/hsts.c index 9525158bcc7c..b84a470f90dc 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -32,10 +32,10 @@ #include "urldata.h" #include "llist.h" #include "hsts.h" +#include "curl_fopen.h" #include "curl_get_line.h" #include "sendf.h" #include "parsedate.h" -#include "fopen.h" #include "rename.h" #include "share.h" #include "strdup.h" @@ -379,7 +379,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, if(result) break; } - fclose(out); + curlx_fclose(out); if(!result && tempstore && Curl_rename(tempstore, file)) result = CURLE_WRITE_ERROR; @@ -524,7 +524,7 @@ static CURLcode hsts_load(struct hsts *h, const char *file) if(!h->filename) return CURLE_OUT_OF_MEMORY; - fp = fopen(file, FOPEN_READTEXT); + fp = curlx_fopen(file, FOPEN_READTEXT); if(fp) { struct dynbuf buf; curlx_dyn_init(&buf, MAX_HSTS_LINE); @@ -542,7 +542,7 @@ static CURLcode hsts_load(struct hsts *h, const char *file) hsts_add(h, lineptr); } curlx_dyn_free(&buf); /* free the line buffer */ - fclose(fp); + curlx_fclose(fp); } return result; } diff --git a/lib/memdebug.c b/lib/memdebug.c index cffd4b2cf61b..0c9d15671583 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -29,6 +29,7 @@ #include #include "urldata.h" +#include "curlx/fopen.h" /* for CURLX_FOPEN_LOW() */ /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -68,7 +69,8 @@ static void curl_dbg_cleanup(void) if(curl_dbg_logfile && curl_dbg_logfile != stderr && curl_dbg_logfile != stdout) { - (fclose)(curl_dbg_logfile); + /* !checksrc! disable BANNEDFUNC 1 */ + fclose(curl_dbg_logfile); } curl_dbg_logfile = NULL; } @@ -78,11 +80,7 @@ void curl_dbg_memdebug(const char *logname) { if(!curl_dbg_logfile) { if(logname && *logname) -#ifdef CURL_FOPEN - curl_dbg_logfile = CURL_FOPEN(logname, FOPEN_WRITETEXT); -#else - curl_dbg_logfile = (fopen)(logname, FOPEN_WRITETEXT); -#endif + curl_dbg_logfile = CURLX_FOPEN_LOW(logname, FOPEN_WRITETEXT); else curl_dbg_logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC @@ -424,13 +422,7 @@ ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode, int line, const char *source) { - FILE *res; -#ifdef CURL_FOPEN - res = CURL_FOPEN(file, mode); -#else - res = (fopen)(file, mode); -#endif - + FILE *res = CURLX_FOPEN_LOW(file, mode); if(source) curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", source, line, file, mode, (void *)res); @@ -442,7 +434,8 @@ ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode, int line, const char *source) { - FILE *res = (fdopen)(filedes, mode); + /* !checksrc! disable BANNEDFUNC 1 */ + FILE *res = fdopen(filedes, mode); if(source) curl_dbg_log("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", source, line, filedes, mode, (void *)res); @@ -459,7 +452,8 @@ int curl_dbg_fclose(FILE *file, int line, const char *source) curl_dbg_log("FILE %s:%d fclose(%p)\n", source, line, (void *)file); - res = (fclose)(file); + /* !checksrc! disable BANNEDFUNC 1 */ + res = fclose(file); return res; } diff --git a/lib/memdebug.h b/lib/memdebug.h index 96ceb61759e5..c2b7fad9528b 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -52,12 +52,5 @@ #endif #endif /* _WIN32 */ -#undef fopen -#define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) -#undef fdopen -#define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__) -#undef fclose -#define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) - #endif /* CURLDEBUG */ #endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/lib/mime.c b/lib/mime.c index 894413be17f2..6ec7f6904671 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -34,6 +34,7 @@ struct Curl_easy; #include "sendf.h" #include "transfer.h" #include "strdup.h" +#include "curlx/fopen.h" #include "curlx/base64.h" #if !defined(CURL_DISABLE_MIME) && \ @@ -131,7 +132,7 @@ static const char aschex[] = #ifndef __VMS #define filesize(name, stat_data) (stat_data.st_size) -#define fopen_read fopen +#define fopen_read curlx_fopen #else @@ -154,7 +155,7 @@ curl_off_t VmsRealFileSize(const char *name, int ret_stat; FILE * file; - file = fopen(name, FOPEN_READTEXT); /* VMS */ + file = curlx_fopen(name, FOPEN_READTEXT); /* VMS */ if(!file) return 0; @@ -165,7 +166,7 @@ curl_off_t VmsRealFileSize(const char *name, if(ret_stat) count += ret_stat; } - fclose(file); + curlx_fclose(file); return count; } @@ -210,10 +211,10 @@ static FILE * vmsfopenread(const char *file, const char *mode) case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: - return fopen(file, FOPEN_READTEXT); /* VMS */ + return curlx_fopen(file, FOPEN_READTEXT); /* VMS */ break; default: - return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); + return curlx_fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); } } @@ -745,7 +746,7 @@ static void mime_file_free(void *ptr) curl_mimepart *part = (curl_mimepart *) ptr; if(part->fp) { - fclose(part->fp); + curlx_fclose(part->fp); part->fp = NULL; } Curl_safefree(part->data); @@ -967,7 +968,7 @@ static size_t readback_part(curl_mimepart *part, mimesetstate(&part->state, MIMESTATE_END, NULL); /* Try sparing open file descriptors. */ if(part->kind == MIMEKIND_FILE && part->fp) { - fclose(part->fp); + curlx_fclose(part->fp); part->fp = NULL; } FALLTHROUGH(); diff --git a/lib/netrc.c b/lib/netrc.c index 447ee095852d..a227ffefcd95 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -39,6 +39,7 @@ #include "netrc.h" #include "strcase.h" #include "curl_get_line.h" +#include "curlx/fopen.h" #include "curlx/strparse.h" /* The last 3 #include files should be in this order */ @@ -76,7 +77,7 @@ enum found_state { static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf) { NETRCcode ret = NETRC_FILE_MISSING; /* if it cannot open the file */ - FILE *file = fopen(filename, FOPEN_READTEXT); + FILE *file = curlx_fopen(filename, FOPEN_READTEXT); struct dynbuf linebuf; curlx_dyn_init(&linebuf, MAX_NETRC_LINE); @@ -99,7 +100,7 @@ static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf) done: curlx_dyn_free(&linebuf); if(file) - fclose(file); + curlx_fclose(file); return ret; } diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index e9252ec2a1d5..2db73ca2d5d1 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -54,6 +54,7 @@ #include "../progress.h" #include "../select.h" #include "../strdup.h" +#include "../curlx/fopen.h" #include "../curlx/warnless.h" #include "x509asn1.h" #include "../multiif.h" @@ -211,7 +212,7 @@ static gnutls_datum_t load_file(const char *file) long filelen; void *ptr; - f = fopen(file, "rb"); + f = curlx_fopen(file, "rb"); if(!f) return loaded_file; if(fseek(f, 0, SEEK_END) != 0 @@ -227,7 +228,7 @@ static gnutls_datum_t load_file(const char *file) loaded_file.data = ptr; loaded_file.size = (unsigned int)filelen; out: - fclose(f); + curlx_fclose(f); return loaded_file; } diff --git a/lib/vtls/keylog.c b/lib/vtls/keylog.c index 2fd25089d97b..9179d38fe76f 100644 --- a/lib/vtls/keylog.c +++ b/lib/vtls/keylog.c @@ -33,6 +33,7 @@ #include "keylog.h" #include #include "../escape.h" +#include "../curlx/fopen.h" /* The last #include files should be: */ #include "../curl_memory.h" @@ -49,7 +50,7 @@ Curl_tls_keylog_open(void) if(!keylog_file_fp) { keylog_file_name = curl_getenv("SSLKEYLOGFILE"); if(keylog_file_name) { - keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); + keylog_file_fp = curlx_fopen(keylog_file_name, FOPEN_APPENDTEXT); if(keylog_file_fp) { #ifdef _WIN32 if(setvbuf(keylog_file_fp, NULL, _IONBF, 0)) @@ -57,7 +58,7 @@ Curl_tls_keylog_open(void) if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) #endif { - fclose(keylog_file_fp); + curlx_fclose(keylog_file_fp); keylog_file_fp = NULL; } } @@ -70,7 +71,7 @@ void Curl_tls_keylog_close(void) { if(keylog_file_fp) { - fclose(keylog_file_fp); + curlx_fclose(keylog_file_fp); keylog_file_fp = NULL; } } diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index a6d8a4652d88..70e109212d36 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -32,6 +32,7 @@ #include +#include "../curlx/fopen.h" #include "../curlx/inet_pton.h" #include "../urldata.h" #include "../sendf.h" @@ -397,7 +398,7 @@ static int read_file_into(const char *filename, struct dynbuf *out) { - FILE *f = fopen(filename, FOPEN_READTEXT); + FILE *f = curlx_fopen(filename, FOPEN_READTEXT); if(!f) { return 0; } @@ -407,14 +408,14 @@ read_file_into(const char *filename, const size_t rr = fread(buf, 1, sizeof(buf), f); if(rr == 0 || CURLE_OK != curlx_dyn_addn(out, buf, rr)) { - fclose(f); + curlx_fclose(f); return 0; } if(rr < sizeof(buf)) break; } - return fclose(f) == 0; + return curlx_fclose(f) == 0; } static void diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 8ff8029e3b3e..bf68321afe96 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -47,6 +47,7 @@ #include "../strdup.h" #include "../strerror.h" #include "../select.h" /* for the socket readiness */ +#include "../curlx/fopen.h" #include "../curlx/inet_pton.h" /* for IP addr SNI check */ #include "../curlx/multibyte.h" #include "../curlx/warnless.h" @@ -563,7 +564,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, &cert_store_path, &cert_thumbprint_str); if(result && (data->set.ssl.primary.clientcert[0]!='\0')) - fInCert = fopen(data->set.ssl.primary.clientcert, "rb"); + fInCert = curlx_fopen(data->set.ssl.primary.clientcert, "rb"); if(result && !fInCert) { failf(data, "schannel: Failed to get certificate location" @@ -611,7 +612,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if((!certdata) || ((int) fread(certdata, certsize, 1, fInCert) != 1)) continue_reading = FALSE; - fclose(fInCert); + curlx_fclose(fInCert); if(!continue_reading) { failf(data, "schannel: Failed to read cert file %s", data->set.ssl.primary.clientcert); diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 9872e4c24d42..9e3870e47005 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -68,6 +68,7 @@ #include "../progress.h" #include "../share.h" #include "../multiif.h" +#include "../curlx/fopen.h" #include "../curlx/timeval.h" #include "../curl_md5.h" #include "../curl_sha256.h" @@ -803,7 +804,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, struct dynbuf buf; char unsigned *pem_ptr = NULL; size_t left; - FILE *fp = fopen(pinnedpubkey, "rb"); + FILE *fp = curlx_fopen(pinnedpubkey, "rb"); if(!fp) return result; @@ -865,7 +866,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, end: curlx_dyn_free(&buf); Curl_safefree(pem_ptr); - fclose(fp); + curlx_fclose(fp); } return result; diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 0012ccdae1ad..b737961899f1 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -88,6 +88,9 @@ "send" => 1, "socket" => 1, "socketpair" => 1, + "fclose" => 1, + "fdopen" => 1, + "fopen" => 1, ); my %warnings_extended = ( @@ -919,8 +922,8 @@ sub scanfile { } # scan for use of non-binary fopen without the macro - if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) { - my $mode = $2; + if($l =~ /^(.*\W)(curlx_fopen|CURLX_FOPEN_LOW)\s*\([^,]*, *\"([^"]*)/) { + my $mode = $3; if($mode !~ /b/) { checkwarn("FOPENMODE", $line, length($1), $file, $ol, diff --git a/src/Makefile.inc b/src/Makefile.inc index 1086c07febb1..35f8e6fdee84 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -36,6 +36,7 @@ CURLX_CFILES = \ ../lib/curlx/base64.c \ ../lib/curlx/multibyte.c \ ../lib/curlx/dynbuf.c \ + ../lib/curlx/fopen.c \ ../lib/curlx/nonblock.c \ ../lib/curlx/strparse.c \ ../lib/curlx/timediff.c \ @@ -49,6 +50,7 @@ CURLX_HFILES = \ ../lib/curlx/multibyte.h \ ../lib/curl_setup.h \ ../lib/curlx/dynbuf.h \ + ../lib/curlx/fopen.h \ ../lib/curlx/nonblock.h \ ../lib/curlx/strparse.h \ ../lib/curlx/timediff.h \ diff --git a/src/tool_cb_dbg.c b/src/tool_cb_dbg.c index 6a587cc1cc63..b454f5ca9bad 100644 --- a/src/tool_cb_dbg.c +++ b/src/tool_cb_dbg.c @@ -124,7 +124,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type, /* Ok, this is somewhat hackish but we do it undocumented for now */ global->trace_stream = tool_stderr; else { - global->trace_stream = fopen(global->trace_dump, FOPEN_WRITETEXT); + global->trace_stream = curlx_fopen(global->trace_dump, FOPEN_WRITETEXT); global->trace_fopened = TRUE; } } diff --git a/src/tool_cb_wrt.c b/src/tool_cb_wrt.c index 6fbf80753de3..b4ea781739a7 100644 --- a/src/tool_cb_wrt.c +++ b/src/tool_cb_wrt.c @@ -55,7 +55,7 @@ bool tool_create_output_file(struct OutStruct *outs, (config->file_clobber_mode == CLOBBER_DEFAULT && !outs->is_cd_filename)) { /* open file for writing */ - file = fopen(fname, "wb"); + file = curlx_fopen(fname, "wb"); } else { int fd; @@ -92,7 +92,7 @@ bool tool_create_output_file(struct OutStruct *outs, is not needed because we would have failed earlier, in the while loop and `fd` would now be -1 */ if(fd != -1) { - file = fdopen(fd, "wb"); + file = curlx_fdopen(fd, "wb"); if(!file) close(fd); } diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 675f4d2d9da9..e2df7cf91f02 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -258,7 +258,7 @@ static void free_globalconfig(void) tool_safefree(global->trace_dump); if(global->trace_fopened && global->trace_stream) - fclose(global->trace_stream); + curlx_fclose(global->trace_stream); global->trace_stream = NULL; tool_safefree(global->libcurl); diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c index 223c66bdf503..bff251e6b03e 100644 --- a/src/tool_easysrc.c +++ b/src/tool_easysrc.c @@ -178,7 +178,7 @@ void dumpeasysrc(void) FILE *out; bool fopened = FALSE; if(strcmp(o, "-")) { - out = fopen(o, FOPEN_WRITETEXT); + out = curlx_fopen(o, FOPEN_WRITETEXT); fopened = TRUE; } else @@ -227,7 +227,7 @@ void dumpeasysrc(void) fprintf(out, "%s\n", c); if(fopened) - fclose(out); + curlx_fclose(out); } easysrc_free(); diff --git a/src/tool_formparse.c b/src/tool_formparse.c index b5ab10a00f80..f1f2f5b7e5c6 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -563,14 +563,14 @@ static int get_param_part(char endchar, endpos--; sep = *p; *endpos = '\0'; - fp = fopen(hdrfile, FOPEN_READTEXT); + fp = curlx_fopen(hdrfile, FOPEN_READTEXT); if(!fp) warnf("Cannot read from %s: %s", hdrfile, strerror(errno)); else { int i = read_field_headers(hdrfile, fp, &headers); - fclose(fp); + curlx_fclose(fp); if(i) { curl_slist_free_all(headers); return -1; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index d7bdadb5d6d3..eed87bb807d7 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -627,7 +627,7 @@ static ParameterError data_urlencode(const char *nextarg, CURLX_SET_BINMODE(stdin); } else { - file = fopen(p, "rb"); + file = curlx_fopen(p, "rb"); if(!file) { errorf("Failed to open %s", p); return PARAM_READ_ERROR; @@ -637,7 +637,7 @@ static ParameterError data_urlencode(const char *nextarg, err = file2memory(&postdata, &size, file); if(file && (file != stdin)) - fclose(file); + curlx_fclose(file); if(err) return err; } @@ -899,7 +899,7 @@ static ParameterError set_data(cmdline_t cmd, CURLX_SET_BINMODE(stdin); } else { - file = fopen(nextarg, "rb"); + file = curlx_fopen(nextarg, "rb"); if(!file) { errorf("Failed to open %s", nextarg); return PARAM_READ_ERROR; @@ -917,7 +917,7 @@ static ParameterError set_data(cmdline_t cmd, } if(file && (file != stdin)) - fclose(file); + curlx_fclose(file); if(err) return err; @@ -1094,7 +1094,7 @@ static ParameterError parse_url(struct OperationConfig *config, if(fromstdin) f = stdin; else - f = fopen(&nextarg[1], FOPEN_READTEXT); + f = curlx_fopen(&nextarg[1], FOPEN_READTEXT); if(f) { curlx_dyn_init(&line, 8092); while(my_get_line(f, &line, &error)) { @@ -1104,7 +1104,7 @@ static ParameterError parse_url(struct OperationConfig *config, break; } if(!fromstdin) - fclose(f); + curlx_fclose(f); curlx_dyn_free(&line); if(error || err) return PARAM_READ_ERROR; @@ -1206,7 +1206,7 @@ static ParameterError parse_ech(struct OperationConfig *config, file = stdin; } else { - file = fopen(nextarg, FOPEN_READTEXT); + file = curlx_fopen(nextarg, FOPEN_READTEXT); } if(!file) { warnf("Couldn't read file \"%s\" " @@ -1216,7 +1216,7 @@ static ParameterError parse_ech(struct OperationConfig *config, } err = file2string(&tmpcfg, file); if(file != stdin) - fclose(file); + curlx_fclose(file); if(err) return err; config->ech_config = aprintf("ecl:%s",tmpcfg); @@ -1242,7 +1242,7 @@ static ParameterError parse_header(struct OperationConfig *config, if(nextarg[0] == '@') { /* read many headers from a file or stdin */ bool use_stdin = !strcmp(&nextarg[1], "-"); - FILE *file = use_stdin ? stdin : fopen(&nextarg[1], FOPEN_READTEXT); + FILE *file = use_stdin ? stdin : curlx_fopen(&nextarg[1], FOPEN_READTEXT); if(!file) { errorf("Failed to open %s", &nextarg[1]); err = PARAM_READ_ERROR; @@ -1263,7 +1263,7 @@ static ParameterError parse_header(struct OperationConfig *config, err = PARAM_READ_ERROR; curlx_dyn_free(&line); if(!use_stdin) - fclose(file); + curlx_fclose(file); } } else { @@ -1536,7 +1536,7 @@ static ParameterError parse_writeout(struct OperationConfig *config, } else { fname = nextarg; - file = fopen(fname, FOPEN_READTEXT); + file = curlx_fopen(fname, FOPEN_READTEXT); if(!file) { errorf("Failed to open %s", fname); return PARAM_READ_ERROR; @@ -1545,7 +1545,7 @@ static ParameterError parse_writeout(struct OperationConfig *config, tool_safefree(config->writeout); err = file2string(&config->writeout, file); if(file && (file != stdin)) - fclose(file); + curlx_fclose(file); if(err) return err; if(!config->writeout) diff --git a/src/tool_ipfs.c b/src/tool_ipfs.c index dd030f09bc92..c2f1b165239c 100644 --- a/src/tool_ipfs.c +++ b/src/tool_ipfs.c @@ -88,7 +88,7 @@ static char *ipfs_gateway(void) if(!gateway_composed_file_path) goto fail; - gateway_file = fopen(gateway_composed_file_path, FOPEN_READTEXT); + gateway_file = curlx_fopen(gateway_composed_file_path, FOPEN_READTEXT); tool_safefree(gateway_composed_file_path); if(gateway_file) { @@ -103,7 +103,7 @@ static char *ipfs_gateway(void) goto fail; } - fclose(gateway_file); + curlx_fclose(gateway_file); gateway_file = NULL; if(curlx_dyn_len(&dyn)) @@ -121,7 +121,7 @@ static char *ipfs_gateway(void) } fail: if(gateway_file) - fclose(gateway_file); + curlx_fclose(gateway_file); tool_safefree(gateway); tool_safefree(ipfs_path); return NULL; diff --git a/src/tool_operate.c b/src/tool_operate.c index 14eff06e0630..d5a1b2646812 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -164,7 +164,7 @@ static curl_off_t vms_realfilesize(const char *name, FILE * file; /* !checksrc! disable FOPENMODE 1 */ - file = fopen(name, "r"); /* VMS */ + file = curlx_fopen(name, "r"); /* VMS */ if(!file) { return 0; } @@ -175,7 +175,7 @@ static curl_off_t vms_realfilesize(const char *name, if(ret_stat) count += ret_stat; } - fclose(file); + curlx_fclose(file); return count; } @@ -660,7 +660,7 @@ static CURLcode post_per_transfer(struct per_transfer *per, /* Close the outs file */ if(outs->fopened && outs->stream) { - rc = fclose(outs->stream); + rc = curlx_fclose(outs->stream); if(!result && rc) { /* something went wrong in the writing process */ result = CURLE_WRITE_ERROR; @@ -696,13 +696,13 @@ static CURLcode post_per_transfer(struct per_transfer *per, /* Close function-local opened file descriptors */ if(per->heads.fopened && per->heads.stream) - fclose(per->heads.stream); + curlx_fclose(per->heads.stream); if(per->heads.alloc_filename) tool_safefree(per->heads.filename); if(per->etag_save.fopened && per->etag_save.stream) - fclose(per->etag_save.stream); + curlx_fclose(per->etag_save.stream); if(per->etag_save.alloc_filename) tool_safefree(per->etag_save.filename); @@ -800,7 +800,7 @@ static CURLcode etag_compare(struct OperationConfig *config) ParameterError pe; /* open file for reading: */ - FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT); + FILE *file = curlx_fopen(config->etag_compare_file, FOPEN_READTEXT); if(!file) warnf("Failed to open %s: %s", config->etag_compare_file, strerror(errno)); @@ -815,7 +815,7 @@ static CURLcode etag_compare(struct OperationConfig *config) if(!header) { if(file) - fclose(file); + curlx_fclose(file); errorf("Failed to allocate memory for custom etag header"); return CURLE_OUT_OF_MEMORY; } @@ -825,7 +825,7 @@ static CURLcode etag_compare(struct OperationConfig *config) tool_safefree(header); if(file) - fclose(file); + curlx_fclose(file); if(pe != PARAM_OK) result = CURLE_OUT_OF_MEMORY; return result; @@ -843,7 +843,7 @@ static CURLcode etag_store(struct OperationConfig *config, /* open file for output: */ if(strcmp(config->etag_save_file, "-")) { - FILE *newfile = fopen(config->etag_save_file, "ab"); + FILE *newfile = curlx_fopen(config->etag_save_file, "ab"); if(!newfile) { warnf("Failed creating file for saving etags: \"%s\". " "Skip this transfer", config->etag_save_file); @@ -893,11 +893,11 @@ static CURLcode setup_headerfile(struct OperationConfig *config, return result; } if(!per->prev || per->prev->config != config) { - newfile = fopen(config->headerfile, "wb"); + newfile = curlx_fopen(config->headerfile, "wb"); if(newfile) - fclose(newfile); + curlx_fclose(newfile); } - newfile = fopen(config->headerfile, "ab"); + newfile = curlx_fopen(config->headerfile, "ab"); if(!newfile) { errorf("Failed to open %s", config->headerfile); @@ -999,11 +999,11 @@ static CURLcode setup_outfile(struct OperationConfig *config, #ifdef __VMS /* open file for output, forcing VMS output format into stream mode which is needed for stat() call above to always work. */ - FILE *file = fopen(outfile, "ab", - "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0"); + FILE *file = curlx_fopen(outfile, "ab", + "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0"); #else /* open file for output: */ - FILE *file = fopen(per->outfile, "ab"); + FILE *file = curlx_fopen(per->outfile, "ab"); #endif if(!file) { errorf("cannot open '%s'", per->outfile); @@ -1193,7 +1193,7 @@ static CURLcode single_transfer(struct OperationConfig *config, if(result) { curl_easy_cleanup(curl); if(etag_first.fopened) - fclose(etag_first.stream); + curlx_fclose(etag_first.stream); return result; } per->etag_save = etag_first; /* copy the whole struct */ @@ -2004,7 +2004,7 @@ static CURLcode cacertpaths(struct OperationConfig *config) char *cacert = NULL; FILE *cafile = tool_execpath("curl-ca-bundle.crt", &cacert); if(cafile) { - fclose(cafile); + curlx_fclose(cafile); config->cacert = strdup(cacert); } #elif !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) && \ diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c index bc22b9d5b7b5..632286530a12 100644 --- a/src/tool_parsecfg.c +++ b/src/tool_parsecfg.c @@ -93,7 +93,7 @@ int parseconfig(const char *filename) /* NULL means load .curlrc from homedir! */ char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE); if(curlrc) { - file = fopen(curlrc, FOPEN_READTEXT); + file = curlx_fopen(curlrc, FOPEN_READTEXT); if(!file) { free(curlrc); return 1; @@ -115,7 +115,7 @@ int parseconfig(const char *filename) } else { if(strcmp(filename, "-")) - file = fopen(filename, FOPEN_READTEXT); + file = curlx_fopen(filename, FOPEN_READTEXT); else file = stdin; } @@ -250,7 +250,7 @@ int parseconfig(const char *filename) curlx_dyn_free(&buf); curlx_dyn_free(&pbuf); if(file != stdin) - fclose(file); + curlx_fclose(file); if(fileerror) rc = 1; } diff --git a/src/tool_ssls.c b/src/tool_ssls.c index edf8d6095a99..6fb01804554d 100644 --- a/src/tool_ssls.c +++ b/src/tool_ssls.c @@ -66,7 +66,7 @@ CURLcode tool_ssls_load(struct OperationConfig *config, bool error = FALSE; curlx_dyn_init(&buf, MAX_SSLS_LINE); - fp = fopen(filename, FOPEN_READTEXT); + fp = curlx_fopen(filename, FOPEN_READTEXT); if(!fp) { /* ok if it does not exist */ notef("SSL session file does not exist (yet?): %s", filename); goto out; @@ -122,7 +122,7 @@ CURLcode tool_ssls_load(struct OperationConfig *config, if(easy) curl_easy_cleanup(easy); if(fp) - fclose(fp); + curlx_fclose(fp); curlx_dyn_free(&buf); curl_free(shmac); curl_free(sdata); @@ -190,7 +190,7 @@ CURLcode tool_ssls_save(struct OperationConfig *config, CURLcode r = CURLE_OK; ctx.exported = 0; - ctx.fp = fopen(filename, FOPEN_WRITETEXT); + ctx.fp = curlx_fopen(filename, FOPEN_WRITETEXT); if(!ctx.fp) { warnf("Warning: Failed to create SSL session file %s", filename); @@ -207,6 +207,6 @@ CURLcode tool_ssls_save(struct OperationConfig *config, if(easy) curl_easy_cleanup(easy); if(ctx.fp) - fclose(ctx.fp); + curlx_fclose(ctx.fp); return r; } diff --git a/src/tool_stderr.c b/src/tool_stderr.c index b023d6c80202..1116c3009255 100644 --- a/src/tool_stderr.c +++ b/src/tool_stderr.c @@ -50,12 +50,12 @@ void tool_set_stderr_file(const char *filename) /* precheck that filename is accessible to lessen the chance that the subsequent freopen will fail. */ - fp = fopen(filename, FOPEN_WRITETEXT); + fp = curlx_fopen(filename, FOPEN_WRITETEXT); if(!fp) { warnf("Warning: Failed to open %s", filename); return; } - fclose(fp); + curlx_fclose(fp); /* freopen the actual stderr (stdio.h stderr) instead of tool_stderr since the latter may be set to stdout. */ diff --git a/src/tool_util.c b/src/tool_util.c index e7ab704f120b..f8415d2a1739 100644 --- a/src/tool_util.c +++ b/src/tool_util.c @@ -127,7 +127,7 @@ FILE *tool_execpath(const char *filename, char **pathp) if(strlen(filename) < remaining - 1) { curl_msnprintf(lastdirchar, remaining, "%s%s", DIR_CHAR, filename); *pathp = filebuffer; - return fopen(filebuffer, FOPEN_READTEXT); + return curlx_fopen(filebuffer, FOPEN_READTEXT); } } } diff --git a/src/tool_writeout.c b/src/tool_writeout.c index cdde28c90950..eaeec152e419 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -772,13 +772,13 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, break; case VAR_STDOUT: if(fclose_stream) - fclose(stream); + curlx_fclose(stream); fclose_stream = FALSE; stream = stdout; break; case VAR_STDERR: if(fclose_stream) - fclose(stream); + curlx_fclose(stream); fclose_stream = FALSE; stream = tool_stderr; break; @@ -824,12 +824,12 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, FILE *stream2; memcpy(fname, ptr, flen); fname[flen] = 0; - stream2 = fopen(fname, append ? FOPEN_APPENDTEXT : - FOPEN_WRITETEXT); + stream2 = curlx_fopen(fname, append ? FOPEN_APPENDTEXT : + FOPEN_WRITETEXT); if(stream2) { /* only change if the open worked */ if(fclose_stream) - fclose(stream); + curlx_fclose(stream); stream = stream2; fclose_stream = TRUE; } @@ -872,6 +872,6 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, } } if(fclose_stream) - fclose(stream); + curlx_fclose(stream); curlx_dyn_free(&name); } diff --git a/src/var.c b/src/var.c index 612735016c95..d279fdeb6e7c 100644 --- a/src/var.c +++ b/src/var.c @@ -455,7 +455,7 @@ ParameterError setvariable(const char *input) if(use_stdin) file = stdin; else { - file = fopen(line, "rb"); + file = curlx_fopen(line, "rb"); if(!file) { errorf("Failed to open %s: %s", line, strerror(errno)); err = PARAM_READ_ERROR; @@ -469,7 +469,7 @@ ParameterError setvariable(const char *input) } curlx_dyn_free(&fname); if(!use_stdin && file) - fclose(file); + curlx_fclose(file); if(err) return err; } diff --git a/tests/data/test1185 b/tests/data/test1185 index 8b14f4c5ffcb..43a27f087054 100644 --- a/tests/data/test1185 +++ b/tests/data/test1185 @@ -47,7 +47,7 @@ func_return() ; a = sprintf(buffer, "%s", moo); -FILE *f = fopen("filename", "r"); +FILE *f = curlx_fopen("filename", "r"); void startfunc(int a, int b) { func(); @@ -124,7 +124,7 @@ void startfunc(int a, int b) { a = sprintf(buffer, "%s", moo); ^ ./%LOGDIR/code1185.c:32:11: warning: use of non-binary fopen without FOPEN_* macro: r (FOPENMODE) - FILE *f = fopen("filename", "r"); + FILE *f = curlx_fopen("filename", "r"); ^ ./%LOGDIR/code1185.c:34:30: warning: wrongly placed open brace (BRACEPOS) void startfunc(int a, int b) { diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index 00273f9e9d6a..c316a0526925 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -34,6 +34,7 @@ UTILS_C = memptr.c testutil.c testtrace.c UTILS_H = testutil.h testtrace.h unitcheck.h CURLX_C = \ + ../../lib/curlx/fopen.c \ ../../lib/curlx/warnless.c \ ../../lib/curlx/multibyte.c \ ../../lib/curlx/timediff.c \ diff --git a/tests/libtest/cli_h2_serverpush.c b/tests/libtest/cli_h2_serverpush.c index 7b465bc61ad0..a865fdfd8f5b 100644 --- a/tests/libtest/cli_h2_serverpush.c +++ b/tests/libtest/cli_h2_serverpush.c @@ -30,7 +30,7 @@ static FILE *out_download; static int setup_h2_serverpush(CURL *hnd, const char *url) { - out_download = fopen("download_0.data", "wb"); + out_download = curlx_fopen("download_0.data", "wb"); if(!out_download) return 1; /* failed */ @@ -72,7 +72,7 @@ static int server_push_callback(CURL *parent, curl_msnprintf(filename, sizeof(filename) - 1, "push%u", count++); /* here's a new stream, save it in a new file for each new push */ - out_push = fopen(filename, "wb"); + out_push = curlx_fopen(filename, "wb"); if(!out_push) { /* if we cannot save it, deny it */ curl_mfprintf(stderr, "Failed to create output file for push\n"); @@ -129,7 +129,7 @@ static CURLcode test_cli_h2_serverpush(const char *URL) easy = curl_easy_init(); if(setup_h2_serverpush(easy, URL)) { - fclose(out_download); + curlx_fclose(out_download); curl_mfprintf(stderr, "failed\n"); return (CURLcode)1; } @@ -166,9 +166,9 @@ static CURLcode test_cli_h2_serverpush(const char *URL) curl_multi_cleanup(multi_handle); - fclose(out_download); + curlx_fclose(out_download); if(out_push) - fclose(out_push); + curlx_fclose(out_push); return CURLE_OK; } diff --git a/tests/libtest/cli_hx_download.c b/tests/libtest/cli_hx_download.c index 6394c5e25b22..7a6a48c171b5 100644 --- a/tests/libtest/cli_hx_download.c +++ b/tests/libtest/cli_hx_download.c @@ -94,7 +94,7 @@ static size_t my_write_d_cb(char *buf, size_t nitems, size_t buflen, if(!t->out) { curl_msnprintf(t->filename, sizeof(t->filename)-1, "download_%zu.data", t->idx); - t->out = fopen(t->filename, "wb"); + t->out = curlx_fopen(t->filename, "wb"); if(!t->out) return 0; } @@ -530,7 +530,7 @@ static CURLcode test_cli_hx_download(const char *URL) for(i = 0; i < transfer_count_d; ++i) { t = &transfer_d[i]; if(t->out) { - fclose(t->out); + curlx_fclose(t->out); t->out = NULL; } if(t->easy) { diff --git a/tests/libtest/cli_hx_upload.c b/tests/libtest/cli_hx_upload.c index 9c69e36787f4..40e486c41a1a 100644 --- a/tests/libtest/cli_hx_upload.c +++ b/tests/libtest/cli_hx_upload.c @@ -74,7 +74,7 @@ static size_t my_write_u_cb(char *buf, size_t nitems, size_t buflen, if(!t->out) { curl_msnprintf(t->filename, sizeof(t->filename)-1, "download_%zu.data", t->idx); - t->out = fopen(t->filename, "wb"); + t->out = curlx_fopen(t->filename, "wb"); if(!t->out) return 0; } @@ -494,7 +494,7 @@ static CURLcode test_cli_hx_upload(const char *URL) for(i = 0; i < transfer_count_u; ++i) { t = &transfer_u[i]; if(t->out) { - fclose(t->out); + curlx_fclose(t->out); t->out = NULL; } if(t->easy) { diff --git a/tests/libtest/lib500.c b/tests/libtest/lib500.c index 7081ec625d28..ffb974f4f0cb 100644 --- a/tests/libtest/lib500.c +++ b/tests/libtest/lib500.c @@ -90,7 +90,7 @@ static CURLcode test_lib500(const char *URL) if(!res) { res = curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ipstr); if(libtest_arg2) { - FILE *moo = fopen(libtest_arg2, "wb"); + FILE *moo = curlx_fopen(libtest_arg2, "wb"); if(moo) { curl_off_t time_namelookup; curl_off_t time_connect; @@ -163,7 +163,7 @@ static CURLcode test_lib500(const char *URL) (long)(time_total % 1000000)); } - fclose(moo); + curlx_fclose(moo); } } } diff --git a/tests/libtest/lib505.c b/tests/libtest/lib505.c index 2285208e9f37..fc200945847e 100644 --- a/tests/libtest/lib505.c +++ b/tests/libtest/lib505.c @@ -51,7 +51,7 @@ static CURLcode test_lib505(const char *URL) return TEST_ERR_USAGE; } - hd_src = fopen(libtest_arg2, "rb"); + hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", errno, strerror(errno)); @@ -70,19 +70,19 @@ static CURLcode test_lib505(const char *URL) curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", errno, strerror(errno)); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } if(!file_info.st_size) { curl_mfprintf(stderr, "File %s has zero size!\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } @@ -91,7 +91,7 @@ static CURLcode test_lib505(const char *URL) if(!curl) { curl_mfprintf(stderr, "curl_easy_init() failed\n"); curl_global_cleanup(); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } @@ -102,7 +102,7 @@ static CURLcode test_lib505(const char *URL) curl_mfprintf(stderr, "curl_slist_append() failed\n"); curl_easy_cleanup(curl); curl_global_cleanup(); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } headerlist = curl_slist_append(hl, buf_2); @@ -111,7 +111,7 @@ static CURLcode test_lib505(const char *URL) curl_slist_free_all(hl); curl_easy_cleanup(curl); curl_global_cleanup(); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } headerlist = hl; @@ -144,7 +144,7 @@ static CURLcode test_lib505(const char *URL) curl_slist_free_all(headerlist); /* close the local file */ - fclose(hd_src); + curlx_fclose(hd_src); curl_easy_cleanup(curl); curl_global_cleanup(); diff --git a/tests/libtest/lib518.c b/tests/libtest/lib518.c index 86eddec003e9..9cf3a42554ad 100644 --- a/tests/libtest/lib518.c +++ b/tests/libtest/lib518.c @@ -77,7 +77,7 @@ static int t518_fopen_works(void) fpa[i] = NULL; } for(i = 0; i < 3; i++) { - fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT); + fpa[i] = curlx_fopen(DEV_NULL, FOPEN_READTEXT); if(!fpa[i]) { t518_store_errmsg("fopen failed", errno); curl_mfprintf(stderr, "%s\n", t518_msgbuff); @@ -87,7 +87,7 @@ static int t518_fopen_works(void) } for(i = 0; i < 3; i++) { if(fpa[i]) - fclose(fpa[i]); + curlx_fclose(fpa[i]); } return ret; } diff --git a/tests/libtest/lib525.c b/tests/libtest/lib525.c index 6c7d6503667a..007889fdc722 100644 --- a/tests/libtest/lib525.c +++ b/tests/libtest/lib525.c @@ -42,7 +42,7 @@ static CURLcode test_lib525(const char *URL) return TEST_ERR_USAGE; } - hd_src = fopen(libtest_arg2, "rb"); + hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", errno, strerror(errno)); @@ -61,13 +61,13 @@ static CURLcode test_lib525(const char *URL) curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", errno, strerror(errno)); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_FSTAT; } res_global_init(CURL_GLOBAL_ALL); if(res) { - fclose(hd_src); + curlx_fclose(hd_src); return res; } @@ -149,7 +149,7 @@ static CURLcode test_lib525(const char *URL) } /* close the local file */ - fclose(hd_src); + curlx_fclose(hd_src); return res; } diff --git a/tests/libtest/lib537.c b/tests/libtest/lib537.c index fa03c3b9833d..90de8a2d0c75 100644 --- a/tests/libtest/lib537.c +++ b/tests/libtest/lib537.c @@ -74,7 +74,7 @@ static int t537_fopen_works(void) fpa[i] = NULL; } for(i = 0; i < 3; i++) { - fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT); + fpa[i] = curlx_fopen(DEV_NULL, FOPEN_READTEXT); if(!fpa[i]) { t537_store_errmsg("fopen failed", errno); curl_mfprintf(stderr, "%s\n", t537_msgbuff); @@ -84,7 +84,7 @@ static int t537_fopen_works(void) } for(i = 0; i < 3; i++) { if(fpa[i]) - fclose(fpa[i]); + curlx_fclose(fpa[i]); } return ret; } diff --git a/tests/libtest/lib541.c b/tests/libtest/lib541.c index 9868474d01b3..3bb64f8ac4a4 100644 --- a/tests/libtest/lib541.c +++ b/tests/libtest/lib541.c @@ -42,7 +42,7 @@ static CURLcode test_lib541(const char *URL) return TEST_ERR_USAGE; } - hd_src = fopen(libtest_arg2, "rb"); + hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", errno, strerror(errno)); @@ -61,19 +61,19 @@ static CURLcode test_lib541(const char *URL) curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", errno, strerror(errno)); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } if(!file_info.st_size) { curl_mfprintf(stderr, "File %s has zero size!\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } @@ -82,7 +82,7 @@ static CURLcode test_lib541(const char *URL) if(!curl) { curl_mfprintf(stderr, "curl_easy_init() failed\n"); curl_global_cleanup(); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } @@ -110,7 +110,7 @@ static CURLcode test_lib541(const char *URL) test_cleanup: /* close the local file */ - fclose(hd_src); + curlx_fclose(hd_src); curl_easy_cleanup(curl); curl_global_cleanup(); diff --git a/tests/libtest/lib566.c b/tests/libtest/lib566.c index 15221cd0ccd8..79f48f235b2c 100644 --- a/tests/libtest/lib566.c +++ b/tests/libtest/lib566.c @@ -54,10 +54,10 @@ static CURLcode test_lib566(const char *URL) res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length); - moo = fopen(libtest_arg2, "wb"); + moo = curlx_fopen(libtest_arg2, "wb"); if(moo) { curl_mfprintf(moo, "CL %.0f\n", content_length); - fclose(moo); + curlx_fclose(moo); } } diff --git a/tests/libtest/lib568.c b/tests/libtest/lib568.c index 8e34194ef5ed..83c6fd23941c 100644 --- a/tests/libtest/lib568.c +++ b/tests/libtest/lib568.c @@ -75,7 +75,7 @@ static CURLcode test_lib568(const char *URL) fstat(sdp, &file_info); close(sdp); - sdpf = fopen(libtest_arg2, "rb"); + sdpf = curlx_fopen(libtest_arg2, "rb"); if(!sdpf) { curl_mfprintf(stderr, "can't fopen %s\n", libtest_arg2); res = TEST_ERR_MAJOR_BAD; @@ -94,7 +94,7 @@ static CURLcode test_lib568(const char *URL) goto test_cleanup; test_setopt(curl, CURLOPT_UPLOAD, 0L); - fclose(sdpf); + curlx_fclose(sdpf); sdpf = NULL; /* Make sure we can do a normal request now */ @@ -159,7 +159,7 @@ static CURLcode test_lib568(const char *URL) test_cleanup: if(sdpf) - fclose(sdpf); + curlx_fclose(sdpf); curl_free(stream_uri); diff --git a/tests/libtest/lib569.c b/tests/libtest/lib569.c index 8f340b489d59..b1a80a7b0118 100644 --- a/tests/libtest/lib569.c +++ b/tests/libtest/lib569.c @@ -38,7 +38,7 @@ static CURLcode test_lib569(const char *URL) int request = 1; int i; - FILE *idfile = fopen(libtest_arg2, "wb"); + FILE *idfile = curlx_fopen(libtest_arg2, "wb"); if(!idfile) { curl_mfprintf(stderr, "couldn't open the Session ID File\n"); return TEST_ERR_MAJOR_BAD; @@ -46,7 +46,7 @@ static CURLcode test_lib569(const char *URL) if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); - fclose(idfile); + curlx_fclose(idfile); return TEST_ERR_MAJOR_BAD; } @@ -54,7 +54,7 @@ static CURLcode test_lib569(const char *URL) if(!curl) { curl_mfprintf(stderr, "curl_easy_init() failed\n"); curl_global_cleanup(); - fclose(idfile); + curlx_fclose(idfile); return TEST_ERR_MAJOR_BAD; } @@ -116,7 +116,7 @@ static CURLcode test_lib569(const char *URL) test_cleanup: if(idfile) - fclose(idfile); + curlx_fclose(idfile); curl_free(stream_uri); curl_easy_cleanup(curl); diff --git a/tests/libtest/lib571.c b/tests/libtest/lib571.c index 2cf4128e7ab5..49afc2211d2a 100644 --- a/tests/libtest/lib571.c +++ b/tests/libtest/lib571.c @@ -95,7 +95,7 @@ static CURLcode test_lib571(const char *URL) char *stream_uri = NULL; int request = 1; - FILE *protofile = fopen(libtest_arg2, "wb"); + FILE *protofile = curlx_fopen(libtest_arg2, "wb"); if(!protofile) { curl_mfprintf(stderr, "Couldn't open the protocol dump file\n"); return TEST_ERR_MAJOR_BAD; @@ -103,14 +103,14 @@ static CURLcode test_lib571(const char *URL) if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); - fclose(protofile); + curlx_fclose(protofile); return TEST_ERR_MAJOR_BAD; } curl = curl_easy_init(); if(!curl) { curl_mfprintf(stderr, "curl_easy_init() failed\n"); - fclose(protofile); + curlx_fclose(protofile); curl_global_cleanup(); return TEST_ERR_MAJOR_BAD; } @@ -194,7 +194,7 @@ static CURLcode test_lib571(const char *URL) curl_free(stream_uri); if(protofile) - fclose(protofile); + curlx_fclose(protofile); curl_easy_cleanup(curl); curl_global_cleanup(); diff --git a/tests/libtest/lib572.c b/tests/libtest/lib572.c index ea9e34e06853..ef5e06602357 100644 --- a/tests/libtest/lib572.c +++ b/tests/libtest/lib572.c @@ -93,7 +93,7 @@ static CURLcode test_lib572(const char *URL) fstat(params, &file_info); close(params); - paramsf = fopen(libtest_arg2, "rb"); + paramsf = curlx_fopen(libtest_arg2, "rb"); if(!paramsf) { curl_mfprintf(stderr, "can't fopen %s\n", libtest_arg2); res = TEST_ERR_MAJOR_BAD; @@ -110,7 +110,7 @@ static CURLcode test_lib572(const char *URL) goto test_cleanup; test_setopt(curl, CURLOPT_UPLOAD, 0L); - fclose(paramsf); + curlx_fclose(paramsf); paramsf = NULL; /* Heartbeat GET_PARAMETERS */ @@ -163,7 +163,7 @@ static CURLcode test_lib572(const char *URL) test_cleanup: if(paramsf) - fclose(paramsf); + curlx_fclose(paramsf); curl_free(stream_uri); diff --git a/tests/libtest/lib578.c b/tests/libtest/lib578.c index a15c9a4f8187..b6be1600f4c9 100644 --- a/tests/libtest/lib578.c +++ b/tests/libtest/lib578.c @@ -33,7 +33,7 @@ static size_t data_size = CURL_ARRAYSIZE(t578_testdata); static int t578_progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { - FILE *moo = fopen(libtest_arg2, "wb"); + FILE *moo = curlx_fopen(libtest_arg2, "wb"); (void)clientp; (void)dltotal; @@ -45,7 +45,7 @@ static int t578_progress_callback(void *clientp, double dltotal, double dlnow, else curl_mfprintf(moo, "Progress callback called with UL %f out of %f\n", ulnow, ultotal); - fclose(moo); + curlx_fclose(moo); } return 0; } diff --git a/tests/libtest/lib579.c b/tests/libtest/lib579.c index 76ecefe4ec53..29396941cc80 100644 --- a/tests/libtest/lib579.c +++ b/tests/libtest/lib579.c @@ -35,11 +35,11 @@ static size_t last_ul_total = 0; static void progress_final_report(void) { - FILE *moo = fopen(libtest_arg2, "ab"); + FILE *moo = curlx_fopen(libtest_arg2, "ab"); curl_mfprintf(moo ? moo : stderr, "Progress: end UL %zu/%zu\n", last_ul, last_ul_total); if(moo) - fclose(moo); + curlx_fclose(moo); else curl_mfprintf(stderr, "Progress: end UL, can't open %s\n", libtest_arg2); started = FALSE; @@ -59,11 +59,11 @@ static int t579_progress_callback(void *clientp, double dltotal, double dlnow, last_ul = (size_t)ulnow; last_ul_total = (size_t)ultotal; if(!started) { - FILE *moo = fopen(libtest_arg2, "ab"); + FILE *moo = curlx_fopen(libtest_arg2, "ab"); curl_mfprintf(moo ? moo : stderr, "Progress: start UL %zu/%zu\n", last_ul, last_ul_total); if(moo) - fclose(moo); + curlx_fclose(moo); else curl_mfprintf(stderr, "Progress: start UL, can't open %s\n", libtest_arg2); diff --git a/tests/libtest/lib582.c b/tests/libtest/lib582.c index 70a9ab65dcdb..b1970632210d 100644 --- a/tests/libtest/lib582.c +++ b/tests/libtest/lib582.c @@ -243,7 +243,7 @@ static CURLcode test_lib582(const char *URL) return TEST_ERR_USAGE; } - hd_src = fopen(libtest_arg2, "rb"); + hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen() failed with error (%d) %s\n", errno, strerror(errno)); @@ -262,7 +262,7 @@ static CURLcode test_lib582(const char *URL) curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", errno, strerror(errno)); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_FSTAT; } curl_mfprintf(stderr, "Set to upload %" CURL_FORMAT_CURL_OFF_T " bytes\n", @@ -270,7 +270,7 @@ static CURLcode test_lib582(const char *URL) res_global_init(CURL_GLOBAL_ALL); if(res != CURLE_OK) { - fclose(hd_src); + curlx_fclose(hd_src); return res; } @@ -356,7 +356,7 @@ static CURLcode test_lib582(const char *URL) curl_global_cleanup(); /* close the local file */ - fclose(hd_src); + curlx_fclose(hd_src); /* free local memory */ free(sockets.read.sockets); diff --git a/tests/libtest/lib591.c b/tests/libtest/lib591.c index 1f09fbdc4d12..77a038c7c320 100644 --- a/tests/libtest/lib591.c +++ b/tests/libtest/lib591.c @@ -39,7 +39,7 @@ static CURLcode test_lib591(const char *URL) start_test_timing(); - upload = fopen(libtest_arg3, "rb"); + upload = curlx_fopen(libtest_arg3, "rb"); if(!upload) { curl_mfprintf(stderr, "fopen() failed with error (%d) %s\n", errno, strerror(errno)); @@ -49,7 +49,7 @@ static CURLcode test_lib591(const char *URL) res_global_init(CURL_GLOBAL_ALL); if(res) { - fclose(upload); + curlx_fclose(upload); return res; } @@ -138,7 +138,7 @@ static CURLcode test_lib591(const char *URL) curl_global_cleanup(); /* close the local file */ - fclose(upload); + curlx_fclose(upload); return res; } diff --git a/tests/libtest/lib599.c b/tests/libtest/lib599.c index 5b52698a29f7..199ef90dbf8c 100644 --- a/tests/libtest/lib599.c +++ b/tests/libtest/lib599.c @@ -82,10 +82,10 @@ static CURLcode test_lib599(const char *URL) FILE *moo; res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length); - moo = fopen(libtest_arg2, "wb"); + moo = curlx_fopen(libtest_arg2, "wb"); if(moo) { curl_mfprintf(moo, "CL %.0f\n", content_length); - fclose(moo); + curlx_fclose(moo); } } diff --git a/tests/libtest/lib678.c b/tests/libtest/lib678.c index 78e03c004f98..5fdabdda9609 100644 --- a/tests/libtest/lib678.c +++ b/tests/libtest/lib678.c @@ -30,7 +30,7 @@ static int loadfile(const char *filename, void **filedata, size_t *filesize) size_t datasize = 0; void *data = NULL; if(filename) { - FILE *fInCert = fopen(filename, "rb"); + FILE *fInCert = curlx_fopen(filename, "rb"); if(fInCert) { long cert_tell = 0; @@ -48,7 +48,7 @@ static int loadfile(const char *filename, void **filedata, size_t *filesize) if((!data) || ((int)fread(data, datasize, 1, fInCert) != 1)) continue_reading = FALSE; - fclose(fInCert); + curlx_fclose(fInCert); if(!continue_reading) { free(data); datasize = 0; diff --git a/tests/server/.checksrc b/tests/server/.checksrc index be8f12cec014..670d4b800912 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -1,4 +1,6 @@ allowfunc accept +allowfunc fclose +allowfunc fopen allowfunc freeaddrinfo allowfunc getaddrinfo allowfunc recv diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index 2e3791c77490..be35fe7c4fd0 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -35,6 +35,7 @@ UTILS_H = CURLX_C = \ ../../lib/curlx/base64.c \ + ../../lib/curlx/fopen.c \ ../../lib/curlx/inet_pton.c \ ../../lib/curlx/inet_ntop.c \ ../../lib/curlx/multibyte.c \ diff --git a/tests/unit/unit3200.c b/tests/unit/unit3200.c index 023bf0ddb6fd..5c3e4d14ad47 100644 --- a/tests/unit/unit3200.c +++ b/tests/unit/unit3200.c @@ -84,12 +84,12 @@ static CURLcode test_unit3200(const char *arg) char *line; curlx_dyn_init(&buf, len); - fp = fopen(arg, "wb"); + fp = curlx_fopen(arg, "wb"); abort_unless(fp != NULL, "Cannot open testfile"); fwrite(filecontents[i], 1, strlen(filecontents[i]), fp); - fclose(fp); + curlx_fclose(fp); - fp = fopen(arg, "rb"); + fp = curlx_fopen(arg, "rb"); abort_unless(fp != NULL, "Cannot open testfile"); curl_mfprintf(stderr, "Test %zd...", i); @@ -158,7 +158,7 @@ static CURLcode test_unit3200(const char *arg) break; } curlx_dyn_free(&buf); - fclose(fp); + curlx_fclose(fp); curl_mfprintf(stderr, "OK\n"); } return (CURLcode)rc;