diff options
79 files changed, 3395 insertions, 3000 deletions
diff --git a/libs/libcurl/docs/CHANGES b/libs/libcurl/docs/CHANGES index f77f0a9e13..692f78f2bb 100644 --- a/libs/libcurl/docs/CHANGES +++ b/libs/libcurl/docs/CHANGES @@ -6,6 +6,1375 @@ Changelog +Version 7.81.0 (5 Jan 2022) + +Daniel Stenberg (5 Jan 2022) +- RELEASE-NOTES: synced + + curl 7.81.0 release + +- THANKS: add names from 7.81.0 release + +- curl_multi_init.3: fix the copyright year range + +- test719-721: require "proxy" feature present to run + + Bug: https://github.com/curl/curl/pull/8223#issuecomment-1005188696 + Reported-by: Marc Hörsken + + Closes #8226 + +- test719: require ipv6 support to run + + Follow-up to effd2bd7ba2a5fd244 + Reported-by: Marc Hörsken + Bug: https://github.com/curl/curl/pull/8217#issuecomment-1004681145 + + Closes #8223 + +- test719-721: verify SOCKS details + + Using the new verify/socks details + +- runtests: add verify/socks check + + If used, this data is compared with the data in log/socksd-request.log + which the socksd server logs. + + Added to FILEFORMAT.md + +- server/socksd: log atyp + address in a separate log + + To allow the test suite to verify that the right data arrived + +- socks5: use appropriate ATYP for numerical IP address host names + + When not resolving the address locallly (known as socks5h). + + Add test 719 and 720 to verify. + + Reported-by: Peter Piekarski + Fixes #8216 + Closes #8217 + +Jay Satiro (3 Jan 2022) +- curl_multi_init.3: fix EXAMPLE formatting + +Daniel Stenberg (3 Jan 2022) +- RELEASE-NOTES: synced + +- libtest: avoid "assignment within conditional expression" + + In lib530, lib540 and lib582 + + Closes #8218 + +- ftp: disable warning 4706 in MSVC + + Follow-up to 21248e052d + + Disabling "assignment within conditional expression" for MSVC needs to + be done before the function starts, for it to take effect. + + Closes #8218 + +- tool_operate: warn if too many output arguments were found + + More output instructions than URLs is likely a user error. + + Add test case 371 to verify + + Closes #8210 + +- .github/workflows/mbedtls.yml: bump to mbedtls 3.1.0 + + Closes #8215 + +- zuul: remove the mbedtls jobs + + Now running as github workflows + + Closes #8215 + +- github/workflows: add mbedtls and mbedtls-clang + + Closes #8215 + +- [Valentin Richter brought this change] + + mbedtls: fix private member designations for v3.1.0 + + "As a last resort, you can access the field foo of a structure bar by + writing bar.MBEDTLS_PRIVATE(foo). Note that you do so at your own risk, + since such code is likely to break in a future minor version of Mbed + TLS." - + https://github.com/ARMmbed/mbedtls/blob/f2d1199edc5834df4297f247f213e614f7782d1d/docs/3.0-migration-guide.md + + That future minor version is v3.1.0. I set the >= to == for the version + checks because v3.1.0 is a release, and I am not sure when the private + designation was reverted after v3.0.0. + + Closes #8214 + +- [Valentin Richter brought this change] + + cmake: prevent dev warning due to mismatched arg + + -- curl version=[7.81.0-DEV] + CMake Warning (dev) at /usr/share/cmake-3.22.1/Modules/FindPackageHandleStandardArgs.cmake:438 (message): + The package name passed to `find_package_handle_standard_args` (MBEDTLS) + does not match the name of the calling package (MbedTLS). This can lead to + problems in calling code that expects `find_package` result variables + (e.g., `_FOUND`) to follow a certain pattern. + Call Stack (most recent call first): + deps/curl/CMake/FindMbedTLS.cmake:31 (find_package_handle_standard_args) + deps/curl/CMakeLists.txt:473 (find_package) + This warning is for project developers. Use -Wno-dev to suppress it. + + Closes #8207 + +- urlapi: if possible, shorten given numerical IPv6 addresses + + Extended test 1560 to verify + + Closes #8206 + +- [Michał Antoniak brought this change] + + url: reduce ssl backend count for CURL_DISABLE_PROXY builds + + Closes #8212 + +- KNOWN_BUGS: "Trying local ports fails on Windows" + + Reported-by: gclinch on github + Closes #8112 + +- misc: update copyright year range + +- zuul: remove the wolfssl even more + + Follow-up to 1914465cf180d32b3d + +- examples/multi-single.c: remove WAITMS() + + As it isn't used. + + Reported-by: Melroy van den Berg + Fixes #8200 + Closes #8201 + +- gtls: add gnutls include for the session type + + Follow-up to 8fbd6feddfa5 to make it build more universally + +- m4/curl-compilers: tell clang -Wno-pointer-bool-conversion + + To hush compiler warnings we don't care for: error: address of function + 'X' will always evaluate to 'true' + + Fixes #8197 + Closes #8198 + +- http_proxy: don't close the socket (too early) + + ... and double-check in the OpenSSL shutdown that the socket is actually + still there before it is used. + + Fixes #8193 + Closes #8195 + + Reported-by: Leszek Kubik + +- ngtcp2: verify the server certificate for the gnutls case + + Closes #8178 + +- ngtcp2: verify the server cert on connect (quictls) + + Make ngtcp2+quictls correctly acknowledge `CURLOPT_SSL_VERIFYPEER` and + `CURLOPT_SSL_VERIFYHOST`. + + The name check now uses a function from lib/vtls/openssl.c which will + need attention for when TLS is not done by OpenSSL or is disabled while + QUIC is enabled. + + Possibly the servercert() function in openssl.c should be adjusted to be + able to use for both regular TLS and QUIC. + + Ref: #8173 + Closes #8178 + +- zuul: remove the wolfssl build + +- github workflow: add wolfssl + + Closes #8196 + +- [Nicolas Sterchele brought this change] + + zuul: fix quiche build pointing to wrong Cargo + + Fixes #8184 + Closes #8189 + +- checksrc: detect more kinds of NULL comparisons we avoid + + Co-authored-by: Jay Satiro + Closes #8180 + +- RELEASE-NOTES: synced + +- mesalink: remove the BACKEND define kludge + + Closes #8183 + +- schannel: remove the BACKEND define kludge + + Closes #8182 + +- gtls: check return code for gnutls_alpn_set_protocols + + Closes #8181 + +- [Stefan Huber brought this change] + + README: label the link to the support document + + Closes #8185 + +- docs/HTTP3: describe how to setup a h3 reverse-proxy for testing + + Assisted-by: Matt Holt + + Closes #8177 + +- libcurl-multi.3: "SOCKS proxy handshakes" are not blocking + + Since 4a4b63daaa0 + +- [Vladimir Panteleev brought this change] + + tests: Add test for CURLOPT_HTTP200ALIASES + +- [Vladimir Panteleev brought this change] + + http: Fix CURLOPT_HTTP200ALIASES + + The httpcode < 100 check was also triggered when none of the fields were + parsed, thus making the if(!nc) block unreachable. + + Closes #8171 + +- RELEASE-NOTES: synced + +- language: "email" + + Missed three occurrences. + + Follow-up to 7a92f86 + +- nss:set_cipher don't clobber the cipher list + + The string is set by the user and needs to remain intact for proper + connection reuse etc. + + Reported-by: Eric Musser + Fixes #8160 + Closes #8161 + +- misc: s/e-mail/email + + Consistency is king. Following the lead in everything curl. + + Closes #8159 + +- [Tobias Nießen brought this change] + + docs: fix typo in OpenSSL 3 build instructions + + Closes #8162 + +- linkcheck.yml: add CI job that checks markdown links + + Closes #8158 + +- RELEASE-PROCEDURE.md: remove ICAL link and old release dates + +- BINDINGS.md: "markdown-link-check-disable" + + It feels a bit unfortunate to litter an ugly tag for this functionality, + but if we get link scans of all markdown files, this might be worth the + price. + +- docs: fix dead links, remove ECH.md + +Jay Satiro (16 Dec 2021) +- openssl: define HAVE_OPENSSL_VERSION for OpenSSL 1.1.0+ + + Prior to this change OpenSSL_version was only detected in configure + builds. For other builds the old version parsing code was used which + would result in incorrect versioning for OpenSSL 3: + + Before: + + curl 7.80.0 (i386-pc-win32) libcurl/7.80.0 OpenSSL/3.0.0a zlib/1.2.11 + WinIDN libssh2/1.9.0 + + After: + + curl 7.80.0 (i386-pc-win32) libcurl/7.80.0 OpenSSL/3.0.1 zlib/1.2.11 + WinIDN libssh2/1.9.0 + + Reported-by: lllaffer@users.noreply.github.com + + Fixes https://github.com/curl/curl/issues/8154 + Closes https://github.com/curl/curl/pull/8155 + +Daniel Stenberg (16 Dec 2021) +- [James Fuller brought this change] + + docs: add known bugs list to HTTP3.md + + Closes #8156 + +Dan Fandrich (15 Dec 2021) +- BINDINGS: add one from Everything curl and update a link + +- libcurl-security.3: mention address and URL mitigations + + The new CURLOPT_PREREQFUNCTION callback is another way to sanitize + addresses. + Using the curl_url API is a way to mitigate against attacks relying on + URL parsing differences. + +Daniel Stenberg (15 Dec 2021) +- RELEASE-NOTES: synced + +- x509asn1: return early on errors + + Overhaul to make sure functions that detect errors bail out early with + error rather than trying to continue and risk hiding the problem. + + Closes #8147 + +- [Patrick Monnerat brought this change] + + openldap: several minor improvements + + - Early check proper LDAP URL syntax. Reject URLs with a userinfo part. + - Use dynamic memory for ldap_init_fd() URL rather than a + stack-allocated buffer. + - Never chase referrals: supporting it would require additional parallel + connections and alternate authentication credentials. + - Do not wait 1 microsecond while polling/reading query response data. + - Store last received server code for retrieval with CURLINFO_RESPONSE_CODE. + + Closes #8140 + +- [Michał Antoniak brought this change] + + misc: remove unused doh flags when CURL_DISABLE_DOH is defined + + Closes #8148 + +- mbedtls: fix CURLOPT_SSLCERT_BLOB + + The memory passed to mbedTLS for this needs to be null terminated. + + Reported-by: Florian Van Heghe + Closes #8146 + +- asyn-ares: ares_getaddrinfo needs no happy eyeballs timer + + Closes #8142 + +- mailmap: add Yongkang Huang + + From #8141 + +- [Yongkang Huang brought this change] + + check ssl_config when re-use proxy connection + +- mbedtls: do a separate malloc for ca_info_blob + + Since the mbedTLS API requires the data to the null terminated. + + Follow-up to 456c53730d21b1fad0c7f72c1817 + + Fixes #8139 + Closes #8145 + +Marc Hoersken (14 Dec 2021) +- CI: build examples for additional code verification + + Some CIs already build them, let's do it on more of them. + + Reviewed-by: Daniel Stenberg + + Follow up to #7690 and 77311f420a541a0de5b3014e0e40ff8b4205d4af + Replaces #7591 + Closes #7922 + +- docs/examples: workaround broken -Wno-pedantic-ms-format + + Avoid CURL_FORMAT_CURL_OFF_T by using unsigned long instead. + Improve size_t to long conversion in imap-append.c example. + + Ref: https://github.com/curl/curl/issues/6079 + Ref: https://github.com/curl/curl/pull/6082 + Assisted-by: Jay Satiro + Reviewed-by: Daniel Stenberg + + Preparation of #7922 + +- tests/data/test302[12]: fix MSYS2 path conversion of hostpubsha256 + + Ref: https://www.msys2.org/wiki/Porting/#filesystem-namespaces + + Reviewed-by: Marcel Raad + Reviewed-by: Jay Satiro + + Fixes #8084 + Closes #8138 + +Daniel Stenberg (13 Dec 2021) +- [Patrick Monnerat brought this change] + + openldap: simplify ldif generation code + + and take care of zero-length values, avoiding conversion to base64 + and/or trailing spaces. + + Closes #8136 + +- example/progressfunc: remove code for old libcurls + + 7.61.0 is over three years old now, remove all #ifdefs for handling + ancient libcurl versions so that the example gets easier to read and + understand + + Closes #8137 + +- [x2018 brought this change] + + sha256/md5: return errors when init fails + + Closes #8133 + +- TODO: 13.3 Defeat TLS fingerprinting + + Closes #8119 + +- RELEASE-NOTES: synced + +- [Patrick Monnerat brought this change] + + openldap: process search query response messages one by one + + Upon receiving large result sets, this reduces memory consumption and + allows starting to output results while the transfer is still in + progress. + + Closes #8101 + +- hash: lazy-alloc the table in Curl_hash_add() + + This makes Curl_hash_init() infallible which saves error paths. + + Closes #8132 + +- multi: cleanup the socket hash when destroying it + + Since each socket hash entry may themselves have a hash table in them, + the destroying of the socket hash needs to make sure all the subhashes + are also correctly destroyed to avoid leaking memory. + + Fixes #8129 + Closes #8131 + +- test1156: fixup the stdout check for Windows + + It is not text mode. + + Follow-up to 6f73e68d182 + + Closes #8134 + +- test1528: enable for hyper + + Closes #8128 + +- test1527: enable for hyper + + Closes #8128 + +- test1526: enable for hyper + + Closes #8128 + +- test1525: slightly tweaked for hyper + + Closes #8128 + +- test1156: enable for hyper + + Minor reorg of the lib1156 code and it works fine for hyper. + + Closes #8127 + +- test661: enable for hyper + + Closes #8126 + +- docs: fix proselint nits + + - remove a lot of exclamation marks + - use consistent spaces (1, not 2) + - use better words at some places + + Closes #8123 + +- [RekGRpth brought this change] + + BINDINGS.md: add cURL client for PostgreSQL + + Closes #8125 + +- [RekGRpth brought this change] + + CURLSHOPT_USERDATA.3: fix copy-paste mistake + + Closes #8124 + +- docs: fix minor nroff format nits + + Repairs test 1140 + + Follow-up to 436cdf82041 + +- docs/URL-SYNTAX.md: space is not fine in a given URL + +- curl_multi_perform/socket_action.3: clarify what errors mean + + An error returned from one of these funtions mean that ALL still ongoing + transfers are to be considered failed. + + Ref: #8114 + Closes #8120 + +- libcurl-errors.3: add CURLM_ABORTED_BY_CALLBACK + + Follow-up to #8089 (2b3dd01) + + Closes #8116 + +- hash: add asserts to help detect bad usage + + For example trying to add entries after the hash has been "cleaned up" + + Closes #8115 + +- lib530: abort on curl_multi errors + + This makes torture tests run more proper. + + Also add an assert to trap situations where it would end up with no + sockets to wait for. + + Closes #8121 + +- FAQ: we never pronounced it "see URL", we say "kurl" + +- RELEASE-NOTES: synced + +- CURLOPT_RESOLVE.3: minor polish + + Minor rephrasing for some explanations. + + Put the format strings in stand-alone lines with .nf/.fi to be easier to spot. + + Move "added in" to AVAILABILITY + + Closed #8110 + +- test1556: adjust for hyper + + Closes #8105 + +- test1554: adjust for hyper + + Closes #8104 + +- retry-all-errors.d: make the example complete + + ... as it needs --retry too to work + +- TODO: 5.7 Require HTTP version X or higher + + Closes #7980 + +- CURLOPT_STDERR.3: does not work with libcurl as a win32 DLL + + This is the exact same limitation already documented for + CURLOPT_WRITEDATA but should be clarified here. It also has a different + work-around. + + Reported-by: Stephane Pellegrino + Bug: https://github.com/curl/curl/issues/8102 + Closes #8103 + +- multi: handle errors returned from socket/timer callbacks + + The callbacks were partially documented to support this. Now the + behavior is documented and returning error from either of these + callbacks will effectively kill all currently ongoing transfers. + + Added test 530 to verify + + Reported-by: Marcelo Juchem + Fixes #8083 + Closes #8089 + +- http2:set_transfer_url() return early on OOM + + If curl_url() returns NULL this should return early to avoid mistakes - + even if right now the subsequent function invokes are all OK. + + Coverity (wrongly) pointed out this as a NULL deref. + + Closes #8100 + +- tool_parsecfg: use correct free() call to free memory + + Detected by Coverity. CID 1494642. + Follow-up from 2be1aa619bca + + Closes #8099 + +- tool_operate: fix potential memory-leak + + A 'CURLU *' would leak if url_proto() is called with no URL. + + Detected by Coverity. CID 1494643. + Follow-up to 18270893abdb19 + Closes #8098 + +- [Patrick Monnerat brought this change] + + openldap: implement STARTTLS + + As this introduces use of CURLOPT_USE_SSL option for LDAP, also check + this option in ldap.c as it is not supported by this backend. + + Closes #8065 + +- [Jun Tseng brought this change] + + curl_easy_unescape.3: call curl_easy_cleanup in example + + Closes #8097 + +- [Jun Tseng brought this change] + + curl_easy_escape.3: call curl_easy_cleanup in example + + Closes #8097 + +- tool_listhelp: sync + + Follow-up to 172068b76f + +- [Damien Walsh brought this change] + + request.d: refer to 'method' rather than 'command' + + Closes #8094 + +- RELEASE-NOTES: synced + +- writeout: fix %{http_version} for HTTP/3 + + Output "3" properly when HTTP/3 was used. + + Reported-by: Bernat Mut + Fixes #8072 + Closes #8092 + +- urlapi: accept port number zero + + This is a regression since 7.62.0 (fb30ac5a2d). + + Updated test 1560 accordingly + + Reported-by: Brad Fitzpatrick + Fixes #8090 + Closes #8091 + +- [Mark Dodgson brought this change] + + lift: ignore is a deprecated config option, use ignoreRules + + Closes #8082 + +- [Alessandro Ghedini brought this change] + + HTTP3: update quiche build instructions + + The repo repo was re-organized a bit, so the build instructions need to + be updated. + + Closes #8076 + +- CURLMOPT_TIMERFUNCTION.3: call it expire time, not interval + + Since we say it is a non-repating timer + +- [Florian Van Heghe brought this change] + + mbedTLS: include NULL byte in blob data length for CURLOPT_CAINFO_BLOB + + Fixes #8079 + Closes #8081 + +Jay Satiro (2 Dec 2021) +- [Wyatt O'Day brought this change] + + version_win32: Check build number and platform id + + Prior to this change the build number was not checked during version + comparison, and the platform id was supposed to be checked but wasn't. + + Checking the build number is required for enabling "evergreen" + Windows 10/11 features (like TLS 1.3). + + Ref: https://github.com/curl/curl/pull/7784 + + Closes https://github.com/curl/curl/pull/7824 + Closes https://github.com/curl/curl/pull/7867 + +- libssh2: fix error message for sha256 mismatch + + - On mismatch error show sha256 fingerprint in base64 format. + + Prior to this change the fingerprint was mistakenly printed in binary. + +Daniel Stenberg (1 Dec 2021) +- [x2018 brought this change] + + openssl: check the return value of BIO_new() + + Closes #8078 + +Dan Fandrich (30 Nov 2021) +- docs: Update the Reducing Size section + + Add many more options that can reduce the size of the binary that were + added since the last update. Update the sample minimal binary size for + version 7.80.0. + +- tests: Add some missing keywords to tests + + These are needed to skip some tests when configure options have disabled + certain features. + +Daniel Stenberg (30 Nov 2021) +- [Florian Van Heghe brought this change] + + mbedTLS: add support for CURLOPT_CAINFO_BLOB + + Closes #8071 + +- [Glenn Strauss brought this change] + + digest: compute user:realm:pass digest w/o userhash + + https://datatracker.ietf.org/doc/html/rfc7616#section-3.4.4 + ... the client MUST calculate a hash of the username after + any other hash calculation ... + + Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> + Closes #8066 + +- config.d: update documentation to match the path search + + Assisted-by: Jay Satiro + +- tool_findfile: search for a file in the homedir + + The homedir() function is now renamed into findfile() and iterates over + all the environment variables trying to access the file in question + until it finds it. Last resort is then getpwuid() if + available. Previously it would first try to find a home directory and if + that was set, insist on checking only that directory for the file. This + now returns the full file name it finds. + + The Windows specific checks are now done differently too and in this + order: + + 1 - %USERPROFILE% + 2 - %APPDATA% + 3 - %USERPROFILE%\\Application Data + + The windows order is modified to match how the Windows 10 ssh tool works + when it searches for .ssh/known_hosts. + + Reported-by: jeffrson on github + Co-authored-by: Jay Satiro + Fixes #8033 + Closes #8035 + +- docs: consistent manpage SYNOPSIS + + Make all libcurl related options use .nf (no fill) for the SYNOPSIS + section - for consistent look. roffit then renders that section using + <pre> (monospace font) in html for the website. + + Extended manpage-syntax (test 1173) with a basic check for it. + + Closes #8062 + +- RELEASE-NOTES: synced + +- [Patrick Monnerat brought this change] + + openldap: handle connect phase with a state machine + + Closes #8054 + +- docs: address proselint nits + + - avoid exclamation marks + - use consistent number of spaces after periods: one + - avoid clichés + - avoid using 'very' + + Closes #8060 + +- [Bruno Baguette brought this change] + + FAQ: typo fix : "yout" ➤ "your" + + Closes #8059 + +- [Bruno Baguette brought this change] + + docs/INSTALL.md: typo fix : added missing "get" verb + + Closes #8058 + +- insecure.d: detail its use for SFTP and SCP as well + + Closes #8056 + +Viktor Szakats (25 Nov 2021) +- Makefile.m32: rename -winssl option to -schannel and tidy up + + - accept `-schannel` as an alternative to `CFG` option `-winssl` + (latter still accepted, but deprecated) + - rename internal variable `WINSSL` to `SCHANNEL` + - make the `CFG` option evaluation shorter, without repeating the option + name + + Reviewed-by: Marcel Raad + Reviewed-by: Daniel Stenberg + Closes #8053 + +Daniel Stenberg (25 Nov 2021) +- KNOWN_BUGS: 5.6 make distclean loops forever + + Reported-by: David Bohman + Closes #7716 + +- KNOWN_BUGS: add one, remove one + + - 5.10 SMB tests fail with Python 2 + + Just use python 3. + + + 5.10 curl hangs on SMB upload over stdin + + Closes #7896 + +- urlapi: provide more detailed return codes + + Previously, the return code CURLUE_MALFORMED_INPUT was used for almost + 30 different URL format violations. This made it hard for users to + understand why a particular URL was not acceptable. Since the API cannot + point out a specific position within the URL for the problem, this now + instead introduces a number of additional and more fine-grained error + codes to allow the API to return more exactly in what "part" or section + of the URL a problem was detected. + + Also bug-fixes curl_url_get() with CURLUPART_ZONEID, which previously + returned CURLUE_OK even if no zoneid existed. + + Test cases in 1560 have been adjusted and extended. Tests 1538 and 1559 + have been updated. + + Updated libcurl-errors.3 and curl_url_strerror() accordingly. + + Closes #8049 + +- urlapi: make Curl_is_absolute_url always use MAX_SCHEME_LEN + + Instad of having all callers pass in the maximum length, always use + it. The passed in length is instead used only as the length of the + target buffer for to storing the scheme name in, if used. + + Added the scheme max length restriction to the curl_url_set.3 man page. + + Follow-up to 45bcb2eaa78c79 + + Closes #8047 + +- [Jay Satiro brought this change] + + cmake: warn on use of the now deprecated symbols + + Follow-up to 9108da2c26d + + Closes #8052 + +- [Kevin Burke brought this change] + + tests/CI.md: add more information on CI environments + + Fixes #8012 + Closes #8022 + +- cmake: private identifiers use CURL_ instead of CMAKE_ prefix + + Since the 'CMAKE_' prefix is reserved for cmake's own private use. + Ref: https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html + + Reported-by: Boris Rasin + Fixes #7988 + Closes #8044 + +- urlapi: reject short file URLs + + file URLs that are 6 bytes or shorter are not complete. Return + CURLUE_MALFORMED_INPUT for those. Extended test 1560 to verify. + + Triggered by #8041 + Closes #8042 + +- curl: improve error message for --head with -J + + ... it now focuses on the "output of headers" combined with the + --remote-header-name option, as that is actually the problem. Both + --head and --include can output headers. + + Reported-by: nimaje on github + Fixes #7987 + Closes #8045 + +- RELEASE-NOTES: synced + +- [Stefan Eissing brought this change] + + urlapi: cleanup scheme parsing + + Makea Curl_is_absolute_url() always leave a defined 'buf' and avoids + copying on urls that do not start with a scheme. + + Closes #8043 + +- tool_operate: only set SSH related libcurl options for SSH URLs + + For example, this avoids trying to find and set the known_hosts file (or + warn for its absence) if SFTP or SCP are not used. + + Closes #8040 + +- [Jacob Hoffman-Andrews brought this change] + + rustls: remove comment about checking handshaking + + The comment is incorrect in two ways: + - It says the check needs to be last, but the check is actually first. + - is_handshaking actually starts out true. + + Closes #8038 + +Marcel Raad (20 Nov 2021) +- openssl: use non-deprecated API to read key parameters + + With OpenSSL 3.0, the parameters are read directly from the `EVP_PKEY` + using `EVP_PKEY_get_bn_param`. + + Closes https://github.com/curl/curl/pull/7893 + +- openssl: reduce code duplication + + `BN_print`'s `BIGNUM` parameter has been `const` since OpenSSL 0.9.4. + + Closes https://github.com/curl/curl/pull/7893 + +- openssl: remove `RSA_METHOD_FLAG_NO_CHECK` handling if unavailable + + The flag has been deprecated without replacement in OpenSSL 3.0. + + Closes https://github.com/curl/curl/pull/7893 + +- openssl: remove usage of deprecated `SSL_get_peer_certificate` + + The function name was changed to `SSL_get1_peer_certificate` in OpenSSL + 3.0. + + Closes https://github.com/curl/curl/pull/7893 + +Daniel Stenberg (19 Nov 2021) +- page-footer: fix typo + + Closes #8036 + +- http: enable haproxy support for hyper backend + + This is done by having native code do the haproxy header output before + hyper issues its request. The little downside with this approach is that + we need the entire Curl_buffer_send() function built, which is otherwise + not used for hyper builds. + + If hyper ends up getting native support for the haproxy protocols we can + backpedal on this. + + Enables test 1455 and 1456 + + Closes #8034 + +- [Bernhard Walle brought this change] + + configure: fix runtime-lib detection on macOS + + With a non-standard installation of openssl we get this error: + + checking run-time libs availability... failed + configure: error: one or more libs available at link-time are not available run-time. Libs used at link-time: -lnghttp2 -lssl -lcrypto -lssl -lcrypto -lz + + There's already code to set LD_LIBRARY_PATH on Linux, so set + DYLD_LIBRARY_PATH equivalent on macOS. + + Closes #8028 + +- [Don J Olmstead brought this change] + + cmake: don't set _USRDLL on a static Windows build + + Closes #8030 + +- page-footer: document more environment variables + + ... that curl might use. + + Closes #8027 + +- netrc.d: edit the .netrc example to look nicer + + Works nicely thanks to d1828b470f43d + + Closes #8025 + +- tftp: mark protocol as not possible to do over CONNECT + + ... and make connect_init() refusing trying to tunnel protocols marked + as not working. Avoids a double-free. + + Reported-by: Even Rouault + Fixes #8018 + Closes #8020 + +- docs/cmdline-opts: do not say "protocols: all" + + Remove the lines saying "protocols: all". It makes the output in the + manpage look funny, and the expectation is probably by default that if + not anything is mentioned about protocols the option apply to them all. + + Closes #8021 + +- curl.1: require "see also" for every documented option + + gen.pl now generates a warning if the "See Also" field is not filled in for a + command line option + + All command line options now provide one or more related options. 167 + "See alsos" added! + + Closes #8019 + +- insecure.d: expand and clarify + + Closes #8017 + +- gen.pl: improve example output format + + Treat consecutive lines that start with a space to be "examples". They + are output enclosed by .nf and .fi + + Updated form.d to use this new fanciness + + Closes #8016 + +- Revert "form-escape.d: double the back-slashes for proper man page output" + + This reverts commit a2d8eac04a4eb1d5a98cf24b4e5cec5cec565d27. + + silly me, it was intended to be one backslash! + +- form-escape.d: double the back-slashes for proper man page output + +- page-footer: add a mention of how to report bugs to the man page + +- RELEASE-NOTES: synced + + and bump to 7.81.0-DEV + +- [Patrick Monnerat brought this change] + + mime: use percent-escaping for multipart form field and file names + + Until now, form field and file names where escaped using the + backslash-escaping algorithm defined for multipart mails. This commit + replaces this with the percent-escaping method for URLs. + + As this may introduce incompatibilities with server-side applications, a + new libcurl option CURLOPT_MIME_OPTIONS with bitmask + CURLMIMEOPT_FORMESCAPE is introduced to revert to legacy use of + backslash-escaping. This is controlled by new cli tool option + --form-escape. + + New tests and documentation are provided for this feature. + + Reported by: Ryan Sleevi + Fixes #7789 + Closes #7805 + +- [Kevin Burke brought this change] + + zuul.d: update rustls-ffi to version 0.8.2 + + This version fixes errors with ALPN negotiation in rustls, which is + necessary for HTTP/2 support. For more information see the rustls-ffi + changelog. + + Closes #8013 + +- configure: better diagnostics if hyper is built wrong + + If hyper is indeed present in the specified directory but couldn't be + used to find the correct symbol, then offer a different error message to + better help the user understand the issue. + + Suggested-by: Jacob Hoffman-Andrews + Fixes #8001 + Closes #8005 + +- test1939: require proxy support to run + + Follow-up to f0b7099a10d1a + + Closes #8011 + +- test302[12]: run only with the libssh2 backend + + ... as the others don't support --hostpubsha256 + + Reported-by: Paul Howarth + Fixes #8009 + Closes #8010 + +- runtests: make the SSH library a testable feature + + libssh2, libssh and wolfssh + +- [Jacob Hoffman-Andrews brought this change] + + rustls: read of zero bytes might be okay + + When we're reading out plaintext from rustls' internal buffers, we might + get a read of zero bytes (meaning a clean TCP close, including + close_notify). However, we shouldn't return immediately when that + happens, since we may have already copied out some plaintext bytes. + Break out of the loop when we get a read of zero bytes, and figure out + which path we're dealing with. + + Acked-by: Kevin Burke + + Closes #8003 + +- [Jacob Hoffman-Andrews brought this change] + + rustls: remove incorrect EOF check + + The update to rustls-ffi 0.8.0 changed handling of EOF and close_notify. + From the CHANGELOG: + + > Handling of unclean close and the close_notify TLS alert. Mirroring + > upstream changes, a rustls_connection now tracks TCP closed state like + > so: rustls_connection_read_tls considers a 0-length read from its + > callback to mean "TCP stream was closed by peer." If that happens + > before the peer sent close_notify, rustls_connection_read will return + > RUSTLS_RESULT_UNEXPECTED_EOF once the available plaintext bytes are + > exhausted. This is useful to protect against truncation attacks. Note: + > some TLS implementations don't send close_notify. If you are already + > getting length information from your protocol (e.g. Content-Length in + > HTTP) you may choose to ignore UNEXPECTED_EOF so long as the number of + > plaintext bytes was as expected. + + That means we don't need to check for unclean EOF in `cr_recv()`, + because `process_new_packets()` will give us an error if appropriate. + + Closes #8003 + +- lib1939: make it endure torture tests + + Follow-up to f0b7099a10d1a + + Closes #8007 + +- azure: make the "w/o HTTP/SMTP/IMAP" build disable SSL proper + + The configure line would previously depend on a configure mistake using + --without-openssl that is fixed and now this configure line needs + adjusting to use --without-ssl. + + Follow-up to b589696f0312d + + Closes #8006 + +- [Jacob Hoffman-Andrews brought this change] + + configure: add -lm to configure for rustls build. + + Note: The list of libraries that rustc tells us we need to include is + longer, but also includes some more platform-specific libraries that I + am not sure how to effectively incorporate. Adding just -lm seems to + solve an immediate problem, so I'm adding just that. + + Closes #8002 + +- curl_share_setopt.3: refer to CURLSHOPT_USERDATA(3) properly + +- curl_share_setopt.3: split out options into their own manpages + + CURLSHOPT_LOCKFUNC.3 + CURLSHOPT_SHARE.3 + CURLSHOPT_UNLOCKFUNC.3 + CURLSHOPT_UNSHARE.3 + CURLSHOPT_USERDATA.3 + + Closes #7998 + +- http_proxy: make Curl_connect_done() work for proxy disabled builds + + ... by making it an empty macro then. + + Follow-up to f0b7099a10d1a + Reported-by: Vincent Grande + Fixes #7995 + Closes #7996 + +- Curl_connect_done: handle being called twice + + Follow-up to f0b7099a10d1a7c + + When torture testing 1021, it turns out the Curl_connect_done function + might be called twice and that previously then wrongly cleared the HTTP + pointer in the second invoke. + + Closes #7999 + +- [Stan Hu brought this change] + + configure: don't enable TLS when --without-* flags are used + + Previously specifying `--without-gnutls` would unexpectedly attempt to + compile with GnuTLS, effectively interpreting this as + `--with-gnutls`. This caused a significant amount of confusion when + `libcurl` was built with SSL disabled since GnuTLS wasn't present. + + 68d89f24 dropped the `--without-*` options from the configure help, but + `AC_ARG_WITH` still defines these flags automatically. As + https://www.gnu.org/software/autoconf/manual/autoconf-2.60/html_node/External-Software.html + describes, the `action-if-given` is called when the user specifies + `--with-*` or `--without-*` options. + + To prevent this confusion, we make the `--without` flag do the right + thing by ignoring the value if it set to "no". + + Closes #7994 + +- [Rikard Falkeborn brought this change] + + docs/checksrc: Add documentation for STRERROR + + Closes #7991 + +- vtls/rustls: adapt to the updated rustls_version proto + + Closes #7956 + +- [Kevin Burke brought this change] + + vtls/rustls: handle RUSTLS_RESULT_PLAINTEXT_EMPTY + + Previously we'd return CURLE_READ_ERROR if we received this, instead + of triggering the error handling logic that's present in the next if + block down. + + After this change, curl requests to https://go.googlesource.com using + HTTP/2 complete successfully. + + Fixes #7949 + Closes #7948 + +- [Kevin Burke brought this change] + + zuul: update build environment for rustls-ffi 0.8.0 + +- [Kevin Burke brought this change] + + vtls/rustls: update to compile with rustls-ffi v0.8.0 + + Some method names, as well as the generated library name, were changed + in a recent refactoring. + + Further, change the default configuration instructions to check for + Hyper in either "target/debug" or "target/release" - the latter + contains an optimized build configuration. + + Fixes #7947 + Closes #7948 + +- RELEASE-NOTES: synced + + and bump the version to 7.80.1 + +- multi: shut down CONNECT in Curl_detach_connnection + + ... to prevent a lingering pointer that would lead to a double-free. + + Added test 1939 to verify. + + Reported-by: Stephen M. Coakley + Fixes #7982 + Closes #7986 + +- curl_easy_cleanup.3: remove from multi handle first + + Easy handles that are used by the multi interface should be removed from + the multi handle before they are cleaned up. + + Reported-by: Stephen M. Coakley + Ref: #7982 + Closes #7983 + +- url.c: fix the SIGPIPE comment for Curl_close + + Closes #7984 + Version 7.80.0 (10 Nov 2021) Daniel Stenberg (10 Nov 2021) @@ -6569,1732 +7938,3 @@ Daniel Stenberg (22 Apr 2021) - configure: split out each TLS library detector into its own function ... and put those functions in separate m4 files per TLS library. - -- configure: make the TLS library choice(s) explicit - - configure no longer tries to find a TLS library by default, but all - libraries are now equal: the user needs to explicitly ask what TLS - library or libraries to use. - - If no TLS library is selected, configure will error out unless - --without-ssl is explicitly used to request a built without TLS (as that - is very rare these days). - - Removes: --with-winssl, --with-darwinssl and all --without-* options for - TLS libraries. - - Closes #6897 - -- tests/disable-scan.pl: also scan all m4 files - - Fixes test 1165 when functions are moved from configure.ac to files in - m4/ - -Jay Satiro (22 Apr 2021) -- schannel: Disable auto credentials; add an option to enable it - - - Disable auto credentials by default. This is a breaking change - for clients that are using it, wittingly or not. - - - New libcurl ssl option value CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl - to automatically locate and use a client certificate for - authentication, when requested by the server. - - - New curl tool options --ssl-auto-client-cert and - --proxy-ssl-auto-client-cert map to CURLSSLOPT_AUTO_CLIENT_CERT. - - This option is only supported for Schannel (the native Windows SSL - library). Prior to this change Schannel would, with no notification to - the client, attempt to locate a client certificate and send it to the - server, when requested by the server. Since the server can request any - certificate that supports client authentication in the OS certificate - store it could be a privacy violation and unexpected. - - Fixes https://github.com/curl/curl/issues/2262 - Reported-by: Jeroen Ooms - Assisted-by: Wes Hinsley - Assisted-by: Rich FitzJohn - - Ref: https://curl.se/mail/lib-2021-02/0066.html - Reported-by: Morten Minde Neergaard - - Closes https://github.com/curl/curl/pull/6673 - -Daniel Stenberg (22 Apr 2021) -- [Michał Antoniak brought this change] - - vtls: deduplicate some DISABLE_PROXY ifdefs - - continue from #5735 - - - using SSL_HOST_NAME, SSL_HOST_DISPNAME, SSL_PINNED_PUB_KEY for other - tls backend - - - create SSL_HOST_PORT - - Closes #6660 - -Jay Satiro (22 Apr 2021) -- OS400: fix typo - - CURLVERSION_HEIGHTH -> CURLVERSION_EIGHTH - -Daniel Stenberg (22 Apr 2021) -- checksrc: complain on == NULL or != 0 checks in conditions - - ... to make them all consistenly use if(!var) and if(var) - - Also added a few missing warnings to the documentation. - - Closes #6912 - -- tidy-up: make conditional checks more consistent - - ... remove '== NULL' and '!= 0' - - Closes #6912 - -- [Patrick Monnerat brought this change] - - vauth: factor base64 conversions out of authentication procedures - - Input challenges and returned messages are now in binary. - Conversions from/to base64 are performed by callers (currently curl_sasl.c - and http_ntlm.c). - - Closes #6654 - -- [Patrick Monnerat brought this change] - - bufref: buffer reference support - - A struct bufref holds a buffer pointer, a data size and a destructor. - When freed or its contents are changed, the previous buffer is implicitly - released by the associated destructor. The data size, although not used - internally, allows binary data support. - - A unit test checks its handling methods: test 1661 - - Closes #6654 - -- [Patrick Monnerat brought this change] - - os400: additional support for options metadata - - New functions curl_easy_option_by_name_ccsid() and - curl_easy_option_get_name_ccsid() allows accessing metadata in alternate - character encoding. - - This commit also updates curl_version_info_ccsid() to handle info version 9 - and adds recent definitions to the ILE/RPG include file. - - Documentation updated accordingly. - - Reviewed-by: Jon Rumsey - Closes #6574 - -- [Patrick Monnerat brought this change] - - test server: take care of siginterrupt() deprecation - - Closes #6529 - -Marc Hoersken (21 Apr 2021) -- lib1564.c: enable last wakeup test part on Windows - - Suggested-by: Gergely Nagy - Reviewed-by: Jay Satiro - Reviewed-by: Marcel Raad - - Closes #6245 - -- multi: fix slow write/upload performance on Windows - - Reset FD_WRITE by sending zero bytes which is permissible - and will be treated by implementations as successful send. - - Without this we won't be notified in case a socket is still - writable if we already received such a notification and did - not send any data afterwards on the socket. This would lead - to waiting forever on a writable socket being writable again. - - Assisted-by: Tommy Odom - Reviewed-by: Jay Satiro - Reviewed-by: Marcel Raad - Tested-by: tmkk on github - - Bug: #6146 - Closes #6245 - -- multi: reduce Win32 API calls to improve performance - - 1. Consolidate pre-checks into a single Curl_poll call: - - This is an attempt to restructure the code in Curl_multi_wait - in such a way that less syscalls are made by removing individual - calls to Curl_socket_check via SOCKET_READABLE/SOCKET_WRITABLE. - - 2. Avoid resetting the WinSock event multiple times: - - We finally call WSAResetEvent anyway, so specifying it as - an optional parameter to WSAEnumNetworkEvents is redundant. - - 3. Wakeup directly in case no sockets are being monitoring: - - Fix the WinSock based implementation to skip extra waiting by - not sleeping in case no sockets are to be waited on and just - the WinSock event is being monitored for wakeup functionality. - - Assisted-by: Tommy Odom - Reviewed-by: Jay Satiro - Reviewed-by: Marcel Raad - - Bug: #6146 - Closes #6245 - -- Revert "Revert 'multi: implement wait using winsock events'" - - This reverts commit 2260e0ebe6d45529495231b3e37a0c58fb92a6a2, - also restoring previous follow up changes which were reverted. - - Authored-by: rcombs on github - Authored-by: Marc Hörsken - Reviewed-by: Jay Satiro - Reviewed-by: Marcel Raad - - Restores #5634 - Reverts #6281 - Part of #6245 - -Daniel Stenberg (21 Apr 2021) -- Revert "cmake: make libcurl library output name configurable" - - This reverts commit 1cba36d2166c396f987eea587cf92671b27acb92. - - CMake provides properties that can be set on a target to rename the - output artifact without changing the name of a target. - - Ref: #6899 - -- [Michael Kolechkin brought this change] - - sectransp: allow cipher name to be specified - - Add parser for CURLOPT_SSL_CIPHER_LIST option for Secure Transport (ST) - back-end. Similar to NSS and GSKit back-ends, new code parses string - value and configures ST library to use those ciphers for communication. - Create cipher spec data structure and initialize the array of specs with - cipher number, name, alias, and 'weak' flag. - - Mark triple-DES ciphers as 'weak', and exclude them from the default - ciphers list. - - Closes #6464 - -- [Michael Kolechkin brought this change] - - NSS: add ciphers to map - - Add cipher names to the `cipherlist` map, based on the list of ciphers - implemented by the NSS in the source code file - https://github.com/nss-dev/nss/blob/master/lib/ssl/sslenum.c - - Closes #6670 - -- http2: remove DEBUG_HTTP2 - - Accidentally committed in 605e84235 - -- [Ralph Langendam brought this change] - - cmake: make libcurl library output name configurable - - Closes #6899 - -- sws: #ifdef S_IFSOCK use - - SCO OpenServer 5.0.7 does not define S_IFSOCK. - - Reported-by: Kevin R. Bulgrien - Bug: https://curl.se/mail/lib-2021-04/0074.html - Closes #6926 - -- curl_setup: provide the shutdown flags wider - - By using #ifdef on the symbol names to work on anything that don't - provide them. SCO OpenServer 5.0.7, sys/socket.h does not define either - SHUT_RDWR, SHUT_RD, and SHUT_WR. - - Reported-by: Kevin R. Bulgrien - Bug: https://curl.se/mail/lib-2021-04/0073.html - Closes #6925 - -- connect: use CURL_SA_FAMILY_T for portability - - Reported-by: Kevin R. Bulgrien - Bug: https://curl.se/mail/lib-2021-04/0071.html - - Closes #6918 - -- urlapi: make sure no +/- signs are accepted in IPv4 numericals - - Follow-up to 56a037cc0ad1b2. Extends test 1560 to verify. - - Reported-by: Tuomas Siipola - Fixes #6916 - Closes #6917 - -- ConnectionExists: respect requests for h1 connections better - - ... for situations when multiplexing isn't enabled on the h2 connection - and h1 is explicitly requested for the transfer. - - Assisted-by: Gergely Nagy - -- multi: don't close connection HTTP_1_1_REQUIRED - - The ConnectionExists() function will note that the new transfer wants - less then h2 and that it can't multiplex it and therefor opt to open a - new connection instead. - -- http2: move the stream error field to the per-transfer storage - - Storing a stream error in the per-connection struct was an error that lead to - race conditions as subsequent stream handling could overwrite the error code - before it was used for the stream with the actual problem. - - Closes #6910 - -- http2: call the handle-closed function correctly on closed stream - - This was this one condition where the stream could be closed due to an - error and the function would still wrongly just return 0 for it. - - Reported-by: Gergely Nagy - Fixes #6862 - Closes #6910 - -- test1660: check the created HSTS file as text mode - - Closes #6922 - -- RELEASE-NOTES: synced - -- test 493: require https in curl to run - - Closes #6927 - -Jay Satiro (20 Apr 2021) -- tool_operate: don't discard failed parallel transfer result - - - Save a parallel transfer's result code only when it fails and the - transfer is not being retried. - - Prior to this change the result code was always set which meant that a - failed result could be erroneously discarded if a different transfer - later had a successful result (CURLE_OK). - - Before: - - > curl --fail -Z https://httpbin.org/status/404 https://httpbin.org/delay/10 - > echo %ERRORLEVEL% - 0 - - After: - - > curl --fail -Z https://httpbin.org/status/404 https://httpbin.org/delay/10 - > echo %ERRORLEVEL% - 22 - - Closes #xxxx - -- [Georeth Zhou brought this change] - - openssl: fix build error with OpenSSL < 1.0.2 - - Closes https://github.com/curl/curl/pull/6920 - -Viktor Szakats (19 Apr 2021) -- README.md: delete Codacy UTM parameters & follow permanent redirect [ci skip] - - UTM parameters leak referrer and various marketing/tracking information - even if these would normally be stripped by website or client policy. - This link also works fine without them. Also took the opportunity to - update the URL to the one pointed to by the previous one via permanent - redirect. - - Reviewed-by: Daniel Stenberg - Closes #6919 - -Daniel Stenberg (19 Apr 2021) -- urlapi: "normalize" numerical IPv4 host names - - When the host name in a URL is given as an IPv4 numerical address, the - address can be specified with dotted numericals in four different ways: - a32, a.b24, a.b.c16 or a.b.c.d and each part can be specified in - decimal, octal (0-prefixed) or hexadecimal (0x-prefixed). - - Instead of passing on the name as-is and leaving the handling to the - underlying name functions, which made them not work with c-ares but work - with getaddrinfo, this change now makes the curl URL API itself detect - and "normalize" host names specified as IPv4 numericals. - - The WHATWG URL Spec says this is an okay way to specify a host name in a - URL. RFC 3896 does not allow them, but curl didn't prevent them before - and it seems other RFC 3896-using tools have not either. Host names used - like this are widely supported by other tools as well due to the - handling being done by getaddrinfo and friends. - - I decided to add the functionality into the URL API itself so that all - users of these functions get the benefits, when for example wanting to - compare two URLs. Also, it makes curl built to use c-ares now support - them as well and make curl builds more consistent. - - The normalization makes HTTPS and virtual hosted HTTP work fine even - when curl gets the address specified using one of the "obscure" formats. - - Test 1560 is extended to verify. - - Fixes #6863 - Closes #6871 - -- libssh: fix "empty expression statement has no effect" warnings - - ... by fixing macros to do-while constructs and moving out the calls to - "break" outside of the actual macro. It also fixes the problem where the - macro was used witin a loop and the break didn't do right. - - Reported-by: Emil Engler - Fixes #6847 - Closes #6909 - -- hsts: enable by default - - No longer considered experimental. - - Closes #6700 - -- vtls: refuse setting any SSL version - - ... previously they were supported if a TLS library would (unexpectedly) - still support them, but from this change they will be refused already in - curl_easy_setopt(). SSLv2 and SSLv3 have been known to be insecure for - many years now. - - Closes #6773 - -- curl: ignore options asking for SSLv2 or SSLv3 - - Instead output a warning about it and continue with the defaults. - - These SSL versions are typically not supported by the TLS libraries since a - long time back already since they are inherently insecure and broken. Asking - for them to be used will just cause an error to be returned slightly later. - - In the unlikely event that a user's TLS library actually still supports these - protocol versions, this change might make the request a little less insecure. - - Closes #6772 - -- test972: verify the json output with jsonlint - - Make sure one of the azure jobs has jsonlint installed so that the test - runs there. - - Ref: #6905 - -- [Jay Satiro brought this change] - - tool_writeout: fix the HTTP_CODE json output - - Update test 970 accordingly. - - Reported-by: Michal Rus - Fixes #6905 - Closes #6906 - -- openldap: protect SSL-specific code with proper #ifdef - - Closes #6901 - -- libssh2: fix Value stored to 'sshp' is never read - - Pointed out by scan-build - - Closes #6900 - -- [Victor Vieux brought this change] - - tool_getparam: replace (in-place) '%20' by '+' according to RFC1866 - - Signed-off-by: Victor Vieux <victorvieux@gmail.com> - - Closes #6895 - -- configure: provide --with-openssl, deprecate --with-ssl - - Makes the option more explicit. - - Closes #6887 - -- RELEASE-NOTES: synced - - and bumped curlver to 7.77.0 - -- [Javier Blazquez brought this change] - - rustls: only return CURLE_AGAIN when TLS session is fully drained - - The code in cr_recv was returning prematurely as soon as the socket - reported no more data to read. However, this could be leaving some - unread plaintext data in the rustls session from a previous call, - causing causing the transfer to hang if the socket never receives - further data. - - We need to ensure that the session is fully drained of plaintext data - before returning CURLE_AGAIN to the caller. - - Reviewed-by: Jacob Hoffman-Andrews - Closes #6894 - -- cookie: CURLOPT_COOKIEFILE set to NULL switches off cookies - - Add test 676 to verify that setting CURLOPT_COOKIEFILE to NULL again clears - the cookiejar from memory. - - Reported-by: Stefan Karpinski - Fixes #6889 - Closes #6891 - -Version 7.76.1 (14 Apr 2021) - -Daniel Stenberg (14 Apr 2021) -- RELEASE-NOTES: synced - - curl 7.76.1 release - -- THANKS: add names from 7.76.1 - -- misc: update copyright year ranges to match latest updates - -- [Tatsuhiro Tsujikawa brought this change] - - ngtcp2: Use ALPN h3-29 for now - - Fixes #6864 - Cloes #6886 - -Jay Satiro (11 Apr 2021) -- TODO: remove 18.22 --fail-with-body - - --fail-with-body was added in 8a964cb (precedes curl-7_76_0). - -Daniel Stenberg (10 Apr 2021) -- [Jürgen Gmach brought this change] - - src/tool_vms.c: remove duplicated word in comment - - Closes #6881 - -- configure: fix CURL_DARWIN_CFLAGS use - - The macro name change was not completely done. - - Follow-up to 5d2c384452543c - Bug: https://github.com/curl/curl/commit/5d2c384452543c7b6c9fb02eaa0afc84fd5ab941#commitcomment-49315187 - Reported-by: Marcel Raad - Closes #6878 - -- [Anthony Shaw brought this change] - - github/workflow: add "security-extended" to codeql-analysis.yml - - Extends the CodeQL code scan. - - Closes #6815 - -- [Jochem Broekhoff brought this change] - - examples/hiperfifo.c: check event_initialized before delete - - If event_del is called with the event struct (still) zeroed out, a - segmentation fault may occur. event_initialized checks whether the - event struct is nonzero. - - Closes #6876 - -- [Patrick Monnerat brought this change] - - ntlm: fix negotiated flags usage - - According to Microsoft document MS-NLMP, current flags usage is not - accurate: flag NTLMFLAG_NEGOTIATE_NTLM2_KEY controls the use of - extended security in an NTLM authentication message and NTLM version 2 - cannot be negotiated within the protocol. - - The solution implemented here is: if the extended security flag is set, - prefer using NTLM version 2 (as a server featuring extended security - should also support version 2). If version 2 has been disabled at - compile time, use extended security. - - Tests involving NTLM are adjusted to this new behavior. - - Fixes #6813 - Closes #6849 - -- [Patrick Monnerat brought this change] - - ntlm: support version 2 on 32-bit platforms - - Closes #6849 - -- [Patrick Monnerat brought this change] - - curl_ntlm_core.h: simplify conditionals for USE_NTLM2SESSION - - ... as !defined(CURL_DISABLE_CRYPTO_AUTH) is a prerequisite for the - whole NTLM. - - Closes #6849 - -- lib: remove unused HAVE_INET_NTOA_R* defines - - Closes #6867 - -- [Michael Forney brought this change] - - configure: include <time.h> unconditionally - - In 2682e5f5, several instances of AC_HEADER_TIME were removed since - it is a deprecated autoconf macro. However, this was the macro that - defined TIME_WITH_SYS_TIME, which was used to indicate that <time.h> - can be included alongside <sys/time.h>. TIME_WITH_SYS_TIME is still - used in the configure test body and since it is no longer defined, - <time.h> is *not* included on systems that have <sys/time.h>. - - In particular, at least on musl libc and glibc, <sys/time.h> does - not implicitly include <time.h> and does not declare clock_gettime, - gmtime_r, or localtime_r. This causes configure to fail to detect - those functions. - - The AC_HEADER_TIME macro deprecation text says - - > All current systems provide time.h; it need not be checked for. - > Not all systems provide sys/time.h, but those that do, all allow - > you to include it and time.h simultaneously. - - So, to fix this issue, simply include <time.h> unconditionally when - testing for time-related functions and in libcurl, and don't bother - checking for it. - - Closes #6859 - -- [Michael Forney brought this change] - - configure: remove use of RETSIGTYPE - - This was previously defined by the obsolete AC_TYPE_SIGNAL macro, - which was removed in 2682e5f5. The deprecation text says - - > Your code may safely assume C89 semantics that RETSIGTYPE is void. - - So, remove it and just use void instead. - - Closes #6861 - -- [Muhammed Yavuz Nuzumlalı brought this change] - - install: add instructions for Apple Darwin platforms - - Closes #6860 - -- [Muhammed Yavuz Nuzumlalı brought this change] - - configure: disable min version set for Darwin - - Fixes #6838 - Closes #6860 - -- [David Hu brought this change] - - docs/HTTP3.md: update the build instruction using gnutls - - In ngtcp2 the `with-gnutls` option is disabled by default, which will - cause `curl` unable to be `make` because of lacking the libraries - needed. - - Closes #6857 - -- RELEASE-NOTES: synced - -- typecheck-gcc: make the ssl-ctx-cb check use SSL_CTX pointers - - ... and not values. - - Reported-by: locpyl-tidnyd on github - Fixes #6818 - Closes #6819 - -- ngtcp2+gnutls: clear credentials when freed - - ... to avoid double-free. - - Reported-by: Kenneth Davidson - Fixes #6824 - Closes #6856 - -Jay Satiro (5 Apr 2021) -- [Cherish98 brought this change] - - tool_progress: Fix progress meter in parallel mode - - Make sure the total amount of DL/UL bytes are counted before the - transfer finalizes. Otherwise if a transfer finishes too quick, its - total numbers are not added, and results in a DL%/UL% that goes above - 100%. - - Detail: - - progress_meter() is called periodically, and it may not catch a - transfer's total bytes if the value was unknown during the last call, - and the transfer is finished and deleted (i.e., lost) during the next - call. - - Closes https://github.com/curl/curl/pull/6840 - -- [Emil Engler brought this change] - - libssh: get rid of PATH_MAX - - This removes the last occurrence of PATH_MAX inside our libssh - implementation by calculating the path length from the string length of - the two components. - - Closes #6829 - -Daniel Stenberg (5 Apr 2021) -- http_proxy: only loop on 407 + close if we have credentials - - ... to fix the retry-loop. - - Add test 718 to verify. - - Reported-by: Daniel Kurečka - Fixes #6828 - Closes #6850 - -- h2: allow 100 streams by default - - instead of 13, before the server has told how many streams it - accepts. The server can always reject new streams anyway if we go above - what it accepts. - - Ref: #6826 - Closes #6852 - -- [Luke Granger-Brown brought this change] - - file: support GETing directories again - - After 957bc1881e686f9714c4e6a01bf33535091f0e21, we no longer compute an - expected_size for directories. This has the upshot that when we compare - even an empty Range with the available size, we fail. - - This brings back the previous behaviour, which was to succeed, but with - empty content. This also removes the "Accept-ranges: bytes" header, - which is nonsensical on directories. - - Adds test 3016 - Fixes #6845 - Closes #6846 - -- RELEASE-NOTES: synced - - and bumped to 7.76.1 - -- TLS: fix HTTP/2 selection - - for GnuTLS, BearSSL, mbedTLS, NSS, SChannnel, Secure Transport and - wolfSSL... - - Regression since 88dd1a8a115b1f5ece (shipped in 7.76.0) - Reported-by: Kenneth Davidson - Reported-by: romamik om github - Fixes #6825 - Closes #6827 - -Jay Satiro (2 Apr 2021) -- hostip: Fix for builds that disable all asynchronous DNS - - - Define Curl_resolver_error function only when USE_CURL_ASYNC. - - Prior to this change building curl without an asynchronous resolver - backend (c-ares or threaded) and without DoH (DNS-over-HTTPS, which is - also asynchronous but independent of resolver backend) would cause a - build error since Curl_resolver_error is called by and evaluates - variables only available in asynchronous builds. - - Reported-by: Benbuck Nason - - Fixes https://github.com/curl/curl/issues/6831 - Closes https://github.com/curl/curl/pull/6832 - -Daniel Stenberg (31 Mar 2021) -- [Gilles Vollant brought this change] - - openssl: Fix CURLOPT_SSLCERT_BLOB without CURLOPT_SSLCERT_KEY - - Reported-by: Christian Schmitz - Fixes #6816 - Closes #6820 - -Version 7.76.0 (31 Mar 2021) - -Daniel Stenberg (31 Mar 2021) -- RELEASE-NOTES: synced - - curl 7.76.0 release - -- THANKS: added names from 7.76.0 - -- CURLOPT_AUTOREFERER.3: clarify that it sets the full URL - - ... some users may not want that! - -- define: remove CURL_DISABLE_NTLM ifdefs - - It was never defined anywhere. Fixed disable-scan (test 1165) to also - scan headers, which found this issue. - - Closes #6809 - -- vtls: fix addsessionid for non-proxy builds - - Follow-up to b09c8ee15771c61 - Fixes #6812 - Closes #6811 - -- [Li Xinwei brought this change] - - cmake: support WinIDN - - Closes #6807 - -- transfer: clear 'referer' in declaration - - To silence (false positive) compiler warnings about it. - - Follow-up to 7214288898f5625 - - Reviewed-by: Marcel Raad - Closes #6810 - -- [Marc Hoersken brought this change] - - config: fix SSPI enabling NTLM if crypto auth is disabled - - Avoid enabling NTLM feature based upon Windows SSPI - being enabled in case that crypto auth is disabled. - - Reported-by: Marcel Raad - - Follow-up to #6277 - Fixes #6803 - Closes #6808 - -- HISTORY: add two 2021 events - -- vtls: add 'isproxy' argument to Curl_ssl_get/addsessionid() - - To make sure we set and extract the correct session. - - Reported-by: Mingtao Yang - Bug: https://curl.se/docs/CVE-2021-22890.html - - CVE-2021-22890 - -- [Viktor Szakats brought this change] - - transfer: strip credentials from the auto-referer header field - - Added test 2081 to verify. - - CVE-2021-22876 - - Bug: https://curl.se/docs/CVE-2021-22876.html - -- curl_sasl: fix compiler error with --disable-crypto-auth - - ... if libgsasl was found. - - Closes #6806 - -- [Patrick Monnerat brought this change] - - ldap: only set the callback ptr for TLS context when TLS is used - - Follow-up to a5eee22e594c2460f - Fixes #6804 - Closes #6805 - -- copyright: update copyright year ranges to 2021 - - Reviewed-by: Emil Engler - Closes #6802 - -- send_speed: simplify the checks for if a speed limit is set - - ... as we know the value cannot be set to negative: enforced by - setopt() - -- http: cap body data amount during send speed limiting - - By making sure never to send off more than the allowed number of bytes - per second the speed limit logic is given more room to actually work. - - Reported-by: Fabian Keil - Bug: https://curl.se/mail/lib-2021-03/0042.html - Closes #6797 - -- urldata: merge "struct DynamicStatic" into "struct UrlState" - - Both were used for the same purposes and there was no logical separation - between them. Combined, this also saves 16 bytes in less holes in my - test build. - - Closes #6798 - -- tests/README.md: mentioned that en_US.UTF-8 is required - - Reported-by: Oumph on github - Fixes #6768 - -- HISTORY: fixed the Mac OS X 10.1 release date - - Based on what Wikipedia says - -Jay Satiro (26 Mar 2021) -- examples: Remove threaded-shared-conn.c due to bug - - Known bug 11.11 is the shared object's connection cache is not thread - safe, so we should not have an example for it. - - Ref: https://github.com/curl/curl/issues/4915 - Ref: https://curl.se/docs/knownbugs.html#A_shared_connection_cache_is_not - - Closes https://github.com/curl/curl/pull/6795 - -- KNOWN_BUGS: Update 11.9 - DoH option inheritance - - - Add description: Explain that some options aren't inherited because - they are not relevant for the DoH SSL connections or may result in - unexpected behavior. - - - Remove the reference to #4578 (SSL verify options not inherited) since - that was fixed by #6597 (separate DoH-specific options for verify). - - - Explain that DoH-specific options (those created by #6597) are - available: CURLOPT_DOH_SSL_VERIFYHOST, CURLOPT_DOH_SSL_VERIFYPEER and - CURLOPT_DOH_SSL_VERIFYSTATUS. - - - Add a reference to #6605 and explain that the user's debug function is - not inherited because it would be unexpected to pass internal handles - (ie DoH handles) to the user's callback. - - Closes https://github.com/curl/curl/issues/6605 - -Daniel Stenberg (26 Mar 2021) -- curl_easy_setopt.3: add curl_easy_option* functions to SEE ALSO - -- [Jean-Philippe Menil brought this change] - - openssl: ensure to check SSL_CTX_set_alpn_protos return values - - SSL_CTX_set_alpn_protos() return 0 on success, and non-0 on failure - - Signed-off-by: Jean-Philippe Menil <jpmenil@gmail.com> - - Closes #6794 - -- multi: close the connection when h2=>h1 downgrading - - Otherwise libcurl is likely to reuse the connection again in the next - attempt since the connection reuse logic doesn't take downgrades into - account. - - Reported-by: Anthony Ramine - Fixes #6788 - Closes #6793 - -- openssl: set the transfer pointer for logging early - - Otherwise, the transfer will be NULL in the trace function when the - early handshake details arrive and then curl won't show them. - - Regresssion in 7.75.0 - - Reported-by: David Hu - Fixes #6783 - Closes #6792 - -- RELEASE-NOTES: synced - -- TODO: Custom progress meter update interval - - Ref: https://stackoverflow.com/q/66789977/93747 - -- docs/ABI: tighten up the language - - Make the promises more firm - - Closes #6786 - -- openldap: disconnect better - - Instead of clearing the callback argument in disconnect, set it to the - (new) transfer to make sure the correct data is passed to the callbacks. - - Follow-up to e467ea3bd937f38 - Assisted-by: Patrick Monnerat - Closes #6787 - -- libssh2: kdb_callback: get the right struct pointer - - After the recent conn/data refactor in this source file, this function - was mistakenly still getting the old struct pointer which would lead to - crash on servers with keyboard-interactive auth enabled. - - Follow-up to a304051620b92e12b (shipped in 7.75.0) - - Reported-by: Christian Schmitz - Fixes #6691 - Closes #6782 - -- tftp: remove unused struct fields - - Follow-up to d3d90ad9c00530d - - Closes #6781 - -- openldap: avoid NULL pointer dereferences - - Follow-up to a59c33ceffb8f78 - Reported-by: Patrick Monnerat - Fixes #6676 - Closes #6780 - -- http: strip default port from URL sent to proxy - - To make sure the Host: header and the URL provide the same authority - portion when sent to the proxy, strip the default port number from the - URL if one was provided. - - Reported-by: Michael Brown - Fixes #6769 - Closes #6778 - -- azure: disable test 433 on azure-ubuntu - - Something in that environment sets XDG_CONFIG_HOME for us in a way that - breaks the test. - - Reported-by: Marc Hörsken - Fixes #6739 - Closes #6777 - -- tftp: remove the 3600 second default timeout - - ... it was never meant to be there. - - Reported-by: Tomas Berger - Fixes #6774 - Closes #6776 - -- docs: make gen.pl support *italic* and **bold** - - Remove some nroffisms from the cmdline doc files to simplify editing, - and instead support this markdown style. - - Closes #6771 - -- ngtcp2: sync with recent API updates - - Closes #6770 - -- RELEASE-NOTES: synced - -- libssh2:ssh_connect: clear session pointer after free - - If libssh2_knownhost_init() returns NULL, like in an OOM situation, the - ssh session was freed but the pointer wasn't cleared which made libcurl - later call libssh2 to cleanup using the stale pointer. - - Fixes #6764 - Closes #6766 - -- [Jacob Hoffman-Andrews brought this change] - - docs: document version of crustls dependency - - This also pins a specific release in the Travis test so future - API-breaking changins in crustls won't break curl builds. - - Add RUSTLS documentation to release tarball. - - Enable running tests for rustls, minus FTP tests (require - connect_blocking, which rustls doesn't implement) and 313 (requires CRL - handling). - - Closes #6763 - -- [Jacob Hoffman-Andrews brought this change] - - rustls: Handle close_notify. - - If we get a close_notify, treat that as EOF. If we get an EOF from the - TCP stream, treat that as an error (because we should have ended the - connection earlier, when we got a close_notify). - - Closes #6763 - -- docs: clarify timeouts for queued transfers in multi API - - Closes #6758 - -- ftpserver: only load the preprocessed test file - - We always preprocess and tests are no longer sensible to load "raw" - - Closes #6738 - -- tests: use %TESTNUMBER instead of fixed number - - This makes the tests easier to copy and relocate to other test numbers - without having to update content. - - Closes #6738 - -- KNOWN_BUGS: CURLOPT_OPENSOCKETPAIRFUNCTION is missing - - Closes #5747 - -- TODO: provide timing info for each redirect - - Closes #6743 - -Jay Satiro (17 Mar 2021) -- docs: Add SSL backend names to CURL_SSL_BACKEND - - - Document the names that can be used with CURL_SSL_BACKEND: - bearssl, gnutls, gskit, mbedtls, mesalink, nss, openssl, rustls, - schannel, secure-transport, wolfssl - - Ref: https://github.com/curl/curl/issues/2209#issuecomment-360623286 - Ref: https://github.com/curl/curl/issues/6717#issuecomment-800745201 - - Closes https://github.com/curl/curl/pull/6755 - -- docs: Explain DOH transfers inherit some SSL settings - - - Document in DOH that some SSL settings are inherited but DOH hostname - and peer verification are not and are controlled separately. - - - Document that CURLOPT_SSL_CTX_FUNCTION is inherited by DOH handles but - we're considering changing behavior to no longer inherit it. Request - feedback. - - Closes https://github.com/curl/curl/pull/6688 - -Daniel Stenberg (17 Mar 2021) -- http: make 416 not fail with resume + CURLOPT_FAILONERRROR - - When asked to resume a download, libcurl will convert that to HTTP logic - and if then the entire file is already transferred it will result in a - 416 response from the HTTP server. With CURLOPT_FAILONERRROR set in that - scenario, it should *not* lead to an error return. - - Updated test 1156, added test 1273 - - Reported-by: Jonathan Watt - Fixes #6740 - Closes #6753 - -- Curl_timeleft: check both timeouts during connect - - The duration of a connect and the total transfer are calculated from two - different time-stamps. It can end up with the total timeout triggering - before the connect timeout expires and we should make sure to - acknowledge whichever timeout that is reached first. - - This is especially notable when a transfer first sits in PENDING, as - that time is counted in the total time but the connect timeout is based - on the time since the handle changed to the CONNECT state. - - The CONNECTTIMEOUT is per connect attempt. The TIMEOUT is for the entire - operation. - - Fixes #6744 - Closes #6745 - Reported-by: Andrei Bica - Assisted-by: Jay Satiro - -- configure: remove use of deprecated macros - - AC_HEADER_TIME, AC_HEADER_STDC and AC_TYPE_SIGNAL - -- configure: make AC_TRY_* into AC_*_IFELSE - - ... as the former versions are deprecated. - -- configure: s/AC_HELP_STRING/AS_HELP_STRING - - AC_HELP_STRING is deprecated in 2.70+ and I believe AS_HELP_STRING works - already since 2.59 so bump the minimum required version to that. - - Reported-by: Emil Engler - Fixes #6647 - Closes #6748 - -- RELEASE-NOTES: synced - -- travis: use ubuntu nghttp2 package instead of build our own - - Closes #6751 - -- travis: bump wolfssl to 4.7.0 - -- travis: only build wolfssl when needed - - Closes #6751 - -- [Jacob Hoffman-Andrews brought this change] - - rustls: allocate a buffer for TLS data. - - Previously, rustls was using an on-stack array for TLS data. However, - crustls has an (unusual) requirement that buffers it deals with are - initialized before writing to them. By using calloc, we can ensure the - buffer is initialized once and then reuse it across calls. - - Closes #6742 - -- travis: add a rustls build - - ... that doesn't run any tests (yet) - - Closes #6750 - -- HTTP2: remove the outdated remark about multiplexing for the tool - -- [Robert Ronto brought this change] - - http2: don't set KEEP_SEND when there's no more data to be sent - - this should fix an issue where curl sometimes doesn't send out a request - with authorization info after a 401 is received over http2 - - Closes #6747 - -Marc Hoersken (15 Mar 2021) -- config: fix building SMB with configure using Win32 Crypto - - Align conditions for NTLM features between CMake and configure - builds by differentiating between USE_NTLM and USE_CURL_NTLM_CORE, - just like curl_setup.h does internally to detect support of: - - - USE_NTLM: required for NTLM crypto authentication feature - - USE_CURL_NTLM_CORE: required for SMB protocol - - Implement USE_WIN32_CRYPTO detection by checking for Crypt functions - in wincrypt.h which are not available in the Windows App environment. - - Link advapi32 and crypt32 for Crypto API and Schannel SSL backend. - Fix condition of Schannel SSL backend in CMake build accordingly. - - Reviewed-by: Marcel Raad - - Closes #6277 - -- config: fix detection of restricted Windows App environment - - Move the detection of the restricted Windows App environment - in curl_setup.h before the definition of USE_WIN32_CRYPTO - via included config-win32.h in case no build system is used. - - Reviewed-by: Marcel Raad - - Part of #6277 - -Daniel Stenberg (15 Mar 2021) -- HISTORY: curl 7.7.2 was the first version used in Mac OS X 10.1 - -- gen.pl: quote "bare" minuses in the nroff curl.1 - - Reported-by: Alejandro Colomar - Fixes #6698 - Closes #6722 - -Daniel Gustafsson (14 Mar 2021) -- hsts: remove unused defines - - MAX_HSTS_SUBLEN and MAX_HSTS_SUBLENSTR were unused from the initial commit, - and mostly likely leftovers from early development. Remove as they're not - used for anything. - - Closes #6741 - Reviewed-by: Daniel Stenberg <daniel@haxx.se> - -Daniel Stenberg (12 Mar 2021) -- github: add torture-ftp for FTP-only torture testing - - and at 20% to try to keep the run-time reasonable - - Closes #6728 - -- travis: split "torture" into a separate "events" build as well - - Run torture without FTP and reducing coverage to 20% - - For some reason the torture tests now run a lot slower on travis and run - into the 50 minute limit all the time. - - Closes #6728 - -- ftp: fix memory leak in ftp_done - - If after a transfer is complete Curl_GetFTPResponse() returns an error, - curl would not free the ftp->pathalloc block. - - Found by torture-testing test 576 - - Closes #6737 - -- [oxalica brought this change] - - http2: fail if connection terminated without END_STREAM - - Closes #6736 - -- RELEASE-NOTES: synced - -- [Jacob Hoffman-Andrews brought this change] - - rustls: support CURLOPT_SSL_VERIFYPEER - - This requires the latest main branch of crustls, which provides - rustls_client_config_builder_dangerous_set_certificate_verifier and - rustls_client_config_builder_set_enable_sni. - - This refactors the session setup into its own function, and adds a new - function cr_hostname_is_ip. Because crustls doesn't support verification - of IP addresses, special handling is needed: We disable SNI and set a - placeholder hostname (which never actually gets sent on the wire). - - Closes #6719 - -Daniel Gustafsson (12 Mar 2021) -- cookies: Fix potential NULL pointer deref with PSL - - Curl_cookie_init can be called with data being NULL, and this can in turn - be passed to Curl_cookie_add, meaning that both functions must be careful - to only use data where it's checked for being a NULL pointer. The libpsl - support code does however dereference data without checking, so if we are - indeed having an unset data pointer we cannot PSL check the cookiedomain. - - This is currently not a reachable dereference, as the only caller with a - NULL data isn't passing a file to initialize cookies from, but since the - API has this contract let's ensure we hold it. - - Closes #6731 - Reviewed-by: Daniel Stenberg <daniel@haxx.se> - -Daniel Stenberg (12 Mar 2021) -- [Michael Hordijk brought this change] - - configure: only add OpenSSL paths if they are defined - - Add paths for OpenSSL compiling and linking only if they have been - defined. If they haven't been defined, we'll assume that the paths are - already available to the toolchain. - - Closes #6730 - -Jay Satiro (12 Mar 2021) -- retry.d: Clarify transient 5xx HTTP response codes - - - Clarify the only 5xx response codes that are treated as transient are - 500, 502, 503 and 504. - - Prior to this change it said it treated all 5xx as transient, but the - code says otherwise. - - Ref: https://github.com/curl/curl/blob/curl-7_75_0/src/tool_operate.c#L462-L495 - - Closes https://github.com/curl/curl/pull/6724 - -- retry-all-errors.d: Explain curl errors versus HTTP response errors - - - Add a paragraph explaining that curl does not consider HTTP response - errors as curl errors, and how that behavior can be modified by using - --retry and --fail. - - The --retry-all-errors doc says "Retry on any error" which some users - may find misleading without the added explanation. - - Ref: https://curl.se/docs/faq.html#Why_do_I_get_downloaded_data_eve - Ref: https://curl.se/docs/faq.html#curl_doesn_t_return_error_for_HT - - Reported-by: Lawrence Gripper - - Fixes https://github.com/curl/curl/issues/6712 - Closes https://github.com/curl/curl/pull/6720 - -Daniel Stenberg (11 Mar 2021) -- travis: switch ngtcp2 build over to quictls - - The ngtcp2 project switched over to using the quictls OpenSSL fork - instead of their own patched OpenSSL. We follow suit. - - Closes #6729 - -- test220/314: adjust to run with Hyper - -- c-hyper: support automatic content-encoding - - Closes #6727 - -- http: remove superfluous NULL assign - - Closes #6727 - -- tool_operate: bail if set CURLOPT_HTTP09_ALLOWED returns error - - Closes #6727 - -- setopt: error on CURLOPT_HTTP09_ALLOWED set true with Hyper - - Not supported. - - Closes #6727 - -- test306: make it not run with Hyper - - ... as it tests HTTP/0.9 which Hyper doesn't support. - -- test304: header CRLF cleanup to work with Hyper - -- FTP: allow SIZE to fail when doing (resumed) upload - - Added test 362 to verify. - - Reported-by: Jordan Brown - Regression since 7ea2e1d0c5a7f (7.73.0) - Fixes #6715 - Closes #6725 - -- configure: provide Largefile feature for curl-config - - ... as cmake now does it correctly, and make test1014 check for it - - Closes #6702 - -- config: remove CURL_SIZEOF_CURL_OFF_T use only SIZEOF_CURL_OFF_T - - Make the code consistently use a single name for the size of the - "curl_off_t" type. - - Closes #6702 - -Jay Satiro (10 Mar 2021) -- [Jun-ya Kato brought this change] - - ngtcp2: Fix build error due to change in ngtcp2_addr_init - - ngtcp2/ngtcp2@b8d90a9 changed the function prototype. - - Closes https://github.com/curl/curl/pull/6716 - -Daniel Stenberg (10 Mar 2021) -- [ejanchivdorj brought this change] - - multi: update pending list when removing handle - - when removing a handle, most of the lists are updated but pending list - is not updated. Updating now. - - Closes #6713 - -- [kokke brought this change] - - lib1536: check ptr against NULL before dereferencing it - - Closes #6710 - -- [kokke brought this change] - - lib1537: check ptr against NULL before dereferencing it - - Fixes #6707 - Closes #6708 - -- travis: make torture tests skip TLS-SRP tests - - ... as it seems to often hang. - - Also: skip the "normal" tests as they're already run by many other - builds. - - Closes #6705 - -- openssl: adapt to v3's new const for a few API calls - - Closes #6703 - -- quiche: fix crash when failing to connect - - Reported-by: ウさん - Fixes #6664 - Closes #6701 - -- RELEASE-NOTES: synced - - Fixed the release counter and added a missing contributor - -- RELEASE-NOTES: synced - -- dynbuf: bump the max HTTP request to 1MB - - Raised from 128KB to allow longer request headers. - - Reported-by: Carl Zogheib - Fixes #6681 - Closes #6685 - -Jay Satiro (6 Mar 2021) -- schannel: Evaluate CURLOPT_SSL_OPTIONS via SSL_SET_OPTION macro - - - Change use of those options from CURLOPT_SSL_OPTIONS that are not - already evaluated via SSL_SET_OPTION in schannel and secure transport - to use that instead of data->set.ssl.optname. - - Example: - - Evaluate SSL_SET_OPTION(no_revoke) instead of data->set.ssl.no_revoke. - - This change is because options set via CURLOPT_SSL_OPTIONS - (data->set.ssl.optname) are separate from those set for HTTPS proxy via - CURLOPT_PROXY_SSL_OPTIONS (data->set.proxy_ssl.optname). The - SSL_SET_OPTION macro determines whether the connection is for HTTPS - proxy and based on that which option to evaluate. - - Since neither Schannel nor Secure Transport backends currently support - HTTPS proxy in libcurl, this change is for posterity and has no other - effect. - - Closes https://github.com/curl/curl/pull/6690 - -- [kokke brought this change] - - c-hyper: Remove superfluous pointer check - - `n` pointer is never NULL once set. Found by static analysis. - - Ref: https://github.com/curl/curl/issues/6696 - - Closes https://github.com/curl/curl/pull/6697 - -- version.d: Add missing features to the features list - - - Add missing entries for gsasl, Kerberos, NTLM_WB, TrackMemory, - Unicode and zstd. - - - Remove krb4 since it's no longer a feature. - - Reported-by: Ádler Jonas Gross - - Fixes https://github.com/curl/curl/issues/6677 - Closes https://github.com/curl/curl/pull/6687 - -- [Vladimir Varlamov brought this change] - - docs: add missing Arg tag to --stderr - - Prior to this change the required argument was not shown. - - curl.1 before: --stderr - curl.1 after: --stderr <file> - - curl --help before: - --stderr Where to redirect stderr - - curl --help after: - --stderr <file> Where to redirect stderr - - Closes https://github.com/curl/curl/pull/6692 - -- projects: Update VS projects for OpenSSL 1.1.x - - - Update VS project templates to use the OpenSSL lib names and include - directories for OpenSSL 1.1.x. - - This change means the VS project files will now build only with OpenSSL - 1.1.x when an OpenSSL configuration is chosen. Prior to this change the - project files built only with OpenSSL 1.0.x (end-of-life) when an - OpenSSL configuration was chosen. - - The template changes in this commit were made by script: - - libeay32.lib => libcrypto.lib - ssleay32.lib => libssl.lib - ..\..\..\..\..\openssl\inc32 => ..\..\..\..\..\openssl\include - - And since the output directory now contains the includes it's prepended: - ..\..\..\..\..\openssl\build\Win{32,64}\VC{6..15}\{DLL,LIB} - {Debug,Release}\include - - - Change build-openssl.bat to copy the build's include directory to the - output directory (as seen above). - - Each build has its own opensslconf.h which is different so we can't just - include the source include directory any longer. - - Note the include directory in the output directory is a full copy from - the build so technically we don't need to include the OpenSSL source - include directory in the template. However, I left it last in case the - user made a custom OpenSSL build using the old method which would put - opensslconf in the OpenSSL source include directory. - - - Change build-openssl.bat to use a temporary install directory that is - different from the temporary build directory. - - For OpenSSL 1.1.x the temporary paths must be separate not a descendant - of the other, otherwise pdb files will be lost between builds. - - Ref: https://curl.se/mail/lib-2018-10/0049.html - Ref: https://gist.github.com/jay/125191c35bbeb894444eff827651f755 - Ref; https://github.com/openssl/openssl/issues/10005 - - Fixes https://github.com/curl/curl/issues/984 - Closes https://github.com/curl/curl/pull/6675 - -- doh: Inherit CURLOPT_STDERR from user's easy handle - - Prior to this change if the user set their easy handle's error stream - to something other than stderr it was not inherited by the doh handles, - which meant that they would still write to the default standard error - stream (stderr) for verbose output. - - Bug: https://github.com/curl/curl/issues/6605 - Reported-by: arvids-kokins-bidstack@users.noreply.github.com - - Closes https://github.com/curl/curl/pull/6661 - -Marc Hoersken (1 Mar 2021) -- CI/azure: replace python-impacket with python3-impacket - - As of this month Azure DevOps uses Ubuntu 20.04 LTS which - no longer supports Python 2 and instead ships Python 3. - - Closes #6678 - -- runtests.pl: kill processes locking test log files - - Introduce a new runtests.pl command option: -rm - - For now only required and implemented for Windows. - Ignore stunnel logs due to long running processes. - - Requires Sysinternals handle[64].exe to be on PATH. - - Reviewed-by: Jay Satiro - - Ref: #6058 - Closes #6179 - -- pathhelp.pm: fix use of pwd -L in Msys environment - - While Msys2 has a pwd binary which supports -L, - Msys1 only has a shell built-in with that feature. - - Reviewed-by: Jay Satiro - - Part of #6179 - -Daniel Gustafsson (1 Mar 2021) -- ldap: use correct memory free function - - unescaped is coming from Curl_urldecode and not a unicode conversion - function, so reclaiming its memory should be performed with a normal - call to free rather than curlx_unicodefree. In reality, this is the - same thing as curlx_unicodefree is implemented as a call to free but - that's not guaranteed to always hold. Using the curlx macro present - issues with memory debugging as well. - - Closes #6671 - Reviewed-by: Jay Satiro <raysatiro@yahoo.com> - Reviewed-by: Daniel Stenberg <daniel@haxx.se> - -- url: fix typo in comment - - Correct a small typo which snuck in with a304051620. - -Jay Satiro (28 Feb 2021) -- tool_help: Increase space between option and description - - - Increase the minimum number of spaces between the option and the - description from 1 to 2. - - Before: - ~~~ - -u, --user <user:password> Server user and password - -A, --user-agent <name> Send User-Agent <name> to server - -v, --verbose Make the operation more talkative - -V, --version Show version number and quit - -w, --write-out <format> Use output FORMAT after completion - --xattr Store metadata in extended file attributes - ~~~ - - After: - ~~~ - -u, --user <user:password> Server user and password - -A, --user-agent <name> Send User-Agent <name> to server - -v, --verbose Make the operation more talkative - -V, --version Show version number and quit - -w, --write-out <format> Use output FORMAT after completion - --xattr Store metadata in extended file attributes - ~~~ - - Closes https://github.com/curl/curl/pull/6674 - -Daniel Stenberg (27 Feb 2021) -- curl: set CURLOPT_NEW_FILE_PERMS if requested - - The --create-file-mode code logic accepted the value but never actually - passed it on to libcurl! - - Follow-up to a7696c73436f (shipped in 7.75.0) - Reported-by: Johannes Lesr - Fixes #6657 - Closes #6666 - -- tool_operate: check argc before accessing argv[1] - - Follow-up to 09363500b - Reported-by: Emil Engler - Reviewed-by: Daniel Gustafsson - Closes #6668 - -Daniel Gustafsson (26 Feb 2021) -- [Jean-Philippe Menil brought this change] - - openssl: remove get_ssl_version_txt in favor of SSL_get_version - - openssl: use SSL_get_version to get connection protocol - - Replace our bespoke get_ssl_version_txt in favor of SSL_get_version. - We can get rid of few lines of code, since SSL_get_version achieve - the exact same thing - - Closes #6665 - Reviewed-by: Daniel Gustafsson <daniel@yesql.se> - Signed-off-by: Jean-Philippe Menil <jpmenil@gmail.com> diff --git a/libs/libcurl/docs/THANKS b/libs/libcurl/docs/THANKS index 82755c72d3..e29cbeedf6 100644 --- a/libs/libcurl/docs/THANKS +++ b/libs/libcurl/docs/THANKS @@ -273,6 +273,7 @@ Benoit Neil Benoit Sigoure Bernard Leak Bernard Spil +Bernat Mut Bernd Mueller Bernhard Iselborn Bernhard M. Wiedemann @@ -341,6 +342,7 @@ Bru Rom Bruce Mitchener Bruce Stephens BrumBrum on hackerone +Bruno Baguette Bruno de Carvalho Bruno Grasselli Bruno Thomsen @@ -478,6 +480,7 @@ Dambaev Alexander Damian Dixon Damien Adant Damien Vielpeau +Damien Walsh Dan Becker Dan Cristian Dan Donahue @@ -537,6 +540,7 @@ David Bau David Benjamin David Binderman David Blaikie +David Bohman David Byron David Cohen David Cook @@ -709,6 +713,7 @@ Eric Lavigne Eric Lubin Eric Melville Eric Mertens +Eric Musser Eric Rautman Eric Rescorla Eric Ridge @@ -771,6 +776,7 @@ Flameborn on github Flavio Medeiros Florian Pritz Florian Schoppmann +Florian Van Heghe Florian Weimer Florin Petriuc Forrest Cahoon @@ -814,6 +820,7 @@ Gavin Wong Gavrie Philipson Gaz Iqbal Gaël Portay +gclinch on github Gealber Morales Geeknik Labs Geoff Beier @@ -849,6 +856,7 @@ Glen Nakamura Glen Scott Glenn de boer Glenn Sheridan +Glenn Strauss Godwin Stewart Google Inc. Gordon Marler @@ -1060,12 +1068,14 @@ Jeff Hodges Jeff Johnson Jeff King Jeff Lawson +Jeff Luszcz Jeff Mears Jeff Phillips Jeff Pohlmeyer Jeff Weber Jeffrey Tolar Jeffrey Walton +jeffrson on github Jens Finkhaeuser Jens Rantil Jens Schleusener @@ -1223,6 +1233,7 @@ Julian Z Julien Chaffraix Julien Nabet Julien Royer +Jun Tseng Jun-ichiro itojun Hagino Jun-ya Kato jungle-boogie on github @@ -1363,6 +1374,7 @@ Leon Breedt Leon Winter Leonardo Rosati Leonardo Taccari +Leszek Kubik Li Xinwei Liam Healy lijian996 on github @@ -1379,6 +1391,7 @@ Lior Kaplan Lisa Xu Liviu Chircu Liza Alenchery +lllaffer on github Lloyd Fournier Lluís Batlle i Rossell locpyl-tidnyd on github @@ -1459,6 +1472,7 @@ Mario Schroeder Mark Brand Mark Butler Mark Davies +Mark Dodgson Mark Hamilton Mark Incley Mark Karpeles @@ -1557,6 +1571,7 @@ mccormickt12 on github Mehmet Bozkurt Mekonikum Melissa Mears +Melroy van den Berg Mert Yazıcıoğlu Mettgut Jamalla Michael Afanasiev @@ -1713,6 +1728,7 @@ Niklas Hambüchen Nikolai Kondrashov Nikos Mavrogiannopoulos Nikos Tsipinakis +nimaje on github niner on github Ning Dong Nir Soffer @@ -1942,6 +1958,7 @@ Red Hat Product Security Reed Loden Reinhard Max Reinout van Schouwen +RekGRpth on github Remco van Hooff Remi Gacogne Remo E @@ -2070,6 +2087,7 @@ Ryan Mast Ryan Nelson Ryan Schmidt Ryan Scott +Ryan Sleevi Ryan Winograd ryancaicse on github Ryuichi KAWAMATA @@ -2182,6 +2200,7 @@ Spork Schivago sspiri on github sstruchtrup on github Stadler Stephan +Stan Hu Stan van de Burgt Stanislav Ivochkin Stanislav Zidek @@ -2192,6 +2211,7 @@ Stefan Bühler Stefan Eissing Stefan Esser Stefan Grether +Stefan Huber Stefan Kanthak Stefan Karpinski Stefan Krause @@ -2210,9 +2230,11 @@ Stephan Bergmann Stephan Lagerholm Stephan Mühlstrasser Stephan Szabo +Stephane Pellegrino Stephen Brokenshire Stephen Collyer Stephen Kick +Stephen M. Coakley Stephen More Stephen Toub Sterling Hughes @@ -2325,6 +2347,7 @@ Tobias Hieta Tobias Hintze Tobias Lindgren Tobias Markus +Tobias Nießen Tobias Nyholm Tobias Rundström Tobias Stoeckmann @@ -2398,6 +2421,7 @@ User Sg ustcqidi on github Vadim Grinshpun Valentin David +Valentin Richter Valentyn Korniienko Valentín Gutiérrez Valerii Zapodovnikov @@ -2432,6 +2456,7 @@ Vlad Ureche Vladimir Grishchenko Vladimir Kotal Vladimir Lazarenko +Vladimir Panteleev Vladimir Varlamov Vlastimil Ovčáčík Vojtech Janota diff --git a/libs/libcurl/include/curl/curl.h b/libs/libcurl/include/curl/curl.h index 6b6ac8a05e..7b69ce2d67 100644 --- a/libs/libcurl/include/curl/curl.h +++ b/libs/libcurl/include/curl/curl.h @@ -2132,6 +2132,9 @@ typedef enum { * (in seconds) */ CURLOPT(CURLOPT_MAXLIFETIME_CONN, CURLOPTTYPE_LONG, 314), + /* Set MIME option flags. */ + CURLOPT(CURLOPT_MIME_OPTIONS, CURLOPTTYPE_LONG, 315), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -2291,6 +2294,9 @@ CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); typedef struct curl_mime curl_mime; /* Mime context. */ typedef struct curl_mimepart curl_mimepart; /* Mime part context. */ +/* CURLMIMEOPT_ defines are for the CURLOPT_MIME_OPTIONS option. */ +#define CURLMIMEOPT_FORMESCAPE (1<<0) /* Use backslash-escaping for forms. */ + /* * NAME curl_mime_init() * diff --git a/libs/libcurl/include/curl/curlver.h b/libs/libcurl/include/curl/curlver.h index 6756c31bff..6d2f99b6da 100644 --- a/libs/libcurl/include/curl/curlver.h +++ b/libs/libcurl/include/curl/curlver.h @@ -30,12 +30,12 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.80.0" +#define LIBCURL_VERSION "7.81.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 80 +#define LIBCURL_VERSION_MINOR 81 #define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier @@ -57,7 +57,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 0x075000 +#define LIBCURL_VERSION_NUM 0x075100 /* * This is the date and time when the full source package was created. The @@ -68,7 +68,7 @@ * * "2007-11-23" */ -#define LIBCURL_TIMESTAMP "2021-11-10" +#define LIBCURL_TIMESTAMP "2022-01-05" #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) #define CURL_AT_LEAST_VERSION(x,y,z) \ diff --git a/libs/libcurl/include/curl/multi.h b/libs/libcurl/include/curl/multi.h index 37f9829b3b..91cd95d323 100644 --- a/libs/libcurl/include/curl/multi.h +++ b/libs/libcurl/include/curl/multi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -73,7 +73,8 @@ typedef enum { CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a callback */ CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */ - CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */ + CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */ + CURLM_ABORTED_BY_CALLBACK, CURLM_LAST } CURLMcode; diff --git a/libs/libcurl/include/curl/urlapi.h b/libs/libcurl/include/curl/urlapi.h index 3c4b4e18aa..a475f91b60 100644 --- a/libs/libcurl/include/curl/urlapi.h +++ b/libs/libcurl/include/curl/urlapi.h @@ -48,6 +48,18 @@ typedef enum { CURLUE_NO_PORT, /* 15 */ CURLUE_NO_QUERY, /* 16 */ CURLUE_NO_FRAGMENT, /* 17 */ + CURLUE_NO_ZONEID, /* 18 */ + CURLUE_BAD_FILE_URL, /* 19 */ + CURLUE_BAD_FRAGMENT, /* 20 */ + CURLUE_BAD_HOSTNAME, /* 21 */ + CURLUE_BAD_IPV6, /* 22 */ + CURLUE_BAD_LOGIN, /* 23 */ + CURLUE_BAD_PASSWORD, /* 24 */ + CURLUE_BAD_PATH, /* 25 */ + CURLUE_BAD_QUERY, /* 26 */ + CURLUE_BAD_SCHEME, /* 27 */ + CURLUE_BAD_SLASHES, /* 28 */ + CURLUE_BAD_USER, /* 29 */ CURLUE_LAST } CURLUcode; diff --git a/libs/libcurl/src/CMakeLists.txt b/libs/libcurl/src/CMakeLists.txt index 2575288f70..46973bf2b8 100644 --- a/libs/libcurl/src/CMakeLists.txt +++ b/libs/libcurl/src/CMakeLists.txt @@ -95,10 +95,6 @@ endif() target_link_libraries(${LIB_NAME} ${CURL_LIBS}) -if(WIN32) - add_definitions(-D_USRDLL) -endif() - set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL OUTPUT_NAME ${LIBCURL_OUTPUT_NAME} @@ -121,6 +117,7 @@ endif() if(WIN32) if(BUILD_SHARED_LIBS) + set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "_USRDLL") if(MSVC) # Add "_imp" as a suffix before the extension to avoid conflicting with # the statically linked "libcurl.lib" diff --git a/libs/libcurl/src/Makefile.m32 b/libs/libcurl/src/Makefile.m32 index d78614da33..2bb208fbe4 100644 --- a/libs/libcurl/src/Makefile.m32 +++ b/libs/libcurl/src/Makefile.m32 @@ -168,76 +168,76 @@ endif ######################################################## ## Nothing more to do below this line! -ifeq ($(findstring -dyn,$(CFG)),-dyn) +ifneq ($(findstring -dyn,$(CFG)),) DYN = 1 endif -ifeq ($(findstring -ares,$(CFG)),-ares) +ifneq ($(findstring -ares,$(CFG)),) ARES = 1 endif -ifeq ($(findstring -sync,$(CFG)),-sync) +ifneq ($(findstring -sync,$(CFG)),) SYNC = 1 endif -ifeq ($(findstring -rtmp,$(CFG)),-rtmp) +ifneq ($(findstring -rtmp,$(CFG)),) RTMP = 1 ZLIB = 1 endif -ifeq ($(findstring -ssh2,$(CFG)),-ssh2) +ifneq ($(findstring -ssh2,$(CFG)),) SSH2 = 1 ZLIB = 1 endif -ifeq ($(findstring -ssl,$(CFG)),-ssl) +ifneq ($(findstring -ssl,$(CFG)),) SSL = 1 endif -ifeq ($(findstring -srp,$(CFG)),-srp) +ifneq ($(findstring -srp,$(CFG)),) SRP = 1 endif -ifeq ($(findstring -zlib,$(CFG)),-zlib) +ifneq ($(findstring -zlib,$(CFG)),) ZLIB = 1 endif -ifeq ($(findstring -zstd,$(CFG)),-zstd) +ifneq ($(findstring -zstd,$(CFG)),) ZSTD = 1 endif -ifeq ($(findstring -brotli,$(CFG)),-brotli) +ifneq ($(findstring -brotli,$(CFG)),) BROTLI = 1 endif -ifeq ($(findstring -gsasl,$(CFG)),-gsasl) +ifneq ($(findstring -gsasl,$(CFG)),) GSASL = 1 endif -ifeq ($(findstring -idn2,$(CFG)),-idn2) +ifneq ($(findstring -idn2,$(CFG)),) IDN2 = 1 endif -ifeq ($(findstring -winidn,$(CFG)),-winidn) +ifneq ($(findstring -winidn,$(CFG)),) WINIDN = 1 endif -ifeq ($(findstring -sspi,$(CFG)),-sspi) +ifneq ($(findstring -sspi,$(CFG)),) SSPI = 1 endif -ifeq ($(findstring -ldaps,$(CFG)),-ldaps) +ifneq ($(findstring -ldaps,$(CFG)),) LDAPS = 1 endif -ifeq ($(findstring -ipv6,$(CFG)),-ipv6) +ifneq ($(findstring -ipv6,$(CFG)),) IPV6 = 1 endif -ifeq ($(findstring -winssl,$(CFG)),-winssl) -WINSSL = 1 +ifneq ($(findstring -schannel,$(CFG))$(findstring -winssl,$(CFG)),) +SCHANNEL = 1 SSPI = 1 endif -ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) +ifneq ($(findstring -nghttp2,$(CFG)),) NGHTTP2 = 1 endif -ifeq ($(findstring -nghttp3,$(CFG)),-nghttp3) +ifneq ($(findstring -nghttp3,$(CFG)),) NGHTTP3 = 1 endif -ifeq ($(findstring -ngtcp2,$(CFG)),-ngtcp2) +ifneq ($(findstring -ngtcp2,$(CFG)),) NGTCP2 = 1 endif -ifeq ($(findstring -unicode,$(CFG)),-unicode) +ifneq ($(findstring -unicode,$(CFG)),) UNICODE = 1 endif # SSH2 and RTMP require an SSL library; assume OpenSSL if none specified ifneq ($(SSH2)$(RTMP),) - ifeq ($(SSL)$(WINSSL),) + ifeq ($(SSL)$(SCHANNEL),) SSL = 1 endif endif @@ -245,7 +245,7 @@ endif INCLUDES = -I. -I../include CFLAGS += -DBUILDING_LIBCURL ifdef SSL - ifdef WINSSL + ifdef SCHANNEL CFLAGS += -DCURL_WITH_MULTI_SSL endif endif @@ -277,7 +277,7 @@ ifdef SSH2 INCLUDES += -I"$(LIBSSH2_PATH)/include" -I"$(LIBSSH2_PATH)/win32" CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2 - ifdef WINSSL + ifdef SCHANNEL ifndef DYN DLL_LIBS += -lbcrypt -lcrypt32 endif @@ -329,7 +329,7 @@ ifdef SSL endif endif endif -ifdef WINSSL +ifdef SCHANNEL CFLAGS += -DUSE_SCHANNEL DLL_LIBS += -lcrypt32 endif diff --git a/libs/libcurl/src/asyn-ares.c b/libs/libcurl/src/asyn-ares.c index fc168baa6e..fd0bb6c96a 100644 --- a/libs/libcurl/src/asyn-ares.c +++ b/libs/libcurl/src/asyn-ares.c @@ -109,7 +109,9 @@ struct thread_data { struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ int last_status; +#ifndef HAVE_CARES_GETADDRINFO struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ +#endif }; /* How long we are willing to wait for additional parallel responses after @@ -375,6 +377,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, waitperform(data, 0); +#ifndef HAVE_CARES_GETADDRINFO /* Now that we've checked for any last minute results above, see if there are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer expires. */ @@ -397,6 +400,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, ares_cancel((ares_channel)data->state.async.resolver); DEBUGASSERT(res->num_pending == 0); } +#endif if(res && !res->num_pending) { (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai); diff --git a/libs/libcurl/src/checksrc.pl b/libs/libcurl/src/checksrc.pl index 8f98a99ab5..eea1126d1c 100644 --- a/libs/libcurl/src/checksrc.pl +++ b/libs/libcurl/src/checksrc.pl @@ -502,7 +502,7 @@ sub scanfile { } # check for '== NULL' in if/while conditions but not if the thing on # the left of it is a function call - if($nostr =~ /^(.*)(if|while)(\(.*[^)]) == NULL/) { + if($nostr =~ /^(.*)(if|while)(\(.*?)([!=]= NULL|NULL [!=]=)/) { checkwarn("EQUALSNULL", $line, length($1) + length($2) + length($3), $file, $l, "we prefer !variable instead of \"== NULL\" comparisons"); diff --git a/libs/libcurl/src/config-win32.h b/libs/libcurl/src/config-win32.h index ef98f6cbdf..89593a815d 100644 --- a/libs/libcurl/src/config-win32.h +++ b/libs/libcurl/src/config-win32.h @@ -225,10 +225,6 @@ /* Define if you have the socket function. */ #define HAVE_SOCKET 1 -/* Define if libSSH2 is in use */ -#define USE_LIBSSH2 1 -#define HAVE_LIBSSH2_H 1 - /* Define if you have the strcasecmp function. */ #ifdef __MINGW32__ #define HAVE_STRCASECMP 1 @@ -669,9 +665,6 @@ Vista # define CURL_DISABLE_LDAP 1 #endif -/* if SSL is enabled */ -#define USE_OPENSSL 1 - /* Define to use the Windows crypto library. */ #if !defined(CURL_WINDOWS_APP) #define USE_WIN32_CRYPTO diff --git a/libs/libcurl/src/conncache.c b/libs/libcurl/src/conncache.c index f5ba8ff70a..fec1937f0b 100644 --- a/libs/libcurl/src/conncache.c +++ b/libs/libcurl/src/conncache.c @@ -113,21 +113,16 @@ static void free_bundle_hash_entry(void *freethis) int Curl_conncache_init(struct conncache *connc, int size) { - int rc; - /* allocate a new easy handle to use when closing cached connections */ connc->closure_handle = curl_easy_init(); if(!connc->closure_handle) return 1; /* bad */ - rc = Curl_hash_init(&connc->hash, size, Curl_hash_str, - Curl_str_key_compare, free_bundle_hash_entry); - if(rc) - Curl_close(&connc->closure_handle); - else - connc->closure_handle->state.conn_cache = connc; + Curl_hash_init(&connc->hash, size, Curl_hash_str, + Curl_str_key_compare, free_bundle_hash_entry); + connc->closure_handle->state.conn_cache = connc; - return rc; + return 0; /* good */ } void Curl_conncache_destroy(struct conncache *connc) diff --git a/libs/libcurl/src/connect.c b/libs/libcurl/src/connect.c index af60947314..5252f9714d 100644 --- a/libs/libcurl/src/connect.c +++ b/libs/libcurl/src/connect.c @@ -744,15 +744,17 @@ void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd, void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn, curl_socket_t sockfd) { - /* 'local_ip' and 'local_port' get filled with local's numerical ip address - and port number whenever an outgoing connection is **established** from - the primary socket to a remote address. */ + /* 'local_ip' and 'local_port' get filled with local's numerical + ip address and port number whenever an outgoing connection is + **established** from the primary socket to a remote address. */ char local_ip[MAX_IPADR_LEN] = ""; int local_port = -1; - if(!conn->bits.reuse && !conn->bits.tcp_fastopen) - Curl_conninfo_remote(data, conn, sockfd); - Curl_conninfo_local(data, sockfd, local_ip, &local_port); + if(conn->transport == TRNSPRT_TCP) { + if(!conn->bits.reuse && !conn->bits.tcp_fastopen) + Curl_conninfo_remote(data, conn, sockfd); + Curl_conninfo_local(data, sockfd, local_ip, &local_port); + } /* end of TCP-only section */ /* persist connection info in session handle */ Curl_persistconninfo(data, conn, local_ip, local_port); @@ -892,6 +894,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data, connkeep(conn, "HTTP/3 default"); return CURLE_OK; } + /* When a QUIC connect attempt fails, the better error explanation is in + 'result' and not in errno */ if(result) { conn->tempsock[i] = CURL_SOCKET_BAD; error = SOCKERRNO; @@ -975,6 +979,13 @@ CURLcode Curl_is_connected(struct Curl_easy *data, char buffer[STRERROR_LEN]; Curl_printable_address(conn->tempaddr[i], ipaddress, sizeof(ipaddress)); +#ifdef ENABLE_QUIC + if(conn->transport == TRNSPRT_QUIC) { + infof(data, "connect to %s port %u failed: %s", + ipaddress, conn->port, curl_easy_strerror(result)); + } + else +#endif infof(data, "connect to %s port %u failed: %s", ipaddress, conn->port, Curl_strerror(error, buffer, sizeof(buffer))); @@ -986,9 +997,11 @@ CURLcode Curl_is_connected(struct Curl_easy *data, ainext(conn, i, TRUE); status = trynextip(data, conn, sockindex, i); if((status != CURLE_COULDNT_CONNECT) || - conn->tempsock[other] == CURL_SOCKET_BAD) + conn->tempsock[other] == CURL_SOCKET_BAD) { /* the last attempt failed and no other sockets remain open */ - result = status; + if(!result) + result = status; + } } } } @@ -1014,6 +1027,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data, /* no more addresses to try */ const char *hostname; char buffer[STRERROR_LEN]; + CURLcode failreason = result; /* if the first address family runs out of addresses to try before the happy eyeball timeout, go ahead and try the next family now */ @@ -1021,6 +1035,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data, if(!result) return result; + result = failreason; + #ifndef CURL_DISABLE_PROXY if(conn->bits.socksproxy) hostname = conn->socks_proxy.host.name; @@ -1034,10 +1050,14 @@ CURLcode Curl_is_connected(struct Curl_easy *data, hostname = conn->host.name; failf(data, "Failed to connect to %s port %u after " - "%" CURL_FORMAT_TIMEDIFF_T " ms: %s", - hostname, conn->port, - Curl_timediff(now, data->progress.t_startsingle), - Curl_strerror(error, buffer, sizeof(buffer))); + "%" CURL_FORMAT_TIMEDIFF_T " ms: %s", + hostname, conn->port, + Curl_timediff(now, data->progress.t_startsingle), +#ifdef ENABLE_QUIC + (conn->transport == TRNSPRT_QUIC) ? + curl_easy_strerror(result) : +#endif + Curl_strerror(error, buffer, sizeof(buffer))); Curl_quic_disconnect(data, conn, 0); Curl_quic_disconnect(data, conn, 1); @@ -1125,7 +1145,7 @@ void Curl_sndbufset(curl_socket_t sockfd) static int detectOsState = DETECT_OS_NONE; if(detectOsState == DETECT_OS_NONE) { - if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT, + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) detectOsState = DETECT_OS_VISTA_OR_LATER; else diff --git a/libs/libcurl/src/cookie.c b/libs/libcurl/src/cookie.c index b7531f7424..d418efa33d 100644 --- a/libs/libcurl/src/cookie.c +++ b/libs/libcurl/src/cookie.c @@ -1164,7 +1164,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, bool fromfile = TRUE; char *line = NULL; - if(NULL == inc) { + if(!inc) { /* we didn't get a struct, create one */ c = calloc(1, sizeof(struct CookieInfo)); if(!c) diff --git a/libs/libcurl/src/curl_config.h.in b/libs/libcurl/src/curl_config.h.in index 751f6a4f65..2bce4ecc48 100644 --- a/libs/libcurl/src/curl_config.h.in +++ b/libs/libcurl/src/curl_config.h.in @@ -498,9 +498,6 @@ /* Define to 1 if you have the <openssl/ssl.h> header file. */ #undef HAVE_OPENSSL_SSL_H -/* Define to 1 if you have the `OpenSSL_version' function. */ -#undef HAVE_OPENSSL_VERSION - /* Define to 1 if you have the <openssl/x509.h> header file. */ #undef HAVE_OPENSSL_X509_H @@ -600,9 +597,6 @@ /* Define to 1 if you have the <socket.h> header file. */ #undef HAVE_SOCKET_H -/* Define to 1 if you have the `SSLv2_client_method' function. */ -#undef HAVE_SSLV2_CLIENT_METHOD - /* Define to 1 if you have the `SSL_get_ech_status' function. */ #undef HAVE_SSL_GET_ECH_STATUS diff --git a/libs/libcurl/src/curl_hmac.h b/libs/libcurl/src/curl_hmac.h index 84c73121bd..5755655d02 100644 --- a/libs/libcurl/src/curl_hmac.h +++ b/libs/libcurl/src/curl_hmac.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,7 @@ #define HMAC_MD5_LENGTH 16 -typedef void (* HMAC_hinit_func)(void *context); +typedef CURLcode (* HMAC_hinit_func)(void *context); typedef void (* HMAC_hupdate_func)(void *context, const unsigned char *data, unsigned int len); diff --git a/libs/libcurl/src/curl_md5.h b/libs/libcurl/src/curl_md5.h index 5739c89ca4..b7d7c1f5d2 100644 --- a/libs/libcurl/src/curl_md5.h +++ b/libs/libcurl/src/curl_md5.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,7 +27,7 @@ #define MD5_DIGEST_LEN 16 -typedef void (* Curl_MD5_init_func)(void *context); +typedef CURLcode (* Curl_MD5_init_func)(void *context); typedef void (* Curl_MD5_update_func)(void *context, const unsigned char *data, unsigned int len); @@ -49,8 +49,8 @@ struct MD5_context { extern const struct MD5_params Curl_DIGEST_MD5[1]; extern const struct HMAC_params Curl_HMAC_MD5[1]; -void Curl_md5it(unsigned char *output, const unsigned char *input, - const size_t len); +CURLcode Curl_md5it(unsigned char *output, const unsigned char *input, + const size_t len); struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params); CURLcode Curl_MD5_update(struct MD5_context *context, diff --git a/libs/libcurl/src/curl_sha256.h b/libs/libcurl/src/curl_sha256.h index b14c475ef8..55dc30ad74 100644 --- a/libs/libcurl/src/curl_sha256.h +++ b/libs/libcurl/src/curl_sha256.h @@ -37,8 +37,8 @@ extern const struct HMAC_params Curl_HMAC_SHA256[1]; #define SHA256_DIGEST_LENGTH 32 #endif -void Curl_sha256it(unsigned char *outbuffer, const unsigned char *input, - const size_t len); +CURLcode Curl_sha256it(unsigned char *outbuffer, const unsigned char *input, + const size_t len); #endif diff --git a/libs/libcurl/src/curl_sspi.c b/libs/libcurl/src/curl_sspi.c index 06841ddec6..339bf549fb 100644 --- a/libs/libcurl/src/curl_sspi.c +++ b/libs/libcurl/src/curl_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -83,7 +83,7 @@ CURLcode Curl_sspi_global_init(void) * have both these DLLs (security.dll forwards calls to secur32.dll) */ /* Load SSPI dll into the address space of the calling process */ - if(curlx_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL)) + if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL)) s_hSecDll = Curl_load_library(TEXT("security.dll")); else s_hSecDll = Curl_load_library(TEXT("secur32.dll")); diff --git a/libs/libcurl/src/easy.c b/libs/libcurl/src/easy.c index 2aca93845b..20293a710b 100644 --- a/libs/libcurl/src/easy.c +++ b/libs/libcurl/src/easy.c @@ -822,7 +822,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) { struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy)); - if(NULL == outcurl) + if(!outcurl) goto fail; /* @@ -1087,14 +1087,16 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) /* if not pausing again, force a recv/send check of this connection as the data might've been read off the socket already */ data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT; - if(data->multi) - Curl_update_timer(data->multi); + if(data->multi) { + if(Curl_update_timer(data->multi)) + return CURLE_ABORTED_BY_CALLBACK; + } } if(!data->state.done) /* This transfer may have been moved in or out of the bundle, update the corresponding socket callback, if used */ - Curl_updatesocket(data); + result = Curl_updatesocket(data); return result; } diff --git a/libs/libcurl/src/easyoptions.c b/libs/libcurl/src/easyoptions.c index b6131d4321..04871ad1e3 100644 --- a/libs/libcurl/src/easyoptions.c +++ b/libs/libcurl/src/easyoptions.c @@ -170,6 +170,7 @@ struct curl_easyoption Curl_easyopts[] = { {"MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE, CURLOT_OFF_T, 0}, {"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0}, {"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0}, + {"MIME_OPTIONS", CURLOPT_MIME_OPTIONS, CURLOT_LONG, 0}, {"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0}, {"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0}, {"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS, CURLOT_LONG, 0}, @@ -359,6 +360,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (314 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (315 + 1)); } #endif diff --git a/libs/libcurl/src/ftp.c b/libs/libcurl/src/ftp.c index a8d209e3fb..f6921e4262 100644 --- a/libs/libcurl/src/ftp.c +++ b/libs/libcurl/src/ftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -1004,7 +1004,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, } /* parse the port */ - if(ip_end != NULL) { + if(ip_end) { port_start = strchr(ip_end, ':'); if(port_start) { port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10)); @@ -4102,6 +4102,11 @@ static CURLcode ftp_disconnect(struct Curl_easy *data, return CURLE_OK; } +#ifdef _MSC_VER +/* warning C4706: assignment within conditional expression */ +#pragma warning(disable:4706) +#endif + /*********************************************************************** * * ftp_parse_url_path() @@ -4190,7 +4195,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data) } /* parse the URL path into separate path components */ - while((slashPos = strchr(curPos, '/')) != NULL) { + while((slashPos = strchr(curPos, '/'))) { size_t compLen = slashPos - curPos; /* path starts with a slash: add that as a directory */ @@ -4357,7 +4362,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data, struct FTP *ftp; data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1); - if(NULL == ftp) + if(!ftp) return CURLE_OUT_OF_MEMORY; ftp->path = &data->state.up.path[1]; /* don't include the initial slash */ diff --git a/libs/libcurl/src/hash.c b/libs/libcurl/src/hash.c index 12e7aa5f27..8848906947 100644 --- a/libs/libcurl/src/hash.c +++ b/libs/libcurl/src/hash.c @@ -53,32 +53,25 @@ hash_element_dtor(void *user, void *element) * @unittest: 1602 * @unittest: 1603 */ -int +void Curl_hash_init(struct Curl_hash *h, int slots, hash_function hfunc, comp_function comparator, Curl_hash_dtor dtor) { - if(!slots || !hfunc || !comparator ||!dtor) { - return 1; /* failure */ - } + DEBUGASSERT(h); + DEBUGASSERT(slots); + DEBUGASSERT(hfunc); + DEBUGASSERT(comparator); + DEBUGASSERT(dtor); + h->table = NULL; h->hash_func = hfunc; h->comp_func = comparator; h->dtor = dtor; h->size = 0; h->slots = slots; - - h->table = malloc(slots * sizeof(struct Curl_llist)); - if(h->table) { - int i; - for(i = 0; i < slots; ++i) - Curl_llist_init(&h->table[i], (Curl_llist_dtor) hash_element_dtor); - return 0; /* fine */ - } - h->slots = 0; - return 1; /* failure */ } static struct Curl_hash_element * @@ -98,8 +91,9 @@ mk_hash_element(const void *key, size_t key_len, const void *p) #define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)] -/* Insert the data in the hash. If there already was a match in the hash, - * that data is replaced. +/* Insert the data in the hash. If there already was a match in the hash, that + * data is replaced. This function also "lazily" allocates the table if + * needed, as it isn't done in the _init function (anymore). * * @unittest: 1305 * @unittest: 1602 @@ -110,7 +104,20 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p) { struct Curl_hash_element *he; struct Curl_llist_element *le; - struct Curl_llist *l = FETCH_LIST(h, key, key_len); + struct Curl_llist *l; + + DEBUGASSERT(h); + DEBUGASSERT(h->slots); + if(!h->table) { + int i; + h->table = malloc(h->slots * sizeof(struct Curl_llist)); + if(!h->table) + return NULL; /* OOM */ + for(i = 0; i < h->slots; ++i) + Curl_llist_init(&h->table[i], hash_element_dtor); + } + + l = FETCH_LIST(h, key, key_len); for(le = l->head; le; le = le->next) { he = (struct Curl_hash_element *) le->ptr; @@ -139,14 +146,20 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p) int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len) { struct Curl_llist_element *le; - struct Curl_llist *l = FETCH_LIST(h, key, key_len); + struct Curl_llist *l; - for(le = l->head; le; le = le->next) { - struct Curl_hash_element *he = le->ptr; - if(h->comp_func(he->key, he->key_len, key, key_len)) { - Curl_llist_remove(l, le, (void *) h); - --h->size; - return 0; + DEBUGASSERT(h); + DEBUGASSERT(h->slots); + if(h->table) { + l = FETCH_LIST(h, key, key_len); + + for(le = l->head; le; le = le->next) { + struct Curl_hash_element *he = le->ptr; + if(h->comp_func(he->key, he->key_len, key, key_len)) { + Curl_llist_remove(l, le, (void *) h); + --h->size; + return 0; + } } } return 1; @@ -162,7 +175,9 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len) struct Curl_llist_element *le; struct Curl_llist *l; - if(h) { + DEBUGASSERT(h); + if(h->table) { + DEBUGASSERT(h->slots); l = FETCH_LIST(h, key, key_len); for(le = l->head; le; le = le->next) { struct Curl_hash_element *he = le->ptr; @@ -204,13 +219,13 @@ Curl_hash_apply(Curl_hash *h, void *user, void Curl_hash_destroy(struct Curl_hash *h) { - int i; - - for(i = 0; i < h->slots; ++i) { - Curl_llist_destroy(&h->table[i], (void *) h); + if(h->table) { + int i; + for(i = 0; i < h->slots; ++i) { + Curl_llist_destroy(&h->table[i], (void *) h); + } + Curl_safefree(h->table); } - - Curl_safefree(h->table); h->size = 0; h->slots = 0; } @@ -235,7 +250,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user, struct Curl_llist *list; int i; - if(!h) + if(!h || !h->table) return; for(i = 0; i < h->slots; ++i) { @@ -290,6 +305,9 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter) { struct Curl_hash *h = iter->hash; + if(!h->table) + return NULL; /* empty hash, nothing to return */ + /* Get the next element in the current list, if any */ if(iter->current_element) iter->current_element = iter->current_element->next; diff --git a/libs/libcurl/src/hash.h b/libs/libcurl/src/hash.h index b7f828e071..e166916a90 100644 --- a/libs/libcurl/src/hash.h +++ b/libs/libcurl/src/hash.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -69,11 +69,11 @@ struct Curl_hash_iterator { struct Curl_llist_element *current_element; }; -int Curl_hash_init(struct Curl_hash *h, - int slots, - hash_function hfunc, - comp_function comparator, - Curl_hash_dtor dtor); +void Curl_hash_init(struct Curl_hash *h, + int slots, + hash_function hfunc, + comp_function comparator, + Curl_hash_dtor dtor); void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p); int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len); diff --git a/libs/libcurl/src/hostcheck.c b/libs/libcurl/src/hostcheck.c index cf267a7659..cd45bd07ee 100644 --- a/libs/libcurl/src/hostcheck.c +++ b/libs/libcurl/src/hostcheck.c @@ -89,7 +89,7 @@ static int hostmatch(char *hostname, char *pattern) match. */ wildcard_enabled = 1; pattern_label_end = strchr(pattern, '.'); - if(!pattern_label_end || strchr(pattern_label_end + 1, '.') == NULL || + if(!pattern_label_end || !strchr(pattern_label_end + 1, '.') || pattern_wildcard > pattern_label_end || strncasecompare(pattern, "xn--", 4)) { wildcard_enabled = 0; diff --git a/libs/libcurl/src/hostip.c b/libs/libcurl/src/hostip.c index c33c9af9d0..911d5ed6d3 100644 --- a/libs/libcurl/src/hostip.c +++ b/libs/libcurl/src/hostip.c @@ -609,7 +609,11 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */ struct connectdata *conn = data->conn; *entry = NULL; +#ifndef CURL_DISABLE_DOH conn->bits.doh = FALSE; /* default is not */ +#else + (void)allowDOH; +#endif if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); @@ -630,11 +634,15 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, struct Curl_addrinfo *addr = NULL; int respwait = 0; +#if !defined(CURL_DISABLE_DOH) || !defined(USE_RESOLVE_ON_IPS) struct in_addr in; +#endif +#ifndef CURL_DISABLE_DOH #ifndef USE_RESOLVE_ON_IPS const #endif bool ipnum = FALSE; +#endif /* notify the resolver start callback */ if(data->set.resolver_start) { @@ -686,6 +694,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, #endif /* ENABLE_IPV6 */ #else /* if USE_RESOLVE_ON_IPS */ +#ifndef CURL_DISABLE_DOH /* First check if this is an IPv4 address string */ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) /* This is a dotted IP address 123.123.123.123-style */ @@ -699,6 +708,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, ipnum = TRUE; } #endif /* ENABLE_IPV6 */ +#endif /* CURL_DISABLE_DOH */ #endif /* !USE_RESOLVE_ON_IPS */ @@ -708,8 +718,10 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, if(strcasecompare(hostname, "localhost")) addr = get_localhost(port); +#ifndef CURL_DISABLE_DOH else if(allowDOH && data->set.doh && !ipnum) addr = Curl_doh(data, hostname, port, &respwait); +#endif else { /* Check what IP specifics the app has requested and if we can provide * it. If not, bail out. */ @@ -977,12 +989,12 @@ static void freednsentry(void *freethis) } /* - * Curl_mk_dnscache() inits a new DNS cache and returns success/failure. + * Curl_init_dnscache() inits a new DNS cache. */ -int Curl_mk_dnscache(struct Curl_hash *hash) +void Curl_init_dnscache(struct Curl_hash *hash) { - return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, - freednsentry); + Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, + freednsentry); } /* @@ -1210,9 +1222,10 @@ CURLcode Curl_resolv_check(struct Curl_easy *data, #if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH) (void)dns; #endif - +#ifndef CURL_DISABLE_DOH if(data->conn->bits.doh) return Curl_doh_is_resolved(data, dns); +#endif return Curl_resolver_is_resolved(data, dns); } @@ -1220,10 +1233,12 @@ int Curl_resolv_getsock(struct Curl_easy *data, curl_socket_t *socks) { #ifdef CURLRES_ASYNCH +#ifndef CURL_DISABLE_DOH if(data->conn->bits.doh) /* nothing to wait for during DoH resolve, those handles have their own sockets */ return GETSOCK_BLANK; +#endif return Curl_resolver_getsock(data, socks); #else (void)data; diff --git a/libs/libcurl/src/hostip.h b/libs/libcurl/src/hostip.h index 67a688aebd..1db5981842 100644 --- a/libs/libcurl/src/hostip.h +++ b/libs/libcurl/src/hostip.h @@ -129,8 +129,8 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns); -/* init a new dns cache and return success */ -int Curl_mk_dnscache(struct Curl_hash *hash); +/* init a new dns cache */ +void Curl_init_dnscache(struct Curl_hash *hash); /* prune old entries from the DNS cache */ void Curl_hostcache_prune(struct Curl_easy *data); diff --git a/libs/libcurl/src/http.c b/libs/libcurl/src/http.c index 78ad10edea..f08a343e3b 100644 --- a/libs/libcurl/src/http.c +++ b/libs/libcurl/src/http.c @@ -1153,7 +1153,6 @@ static bool http_should_fail(struct Curl_easy *data) return data->state.authproblem; } -#ifndef USE_HYPER /* * readmoredata() is a "fread() emulation" to provide POST and/or request * data. It is used when a huge POST is to be made and the entire chunk wasn't @@ -1412,8 +1411,6 @@ CURLcode Curl_buffer_send(struct dynbuf *in, return result; } -#endif - /* end of the add_buffer functions */ /* ------------------------------------------------------------------------- */ @@ -2375,6 +2372,9 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, #ifndef USE_HYPER /* Hyper always handles the body separately */ curl_off_t included_body = 0; +#else + /* from this point down, this function should not be used */ +#define Curl_buffer_send(a,b,c,d,e) CURLE_OK #endif CURLcode result = CURLE_OK; struct HTTP *http = data->req.p.http; @@ -2685,7 +2685,6 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, /* issue the request */ result = Curl_buffer_send(r, data, &data->info.request_size, 0, FIRSTSOCKET); - if(result) failf(data, "Failed sending HTTP request"); else @@ -3312,7 +3311,7 @@ checkhttpprefix(struct Curl_easy *data, #ifdef CURL_DOES_CONVERSIONS /* convert from the network encoding using a scratch area */ char *scratch = strdup(s); - if(NULL == scratch) { + if(!scratch) { failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } @@ -3352,7 +3351,7 @@ checkrtspprefix(struct Curl_easy *data, #ifdef CURL_DOES_CONVERSIONS /* convert from the network encoding using a scratch area */ char *scratch = strdup(s); - if(NULL == scratch) { + if(!scratch) { failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } @@ -4245,7 +4244,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, The sscanf() line above will also allow zero-prefixed and negative numbers, so we check for that too here. */ - else if(ISDIGIT(digit4) || (k->httpcode < 100)) { + else if(ISDIGIT(digit4) || (nc >= 4 && k->httpcode < 100)) { failf(data, "Unsupported response code in HTTP response"); return CURLE_UNSUPPORTED_PROTOCOL; } diff --git a/libs/libcurl/src/http.h b/libs/libcurl/src/http.h index cb5b56faf3..b4aaba2a26 100644 --- a/libs/libcurl/src/http.h +++ b/libs/libcurl/src/http.h @@ -54,15 +54,11 @@ char *Curl_copy_header_value(const char *header); char *Curl_checkProxyheaders(struct Curl_easy *data, const struct connectdata *conn, const char *thisheader); -#ifndef USE_HYPER CURLcode Curl_buffer_send(struct dynbuf *in, struct Curl_easy *data, curl_off_t *bytes_written, curl_off_t included_body_bytes, int socketindex); -#else -#define Curl_buffer_send(a,b,c,d,e) CURLE_OK -#endif CURLcode Curl_add_timecondition(struct Curl_easy *data, #ifndef USE_HYPER diff --git a/libs/libcurl/src/http2.c b/libs/libcurl/src/http2.c index 992fbbb26d..e74400a4ca 100644 --- a/libs/libcurl/src/http2.c +++ b/libs/libcurl/src/http2.c @@ -505,10 +505,13 @@ static int set_transfer_url(struct Curl_easy *data, struct curl_pushheaders *hp) { const char *v; - CURLU *u = curl_url(); CURLUcode uc; char *url = NULL; int rc = 0; + CURLU *u = curl_url(); + + if(!u) + return 5; v = curl_pushheader_byname(hp, ":scheme"); if(v) { diff --git a/libs/libcurl/src/http_aws_sigv4.c b/libs/libcurl/src/http_aws_sigv4.c index cbbecb7129..751e5af5f9 100644 --- a/libs/libcurl/src/http_aws_sigv4.c +++ b/libs/libcurl/src/http_aws_sigv4.c @@ -286,8 +286,11 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) post_data_len = strlen(post_data); else post_data_len = (size_t)data->set.postfieldsize; - Curl_sha256it(sha_hash, - (const unsigned char *) post_data, post_data_len); + if(Curl_sha256it(sha_hash, (const unsigned char *) post_data, + post_data_len)) { + goto fail; + } + sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); Curl_http_method(data, conn, &method, &httpreq); @@ -320,8 +323,11 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) goto fail; } - Curl_sha256it(sha_hash, (unsigned char *) canonical_request, - strlen(canonical_request)); + if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request, + strlen(canonical_request))) { + goto fail; + } + sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); /* diff --git a/libs/libcurl/src/http_proxy.c b/libs/libcurl/src/http_proxy.c index fc050a07d5..e13f485a73 100644 --- a/libs/libcurl/src/http_proxy.c +++ b/libs/libcurl/src/http_proxy.c @@ -158,6 +158,10 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit) { struct http_connect_state *s; struct connectdata *conn = data->conn; + if(conn->handler->flags & PROTOPT_NOTCPPROXY) { + failf(data, "%s cannot be done over CONNECT", conn->handler->scheme); + return CURLE_UNSUPPORTED_PROTOCOL; + } if(!reinit) { CURLcode result; DEBUGASSERT(!conn->connect_state); @@ -198,17 +202,18 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit) return CURLE_OK; } -static void connect_done(struct Curl_easy *data) +void Curl_connect_done(struct Curl_easy *data) { struct connectdata *conn = data->conn; struct http_connect_state *s = conn->connect_state; - if(s->tunnel_state != TUNNEL_EXIT) { + if(s && (s->tunnel_state != TUNNEL_EXIT)) { s->tunnel_state = TUNNEL_EXIT; Curl_dyn_free(&s->rcvbuf); Curl_dyn_free(&s->req); - /* restore the protocol pointer */ - data->req.p.http = s->prot_save; + /* restore the protocol pointer, if not already done */ + if(s->prot_save) + data->req.p.http = s->prot_save; s->prot_save = NULL; data->info.httpcode = 0; /* clear it as it might've been used for the proxy */ @@ -662,15 +667,13 @@ static CURLcode CONNECT(struct Curl_easy *data, if(s->close_connection && data->req.newurl) { conn->bits.proxy_connect_closed = TRUE; infof(data, "Connect me again please"); - connect_done(data); + Curl_connect_done(data); } else { free(data->req.newurl); data->req.newurl = NULL; /* failure, close this connection to avoid re-use */ streamclose(conn, "proxy CONNECT failure"); - Curl_closesocket(data, conn, conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; } /* to back to init state */ @@ -974,7 +977,7 @@ static CURLcode CONNECT(struct Curl_easy *data, if(conn->bits.close && data->req.newurl) { conn->bits.proxy_connect_closed = TRUE; infof(data, "Connect me again please"); - connect_done(data); + Curl_connect_done(data); } else { free(data->req.newurl); @@ -1048,7 +1051,7 @@ CURLcode Curl_proxyCONNECT(struct Curl_easy *data, result = CONNECT(data, sockindex, hostname, remote_port); if(result || Curl_connect_complete(conn)) - connect_done(data); + Curl_connect_done(data); return result; } diff --git a/libs/libcurl/src/http_proxy.h b/libs/libcurl/src/http_proxy.h index cdf8de4fba..2820e11841 100644 --- a/libs/libcurl/src/http_proxy.h +++ b/libs/libcurl/src/http_proxy.h @@ -39,6 +39,7 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex); bool Curl_connect_complete(struct connectdata *conn); bool Curl_connect_ongoing(struct connectdata *conn); int Curl_connect_getsock(struct connectdata *conn); +void Curl_connect_done(struct Curl_easy *data); #else #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN @@ -46,10 +47,10 @@ int Curl_connect_getsock(struct connectdata *conn); #define Curl_connect_complete(x) CURLE_OK #define Curl_connect_ongoing(x) FALSE #define Curl_connect_getsock(x) 0 +#define Curl_connect_done(x) #endif void Curl_connect_free(struct Curl_easy *data); -void Curl_connect_done(struct Curl_easy *data); /* struct for HTTP CONNECT state data */ struct http_connect_state { diff --git a/libs/libcurl/src/if2ip.c b/libs/libcurl/src/if2ip.c index 21e00b1f16..132b3eeeea 100644 --- a/libs/libcurl/src/if2ip.c +++ b/libs/libcurl/src/if2ip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -114,7 +114,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, if(getifaddrs(&head) >= 0) { for(iface = head; iface != NULL; iface = iface->ifa_next) { - if(iface->ifa_addr != NULL) { + if(iface->ifa_addr) { if(iface->ifa_addr->sa_family == af) { if(strcasecompare(iface->ifa_name, interf)) { void *addr; diff --git a/libs/libcurl/src/imap.c b/libs/libcurl/src/imap.c index bea964f79a..958ad1456c 100644 --- a/libs/libcurl/src/imap.c +++ b/libs/libcurl/src/imap.c @@ -329,7 +329,7 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn, /* Do we have a continuation response? This should be a + symbol followed by a space and optionally some text as per RFC-3501 for the AUTHENTICATE and APPEND commands and as outlined in Section 4. Examples of RFC-4959 but - some e-mail servers ignore this and only send a single + instead. */ + some email servers ignore this and only send a single + instead. */ if(imap && !imap->custom && ((len == 3 && line[0] == '+') || (len >= 2 && !memcmp("+ ", line, 2)))) { switch(imapc->state) { diff --git a/libs/libcurl/src/inet_pton.c b/libs/libcurl/src/inet_pton.c index 4923cae245..ada57af289 100644 --- a/libs/libcurl/src/inet_pton.c +++ b/libs/libcurl/src/inet_pton.c @@ -1,6 +1,6 @@ /* This is from the BIND 4.9.4 release, modified to compile by itself */ -/* Copyright (c) 1996 - 2020 by Internet Software Consortium. +/* Copyright (c) 1996 - 2021 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -174,7 +174,7 @@ inet_pton6(const char *src, unsigned char *dst) pch = strchr((xdigits = xdigits_l), ch); if(!pch) pch = strchr((xdigits = xdigits_u), ch); - if(pch != NULL) { + if(pch) { val <<= 4; val |= (pch - xdigits); if(++saw_xdigit > 4) @@ -211,7 +211,7 @@ inet_pton6(const char *src, unsigned char *dst) *tp++ = (unsigned char) ((val >> 8) & 0xff); *tp++ = (unsigned char) (val & 0xff); } - if(colonp != NULL) { + if(colonp) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. diff --git a/libs/libcurl/src/krb5.c b/libs/libcurl/src/krb5.c index afe425b046..5edd34cbdf 100644 --- a/libs/libcurl/src/krb5.c +++ b/libs/libcurl/src/krb5.c @@ -880,7 +880,7 @@ Curl_sec_login(struct Curl_easy *data, struct connectdata *conn) void Curl_sec_end(struct connectdata *conn) { - if(conn->mech != NULL && conn->mech->end) + if(conn->mech && conn->mech->end) conn->mech->end(conn->app_data); free(conn->app_data); conn->app_data = NULL; diff --git a/libs/libcurl/src/ldap.c b/libs/libcurl/src/ldap.c index 1d9e44cc9c..3154db5cf0 100644 --- a/libs/libcurl/src/ldap.c +++ b/libs/libcurl/src/ldap.c @@ -464,6 +464,11 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #endif #endif /* CURL_LDAP_USE_SSL */ } + else if(data->set.use_ssl > CURLUSESSL_TRY) { + failf(data, "LDAP local: explicit TLS not supported"); + result = CURLE_NOT_BUILT_IN; + goto quit; + } else { server = ldap_init(host, (int)conn->port); if(!server) { @@ -590,7 +595,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) attr_len = strlen(attr); vals = ldap_get_values_len(server, entryIterator, attribute); - if(vals != NULL) { + if(vals) { for(i = 0; (vals[i] != NULL); i++) { result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1); if(result) { diff --git a/libs/libcurl/src/libcurl.plist b/libs/libcurl/src/libcurl.plist index daf485621b..0e5311b5a4 100644 --- a/libs/libcurl/src/libcurl.plist +++ b/libs/libcurl/src/libcurl.plist @@ -15,7 +15,7 @@ <string>se.curl.libcurl</string> <key>CFBundleVersion</key> - <string>7.80.0</string> + <string>7.81.0</string> <key>CFBundleName</key> <string>libcurl</string> @@ -27,9 +27,9 @@ <string>????</string> <key>CFBundleShortVersionString</key> - <string>libcurl 7.80.0</string> + <string>libcurl 7.81.0</string> <key>CFBundleGetInfoString</key> - <string>libcurl.plist 7.80.0</string> + <string>libcurl.plist 7.81.0</string> </dict> </plist> diff --git a/libs/libcurl/src/md4.c b/libs/libcurl/src/md4.c index d90e45475c..117cce4fd9 100644 --- a/libs/libcurl/src/md4.c +++ b/libs/libcurl/src/md4.c @@ -189,7 +189,7 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { if(!ctx->data) { ctx->data = malloc(size); - if(ctx->data != NULL) { + if(ctx->data) { memcpy(ctx->data, data, size); ctx->size = size; } @@ -198,7 +198,7 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { - if(ctx->data != NULL) { + if(ctx->data) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_md4(ctx->data, ctx->size, result); #else diff --git a/libs/libcurl/src/md5.c b/libs/libcurl/src/md5.c index 810c5fba8e..c6923e036b 100644 --- a/libs/libcurl/src/md5.c +++ b/libs/libcurl/src/md5.c @@ -62,9 +62,10 @@ typedef struct md5_ctx MD5_CTX; -static void MD5_Init(MD5_CTX *ctx) +static CURLcode MD5_Init(MD5_CTX *ctx) { md5_init(ctx); + return CURLE_OK; } static void MD5_Update(MD5_CTX *ctx, @@ -98,13 +99,14 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) typedef mbedtls_md5_context MD5_CTX; -static void MD5_Init(MD5_CTX *ctx) +static CURLcode MD5_Init(MD5_CTX *ctx) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) (void) mbedtls_md5_starts(ctx); #else (void) mbedtls_md5_starts_ret(ctx); #endif + return CURLE_OK; } static void MD5_Update(MD5_CTX *ctx, @@ -146,9 +148,10 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) /* The last #include file should be: */ #include "memdebug.h" -static void MD5_Init(MD5_CTX *ctx) +static CURLcode MD5_Init(MD5_CTX *ctx) { CC_MD5_Init(ctx); + return CURLE_OK; } static void MD5_Update(MD5_CTX *ctx, @@ -176,12 +179,13 @@ struct md5_ctx { }; typedef struct md5_ctx MD5_CTX; -static void MD5_Init(MD5_CTX *ctx) +static CURLcode MD5_Init(MD5_CTX *ctx) { if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); } + return CURLE_OK; } static void MD5_Update(MD5_CTX *ctx, @@ -261,7 +265,7 @@ struct md5_ctx { }; typedef struct md5_ctx MD5_CTX; -static void MD5_Init(MD5_CTX *ctx); +static CURLcode MD5_Init(MD5_CTX *ctx); static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); static void MD5_Final(unsigned char *result, MD5_CTX *ctx); @@ -422,7 +426,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) return ptr; } -static void MD5_Init(MD5_CTX *ctx) +static CURLcode MD5_Init(MD5_CTX *ctx) { ctx->a = 0x67452301; ctx->b = 0xefcdab89; @@ -431,6 +435,8 @@ static void MD5_Init(MD5_CTX *ctx) ctx->lo = 0; ctx->hi = 0; + + return CURLE_OK; } static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) @@ -555,8 +561,9 @@ const struct MD5_params Curl_DIGEST_MD5[] = { /* * @unittest: 1601 + * Returns CURLE_OK on success. */ -void Curl_md5it(unsigned char *outbuffer, const unsigned char *input, +CURLcode Curl_md5it(unsigned char *outbuffer, const unsigned char *input, const size_t len) { MD5_CTX ctx; @@ -564,6 +571,8 @@ void Curl_md5it(unsigned char *outbuffer, const unsigned char *input, MD5_Init(&ctx); MD5_Update(&ctx, input, curlx_uztoui(len)); MD5_Final(outbuffer, &ctx); + + return CURLE_OK; } struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params) diff --git a/libs/libcurl/src/mime.c b/libs/libcurl/src/mime.c index f40cc1a618..7783b8990a 100644 --- a/libs/libcurl/src/mime.c +++ b/libs/libcurl/src/mime.c @@ -40,6 +40,7 @@ #include "rand.h" #include "slist.h" #include "strcase.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -279,29 +280,52 @@ static void mimesetstate(struct mime_state *state, /* Escape header string into allocated memory. */ -static char *escape_string(const char *src) -{ - size_t bytecount = 0; - size_t i; - char *dst; +static char *escape_string(struct Curl_easy *data, + const char *src, enum mimestrategy strategy) +{ + CURLcode result; + struct dynbuf db; + const char * const *table; + const char * const *p; + /* replace first character by rest of string. */ + static const char * const mimetable[] = { + "\\\\\\", + "\"\\\"", + NULL + }; + /* WHATWG HTML living standard 4.10.21.8 2 specifies: + For field names and filenames for file fields, the result of the + encoding in the previous bullet point must be escaped by replacing + any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D` + and 0x22 (") with `%22`. + The user agent must not perform any other escapes. */ + static const char * const formtable[] = { + "\"%22", + "\r%0D", + "\n%0A", + NULL + }; - for(i = 0; src[i]; i++) - if(src[i] == '"' || src[i] == '\\') - bytecount++; + table = formtable; + /* data can be NULL when this function is called indirectly from + curl_formget(). */ + if(strategy == MIMESTRATEGY_MAIL || + (data && (data->set.mime_options & CURLMIMEOPT_FORMESCAPE))) + table = mimetable; - bytecount += i; - dst = malloc(bytecount + 1); - if(!dst) - return NULL; + Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH); - for(i = 0; *src; src++) { - if(*src == '"' || *src == '\\') - dst[i++] = '\\'; - dst[i++] = *src; + for(result = Curl_dyn_add(&db, ""); !result && *src; src++) { + for(p = table; *p && **p != *src; p++) + ; + + if(*p) + result = Curl_dyn_add(&db, *p + 1); + else + result = Curl_dyn_addn(&db, src, 1); } - dst[i] = '\0'; - return dst; + return Curl_dyn_ptr(&db); } /* Check if header matches. */ @@ -1866,12 +1890,12 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part, char *filename = NULL; if(part->name) { - name = escape_string(part->name); + name = escape_string(part->easy, part->name, strategy); if(!name) ret = CURLE_OUT_OF_MEMORY; } if(!ret && part->filename) { - filename = escape_string(part->filename); + filename = escape_string(part->easy, part->filename, strategy); if(!filename) ret = CURLE_OUT_OF_MEMORY; } diff --git a/libs/libcurl/src/mprintf.c b/libs/libcurl/src/mprintf.c index 7a1aec570e..0fd3afc8ae 100644 --- a/libs/libcurl/src/mprintf.c +++ b/libs/libcurl/src/mprintf.c @@ -858,7 +858,7 @@ static int dprintf_formatf( { void *ptr; ptr = (void *) p->data.ptr; - if(ptr != NULL) { + if(ptr) { /* If the pointer is not NULL, write it as a %#x spec. */ base = 16; digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c index f307d63b93..f8dcc63b47 100644 --- a/libs/libcurl/src/multi.c +++ b/libs/libcurl/src/multi.c @@ -243,6 +243,26 @@ static void trhash_dtor(void *nada) (void)nada; } +/* + * The sockhash has its own separate subhash in each entry that need to be + * safely destroyed first. + */ +static void sockhash_destroy(struct Curl_hash *h) +{ + struct Curl_hash_iterator iter; + struct Curl_hash_element *he; + + DEBUGASSERT(h); + Curl_hash_start_iterate(h, &iter); + he = Curl_hash_next_element(&iter); + while(he) { + struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr; + Curl_hash_destroy(&sh->transfers); + he = Curl_hash_next_element(&iter); + } + Curl_hash_destroy(h); +} + /* make sure this socket is present in the hash for this handle */ static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh, @@ -261,11 +281,8 @@ static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh, if(!check) return NULL; /* major failure */ - if(Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, - trhash_compare, trhash_dtor)) { - free(check); - return NULL; - } + Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare, + trhash_dtor); /* make/add new hash entry */ if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { @@ -332,10 +349,10 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num) * per call." * */ -static int sh_init(struct Curl_hash *hash, int hashsize) +static void sh_init(struct Curl_hash *hash, int hashsize) { - return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare, - sh_freeentry); + Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare, + sh_freeentry); } /* @@ -362,11 +379,9 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ multi->magic = CURL_MULTI_HANDLE; - if(Curl_mk_dnscache(&multi->hostcache)) - goto error; + Curl_init_dnscache(&multi->hostcache); - if(sh_init(&multi->sockhash, hashsize)) - goto error; + sh_init(&multi->sockhash, hashsize); if(Curl_conncache_init(&multi->conn_cache, chashsize)) goto error; @@ -405,7 +420,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ error: - Curl_hash_destroy(&multi->sockhash); + sockhash_destroy(&multi->sockhash); Curl_hash_destroy(&multi->hostcache); Curl_conncache_destroy(&multi->conn_cache); Curl_llist_destroy(&multi->msglist, NULL); @@ -424,6 +439,7 @@ struct Curl_multi *curl_multi_init(void) CURLMcode curl_multi_add_handle(struct Curl_multi *multi, struct Curl_easy *data) { + CURLMcode rc; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -440,6 +456,15 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + if(multi->dead) { + /* a "dead" handle cannot get added transfers while any existing easy + handles are still alive - but if there are none alive anymore, it is + fine to start over and unmark the "deadness" of this handle */ + if(multi->num_alive) + return CURLM_ABORTED_BY_CALLBACK; + multi->dead = FALSE; + } + /* Initialize timeout list for this handle */ Curl_llist_init(&data->state.timeoutlist, NULL); @@ -452,6 +477,34 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, if(data->set.errorbuffer) data->set.errorbuffer[0] = 0; + /* make the Curl_easy refer back to this multi handle - before Curl_expire() + is called. */ + data->multi = multi; + + /* Set the timeout for this handle to expire really soon so that it will + be taken care of even when this handle is added in the midst of operation + when only the curl_multi_socket() API is used. During that flow, only + sockets that time-out or have actions will be dealt with. Since this + handle has no action yet, we make sure it times out to get things to + happen. */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + /* A somewhat crude work-around for a little glitch in Curl_update_timer() + that happens if the lastcall time is set to the same time when the handle + is removed as when the next handle is added, as then the check in + Curl_update_timer() that prevents calling the application multiple times + with the same timer info will not trigger and then the new handle's + timeout will not be notified to the app. + + The work-around is thus simply to clear the 'lastcall' variable to force + Curl_update_timer() to always trigger a callback to the app when a new + easy handle is added */ + memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + + rc = Curl_update_timer(multi); + if(rc) + return rc; + /* set the easy handle */ multistate(data, MSTATE_INIT); @@ -492,35 +545,12 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, multi->easylp = multi->easyp = data; /* both first and last */ } - /* make the Curl_easy refer back to this multi handle */ - data->multi = multi; - - /* Set the timeout for this handle to expire really soon so that it will - be taken care of even when this handle is added in the midst of operation - when only the curl_multi_socket() API is used. During that flow, only - sockets that time-out or have actions will be dealt with. Since this - handle has no action yet, we make sure it times out to get things to - happen. */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); - /* increase the node-counter */ multi->num_easy++; /* increase the alive-counter */ multi->num_alive++; - /* A somewhat crude work-around for a little glitch in Curl_update_timer() - that happens if the lastcall time is set to the same time when the handle - is removed as when the next handle is added, as then the check in - Curl_update_timer() that prevents calling the application multiple times - with the same timer info will not trigger and then the new handle's - timeout will not be notified to the app. - - The work-around is thus simply to clear the 'lastcall' variable to force - Curl_update_timer() to always trigger a callback to the app when a new - easy handle is added */ - memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); - CONNCACHE_LOCK(data); /* The closure handle only ever has default timeouts set. To improve the state somewhat we clone the timeouts from each added handle so that the @@ -533,14 +563,13 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, data->set.no_signal; CONNCACHE_UNLOCK(data); - Curl_update_timer(multi); return CURLM_OK; } #if 0 /* Debug-function, used like this: * - * Curl_hash_print(multi->sockhash, debug_print_sock_hash); + * Curl_hash_print(&multi->sockhash, debug_print_sock_hash); * * Enable the hash print function first by editing hash.c */ @@ -548,8 +577,8 @@ static void debug_print_sock_hash(void *p) { struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; - fprintf(stderr, " [easy %p/magic %x/socket %d]", - (void *)sh->data, sh->data->magic, (int)sh->socket); + fprintf(stderr, " [readers %u][writers %u]", + sh->readers, sh->writers); } #endif @@ -562,7 +591,8 @@ static CURLcode multi_done(struct Curl_easy *data, struct connectdata *conn = data->conn; unsigned int i; - DEBUGF(infof(data, "multi_done")); + DEBUGF(infof(data, "multi_done: status: %d prem: %d done: %d", + (int)status, (int)premature, data->state.done)); if(data->state.done) /* Stop if multi_done() has already been called */ @@ -719,6 +749,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, struct Curl_easy *easy = data; bool premature; struct Curl_llist_element *e; + CURLMcode rc; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) @@ -792,8 +823,11 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* change state without using multistate(), only to make singlesocket() do what we want */ data->mstate = MSTATE_COMPLETED; - singlesocket(multi, easy); /* to let the application know what sockets that - vanish with this handle */ + + /* This ignores the return code even in case of problems because there's + nothing more to do about that, here */ + (void)singlesocket(multi, easy); /* to let the application know what sockets + that vanish with this handle */ /* Remove the association between the connection and the handle */ Curl_detach_connnection(data); @@ -858,7 +892,9 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, process_pending_handles(multi); - Curl_update_timer(multi); + rc = Curl_update_timer(multi); + if(rc) + return rc; return CURLM_OK; } @@ -878,6 +914,7 @@ void Curl_detach_connnection(struct Curl_easy *data) { struct connectdata *conn = data->conn; if(conn) { + Curl_connect_done(data); /* if mid-CONNECT, shut it down */ Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL); Curl_ssl_detach_conn(data, conn); } @@ -1742,6 +1779,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; + if(multi->dead) { + /* a multi-level callback returned error before, meaning every individual + transfer now has failed */ + result = CURLE_ABORTED_BY_CALLBACK; + Curl_posttransfer(data); + multi_done(data, result, FALSE); + multistate(data, MSTATE_COMPLETED); + } + do { /* A "stream" here is a logical stream if the protocol can handle that (HTTP/2), or the full connection for older protocols */ @@ -1892,7 +1938,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, down. If the name has not yet been resolved, it is likely that new sockets have been opened in an attempt to contact another resolver. */ - singlesocket(multi, data); + rc = singlesocket(multi, data); + if(rc) + return rc; if(dns) { /* Perform the next step in the connection phase, and then move on @@ -2617,7 +2665,7 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) *running_handles = multi->num_alive; if(CURLM_OK >= returncode) - Curl_update_timer(multi); + returncode = Curl_update_timer(multi); return returncode; } @@ -2662,7 +2710,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) /* Close all the connections in the connection cache */ Curl_conncache_close_all_connections(&multi->conn_cache); - Curl_hash_destroy(&multi->sockhash); + sockhash_destroy(&multi->sockhash); Curl_conncache_destroy(&multi->conn_cache); Curl_llist_destroy(&multi->msglist, NULL); Curl_llist_destroy(&multi->pending, NULL); @@ -2737,6 +2785,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi, int num; unsigned int curraction; unsigned char actions[MAX_SOCKSPEREASYHANDLE]; + int rc; for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) socks[i] = CURL_SOCKET_BAD; @@ -2808,8 +2857,10 @@ static CURLMcode singlesocket(struct Curl_multi *multi, /* add 'data' to the transfer hash on this socket! */ if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */ - sizeof(struct Curl_easy *), data)) + sizeof(struct Curl_easy *), data)) { + Curl_hash_destroy(&entry->transfers); return CURLM_OUT_OF_MEMORY; + } } comboaction = (entry->writers? CURL_POLL_OUT : 0) | @@ -2820,9 +2871,14 @@ static CURLMcode singlesocket(struct Curl_multi *multi, /* same, continue */ continue; - if(multi->socket_cb) - multi->socket_cb(data, s, comboaction, multi->socket_userp, - entry->socketp); + if(multi->socket_cb) { + rc = multi->socket_cb(data, s, comboaction, multi->socket_userp, + entry->socketp); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + } entry->action = comboaction; /* store the current action state */ } @@ -2857,10 +2913,14 @@ static CURLMcode singlesocket(struct Curl_multi *multi, if(oldactions & CURL_POLL_IN) entry->readers--; if(!entry->users) { - if(multi->socket_cb) - multi->socket_cb(data, s, CURL_POLL_REMOVE, - multi->socket_userp, - entry->socketp); + if(multi->socket_cb) { + rc = multi->socket_cb(data, s, CURL_POLL_REMOVE, + multi->socket_userp, entry->socketp); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + } sh_delentry(entry, &multi->sockhash, s); } else { @@ -2879,9 +2939,11 @@ static CURLMcode singlesocket(struct Curl_multi *multi, return CURLM_OK; } -void Curl_updatesocket(struct Curl_easy *data) +CURLcode Curl_updatesocket(struct Curl_easy *data) { - singlesocket(data->multi, data); + if(singlesocket(data->multi, data)) + return CURLE_ABORTED_BY_CALLBACK; + return CURLE_OK; } @@ -2906,13 +2968,18 @@ void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s) struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); if(entry) { + int rc = 0; if(multi->socket_cb) - multi->socket_cb(data, s, CURL_POLL_REMOVE, - multi->socket_userp, - entry->socketp); + rc = multi->socket_cb(data, s, CURL_POLL_REMOVE, + multi->socket_userp, entry->socketp); /* now remove it from the socket hash */ sh_delentry(entry, &multi->sockhash, s); + if(rc == -1) + /* This just marks the multi handle as "dead" without returning an + error code primarily because this function is used from many + places where propagating an error back is tricky. */ + multi->dead = TRUE; } } } @@ -3172,7 +3239,7 @@ CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s, return CURLM_RECURSIVE_API_CALL; result = multi_socket(multi, FALSE, s, 0, running_handles); if(CURLM_OK >= result) - Curl_update_timer(multi); + result = Curl_update_timer(multi); return result; } @@ -3184,7 +3251,7 @@ CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s, return CURLM_RECURSIVE_API_CALL; result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles); if(CURLM_OK >= result) - Curl_update_timer(multi); + result = Curl_update_timer(multi); return result; } @@ -3195,7 +3262,7 @@ CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles) return CURLM_RECURSIVE_API_CALL; result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles); if(CURLM_OK >= result) - Curl_update_timer(multi); + result = Curl_update_timer(multi); return result; } @@ -3204,6 +3271,11 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, { static const struct curltime tv_zero = {0, 0}; + if(multi->dead) { + *timeout_ms = 0; + return CURLM_OK; + } + if(multi->timetree) { /* we have a tree of expire times */ struct curltime now = Curl_now(); @@ -3255,14 +3327,15 @@ CURLMcode curl_multi_timeout(struct Curl_multi *multi, * Tell the application it should update its timers, if it subscribes to the * update timer callback. */ -void Curl_update_timer(struct Curl_multi *multi) +CURLMcode Curl_update_timer(struct Curl_multi *multi) { long timeout_ms; + int rc; - if(!multi->timer_cb) - return; + if(!multi->timer_cb || multi->dead) + return CURLM_OK; if(multi_timeout(multi, &timeout_ms)) { - return; + return CURLM_OK; } if(timeout_ms < 0) { static const struct curltime none = {0, 0}; @@ -3270,10 +3343,14 @@ void Curl_update_timer(struct Curl_multi *multi) multi->timer_lastcall = none; /* there's no timeout now but there was one previously, tell the app to disable it */ - multi->timer_cb(multi, -1, multi->timer_userp); - return; + rc = multi->timer_cb(multi, -1, multi->timer_userp); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + return CURLM_OK; } - return; + return CURLM_OK; } /* When multi_timeout() is done, multi->timetree points to the node with the @@ -3281,11 +3358,16 @@ void Curl_update_timer(struct Curl_multi *multi) * if this is the same (fixed) time as we got in a previous call and then * avoid calling the callback again. */ if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0) - return; + return CURLM_OK; multi->timer_lastcall = multi->timetree->key; - multi->timer_cb(multi, timeout_ms, multi->timer_userp); + rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + return CURLM_OK; } /* diff --git a/libs/libcurl/src/multihandle.h b/libs/libcurl/src/multihandle.h index 2e4a6ffba5..db7f130efd 100644 --- a/libs/libcurl/src/multihandle.h +++ b/libs/libcurl/src/multihandle.h @@ -156,6 +156,8 @@ struct Curl_multi { #ifdef USE_OPENSSL bool ssl_seeded; #endif + bool dead; /* a callback returned error, everything needs to crash and + burn */ }; #endif /* HEADER_CURL_MULTIHANDLE_H */ diff --git a/libs/libcurl/src/multiif.h b/libs/libcurl/src/multiif.h index 2fbef53c48..f4d0ada8e8 100644 --- a/libs/libcurl/src/multiif.h +++ b/libs/libcurl/src/multiif.h @@ -26,11 +26,11 @@ * Prototypes for library-wide functions provided by multi.c */ -void Curl_updatesocket(struct Curl_easy *data); +CURLcode Curl_updatesocket(struct Curl_easy *data); void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id); void Curl_expire_clear(struct Curl_easy *data); void Curl_expire_done(struct Curl_easy *data, expire_id id); -void Curl_update_timer(struct Curl_multi *multi); +CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT; void Curl_attach_connnection(struct Curl_easy *data, struct connectdata *conn); void Curl_detach_connnection(struct Curl_easy *data); diff --git a/libs/libcurl/src/openldap.c b/libs/libcurl/src/openldap.c index fb5e743c27..0ffb6a36a2 100644 --- a/libs/libcurl/src/openldap.c +++ b/libs/libcurl/src/openldap.c @@ -70,6 +70,17 @@ */ /* #define CURL_OPENLDAP_DEBUG */ +/* Machine states. */ +typedef enum { + OLDAP_STOP, /* Do nothing state, stops the state machine */ + OLDAP_SSL, /* Performing SSL handshake. */ + OLDAP_STARTTLS, /* STARTTLS request sent. */ + OLDAP_TLS, /* Performing TLS handshake. */ + OLDAP_BIND, /* Simple bind reply. */ + OLDAP_BINDV2, /* Simple bind reply in protocol version 2. */ + OLDAP_LAST /* Never used */ +} ldapstate; + #ifndef _LDAP_PVT_H extern int ldap_pvt_url_scheme2proto(const char *); extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, @@ -143,29 +154,13 @@ const struct Curl_handler Curl_handler_ldaps = { }; #endif -static const char *url_errs[] = { - "success", - "out of memory", - "bad parameter", - "unrecognized scheme", - "unbalanced delimiter", - "bad URL", - "bad host or port", - "bad or missing attributes", - "bad or missing scope", - "bad or missing filter", - "bad or missing extensions" -}; - struct ldapconninfo { - LDAP *ld; - Curl_recv *recv; /* for stacking SSL handler */ + LDAP *ld; /* Openldap connection handle. */ + Curl_recv *recv; /* For stacking SSL handler */ Curl_send *send; - int proto; - int msgid; - bool ssldone; - bool sslinst; - bool didbind; + ldapstate state; /* Current machine state. */ + int proto; /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */ + int msgid; /* Current message id. */ }; struct ldapreqinfo { @@ -173,194 +168,379 @@ struct ldapreqinfo { int nument; }; -static CURLcode oldap_setup_connection(struct Curl_easy *data, - struct connectdata *conn) +/* + * state() + * + * This is the ONLY way to change LDAP state! + */ +static void state(struct Curl_easy *data, ldapstate newstate) { - struct ldapconninfo *li; - LDAPURLDesc *lud; - int rc, proto; - CURLcode status; + struct ldapconninfo *ldapc = data->conn->proto.ldapc; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[] = { + "STOP", + "SSL", + "STARTTLS", + "TLS", + "BIND", + "BINDV2", + /* LAST */ + }; + + if(ldapc->state != newstate) + infof(data, "LDAP %p state change from %s to %s", + (void *)ldapc, names[ldapc->state], names[newstate]); +#endif + + ldapc->state = newstate; +} - rc = ldap_url_parse(data->state.url, &lud); +/* Map some particular LDAP error codes to CURLcode values. */ +static CURLcode oldap_map_error(int rc, CURLcode result) +{ + switch(rc) { + case LDAP_NO_MEMORY: + result = CURLE_OUT_OF_MEMORY; + break; + case LDAP_INVALID_CREDENTIALS: + result = CURLE_LOGIN_DENIED; + break; + case LDAP_PROTOCOL_ERROR: + result = CURLE_UNSUPPORTED_PROTOCOL; + break; + case LDAP_INSUFFICIENT_ACCESS: + result = CURLE_REMOTE_ACCESS_DENIED; + break; + } + return result; +} + +static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp) +{ + CURLcode result = CURLE_OK; + int rc = LDAP_URL_ERR_BADURL; + static const char * const url_errs[] = { + "success", + "out of memory", + "bad parameter", + "unrecognized scheme", + "unbalanced delimiter", + "bad URL", + "bad host or port", + "bad or missing attributes", + "bad or missing scope", + "bad or missing filter", + "bad or missing extensions" + }; + + *ludp = NULL; + if(!data->state.up.user && !data->state.up.password && + !data->state.up.options) + rc = ldap_url_parse(data->state.url, ludp); if(rc != LDAP_URL_SUCCESS) { const char *msg = "url parsing problem"; - status = CURLE_URL_MALFORMAT; - if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { - if(rc == LDAP_URL_ERR_MEM) - status = CURLE_OUT_OF_MEMORY; + + result = rc == LDAP_URL_ERR_MEM? CURLE_OUT_OF_MEMORY: CURLE_URL_MALFORMAT; + rc -= LDAP_URL_SUCCESS; + if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0])) msg = url_errs[rc]; - } failf(data, "LDAP local: %s", msg); - return status; } - proto = ldap_pvt_url_scheme2proto(lud->lud_scheme); + return result; +} + +static CURLcode oldap_setup_connection(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + LDAPURLDesc *lud; + struct ldapconninfo *li; + + /* Early URL syntax check. */ + result = oldap_url_parse(data, &lud); ldap_free_urldesc(lud); - li = calloc(1, sizeof(struct ldapconninfo)); - if(!li) - return CURLE_OUT_OF_MEMORY; - li->proto = proto; - conn->proto.ldapc = li; - connkeep(conn, "OpenLDAP default"); - return CURLE_OK; + if(!result) { + li = calloc(1, sizeof(struct ldapconninfo)); + if(!li) + result = CURLE_OUT_OF_MEMORY; + else { + li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme); + conn->proto.ldapc = li; + connkeep(conn, "OpenLDAP default"); + + /* Clear the TLS upgraded flag */ + conn->bits.tls_upgraded = FALSE; + } + } + + return result; +} + +/* Starts LDAP simple bind. */ +static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + char *binddn = NULL; + struct berval passwd; + int rc; + + passwd.bv_val = NULL; + passwd.bv_len = 0; + + if(conn->bits.user_passwd) { + binddn = conn->user; + passwd.bv_val = conn->passwd; + passwd.bv_len = strlen(passwd.bv_val); + } + + rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd, + NULL, NULL, &li->msgid); + if(rc == LDAP_SUCCESS) + state(data, newstate); + else + result = oldap_map_error(rc, + conn->bits.user_passwd? + CURLE_LOGIN_DENIED: CURLE_LDAP_CANNOT_BIND); + return result; } #ifdef USE_SSL static Sockbuf_IO ldapsb_tls; -#endif -static CURLcode oldap_connect(struct Curl_easy *data, bool *done) +static bool ssl_installed(struct connectdata *conn) +{ + return conn->proto.ldapc->recv != NULL; +} + +static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate) { + CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; struct ldapconninfo *li = conn->proto.ldapc; - int rc, proto = LDAP_VERSION3; - char hosturl[1024]; - char *ptr; + bool ssldone = 0; - (void)done; + result = Curl_ssl_connect_nonblocking(data, conn, FALSE, + FIRSTSOCKET, &ssldone); + if(!result) { + state(data, newstate); - strcpy(hosturl, "ldap"); - ptr = hosturl + 4; - if(conn->handler->flags & PROTOPT_SSL) - *ptr++ = 's'; - msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d", - conn->host.name, conn->remote_port); + if(ssldone) { + Sockbuf *sb; -#ifdef CURL_OPENLDAP_DEBUG - static int do_trace = 0; - const char *env = getenv("CURL_OPENLDAP_TRACE"); - do_trace = (env && strtol(env, NULL, 10) > 0); - if(do_trace) { - ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace); + /* Install the libcurl SSL handlers into the sockbuf. */ + ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); + li->recv = conn->recv[FIRSTSOCKET]; + li->send = conn->send[FIRSTSOCKET]; + } } + + return result; +} + +/* Send the STARTTLS request */ +static CURLcode oldap_perform_starttls(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct ldapconninfo *li = data->conn->proto.ldapc; + int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid); + + if(rc == LDAP_SUCCESS) + state(data, OLDAP_STARTTLS); + else + result = oldap_map_error(rc, CURLE_USE_SSL_FAILED); + return result; +} #endif +static CURLcode oldap_connect(struct Curl_easy *data, bool *done) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + static const int version = LDAP_VERSION3; + int rc; + char *hosturl; +#ifdef CURL_OPENLDAP_DEBUG + static int do_trace = -1; +#endif + + (void)done; + + hosturl = aprintf("ldap%s://%s:%d", + conn->handler->flags & PROTOPT_SSL? "s": "", + conn->host.name, conn->remote_port); + if(!hosturl) + return CURLE_OUT_OF_MEMORY; + rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld); if(rc) { failf(data, "LDAP local: Cannot connect to %s, %s", hosturl, ldap_err2string(rc)); + free(hosturl); return CURLE_COULDNT_CONNECT; } - ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); + free(hosturl); + +#ifdef CURL_OPENLDAP_DEBUG + if(do_trace < 0) { + const char *env = getenv("CURL_OPENLDAP_TRACE"); + do_trace = (env && strtol(env, NULL, 10) > 0); + } + if(do_trace) + ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace); +#endif + + /* Try version 3 first. */ + ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version); + + /* Do not chase referrals. */ + ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); #ifdef USE_SSL - if(conn->handler->flags & PROTOPT_SSL) { - CURLcode result; - result = Curl_ssl_connect_nonblocking(data, conn, FALSE, - FIRSTSOCKET, &li->ssldone); - if(result) + if(conn->handler->flags & PROTOPT_SSL) + return oldap_ssl_connect(data, OLDAP_SSL); + + if(data->set.use_ssl) { + CURLcode result = oldap_perform_starttls(data); + + if(!result || data->set.use_ssl != CURLUSESSL_TRY) return result; } #endif - return CURLE_OK; + /* Force bind even if anonymous bind is not needed in protocol version 3 + to detect missing version 3 support. */ + return oldap_perform_bind(data, OLDAP_BIND); } -static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) +/* Handle a simple bind response. */ +static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg, + int code) { struct connectdata *conn = data->conn; struct ldapconninfo *li = conn->proto.ldapc; - LDAPMessage *msg = NULL; - struct timeval tv = {0, 1}, *tvp; - int rc, err; - char *info = NULL; + CURLcode result = CURLE_OK; + struct berval *bv = NULL; + int rc; -#ifdef USE_SSL - if(conn->handler->flags & PROTOPT_SSL) { - /* Is the SSL handshake complete yet? */ - if(!li->ssldone) { - CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE, - FIRSTSOCKET, - &li->ssldone); - if(result || !li->ssldone) - return result; - } + if(code != LDAP_SUCCESS) + return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND); - /* Have we installed the libcurl SSL handlers into the sockbuf yet? */ - if(!li->sslinst) { - Sockbuf *sb; - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); - li->sslinst = TRUE; - li->recv = conn->recv[FIRSTSOCKET]; - li->send = conn->send[FIRSTSOCKET]; - } + rc = ldap_parse_sasl_bind_result(li->ld, msg, &bv, 0); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: bind ldap_parse_sasl_bind_result %s", + ldap_err2string(rc)); + result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); } -#endif + else + state(data, OLDAP_STOP); - tvp = &tv; - - retry: - if(!li->didbind) { - char *binddn; - struct berval passwd; + if(bv) + ber_bvfree(bv); + return result; +} - if(conn->bits.user_passwd) { - binddn = conn->user; - passwd.bv_val = conn->passwd; - passwd.bv_len = strlen(passwd.bv_val); +static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + LDAPMessage *msg = NULL; + struct timeval tv = {0, 0}; + int code = LDAP_SUCCESS; + int rc; + + if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) { + /* Get response to last command. */ + rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg); + if(!rc) + return CURLE_OK; /* Timed out. */ + if(rc < 0) { + failf(data, "LDAP local: connecting ldap_result %s", + ldap_err2string(rc)); + return oldap_map_error(rc, CURLE_COULDNT_CONNECT); } + + /* Get error code from message. */ + rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0); + if(rc) + code = rc; else { - binddn = NULL; - passwd.bv_val = NULL; - passwd.bv_len = 0; + /* store the latest code for later retrieval */ + data->info.httpcode = code; } - rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd, - NULL, NULL, &li->msgid); - if(rc) - return CURLE_LDAP_CANNOT_BIND; - li->didbind = TRUE; - if(tvp) - return CURLE_OK; - } - rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg); - if(rc < 0) { - failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc)); - return CURLE_LDAP_CANNOT_BIND; - } - if(rc == 0) { - /* timed out */ - return CURLE_OK; - } + /* If protocol version 3 is not supported, fallback to version 2. */ + if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 +#ifdef USE_SSL + && (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) +#endif + ) { + static const int version = LDAP_VERSION2; - rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1); - if(rc) { - failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc)); - return CURLE_LDAP_CANNOT_BIND; + ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version); + ldap_msgfree(msg); + return oldap_perform_bind(data, OLDAP_BINDV2); + } } - /* Try to fallback to LDAPv2? */ - if(err == LDAP_PROTOCOL_ERROR) { - int proto; - ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); - if(proto == LDAP_VERSION3) { - if(info) { - ldap_memfree(info); - info = NULL; + /* Handle response message according to current state. */ + switch(li->state) { + +#ifdef USE_SSL + case OLDAP_SSL: + result = oldap_ssl_connect(data, OLDAP_SSL); + if(!result && ssl_installed(conn)) + result = oldap_perform_bind(data, OLDAP_BIND); + break; + case OLDAP_STARTTLS: + if(code != LDAP_SUCCESS) { + if(data->set.use_ssl != CURLUSESSL_TRY) + result = oldap_map_error(code, CURLE_USE_SSL_FAILED); + else + result = oldap_perform_bind(data, OLDAP_BIND); + break; + } + /* FALLTHROUGH */ + case OLDAP_TLS: + result = oldap_ssl_connect(data, OLDAP_TLS); + if(result && data->set.use_ssl != CURLUSESSL_TRY) + result = oldap_map_error(code, CURLE_USE_SSL_FAILED); + else if(ssl_installed(conn)) { + conn->bits.tls_upgraded = TRUE; + if(conn->bits.user_passwd) + result = oldap_perform_bind(data, OLDAP_BIND); + else { + state(data, OLDAP_STOP); /* Version 3 supported: no bind required */ + result = CURLE_OK; } - proto = LDAP_VERSION2; - ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); - li->didbind = FALSE; - goto retry; } - } + break; +#endif - if(err) { - failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc), - info ? info : ""); - if(info) - ldap_memfree(info); - return CURLE_LOGIN_DENIED; + case OLDAP_BIND: + case OLDAP_BINDV2: + result = oldap_state_bind_resp(data, msg, code); + break; + default: + /* internal error */ + result = CURLE_COULDNT_CONNECT; + break; } - if(info) - ldap_memfree(info); - conn->recv[FIRSTSOCKET] = oldap_recv; - *done = TRUE; + ldap_msgfree(msg); - return CURLE_OK; + *done = li->state == OLDAP_STOP; + if(*done) + conn->recv[FIRSTSOCKET] = oldap_recv; + + return result; } static CURLcode oldap_disconnect(struct Curl_easy *data, @@ -373,7 +553,7 @@ static CURLcode oldap_disconnect(struct Curl_easy *data, if(li) { if(li->ld) { #ifdef USE_SSL - if(conn->ssl[FIRSTSOCKET].use) { + if(ssl_installed(conn)) { Sockbuf *sb; ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); @@ -393,44 +573,40 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) struct connectdata *conn = data->conn; struct ldapconninfo *li = conn->proto.ldapc; struct ldapreqinfo *lr; - CURLcode status = CURLE_OK; - int rc = 0; - LDAPURLDesc *ludp = NULL; + CURLcode result; + int rc; + LDAPURLDesc *lud; int msgid; connkeep(conn, "OpenLDAP do"); infof(data, "LDAP local: %s", data->state.url); - rc = ldap_url_parse(data->state.url, &ludp); - if(rc != LDAP_URL_SUCCESS) { - const char *msg = "url parsing problem"; - status = CURLE_URL_MALFORMAT; - if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { - if(rc == LDAP_URL_ERR_MEM) - status = CURLE_OUT_OF_MEMORY; - msg = url_errs[rc]; + result = oldap_url_parse(data, &lud); + if(!result) { + rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope, + lud->lud_filter, lud->lud_attrs, 0, + NULL, NULL, NULL, 0, &msgid); + ldap_free_urldesc(lud); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); + result = CURLE_LDAP_SEARCH_FAILED; + } + else { + lr = calloc(1, sizeof(struct ldapreqinfo)); + if(!lr) { + ldap_abandon_ext(li->ld, msgid, NULL, NULL); + result = CURLE_OUT_OF_MEMORY; + } + else { + lr->msgid = msgid; + data->req.p.ldap = lr; + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + *done = TRUE; + } } - failf(data, "LDAP local: %s", msg); - return status; - } - - rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, 0, - NULL, NULL, NULL, 0, &msgid); - ldap_free_urldesc(ludp); - if(rc != LDAP_SUCCESS) { - failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); - return CURLE_LDAP_SEARCH_FAILED; } - lr = calloc(1, sizeof(struct ldapreqinfo)); - if(!lr) - return CURLE_OUT_OF_MEMORY; - lr->msgid = msgid; - data->req.p.ldap = lr; - Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); - *done = TRUE; - return CURLE_OK; + return result; } static CURLcode oldap_done(struct Curl_easy *data, CURLcode res, @@ -456,163 +632,146 @@ static CURLcode oldap_done(struct Curl_easy *data, CURLcode res, return CURLE_OK; } +static CURLcode client_write(struct Curl_easy *data, const char *prefix, + const char *value, size_t len, const char *suffix) +{ + CURLcode result = CURLE_OK; + size_t l; + + if(prefix) { + l = strlen(prefix); + /* If we have a zero-length value and the prefix ends with a space + separator, drop the latter. */ + if(!len && l && prefix[l - 1] == ' ') + l--; + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, l); + if(!result) + data->req.bytecount += l; + } + if(!result && value) { + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len); + if(!result) + data->req.bytecount += len; + } + if(!result && suffix) { + l = strlen(suffix); + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, l); + if(!result) + data->req.bytecount += l; + } + return result; +} + static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, size_t len, CURLcode *err) { struct connectdata *conn = data->conn; struct ldapconninfo *li = conn->proto.ldapc; struct ldapreqinfo *lr = data->req.p.ldap; - int rc, ret; + int rc; LDAPMessage *msg = NULL; - LDAPMessage *ent; BerElement *ber = NULL; - struct timeval tv = {0, 1}; + struct timeval tv = {0, 0}; + struct berval bv, *bvals; + int binary = 0; + CURLcode result = CURLE_AGAIN; + int code; + char *info = NULL; (void)len; (void)buf; (void)sockindex; - rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg); + rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg); if(rc < 0) { failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc)); - *err = CURLE_RECV_ERROR; - return -1; + result = CURLE_RECV_ERROR; } - *err = CURLE_AGAIN; - ret = -1; + *err = result; - /* timed out */ + /* error or timed out */ if(!msg) - return ret; - - for(ent = ldap_first_message(li->ld, msg); ent; - ent = ldap_next_message(li->ld, ent)) { - struct berval bv, *bvals; - int binary = 0, msgtype; - CURLcode writeerr; - - msgtype = ldap_msgtype(ent); - if(msgtype == LDAP_RES_SEARCH_RESULT) { - int code; - char *info = NULL; - rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0); - if(rc) { - failf(data, "LDAP local: search ldap_parse_result %s", - ldap_err2string(rc)); - *err = CURLE_LDAP_SEARCH_FAILED; - } - else if(code && code != LDAP_SIZELIMIT_EXCEEDED) { - failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc), - info ? info : ""); - *err = CURLE_LDAP_SEARCH_FAILED; - } - else { - /* successful */ - if(code == LDAP_SIZELIMIT_EXCEEDED) - infof(data, "There are more than %d entries", lr->nument); - data->req.size = data->req.bytecount; - *err = CURLE_OK; - ret = 0; - } - lr->msgid = 0; - ldap_memfree(info); + return -1; + + result = CURLE_OK; + + switch(ldap_msgtype(msg)) { + case LDAP_RES_SEARCH_RESULT: + lr->msgid = 0; + rc = ldap_parse_result(li->ld, msg, &code, NULL, &info, NULL, NULL, 0); + if(rc) { + failf(data, "LDAP local: search ldap_parse_result %s", + ldap_err2string(rc)); + result = CURLE_LDAP_SEARCH_FAILED; break; } - else if(msgtype != LDAP_RES_SEARCH_ENTRY) - continue; + /* store the latest code for later retrieval */ + data->info.httpcode = code; + + switch(code) { + case LDAP_SIZELIMIT_EXCEEDED: + infof(data, "There are more than %d entries", lr->nument); + /* FALLTHROUGH */ + case LDAP_SUCCESS: + data->req.size = data->req.bytecount; + break; + default: + failf(data, "LDAP remote: search failed %s %s", ldap_err2string(code), + info ? info : ""); + result = CURLE_LDAP_SEARCH_FAILED; + break; + } + if(info) + ldap_memfree(info); + break; + case LDAP_RES_SEARCH_ENTRY: lr->nument++; - rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv); + rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv); if(rc < 0) { - *err = CURLE_RECV_ERROR; - return -1; - } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4); - if(writeerr) { - *err = writeerr; - return -1; - } - - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val, - bv.bv_len); - if(writeerr) { - *err = writeerr; - return -1; + result = CURLE_RECV_ERROR; + break; } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - data->req.bytecount += bv.bv_len + 5; + result = client_write(data, "DN: ", bv.bv_val, bv.bv_len, "\n"); + if(result) + break; - for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals); + for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals); rc == LDAP_SUCCESS; - rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) { + rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) { int i; if(!bv.bv_val) break; - if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7)) - binary = 1; - else - binary = 0; - if(!bvals) { - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val, - bv.bv_len); - if(writeerr) { - *err = writeerr; - return -1; - } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":\n", 2); - if(writeerr) { - *err = writeerr; - return -1; - } - data->req.bytecount += bv.bv_len + 3; + result = client_write(data, "\t", bv.bv_val, bv.bv_len, ":\n"); + if(result) + break; continue; } + binary = bv.bv_len > 7 && + !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7); + for(i = 0; bvals[i].bv_val != NULL; i++) { int binval = 0; - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val, - bv.bv_len); - if(writeerr) { - *err = writeerr; - return -1; - } - - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - data->req.bytecount += bv.bv_len + 2; + result = client_write(data, "\t", bv.bv_val, bv.bv_len, ":"); + if(result) + break; if(!binary) { /* check for leading or trailing whitespace */ if(ISSPACE(bvals[i].bv_val[0]) || - ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1])) + ISSPACE(bvals[i].bv_val[bvals[i].bv_len - 1])) binval = 1; else { /* check for unprintable characters */ unsigned int j; - for(j = 0; j<bvals[i].bv_len; j++) + for(j = 0; j < bvals[i].bv_len; j++) if(!ISPRINT(bvals[i].bv_val[j])) { binval = 1; break; @@ -622,80 +781,42 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, if(binary || binval) { char *val_b64 = NULL; size_t val_b64_sz = 0; - /* Binary value, encode to base64. */ - CURLcode error = Curl_base64_encode(data, - bvals[i].bv_val, - bvals[i].bv_len, - &val_b64, - &val_b64_sz); - if(error) { - ber_memfree(bvals); - ber_free(ber, 0); - ldap_msgfree(msg); - *err = error; - return -1; - } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, - (char *)": ", 2); - if(writeerr) { - *err = writeerr; - return -1; - } - - data->req.bytecount += 2; - if(val_b64_sz > 0) { - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, val_b64, - val_b64_sz); - if(writeerr) { - *err = writeerr; - return -1; - } - free(val_b64); - data->req.bytecount += val_b64_sz; - } - } - else { - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)" ", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, bvals[i].bv_val, - bvals[i].bv_len); - if(writeerr) { - *err = writeerr; - return -1; - } - - data->req.bytecount += bvals[i].bv_len + 1; - } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); - if(writeerr) { - *err = writeerr; - return -1; + /* Binary value, encode to base64. */ + if(bvals[i].bv_len) + result = Curl_base64_encode(data, bvals[i].bv_val, bvals[i].bv_len, + &val_b64, &val_b64_sz); + if(!result) + result = client_write(data, ": ", val_b64, val_b64_sz, "\n"); + free(val_b64); } - - data->req.bytecount++; + else + result = client_write(data, " ", + bvals[i].bv_val, bvals[i].bv_len, "\n"); + if(result) + break; } + ber_memfree(bvals); - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); - if(writeerr) { - *err = writeerr; - return -1; - } - data->req.bytecount++; - } - writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); - if(writeerr) { - *err = writeerr; - return -1; + bvals = NULL; + if(!result) + result = client_write(data, "\n", NULL, 0, NULL); + if(result) + break; } - data->req.bytecount++; + ber_free(ber, 0); + + if(!result) + result = client_write(data, "\n", NULL, 0, NULL); + if(!result) + result = CURLE_AGAIN; + break; } + ldap_msgfree(msg); - return ret; + *err = result; + return result? -1: 0; } #ifdef USE_SSL diff --git a/libs/libcurl/src/setopt.c b/libs/libcurl/src/setopt.c index 56d9c49926..599ed5d994 100644 --- a/libs/libcurl/src/setopt.c +++ b/libs/libcurl/src/setopt.c @@ -1870,6 +1870,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.ssl.primary.verifypeer; } break; +#ifndef CURL_DISABLE_DOH case CURLOPT_DOH_SSL_VERIFYPEER: /* * Enable peer SSL verifying for DoH. @@ -1877,6 +1878,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.doh_verifypeer = (0 != va_arg(param, long)) ? TRUE : FALSE; break; +#endif #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSL_VERIFYPEER: /* @@ -1909,6 +1911,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.ssl.primary.verifyhost; } break; +#ifndef CURL_DISABLE_DOH case CURLOPT_DOH_SSL_VERIFYHOST: /* * Enable verification of the host name in the peer certificate for DoH @@ -1918,6 +1921,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* Treat both 1 and 2 as TRUE */ data->set.doh_verifyhost = (bool)((arg & 3) ? TRUE : FALSE); break; +#endif #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSL_VERIFYHOST: /* @@ -1953,6 +1957,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.ssl.primary.verifystatus; } break; +#ifndef CURL_DISABLE_DOH case CURLOPT_DOH_SSL_VERIFYSTATUS: /* * Enable certificate status verifying for DoH. @@ -1965,6 +1970,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.doh_verifystatus = (0 != va_arg(param, long)) ? TRUE : FALSE; break; +#endif case CURLOPT_SSL_CTX_FUNCTION: /* * Set a SSL_CTX callback @@ -2609,6 +2615,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; #endif +#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ + !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) + case CURLOPT_MIME_OPTIONS: + data->set.mime_options = va_arg(param, long); + break; +#endif + case CURLOPT_SASL_AUTHZID: /* Authorisation identity (identity to act as) */ result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], diff --git a/libs/libcurl/src/sha256.c b/libs/libcurl/src/sha256.c index 1391412ce5..cf7ea4f543 100644 --- a/libs/libcurl/src/sha256.c +++ b/libs/libcurl/src/sha256.c @@ -82,10 +82,14 @@ struct sha256_ctx { }; typedef struct sha256_ctx my_sha256_ctx; -static void my_sha256_init(my_sha256_ctx *ctx) +static CURLcode my_sha256_init(my_sha256_ctx *ctx) { ctx->openssl_ctx = EVP_MD_CTX_create(); + if(!ctx->openssl_ctx) + return CURLE_OUT_OF_MEMORY; + EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL); + return CURLE_OK; } static void my_sha256_update(my_sha256_ctx *ctx, @@ -112,9 +116,10 @@ static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) typedef struct sha256_ctx my_sha256_ctx; -static void my_sha256_init(my_sha256_ctx *ctx) +static CURLcode my_sha256_init(my_sha256_ctx *ctx) { sha256_init(ctx); + return CURLE_OK; } static void my_sha256_update(my_sha256_ctx *ctx, @@ -140,13 +145,14 @@ static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) typedef mbedtls_sha256_context my_sha256_ctx; -static void my_sha256_init(my_sha256_ctx *ctx) +static CURLcode my_sha256_init(my_sha256_ctx *ctx) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) (void) mbedtls_sha256_starts(ctx, 0); #else (void) mbedtls_sha256_starts_ret(ctx, 0); #endif + return CURLE_OK; } static void my_sha256_update(my_sha256_ctx *ctx, @@ -183,9 +189,10 @@ static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) typedef CC_SHA256_CTX my_sha256_ctx; -static void my_sha256_init(my_sha256_ctx *ctx) +static CURLcode my_sha256_init(my_sha256_ctx *ctx) { (void) CC_SHA256_Init(ctx); + return CURLE_OK; } static void my_sha256_update(my_sha256_ctx *ctx, @@ -214,12 +221,14 @@ typedef struct sha256_ctx my_sha256_ctx; #define CALG_SHA_256 0x0000800c #endif -static void my_sha256_init(my_sha256_ctx *ctx) +static CURLcode my_sha256_init(my_sha256_ctx *ctx) { if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash); } + + return CURLE_OK; } static void my_sha256_update(my_sha256_ctx *ctx, @@ -375,7 +384,7 @@ static int sha256_compress(struct sha256_state *md, } /* Initialize the hash state */ -static void my_sha256_init(struct sha256_state *md) +static CURLcode my_sha256_init(struct sha256_state *md) { md->curlen = 0; md->length = 0; @@ -387,6 +396,8 @@ static void my_sha256_init(struct sha256_state *md) md->state[5] = 0x9B05688CUL; md->state[6] = 0x1F83D9ABUL; md->state[7] = 0x5BE0CD19UL; + + return CURLE_OK; } /* @@ -394,7 +405,7 @@ static void my_sha256_init(struct sha256_state *md) @param md The hash state @param in The data to hash @param inlen The length of the data (octets) - @return CRYPT_OK if successful + @return 0 if successful */ static int my_sha256_update(struct sha256_state *md, const unsigned char *in, @@ -435,7 +446,7 @@ static int my_sha256_update(struct sha256_state *md, Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (32 bytes) - @return CRYPT_OK if successful + @return 0 if successful */ static int my_sha256_final(unsigned char *out, struct sha256_state *md) @@ -491,15 +502,21 @@ static int my_sha256_final(unsigned char *out, * output [in/out] - The output buffer. * input [in] - The input data. * length [in] - The input length. + * + * Returns CURLE_OK on success. */ -void Curl_sha256it(unsigned char *output, const unsigned char *input, +CURLcode Curl_sha256it(unsigned char *output, const unsigned char *input, const size_t length) { + CURLcode result; my_sha256_ctx ctx; - my_sha256_init(&ctx); - my_sha256_update(&ctx, input, curlx_uztoui(length)); - my_sha256_final(output, &ctx); + result = my_sha256_init(&ctx); + if(!result) { + my_sha256_update(&ctx, input, curlx_uztoui(length)); + my_sha256_final(output, &ctx); + } + return result; } diff --git a/libs/libcurl/src/share.c b/libs/libcurl/src/share.c index 9c43c8f705..403563fdd6 100644 --- a/libs/libcurl/src/share.c +++ b/libs/libcurl/src/share.c @@ -39,11 +39,7 @@ curl_share_init(void) if(share) { share->magic = CURL_GOOD_SHARE; share->specifier |= (1<<CURL_LOCK_DATA_SHARE); - - if(Curl_mk_dnscache(&share->hostcache)) { - free(share); - return NULL; - } + Curl_init_dnscache(&share->hostcache); } return share; diff --git a/libs/libcurl/src/smtp.c b/libs/libcurl/src/smtp.c index 8e0b046096..6c08293783 100644 --- a/libs/libcurl/src/smtp.c +++ b/libs/libcurl/src/smtp.c @@ -222,7 +222,7 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn, /* Do we have a command response? This should be the response code followed by a space and optionally some text as per RFC-5321 and as outlined in - Section 4. Examples of RFC-4954 but some e-mail servers ignore this and + Section 4. Examples of RFC-4954 but some email servers ignore this and only send the response code instead as per Section 4.2. */ if(line[3] == ' ' || len == 5) { char tmpline[6]; diff --git a/libs/libcurl/src/socks.c b/libs/libcurl/src/socks.c index db4c80834e..a014aa6684 100644 --- a/libs/libcurl/src/socks.c +++ b/libs/libcurl/src/socks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -38,6 +38,7 @@ #include "timeval.h" #include "socks.h" #include "multiif.h" /* for getsock macros */ +#include "inet_pton.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -856,10 +857,32 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user, socksreq[len++] = 0; /* must be zero */ if(!socks5_resolve_local) { - socksreq[len++] = 3; /* ATYP: domain name = 3 */ - socksreq[len++] = (char) hostname_len; /* one byte address length */ - memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */ - len += hostname_len; + /* ATYP: domain name = 3, + IPv6 == 4, + IPv4 == 1 */ + unsigned char ip4[4]; +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip) { + char ip6[16]; + if(1 != Curl_inet_pton(AF_INET6, hostname, ip6)) + return CURLPX_BAD_ADDRESS_TYPE; + socksreq[len++] = 4; + memcpy(&socksreq[len], ip6, sizeof(ip6)); + len += sizeof(ip6); + } + else +#endif + if(1 == Curl_inet_pton(AF_INET, hostname, ip4)) { + socksreq[len++] = 1; + memcpy(&socksreq[len], ip4, sizeof(ip4)); + len += sizeof(ip4); + } + else { + socksreq[len++] = 3; + socksreq[len++] = (char) hostname_len; /* one byte address length */ + memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */ + len += hostname_len; + } infof(data, "SOCKS5 connect to %s:%d (remotely resolved)", hostname, remote_port); } diff --git a/libs/libcurl/src/splay.c b/libs/libcurl/src/splay.c index 1c1dafb920..bcc0795212 100644 --- a/libs/libcurl/src/splay.c +++ b/libs/libcurl/src/splay.c @@ -107,7 +107,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i, if(!node) return t; - if(t != NULL) { + if(t) { t = Curl_splay(i, t); if(compare(i, t->key) == 0) { /* There already exists a node in the tree with the very same key. Build diff --git a/libs/libcurl/src/strerror.c b/libs/libcurl/src/strerror.c index 31eb2bf790..07d73a74b7 100644 --- a/libs/libcurl/src/strerror.c +++ b/libs/libcurl/src/strerror.c @@ -404,6 +404,9 @@ curl_multi_strerror(CURLMcode error) case CURLM_BAD_FUNCTION_ARGUMENT: return "A libcurl function was given a bad argument"; + case CURLM_ABORTED_BY_CALLBACK: + return "Operation was aborted by an application callback"; + case CURLM_LAST: break; } @@ -468,10 +471,10 @@ curl_url_strerror(CURLUcode error) return "An invalid 'part' argument was passed as argument"; case CURLUE_MALFORMED_INPUT: - return "A malformed input was passed to a URL API function"; + return "Malformed input to a URL function"; case CURLUE_BAD_PORT_NUMBER: - return "The port number was not a decimal number between 0 and 65535"; + return "Port number was not a decimal number between 0 and 65535"; case CURLUE_UNSUPPORTED_SCHEME: return "This libcurl build doesn't support the given URL scheme"; @@ -489,28 +492,64 @@ curl_url_strerror(CURLUcode error) return "An unknown part ID was passed to a URL API function"; case CURLUE_NO_SCHEME: - return "There is no scheme part in the URL"; + return "No scheme part in the URL"; case CURLUE_NO_USER: - return "There is no user part in the URL"; + return "No user part in the URL"; case CURLUE_NO_PASSWORD: - return "There is no password part in the URL"; + return "No password part in the URL"; case CURLUE_NO_OPTIONS: - return "There is no options part in the URL"; + return "No options part in the URL"; case CURLUE_NO_HOST: - return "There is no host part in the URL"; + return "No host part in the URL"; case CURLUE_NO_PORT: - return "There is no port part in the URL"; + return "No port part in the URL"; case CURLUE_NO_QUERY: - return "There is no query part in the URL"; + return "No query part in the URL"; case CURLUE_NO_FRAGMENT: - return "There is no fragment part in the URL"; + return "No fragment part in the URL"; + + case CURLUE_NO_ZONEID: + return "No zoneid part in the URL"; + + case CURLUE_BAD_LOGIN: + return "Bad login part"; + + case CURLUE_BAD_IPV6: + return "Bad IPv6 address"; + + case CURLUE_BAD_HOSTNAME: + return "Bad hostname"; + + case CURLUE_BAD_FILE_URL: + return "Bad file:// URL"; + + case CURLUE_BAD_SLASHES: + return "Unsupported number of slashes"; + + case CURLUE_BAD_SCHEME: + return "Bad scheme"; + + case CURLUE_BAD_PATH: + return "Bad path"; + + case CURLUE_BAD_FRAGMENT: + return "Bad fragment"; + + case CURLUE_BAD_QUERY: + return "Bad query"; + + case CURLUE_BAD_PASSWORD: + return "Bad password"; + + case CURLUE_BAD_USER: + return "Bad user"; case CURLUE_LAST: break; diff --git a/libs/libcurl/src/system_win32.c b/libs/libcurl/src/system_win32.c index d4e194831f..9a6dd9cef6 100644 --- a/libs/libcurl/src/system_win32.c +++ b/libs/libcurl/src/system_win32.c @@ -104,7 +104,7 @@ CURLcode Curl_win32_init(long flags) /* curlx_verify_windows_version must be called during init at least once because it has its own initialization routine. */ - if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT, + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { Curl_isVistaOrGreater = TRUE; } diff --git a/libs/libcurl/src/tftp.c b/libs/libcurl/src/tftp.c index 7e5246f010..f8c68441ca 100644 --- a/libs/libcurl/src/tftp.c +++ b/libs/libcurl/src/tftp.c @@ -186,7 +186,7 @@ const struct Curl_handler Curl_handler_tftp = { PORT_TFTP, /* defport */ CURLPROTO_TFTP, /* protocol */ CURLPROTO_TFTP, /* family */ - PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ + PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */ }; /********************************************************** diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c index 05fec7998c..22704fa158 100644 --- a/libs/libcurl/src/transfer.c +++ b/libs/libcurl/src/transfer.c @@ -1631,7 +1631,7 @@ CURLcode Curl_follow(struct Curl_easy *data, if((type != FOLLOW_RETRY) && (data->req.httpcode != 401) && (data->req.httpcode != 407) && - Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN)) + Curl_is_absolute_url(newurl, NULL, 0)) /* If this is not redirect due to a 401 or 407 response and an absolute URL: don't allow a custom port number */ disallowport = TRUE; diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c index 93b4397bff..9f1013554f 100644 --- a/libs/libcurl/src/url.c +++ b/libs/libcurl/src/url.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -137,6 +137,15 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "curl_memory.h" #include "memdebug.h" +/* Count of the backend ssl objects to allocate */ +#ifdef USE_SSL +# ifndef CURL_DISABLE_PROXY +# define SSL_BACKEND_CNT 4 +# else +# define SSL_BACKEND_CNT 2 +# endif +#endif + static void conn_free(struct connectdata *conn); /* Some parts of the code (e.g. chunked encoding) assume this buffer has at @@ -354,9 +363,7 @@ static void up_free(struct Curl_easy *data) * This is the internal function curl_easy_cleanup() calls. This should * cleanup and free all resources associated with this sessionhandle. * - * NOTE: if we ever add something that attempts to write to a socket or - * similar here, we must ignore SIGPIPE first. It is currently only done - * when curl_easy_perform() is invoked. + * We ignore SIGPIPE when this is called from curl_easy_cleanup. */ CURLcode Curl_close(struct Curl_easy **datap) @@ -542,8 +549,10 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) * libcurl 7.10 introduced SSL verification *by default*! This needs to be * switched off unless wanted. */ +#ifndef CURL_DISABLE_DOH set->doh_verifyhost = TRUE; set->doh_verifypeer = TRUE; +#endif set->ssl.primary.verifypeer = TRUE; set->ssl.primary.verifyhost = TRUE; #ifdef USE_TLS_SRP @@ -845,7 +854,7 @@ CURLcode Curl_disconnect(struct Curl_easy *data, return CURLE_OK; } - if(conn->dns_entry != NULL) { + if(conn->dns_entry) { Curl_resolv_unlock(data, conn->dns_entry); conn->dns_entry = NULL; } @@ -1300,13 +1309,12 @@ ConnectionExists(struct Curl_easy *data, if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete) continue; } - else { - if(!Curl_ssl_config_matches(&needle->ssl_config, - &check->ssl_config)) - continue; - if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) - continue; - } + + if(!Curl_ssl_config_matches(&needle->ssl_config, + &check->ssl_config)) + continue; + if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) + continue; } } #endif @@ -1683,7 +1691,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) data becomes proxy backend data). */ { size_t sslsize = Curl_ssl->sizeof_ssl_backend_data; - char *ssl = calloc(4, sslsize); + char *ssl = calloc(SSL_BACKEND_CNT, sslsize); if(!ssl) { free(conn); return NULL; @@ -1950,7 +1958,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; if(data->set.str[STRING_DEFAULT_PROTOCOL] && - !Curl_is_absolute_url(data->state.url, NULL, MAX_SCHEME_LEN)) { + !Curl_is_absolute_url(data->state.url, NULL, 0)) { char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL], data->state.url); if(!url) @@ -2593,7 +2601,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data, if(data->set.str[STRING_PROXY]) { proxy = strdup(data->set.str[STRING_PROXY]); /* if global proxy is set, this is it */ - if(NULL == proxy) { + if(!proxy) { failf(data, "memory shortage"); result = CURLE_OUT_OF_MEMORY; goto out; @@ -2603,7 +2611,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data, if(data->set.str[STRING_PRE_PROXY]) { socksproxy = strdup(data->set.str[STRING_PRE_PROXY]); /* if global socks proxy is set, this is it */ - if(NULL == socksproxy) { + if(!socksproxy) { failf(data, "memory shortage"); result = CURLE_OUT_OF_MEMORY; goto out; diff --git a/libs/libcurl/src/urlapi-int.h b/libs/libcurl/src/urlapi-int.h index 4257233094..bd6b601751 100644 --- a/libs/libcurl/src/urlapi-int.h +++ b/libs/libcurl/src/urlapi-int.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,8 +22,6 @@ * ***************************************************************************/ #include "curl_setup.h" -/* scheme is not URL encoded, the longest libcurl supported ones are... */ -#define MAX_SCHEME_LEN 40 bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen); diff --git a/libs/libcurl/src/urlapi.c b/libs/libcurl/src/urlapi.c index 6d116b61bf..d29aeb238f 100644 --- a/libs/libcurl/src/urlapi.c +++ b/libs/libcurl/src/urlapi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,6 +30,7 @@ #include "escape.h" #include "curl_ctype.h" #include "inet_pton.h" +#include "inet_ntop.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -50,6 +51,9 @@ ((str)[1] == ':' || (str)[1] == '|') && \ ((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0)) +/* scheme is not URL encoded, the longest libcurl supported ones are... */ +#define MAX_SCHEME_LEN 40 + /* Internal representation of CURLU. Point to URL-encoded strings. */ struct Curl_URL { char *scheme; @@ -228,33 +232,40 @@ static void strcpy_url(char *output, const char *url, bool relative) } /* - * Returns true if the given URL is absolute (as opposed to relative) within - * the buffer size. Returns the scheme in the buffer if TRUE and 'buf' is - * non-NULL. + * Returns true if the given URL is absolute (as opposed to relative). Returns + * the scheme in the buffer if TRUE and 'buf' is non-NULL. The buflen must + * be larger than MAX_SCHEME_LEN if buf is set. */ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) { size_t i; + DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN)); + (void)buflen; /* only used in debug-builds */ + if(buf) + buf[0] = 0; /* always leave a defined value in buf */ #ifdef WIN32 if(STARTS_WITH_DRIVE_PREFIX(url)) return FALSE; #endif - for(i = 0; i < buflen && url[i]; ++i) { + for(i = 0; i < MAX_SCHEME_LEN; ++i) { char s = url[i]; - if((s == ':') && (url[i + 1] == '/')) { - if(buf) - buf[i] = 0; - return TRUE; - } - /* RFC 3986 3.1 explains: - scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - */ - else if(ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') ) { - if(buf) - buf[i] = (char)TOLOWER(s); + if(s && (ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') )) { + /* RFC 3986 3.1 explains: + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + */ } - else + else { break; + } + } + if(i && (url[i] == ':') && (url[i + 1] == '/')) { + if(buf) { + buf[i] = 0; + while(i--) { + buf[i] = (char)TOLOWER(url[i]); + } + } + return TRUE; } return FALSE; } @@ -418,6 +429,29 @@ static char *concat_url(const char *base, const char *relurl) return newest; } +/* scan for byte values < 31 or 127 */ +static bool junkscan(const char *part, unsigned int flags) +{ + if(part) { + static const char badbytes[]={ + /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x7f, 0x00 /* null-terminate */ + }; + size_t n = strlen(part); + size_t nfine = strcspn(part, badbytes); + if(nfine != n) + /* since we don't know which part is scanned, return a generic error + code */ + return TRUE; + if(!(flags & CURLU_ALLOW_SPACE) && strchr(part, ' ')) + return TRUE; + } + return FALSE; +} + /* * parse_hostname_login() * @@ -465,7 +499,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, (h && (h->flags & PROTOPT_URLOPTIONS)) ? &optionsp:NULL); if(ccode) { - result = CURLUE_MALFORMED_INPUT; + result = CURLUE_BAD_LOGIN; goto out; } @@ -475,15 +509,28 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, result = CURLUE_USER_NOT_ALLOWED; goto out; } - + if(junkscan(userp, flags)) { + result = CURLUE_BAD_USER; + goto out; + } u->user = userp; } - if(passwdp) + if(passwdp) { + if(junkscan(passwdp, flags)) { + result = CURLUE_BAD_PASSWORD; + goto out; + } u->password = passwdp; + } - if(optionsp) + if(optionsp) { + if(junkscan(optionsp, flags)) { + result = CURLUE_BAD_LOGIN; + goto out; + } u->options = optionsp; + } return CURLUE_OK; out: @@ -491,6 +538,9 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, free(userp); free(passwdp); free(optionsp); + u->user = NULL; + u->password = NULL; + u->options = NULL; return result; } @@ -514,19 +564,19 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, int zonelen = len; if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) { if(']' != endbracket) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; portptr = &hostname[--zonelen + len + 1]; } else - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; } else - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; /* this is a RFC2732-style specified IP-address */ if(portptr && *portptr) { if(*portptr != ':') - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; } else portptr = NULL; @@ -556,9 +606,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */ - if((port <= 0) || (port > 0xffff)) - /* Single unix standard says port numbers are 16 bits long, but we don't - treat port zero as OK. */ + if(port > 0xffff) return CURLUE_BAD_PORT_NUMBER; if(rest[0]) @@ -577,46 +625,20 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, return CURLUE_OK; } -/* scan for byte values < 31 or 127 */ -static bool junkscan(const char *part, unsigned int flags) -{ - if(part) { - static const char badbytes[]={ - /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x7f, 0x00 /* null-terminate */ - }; - size_t n = strlen(part); - size_t nfine = strcspn(part, badbytes); - if(nfine != n) - /* since we don't know which part is scanned, return a generic error - code */ - return TRUE; - if(!(flags & CURLU_ALLOW_SPACE) && strchr(part, ' ')) - return TRUE; - } - return FALSE; -} - static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) { size_t len; size_t hlen = strlen(hostname); if(hostname[0] == '[') { -#ifdef ENABLE_IPV6 - char dest[16]; /* fits a binary IPv6 address */ -#endif const char *l = "0123456789abcdefABCDEF:."; if(hlen < 4) /* '[::]' is the shortest possible valid string */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; hostname++; hlen -= 2; if(hostname[hlen] != ']') - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; /* only valid letters are ok */ len = strspn(hostname, l); @@ -633,6 +655,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) while(*h && (*h != ']') && (i < 15)) zoneid[i++] = *h++; if(!i || (']' != *h)) + /* impossible to reach? */ return CURLUE_MALFORMED_INPUT; zoneid[i] = 0; u->zoneid = strdup(zoneid); @@ -642,14 +665,26 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) hostname[len + 1] = 0; /* terminate the hostname */ } else - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; /* hostname is fine */ } #ifdef ENABLE_IPV6 - hostname[hlen] = 0; /* end the address there */ - if(1 != Curl_inet_pton(AF_INET6, hostname, dest)) - return CURLUE_MALFORMED_INPUT; - hostname[hlen] = ']'; /* restore ending bracket */ + { + char dest[16]; /* fits a binary IPv6 address */ + char norm[MAX_IPADR_LEN]; + hostname[hlen] = 0; /* end the address there */ + if(1 != Curl_inet_pton(AF_INET6, hostname, dest)) + return CURLUE_BAD_IPV6; + + /* check if it can be done shorter */ + if(Curl_inet_ntop(AF_INET6, dest, norm, sizeof(norm)) && + (strlen(norm) < hlen)) { + strcpy(hostname, norm); + hlen = strlen(norm); + hostname[hlen + 1] = 0; + } + hostname[hlen] = ']'; /* restore ending bracket */ + } #endif } else { @@ -657,7 +692,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) len = strcspn(hostname, " \r\n"); if(hlen != len) /* hostname with bad content */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_HOSTNAME; } if(!hostname[0]) return CURLUE_NO_HOST; @@ -772,7 +807,7 @@ static CURLUcode decode_host(char *hostname, char **outp) CURLcode result = Curl_urldecode(NULL, hostname, 0, outp, &dlen, REJECT_CTRL); if(result) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_HOSTNAME; } return CURLUE_OK; @@ -817,7 +852,11 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } /* handle the file: scheme */ - if(url_has_scheme && strcasecompare(schemebuf, "file")) { + if(url_has_scheme && !strcmp(schemebuf, "file")) { + if(urllen <= 6) + /* file:/ is not enough to actually be a complete file: URL */ + return CURLUE_BAD_FILE_URL; + /* path has been allocated large enough to hold this */ strcpy(path, &url[5]); @@ -870,7 +909,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) host name */ path = strpbrk(ptr, "/\\:*?\"<>|"); if(!path || *path != '/') - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_FILE_URL; len = path - ptr; if(len) { @@ -883,7 +922,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) #else /* Invalid file://hostname/, expected localhost or 127.0.0.1 or none */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_FILE_URL; #endif } } @@ -900,7 +939,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) || STARTS_WITH_URL_DRIVE_PREFIX(path)) { /* File drive letters are only accepted in MSDOS/Windows */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_FILE_URL; } #else /* If the path starts with a slash and a drive letter, ditch the slash */ @@ -927,7 +966,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } if((i < 1) || (i>3)) /* less than one or more than three slashes */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_SLASHES; schemep = schemebuf; if(!Curl_builtin_scheme(schemep) && @@ -935,13 +974,13 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) return CURLUE_UNSUPPORTED_SCHEME; if(junkscan(schemep, flags)) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_SCHEME; } else { /* no scheme! */ if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_SCHEME; if(flags & CURLU_DEFAULT_SCHEME) schemep = DEFAULT_SCHEME; @@ -952,7 +991,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } hostp = p; /* host name starts here */ - while(*p && !HOSTNAME_END(*p)) /* find end of host name */ + /* find the end of the host name + port number */ + while(*p && !HOSTNAME_END(*p)) p++; len = p - hostp; @@ -962,7 +1002,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } else { if(!(flags & CURLU_NO_AUTHORITY)) - return CURLUE_MALFORMED_INPUT; + return CURLUE_NO_HOST; } len = strlen(p); @@ -976,9 +1016,6 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } } - if(junkscan(path, flags)) - return CURLUE_MALFORMED_INPUT; - if((flags & CURLU_URLENCODE) && path[0]) { /* worst case output length is 3x the original! */ char *newp = malloc(strlen(path) * 3); @@ -992,6 +1029,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) fragment = strchr(path, '#'); if(fragment) { *fragment++ = 0; + if(junkscan(fragment, flags)) + return CURLUE_BAD_FRAGMENT; if(fragment[0]) { u->fragment = strdup(fragment); if(!u->fragment) @@ -1002,12 +1041,17 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) query = strchr(path, '?'); if(query) { *query++ = 0; + if(junkscan(query, flags)) + return CURLUE_BAD_QUERY; /* done even if the query part is a blank string */ u->query = strdup(query); if(!u->query) return CURLUE_OUT_OF_MEMORY; } + if(junkscan(path, flags)) + return CURLUE_BAD_PATH; + if(!path[0]) /* if there's no path left set, unset */ path = NULL; @@ -1037,12 +1081,10 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(hostname) { char normalized_ipv4[sizeof("255.255.255.255") + 1]; + /* * Parse the login details and strip them out of the host name. */ - if(junkscan(hostname, flags)) - return CURLUE_MALFORMED_INPUT; - result = parse_hostname_login(u, &hostname, flags); if(result) return result; @@ -1051,6 +1093,9 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(result) return result; + if(junkscan(hostname, flags)) + return CURLUE_BAD_HOSTNAME; + if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) { /* Skip hostname check, it's allowed to be empty. */ u->host = strdup(""); @@ -1196,6 +1241,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, break; case CURLUPART_ZONEID: ptr = u->zoneid; + ifmissing = CURLUE_NO_ZONEID; break; case CURLUPART_PORT: ptr = u->port; @@ -1453,7 +1499,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, case CURLUPART_SCHEME: if(strlen(part) > MAX_SCHEME_LEN) /* too long */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_SCHEME; if(!(flags & CURLU_NON_SUPPORT_SCHEME) && /* verify that it is a fine scheme */ !Curl_builtin_scheme(part)) @@ -1474,7 +1520,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, size_t len = strcspn(part, " \r\n"); if(strlen(part) != len) /* hostname with bad content */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_HOSTNAME; storep = &u->host; Curl_safefree(u->zoneid); break; @@ -1491,7 +1537,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_BAD_PORT_NUMBER; if(*endp) /* weirdly provided number, not good! */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_PORT_NUMBER; storep = &u->port; } break; @@ -1520,7 +1566,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, char *redired_url; CURLU *handle2; - if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN + 1)) { + if(Curl_is_absolute_url(part, NULL, 0)) { handle2 = curl_url(); if(!handle2) return CURLUE_OUT_OF_MEMORY; @@ -1655,7 +1701,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, else { if(hostname_check(u, (char *)newp)) { free((char *)newp); - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_HOSTNAME; } } } diff --git a/libs/libcurl/src/urldata.h b/libs/libcurl/src/urldata.h index 22068882f0..cc9c888709 100644 --- a/libs/libcurl/src/urldata.h +++ b/libs/libcurl/src/urldata.h @@ -518,7 +518,9 @@ struct ConnectBits { BIT(tls_enable_npn); /* TLS NPN extension? */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ BIT(connect_only); +#ifndef CURL_DISABLE_DOH BIT(doh); +#endif #ifdef USE_UNIX_SOCKETS BIT(abstract_unix_socket); #endif @@ -835,6 +837,7 @@ struct Curl_handler { #define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */ #define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in user name and password */ +#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol can't proxy over TCP */ #define CONNCHECK_NONE 0 /* No checks */ #define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */ @@ -1749,6 +1752,7 @@ struct UserDefined { unsigned int scope_id; /* Scope id for IPv6 */ long allowed_protocols; long redir_protocols; + long mime_options; /* Mime option flags. */ struct curl_slist *mail_rcpt; /* linked list of mail recipients */ /* Common RTSP header options */ Curl_RtspReq rtspreq; /* RTSP request type */ @@ -1856,10 +1860,12 @@ struct UserDefined { header */ BIT(abstract_unix_socket); BIT(disallow_username_in_url); /* disallow username in url */ +#ifndef CURL_DISABLE_DOH BIT(doh); /* DNS-over-HTTPS enabled */ BIT(doh_verifypeer); /* DoH certificate peer verification */ BIT(doh_verifyhost); /* DoH certificate hostname verification */ BIT(doh_verifystatus); /* DoH certificate status verification */ +#endif BIT(http09_allowed); /* allow HTTP/0.9 responses */ BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some recipients */ diff --git a/libs/libcurl/src/vauth/digest.c b/libs/libcurl/src/vauth/digest.c index a04ffab6fb..d8aac66bda 100644 --- a/libs/libcurl/src/vauth/digest.c +++ b/libs/libcurl/src/vauth/digest.c @@ -230,7 +230,7 @@ static CURLcode auth_digest_get_qop_values(const char *options, int *value) return CURLE_OUT_OF_MEMORY; token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { + while(token) { if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) *value |= DIGEST_QOP_VALUE_AUTH; else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) @@ -556,7 +556,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, return CURLE_OUT_OF_MEMORY; token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { + while(token) { if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { foundAuth = TRUE; } @@ -666,8 +666,8 @@ static CURLcode auth_create_digest_http_message( struct digestdata *digest, char **outptr, size_t *outlen, void (*convert_to_ascii)(unsigned char *, unsigned char *), - void (*hash)(unsigned char *, const unsigned char *, - const size_t)) + CURLcode (*hash)(unsigned char *, const unsigned char *, + const size_t)) { CURLcode result; unsigned char hashbuf[32]; /* 32 bytes/256 bits */ @@ -722,8 +722,7 @@ static CURLcode auth_create_digest_http_message( unq(nonce-value) ":" unq(cnonce-value) */ - hashthis = aprintf("%s:%s:%s", digest->userhash ? userh : userp, - digest->realm, passwdp); + hashthis = aprintf("%s:%s:%s", userp, digest->realm, passwdp); if(!hashthis) return CURLE_OUT_OF_MEMORY; diff --git a/libs/libcurl/src/vauth/ntlm.c b/libs/libcurl/src/vauth/ntlm.c index 0aa3f1c8ca..04f6590acf 100644 --- a/libs/libcurl/src/vauth/ntlm.c +++ b/libs/libcurl/src/vauth/ntlm.c @@ -603,7 +603,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, memcpy(tmp, &ntlm->nonce[0], 8); memcpy(tmp + 8, entropy, 8); - Curl_md5it(md5sum, tmp, 16); + result = Curl_md5it(md5sum, tmp, 16); + if(result) + return result; /* We shall only use the first 8 bytes of md5sum, but the des code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ diff --git a/libs/libcurl/src/version_win32.c b/libs/libcurl/src/version_win32.c index 2f845413cc..79a2aa6ab4 100644 --- a/libs/libcurl/src/version_win32.c +++ b/libs/libcurl/src/version_win32.c @@ -57,6 +57,8 @@ struct OUR_OSVERSIONINFOEXW { * * majorVersion [in] - The major version number. * minorVersion [in] - The minor version number. + * buildVersion [in] - The build version number. If 0, this parameter is + * ignored. * platform [in] - The optional platform identifier. * condition [in] - The test condition used to specifier whether we are * checking a version less then, equal to or greater than @@ -67,6 +69,7 @@ struct OUR_OSVERSIONINFOEXW { */ bool curlx_verify_windows_version(const unsigned int majorVersion, const unsigned int minorVersion, + const unsigned int buildVersion, const PlatformIdentifier platform, const VersionCondition condition) { @@ -118,34 +121,52 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, case VERSION_LESS_THAN: if(osver.dwMajorVersion < majorVersion || (osver.dwMajorVersion == majorVersion && - osver.dwMinorVersion < minorVersion)) + osver.dwMinorVersion < minorVersion) || + (buildVersion != 0 && + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + osver.dwBuildNumber < buildVersion))) matched = TRUE; break; case VERSION_LESS_THAN_EQUAL: if(osver.dwMajorVersion < majorVersion || (osver.dwMajorVersion == majorVersion && - osver.dwMinorVersion <= minorVersion)) + osver.dwMinorVersion < minorVersion) || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + (buildVersion == 0 || + osver.dwBuildNumber <= buildVersion))) matched = TRUE; break; case VERSION_EQUAL: if(osver.dwMajorVersion == majorVersion && - osver.dwMinorVersion == minorVersion) + osver.dwMinorVersion == minorVersion && + (buildVersion == 0 || + osver.dwBuildNumber == buildVersion)) matched = TRUE; break; case VERSION_GREATER_THAN_EQUAL: if(osver.dwMajorVersion > majorVersion || (osver.dwMajorVersion == majorVersion && - osver.dwMinorVersion >= minorVersion)) + osver.dwMinorVersion > minorVersion) || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + (buildVersion == 0 || + osver.dwBuildNumber >= buildVersion))) matched = TRUE; break; case VERSION_GREATER_THAN: if(osver.dwMajorVersion > majorVersion || (osver.dwMajorVersion == majorVersion && - osver.dwMinorVersion > minorVersion)) + osver.dwMinorVersion > minorVersion) || + (buildVersion != 0 && + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion && + osver.dwBuildNumber > buildVersion))) matched = TRUE; break; } @@ -161,6 +182,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, case PLATFORM_WINNT: if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT) matched = FALSE; + break; default: /* like platform == PLATFORM_DONT_CARE */ break; @@ -172,8 +194,11 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, struct OUR_OSVERSIONINFOEXW osver; BYTE majorCondition; BYTE minorCondition; + BYTE buildCondition; BYTE spMajorCondition; BYTE spMinorCondition; + DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN) (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG); @@ -190,6 +215,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, case VERSION_LESS_THAN: majorCondition = VER_LESS; minorCondition = VER_LESS; + buildCondition = VER_LESS; spMajorCondition = VER_LESS_EQUAL; spMinorCondition = VER_LESS_EQUAL; break; @@ -197,6 +223,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, case VERSION_LESS_THAN_EQUAL: majorCondition = VER_LESS_EQUAL; minorCondition = VER_LESS_EQUAL; + buildCondition = VER_LESS_EQUAL; spMajorCondition = VER_LESS_EQUAL; spMinorCondition = VER_LESS_EQUAL; break; @@ -204,6 +231,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, case VERSION_EQUAL: majorCondition = VER_EQUAL; minorCondition = VER_EQUAL; + buildCondition = VER_EQUAL; spMajorCondition = VER_GREATER_EQUAL; spMinorCondition = VER_GREATER_EQUAL; break; @@ -211,6 +239,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, case VERSION_GREATER_THAN_EQUAL: majorCondition = VER_GREATER_EQUAL; minorCondition = VER_GREATER_EQUAL; + buildCondition = VER_GREATER_EQUAL; spMajorCondition = VER_GREATER_EQUAL; spMinorCondition = VER_GREATER_EQUAL; break; @@ -218,6 +247,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, case VERSION_GREATER_THAN: majorCondition = VER_GREATER; minorCondition = VER_GREATER; + buildCondition = VER_GREATER; spMajorCondition = VER_GREATER_EQUAL; spMinorCondition = VER_GREATER_EQUAL; break; @@ -230,6 +260,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, osver.dwOSVersionInfoSize = sizeof(osver); osver.dwMajorVersion = majorVersion; osver.dwMinorVersion = minorVersion; + osver.dwBuildNumber = buildVersion; if(platform == PLATFORM_WINDOWS) osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; else if(platform == PLATFORM_WINNT) @@ -239,26 +270,43 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition); cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition); cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition); - if(platform != PLATFORM_DONT_CARE) + + if(platform != PLATFORM_DONT_CARE) { cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); + dwTypeMask |= VER_PLATFORMID; + } /* Later versions of Windows have version functions that may not return the real version of Windows unless the application is so manifested. We prefer the real version always, so we use the Rtl variant of the function when possible. Note though the function signatures have underlying fundamental types that are the same, the return values are different. */ - if(pRtlVerifyVersionInfo) { - matched = !pRtlVerifyVersionInfo(&osver, - (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), - cm); - } - else { - matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, - (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), - cm); + if(pRtlVerifyVersionInfo) + matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); + else + matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm); + + /* Compare the build number separately. VerifyVersionInfo normally compares + major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not + do the same for build (eg 1.9 build 222 is not less than 2.0 build 111). + Build comparison is only needed when build numbers are equal (eg 1.9 is + always less than 2.0 so build comparison is not needed). */ + if(matched && buildVersion && + (condition == VERSION_EQUAL || + ((condition == VERSION_GREATER_THAN_EQUAL || + condition == VERSION_LESS_THAN_EQUAL) && + curlx_verify_windows_version(majorVersion, minorVersion, 0, + platform, VERSION_EQUAL)))) { + + cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition); + dwTypeMask = VER_BUILDNUMBER; + if(pRtlVerifyVersionInfo) + matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm); + else + matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, + dwTypeMask, cm); } + #endif return matched; diff --git a/libs/libcurl/src/version_win32.h b/libs/libcurl/src/version_win32.h index 9b1bd88874..38af87fa09 100644 --- a/libs/libcurl/src/version_win32.h +++ b/libs/libcurl/src/version_win32.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2016 - 2020, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2016 - 2021, Steve Holme, <steve_holme@hotmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -45,6 +45,7 @@ typedef enum { /* This is used to verify if we are running on a specific windows version */ bool curlx_verify_windows_version(const unsigned int majorVersion, const unsigned int minorVersion, + const unsigned int buildVersion, const PlatformIdentifier platform, const VersionCondition condition); diff --git a/libs/libcurl/src/vquic/ngtcp2.c b/libs/libcurl/src/vquic/ngtcp2.c index dfe8f96fb1..1596049b77 100644 --- a/libs/libcurl/src/vquic/ngtcp2.c +++ b/libs/libcurl/src/vquic/ngtcp2.c @@ -29,8 +29,10 @@ #ifdef USE_OPENSSL #include <openssl/err.h> #include <ngtcp2/ngtcp2_crypto_openssl.h> +#include "vtls/openssl.h" #elif defined(USE_GNUTLS) #include <ngtcp2/ngtcp2_crypto_gnutls.h> +#include "vtls/gtls.h" #endif #include "urldata.h" #include "sendf.h" @@ -287,6 +289,27 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); } + { + struct connectdata *conn = data->conn; + const char * const ssl_cafile = conn->ssl_config.CAfile; + const char * const ssl_capath = conn->ssl_config.CApath; + + if(conn->ssl_config.verifypeer) { + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + /* tell OpenSSL where to find CA certificates that are used to verify + the server's certificate. */ + if(!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return NULL; + } + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } + } return ssl_ctx; } @@ -1638,8 +1661,10 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data, return sent; } -static void ng_has_connected(struct connectdata *conn, int tempindex) +static CURLcode ng_has_connected(struct Curl_easy *data, + struct connectdata *conn, int tempindex) { + CURLcode result = CURLE_OK; conn->recv[FIRSTSOCKET] = ngh3_stream_recv; conn->send[FIRSTSOCKET] = ngh3_stream_send; conn->handler = &Curl_handler_http3; @@ -1647,6 +1672,27 @@ static void ng_has_connected(struct connectdata *conn, int tempindex) conn->httpversion = 30; conn->bundle->multiuse = BUNDLE_MULTIPLEX; conn->quic = &conn->hequic[tempindex]; + + if(conn->ssl_config.verifyhost) { +#ifdef USE_OPENSSL + X509 *server_cert; + CURLcode result; + server_cert = SSL_get_peer_certificate(conn->quic->ssl); + if(!server_cert) { + return CURLE_PEER_FAILED_VERIFICATION; + } + result = Curl_ossl_verifyhost(data, conn, server_cert); + X509_free(server_cert); + if(result) + return result; + infof(data, "Verified certificate just fine"); +#else + result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET); +#endif + } + else + infof(data, "Skipped certificate verification"); + return result; } /* @@ -1670,8 +1716,9 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data, goto error; if(ngtcp2_conn_get_handshake_completed(qs->qconn)) { - *done = TRUE; - ng_has_connected(conn, sockindex); + result = ng_has_connected(data, conn, sockindex); + if(!result) + *done = TRUE; } return result; @@ -1718,6 +1765,10 @@ static CURLcode ng_process_ingress(struct Curl_easy *data, rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts); if(rv) { /* TODO Send CONNECTION_CLOSE if possible */ + if(rv == NGTCP2_ERR_CRYPTO) + /* this is a "TLS problem", but a failed certificate verification + is a common reason for this */ + return CURLE_PEER_FAILED_VERIFICATION; return CURLE_RECV_ERROR; } } diff --git a/libs/libcurl/src/vssh/libssh2.c b/libs/libcurl/src/vssh/libssh2.c index 7466840ffa..581bc1be82 100644 --- a/libs/libcurl/src/vssh/libssh2.c +++ b/libs/libcurl/src/vssh/libssh2.c @@ -645,8 +645,8 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL); if(hostkey) { - Curl_sha256it(hash, (const unsigned char *) hostkey, len); - fingerprint = (char *) hash; + if(!Curl_sha256it(hash, (const unsigned char *) hostkey, len)) + fingerprint = (char *) hash; } #endif @@ -661,16 +661,15 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) /* The length of fingerprint is 32 bytes for SHA256. * See libssh2_hostkey_hash documentation. */ - if(Curl_base64_encode (data, fingerprint, 32, &fingerprint_b64, - &fingerprint_b64_len) != CURLE_OK) { + if(Curl_base64_encode(data, fingerprint, 32, &fingerprint_b64, + &fingerprint_b64_len) != CURLE_OK) { state(data, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } if(!fingerprint_b64) { - failf(data, - "sha256 fingerprint could not be encoded"); + failf(data, "sha256 fingerprint could not be encoded"); state(data, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; @@ -698,7 +697,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) failf(data, "Denied establishing ssh session: mismatch sha256 fingerprint. " - "Remote %s is not equal to %s", fingerprint, pubkey_sha256); + "Remote %s is not equal to %s", fingerprint_b64, pubkey_sha256); state(data, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c index 2053fd439d..18864aa4b2 100644 --- a/libs/libcurl/src/vtls/gtls.c +++ b/libs/libcurl/src/vtls/gtls.c @@ -497,6 +497,7 @@ gtls_connect_step1(struct Curl_easy *data, /* use system ca certificate store as fallback */ if(SSL_CONN_CONFIG(verifypeer) && !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) { + /* this ignores errors on purpose */ gnutls_certificate_set_x509_system_trust(backend->cred); } #endif @@ -631,7 +632,10 @@ gtls_connect_step1(struct Curl_easy *data, cur++; infof(data, "ALPN, offering %s", ALPN_HTTP_1_1); - gnutls_alpn_set_protocols(session, protocols, cur, 0); + if(gnutls_alpn_set_protocols(session, protocols, cur, 0)) { + failf(data, "failed setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } } if(SSL_SET_OPTION(primary.clientcert)) { @@ -757,10 +761,10 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ - if(NULL == pinnedpubkey) + if(!pinnedpubkey) return CURLE_OK; - if(NULL == cert) + if(!cert) return result; do { @@ -778,7 +782,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, break; /* failed */ buff1 = malloc(len1); - if(NULL == buff1) + if(!buff1) break; /* failed */ len2 = len1; @@ -793,7 +797,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); - if(NULL != key) + if(key) gnutls_pubkey_deinit(key); Curl_safefree(buff1); @@ -804,10 +808,11 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, static Curl_recv gtls_recv; static Curl_send gtls_send; -static CURLcode -gtls_connect_step3(struct Curl_easy *data, - struct connectdata *conn, - int sockindex) +CURLcode +Curl_gtls_verifyserver(struct Curl_easy *data, + struct connectdata *conn, + gnutls_session_t session, + int sockindex) { unsigned int cert_list_size; const gnutls_datum_t *chainp; @@ -819,9 +824,6 @@ gtls_connect_step3(struct Curl_easy *data, size_t size; time_t certclock; const char *ptr; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_backend_data *backend = connssl->backend; - gnutls_session_t session = backend->session; int rc; gnutls_datum_t proto; CURLcode result = CURLE_OK; @@ -1265,8 +1267,6 @@ gtls_connect_step3(struct Curl_easy *data, } conn->ssl[sockindex].state = ssl_connection_complete; - conn->recv[sockindex] = gtls_recv; - conn->send[sockindex] = gtls_send; if(SSL_SET_OPTION(primary.sessionid)) { /* we always unconditionally get the session id here, as even if we @@ -1351,9 +1351,13 @@ gtls_connect_common(struct Curl_easy *data, /* Finish connecting once the handshake is done */ if(ssl_connect_1 == connssl->connecting_state) { - rc = gtls_connect_step3(data, conn, sockindex); + struct ssl_backend_data *backend = connssl->backend; + gnutls_session_t session = backend->session; + rc = Curl_gtls_verifyserver(data, conn, session, sockindex); if(rc) return rc; + conn->recv[sockindex] = gtls_recv; + conn->send[sockindex] = gtls_send; } *done = ssl_connect_1 == connssl->connecting_state; diff --git a/libs/libcurl/src/vtls/gtls.h b/libs/libcurl/src/vtls/gtls.h index 1a146a3a93..642d5f093a 100644 --- a/libs/libcurl/src/vtls/gtls.h +++ b/libs/libcurl/src/vtls/gtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,7 +27,11 @@ #ifdef USE_GNUTLS #include "urldata.h" - +#include <gnutls/gnutls.h> +CURLcode +Curl_gtls_verifyserver(struct Curl_easy *data, struct connectdata *conn, + gnutls_session_t session, + int sockindex); extern const struct Curl_ssl Curl_ssl_gnutls; #endif /* USE_GNUTLS */ diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c index 08c79e1624..1d209b2732 100644 --- a/libs/libcurl/src/vtls/mbedtls.c +++ b/libs/libcurl/src/vtls/mbedtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which @@ -270,7 +270,10 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; - const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); char * const ssl_cert = SSL_SET_OPTION(primary.clientcert); @@ -316,16 +319,34 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, /* Load the trusted CA */ mbedtls_x509_crt_init(&backend->cacert); - if(ssl_cafile) { + if(ca_info_blob && verifypeer) { + /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null + terminated even when provided the exact length, forcing us to waste + extra memory here. */ + unsigned char *newblob = malloc(ca_info_blob->len + 1); + if(!newblob) + return CURLE_OUT_OF_MEMORY; + memcpy(newblob, ca_info_blob->data, ca_info_blob->len); + newblob[ca_info_blob->len] = 0; /* null terminate */ + ret = mbedtls_x509_crt_parse(&backend->cacert, newblob, + ca_info_blob->len + 1); + free(newblob); + if(ret<0) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s", + -ret, errorbuf); + return ret; + } + } + + if(ssl_cafile && verifypeer) { ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile); if(ret<0) { mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", ssl_cafile, -ret, errorbuf); - - if(verifypeer) - return CURLE_SSL_CACERT_BADFILE; + return CURLE_SSL_CACERT_BADFILE; } } @@ -358,10 +379,17 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, } if(ssl_cert_blob) { - const unsigned char *blob_data = - (const unsigned char *)ssl_cert_blob->data; - ret = mbedtls_x509_crt_parse(&backend->clicert, blob_data, + /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null + terminated even when provided the exact length, forcing us to waste + extra memory here. */ + unsigned char *newblob = malloc(ssl_cert_blob->len + 1); + if(!newblob) + return CURLE_OUT_OF_MEMORY; + memcpy(newblob, ssl_cert_blob->data, ssl_cert_blob->len); + newblob[ssl_cert_blob->len] = 0; /* null terminate */ + ret = mbedtls_x509_crt_parse(&backend->clicert, newblob, ssl_cert_blob->len); + free(newblob); if(ret) { mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -671,7 +699,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, mbedtls_x509_crt *p = NULL; unsigned char *pubkey = NULL; -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#if MBEDTLS_VERSION_NUMBER == 0x03000000 if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) { #else @@ -698,7 +726,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/ARMmbed/mbedtls/issues/396 */ -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#if MBEDTLS_VERSION_NUMBER == 0x03000000 if(mbedtls_x509_crt_parse_der(p, peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) { @@ -710,7 +738,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, goto pinnedpubkey_error; } -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#if MBEDTLS_VERSION_NUMBER == 0x03000000 size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey, PUB_DER_MAX_BYTES); #else @@ -1154,6 +1182,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = { { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */ SSLSUPP_CA_PATH | + SSLSUPP_CAINFO_BLOB | SSLSUPP_PINNEDPUBKEY | SSLSUPP_SSL_CTX, diff --git a/libs/libcurl/src/vtls/mesalink.c b/libs/libcurl/src/vtls/mesalink.c index 0a1dea3ac0..35a916586e 100644 --- a/libs/libcurl/src/vtls/mesalink.c +++ b/libs/libcurl/src/vtls/mesalink.c @@ -68,8 +68,6 @@ struct ssl_backend_data SSL *handle; }; -#define BACKEND connssl->backend - static Curl_recv mesalink_recv; static Curl_send mesalink_send; @@ -100,9 +98,9 @@ mesalink_connect_step1(struct Curl_easy *data, #endif const char * const hostname = SSL_HOST_NAME(); size_t hostname_len = strlen(hostname); - SSL_METHOD *req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_backend_data *backend = connssl->backend; if(connssl->state == ssl_connection_complete) return CURLE_OK; @@ -139,22 +137,22 @@ mesalink_connect_step1(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - if(BACKEND->ctx) - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = SSL_CTX_new(req_method); + if(backend->ctx) + SSL_CTX_free(backend->ctx); + backend->ctx = SSL_CTX_new(req_method); - if(!BACKEND->ctx) { + if(!backend->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } SSL_CTX_set_verify( - BACKEND->ctx, SSL_CONN_CONFIG(verifypeer) ? + backend->ctx, SSL_CONN_CONFIG(verifypeer) ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath)) { - if(!SSL_CTX_load_verify_locations(BACKEND->ctx, SSL_CONN_CONFIG(CAfile), - SSL_CONN_CONFIG(CApath))) { + if(!SSL_CTX_load_verify_locations(backend->ctx, SSL_CONN_CONFIG(CAfile), + SSL_CONN_CONFIG(CApath))) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "error setting certificate verify locations: " @@ -181,7 +179,7 @@ mesalink_connect_step1(struct Curl_easy *data, if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) { int file_type = do_file_type(SSL_SET_OPTION(cert_type)); - if(SSL_CTX_use_certificate_chain_file(BACKEND->ctx, + if(SSL_CTX_use_certificate_chain_file(backend->ctx, SSL_SET_OPTION(primary.clientcert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" @@ -190,8 +188,8 @@ mesalink_connect_step1(struct Curl_easy *data, } file_type = do_file_type(SSL_SET_OPTION(key_type)); - if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key), - file_type) != 1) { + if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key), + file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; } @@ -204,7 +202,7 @@ mesalink_connect_step1(struct Curl_easy *data, ciphers = SSL_CONN_CONFIG(cipher_list); if(ciphers) { #ifdef MESALINK_HAVE_CIPHER - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } @@ -212,10 +210,10 @@ mesalink_connect_step1(struct Curl_easy *data, infof(data, "Cipher selection: %s", ciphers); } - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } @@ -227,7 +225,7 @@ mesalink_connect_step1(struct Curl_easy *data, #endif ) { /* hostname is not a valid IP address */ - if(SSL_set_tlsext_host_name(BACKEND->handle, hostname) != SSL_SUCCESS) { + if(SSL_set_tlsext_host_name(backend->handle, hostname) != SSL_SUCCESS) { failf(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -244,7 +242,7 @@ mesalink_connect_step1(struct Curl_easy *data, || strncmp(hostname, "[::1]", 5) == 0 #endif ) { - SSL_set_tlsext_host_name(BACKEND->handle, "localhost"); + SSL_set_tlsext_host_name(backend->handle, "localhost"); } else #endif @@ -264,12 +262,12 @@ mesalink_connect_step1(struct Curl_easy *data, SSL_IS_PROXY() ? TRUE : FALSE, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ - if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + if(!SSL_set_session(backend->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(data); failf( data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer)); + ERR_error_string(SSL_get_error(backend->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ @@ -279,7 +277,7 @@ mesalink_connect_step1(struct Curl_easy *data, } #endif /* MESALINK_HAVE_SESSION */ - if(SSL_set_fd(BACKEND->handle, (int)sockfd) != SSL_SUCCESS) { + if(SSL_set_fd(backend->handle, (int)sockfd) != SSL_SUCCESS) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } @@ -294,13 +292,14 @@ mesalink_connect_step2(struct Curl_easy *data, { int ret = -1; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; conn->recv[sockindex] = mesalink_recv; conn->send[sockindex] = mesalink_send; - ret = SSL_connect(BACKEND->handle); + ret = SSL_connect(backend->handle); if(ret != SSL_SUCCESS) { - int detail = SSL_get_error(BACKEND->handle, ret); + int detail = SSL_get_error(backend->handle, ret); if(SSL_ERROR_WANT_CONNECT == detail || SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; @@ -327,8 +326,8 @@ mesalink_connect_step2(struct Curl_easy *data, connssl->connecting_state = ssl_connect_3; infof(data, "SSL connection using %s / %s", - SSL_get_version(BACKEND->handle), - SSL_get_cipher_name(BACKEND->handle)); + SSL_get_version(backend->handle), + SSL_get_cipher_name(backend->handle)); return CURLE_OK; } @@ -347,8 +346,9 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex) SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + struct ssl_backend_data *backend = connssl->backend; - our_ssl_sessionid = SSL_get_session(BACKEND->handle); + our_ssl_sessionid = SSL_get_session(backend->handle); Curl_ssl_sessionid_lock(data); incache = @@ -387,12 +387,13 @@ mesalink_send(struct Curl_easy *data, int sockindex, const void *mem, { struct connectdata *conn = data->conn; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; char error_buffer[MESALINK_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - int rc = SSL_write(BACKEND->handle, mem, memlen); + int rc = SSL_write(backend->handle, mem, memlen); if(rc < 0) { - int err = SSL_get_error(BACKEND->handle, rc); + int err = SSL_get_error(backend->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: @@ -415,17 +416,18 @@ static void mesalink_close(struct Curl_easy *data, struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; (void) data; - if(BACKEND->handle) { - (void)SSL_shutdown(BACKEND->handle); - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + if(backend->handle) { + (void)SSL_shutdown(backend->handle); + SSL_free(backend->handle); + backend->handle = NULL; } - if(BACKEND->ctx) { - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = NULL; + if(backend->ctx) { + SSL_CTX_free(backend->ctx); + backend->ctx = NULL; } } @@ -435,12 +437,13 @@ mesalink_recv(struct Curl_easy *data, int num, char *buf, size_t buffersize, { struct connectdata *conn = data->conn; struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; char error_buffer[MESALINK_MAX_ERROR_SZ]; int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - int nread = SSL_read(BACKEND->handle, buf, buffsize); + int nread = SSL_read(backend->handle, buf, buffsize); if(nread <= 0) { - int err = SSL_get_error(BACKEND->handle, nread); + int err = SSL_get_error(backend->handle, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ @@ -485,12 +488,13 @@ mesalink_shutdown(struct Curl_easy *data, { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; (void) data; - if(BACKEND->handle) { - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + if(backend->handle) { + SSL_free(backend->handle); + backend->handle = NULL; } return retval; } @@ -636,8 +640,9 @@ static void * mesalink_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->handle; + return backend->handle; } const struct Curl_ssl Curl_ssl_mesalink = { diff --git a/libs/libcurl/src/vtls/nss.c b/libs/libcurl/src/vtls/nss.c index 1897b9ab1d..2b44f05126 100644 --- a/libs/libcurl/src/vtls/nss.c +++ b/libs/libcurl/src/vtls/nss.c @@ -304,13 +304,14 @@ static char *nss_sslver_to_name(PRUint16 nssver) } } -static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, - char *cipher_list) +/* the longest cipher name this supports */ +#define MAX_CIPHER_LENGTH 128 + +static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc *model, + const char *cipher_list) { unsigned int i; - PRBool cipher_state[NUM_OF_CIPHERS]; - PRBool found; - char *cipher; + const char *cipher; /* use accessors to avoid dynamic linking issues after an update of NSS */ const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers(); @@ -326,51 +327,52 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE); } - /* Set every entry in our list to false */ - for(i = 0; i < NUM_OF_CIPHERS; i++) { - cipher_state[i] = PR_FALSE; - } - cipher = cipher_list; - while(cipher_list && (cipher_list[0])) { + while(cipher && cipher[0]) { + const char *end; + char name[MAX_CIPHER_LENGTH + 1]; + size_t len; + bool found = FALSE; while((*cipher) && (ISSPACE(*cipher))) ++cipher; - cipher_list = strpbrk(cipher, ":, "); - if(cipher_list) { - *cipher_list++ = '\0'; - } - - found = PR_FALSE; - - for(i = 0; i<NUM_OF_CIPHERS; i++) { - if(strcasecompare(cipher, cipherlist[i].name)) { - cipher_state[i] = PR_TRUE; - found = PR_TRUE; - break; - } - } + end = strpbrk(cipher, ":, "); + if(end) + len = end - cipher; + else + len = strlen(cipher); - if(found == PR_FALSE) { - failf(data, "Unknown cipher in list: %s", cipher); + if(len > MAX_CIPHER_LENGTH) { + failf(data, "Bad cipher list"); return SECFailure; } - - if(cipher_list) { - cipher = cipher_list; + else if(len) { + memcpy(name, cipher, len); + name[len] = 0; + + for(i = 0; i<NUM_OF_CIPHERS; i++) { + if(strcasecompare(name, cipherlist[i].name)) { + /* Enable the selected cipher */ + if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != + SECSuccess) { + failf(data, "cipher-suite not supported by NSS: %s", name); + return SECFailure; + } + found = TRUE; + break; + } + } } - } - /* Finally actually enable the selected ciphers */ - for(i = 0; i<NUM_OF_CIPHERS; i++) { - if(!cipher_state[i]) - continue; - - if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) { - failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name); + if(!found && len) { + failf(data, "Unknown cipher: %s", name); return SECFailure; } + if(end) + cipher = ++end; + else + break; } return SECSuccess; @@ -782,7 +784,7 @@ static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg) { (void)slot; /* unused */ - if(retry || NULL == arg) + if(retry || !arg) return NULL; else return (char *)PORT_Strdup((char *)arg); @@ -1168,7 +1170,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct SECKEYPrivateKeyStr *key; PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname); - if(NULL == slot) { + if(!slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; } @@ -1182,7 +1184,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win); SECITEM_FreeItem(&cert_der, PR_FALSE); - if(NULL == cert) { + if(!cert) { failf(data, "NSS: client certificate from file not found"); PK11_FreeSlot(slot); return SECFailure; @@ -1190,7 +1192,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, key = PK11_FindPrivateKeyFromCert(slot, cert, NULL); PK11_FreeSlot(slot); - if(NULL == key) { + if(!key) { failf(data, "NSS: private key from file not found"); CERT_DestroyCertificate(cert); return SECFailure; @@ -1207,9 +1209,9 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, /* use the default NSS hook */ if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, pRetCert, pRetKey) - || NULL == *pRetCert) { + || !*pRetCert) { - if(NULL == nickname) + if(!nickname) failf(data, "NSS: client certificate not found (nickname not " "specified)"); else @@ -1220,7 +1222,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, /* get certificate nickname if any */ nickname = (*pRetCert)->nickname; - if(NULL == nickname) + if(!nickname) nickname = "[unknown]"; if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) { @@ -1229,7 +1231,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, return SECFailure; } - if(NULL == *pRetKey) { + if(!*pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; } @@ -1344,7 +1346,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) PRErrorCode err; const char *err_name; - if(nss_context != NULL) + if(nss_context) return CURLE_OK; memset((void *) &initparams, '\0', sizeof(initparams)); @@ -1360,7 +1362,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) NSS_INIT_READONLY | NSS_INIT_PK11RELOAD); free(certpath); - if(nss_context != NULL) + if(nss_context) return CURLE_OK; err = PR_GetError(); @@ -1372,7 +1374,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); - if(nss_context != NULL) + if(nss_context) return CURLE_OK; err = PR_GetError(); diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c index a1baef9c3f..f836c63b07 100644 --- a/libs/libcurl/src/vtls/openssl.c +++ b/libs/libcurl/src/vtls/openssl.c @@ -171,6 +171,21 @@ #define OPENSSL_load_builtin_modules(x) #endif +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#define HAVE_EVP_PKEY_GET_PARAMS 1 +#else +#define SSL_get1_peer_certificate SSL_get_peer_certificate +#endif + +#ifdef HAVE_EVP_PKEY_GET_PARAMS +#include <openssl/core_names.h> +#define DECLARE_PKEY_PARAM_BIGNUM(name) BIGNUM *name = NULL +#define FREE_PKEY_PARAM_BIGNUM(name) BN_clear_free(name) +#else +#define DECLARE_PKEY_PARAM_BIGNUM(name) const BIGNUM *name +#define FREE_PKEY_PARAM_BIGNUM(name) +#endif + /* * Whether SSL_CTX_set_keylog_callback is available. * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 @@ -231,6 +246,13 @@ #define HAVE_RANDOM_INIT_BY_DEFAULT 1 #endif +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x2070100fL) && \ + !defined(OPENSSL_IS_BORINGSSL) +#define HAVE_OPENSSL_VERSION +#endif + struct ssl_backend_data { struct Curl_easy *logger; /* transfer handle to pass trace logs to, only using sockindex 0 */ @@ -1099,7 +1121,8 @@ int cert_stuff(struct Curl_easy *data, EVP_PKEY_free(pktmp); } -#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) && \ + !defined(OPENSSL_NO_DEPRECATED_3_0) { /* If RSA is used, don't check the private key if its flags indicate * it doesn't support it. */ @@ -1412,6 +1435,12 @@ static void ossl_closeone(struct Curl_easy *data, if(backend->handle) { char buf[32]; set_logger(conn, data); + /* + * The conn->sock[0] socket is passed to openssl with SSL_set_fd(). Make + * sure the socket is not closed before calling OpenSSL functions that + * will use it. + */ + DEBUGASSERT(conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD); /* Maybe the server has already sent a close notify alert. Read it to avoid an RST on the TCP connection. */ @@ -1650,9 +1679,10 @@ static bool subj_alt_hostcheck(struct Curl_easy *data, hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI. + This function is now used from ngtcp2 (QUIC) as well. */ -static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn, - X509 *server_cert) +CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + X509 *server_cert) { bool matched = FALSE; int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ @@ -1937,7 +1967,7 @@ static CURLcode verifystatus(struct Curl_easy *data, } /* Compute the certificate's ID */ - cert = SSL_get_peer_certificate(backend->handle); + cert = SSL_get1_peer_certificate(backend->handle); if(!cert) { failf(data, "Error getting peer certificate"); result = CURLE_SSL_INVALIDCERTSTATUS; @@ -3466,10 +3496,7 @@ static void pubkey_show(struct Curl_easy *data, int num, const char *type, const char *name, -#ifdef HAVE_OPAQUE_RSA_DSA_DH - const -#endif - BIGNUM *bn) + const BIGNUM *bn) { char *ptr; char namebuf[32]; @@ -3534,12 +3561,6 @@ typedef size_t numcert_t; typedef int numcert_t; #endif -#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) -#define OSSL3_CONST const -#else -#define OSSL3_CONST -#endif - static CURLcode get_cert_chain(struct Curl_easy *data, struct ssl_connect_data *connssl) { @@ -3563,6 +3584,9 @@ static CURLcode get_cert_chain(struct Curl_easy *data, } mem = BIO_new(BIO_s_mem()); + if(!mem) { + return CURLE_OUT_OF_MEMORY; + } for(i = 0; i < (int)numcerts; i++) { ASN1_INTEGER *num; @@ -3647,92 +3671,115 @@ static CURLcode get_cert_chain(struct Curl_easy *data, switch(pktype) { case EVP_PKEY_RSA: { - OSSL3_CONST RSA *rsa; +#ifndef HAVE_EVP_PKEY_GET_PARAMS + RSA *rsa; #ifdef HAVE_OPAQUE_EVP_PKEY rsa = EVP_PKEY_get0_RSA(pubkey); #else rsa = pubkey->pkey.rsa; -#endif +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ -#ifdef HAVE_OPAQUE_RSA_DSA_DH { - const BIGNUM *n; - const BIGNUM *e; - +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(n); + DECLARE_PKEY_PARAM_BIGNUM(e); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e); +#else RSA_get0_key(rsa, &n, &e, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ BIO_printf(mem, "%d", BN_num_bits(n)); +#else + BIO_printf(mem, "%d", BN_num_bits(rsa->n)); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); + FREE_PKEY_PARAM_BIGNUM(n); + FREE_PKEY_PARAM_BIGNUM(e); } -#else - BIO_printf(mem, "%d", BN_num_bits(rsa->n)); - push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); - print_pubkey_BN(rsa, e, i); -#endif break; } case EVP_PKEY_DSA: { #ifndef OPENSSL_NO_DSA - OSSL3_CONST DSA *dsa; +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DSA *dsa; #ifdef HAVE_OPAQUE_EVP_PKEY dsa = EVP_PKEY_get0_DSA(pubkey); #else dsa = pubkey->pkey.dsa; -#endif -#ifdef HAVE_OPAQUE_RSA_DSA_DH +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ { - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *g; - const BIGNUM *pub_key; - +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else DSA_get0_pqg(dsa, &p, &q, &g); DSA_get0_key(dsa, &pub_key, NULL); - +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); print_pubkey_BN(dsa, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); } -#else - print_pubkey_BN(dsa, p, i); - print_pubkey_BN(dsa, q, i); - print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, pub_key, i); -#endif #endif /* !OPENSSL_NO_DSA */ break; } case EVP_PKEY_DH: { - OSSL3_CONST DH *dh; +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DH *dh; #ifdef HAVE_OPAQUE_EVP_PKEY dh = EVP_PKEY_get0_DH(pubkey); #else dh = pubkey->pkey.dh; -#endif -#ifdef HAVE_OPAQUE_RSA_DSA_DH +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ { - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *g; - const BIGNUM *pub_key; +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else DH_get0_pqg(dh, &p, &q, &g); DH_get0_key(dh, &pub_key, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, q, i); print_pubkey_BN(dh, g, i); +#else + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, g, i); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ print_pubkey_BN(dh, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); } -#else - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, g, i); - print_pubkey_BN(dh, pub_key, i); -#endif break; } } @@ -3836,11 +3883,20 @@ static CURLcode servercert(struct Curl_easy *data, BIO *mem = BIO_new(BIO_s_mem()); struct ssl_backend_data *backend = connssl->backend; + if(!mem) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return CURLE_OUT_OF_MEMORY; + } + if(data->set.ssl.certinfo) /* we've been asked to gather certificate info! */ (void)get_cert_chain(data, connssl); - backend->server_cert = SSL_get_peer_certificate(backend->handle); + backend->server_cert = SSL_get1_peer_certificate(backend->handle); if(!backend->server_cert) { BIO_free(mem); if(!strict) @@ -3874,7 +3930,7 @@ static CURLcode servercert(struct Curl_easy *data, BIO_free(mem); if(SSL_CONN_CONFIG(verifyhost)) { - result = verifyhost(data, conn, backend->server_cert); + result = Curl_ossl_verifyhost(data, conn, backend->server_cert); if(result) { X509_free(backend->server_cert); backend->server_cert = NULL; @@ -4354,13 +4410,7 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */ static size_t ossl_version(char *buffer, size_t size) { #ifdef LIBRESSL_VERSION_NUMBER -#if LIBRESSL_VERSION_NUMBER < 0x2070100fL - return msnprintf(buffer, size, "%s/%lx.%lx.%lx", - OSSL_PACKAGE, - (LIBRESSL_VERSION_NUMBER>>28)&0xf, - (LIBRESSL_VERSION_NUMBER>>20)&0xff, - (LIBRESSL_VERSION_NUMBER>>12)&0xff); -#else /* OpenSSL_version() first appeared in LibreSSL 2.7.1 */ +#ifdef HAVE_OPENSSL_VERSION char *p; int count; const char *ver = OpenSSL_version(OPENSSL_VERSION); @@ -4374,6 +4424,12 @@ static size_t ossl_version(char *buffer, size_t size) *p = '_'; } return count; +#else + return msnprintf(buffer, size, "%s/%lx.%lx.%lx", + OSSL_PACKAGE, + (LIBRESSL_VERSION_NUMBER>>28)&0xf, + (LIBRESSL_VERSION_NUMBER>>20)&0xff, + (LIBRESSL_VERSION_NUMBER>>12)&0xff); #endif #elif defined(OPENSSL_IS_BORINGSSL) return msnprintf(buffer, size, OSSL_PACKAGE); diff --git a/libs/libcurl/src/vtls/openssl.h b/libs/libcurl/src/vtls/openssl.h index 2f6e1b2db8..28058453c0 100644 --- a/libs/libcurl/src/vtls/openssl.h +++ b/libs/libcurl/src/vtls/openssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,11 +26,15 @@ #ifdef USE_OPENSSL /* - * This header should only be needed to get included by vtls.c and openssl.c + * This header should only be needed to get included by vtls.c, openssl.c + * and ngtcp2.c */ +#include <openssl/x509v3.h> #include "urldata.h" +CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + X509 *server_cert); extern const struct Curl_ssl Curl_ssl_openssl; #endif /* USE_OPENSSL */ diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c index 2ac97ce28e..6dbb1ef3cd 100644 --- a/libs/libcurl/src/vtls/rustls.c +++ b/libs/libcurl/src/vtls/rustls.c @@ -27,7 +27,7 @@ #include "curl_printf.h" #include <errno.h> -#include <crustls.h> +#include <rustls.h> #include "inet_pton.h" #include "urldata.h" @@ -138,11 +138,6 @@ cr_recv(struct Curl_easy *data, int sockindex, *err = CURLE_READ_ERROR; return -1; } - else if(tls_bytes_read == 0) { - failf(data, "connection closed without TLS close_notify alert"); - *err = CURLE_READ_ERROR; - return -1; - } infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read); @@ -161,22 +156,21 @@ cr_recv(struct Curl_easy *data, int sockindex, (uint8_t *)plainbuf + plain_bytes_copied, plainlen - plain_bytes_copied, &n); - if(rresult == RUSTLS_RESULT_ALERT_CLOSE_NOTIFY) { - *err = CURLE_OK; - return 0; + if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) { + infof(data, "cr_recv got PLAINTEXT_EMPTY. will try again later."); + backend->data_pending = FALSE; + break; } else if(rresult != RUSTLS_RESULT_OK) { - failf(data, "error in rustls_connection_read"); + /* n always equals 0 in this case, don't need to check it */ + failf(data, "error in rustls_connection_read: %d", rresult); *err = CURLE_READ_ERROR; return -1; } else if(n == 0) { - /* rustls returns 0 from connection_read to mean "all currently - available data has been read." If we bring in more ciphertext with - read_tls, more plaintext will become available. So don't tell curl - this is an EOF. Instead, say "come back later." */ - infof(data, "cr_recv got 0 bytes of plaintext"); - backend->data_pending = FALSE; + /* n == 0 indicates clean EOF, but we may have read some other + plaintext bytes before we reached this. Break out of the loop + so we can figure out whether to return success or EOF. */ break; } else { @@ -185,15 +179,23 @@ cr_recv(struct Curl_easy *data, int sockindex, } } - /* If we wrote out 0 plaintext bytes, it might just mean we haven't yet - read a full TLS record. Return CURLE_AGAIN so curl doesn't treat this - as EOF. */ - if(plain_bytes_copied == 0) { + if(plain_bytes_copied) { + *err = CURLE_OK; + return plain_bytes_copied; + } + + /* If we wrote out 0 plaintext bytes, that means either we hit a clean EOF, + OR we got a RUSTLS_RESULT_PLAINTEXT_EMPTY. + If the latter, return CURLE_AGAIN so curl doesn't treat this as EOF. */ + if(!backend->data_pending) { *err = CURLE_AGAIN; return -1; } - return plain_bytes_copied; + /* Zero bytes read, and no RUSTLS_RESULT_PLAINTEXT_EMPTY, means the TCP + connection was cleanly closed (with a close_notify alert). */ + *err = CURLE_OK; + return 0; } /* @@ -309,10 +311,10 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn, config_builder = rustls_client_config_builder_new(); #ifdef USE_HTTP2 infof(data, "offering ALPN for HTTP/1.1 and HTTP/2"); - rustls_client_config_builder_set_protocols(config_builder, alpn, 2); + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 2); #else infof(data, "offering ALPN for HTTP/1.1 only"); - rustls_client_config_builder_set_protocols(config_builder, alpn, 1); + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 1); #endif if(!verifypeer) { rustls_client_config_builder_dangerous_set_certificate_verifier( @@ -358,7 +360,7 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn, size_t len = 0; rustls_connection_get_alpn_protocol(rconn, &protocol, &len); - if(NULL == protocol) { + if(!protocol) { infof(data, "ALPN, server did not agree to a protocol"); return; } @@ -414,9 +416,6 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn, /* * Connection has been established according to rustls. Set send/recv * handlers, and update the state machine. - * This check has to come last because is_handshaking starts out false, - * then becomes true when we first write data, then becomes false again - * once the handshake is done. */ if(!rustls_connection_is_handshaking(rconn)) { infof(data, "Done handshaking"); @@ -543,6 +542,12 @@ cr_close(struct Curl_easy *data, struct connectdata *conn, } } +static size_t cr_version(char *buffer, size_t size) +{ + struct rustls_str ver = rustls_version(); + return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data); +} + const struct Curl_ssl Curl_ssl_rustls = { { CURLSSLBACKEND_RUSTLS, "rustls" }, SSLSUPP_TLS13_CIPHERSUITES, /* supports */ @@ -550,7 +555,7 @@ const struct Curl_ssl Curl_ssl_rustls = { Curl_none_init, /* init */ Curl_none_cleanup, /* cleanup */ - rustls_version, /* version */ + cr_version, /* version */ Curl_none_check_cxn, /* check_cxn */ Curl_none_shutdown, /* shutdown */ cr_data_pending, /* data_pending */ diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c index 44c59e7796..0a8e60610d 100644 --- a/libs/libcurl/src/vtls/schannel.c +++ b/libs/libcurl/src/vtls/schannel.c @@ -147,8 +147,6 @@ #define ALG_CLASS_DHASH ALG_CLASS_HASH #endif -#define BACKEND connssl->backend - static Curl_recv schannel_recv; static Curl_send schannel_send; @@ -423,6 +421,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, PCCERT_CONTEXT client_certs[1] = { NULL }; SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; + struct ssl_backend_data *backend = connssl->backend; /* setup Schannel API options */ memset(&schannel_cred, 0, sizeof(schannel_cred)); @@ -430,7 +429,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, if(conn->ssl_config.verifypeer) { #ifdef HAS_MANUAL_VERIFY_API - if(BACKEND->use_manual_cred_validation) + if(backend->use_manual_cred_validation) schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; else #endif @@ -503,7 +502,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, if(SSL_CONN_CONFIG(cipher_list)) { result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list), - BACKEND->algIds); + backend->algIds); if(CURLE_OK != result) { failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG"); return result; @@ -600,7 +599,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, datablob.pbData = (BYTE*)certdata; datablob.cbData = (DWORD)certsize; - if(data->set.ssl.key_passwd != NULL) + if(data->set.ssl.key_passwd) pwd_len = strlen(data->set.ssl.key_passwd); pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1)); if(pszPassword) { @@ -704,9 +703,9 @@ schannel_acquire_credential_handle(struct Curl_easy *data, #endif /* allocate memory for the re-usable credential handle */ - BACKEND->cred = (struct Curl_schannel_cred *) + backend->cred = (struct Curl_schannel_cred *) calloc(1, sizeof(struct Curl_schannel_cred)); - if(!BACKEND->cred) { + if(!backend->cred) { failf(data, "schannel: unable to allocate memory"); if(client_certs[0]) @@ -714,14 +713,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - BACKEND->cred->refcount = 1; + backend->cred->refcount = 1; sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL, - &BACKEND->cred->cred_handle, - &BACKEND->cred->time_stamp); + &backend->cred->cred_handle, + &backend->cred->time_stamp); if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); @@ -730,7 +729,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, char buffer[STRERROR_LEN]; failf(data, "schannel: AcquireCredentialsHandle failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - Curl_safefree(BACKEND->cred); + Curl_safefree(backend->cred); switch(sspi_status) { case SEC_E_INSUFFICIENT_MEMORY: return CURLE_OUT_OF_MEMORY; @@ -769,12 +768,13 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, TCHAR *host_name; CURLcode result; char * const hostname = SSL_HOST_NAME(); + struct ssl_backend_data *backend = connssl->backend; DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)", hostname, conn->remote_port)); - if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT, + if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT, VERSION_LESS_THAN_EQUAL)) { /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and algorithms that may not be supported by all servers. */ @@ -785,29 +785,29 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, #ifdef HAS_ALPN /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. Also it doesn't seem to be supported for Wine, see curl bug #983. */ - BACKEND->use_alpn = conn->bits.tls_enable_alpn && + backend->use_alpn = conn->bits.tls_enable_alpn && !GetProcAddress(GetModuleHandle(TEXT("ntdll")), "wine_get_version") && - curlx_verify_windows_version(6, 3, PLATFORM_WINNT, + curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL); #else - BACKEND->use_alpn = false; + backend->use_alpn = false; #endif #ifdef _WIN32_WCE #ifdef HAS_MANUAL_VERIFY_API /* certificate validation on CE doesn't seem to work right; we'll * do it following a more manual process. */ - BACKEND->use_manual_cred_validation = true; + backend->use_manual_cred_validation = true; #else #error "compiler too old to support requisite manual cert verify for Win CE" #endif #else #ifdef HAS_MANUAL_VERIFY_API if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) { - if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT, + if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { - BACKEND->use_manual_cred_validation = true; + backend->use_manual_cred_validation = true; } else { failf(data, "schannel: this version of Windows is too old to support " @@ -816,7 +816,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, } } else - BACKEND->use_manual_cred_validation = false; + backend->use_manual_cred_validation = false; #else if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) { failf(data, "schannel: CA cert support not built in"); @@ -825,7 +825,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, #endif #endif - BACKEND->cred = NULL; + backend->cred = NULL; /* check for an existing re-usable credential handle */ if(SSL_SET_OPTION(primary.sessionid)) { @@ -833,19 +833,19 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, (void **)&old_cred, NULL, sockindex)) { - BACKEND->cred = old_cred; + backend->cred = old_cred; DEBUGF(infof(data, "schannel: re-using existing credential handle")); /* increment the reference counter of the credential/session handle */ - BACKEND->cred->refcount++; + backend->cred->refcount++; DEBUGF(infof(data, "schannel: incremented credential handle refcount = %d", - BACKEND->cred->refcount)); + backend->cred->refcount)); } Curl_ssl_sessionid_unlock(data); } - if(!BACKEND->cred) { + if(!backend->cred) { result = schannel_acquire_credential_handle(data, conn, sockindex); if(result != CURLE_OK) { return result; @@ -862,7 +862,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, } #ifdef HAS_ALPN - if(BACKEND->use_alpn) { + if(backend->use_alpn) { int cur = 0; int list_start_index = 0; unsigned int *extension_len = NULL; @@ -920,18 +920,18 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, InitSecBufferDesc(&outbuf_desc, &outbuf, 1); /* security request flags */ - BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | + backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; if(!SSL_SET_OPTION(auto_client_cert)) { - BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; } /* allocate memory for the security context handle */ - BACKEND->ctxt = (struct Curl_schannel_ctxt *) + backend->ctxt = (struct Curl_schannel_ctxt *) calloc(1, sizeof(struct Curl_schannel_ctxt)); - if(!BACKEND->ctxt) { + if(!backend->ctxt) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } @@ -948,16 +948,16 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, us problems with inbuf regardless. https://github.com/curl/curl/issues/983 */ sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, NULL, host_name, 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); + &backend->cred->cred_handle, NULL, host_name, 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); curlx_unicodefree(host_name); if(sspi_status != SEC_I_CONTINUE_NEEDED) { char buffer[STRERROR_LEN]; - Curl_safefree(BACKEND->ctxt); + Curl_safefree(backend->ctxt); switch(sspi_status) { case SEC_E_INSUFFICIENT_MEMORY: failf(data, "schannel: initial InitializeSecurityContext failed: %s", @@ -1001,10 +1001,10 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, DEBUGF(infof(data, "schannel: sent initial handshake data: " "sent %zd bytes", written)); - BACKEND->recv_unrecoverable_err = CURLE_OK; - BACKEND->recv_sspi_close_notify = false; - BACKEND->recv_connection_closed = false; - BACKEND->encdata_is_incomplete = false; + backend->recv_unrecoverable_err = CURLE_OK; + backend->recv_sspi_close_notify = false; + backend->recv_connection_closed = false; + backend->encdata_is_incomplete = false; /* continue to second handshake step */ connssl->connecting_state = ssl_connect_2; @@ -1029,6 +1029,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, bool doread; char * const hostname = SSL_HOST_NAME(); const char *pubkey_ptr; + struct ssl_backend_data *backend = connssl->backend; doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; @@ -1036,39 +1037,39 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, "schannel: SSL/TLS connection with %s port %hu (step 2/3)", hostname, conn->remote_port)); - if(!BACKEND->cred || !BACKEND->ctxt) + if(!backend->cred || !backend->ctxt) return CURLE_SSL_CONNECT_ERROR; /* buffer to store previously received and decrypted data */ - if(!BACKEND->decdata_buffer) { - BACKEND->decdata_offset = 0; - BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - BACKEND->decdata_buffer = malloc(BACKEND->decdata_length); - if(!BACKEND->decdata_buffer) { + if(!backend->decdata_buffer) { + backend->decdata_offset = 0; + backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + backend->decdata_buffer = malloc(backend->decdata_length); + if(!backend->decdata_buffer) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } } /* buffer to store previously received and encrypted data */ - if(!BACKEND->encdata_buffer) { - BACKEND->encdata_is_incomplete = false; - BACKEND->encdata_offset = 0; - BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - BACKEND->encdata_buffer = malloc(BACKEND->encdata_length); - if(!BACKEND->encdata_buffer) { + if(!backend->encdata_buffer) { + backend->encdata_is_incomplete = false; + backend->encdata_offset = 0; + backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + backend->encdata_buffer = malloc(backend->encdata_length); + if(!backend->encdata_buffer) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } } /* if we need a bigger buffer to read a full message, increase buffer now */ - if(BACKEND->encdata_length - BACKEND->encdata_offset < + if(backend->encdata_length - backend->encdata_offset < CURL_SCHANNEL_BUFFER_FREE_SIZE) { /* increase internal encrypted data buffer */ - size_t reallocated_length = BACKEND->encdata_offset + + size_t reallocated_length = backend->encdata_offset + CURL_SCHANNEL_BUFFER_FREE_SIZE; - reallocated_buffer = realloc(BACKEND->encdata_buffer, + reallocated_buffer = realloc(backend->encdata_buffer, reallocated_length); if(!reallocated_buffer) { @@ -1076,8 +1077,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } else { - BACKEND->encdata_buffer = reallocated_buffer; - BACKEND->encdata_length = reallocated_length; + backend->encdata_buffer = reallocated_buffer; + backend->encdata_length = reallocated_length; } } @@ -1086,10 +1087,10 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(doread) { /* read encrypted handshake data from socket */ result = Curl_read_plain(conn->sock[sockindex], - (char *) (BACKEND->encdata_buffer + - BACKEND->encdata_offset), - BACKEND->encdata_length - - BACKEND->encdata_offset, + (char *) (backend->encdata_buffer + + backend->encdata_offset), + backend->encdata_length - + backend->encdata_offset, &nread); if(result == CURLE_AGAIN) { if(connssl->connecting_state != ssl_connect_2_writing) @@ -1105,18 +1106,18 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } /* increase encrypted data buffer offset */ - BACKEND->encdata_offset += nread; - BACKEND->encdata_is_incomplete = false; + backend->encdata_offset += nread; + backend->encdata_is_incomplete = false; DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); /* setup input buffers */ - InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset), - curlx_uztoul(BACKEND->encdata_offset)); + InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset), + curlx_uztoul(backend->encdata_offset)); InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, inbuf, 2); @@ -1132,17 +1133,17 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } /* copy received handshake data into input buffer */ - memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer, - BACKEND->encdata_offset); + memcpy(inbuf[0].pvBuffer, backend->encdata_buffer, + backend->encdata_offset); host_name = curlx_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, - host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL, - &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); + &backend->cred->cred_handle, &backend->ctxt->ctxt_handle, + host_name, backend->req_flags, 0, 0, &inbuf_desc, 0, NULL, + &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); curlx_unicodefree(host_name); @@ -1151,7 +1152,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, /* check if the handshake was incomplete */ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - BACKEND->encdata_is_incomplete = true; + backend->encdata_is_incomplete = true; connssl->connecting_state = ssl_connect_2_reading; DEBUGF(infof(data, "schannel: received incomplete message, need more data")); @@ -1162,8 +1163,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, the handshake without one. This will allow connections to servers which request a client certificate but do not require it. */ if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && - !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { - BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { + backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; connssl->connecting_state = ssl_connect_2_writing; DEBUGF(infof(data, "schannel: a client certificate has been requested")); @@ -1191,7 +1192,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } /* free obsolete buffer */ - if(outbuf[i].pvBuffer != NULL) { + if(outbuf[i].pvBuffer) { s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer); } } @@ -1245,11 +1246,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, */ /* check if the remaining data is less than the total amount and therefore begins after the already processed data */ - if(BACKEND->encdata_offset > inbuf[1].cbBuffer) { - memmove(BACKEND->encdata_buffer, - (BACKEND->encdata_buffer + BACKEND->encdata_offset) - + if(backend->encdata_offset > inbuf[1].cbBuffer) { + memmove(backend->encdata_buffer, + (backend->encdata_buffer + backend->encdata_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer); - BACKEND->encdata_offset = inbuf[1].cbBuffer; + backend->encdata_offset = inbuf[1].cbBuffer; if(sspi_status == SEC_I_CONTINUE_NEEDED) { doread = FALSE; continue; @@ -1257,7 +1258,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } } else { - BACKEND->encdata_offset = 0; + backend->encdata_offset = 0; } break; } @@ -1284,7 +1285,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, } #ifdef HAS_MANUAL_VERIFY_API - if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) { + if(conn->ssl_config.verifypeer && backend->use_manual_cred_validation) { return Curl_verify_certificate(data, conn, sockindex); } #endif @@ -1366,6 +1367,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, #ifdef HAS_ALPN SecPkgContext_ApplicationProtocol alpn_result; #endif + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -1373,28 +1375,28 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, "schannel: SSL/TLS connection with %s port %hu (step 3/3)", hostname, conn->remote_port)); - if(!BACKEND->cred) + if(!backend->cred) return CURLE_SSL_CONNECT_ERROR; /* check if the required context attributes are met */ - if(BACKEND->ret_flags != BACKEND->req_flags) { - if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT)) + if(backend->ret_flags != backend->req_flags) { + if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT)) failf(data, "schannel: failed to setup sequence detection"); - if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT)) + if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT)) failf(data, "schannel: failed to setup replay detection"); - if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY)) + if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY)) failf(data, "schannel: failed to setup confidentiality"); - if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY)) + if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY)) failf(data, "schannel: failed to setup memory allocation"); - if(!(BACKEND->ret_flags & ISC_RET_STREAM)) + if(!(backend->ret_flags & ISC_RET_STREAM)) failf(data, "schannel: failed to setup stream orientation"); return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN - if(BACKEND->use_alpn) { + if(backend->use_alpn) { sspi_status = - s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); @@ -1439,7 +1441,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred, NULL, sockindex)); if(incache) { - if(old_cred != BACKEND->cred) { + if(old_cred != backend->cred) { DEBUGF(infof(data, "schannel: old credential handle is stale, removing")); /* we're not taking old_cred ownership here, no refcount++ is needed */ @@ -1448,7 +1450,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, } } if(!incache) { - result = Curl_ssl_addsessionid(data, conn, isproxy, BACKEND->cred, + result = Curl_ssl_addsessionid(data, conn, isproxy, backend->cred, sizeof(struct Curl_schannel_cred), sockindex, &added); if(result) { @@ -1458,7 +1460,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, } else if(added) { /* this cred session is now also referenced by sessionid cache */ - BACKEND->cred->refcount++; + backend->cred->refcount++; DEBUGF(infof(data, "schannel: stored credential handle in session cache")); } @@ -1469,7 +1471,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(data->set.ssl.certinfo) { int certs_count = 0; sspi_status = - s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); @@ -1606,7 +1608,10 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn, * binding to pass the IIS extended protection checks. * Available on Windows 7 or later. */ - conn->sslContext = &BACKEND->ctxt->ctxt_handle; + { + struct ssl_backend_data *backend = connssl->backend; + conn->sslContext = &backend->ctxt->ctxt_handle; + } #endif *done = TRUE; @@ -1633,13 +1638,14 @@ schannel_send(struct Curl_easy *data, int sockindex, SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; + struct ssl_backend_data *backend = connssl->backend; /* check if the maximum stream sizes were queried */ - if(BACKEND->stream_sizes.cbMaximumMessage == 0) { + if(backend->stream_sizes.cbMaximumMessage == 0) { sspi_status = s_pSecFn->QueryContextAttributes( - &BACKEND->ctxt->ctxt_handle, + &backend->ctxt->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, - &BACKEND->stream_sizes); + &backend->stream_sizes); if(sspi_status != SEC_E_OK) { *err = CURLE_SEND_ERROR; return -1; @@ -1647,13 +1653,13 @@ schannel_send(struct Curl_easy *data, int sockindex, } /* check if the buffer is longer than the maximum message length */ - if(len > BACKEND->stream_sizes.cbMaximumMessage) { - len = BACKEND->stream_sizes.cbMaximumMessage; + if(len > backend->stream_sizes.cbMaximumMessage) { + len = backend->stream_sizes.cbMaximumMessage; } /* calculate the complete message length and allocate a buffer for it */ - data_len = BACKEND->stream_sizes.cbHeader + len + - BACKEND->stream_sizes.cbTrailer; + data_len = backend->stream_sizes.cbHeader + len + + backend->stream_sizes.cbTrailer; ptr = (unsigned char *) malloc(data_len); if(!ptr) { *err = CURLE_OUT_OF_MEMORY; @@ -1662,12 +1668,12 @@ schannel_send(struct Curl_easy *data, int sockindex, /* setup output buffers (header, data, trailer, empty) */ InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, - ptr, BACKEND->stream_sizes.cbHeader); + ptr, backend->stream_sizes.cbHeader); InitSecBuffer(&outbuf[1], SECBUFFER_DATA, - ptr + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len)); + ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len)); InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, - ptr + BACKEND->stream_sizes.cbHeader + len, - BACKEND->stream_sizes.cbTrailer); + ptr + backend->stream_sizes.cbHeader + len, + backend->stream_sizes.cbTrailer); InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, outbuf, 4); @@ -1675,7 +1681,7 @@ schannel_send(struct Curl_easy *data, int sockindex, memcpy(outbuf[1].pvBuffer, buf, len); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ - sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0, + sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0, &outbuf_desc, 0); /* check if the message was encrypted */ @@ -1780,9 +1786,10 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* we want the length of the encrypted buffer to be at least large enough that it can hold all the bytes requested and some TLS record overhead. */ size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; + struct ssl_backend_data *backend = connssl->backend; /**************************************************************************** - * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup. + * Don't return or set backend->recv_unrecoverable_err unless in the cleanup. * The pattern for return error is set *err, optional infof, goto cleanup. * * Our priority is to always return as much decrypted data to the caller as @@ -1794,16 +1801,16 @@ schannel_recv(struct Curl_easy *data, int sockindex, DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len)); *err = CURLE_OK; - if(len && len <= BACKEND->decdata_offset) { + if(len && len <= backend->decdata_offset) { infof(data, "schannel: enough decrypted data is already available"); goto cleanup; } - else if(BACKEND->recv_unrecoverable_err) { - *err = BACKEND->recv_unrecoverable_err; + else if(backend->recv_unrecoverable_err) { + *err = backend->recv_unrecoverable_err; infof(data, "schannel: an unrecoverable error occurred in a prior call"); goto cleanup; } - else if(BACKEND->recv_sspi_close_notify) { + else if(backend->recv_sspi_close_notify) { /* once a server has indicated shutdown there is no more encrypted data */ infof(data, "schannel: server indicated shutdown in a prior call"); goto cleanup; @@ -1813,17 +1820,17 @@ schannel_recv(struct Curl_easy *data, int sockindex, immediately because there may be data to decrypt (in the case we want to decrypt all encrypted cached data) so handle !len later in cleanup. */ - else if(len && !BACKEND->recv_connection_closed) { + else if(len && !backend->recv_connection_closed) { /* increase enc buffer in order to fit the requested amount of data */ - size = BACKEND->encdata_length - BACKEND->encdata_offset; + size = backend->encdata_length - backend->encdata_offset; if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || - BACKEND->encdata_length < min_encdata_length) { - reallocated_length = BACKEND->encdata_offset + + backend->encdata_length < min_encdata_length) { + reallocated_length = backend->encdata_offset + CURL_SCHANNEL_BUFFER_FREE_SIZE; if(reallocated_length < min_encdata_length) { reallocated_length = min_encdata_length; } - reallocated_buffer = realloc(BACKEND->encdata_buffer, + reallocated_buffer = realloc(backend->encdata_buffer, reallocated_length); if(!reallocated_buffer) { *err = CURLE_OUT_OF_MEMORY; @@ -1831,21 +1838,21 @@ schannel_recv(struct Curl_easy *data, int sockindex, goto cleanup; } - BACKEND->encdata_buffer = reallocated_buffer; - BACKEND->encdata_length = reallocated_length; - size = BACKEND->encdata_length - BACKEND->encdata_offset; + backend->encdata_buffer = reallocated_buffer; + backend->encdata_length = reallocated_length; + size = backend->encdata_length - backend->encdata_offset; DEBUGF(infof(data, "schannel: encdata_buffer resized %zu", - BACKEND->encdata_length)); + backend->encdata_length)); } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); /* read encrypted data from socket */ *err = Curl_read_plain(conn->sock[sockindex], - (char *)(BACKEND->encdata_buffer + - BACKEND->encdata_offset), + (char *)(backend->encdata_buffer + + backend->encdata_offset), size, &nread); if(*err) { nread = -1; @@ -1858,27 +1865,27 @@ schannel_recv(struct Curl_easy *data, int sockindex, infof(data, "schannel: Curl_read_plain returned error %d", *err); } else if(nread == 0) { - BACKEND->recv_connection_closed = true; + backend->recv_connection_closed = true; DEBUGF(infof(data, "schannel: server closed the connection")); } else if(nread > 0) { - BACKEND->encdata_offset += (size_t)nread; - BACKEND->encdata_is_incomplete = false; + backend->encdata_offset += (size_t)nread; + backend->encdata_is_incomplete = false; DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); } } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); /* decrypt loop */ - while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK && - (!len || BACKEND->decdata_offset < len || - BACKEND->recv_connection_closed)) { + while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK && + (!len || backend->decdata_offset < len || + backend->recv_connection_closed)) { /* prepare data buffer for DecryptMessage call */ - InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer, - curlx_uztoul(BACKEND->encdata_offset)); + InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer, + curlx_uztoul(backend->encdata_offset)); /* we need 3 more empty input buffers for possible output */ InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); @@ -1888,7 +1895,7 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */ - sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle, + sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); /* check if everything went fine (server may want to renegotiate @@ -1904,37 +1911,37 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* increase buffer in order to fit the received amount of data */ size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; - if(BACKEND->decdata_length - BACKEND->decdata_offset < size || - BACKEND->decdata_length < len) { + if(backend->decdata_length - backend->decdata_offset < size || + backend->decdata_length < len) { /* increase internal decrypted data buffer */ - reallocated_length = BACKEND->decdata_offset + size; + reallocated_length = backend->decdata_offset + size; /* make sure that the requested amount of data fits */ if(reallocated_length < len) { reallocated_length = len; } - reallocated_buffer = realloc(BACKEND->decdata_buffer, + reallocated_buffer = realloc(backend->decdata_buffer, reallocated_length); if(!reallocated_buffer) { *err = CURLE_OUT_OF_MEMORY; failf(data, "schannel: unable to re-allocate memory"); goto cleanup; } - BACKEND->decdata_buffer = reallocated_buffer; - BACKEND->decdata_length = reallocated_length; + backend->decdata_buffer = reallocated_buffer; + backend->decdata_length = reallocated_length; } /* copy decrypted data to internal buffer */ size = inbuf[1].cbBuffer; if(size) { - memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset, + memcpy(backend->decdata_buffer + backend->decdata_offset, inbuf[1].pvBuffer, size); - BACKEND->decdata_offset += size; + backend->decdata_offset += size; } DEBUGF(infof(data, "schannel: decrypted data added: %zu", size)); DEBUGF(infof(data, "schannel: decrypted cached: offset %zu length %zu", - BACKEND->decdata_offset, BACKEND->decdata_length)); + backend->decdata_offset, backend->decdata_length)); } /* check for remaining encrypted data */ @@ -1945,22 +1952,22 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* check if the remaining data is less than the total amount * and therefore begins after the already processed data */ - if(BACKEND->encdata_offset > inbuf[3].cbBuffer) { + if(backend->encdata_offset > inbuf[3].cbBuffer) { /* move remaining encrypted data forward to the beginning of buffer */ - memmove(BACKEND->encdata_buffer, - (BACKEND->encdata_buffer + BACKEND->encdata_offset) - + memmove(backend->encdata_buffer, + (backend->encdata_buffer + backend->encdata_offset) - inbuf[3].cbBuffer, inbuf[3].cbBuffer); - BACKEND->encdata_offset = inbuf[3].cbBuffer; + backend->encdata_offset = inbuf[3].cbBuffer; } DEBUGF(infof(data, "schannel: encrypted cached: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); } else { /* reset encrypted buffer offset, because there is no data remaining */ - BACKEND->encdata_offset = 0; + backend->encdata_offset = 0; } /* check if server wants to renegotiate the connection context */ @@ -1970,7 +1977,7 @@ schannel_recv(struct Curl_easy *data, int sockindex, infof(data, "schannel: can't renegotiate, an error is pending"); goto cleanup; } - if(BACKEND->encdata_offset) { + if(backend->encdata_offset) { *err = CURLE_RECV_ERROR; infof(data, "schannel: can't renegotiate, " "encrypted data available"); @@ -1994,16 +2001,16 @@ schannel_recv(struct Curl_easy *data, int sockindex, else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not returned so we have to work around that in cleanup. */ - BACKEND->recv_sspi_close_notify = true; - if(!BACKEND->recv_connection_closed) { - BACKEND->recv_connection_closed = true; + backend->recv_sspi_close_notify = true; + if(!backend->recv_connection_closed) { + backend->recv_connection_closed = true; infof(data, "schannel: server closed the connection"); } goto cleanup; } } else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - BACKEND->encdata_is_incomplete = true; + backend->encdata_is_incomplete = true; if(!*err) *err = CURLE_AGAIN; infof(data, "schannel: failed to decrypt data, need more data"); @@ -2022,11 +2029,11 @@ schannel_recv(struct Curl_easy *data, int sockindex, DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu", - BACKEND->encdata_offset, BACKEND->encdata_length)); + backend->encdata_offset, backend->encdata_length)); DEBUGF(infof(data, "schannel: decrypted data buffer: offset %zu length %zu", - BACKEND->decdata_offset, BACKEND->decdata_length)); + backend->decdata_offset, backend->decdata_length)); cleanup: /* Warning- there is no guarantee the encdata state is valid at this point */ @@ -2043,13 +2050,13 @@ schannel_recv(struct Curl_easy *data, int sockindex, assume it was graceful (close_notify) since there doesn't seem to be a way to tell. */ - if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed && - !BACKEND->recv_sspi_close_notify) { - bool isWin2k = curlx_verify_windows_version(5, 0, PLATFORM_WINNT, + if(len && !backend->decdata_offset && backend->recv_connection_closed && + !backend->recv_sspi_close_notify) { + bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT, VERSION_EQUAL); if(isWin2k && sspi_status == SEC_E_OK) - BACKEND->recv_sspi_close_notify = true; + backend->recv_sspi_close_notify = true; else { *err = CURLE_RECV_ERROR; infof(data, "schannel: server closed abruptly (missing close_notify)"); @@ -2058,23 +2065,23 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* Any error other than CURLE_AGAIN is an unrecoverable error. */ if(*err && *err != CURLE_AGAIN) - BACKEND->recv_unrecoverable_err = *err; + backend->recv_unrecoverable_err = *err; - size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset; + size = len < backend->decdata_offset ? len : backend->decdata_offset; if(size) { - memcpy(buf, BACKEND->decdata_buffer, size); - memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size, - BACKEND->decdata_offset - size); - BACKEND->decdata_offset -= size; + memcpy(buf, backend->decdata_buffer, size); + memmove(backend->decdata_buffer, backend->decdata_buffer + size, + backend->decdata_offset - size); + backend->decdata_offset -= size; DEBUGF(infof(data, "schannel: decrypted data returned %zu", size)); DEBUGF(infof(data, "schannel: decrypted data buffer: offset %zu length %zu", - BACKEND->decdata_offset, BACKEND->decdata_length)); + backend->decdata_offset, backend->decdata_length)); *err = CURLE_OK; return (ssize_t)size; } - if(!*err && !BACKEND->recv_connection_closed) + if(!*err && !backend->recv_connection_closed) *err = CURLE_AGAIN; /* It's debatable what to return when !len. We could return whatever error @@ -2113,10 +2120,11 @@ static bool schannel_data_pending(const struct connectdata *conn, int sockindex) { const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; if(connssl->use) /* SSL/TLS is in use */ - return (BACKEND->decdata_offset > 0 || - (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete)); + return (backend->decdata_offset > 0 || + (backend->encdata_offset > 0 && !backend->encdata_is_incomplete)); else return FALSE; } @@ -2146,6 +2154,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, */ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; char * const hostname = SSL_HOST_NAME(); + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(data); @@ -2154,7 +2163,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, hostname, conn->remote_port); } - if(connssl->use && BACKEND->cred && BACKEND->ctxt) { + if(connssl->use && backend->cred && backend->ctxt) { SecBufferDesc BuffDesc; SecBuffer Buffer; SECURITY_STATUS sspi_status; @@ -2167,7 +2176,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); InitSecBufferDesc(&BuffDesc, &Buffer, 1); - sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle, + sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle, &BuffDesc); if(sspi_status != SEC_E_OK) { @@ -2185,18 +2194,18 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, InitSecBufferDesc(&outbuf_desc, &outbuf, 1); sspi_status = s_pSecFn->InitializeSecurityContext( - &BACKEND->cred->cred_handle, - &BACKEND->ctxt->ctxt_handle, + &backend->cred->cred_handle, + &backend->ctxt->ctxt_handle, host_name, - BACKEND->req_flags, + backend->req_flags, 0, 0, NULL, 0, - &BACKEND->ctxt->ctxt_handle, + &backend->ctxt->ctxt_handle, &outbuf_desc, - &BACKEND->ret_flags, - &BACKEND->ctxt->time_stamp); + &backend->ret_flags, + &backend->ctxt->time_stamp); curlx_unicodefree(host_name); @@ -2215,33 +2224,33 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, } /* free SSPI Schannel API security context handle */ - if(BACKEND->ctxt) { + if(backend->ctxt) { DEBUGF(infof(data, "schannel: clear security context handle")); - s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle); - Curl_safefree(BACKEND->ctxt); + s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle); + Curl_safefree(backend->ctxt); } /* free SSPI Schannel API credential handle */ - if(BACKEND->cred) { + if(backend->cred) { Curl_ssl_sessionid_lock(data); - schannel_session_free(BACKEND->cred); + schannel_session_free(backend->cred); Curl_ssl_sessionid_unlock(data); - BACKEND->cred = NULL; + backend->cred = NULL; } /* free internal buffer for received encrypted data */ - if(BACKEND->encdata_buffer != NULL) { - Curl_safefree(BACKEND->encdata_buffer); - BACKEND->encdata_length = 0; - BACKEND->encdata_offset = 0; - BACKEND->encdata_is_incomplete = false; + if(backend->encdata_buffer) { + Curl_safefree(backend->encdata_buffer); + backend->encdata_length = 0; + backend->encdata_offset = 0; + backend->encdata_is_incomplete = false; } /* free internal buffer for received decrypted data */ - if(BACKEND->decdata_buffer != NULL) { - Curl_safefree(BACKEND->decdata_buffer); - BACKEND->decdata_length = 0; - BACKEND->decdata_offset = 0; + if(backend->decdata_buffer) { + Curl_safefree(backend->decdata_buffer); + backend->decdata_length = 0; + backend->decdata_offset = 0; } return CURLE_OK; @@ -2299,6 +2308,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, const char *pinnedpubkey) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CERT_CONTEXT *pCertContextServer = NULL; /* Result is returned to caller */ @@ -2316,7 +2326,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, struct Curl_asn1Element *pubkey; sspi_status = - s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pCertContextServer); @@ -2422,8 +2432,9 @@ static CURLcode schannel_sha256sum(const unsigned char *input, static void *schannel_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return &BACKEND->ctxt->ctxt_handle; + return &backend->ctxt->ctxt_handle; } const struct Curl_ssl Curl_ssl_schannel = { diff --git a/libs/libcurl/src/vtls/schannel_verify.c b/libs/libcurl/src/vtls/schannel_verify.c index 1b283d0453..4966cd4945 100644 --- a/libs/libcurl/src/vtls/schannel_verify.c +++ b/libs/libcurl/src/vtls/schannel_verify.c @@ -355,7 +355,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data, DWORD i; /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */ - if(curlx_verify_windows_version(6, 2, PLATFORM_WINNT, + if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG /* CertGetNameString will provide the 8-bit character string without @@ -597,7 +597,8 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data, * trusted certificates. This is only supported on Windows 7+. */ - if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) { + if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT, + VERSION_LESS_THAN)) { failf(data, "schannel: this version of Windows is too old to support " "certificate verification via CA bundle file."); result = CURLE_SSL_CACERT_BADFILE; diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c index 0bf515460d..f7a20b20b1 100644 --- a/libs/libcurl/src/vtls/sectransp.c +++ b/libs/libcurl/src/vtls/sectransp.c @@ -997,14 +997,14 @@ CF_INLINE CFStringRef getsubject(SecCertificateRef cert) #else #if CURL_BUILD_MAC_10_7 /* Lion & later: Get the long description if we can. */ - if(SecCertificateCopyLongDescription != NULL) + if(SecCertificateCopyLongDescription) server_cert_summary = SecCertificateCopyLongDescription(NULL, cert, NULL); else #endif /* CURL_BUILD_MAC_10_7 */ #if CURL_BUILD_MAC_10_6 /* Snow Leopard: Get the certificate summary. */ - if(SecCertificateCopySubjectSummary != NULL) + if(SecCertificateCopySubjectSummary) server_cert_summary = SecCertificateCopySubjectSummary(cert); else #endif /* CURL_BUILD_MAC_10_6 */ @@ -1118,7 +1118,7 @@ static OSStatus CopyIdentityWithLabel(char *label, /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. kSecClassIdentity was introduced in Lion. If both exist, let's use them to find the certificate. */ - if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) { + if(SecItemCopyMatching && kSecClassIdentity) { CFTypeRef keys[5]; CFTypeRef values[5]; CFDictionaryRef query_dict; @@ -1248,7 +1248,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath, CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, password ? 1L : 0L, NULL, NULL); - if(options != NULL) { + if(options) { status = SecPKCS12Import(pkcs_data, options, &items); CFRelease(options); } @@ -1406,7 +1406,7 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn, } #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLSetProtocolVersionMax != NULL) { + if(SSLSetProtocolVersionMax) { SSLProtocol darwin_ver_min = kTLSProtocol1; SSLProtocol darwin_ver_max = kTLSProtocol1; CURLcode result = sectransp_version_from_curl(&darwin_ver_min, @@ -1608,7 +1608,7 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data, if(tls_name) { table_cipher_name = ciphertable[i].name; } - else if(ciphertable[i].alias_name != NULL) { + else if(ciphertable[i].alias_name) { table_cipher_name = ciphertable[i].alias_name; } else { @@ -1688,7 +1688,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, #endif /* CURL_BUILD_MAC */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLCreateContext != NULL) { /* use the newer API if available */ + if(SSLCreateContext) { /* use the newer API if available */ if(backend->ssl_ctx) CFRelease(backend->ssl_ctx); backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); @@ -1722,7 +1722,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, /* check to see if we've been told to use an explicit SSL/TLS version */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLSetProtocolVersionMax != NULL) { + if(SSLSetProtocolVersionMax) { switch(conn->ssl_config.version) { case CURL_SSLVERSION_TLSv1: (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1); @@ -1980,9 +1980,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, Darwin 15.x.x is El Capitan (10.11) */ #if CURL_BUILD_MAC - if(SSLSetSessionOption != NULL && darwinver_maj >= 13) { + if(SSLSetSessionOption && darwinver_maj >= 13) { #else - if(SSLSetSessionOption != NULL) { + if(SSLSetSessionOption) { #endif /* CURL_BUILD_MAC */ bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile || ssl_cablob; @@ -2065,7 +2065,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 /* We want to enable 1/n-1 when using a CBC cipher unless the user specifically doesn't want us doing that: */ - if(SSLSetSessionOption != NULL) { + if(SSLSetSessionOption) { SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord, !SSL_SET_OPTION(enable_beast)); SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart, @@ -2521,7 +2521,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, } while(0); Curl_safefree(realpubkey); - if(publicKeyBits != NULL) + if(publicKeyBits) CFRelease(publicKeyBits); return result; @@ -2947,7 +2947,7 @@ collect_server_cert(struct Curl_easy *data, private API and doesn't work as expected. So we have to look for a different symbol to make sure this code is only executed under Lion or later. */ - if(SecTrustEvaluateAsync != NULL) { + if(SecTrustEvaluateAsync) { #pragma unused(server_certs) err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); /* For some reason, SSLCopyPeerTrust() can return noErr and yet return @@ -3165,7 +3165,7 @@ static void sectransp_close(struct Curl_easy *data, struct connectdata *conn, if(backend->ssl_ctx) { (void)SSLClose(backend->ssl_ctx); #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(SSLCreateContext != NULL) + if(SSLCreateContext) CFRelease(backend->ssl_ctx); #if CURL_SUPPORT_MAC_10_8 else @@ -3329,7 +3329,7 @@ static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */ static bool sectransp_false_start(void) { #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 - if(SSLSetSessionOption != NULL) + if(SSLSetSessionOption) return TRUE; #endif return FALSE; diff --git a/libs/libcurl/src/x509asn1.c b/libs/libcurl/src/x509asn1.c index 1bdaeadc80..0341543a2b 100644 --- a/libs/libcurl/src/x509asn1.c +++ b/libs/libcurl/src/x509asn1.c @@ -608,7 +608,10 @@ static const char *ASN1tostr(struct Curl_asn1Element *elem, int type) /* * ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at - * `buf'. Return the total string length, even if larger than `buflen'. + * `buf'. + * + * Returns the total string length, even if larger than `buflen' or -1 on + * error. */ static ssize_t encodeDN(char *buf, size_t buflen, struct Curl_asn1Element *dn) { @@ -692,7 +695,10 @@ static const char *DNtostr(struct Curl_asn1Element *dn) if(buflen >= 0) { buf = malloc(buflen + 1); if(buf) { - encodeDN(buf, buflen + 1, dn); + if(encodeDN(buf, buflen + 1, dn) == -1) { + free(buf); + return NULL; + } buf[buflen] = '\0'; } } @@ -855,26 +861,30 @@ static const char *dumpAlgo(struct Curl_asn1Element *param, return OID2str(oid.beg, oid.end, TRUE); } -static void do_pubkey_field(struct Curl_easy *data, int certnum, - const char *label, struct Curl_asn1Element *elem) +/* return 0 on success, 1 on error */ +static int do_pubkey_field(struct Curl_easy *data, int certnum, + const char *label, struct Curl_asn1Element *elem) { const char *output; + CURLcode result = CURLE_OK; /* Generate a certificate information record for the public key. */ output = ASN1tostr(elem, 0); if(output) { if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, label, output); - if(!certnum) + result = Curl_ssl_push_certinfo(data, certnum, label, output); + if(!certnum && !result) infof(data, " %s: %s", label, output); free((char *) output); } + return result ? 1 : 0; } -static void do_pubkey(struct Curl_easy *data, int certnum, - const char *algo, struct Curl_asn1Element *param, - struct Curl_asn1Element *pubkey) +/* return 0 on success, 1 on error */ +static int do_pubkey(struct Curl_easy *data, int certnum, + const char *algo, struct Curl_asn1Element *param, + struct Curl_asn1Element *pubkey) { struct Curl_asn1Element elem; struct Curl_asn1Element pk; @@ -884,7 +894,7 @@ static void do_pubkey(struct Curl_easy *data, int certnum, /* Get the public key (single element). */ if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end)) - return; + return 1; if(strcasecompare(algo, "rsaEncryption")) { const char *q; @@ -892,7 +902,7 @@ static void do_pubkey(struct Curl_easy *data, int certnum, p = getASN1Element(&elem, pk.beg, pk.end); if(!p) - return; + return 1; /* Compute key length. */ for(q = elem.beg; !*q && q < elem.end; q++) @@ -910,26 +920,35 @@ static void do_pubkey(struct Curl_easy *data, int certnum, if(data->set.ssl.certinfo) { q = curl_maprintf("%lu", len); if(q) { - Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q); + CURLcode result = + Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q); free((char *) q); + if(result) + return 1; } } /* Generate coefficients. */ - do_pubkey_field(data, certnum, "rsa(n)", &elem); + if(do_pubkey_field(data, certnum, "rsa(n)", &elem)) + return 1; if(!getASN1Element(&elem, p, pk.end)) - return; - do_pubkey_field(data, certnum, "rsa(e)", &elem); + return 1; + if(do_pubkey_field(data, certnum, "rsa(e)", &elem)) + return 1; } else if(strcasecompare(algo, "dsa")) { p = getASN1Element(&elem, param->beg, param->end); if(p) { - do_pubkey_field(data, certnum, "dsa(p)", &elem); + if(do_pubkey_field(data, certnum, "dsa(p)", &elem)) + return 1; p = getASN1Element(&elem, p, param->end); if(p) { - do_pubkey_field(data, certnum, "dsa(q)", &elem); + if(do_pubkey_field(data, certnum, "dsa(q)", &elem)) + return 1; if(getASN1Element(&elem, p, param->end)) { - do_pubkey_field(data, certnum, "dsa(g)", &elem); - do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); + if(do_pubkey_field(data, certnum, "dsa(g)", &elem)) + return 1; + if(do_pubkey_field(data, certnum, "dsa(pub_key)", &pk)) + return 1; } } } @@ -937,13 +956,17 @@ static void do_pubkey(struct Curl_easy *data, int certnum, else if(strcasecompare(algo, "dhpublicnumber")) { p = getASN1Element(&elem, param->beg, param->end); if(p) { - do_pubkey_field(data, certnum, "dh(p)", &elem); + if(do_pubkey_field(data, certnum, "dh(p)", &elem)) + return 1; if(getASN1Element(&elem, param->beg, param->end)) { - do_pubkey_field(data, certnum, "dh(g)", &elem); - do_pubkey_field(data, certnum, "dh(pub_key)", &pk); + if(do_pubkey_field(data, certnum, "dh(g)", &elem)) + return 1; + if(do_pubkey_field(data, certnum, "dh(pub_key)", &pk)) + return 1; } } } + return 0; } CURLcode Curl_extract_certinfo(struct Curl_easy *data, @@ -957,7 +980,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, char *cp1; size_t cl1; char *cp2; - CURLcode result; + CURLcode result = CURLE_OK; unsigned long version; size_t i; size_t j; @@ -976,8 +999,11 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, ccp = DNtostr(&cert.subject); if(!ccp) return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Subject", ccp); + if(data->set.ssl.certinfo) { + result = Curl_ssl_push_certinfo(data, certnum, "Subject", ccp); + if(result) + return result; + } if(!certnum) infof(data, "%2d Subject: %s", certnum, ccp); free((char *) ccp); @@ -986,11 +1012,14 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, ccp = DNtostr(&cert.issuer); if(!ccp) return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp); + if(data->set.ssl.certinfo) { + result = Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp); + } if(!certnum) infof(data, " Issuer: %s", ccp); free((char *) ccp); + if(result) + return result; /* Version (always fits in less than 32 bits). */ version = 0; @@ -1000,8 +1029,10 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, ccp = curl_maprintf("%lx", version); if(!ccp) return CURLE_OUT_OF_MEMORY; - Curl_ssl_push_certinfo(data, certnum, "Version", ccp); + result = Curl_ssl_push_certinfo(data, certnum, "Version", ccp); free((char *) ccp); + if(result) + return result; } if(!certnum) infof(data, " Version: %lu (0x%lx)", version + 1, version); @@ -1011,10 +1042,12 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp); + result = Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp); if(!certnum) infof(data, " Serial Number: %s", ccp); free((char *) ccp); + if(result) + return result; /* Signature algorithm .*/ ccp = dumpAlgo(¶m, cert.signatureAlgorithm.beg, @@ -1022,30 +1055,36 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp); + result = Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp); if(!certnum) infof(data, " Signature Algorithm: %s", ccp); free((char *) ccp); + if(result) + return result; /* Start Date. */ ccp = ASN1tostr(&cert.notBefore, 0); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp); + result = Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp); if(!certnum) infof(data, " Start Date: %s", ccp); free((char *) ccp); + if(result) + return result; /* Expire Date. */ ccp = ASN1tostr(&cert.notAfter, 0); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp); + result = Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp); if(!certnum) infof(data, " Expire Date: %s", ccp); free((char *) ccp); + if(result) + return result; /* Public Key Algorithm. */ ccp = dumpAlgo(¶m, cert.subjectPublicKeyAlgorithm.beg, @@ -1053,21 +1092,31 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp); - if(!certnum) - infof(data, " Public Key Algorithm: %s", ccp); - do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey); + result = Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", + ccp); + if(!result) { + int ret; + if(!certnum) + infof(data, " Public Key Algorithm: %s", ccp); + ret = do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey); + if(ret) + result = CURLE_OUT_OF_MEMORY; /* the most likely error */ + } free((char *) ccp); + if(result) + return result; /* Signature. */ ccp = ASN1tostr(&cert.signature, 0); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Signature", ccp); + result = Curl_ssl_push_certinfo(data, certnum, "Signature", ccp); if(!certnum) infof(data, " Signature: %s", ccp); free((char *) ccp); + if(result) + return result; /* Generate PEM certificate. */ result = Curl_base64_encode(data, cert.certificate.beg, @@ -1097,11 +1146,11 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, cp2[i] = '\0'; free(cp1); if(data->set.ssl.certinfo) - Curl_ssl_push_certinfo(data, certnum, "Cert", cp2); + result = Curl_ssl_push_certinfo(data, certnum, "Cert", cp2); if(!certnum) infof(data, "%s", cp2); free(cp2); - return CURLE_OK; + return result; } #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL |