summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2022-01-07 11:41:57 -0500
committerBrad King <brad.king@kitware.com>2022-01-07 11:41:57 -0500
commit697e8871a1d1cf56f01866c082235ea20bd1057f (patch)
treeb0fe132b726b5dcce50eac5b2de3ac7456df3d18 /Utilities/cmcurl
parentbdb3a8203e1a1207e7a89dca1b3e6a569a732b10 (diff)
parenta1f6ec647cfab8d613897562f8ee5f81a8f6b68d (diff)
downloadcmake-697e8871a1d1cf56f01866c082235ea20bd1057f.tar.gz
Merge branch 'upstream-curl' into update-curl
* upstream-curl: curl 2022-01-05 (801bd513)
Diffstat (limited to 'Utilities/cmcurl')
-rw-r--r--Utilities/cmcurl/CMake/CurlTests.c20
-rw-r--r--Utilities/cmcurl/CMake/FindMbedTLS.cmake4
-rw-r--r--Utilities/cmcurl/CMake/OtherTests.cmake1
-rw-r--r--Utilities/cmcurl/CMakeLists.txt152
-rw-r--r--Utilities/cmcurl/include/curl/curl.h42
-rw-r--r--Utilities/cmcurl/include/curl/curlver.h8
-rw-r--r--Utilities/cmcurl/include/curl/multi.h5
-rw-r--r--Utilities/cmcurl/include/curl/typecheck-gcc.h2
-rw-r--r--Utilities/cmcurl/include/curl/urlapi.h21
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt7
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c6
-rw-r--r--Utilities/cmcurl/lib/c-hyper.c203
-rw-r--r--Utilities/cmcurl/lib/conncache.c13
-rw-r--r--Utilities/cmcurl/lib/connect.c38
-rw-r--r--Utilities/cmcurl/lib/content_encoding.c3
-rw-r--r--Utilities/cmcurl/lib/cookie.c2
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake3
-rw-r--r--Utilities/cmcurl/lib/curl_des.c4
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.c10
-rw-r--r--Utilities/cmcurl/lib/curl_hmac.h4
-rw-r--r--Utilities/cmcurl/lib/curl_md5.h8
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c19
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c117
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.h67
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h2
-rw-r--r--Utilities/cmcurl/lib/curl_sha256.h13
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.c4
-rw-r--r--Utilities/cmcurl/lib/doh.c25
-rw-r--r--Utilities/cmcurl/lib/easy.c10
-rw-r--r--Utilities/cmcurl/lib/easyoptions.c8
-rw-r--r--Utilities/cmcurl/lib/ftp.c24
-rw-r--r--Utilities/cmcurl/lib/hash.c82
-rw-r--r--Utilities/cmcurl/lib/hash.h12
-rw-r--r--Utilities/cmcurl/lib/hostcheck.c2
-rw-r--r--Utilities/cmcurl/lib/hostip.c31
-rw-r--r--Utilities/cmcurl/lib/hostip.h4
-rw-r--r--Utilities/cmcurl/lib/http.c89
-rw-r--r--Utilities/cmcurl/lib/http.h6
-rw-r--r--Utilities/cmcurl/lib/http2.c31
-rw-r--r--Utilities/cmcurl/lib/http_aws_sigv4.c21
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.c11
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c110
-rw-r--r--Utilities/cmcurl/lib/http_proxy.h3
-rw-r--r--Utilities/cmcurl/lib/if2ip.c4
-rw-r--r--Utilities/cmcurl/lib/imap.c157
-rw-r--r--Utilities/cmcurl/lib/inet_pton.c6
-rw-r--r--Utilities/cmcurl/lib/krb5.c8
-rw-r--r--Utilities/cmcurl/lib/ldap.c7
-rw-r--r--Utilities/cmcurl/lib/libcurl.rc4
-rw-r--r--Utilities/cmcurl/lib/llist.c4
-rw-r--r--Utilities/cmcurl/lib/md4.c17
-rw-r--r--Utilities/cmcurl/lib/md5.c42
-rw-r--r--Utilities/cmcurl/lib/mime.c80
-rw-r--r--Utilities/cmcurl/lib/mprintf.c2
-rw-r--r--Utilities/cmcurl/lib/multi.c252
-rw-r--r--Utilities/cmcurl/lib/multihandle.h2
-rw-r--r--Utilities/cmcurl/lib/multiif.h4
-rw-r--r--Utilities/cmcurl/lib/openldap.c833
-rw-r--r--Utilities/cmcurl/lib/pop3.c100
-rw-r--r--Utilities/cmcurl/lib/select.c2
-rw-r--r--Utilities/cmcurl/lib/sendf.c8
-rw-r--r--Utilities/cmcurl/lib/setopt.c38
-rw-r--r--Utilities/cmcurl/lib/setup-win32.h14
-rw-r--r--Utilities/cmcurl/lib/sha256.c141
-rw-r--r--Utilities/cmcurl/lib/share.c6
-rw-r--r--Utilities/cmcurl/lib/smtp.c103
-rw-r--r--Utilities/cmcurl/lib/socks.c33
-rw-r--r--Utilities/cmcurl/lib/socks_gssapi.c4
-rw-r--r--Utilities/cmcurl/lib/socks_sspi.c2
-rw-r--r--Utilities/cmcurl/lib/splay.c4
-rw-r--r--Utilities/cmcurl/lib/strerror.c111
-rw-r--r--Utilities/cmcurl/lib/system_win32.c4
-rw-r--r--Utilities/cmcurl/lib/tftp.c6
-rw-r--r--Utilities/cmcurl/lib/transfer.c2
-rw-r--r--Utilities/cmcurl/lib/url.c76
-rw-r--r--Utilities/cmcurl/lib/urlapi-int.h4
-rw-r--r--Utilities/cmcurl/lib/urlapi.c402
-rw-r--r--Utilities/cmcurl/lib/urldata.h14
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.c11
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.c4
-rw-r--r--Utilities/cmcurl/lib/version_win32.c113
-rw-r--r--Utilities/cmcurl/lib/version_win32.h3
-rw-r--r--Utilities/cmcurl/lib/vquic/ngtcp2.c107
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh2.c154
-rw-r--r--Utilities/cmcurl/lib/vssh/wolfssh.c6
-rw-r--r--Utilities/cmcurl/lib/vtls/bearssl.c6
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c79
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h8
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c60
-rw-r--r--Utilities/cmcurl/lib/vtls/mesalink.c93
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c107
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c290
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.h8
-rw-r--r--Utilities/cmcurl/lib/vtls/rustls.c61
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c447
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c5
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c32
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c10
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h3
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.c75
-rw-r--r--Utilities/cmcurl/lib/x509asn1.c127
101 files changed, 3551 insertions, 2001 deletions
diff --git a/Utilities/cmcurl/CMake/CurlTests.c b/Utilities/cmcurl/CMake/CurlTests.c
index e418146b48..8666da0da9 100644
--- a/Utilities/cmcurl/CMake/CurlTests.c
+++ b/Utilities/cmcurl/CMake/CurlTests.c
@@ -229,10 +229,6 @@ int main () { ; return 0; }
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
@@ -258,10 +254,6 @@ main ()
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
@@ -285,10 +277,6 @@ main ()
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
@@ -313,10 +301,6 @@ main ()
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
@@ -403,10 +387,6 @@ main ()
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
/* includes start */
diff --git a/Utilities/cmcurl/CMake/FindMbedTLS.cmake b/Utilities/cmcurl/CMake/FindMbedTLS.cmake
index 1746093dfa..7bdb1976d0 100644
--- a/Utilities/cmcurl/CMake/FindMbedTLS.cmake
+++ b/Utilities/cmcurl/CMake/FindMbedTLS.cmake
@@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
-# Copyright (C) 1998 - 2020, 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
@@ -28,7 +28,7 @@ find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(MBEDTLS DEFAULT_MSG
+find_package_handle_standard_args(MbedTLS DEFAULT_MSG
MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake
index 7fda7aca3a..d06b3ed774 100644
--- a/Utilities/cmcurl/CMake/OtherTests.cmake
+++ b/Utilities/cmcurl/CMake/OtherTests.cmake
@@ -33,7 +33,6 @@ set(signature_call_conv)
if(HAVE_WINDOWS_H)
add_header_include(HAVE_WINSOCK2_H "winsock2.h")
add_header_include(HAVE_WINDOWS_H "windows.h")
- add_header_include(HAVE_WINSOCK_H "winsock.h")
set(_source_epilogue
"${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif")
set(signature_call_conv "PASCAL")
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index cd5d3542a5..cd5e0a8681 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -387,6 +387,17 @@ if(ENABLE_IPV6 AND NOT WIN32)
set(ENABLE_IPV6 OFF
CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
endif()
+
+ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT ENABLE_ARES)
+ set(use_core_foundation ON)
+
+ find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
+ if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
+ message(FATAL_ERROR "SystemConfiguration framework not found")
+ endif()
+
+ list(APPEND CURL_LIBS "-framework SystemConfiguration")
+ endif()
endif()
if(0) # This code not needed for building within CMake.
@@ -479,84 +490,94 @@ if(WIN32)
check_library_exists_concat("winmm" getch HAVE_LIBWINMM)
endif()
-# check SSL libraries
-# TODO support GnuTLS
+# This check below for use of deprecated symbols is only temporary and is to
+# be removed again after a year's service. Remove after November 25, 2022.
+set(CURL_RECONFIG_REQUIRED 0)
+foreach(_LIB GSSAPI OPENLDAP LIBSSH LIBSSH2 BEARSSL MBEDTLS NSS OPENSSL
+ SCHANNEL SECTRANSP WOLFSSL)
+ if(CMAKE_USE_${_LIB})
+ set(CURL_RECONFIG_REQUIRED 1)
+ message(SEND_ERROR "The option CMAKE_USE_${_LIB} was renamed to CURL_USE_${_LIB}.")
+ endif()
+endforeach()
if(CMAKE_USE_WINSSL)
- message(FATAL_ERROR "The cmake option CMAKE_USE_WINSSL was renamed to CMAKE_USE_SCHANNEL.")
+ set(CURL_RECONFIG_REQUIRED 1)
+ message(SEND_ERROR "The option CMAKE_USE_WINSSL was renamed to CURL_USE_SCHANNEL.")
+endif()
+if(CURL_RECONFIG_REQUIRED)
+ message(FATAL_ERROR "Reconfig required")
endif()
+# check SSL libraries
+# TODO support GnuTLS
+option(CURL_ENABLE_SSL "Enable SSL support" ON)
+
if(APPLE)
- option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF)
+ cmake_dependent_option(CURL_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
endif()
if(WIN32)
- option(CMAKE_USE_SCHANNEL "enable Windows native SSL/TLS" OFF)
+ cmake_dependent_option(CURL_USE_SCHANNEL "enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON
- CMAKE_USE_SCHANNEL OFF)
+ CURL_USE_SCHANNEL OFF)
endif()
-option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF)
-option(CMAKE_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF)
-option(CMAKE_USE_NSS "Enable NSS for SSL/TLS" OFF)
-option(CMAKE_USE_WOLFSSL "enable wolfSSL for SSL/TLS" OFF)
+cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+cmake_dependent_option(CURL_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+cmake_dependent_option(CURL_USE_NSS "Enable NSS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+cmake_dependent_option(CURL_USE_WOLFSSL "enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
set(openssl_default ON)
-if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_SCHANNEL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS OR CMAKE_USE_WOLFSSL)
+if(WIN32 OR CURL_USE_SECTRANSP OR CURL_USE_SCHANNEL OR CURL_USE_MBEDTLS OR CURL_USE_NSS OR CURL_USE_WOLFSSL)
set(openssl_default OFF)
endif()
+cmake_dependent_option(CURL_USE_OPENSSL "Use OpenSSL code. Experimental" ${openssl_default} CURL_ENABLE_SSL OFF)
option(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG "Disable automatic loading of OpenSSL configuration" OFF)
count_true(enabled_ssl_options_count
- CMAKE_USE_SCHANNEL
- CMAKE_USE_SECTRANSP
- CMAKE_USE_OPENSSL
- CMAKE_USE_MBEDTLS
- CMAKE_USE_BEARSSL
- CMAKE_USE_NSS
- CMAKE_USE_WOLFSSL
+ CURL_USE_SCHANNEL
+ CURL_USE_SECTRANSP
+ CURL_USE_OPENSSL
+ CURL_USE_MBEDTLS
+ CURL_USE_BEARSSL
+ CURL_USE_NSS
+ CURL_USE_WOLFSSL
)
if(enabled_ssl_options_count GREATER "1")
set(CURL_WITH_MULTI_SSL ON)
endif()
-if(CMAKE_USE_SCHANNEL)
+if(CURL_USE_SCHANNEL)
set(SSL_ENABLED ON)
set(USE_SCHANNEL ON) # Windows native SSL/TLS support
- set(USE_WINDOWS_SSPI ON) # CMAKE_USE_SCHANNEL implies CURL_WINDOWS_SSPI
+ set(USE_WINDOWS_SSPI ON) # CURL_USE_SCHANNEL implies CURL_WINDOWS_SSPI
endif()
if(CURL_WINDOWS_SSPI)
set(USE_WINDOWS_SSPI ON)
set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32")
endif()
-if(CMAKE_USE_DARWINSSL)
- message(FATAL_ERROR "The cmake option CMAKE_USE_DARWINSSL was renamed to CMAKE_USE_SECTRANSP.")
+if(CURL_USE_SECTRANSP)
+ set(use_core_foundation ON)
+
+ find_library(SECURITY_FRAMEWORK "Security")
+ if(NOT SECURITY_FRAMEWORK)
+ message(FATAL_ERROR "Security framework not found")
+ endif()
+
+ set(SSL_ENABLED ON)
+ set(USE_SECTRANSP ON)
+ list(APPEND CURL_LIBS "-framework Security")
endif()
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+if(use_core_foundation)
find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation")
if(NOT COREFOUNDATION_FRAMEWORK)
message(FATAL_ERROR "CoreFoundation framework not found")
endif()
- find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
- if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
- message(FATAL_ERROR "SystemConfiguration framework not found")
- endif()
-
- list(APPEND CURL_LIBS "-framework CoreFoundation" "-framework SystemConfiguration")
-
- if(CMAKE_USE_SECTRANSP)
- find_library(SECURITY_FRAMEWORK "Security")
- if(NOT SECURITY_FRAMEWORK)
- message(FATAL_ERROR "Security framework not found")
- endif()
-
- set(SSL_ENABLED ON)
- set(USE_SECTRANSP ON)
- list(APPEND CURL_LIBS "-framework Security")
- endif()
+ list(APPEND CURL_LIBS "-framework CoreFoundation")
endif()
-if(CMAKE_USE_OPENSSL)
+if(CURL_USE_OPENSSL)
find_package(OpenSSL)
if(NOT OpenSSL_FOUND)
message(FATAL_ERROR
@@ -588,9 +609,11 @@ if(CMAKE_USE_OPENSSL)
if(CURL_CA_PATH)
add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}")
endif()
+
+ add_definitions(-DOPENSSL_SUPPRESS_DEPRECATED)
endif()
-if(CMAKE_USE_MBEDTLS)
+if(CURL_USE_MBEDTLS)
find_package(MbedTLS REQUIRED)
set(SSL_ENABLED ON)
set(USE_MBEDTLS ON)
@@ -598,7 +621,7 @@ if(CMAKE_USE_MBEDTLS)
include_directories(${MBEDTLS_INCLUDE_DIRS})
endif()
-if(CMAKE_USE_BEARSSL)
+if(CURL_USE_BEARSSL)
find_package(BearSSL REQUIRED)
set(SSL_ENABLED ON)
set(USE_BEARSSL ON)
@@ -606,7 +629,7 @@ if(CMAKE_USE_BEARSSL)
include_directories(${BEARSSL_INCLUDE_DIRS})
endif()
-if(CMAKE_USE_WOLFSSL)
+if(CURL_USE_WOLFSSL)
find_package(WolfSSL REQUIRED)
set(SSL_ENABLED ON)
set(USE_WOLFSSL ON)
@@ -614,7 +637,7 @@ if(CMAKE_USE_WOLFSSL)
include_directories(${WolfSSL_INCLUDE_DIRS})
endif()
-if(CMAKE_USE_NSS)
+if(CURL_USE_NSS)
find_package(NSS REQUIRED)
include_directories(${NSS_INCLUDE_DIRS})
list(APPEND CURL_LIBS ${NSS_LIBRARIES})
@@ -695,13 +718,13 @@ if(NOT CURL_DISABLE_LDAP)
endif()
endif()
- option(CMAKE_USE_OPENLDAP "Use OpenLDAP code." OFF)
- mark_as_advanced(CMAKE_USE_OPENLDAP)
+ option(CURL_USE_OPENLDAP "Use OpenLDAP code." OFF)
+ mark_as_advanced(CURL_USE_OPENLDAP)
set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library")
set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library")
- if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP)
- message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time")
+ if(CURL_USE_OPENLDAP AND USE_WIN32_LDAP)
+ message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CURL_USE_OPENLDAP at the same time")
endif()
# Now that we know, we're not using windows LDAP...
@@ -731,7 +754,7 @@ if(NOT CURL_DISABLE_LDAP)
set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
else()
- if(CMAKE_USE_OPENLDAP)
+ if(CURL_USE_OPENLDAP)
set(USE_OPENLDAP ON)
endif()
if(CMAKE_LDAP_INCLUDE_DIR)
@@ -873,13 +896,13 @@ if(CURL_ZSTD)
endif()
#libSSH2
-option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON)
-mark_as_advanced(CMAKE_USE_LIBSSH2)
+option(CURL_USE_LIBSSH2 "Use libSSH2" ON)
+mark_as_advanced(CURL_USE_LIBSSH2)
set(USE_LIBSSH2 OFF)
set(HAVE_LIBSSH2 OFF)
set(HAVE_LIBSSH2_H OFF)
-if(CMAKE_USE_LIBSSH2)
+if(CURL_USE_LIBSSH2)
find_package(LibSSH2)
if(LIBSSH2_FOUND)
list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
@@ -898,9 +921,9 @@ if(CMAKE_USE_LIBSSH2)
endif()
# libssh
-option(CMAKE_USE_LIBSSH "Use libSSH" OFF)
-mark_as_advanced(CMAKE_USE_LIBSSH)
-if(NOT HAVE_LIBSSH2 AND CMAKE_USE_LIBSSH)
+option(CURL_USE_LIBSSH "Use libSSH" OFF)
+mark_as_advanced(CURL_USE_LIBSSH)
+if(NOT HAVE_LIBSSH2 AND CURL_USE_LIBSSH)
find_package(libssh CONFIG)
if(libssh_FOUND)
message(STATUS "Found libssh ${libssh_VERSION}")
@@ -911,10 +934,10 @@ if(NOT HAVE_LIBSSH2 AND CMAKE_USE_LIBSSH)
endif()
endif()
-option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
-mark_as_advanced(CMAKE_USE_GSSAPI)
+option(CURL_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
+mark_as_advanced(CURL_USE_GSSAPI)
-if(CMAKE_USE_GSSAPI)
+if(CURL_USE_GSSAPI)
find_package(GSS)
set(HAVE_GSSAPI ${GSS_FOUND})
@@ -1065,7 +1088,6 @@ endif()
# Check for header files
if(NOT UNIX)
check_include_file_concat("windows.h" HAVE_WINDOWS_H)
- check_include_file_concat("winsock.h" HAVE_WINSOCK_H)
check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H)
check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H)
check_include_file_concat("wincrypt.h" HAVE_WINCRYPT_H)
@@ -1643,12 +1665,10 @@ set(libdir "${CMAKE_INSTALL_PREFIX}/lib")
foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
if(TARGET "${_lib}")
set(_libname "${_lib}")
- get_target_property(_libtype "${_libname}" TYPE)
- if(_libtype STREQUAL INTERFACE_LIBRARY)
- # Interface libraries can occur when an external project embeds curl and
- # defined targets such as ZLIB::ZLIB by themselves. Ignore these as
- # reading the LOCATION property will error out. Assume the user won't need
- # this information in the .pc file.
+ get_target_property(_imported "${_libname}" IMPORTED)
+ if(NOT _imported)
+ # Reading the LOCATION property on non-imported target will error out.
+ # Assume the user won't need this information in the .pc file.
continue()
endif()
get_target_property(_lib "${_libname}" LOCATION)
diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h
index 7b50b7c07d..ec2e245243 100644
--- a/Utilities/cmcurl/include/curl/curl.h
+++ b/Utilities/cmcurl/include/curl/curl.h
@@ -46,8 +46,8 @@
#include <stdio.h>
#include <limits.h>
-#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
-/* Needed for __FreeBSD_version symbol definition */
+#if (defined(__FreeBSD__) && (__FreeBSD__ >= 2)) || defined(__MidnightBSD__)
+/* Needed for __FreeBSD_version or __MidnightBSD_version symbol definition */
#include <osreldate.h>
#endif
@@ -73,6 +73,7 @@
defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
(defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
+ (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
defined(__VXWORKS__)
#include <sys/select.h>
#endif
@@ -470,6 +471,20 @@ typedef int (*curl_debug_callback)
size_t size, /* size of the data pointed to */
void *userptr); /* whatever the user please */
+/* This is the CURLOPT_PREREQFUNCTION callback prototype. */
+typedef int (*curl_prereq_callback)(void *clientp,
+ char *conn_primary_ip,
+ char *conn_local_ip,
+ int conn_primary_port,
+ int conn_local_port);
+
+/* Return code for when the pre-request callback has terminated without
+ any errors */
+#define CURL_PREREQFUNC_OK 0
+/* Return code for when the pre-request callback wants to abort the
+ request */
+#define CURL_PREREQFUNC_ABORT 1
+
/* All possible error codes from all sorts of curl functions. Future versions
may return other values, stay prepared.
@@ -2043,7 +2058,8 @@ typedef enum {
/* alt-svc cache file name to possibly read from/write to */
CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),
- /* maximum age of a connection to consider it for reuse (in seconds) */
+ /* maximum age (idle time) of a connection to consider it for reuse
+ * (in seconds) */
CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),
/* SASL authorisation identity */
@@ -2102,6 +2118,23 @@ typedef enum {
this option is used only if PROXY_SSL_VERIFYPEER is true */
CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
+ /* used by scp/sftp to verify the host's public key */
+ CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPTTYPE_STRINGPOINT, 311),
+
+ /* Function that will be called immediately before the initial request
+ is made on a connection (after any protocol negotiation step). */
+ CURLOPT(CURLOPT_PREREQFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 312),
+
+ /* Data passed to the CURLOPT_PREREQFUNCTION callback */
+ CURLOPT(CURLOPT_PREREQDATA, CURLOPTTYPE_CBPOINT, 313),
+
+ /* maximum age (since creation) of a connection to consider it for reuse
+ * (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;
@@ -2261,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/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h
index 9019868c06..1f268fa01a 100644
--- a/Utilities/cmcurl/include/curl/curlver.h
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@ -30,13 +30,13 @@
/* This is the version number of the libcurl package from which this header
file origins: */
-#define LIBCURL_VERSION "7.79.1"
+#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 79
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 81
+#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -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 0x074f01
+#define LIBCURL_VERSION_NUM 0x075100
/*
* This is the date and time when the full source package was created. The
diff --git a/Utilities/cmcurl/include/curl/multi.h b/Utilities/cmcurl/include/curl/multi.h
index 37f9829b3b..91cd95d323 100644
--- a/Utilities/cmcurl/include/curl/multi.h
+++ b/Utilities/cmcurl/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/Utilities/cmcurl/include/curl/typecheck-gcc.h b/Utilities/cmcurl/include/curl/typecheck-gcc.h
index 34d0267ed9..9e14d8a372 100644
--- a/Utilities/cmcurl/include/curl/typecheck-gcc.h
+++ b/Utilities/cmcurl/include/curl/typecheck-gcc.h
@@ -317,6 +317,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_SERVICE_NAME || \
(option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
(option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
+ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 || \
(option) == CURLOPT_SSH_KNOWNHOSTS || \
(option) == CURLOPT_SSH_PRIVATE_KEYFILE || \
(option) == CURLOPT_SSH_PUBLIC_KEYFILE || \
@@ -363,6 +364,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_INTERLEAVEDATA || \
(option) == CURLOPT_IOCTLDATA || \
(option) == CURLOPT_OPENSOCKETDATA || \
+ (option) == CURLOPT_PREREQDATA || \
(option) == CURLOPT_PROGRESSDATA || \
(option) == CURLOPT_READDATA || \
(option) == CURLOPT_SEEKDATA || \
diff --git a/Utilities/cmcurl/include/curl/urlapi.h b/Utilities/cmcurl/include/curl/urlapi.h
index 1d70880117..a475f91b60 100644
--- a/Utilities/cmcurl/include/curl/urlapi.h
+++ b/Utilities/cmcurl/include/curl/urlapi.h
@@ -47,7 +47,20 @@ typedef enum {
CURLUE_NO_HOST, /* 14 */
CURLUE_NO_PORT, /* 15 */
CURLUE_NO_QUERY, /* 16 */
- CURLUE_NO_FRAGMENT /* 17 */
+ 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;
typedef enum {
@@ -118,6 +131,12 @@ CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
const char *part, unsigned int flags);
+/*
+ * curl_url_strerror() turns a CURLUcode value into the equivalent human
+ * readable error string. This is useful for printing meaningful error
+ * messages.
+ */
+CURL_EXTERN const char *curl_url_strerror(CURLUcode);
#ifdef __cplusplus
} /* end of extern "C" */
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index d8fd7bd30f..6303b35c23 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -120,12 +120,6 @@ endif()
target_link_libraries(${LIB_NAME} PRIVATE ${CURL_LIBS})
-if(0) # This code not needed for building within CMake.
-if(WIN32)
- add_definitions(-D_USRDLL)
-endif()
-endif()
-
set_target_properties(${LIB_NAME} PROPERTIES
COMPILE_DEFINITIONS BUILDING_LIBCURL
OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
@@ -149,6 +143,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/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
index 763a4aaa0e..fd0bb6c96a 100644
--- a/Utilities/cmcurl/lib/asyn-ares.c
+++ b/Utilities/cmcurl/lib/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
@@ -341,7 +343,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
nfds = 0;
if(!nfds)
- /* Call ares_process() unconditonally here, even if we simply timed out
+ /* Call ares_process() unconditionally here, even if we simply timed out
above, as otherwise the ares name resolve won't timeout! */
ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
ARES_SOCKET_BAD);
@@ -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/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c
index 26635cdc1e..c253cd36ed 100644
--- a/Utilities/cmcurl/lib/c-hyper.c
+++ b/Utilities/cmcurl/lib/c-hyper.c
@@ -156,13 +156,15 @@ static int hyper_each_header(void *userdata,
Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
- writetype = CLIENTWRITE_HEADER;
- if(data->set.include_header)
- writetype |= CLIENTWRITE_BODY;
- result = Curl_client_write(data, writetype, headp, len);
- if(result) {
- data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
- return HYPER_ITER_BREAK;
+ if(!data->state.hconnect || !data->set.suppress_connect_headers) {
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+ result = Curl_client_write(data, writetype, headp, len);
+ if(result) {
+ data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+ return HYPER_ITER_BREAK;
+ }
}
data->info.header_size += (long)len;
@@ -205,7 +207,8 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
k->exp100 = EXP100_FAILED;
}
}
- if(data->state.hconnect && (data->req.httpcode/100 != 2)) {
+ if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
+ data->state.authproxy.done) {
done = TRUE;
result = CURLE_OK;
}
@@ -260,6 +263,12 @@ static CURLcode status_line(struct Curl_easy *data,
if(http_version == HYPER_HTTP_VERSION_1_0)
data->state.httpwant = CURL_HTTP_VERSION_1_0;
+ if(data->state.hconnect)
+ /* CONNECT */
+ data->info.httpproxycode = http_status;
+
+ /* We need to set 'httpcodeq' for functions that check the response code in
+ a single place. */
data->req.httpcode = http_status;
result = Curl_http_statusline(data, conn);
@@ -277,16 +286,18 @@ static CURLcode status_line(struct Curl_easy *data,
len = Curl_dyn_len(&data->state.headerb);
Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
len);
- writetype = CLIENTWRITE_HEADER;
- if(data->set.include_header)
- writetype |= CLIENTWRITE_BODY;
- result = Curl_client_write(data, writetype,
- Curl_dyn_ptr(&data->state.headerb), len);
- if(result) {
- data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
- return HYPER_ITER_BREAK;
- }
+ if(!data->state.hconnect || !data->set.suppress_connect_headers) {
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+ result = Curl_client_write(data, writetype,
+ Curl_dyn_ptr(&data->state.headerb), len);
+ if(result) {
+ data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+ return HYPER_ITER_BREAK;
+ }
+ }
data->info.header_size += (long)len;
data->req.headerbytecount += (long)len;
data->req.httpcode = http_status;
@@ -299,8 +310,14 @@ static CURLcode status_line(struct Curl_easy *data,
*/
static CURLcode empty_header(struct Curl_easy *data)
{
- return hyper_each_header(data, NULL, 0, NULL, 0) ?
- CURLE_WRITE_ERROR : CURLE_OK;
+ CURLcode result = Curl_http_size(data);
+ if(!result) {
+ result = hyper_each_header(data, NULL, 0, NULL, 0) ?
+ CURLE_WRITE_ERROR : CURLE_OK;
+ if(result)
+ failf(data, "hyperstream: couldn't pass blank header");
+ }
+ return result;
}
CURLcode Curl_hyper_stream(struct Curl_easy *data,
@@ -443,11 +460,9 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
break;
}
- if(empty_header(data)) {
- failf(data, "hyperstream: couldn't pass blank header");
- result = CURLE_OUT_OF_MEMORY;
+ result = empty_header(data);
+ if(result)
break;
- }
/* Curl_http_auth_act() checks what authentication methods that are
* available and decides which one (if any) to use. It will set 'newurl'
@@ -584,9 +599,22 @@ static CURLcode request_target(struct Curl_easy *data,
if(result)
return result;
- if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
- Curl_dyn_len(&r))) {
- failf(data, "error setting path");
+ if(h2 && hyper_request_set_uri_parts(req,
+ /* scheme */
+ (uint8_t *)data->state.up.scheme,
+ strlen(data->state.up.scheme),
+ /* authority */
+ (uint8_t *)conn->host.name,
+ strlen(conn->host.name),
+ /* path_and_query */
+ (uint8_t *)Curl_dyn_uptr(&r),
+ Curl_dyn_len(&r))) {
+ failf(data, "error setting uri parts to hyper");
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else if(!h2 && hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
+ Curl_dyn_len(&r))) {
+ failf(data, "error setting uri to hyper");
result = CURLE_OUT_OF_MEMORY;
}
else
@@ -850,6 +878,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
io = hyper_io_new();
if(!io) {
failf(data, "Couldn't create hyper IO");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
/* tell Hyper how to read/write network data */
@@ -862,6 +891,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
h->exec = hyper_executor_new();
if(!h->exec) {
failf(data, "Couldn't create hyper executor");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
}
@@ -869,6 +899,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
options = hyper_clientconn_options_new();
if(!options) {
failf(data, "Couldn't create hyper client options");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(conn->negnpn == CURL_HTTP_VERSION_2) {
@@ -882,6 +913,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
handshake = hyper_clientconn_handshake(io, options);
if(!handshake) {
failf(data, "Couldn't create hyper client handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
io = NULL;
@@ -889,6 +921,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
failf(data, "Couldn't hyper_executor_push the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
handshake = NULL; /* ownership passed on */
@@ -896,6 +929,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
task = hyper_executor_poll(h->exec);
if(!task) {
failf(data, "Couldn't hyper_executor_poll the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -905,6 +939,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
req = hyper_request_new();
if(!req) {
failf(data, "Couldn't hyper_request_new");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -912,12 +947,14 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(HYPERE_OK != hyper_request_set_version(req,
HYPER_HTTP_VERSION_1_0)) {
failf(data, "error setting HTTP version");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
}
if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
failf(data, "error setting method");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -928,51 +965,81 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
headers = hyper_request_headers(req);
if(!headers) {
failf(data, "hyper_request_headers");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
rc = hyper_request_on_informational(req, http1xx_cb, data);
- if(rc)
- return CURLE_OUT_OF_MEMORY;
+ if(rc) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
result = Curl_http_body(data, conn, httpreq, &te);
if(result)
- return result;
-
- if(data->state.aptr.host &&
- Curl_hyper_header(data, headers, data->state.aptr.host))
goto error;
- if(data->state.aptr.proxyuserpwd &&
- Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
- goto error;
+ if(!h2) {
+ if(data->state.aptr.host) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.host);
+ if(result)
+ goto error;
+ }
+ }
+ else {
+ /* For HTTP/2, we show the Host: header as if we sent it, to make it look
+ like for HTTP/1 but it isn't actually sent since :authority is then
+ used. */
+ result = Curl_debug(data, CURLINFO_HEADER_OUT, data->state.aptr.host,
+ strlen(data->state.aptr.host));
+ if(result)
+ goto error;
+ }
- if(data->state.aptr.userpwd &&
- Curl_hyper_header(data, headers, data->state.aptr.userpwd))
- goto error;
+ if(data->state.aptr.proxyuserpwd) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
+ if(result)
+ goto error;
+ }
- if((data->state.use_range && data->state.aptr.rangeline) &&
- Curl_hyper_header(data, headers, data->state.aptr.rangeline))
- goto error;
+ if(data->state.aptr.userpwd) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
+ if(result)
+ goto error;
+ }
+
+ if((data->state.use_range && data->state.aptr.rangeline)) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
+ if(result)
+ goto error;
+ }
if(data->set.str[STRING_USERAGENT] &&
*data->set.str[STRING_USERAGENT] &&
- data->state.aptr.uagent &&
- Curl_hyper_header(data, headers, data->state.aptr.uagent))
- goto error;
+ data->state.aptr.uagent) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
+ if(result)
+ goto error;
+ }
p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
- if(p_accept && Curl_hyper_header(data, headers, p_accept))
- goto error;
-
- if(te && Curl_hyper_header(data, headers, te))
- goto error;
+ if(p_accept) {
+ result = Curl_hyper_header(data, headers, p_accept);
+ if(result)
+ goto error;
+ }
+ if(te) {
+ result = Curl_hyper_header(data, headers, te);
+ if(result)
+ goto error;
+ }
#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
!Curl_checkheaders(data, "Proxy-Connection") &&
!Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
- if(Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
+ result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
+ if(result)
goto error;
}
#endif
@@ -981,8 +1048,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
if(!data->state.aptr.ref)
- return CURLE_OUT_OF_MEMORY;
- if(Curl_hyper_header(data, headers, data->state.aptr.ref))
+ result = CURLE_OUT_OF_MEMORY;
+ else
+ result = Curl_hyper_header(data, headers, data->state.aptr.ref);
+ if(result)
goto error;
}
@@ -992,8 +1061,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
if(!data->state.aptr.accept_encoding)
- return CURLE_OUT_OF_MEMORY;
- if(Curl_hyper_header(data, headers, data->state.aptr.accept_encoding))
+ result = CURLE_OUT_OF_MEMORY;
+ else
+ result = Curl_hyper_header(data, headers,
+ data->state.aptr.accept_encoding);
+ if(result)
goto error;
}
else
@@ -1003,38 +1075,43 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* we only consider transfer-encoding magic if libz support is built-in */
result = Curl_transferencode(data);
if(result)
- return result;
- if(Curl_hyper_header(data, headers, data->state.aptr.te))
+ goto error;
+ result = Curl_hyper_header(data, headers, data->state.aptr.te);
+ if(result)
goto error;
#endif
result = cookies(data, conn, headers);
if(result)
- return result;
+ goto error;
result = Curl_add_timecondition(data, headers);
if(result)
- return result;
+ goto error;
result = Curl_add_custom_headers(data, FALSE, headers);
if(result)
- return result;
+ goto error;
result = bodysend(data, conn, headers, req, httpreq);
if(result)
- return result;
+ goto error;
- Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
+ result = Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
+ if(result)
+ goto error;
data->req.upload_chunky = FALSE;
sendtask = hyper_clientconn_send(client, req);
if(!sendtask) {
failf(data, "hyper_clientconn_send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
failf(data, "Couldn't hyper_executor_push the send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -1057,7 +1134,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
Curl_safefree(data->state.aptr.proxyuserpwd);
return CURLE_OK;
error:
-
+ DEBUGASSERT(result);
if(io)
hyper_io_free(io);
@@ -1067,7 +1144,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(handshake)
hyper_task_free(handshake);
- return CURLE_OUT_OF_MEMORY;
+ return result;
}
void Curl_hyper_done(struct Curl_easy *data)
diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
index f5ba8ff70a..fec1937f0b 100644
--- a/Utilities/cmcurl/lib/conncache.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index d61b0374e3..5252f9714d 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -85,7 +85,7 @@
static bool verifyconnect(curl_socket_t sockfd, int *error);
-#if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
+#if defined(__DragonFly__) || defined(HAVE_WINSOCK2_H)
/* DragonFlyBSD and Windows use millisecond units */
#define KEEPALIVE_FACTOR(x) (x *= 1000)
#else
@@ -629,7 +629,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
#ifdef ENABLE_IPV6
struct sockaddr_in6 *si6 = NULL;
#endif
-#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
struct sockaddr_un *su = NULL;
#else
(void)salen;
@@ -656,7 +656,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
}
break;
#endif
-#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
case AF_UNIX:
if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
su = (struct sockaddr_un*)sa;
@@ -894,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;
@@ -977,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)));
@@ -988,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;
+ }
}
}
}
@@ -1016,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 */
@@ -1023,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;
@@ -1036,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);
@@ -1127,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/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c
index a84ff543b9..c03637a391 100644
--- a/Utilities/cmcurl/lib/content_encoding.c
+++ b/Utilities/cmcurl/lib/content_encoding.c
@@ -240,7 +240,8 @@ static CURLcode inflate_stream(struct Curl_easy *data,
}
zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */
}
- /* FALLTHROUGH */
+ result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
+ break;
default:
result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
break;
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index b7531f7424..d418efa33d 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
index de035507ec..6349ec3c5f 100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -702,9 +702,6 @@
/* Define to 1 if you have the winsock2.h header file. */
#cmakedefine HAVE_WINSOCK2_H 1
-/* Define to 1 if you have the winsock.h header file. */
-#cmakedefine HAVE_WINSOCK_H 1
-
/* Define this symbol if your OS supports changing the contents of argv */
#cmakedefine HAVE_WRITABLE_ARGV 1
diff --git a/Utilities/cmcurl/lib/curl_des.c b/Utilities/cmcurl/lib/curl_des.c
index 8c5af19cd2..76185cbf21 100644
--- a/Utilities/cmcurl/lib/curl_des.c
+++ b/Utilities/cmcurl/lib/curl_des.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2015 - 2020, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2015 - 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
@@ -22,7 +22,7 @@
#include "curl_setup.h"
-#if defined(USE_NTLM) && !defined(USE_OPENSSL)
+#if defined(USE_NTLM) && !defined(USE_OPENSSL) && !defined(USE_WOLFSSL)
#include "curl_des.h"
diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c
index 5810dad14b..8f340562bc 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.c
+++ b/Utilities/cmcurl/lib/curl_gssapi.c
@@ -32,10 +32,12 @@
#include "curl_memory.h"
#include "memdebug.h"
-static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02";
-gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes };
-static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02";
-gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes };
+gss_OID_desc Curl_spnego_mech_oid = {
+ 6, (char *)"\x2b\x06\x01\x05\x05\x02"
+};
+gss_OID_desc Curl_krb5_mech_oid = {
+ 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
+};
OM_uint32 Curl_gss_init_sec_context(
struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/curl_hmac.h b/Utilities/cmcurl/lib/curl_hmac.h
index 84c73121bd..5755655d02 100644
--- a/Utilities/cmcurl/lib/curl_hmac.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/curl_md5.h b/Utilities/cmcurl/lib/curl_md5.h
index 5739c89ca4..b7d7c1f5d2 100644
--- a/Utilities/cmcurl/lib/curl_md5.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
index 749b44e4a9..ed123d0c1c 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.c
@@ -49,7 +49,14 @@
in NTLM type-3 messages.
*/
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL)
+ #include <openssl/opensslconf.h>
+ #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+ #define USE_OPENSSL_DES
+ #endif
+#endif
+
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
#ifdef USE_WOLFSSL
#include <wolfssl/options.h>
@@ -97,7 +104,7 @@
#elif defined(USE_WIN32_CRYPTO)
# include <wincrypt.h>
#else
-# error "Can't compile NTLM support without a crypto library."
+# error "Can't compile NTLM support without a crypto library with DES."
#endif
#include "urldata.h"
@@ -133,7 +140,7 @@ static void extend_key_56_to_64(const unsigned char *key_56, char *key)
key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
}
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
/*
* Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
* key schedule ks is also set.
@@ -150,7 +157,7 @@ static void setup_des_key(const unsigned char *key_56,
DES_set_odd_parity(&key);
/* Set the key */
- DES_set_key(&key, ks);
+ DES_set_key_unchecked(&key, ks);
}
#elif defined(USE_GNUTLS)
@@ -362,7 +369,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
const unsigned char *plaintext,
unsigned char *results)
{
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
DES_key_schedule ks;
setup_des_key(keys, DESKEY(ks));
@@ -420,7 +427,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
{
/* Create LanManager hashed password. */
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
DES_key_schedule ks;
setup_des_key(pw, DESKEY(ks));
diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c
index 4a2488720e..8d39e4f81b 100644
--- a/Utilities/cmcurl/lib/curl_sasl.c
+++ b/Utilities/cmcurl/lib/curl_sasl.c
@@ -56,8 +56,8 @@
/* Supported mechanisms */
static const struct {
- const char *name; /* Name */
- size_t len; /* Name length */
+ const char *name; /* Name */
+ size_t len; /* Name length */
unsigned short bit; /* Flag bit */
} mechtable[] = {
{ "LOGIN", 5, SASL_MECH_LOGIN },
@@ -85,8 +85,11 @@ static const struct {
* conn [in] - The connection data.
* authused [in] - The authentication mechanism used.
*/
-void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
{
+ (void)conn;
+ (void)authused;
+
#if defined(USE_KERBEROS5)
/* Cleanup the gssapi structure */
if(authused == SASL_MECH_GSSAPI) {
@@ -107,12 +110,6 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
Curl_auth_cleanup_ntlm(&conn->ntlm);
}
#endif
-
-#if !defined(USE_KERBEROS5) && !defined(USE_NTLM)
- /* Reserved for future use */
- (void)conn;
- (void)authused;
-#endif
}
/*
@@ -189,16 +186,35 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
*
* Initializes the SASL structure.
*/
-void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
+void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
+ const struct SASLproto *params)
{
+ unsigned long auth = data->set.httpauth;
+
sasl->params = params; /* Set protocol dependent parameters */
sasl->state = SASL_STOP; /* Not yet running */
+ sasl->curmech = NULL; /* No mechanism yet. */
sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
- sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */
- sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */
+ sasl->prefmech = params->defmechs; /* Default preferred mechanisms */
+ sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */
sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
sasl->force_ir = FALSE; /* Respect external option */
+
+ if(auth != CURLAUTH_BASIC) {
+ sasl->resetprefs = FALSE;
+ sasl->prefmech = SASL_AUTH_NONE;
+ if(auth & CURLAUTH_BASIC)
+ sasl->prefmech |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
+ if(auth & CURLAUTH_DIGEST)
+ sasl->prefmech |= SASL_MECH_DIGEST_MD5;
+ if(auth & CURLAUTH_NTLM)
+ sasl->prefmech |= SASL_MECH_NTLM;
+ if(auth & CURLAUTH_BEARER)
+ sasl->prefmech |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
+ if(auth & CURLAUTH_GSSAPI)
+ sasl->prefmech |= SASL_MECH_GSSAPI;
+ }
}
/*
@@ -247,40 +263,45 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
struct bufref *out)
{
- unsigned char *msg;
- size_t msglen;
- char *serverdata = NULL;
CURLcode result = CURLE_OK;
- sasl->params->getmessage(data->state.buffer, &serverdata);
- if(!serverdata)
- result = CURLE_BAD_CONTENT_ENCODING;
- else if(!*serverdata || *serverdata == '=')
- Curl_bufref_set(out, NULL, 0, NULL);
- else {
- result = Curl_base64_decode(serverdata, &msg, &msglen);
- if(!result)
- Curl_bufref_set(out, msg, msglen, curl_free);
+ result = sasl->params->getmessage(data, out);
+ if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
+ unsigned char *msg;
+ size_t msglen;
+ const char *serverdata = (const char *) Curl_bufref_ptr(out);
+
+ if(!*serverdata || *serverdata == '=')
+ Curl_bufref_set(out, NULL, 0, NULL);
+ else {
+ result = Curl_base64_decode(serverdata, &msg, &msglen);
+ if(!result)
+ Curl_bufref_set(out, msg, msglen, curl_free);
+ }
}
return result;
}
/* Encode the outgoing SASL message. */
-static CURLcode build_message(struct Curl_easy *data, struct bufref *msg)
+static CURLcode build_message(struct SASL *sasl, struct Curl_easy *data,
+ struct bufref *msg)
{
CURLcode result = CURLE_OK;
- char *base64;
- size_t base64len;
- if(!Curl_bufref_ptr(msg)) /* Empty mesage. */
- Curl_bufref_set(msg, "", 0, NULL);
- else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
- Curl_bufref_set(msg, "=", 1, NULL);
- else {
- result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg),
- Curl_bufref_len(msg), &base64, &base64len);
- if(!result)
- Curl_bufref_set(msg, base64, base64len, curl_free);
+ if(sasl->params->flags & SASL_FLAG_BASE64) {
+ if(!Curl_bufref_ptr(msg)) /* Empty message. */
+ Curl_bufref_set(msg, "", 0, NULL);
+ else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
+ Curl_bufref_set(msg, "=", 1, NULL);
+ else {
+ char *base64;
+ size_t base64len;
+
+ result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg),
+ Curl_bufref_len(msg), &base64, &base64len);
+ if(!result)
+ Curl_bufref_set(msg, base64, base64len, curl_free);
+ }
}
return result;
@@ -310,11 +331,11 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
* Calculate the required login details for SASL authentication.
*/
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
- struct connectdata *conn,
bool force_ir, saslprogress *progress)
{
CURLcode result = CURLE_OK;
- unsigned int enabledmechs;
+ struct connectdata *conn = data->conn;
+ unsigned short enabledmechs;
const char *mech = NULL;
struct bufref resp;
saslstate state1 = SASL_STOP;
@@ -471,16 +492,16 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
}
if(!result && mech) {
+ sasl->curmech = mech;
if(Curl_bufref_ptr(&resp))
- result = build_message(data, &resp);
+ result = build_message(sasl, data, &resp);
if(sasl->params->maxirlen &&
strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
Curl_bufref_free(&resp);
if(!result)
- result = sasl->params->sendauth(data, conn, mech,
- (const char *) Curl_bufref_ptr(&resp));
+ result = sasl->params->sendauth(data, mech, &resp);
if(!result) {
*progress = SASL_INPROGRESS;
@@ -498,10 +519,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
* Continue the authentication.
*/
CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
- struct connectdata *conn,
int code, saslprogress *progress)
{
CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
saslstate newstate = SASL_FINAL;
struct bufref resp;
const char * const hostname = SSL_HOST_NAME();
@@ -574,7 +595,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_digest_md5_message(data, &serverdata,
conn->user, conn->passwd,
service, &resp);
- newstate = SASL_DIGESTMD5_RESP;
+ if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
+ newstate = SASL_DIGESTMD5_RESP;
break;
case SASL_DIGESTMD5_RESP:
/* Keep response NULL to output an empty line. */
@@ -691,7 +713,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
sasl->authmechs ^= sasl->authused;
/* Start an alternative SASL authentication */
- return Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
+ return Curl_sasl_start(sasl, data, sasl->force_ir, progress);
default:
failf(data, "Unsupported SASL authentication mechanism");
result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
@@ -703,14 +725,13 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
switch(result) {
case CURLE_BAD_CONTENT_ENCODING:
/* Cancel dialog */
- result = sasl->params->sendcont(data, conn, "*");
+ result = sasl->params->cancelauth(data, sasl->curmech);
newstate = SASL_CANCEL;
break;
case CURLE_OK:
- result = build_message(data, &resp);
+ result = build_message(sasl, data, &resp);
if(!result)
- result = sasl->params->sendcont(data, conn,
- (const char *) Curl_bufref_ptr(&resp));
+ result = sasl->params->contauth(data, sasl->curmech, &resp);
break;
default:
newstate = SASL_STOP; /* Stop on error */
diff --git a/Utilities/cmcurl/lib/curl_sasl.h b/Utilities/cmcurl/lib/curl_sasl.h
index e17d323eba..91458c74a0 100644
--- a/Utilities/cmcurl/lib/curl_sasl.h
+++ b/Utilities/cmcurl/lib/curl_sasl.h
@@ -24,6 +24,8 @@
#include <curl/curl.h>
+#include "bufref.h"
+
struct Curl_easy;
struct connectdata;
@@ -46,17 +48,20 @@ struct connectdata;
#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
/* Authentication mechanism strings */
-#define SASL_MECH_STRING_LOGIN "LOGIN"
-#define SASL_MECH_STRING_PLAIN "PLAIN"
-#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5"
-#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
-#define SASL_MECH_STRING_GSSAPI "GSSAPI"
-#define SASL_MECH_STRING_EXTERNAL "EXTERNAL"
-#define SASL_MECH_STRING_NTLM "NTLM"
-#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2"
-#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER"
-#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1"
-#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256"
+#define SASL_MECH_STRING_LOGIN "LOGIN"
+#define SASL_MECH_STRING_PLAIN "PLAIN"
+#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5"
+#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
+#define SASL_MECH_STRING_GSSAPI "GSSAPI"
+#define SASL_MECH_STRING_EXTERNAL "EXTERNAL"
+#define SASL_MECH_STRING_NTLM "NTLM"
+#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2"
+#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER"
+#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1"
+#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256"
+
+/* SASL flags */
+#define SASL_FLAG_BASE64 0x0001 /* Messages are base64-encoded */
/* SASL machine states */
typedef enum {
@@ -90,30 +95,37 @@ typedef enum {
/* Protocol dependent SASL parameters */
struct SASLproto {
const char *service; /* The service name */
- int contcode; /* Code to receive when continuation is expected */
- int finalcode; /* Code to receive upon authentication success */
- size_t maxirlen; /* Maximum initial response length */
- CURLcode (*sendauth)(struct Curl_easy *data,
- struct connectdata *conn,
- const char *mech, const char *ir);
+ CURLcode (*sendauth)(struct Curl_easy *data, const char *mech,
+ const struct bufref *ir);
/* Send authentication command */
- CURLcode (*sendcont)(struct Curl_easy *data,
- struct connectdata *conn, const char *contauth);
+ CURLcode (*contauth)(struct Curl_easy *data, const char *mech,
+ const struct bufref *contauth);
/* Send authentication continuation */
- void (*getmessage)(char *buffer, char **outptr);
+ CURLcode (*cancelauth)(struct Curl_easy *data, const char *mech);
+ /* Cancel authentication. */
+ CURLcode (*getmessage)(struct Curl_easy *data, struct bufref *out);
/* Get SASL response message */
+ size_t maxirlen; /* Maximum initial response + mechanism length,
+ or zero if no max. This is normally the max
+ command length - other characters count.
+ This has to be zero for non-base64 protocols. */
+ int contcode; /* Code to receive when continuation is expected */
+ int finalcode; /* Code to receive upon authentication success */
+ unsigned short defmechs; /* Mechanisms enabled by default */
+ unsigned short flags; /* Configuration flags. */
};
/* Per-connection parameters */
struct SASL {
const struct SASLproto *params; /* Protocol dependent parameters */
- saslstate state; /* Current machine state */
+ saslstate state; /* Current machine state */
+ const char *curmech; /* Current mechanism id. */
unsigned short authmechs; /* Accepted authentication mechanisms */
unsigned short prefmech; /* Preferred authentication mechanism */
unsigned short authused; /* Auth mechanism used for the connection */
- bool resetprefs; /* For URL auth option parsing. */
- bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */
- bool force_ir; /* Protocol always supports initial response */
+ bool resetprefs; /* For URL auth option parsing. */
+ bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */
+ bool force_ir; /* Protocol always supports initial response */
};
/* This is used to test whether the line starts with the given mechanism */
@@ -123,7 +135,7 @@ struct SASL {
/* This is used to cleanup any libraries or curl modules used by the sasl
functions */
-void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused);
/* Convert a mechanism name to a token */
unsigned short Curl_sasl_decode_mech(const char *ptr,
@@ -134,19 +146,18 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
const char *value, size_t len);
/* Initializes an SASL structure */
-void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params);
+void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
+ const struct SASLproto *params);
/* Check if we have enough auth data and capabilities to authenticate */
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
/* Calculate the required login details for SASL authentication */
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
- struct connectdata *conn,
bool force_ir, saslprogress *progress);
/* Continue an SASL authentication */
CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
- struct connectdata *conn,
int code, saslprogress *progress);
#endif /* HEADER_CURL_SASL_H */
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index 554dcc1e67..7421b6702e 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -732,7 +732,6 @@ int netware_init(void);
#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
# if defined(SOCKET) || \
defined(USE_WINSOCK) || \
- defined(HAVE_WINSOCK_H) || \
defined(HAVE_WINSOCK2_H) || \
defined(HAVE_WS2TCPIP_H)
# error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
@@ -854,6 +853,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
ADDRESS_FAMILY sun_family;
char sun_path[UNIX_PATH_MAX];
} SOCKADDR_UN, *PSOCKADDR_UN;
+# define WIN32_SOCKADDR_UN
# endif
#endif
diff --git a/Utilities/cmcurl/lib/curl_sha256.h b/Utilities/cmcurl/lib/curl_sha256.h
index b4579d7692..55dc30ad74 100644
--- a/Utilities/cmcurl/lib/curl_sha256.h
+++ b/Utilities/cmcurl/lib/curl_sha256.h
@@ -8,7 +8,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2017, Florin Petriuc, <petriuc.florin@gmail.com>
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 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
@@ -28,10 +28,17 @@
extern const struct HMAC_params Curl_HMAC_SHA256[1];
+#ifdef USE_WOLFSSL
+/* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from
+ * sha.h*/
+#include <wolfssl/options.h>
+#include <openssl/sha.h>
+#else
#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/Utilities/cmcurl/lib/curl_sspi.c b/Utilities/cmcurl/lib/curl_sspi.c
index 06841ddec6..339bf549fb 100644
--- a/Utilities/cmcurl/lib/curl_sspi.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c
index de0c902b86..d6a2167701 100644
--- a/Utilities/cmcurl/lib/doh.c
+++ b/Utilities/cmcurl/lib/doh.c
@@ -235,25 +235,6 @@ static CURLcode dohprobe(struct Curl_easy *data,
p->dnstype = dnstype;
Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
- /* Note: this is code for sending the DoH request with GET but there's still
- no logic that actually enables this. We should either add that ability or
- yank out the GET code. Discuss! */
- if(data->set.doh_get) {
- char *b64;
- size_t b64len;
- result = Curl_base64url_encode(data, (char *)p->dohbuffer, p->dohlen,
- &b64, &b64len);
- if(result)
- goto error;
- nurl = aprintf("%s?dns=%s", url, b64);
- free(b64);
- if(!nurl) {
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- url = nurl;
- }
-
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms <= 0) {
result = CURLE_OPERATION_TIMEDOUT;
@@ -268,10 +249,8 @@ static CURLcode dohprobe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_URL, url);
ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
- if(!data->set.doh_get) {
- ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
- ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
- }
+ ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
+ ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
#ifdef USE_NGHTTP2
ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index 2aca93845b..20293a710b 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/easyoptions.c b/Utilities/cmcurl/lib/easyoptions.c
index 4e65e3525b..04871ad1e3 100644
--- a/Utilities/cmcurl/lib/easyoptions.c
+++ b/Utilities/cmcurl/lib/easyoptions.c
@@ -165,10 +165,12 @@ struct curl_easyoption Curl_easyopts[] = {
{"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0},
{"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0},
{"MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE, CURLOT_OFF_T, 0},
+ {"MAXLIFETIME_CONN", CURLOPT_MAXLIFETIME_CONN, CURLOT_LONG, 0},
{"MAXREDIRS", CURLOPT_MAXREDIRS, CURLOT_LONG, 0},
{"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},
@@ -192,6 +194,8 @@ struct curl_easyoption Curl_easyopts[] = {
{"POSTQUOTE", CURLOPT_POSTQUOTE, CURLOT_SLIST, 0},
{"POSTREDIR", CURLOPT_POSTREDIR, CURLOT_VALUES, 0},
{"PREQUOTE", CURLOPT_PREQUOTE, CURLOT_SLIST, 0},
+ {"PREREQDATA", CURLOPT_PREREQDATA, CURLOT_CBPTR, 0},
+ {"PREREQFUNCTION", CURLOPT_PREREQFUNCTION, CURLOT_FUNCTION, 0},
{"PRE_PROXY", CURLOPT_PRE_PROXY, CURLOT_STRING, 0},
{"PRIVATE", CURLOPT_PRIVATE, CURLOT_OBJECT, 0},
{"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
@@ -271,6 +275,8 @@ struct curl_easyoption Curl_easyopts[] = {
{"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0},
{"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
CURLOT_STRING, 0},
+ {"SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
+ CURLOT_STRING, 0},
{"SSH_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0},
{"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
{"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
@@ -354,6 +360,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
- return ((CURLOPT_LASTENTRY%10000) != (310 + 1));
+ return ((CURLOPT_LASTENTRY%10000) != (315 + 1));
}
#endif
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index cad584f243..5c39edb259 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/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
@@ -876,11 +876,6 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data,
ftpc->count2 = 0; /* count2 counts failed CWDs */
- /* count3 is set to allow a MKD to fail once. In the case when first CWD
- fails and then MKD fails (due to another session raced it to create the
- dir) this then allows for a second try to CWD to it */
- ftpc->count3 = (data->set.ftp_create_missing_dirs == 2)?1:0;
-
if(conn->bits.reuse && ftpc->entrypath &&
/* no need to go to entrypath when we have an absolute path */
!(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
@@ -1009,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));
@@ -3002,6 +2997,12 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
ftpc->cwdcount && !ftpc->count2) {
/* try making it */
ftpc->count2++; /* counter to prevent CWD-MKD loops */
+
+ /* count3 is set to allow MKD to fail once per dir. In the case when
+ CWD fails and then MKD fails (due to another session raced it to
+ create the dir) this then allows for a second try to CWD to it. */
+ ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0;
+
result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s",
ftpc->dirs[ftpc->cwdcount - 1]);
if(!result)
@@ -4102,6 +4103,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 +4196,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 +4363,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/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c
index 12e7aa5f27..8848906947 100644
--- a/Utilities/cmcurl/lib/hash.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/hash.h b/Utilities/cmcurl/lib/hash.h
index b7f828e071..e166916a90 100644
--- a/Utilities/cmcurl/lib/hash.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/hostcheck.c b/Utilities/cmcurl/lib/hostcheck.c
index cf267a7659..cd45bd07ee 100644
--- a/Utilities/cmcurl/lib/hostcheck.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index 117caa2957..911d5ed6d3 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -507,9 +507,6 @@ static struct Curl_addrinfo *get_localhost(int port)
struct sockaddr_in sa;
unsigned int ipv4;
unsigned short port16 = (unsigned short)(port & 0xffff);
- ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
- if(!ca)
- return NULL;
/* memset to clear the sa.sin_zero field */
memset(&sa, 0, sizeof(sa));
@@ -519,6 +516,9 @@ static struct Curl_addrinfo *get_localhost(int port)
return NULL;
memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4));
+ ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
+ if(!ca)
+ return NULL;
ca->ai_flags = 0;
ca->ai_family = AF_INET;
ca->ai_socktype = SOCK_STREAM;
@@ -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/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h
index 67a688aebd..1db5981842 100644
--- a/Utilities/cmcurl/lib/hostip.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index 648583c56a..f08a343e3b 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -323,7 +323,7 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
pwd = data->state.aptr.passwd;
}
- out = aprintf("%s:%s", user, pwd ? pwd : "");
+ out = aprintf("%s:%s", user ? user : "", pwd ? pwd : "");
if(!out)
return CURLE_OUT_OF_MEMORY;
@@ -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
@@ -2902,20 +2901,6 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
bool *done)
{
struct SingleRequest *k = &data->req;
- DEBUGASSERT(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP));
- if(data->req.ignore_cl) {
- k->size = k->maxdownload = -1;
- }
- else if(k->size != -1) {
- /* We wait until after all headers have been received to set this so that
- we know for sure Content-Length is valid. */
- if(data->set.max_filesize &&
- k->size > data->set.max_filesize) {
- failf(data, "Maximum file size exceeded");
- return CURLE_FILESIZE_EXCEEDED;
- }
- Curl_pgrsSetDownloadSize(data, k->size);
- }
if(data->req.newurl) {
if(conn->bits.close) {
@@ -3326,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 */
}
@@ -3366,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 */
}
@@ -3787,6 +3772,29 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
return CURLE_OK;
}
+/* Content-Length must be ignored if any Transfer-Encoding is present in the
+ response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
+ figured out here after all headers have been received but before the final
+ call to the user's header callback, so that a valid content length can be
+ retrieved by the user in the final call. */
+CURLcode Curl_http_size(struct Curl_easy *data)
+{
+ struct SingleRequest *k = &data->req;
+ if(data->req.ignore_cl || k->chunk) {
+ k->size = k->maxdownload = -1;
+ }
+ else if(k->size != -1) {
+ if(data->set.max_filesize &&
+ k->size > data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
+ }
+ Curl_pgrsSetDownloadSize(data, k->size);
+ k->maxdownload = k->size;
+ }
+ return CURLE_OK;
+}
+
/*
* Read any HTTP header lines from the server and pass them to the client app.
*/
@@ -3981,6 +3989,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
+ if(!k->header) {
+ result = Curl_http_size(data);
+ if(result)
+ return result;
+ }
+
/* At this point we have some idea about the fate of the connection.
If we are closing the connection it may result auth failure. */
#if defined(USE_NTLM)
@@ -4137,31 +4151,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
reason */
*stop_reading = TRUE;
#endif
- else {
- /* If we know the expected size of this document, we set the
- maximum download size to the size of the expected
- document or else, we won't know when to stop reading!
-
- Note that we set the download maximum even if we read a
- "Connection: close" header, to make sure that
- "Content-Length: 0" still prevents us from attempting to
- read the (missing) response-body.
- */
- /* According to RFC2616 section 4.4, we MUST ignore
- Content-Length: headers if we are now receiving data
- using chunked Transfer-Encoding.
- */
- if(k->chunk)
- k->maxdownload = k->size = -1;
- }
- if(-1 != k->size) {
- /* We do this operation even if no_body is true, since this
- data might be retrieved later with curl_easy_getinfo()
- and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */
-
- Curl_pgrsSetDownloadSize(data, k->size);
- k->maxdownload = k->size;
- }
/* If max download size is *zero* (nothing) we already have
nothing and can safely return ok now! But for HTTP/2, we'd
@@ -4250,8 +4239,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* There can only be a 4th response code digit stored in 'digit4' if
all the other fields were parsed and stored first, so nc is 5 when
- digit4 a digit */
- else if(ISDIGIT(digit4)) {
+ digit4 a digit.
+
+ The sscanf() line above will also allow zero-prefixed and negative
+ numbers, so we check for that too here.
+ */
+ else if(ISDIGIT(digit4) || (nc >= 4 && k->httpcode < 100)) {
failf(data, "Unsupported response code in HTTP response");
return CURLE_UNSUPPORTED_PROTOCOL;
}
diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h
index e4ab466c00..b4aaba2a26 100644
--- a/Utilities/cmcurl/lib/http.h
+++ b/Utilities/cmcurl/lib/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
@@ -289,6 +285,8 @@ struct http_conn {
#endif
};
+CURLcode Curl_http_size(struct Curl_easy *data);
+
CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
struct connectdata *conn,
ssize_t *nread,
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index 6d63f43636..e74400a4ca 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -100,6 +100,7 @@ static int http2_getsock(struct Curl_easy *data,
const struct http_conn *c = &conn->proto.httpc;
struct SingleRequest *k = &data->req;
int bitmap = GETSOCK_BLANK;
+ struct HTTP *stream = data->req.p.http;
sock[0] = conn->sock[FIRSTSOCKET];
@@ -108,9 +109,13 @@ static int http2_getsock(struct Curl_easy *data,
frame so we should always be ready for one */
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
- /* we're still uploading or the HTTP/2 layer wants to send data */
- if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
- nghttp2_session_want_write(c->h2))
+ /* we're (still uploading OR the HTTP/2 layer wants to send data) AND
+ there's a window to send data in */
+ if((((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
+ nghttp2_session_want_write(c->h2)) &&
+ (nghttp2_session_get_remote_window_size(c->h2) &&
+ nghttp2_session_get_stream_remote_window_size(c->h2,
+ stream->stream_id)))
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
return bitmap;
@@ -500,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) {
@@ -1953,8 +1961,19 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
nghttp2_session_resume_data(h2, stream->stream_id);
}
- H2BUGF(infof(data, "http2_send returns %zu for stream %u", len,
- stream->stream_id));
+#ifdef DEBUG_HTTP2
+ if(!len) {
+ infof(data, "http2_send: easy %p (stream %u) win %u/%u",
+ data, stream->stream_id,
+ nghttp2_session_get_remote_window_size(httpc->h2),
+ nghttp2_session_get_stream_remote_window_size(httpc->h2,
+ stream->stream_id)
+ );
+
+ }
+ infof(data, "http2_send returns %zu for stream %u", len,
+ stream->stream_id);
+#endif
return len;
}
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
index 02663abd63..751e5af5f9 100644
--- a/Utilities/cmcurl/lib/http_aws_sigv4.c
+++ b/Utilities/cmcurl/lib/http_aws_sigv4.c
@@ -92,6 +92,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
char *signed_headers = NULL;
Curl_HttpReq httpreq;
const char *method;
+ size_t post_data_len;
const char *post_data = data->set.postfields ? data->set.postfields : "";
unsigned char sha_hash[32];
char sha_hex[65];
@@ -281,8 +282,15 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
goto fail;
}
- Curl_sha256it(sha_hash,
- (const unsigned char *) post_data, strlen(post_data));
+ if(data->set.postfieldsize < 0)
+ post_data_len = strlen(post_data);
+ else
+ post_data_len = (size_t)data->set.postfieldsize;
+ 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);
@@ -315,13 +323,16 @@ 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));
/*
* Google allow to use rsa key instead of HMAC, so this code might change
- * In the furure, but for now we support only HMAC version
+ * In the future, but for now we support only HMAC version
*/
str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
"%s\n" /* RequestDateTime */
diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c
index 627a11c5af..a6526db9f7 100644
--- a/Utilities/cmcurl/lib/http_ntlm.c
+++ b/Utilities/cmcurl/lib/http_ntlm.c
@@ -198,6 +198,12 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
#endif
Curl_bufref_init(&ntlmmsg);
+
+ /* connection is already authenticated, don't send a header in future
+ * requests so go directly to NTLMSTATE_LAST */
+ if(*state == NTLMSTATE_TYPE3)
+ *state = NTLMSTATE_LAST;
+
switch(*state) {
case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */
@@ -246,11 +252,6 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
}
break;
- case NTLMSTATE_TYPE3:
- /* connection is already authenticated,
- * don't send a header in future requests */
- *state = NTLMSTATE_LAST;
- /* FALLTHROUGH */
case NTLMSTATE_LAST:
Curl_safefree(*allocuserpwd);
authp->done = TRUE;
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index 58489abec1..e13f485a73 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/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,18 +202,25 @@ 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);
- /* retore 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 */
+ data->req.ignorebody = FALSE;
+#ifdef USE_HYPER
+ data->state.hconnect = FALSE;
+#endif
infof(data, "CONNECT phase completed!");
}
}
@@ -284,8 +295,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
/* This only happens if we've looped here due to authentication
reasons, and we don't really use the newly cloned URL here
then. Just free() it. */
- free(data->req.newurl);
- data->req.newurl = NULL;
+ Curl_safefree(data->req.newurl);
/* initialize send-buffer */
Curl_dyn_init(req, DYN_HTTP_REQUEST);
@@ -657,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 */
@@ -735,6 +743,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
io = hyper_io_new();
if(!io) {
failf(data, "Couldn't create hyper IO");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
/* tell Hyper how to read/write network data */
@@ -750,6 +759,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
h->exec = hyper_executor_new();
if(!h->exec) {
failf(data, "Couldn't create hyper executor");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
}
@@ -757,6 +767,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
options = hyper_clientconn_options_new();
if(!options) {
failf(data, "Couldn't create hyper client options");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -767,6 +778,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
handshake = hyper_clientconn_handshake(io, options);
if(!handshake) {
failf(data, "Couldn't create hyper client handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
io = NULL;
@@ -774,6 +786,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
failf(data, "Couldn't hyper_executor_push the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
handshake = NULL; /* ownership passed on */
@@ -781,6 +794,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
task = hyper_executor_poll(h->exec);
if(!task) {
failf(data, "Couldn't hyper_executor_poll the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -789,14 +803,24 @@ static CURLcode CONNECT(struct Curl_easy *data,
req = hyper_request_new();
if(!req) {
failf(data, "Couldn't hyper_request_new");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
strlen("CONNECT"))) {
failf(data, "error setting method");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
+ infof(data, "Establish HTTP proxy tunnel to %s:%d",
+ hostname, remote_port);
+
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
+ then. Just free() it. */
+ Curl_safefree(data->req.newurl);
+
result = CONNECT_host(data, conn, hostname, remote_port,
&hostheader, &host);
if(result)
@@ -806,6 +830,16 @@ static CURLcode CONNECT(struct Curl_easy *data,
strlen(hostheader))) {
failf(data, "error setting path");
result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ if(data->set.verbose) {
+ char *se = aprintf("CONNECT %s HTTP/1.1\r\n", hostheader);
+ if(!se) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se));
+ free(se);
}
/* Setup the proxy-authorization header, if any */
result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
@@ -819,21 +853,29 @@ static CURLcode CONNECT(struct Curl_easy *data,
(HYPERE_OK != hyper_request_set_version(req,
HYPER_HTTP_VERSION_1_0))) {
failf(data, "error setting HTTP version");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
headers = hyper_request_headers(req);
if(!headers) {
failf(data, "hyper_request_headers");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
- if(host && Curl_hyper_header(data, headers, host))
- goto error;
- Curl_safefree(host);
+ if(host) {
+ result = Curl_hyper_header(data, headers, host);
+ if(result)
+ goto error;
+ Curl_safefree(host);
+ }
- if(data->state.aptr.proxyuserpwd &&
- Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
- goto error;
+ if(data->state.aptr.proxyuserpwd) {
+ result = Curl_hyper_header(data, headers,
+ data->state.aptr.proxyuserpwd);
+ if(result)
+ goto error;
+ }
if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
data->set.str[STRING_USERAGENT]) {
@@ -843,26 +885,33 @@ static CURLcode CONNECT(struct Curl_easy *data,
data->set.str[STRING_USERAGENT]);
if(result)
goto error;
- if(Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua)))
+ result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua));
+ if(result)
goto error;
Curl_dyn_free(&ua);
}
- if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") &&
- Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
- goto error;
+ if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
+ result = Curl_hyper_header(data, headers,
+ "Proxy-Connection: Keep-Alive");
+ if(result)
+ goto error;
+ }
- if(Curl_add_custom_headers(data, TRUE, headers))
+ result = Curl_add_custom_headers(data, TRUE, headers);
+ if(result)
goto error;
sendtask = hyper_clientconn_send(client, req);
if(!sendtask) {
failf(data, "hyper_clientconn_send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
failf(data, "Couldn't hyper_executor_push the send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -875,8 +924,11 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(error)
hypererr = hyper_task_value(task);
hyper_task_free(task);
- if(error)
+ if(error) {
+ /* this could probably use a better error code? */
+ result = CURLE_OUT_OF_MEMORY;
goto error;
+ }
}
} while(task);
s->tunnel_state = TUNNEL_CONNECT;
@@ -904,20 +956,28 @@ static CURLcode CONNECT(struct Curl_easy *data,
h->write_waker = NULL;
}
}
- /* FALLTHROUGH */
+ break;
+
default:
break;
}
+
+ /* If we are supposed to continue and request a new URL, which basically
+ * means the HTTP authentication is still going on so if the tunnel
+ * is complete we start over in INIT state */
+ if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) {
+ infof(data, "CONNECT request done, loop to make another");
+ connect_init(data, TRUE); /* reinit */
+ }
} while(data->req.newurl);
result = CURLE_OK;
if(s->tunnel_state == TUNNEL_COMPLETE) {
- data->info.httpproxycode = data->req.httpcode;
if(data->info.httpproxycode/100 != 2) {
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);
@@ -991,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/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h
index cdf8de4fba..2820e11841 100644
--- a/Utilities/cmcurl/lib/http_proxy.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c
index 21e00b1f16..132b3eeeea 100644
--- a/Utilities/cmcurl/lib/if2ip.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
index 6163899bbe..958ad1456c 100644
--- a/Utilities/cmcurl/lib/imap.c
+++ b/Utilities/cmcurl/lib/imap.c
@@ -78,6 +78,7 @@
#include "multiif.h"
#include "url.h"
#include "strcase.h"
+#include "bufref.h"
#include "curl_sasl.h"
#include "warnless.h"
@@ -101,19 +102,19 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode imap_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static char *imap_atom(const char *str, bool escape_only);
-static CURLcode imap_sendf(struct Curl_easy *data,
- struct connectdata *conn, const char *fmt, ...);
+static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...);
static CURLcode imap_parse_url_options(struct connectdata *conn);
static CURLcode imap_parse_url_path(struct Curl_easy *data);
static CURLcode imap_parse_custom_request(struct Curl_easy *data);
static CURLcode imap_perform_authenticate(struct Curl_easy *data,
- struct connectdata *conn,
const char *mech,
- const char *initresp);
+ const struct bufref *initresp);
static CURLcode imap_continue_authenticate(struct Curl_easy *data,
- struct connectdata *conn,
- const char *resp);
-static void imap_get_message(char *buffer, char **outptr);
+ const char *mech,
+ const struct bufref *resp);
+static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
+ const char *mech);
+static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
/*
* IMAP protocol handler.
@@ -180,12 +181,15 @@ const struct Curl_handler Curl_handler_imaps = {
/* SASL parameters for the imap protocol */
static const struct SASLproto saslimap = {
"imap", /* The service name */
- '+', /* Code received when continuation is expected */
- IMAP_RESP_OK, /* Code to receive upon authentication success */
- 0, /* Maximum initial response length (no max) */
imap_perform_authenticate, /* Send authentication command */
imap_continue_authenticate, /* Send authentication continuation */
- imap_get_message /* Get SASL response message */
+ imap_cancel_authenticate, /* Send authentication cancellation */
+ imap_get_message, /* Get SASL response message */
+ 0, /* No maximum initial response length */
+ '+', /* Code received when continuation is expected */
+ IMAP_RESP_OK, /* Code to receive upon authentication success */
+ SASL_AUTH_DEFAULT, /* Default mechanisms */
+ SASL_FLAG_BASE64 /* Configuration flags */
};
@@ -293,6 +297,7 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
!strcasecompare(imap->custom, "EXPUNGE") &&
!strcasecompare(imap->custom, "LSUB") &&
!strcasecompare(imap->custom, "UID") &&
+ !strcasecompare(imap->custom, "GETQUOTAROOT") &&
!strcasecompare(imap->custom, "NOOP")))
return FALSE;
break;
@@ -324,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) {
@@ -352,34 +357,32 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
*
* Gets the authentication message from the response buffer.
*/
-static void imap_get_message(char *buffer, char **outptr)
+static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
{
- size_t len = strlen(buffer);
- char *message = NULL;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 2) {
/* Find the start of the message */
len -= 2;
- for(message = buffer + 2; *message == ' ' || *message == '\t';
- message++, len--)
+ for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
;
/* Find the end of the message */
- for(; len--;)
+ while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t')
break;
/* Terminate the message */
- if(++len) {
- message[len] = '\0';
- }
+ message[++len] = '\0';
+ Curl_bufref_set(out, message, len, NULL);
}
else
/* junk input => zero length output */
- message = &buffer[len];
+ Curl_bufref_set(out, "", 0, NULL);
- *outptr = message;
+ return CURLE_OK;
}
/***********************************************************************
@@ -437,7 +440,7 @@ static CURLcode imap_perform_capability(struct Curl_easy *data,
imapc->tls_supported = FALSE; /* Clear the TLS capability */
/* Send the CAPABILITY command */
- result = imap_sendf(data, conn, "CAPABILITY");
+ result = imap_sendf(data, "CAPABILITY");
if(!result)
state(data, IMAP_CAPABILITY);
@@ -451,11 +454,10 @@ static CURLcode imap_perform_capability(struct Curl_easy *data,
*
* Sends the STARTTLS command to start the upgrade to TLS.
*/
-static CURLcode imap_perform_starttls(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode imap_perform_starttls(struct Curl_easy *data)
{
/* Send the STARTTLS command */
- CURLcode result = imap_sendf(data, conn, "STARTTLS");
+ CURLcode result = imap_sendf(data, "STARTTLS");
if(!result)
state(data, IMAP_STARTTLS);
@@ -516,7 +518,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
passwd = imap_atom(conn->passwd, false);
/* Send the LOGIN command */
- result = imap_sendf(data, conn, "LOGIN %s %s", user ? user : "",
+ result = imap_sendf(data, "LOGIN %s %s", user ? user : "",
passwd ? passwd : "");
free(user);
@@ -536,20 +538,19 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
* SASL authentication mechanism.
*/
static CURLcode imap_perform_authenticate(struct Curl_easy *data,
- struct connectdata *conn,
const char *mech,
- const char *initresp)
+ const struct bufref *initresp)
{
CURLcode result = CURLE_OK;
- (void)data;
+ const char *ir = (const char *) Curl_bufref_ptr(initresp);
- if(initresp) {
+ if(ir) {
/* Send the AUTHENTICATE command with the initial response */
- result = imap_sendf(data, conn, "AUTHENTICATE %s %s", mech, initresp);
+ result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir);
}
else {
/* Send the AUTHENTICATE command */
- result = imap_sendf(data, conn, "AUTHENTICATE %s", mech);
+ result = imap_sendf(data, "AUTHENTICATE %s", mech);
}
return result;
@@ -559,15 +560,34 @@ static CURLcode imap_perform_authenticate(struct Curl_easy *data,
*
* imap_continue_authenticate()
*
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
*/
static CURLcode imap_continue_authenticate(struct Curl_easy *data,
- struct connectdata *conn,
- const char *resp)
+ const char *mech,
+ const struct bufref *resp)
{
- struct imap_conn *imapc = &conn->proto.imapc;
+ struct imap_conn *imapc = &data->conn->proto.imapc;
+
+ (void)mech;
- return Curl_pp_sendf(data, &imapc->pp, "%s", resp);
+ return Curl_pp_sendf(data, &imapc->pp,
+ "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * imap_cancel_authenticate()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
+ const char *mech)
+{
+ struct imap_conn *imapc = &data->conn->proto.imapc;
+
+ (void)mech;
+
+ return Curl_pp_sendf(data, &imapc->pp, "*");
}
/***********************************************************************
@@ -594,8 +614,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
}
/* Calculate the SASL login details */
- result = Curl_sasl_start(&imapc->sasl, data, conn,
- imapc->ir_supported, &progress);
+ result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress);
if(!result) {
if(progress == SASL_INPROGRESS)
@@ -622,12 +641,11 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
static CURLcode imap_perform_list(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap;
if(imap->custom)
/* Send the custom request */
- result = imap_sendf(data, conn, "%s%s", imap->custom,
+ result = imap_sendf(data, "%s%s", imap->custom,
imap->custom_params ? imap->custom_params : "");
else {
/* Make sure the mailbox is in the correct atom format if necessary */
@@ -637,7 +655,7 @@ static CURLcode imap_perform_list(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
/* Send the LIST command */
- result = imap_sendf(data, conn, "LIST \"%s\" *", mailbox);
+ result = imap_sendf(data, "LIST \"%s\" *", mailbox);
free(mailbox);
}
@@ -678,7 +696,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
/* Send the SELECT command */
- result = imap_sendf(data, conn, "SELECT %s", mailbox);
+ result = imap_sendf(data, "SELECT %s", mailbox);
free(mailbox);
@@ -694,8 +712,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data)
*
* Sends a FETCH command to initiate the download of a message.
*/
-static CURLcode imap_perform_fetch(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode imap_perform_fetch(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
struct IMAP *imap = data->req.p.imap;
@@ -704,21 +721,21 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data,
/* Send the FETCH command */
if(imap->partial)
- result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]<%s>",
+ result = imap_sendf(data, "UID FETCH %s BODY[%s]<%s>",
imap->uid, imap->section ? imap->section : "",
imap->partial);
else
- result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]",
+ result = imap_sendf(data, "UID FETCH %s BODY[%s]",
imap->uid, imap->section ? imap->section : "");
}
else if(imap->mindex) {
/* Send the FETCH command */
if(imap->partial)
- result = imap_sendf(data, conn, "FETCH %s BODY[%s]<%s>",
+ result = imap_sendf(data, "FETCH %s BODY[%s]<%s>",
imap->mindex, imap->section ? imap->section : "",
imap->partial);
else
- result = imap_sendf(data, conn, "FETCH %s BODY[%s]",
+ result = imap_sendf(data, "FETCH %s BODY[%s]",
imap->mindex, imap->section ? imap->section : "");
}
else {
@@ -740,7 +757,6 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data,
static CURLcode imap_perform_append(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap;
char *mailbox;
@@ -791,7 +807,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
/* Send the APPEND command */
- result = imap_sendf(data, conn,
+ result = imap_sendf(data,
"APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
mailbox, data->state.infilesize);
@@ -809,8 +825,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
*
* Sends a SEARCH command.
*/
-static CURLcode imap_perform_search(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode imap_perform_search(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
struct IMAP *imap = data->req.p.imap;
@@ -822,7 +837,7 @@ static CURLcode imap_perform_search(struct Curl_easy *data,
}
/* Send the SEARCH command */
- result = imap_sendf(data, conn, "SEARCH %s", imap->query);
+ result = imap_sendf(data, "SEARCH %s", imap->query);
if(!result)
state(data, IMAP_SEARCH);
@@ -836,11 +851,10 @@ static CURLcode imap_perform_search(struct Curl_easy *data,
*
* Performs the logout action prior to sclose() being called.
*/
-static CURLcode imap_perform_logout(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode imap_perform_logout(struct Curl_easy *data)
{
/* Send the LOGOUT command */
- CURLcode result = imap_sendf(data, conn, "LOGOUT");
+ CURLcode result = imap_sendf(data, "LOGOUT");
if(!result)
state(data, IMAP_LOGOUT);
@@ -938,7 +952,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
/* PREAUTH is not compatible with STARTTLS. */
if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
/* Switch to TLS connection now */
- result = imap_perform_starttls(data, conn);
+ result = imap_perform_starttls(data);
}
else if(data->set.use_ssl <= CURLUSESSL_TRY)
result = imap_perform_authentication(data, conn);
@@ -993,7 +1007,7 @@ static CURLcode imap_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
- result = Curl_sasl_continue(&imapc->sasl, data, conn, imapcode, &progress);
+ result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress);
if(!result)
switch(progress) {
case SASL_DONE:
@@ -1094,9 +1108,9 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
if(imap->custom)
result = imap_perform_list(data);
else if(imap->query)
- result = imap_perform_search(data, conn);
+ result = imap_perform_search(data);
else
- result = imap_perform_fetch(data, conn);
+ result = imap_perform_fetch(data);
}
}
else {
@@ -1441,7 +1455,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done)
/* Set the default preferred authentication type and mechanism */
imapc->preftype = IMAP_TYPE_ANY;
- Curl_sasl_init(&imapc->sasl, &saslimap);
+ Curl_sasl_init(&imapc->sasl, data, &saslimap);
Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
/* Initialise the pingpong layer */
@@ -1568,10 +1582,10 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
result = imap_perform_list(data);
else if(!imap->custom && selected && (imap->uid || imap->mindex))
/* FETCH from the same mailbox */
- result = imap_perform_fetch(data, conn);
+ result = imap_perform_fetch(data);
else if(!imap->custom && selected && imap->query)
/* SEARCH the current mailbox */
- result = imap_perform_search(data, conn);
+ result = imap_perform_search(data);
else if(imap->mailbox && !selected &&
(imap->custom || imap->uid || imap->mindex || imap->query))
/* SELECT the mailbox */
@@ -1643,7 +1657,7 @@ static CURLcode imap_disconnect(struct Curl_easy *data,
/* The IMAP session may or may not have been allocated/setup at this
point! */
if(!dead_connection && conn->bits.protoconnstart) {
- if(!imap_perform_logout(data, conn))
+ if(!imap_perform_logout(data))
(void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
}
@@ -1747,17 +1761,16 @@ static CURLcode imap_setup_connection(struct Curl_easy *data,
*
* Designed to never block.
*/
-static CURLcode imap_sendf(struct Curl_easy *data,
- struct connectdata *conn, const char *fmt, ...)
+static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
{
CURLcode result = CURLE_OK;
- struct imap_conn *imapc = &conn->proto.imapc;
+ struct imap_conn *imapc = &data->conn->proto.imapc;
DEBUGASSERT(fmt);
/* Calculate the tag based on the connection ID and command ID */
msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
- 'A' + curlx_sltosi(conn->connection_id % 26),
+ 'A' + curlx_sltosi(data->conn->connection_id % 26),
(++imapc->cmdid)%1000);
/* start with a blank buffer */
@@ -1911,8 +1924,6 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
struct imap_conn *imapc = &conn->proto.imapc;
const char *ptr = conn->options;
- imapc->sasl.resetprefs = TRUE;
-
while(!result && ptr && *ptr) {
const char *key = ptr;
const char *value;
diff --git a/Utilities/cmcurl/lib/inet_pton.c b/Utilities/cmcurl/lib/inet_pton.c
index 4923cae245..ada57af289 100644
--- a/Utilities/cmcurl/lib/inet_pton.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c
index 659947d9b8..54edb47299 100644
--- a/Utilities/cmcurl/lib/krb5.c
+++ b/Utilities/cmcurl/lib/krb5.c
@@ -374,7 +374,7 @@ static void krb5_end(void *app_data)
}
}
-static struct Curl_sec_client_mech Curl_krb5_client_mech = {
+static const struct Curl_sec_client_mech Curl_krb5_client_mech = {
"GSSAPI",
sizeof(gss_ctx_id_t),
krb5_init,
@@ -684,7 +684,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
(void) data;
if(!conn->mech)
- /* not inititalized, return error */
+ /* not initialized, return error */
return -1;
DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
@@ -768,7 +768,7 @@ static int sec_set_protection_level(struct Curl_easy *data)
}
}
- /* Now try to negiociate the protection level. */
+ /* Now try to negotiate the protection level. */
code = ftp_send_command(data, "PROT %c", level_to_char(level));
if(code < 0)
@@ -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/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index 1d9e44cc9c..3154db5cf0 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/libcurl.rc b/Utilities/cmcurl/lib/libcurl.rc
index 3f7ae16034..fde6c8cae1 100644
--- a/Utilities/cmcurl/lib/libcurl.rc
+++ b/Utilities/cmcurl/lib/libcurl.rc
@@ -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
@@ -51,7 +51,7 @@ BEGIN
VALUE "OriginalFilename", "libcurl.dll\0"
VALUE "ProductName", "The curl library\0"
VALUE "ProductVersion", LIBCURL_VERSION "\0"
- VALUE "LegalCopyright", "\xa9 " LIBCURL_COPYRIGHT "\0" /* a9: Copyright symbol */
+ VALUE "LegalCopyright", "Copyright (C) " LIBCURL_COPYRIGHT "\0"
VALUE "License", "https://curl.se/docs/copyright.html\0"
END
END
diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c
index e0ec7393d2..e78da7da82 100644
--- a/Utilities/cmcurl/lib/llist.c
+++ b/Utilities/cmcurl/lib/llist.c
@@ -106,9 +106,7 @@ Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e,
e->next->prev = NULL;
}
else {
- if(!e->prev)
- list->head = e->next;
- else
+ if(e->prev)
e->prev->next = e->next;
if(!e->next)
diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c
index e7a428fc28..117cce4fd9 100644
--- a/Utilities/cmcurl/lib/md4.c
+++ b/Utilities/cmcurl/lib/md4.c
@@ -27,6 +27,7 @@
#include "curl_md4.h"
#include "warnless.h"
+
#ifdef USE_OPENSSL
#include <openssl/opensslconf.h>
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
@@ -35,6 +36,13 @@
#endif
#endif /* USE_OPENSSL */
+#ifdef USE_WOLFSSL
+#include <wolfssl/options.h>
+#ifdef NO_MD4
+#define OPENSSL_NO_MD4
+#endif
+#endif
+
#ifdef USE_MBEDTLS
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
@@ -74,8 +82,9 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
md4_digest(ctx, MD4_DIGEST_SIZE, result);
}
-#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
-/* When OpenSSL is available we use the MD4-functions from OpenSSL */
+#elif (defined(USE_OPENSSL) || defined(USE_WOLFSSL)) && \
+ !defined(OPENSSL_NO_MD4)
+/* When OpenSSL or wolfSSL is available, we use their MD4 functions. */
#include <openssl/md4.h>
#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
@@ -180,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;
}
@@ -189,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/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c
index 983ed9746e..c6923e036b 100644
--- a/Utilities/cmcurl/lib/md5.c
+++ b/Utilities/cmcurl/lib/md5.c
@@ -39,6 +39,20 @@
#endif
#endif /* USE_MBEDTLS */
+#if defined(USE_OPENSSL) && !defined(USE_AMISSL)
+ #include <openssl/opensslconf.h>
+ #if !defined(OPENSSL_NO_MD5) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+ #define USE_OPENSSL_MD5
+ #endif
+#endif
+
+#ifdef USE_WOLFSSL
+ #include <wolfssl/options.h>
+ #ifndef NO_MD5
+ #define USE_WOLFSSL_MD5
+ #endif
+#endif
+
#if defined(USE_GNUTLS)
#include <nettle/md5.h>
@@ -48,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,
@@ -65,8 +80,9 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
md5_digest(ctx, 16, digest);
}
-#elif defined(USE_OPENSSL) && !defined(USE_AMISSL)
-/* When OpenSSL is available we use the MD5-function from OpenSSL */
+#elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5)
+
+/* When OpenSSL or wolfSSL is available, we use their MD5 functions. */
#include <openssl/md5.h>
#include "curl_memory.h"
/* The last #include file should be: */
@@ -83,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,
@@ -131,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,
@@ -161,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,
@@ -246,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);
@@ -407,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;
@@ -416,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)
@@ -540,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;
@@ -549,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/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c
index 0bf1b46a4c..7783b8990a 100644
--- a/Utilities/cmcurl/lib/mime.c
+++ b/Utilities/cmcurl/lib/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(result = Curl_dyn_add(&db, ""); !result && *src; src++) {
+ for(p = table; *p && **p != *src; p++)
+ ;
- for(i = 0; *src; src++) {
- if(*src == '"' || *src == '\\')
- dst[i++] = '\\';
- dst[i++] = *src;
+ 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. */
@@ -462,11 +486,13 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
/* Buffered data size can only be 0, 1 or 2. */
ptr[2] = ptr[3] = '=';
i = 0;
- switch(st->bufend - st->bufbeg) {
- case 2:
- i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
- /* FALLTHROUGH */
- case 1:
+
+ /* If there is buffered data */
+ if(st->bufend != st->bufbeg) {
+
+ if(st->bufend - st->bufbeg == 2)
+ i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
+
i |= (st->buf[st->bufbeg] & 0xFF) << 16;
ptr[0] = base64[(i >> 18) & 0x3F];
ptr[1] = base64[(i >> 12) & 0x3F];
@@ -476,7 +502,6 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
}
cursize += 4;
st->pos += 4;
- break;
}
}
}
@@ -1865,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;
}
@@ -1954,7 +1979,8 @@ void Curl_mime_unpause(curl_mimepart *part)
}
-#else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
+#else /* !CURL_DISABLE_HTTP && !CURL_DISABLE_MIME ||
+ !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
/* Mime not compiled in: define stubs for externally-referenced functions. */
curl_mime *curl_mime_init(CURL *easy)
diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c
index 7a1aec570e..0fd3afc8ae 100644
--- a/Utilities/cmcurl/lib/mprintf.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 518ceb51f5..f8dcc63b47 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/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
@@ -2028,6 +2076,28 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case MSTATE_DO:
+ if(data->set.fprereq) {
+ int prereq_rc;
+
+ /* call the prerequest callback function */
+ Curl_set_in_callback(data, true);
+ prereq_rc = data->set.fprereq(data->set.prereq_userp,
+ data->info.conn_primary_ip,
+ data->info.conn_local_ip,
+ data->info.conn_primary_port,
+ data->info.conn_local_port);
+ Curl_set_in_callback(data, false);
+ if(prereq_rc != CURL_PREREQFUNC_OK) {
+ failf(data, "operation aborted by pre-request callback");
+ /* failure in pre-request callback - don't do any other processing */
+ result = CURLE_ABORTED_BY_CALLBACK;
+ Curl_posttransfer(data);
+ multi_done(data, result, FALSE);
+ stream_error = TRUE;
+ break;
+ }
+ }
+
if(data->set.connect_only) {
/* keep connection open for application to use the socket */
connkeep(data->conn, "CONNECT_ONLY");
@@ -2595,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;
}
@@ -2611,7 +2681,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
multi->magic = 0; /* not good anymore */
- /* Firsrt remove all remaining easy handles */
+ /* First remove all remaining easy handles */
data = multi->easyp;
while(data) {
nextdata = data->next;
@@ -2640,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);
@@ -2715,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;
@@ -2786,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) |
@@ -2798,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 */
}
@@ -2835,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 {
@@ -2857,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;
}
@@ -2884,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;
}
}
}
@@ -3150,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;
}
@@ -3162,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;
}
@@ -3173,14 +3262,19 @@ 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;
}
static CURLMcode multi_timeout(struct Curl_multi *multi,
long *timeout_ms)
{
- static struct curltime tv_zero = {0, 0};
+ 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 */
@@ -3233,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};
@@ -3248,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
@@ -3259,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/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
index 2e4a6ffba5..db7f130efd 100644
--- a/Utilities/cmcurl/lib/multihandle.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h
index 2fbef53c48..f4d0ada8e8 100644
--- a/Utilities/cmcurl/lib/multiif.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
index fb5e743c27..0ffb6a36a2 100644
--- a/Utilities/cmcurl/lib/openldap.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
index d3f3de6d49..d4ca67877d 100644
--- a/Utilities/cmcurl/lib/pop3.c
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -78,6 +78,7 @@
#include "select.h"
#include "multiif.h"
#include "url.h"
+#include "bufref.h"
#include "curl_sasl.h"
#include "curl_md5.h"
#include "warnless.h"
@@ -103,12 +104,12 @@ static CURLcode pop3_setup_connection(struct Curl_easy *data,
static CURLcode pop3_parse_url_options(struct connectdata *conn);
static CURLcode pop3_parse_url_path(struct Curl_easy *data);
static CURLcode pop3_parse_custom_request(struct Curl_easy *data);
-static CURLcode pop3_perform_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *mech,
- const char *initresp);
-static CURLcode pop3_continue_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *resp);
-static void pop3_get_message(char *buffer, char **outptr);
+static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech,
+ const struct bufref *initresp);
+static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech,
+ const struct bufref *resp);
+static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech);
+static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
/*
* POP3 protocol handler.
@@ -170,13 +171,16 @@ const struct Curl_handler Curl_handler_pop3s = {
/* SASL parameters for the pop3 protocol */
static const struct SASLproto saslpop3 = {
- "pop", /* The service name */
- '*', /* Code received when continuation is expected */
- '+', /* Code to receive upon authentication success */
- 255 - 8, /* Maximum initial response length (no max) */
- pop3_perform_auth, /* Send authentication command */
- pop3_continue_auth, /* Send authentication continuation */
- pop3_get_message /* Get SASL response message */
+ "pop", /* The service name */
+ pop3_perform_auth, /* Send authentication command */
+ pop3_continue_auth, /* Send authentication continuation */
+ pop3_cancel_auth, /* Send authentication cancellation */
+ pop3_get_message, /* Get SASL response message */
+ 255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
+ '*', /* Code received when continuation is expected */
+ '+', /* Code to receive upon authentication success */
+ SASL_AUTH_DEFAULT, /* Default mechanisms */
+ SASL_FLAG_BASE64 /* Configuration flags */
};
#ifdef USE_SSL
@@ -250,34 +254,32 @@ static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
*
* Gets the authentication message from the response buffer.
*/
-static void pop3_get_message(char *buffer, char **outptr)
+static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
{
- size_t len = strlen(buffer);
- char *message = NULL;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 2) {
/* Find the start of the message */
len -= 2;
- for(message = buffer + 2; *message == ' ' || *message == '\t';
- message++, len--)
+ for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
;
/* Find the end of the message */
- for(; len--;)
+ while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t')
break;
/* Terminate the message */
- if(++len) {
- message[len] = '\0';
- }
+ message[++len] = '\0';
+ Curl_bufref_set(out, message, len, NULL);
}
else
/* junk input => zero length output */
- message = &buffer[len];
+ Curl_bufref_set(out, "", 0, NULL);
- *outptr = message;
+ return CURLE_OK;
}
/***********************************************************************
@@ -474,16 +476,16 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
* authentication mechanism.
*/
static CURLcode pop3_perform_auth(struct Curl_easy *data,
- struct connectdata *conn,
const char *mech,
- const char *initresp)
+ const struct bufref *initresp)
{
CURLcode result = CURLE_OK;
- struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+ const char *ir = (const char *) Curl_bufref_ptr(initresp);
- if(initresp) { /* AUTH <mech> ...<crlf> */
+ if(ir) { /* AUTH <mech> ...<crlf> */
/* Send the AUTH command with the initial response */
- result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, initresp);
+ result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, ir);
}
else {
/* Send the AUTH command */
@@ -497,15 +499,33 @@ static CURLcode pop3_perform_auth(struct Curl_easy *data,
*
* pop3_continue_auth()
*
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
*/
static CURLcode pop3_continue_auth(struct Curl_easy *data,
- struct connectdata *conn,
- const char *resp)
+ const char *mech,
+ const struct bufref *resp)
{
- struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+
+ (void)mech;
- return Curl_pp_sendf(data, &pop3c->pp, "%s", resp);
+ return Curl_pp_sendf(data, &pop3c->pp,
+ "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * pop3_cancel_auth()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech)
+{
+ struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+
+ (void)mech;
+
+ return Curl_pp_sendf(data, &pop3c->pp, "*");
}
/***********************************************************************
@@ -532,7 +552,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
/* Calculate the SASL login details */
- result = Curl_sasl_start(&pop3c->sasl, data, conn, FALSE, &progress);
+ result = Curl_sasl_start(&pop3c->sasl, data, FALSE, &progress);
if(!result)
if(progress == SASL_INPROGRESS)
@@ -801,7 +821,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
- result = Curl_sasl_continue(&pop3c->sasl, data, conn, pop3code, &progress);
+ result = Curl_sasl_continue(&pop3c->sasl, data, pop3code, &progress);
if(!result)
switch(progress) {
case SASL_DONE:
@@ -1011,7 +1031,9 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
break;
case POP3_QUIT:
- /* fallthrough, just stop! */
+ state(data, POP3_STOP);
+ break;
+
default:
/* internal error */
state(data, POP3_STOP);
@@ -1102,7 +1124,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
/* Set the default preferred authentication type and mechanism */
pop3c->preftype = POP3_TYPE_ANY;
- Curl_sasl_init(&pop3c->sasl, &saslpop3);
+ Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
/* Initialise the pingpong layer */
Curl_pp_setup(pp);
@@ -1343,8 +1365,6 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)
struct pop3_conn *pop3c = &conn->proto.pop3c;
const char *ptr = conn->options;
- pop3c->sasl.resetprefs = TRUE;
-
while(!result && ptr && *ptr) {
const char *key = ptr;
const char *value;
diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c
index 84d0b8ff3d..5f31870812 100644
--- a/Utilities/cmcurl/lib/select.c
+++ b/Utilities/cmcurl/lib/select.c
@@ -64,7 +64,7 @@
* Waiting indefinitely with this function is not allowed, a
* zero or negative timeout value will return immediately.
* Timeout resolution, accuracy, as well as maximum supported
- * value is system dependent, neither factor is a citical issue
+ * value is system dependent, neither factor is a critical issue
* for the intended use of this function in the library.
*
* Return values:
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
index 14ca84bfe5..bcfa27a501 100644
--- a/Utilities/cmcurl/lib/sendf.c
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -608,7 +608,7 @@ static CURLcode chop_write(struct Curl_easy *data,
/* Curl_client_write() sends data to the write callback(s)
The bit pattern defines to what "streams" to write to. Body and/or header.
- The defines are in sendf.h of course. "len" is not allowed to be 0.
+ The defines are in sendf.h of course.
If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
local character encoding. This is a problem and should be changed in
@@ -621,8 +621,10 @@ CURLcode Curl_client_write(struct Curl_easy *data,
{
struct connectdata *conn = data->conn;
- DEBUGASSERT(len);
- DEBUGASSERT(type <= 3);
+ DEBUGASSERT(!(type & ~CLIENTWRITE_BOTH));
+
+ if(!len)
+ return CURLE_OK;
/* FTP data may need conversion. */
if((type & CLIENTWRITE_BODY) &&
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index 08827d1ef9..599ed5d994 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/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
@@ -2477,6 +2483,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
va_arg(param, char *));
break;
+ case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
+ /*
+ * Option to allow for the SHA256 of the host public key to be checked
+ * for validation purposes.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256],
+ va_arg(param, char *));
+ break;
+
case CURLOPT_SSH_KNOWNHOSTS:
/*
* Store the file name to read known hosts from.
@@ -2507,8 +2522,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* disable libcurl transfer encoding is used
*/
+#ifndef USE_HYPER
data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
break;
+#else
+ return CURLE_NOT_BUILT_IN; /* hyper doesn't support */
+#endif
case CURLOPT_HTTP_CONTENT_DECODING:
/*
@@ -2596,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],
@@ -2929,6 +2955,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.maxage_conn = arg;
break;
+ case CURLOPT_MAXLIFETIME_CONN:
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.maxlifetime_conn = arg;
+ break;
case CURLOPT_TRAILERFUNCTION:
#ifndef CURL_DISABLE_HTTP
data->set.trailer_callback = va_arg(param, curl_trailer_callback);
@@ -3004,6 +3036,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return result;
break;
#endif
+ case CURLOPT_PREREQFUNCTION:
+ data->set.fprereq = va_arg(param, curl_prereq_callback);
+ break;
+ case CURLOPT_PREREQDATA:
+ data->set.prereq_userp = va_arg(param, void *);
+ break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
diff --git a/Utilities/cmcurl/lib/setup-win32.h b/Utilities/cmcurl/lib/setup-win32.h
index c35dec88cb..fa8742f3b1 100644
--- a/Utilities/cmcurl/lib/setup-win32.h
+++ b/Utilities/cmcurl/lib/setup-win32.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
@@ -25,11 +25,11 @@
/*
* Include header files for windows builds before redefining anything.
* Use this preprocessor block only to include or exclude windows.h,
- * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
+ * winsock2.h or ws2tcpip.h. Any other windows thing belongs
* to any other further and independent block. Under Cygwin things work
* just as under linux (e.g. <sys/socket.h>) and the winsock headers should
* never be included when __CYGWIN__ is defined. configure script takes
- * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H,
+ * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK2_H,
* neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
*/
@@ -47,10 +47,6 @@
# ifdef HAVE_WS2TCPIP_H
# include <ws2tcpip.h>
# endif
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
# include <tchar.h>
# ifdef UNICODE
@@ -67,10 +63,6 @@
#ifdef HAVE_WINSOCK2_H
# define USE_WINSOCK 2
-#else
-# ifdef HAVE_WINSOCK_H
-# error "WinSock version 1 is no longer supported, version 2 is required!"
-# endif
#endif
/*
diff --git a/Utilities/cmcurl/lib/sha256.c b/Utilities/cmcurl/lib/sha256.c
index a2e7e41316..cf7ea4f543 100644
--- a/Utilities/cmcurl/lib/sha256.c
+++ b/Utilities/cmcurl/lib/sha256.c
@@ -29,11 +29,18 @@
#include "curl_sha256.h"
#include "curl_hmac.h"
+#ifdef USE_WOLFSSL
+#include <wolfssl/options.h>
+#ifndef NO_SHA256
+#define USE_OPENSSL_SHA256
+#endif
+#endif
+
#if defined(USE_OPENSSL)
#include <openssl/opensslv.h>
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
+#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL)
#define USE_OPENSSL_SHA256
#endif
@@ -63,7 +70,40 @@
#if defined(USE_OPENSSL_SHA256)
/* When OpenSSL is available we use the SHA256-function from OpenSSL */
-#include <openssl/sha.h>
+#include <openssl/evp.h>
+
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct sha256_ctx {
+ EVP_MD_CTX *openssl_ctx;
+};
+typedef struct sha256_ctx my_sha256_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,
+ const unsigned char *data,
+ unsigned int length)
+{
+ EVP_DigestUpdate(ctx->openssl_ctx, data, length);
+}
+
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+{
+ EVP_DigestFinal_ex(ctx->openssl_ctx, digest, NULL);
+ EVP_MD_CTX_destroy(ctx->openssl_ctx);
+}
#elif defined(USE_GNUTLS)
@@ -74,21 +114,22 @@
/* The last #include file should be: */
#include "memdebug.h"
-typedef struct sha256_ctx SHA256_CTX;
+typedef struct sha256_ctx my_sha256_ctx;
-static void SHA256_Init(SHA256_CTX *ctx)
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
{
sha256_init(ctx);
+ return CURLE_OK;
}
-static void SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
{
sha256_update(ctx, length, data);
}
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
{
sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
}
@@ -102,20 +143,21 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
/* The last #include file should be: */
#include "memdebug.h"
-typedef mbedtls_sha256_context SHA256_CTX;
+typedef mbedtls_sha256_context my_sha256_ctx;
-static void SHA256_Init(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 SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
{
#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
(void) mbedtls_sha256_update(ctx, data, length);
@@ -124,7 +166,7 @@ static void SHA256_Update(SHA256_CTX *ctx,
#endif
}
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
{
#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
(void) mbedtls_sha256_finish(ctx, digest);
@@ -145,21 +187,22 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
/* The last #include file should be: */
#include "memdebug.h"
-typedef CC_SHA256_CTX SHA256_CTX;
+typedef CC_SHA256_CTX my_sha256_ctx;
-static void SHA256_Init(SHA256_CTX *ctx)
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
{
(void) CC_SHA256_Init(ctx);
+ return CURLE_OK;
}
-static void SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
{
(void) CC_SHA256_Update(ctx, data, length);
}
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
{
(void) CC_SHA256_Final(digest, ctx);
}
@@ -172,28 +215,30 @@ struct sha256_ctx {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
};
-typedef struct sha256_ctx SHA256_CTX;
+typedef struct sha256_ctx my_sha256_ctx;
#if !defined(CALG_SHA_256)
#define CALG_SHA_256 0x0000800c
#endif
-static void SHA256_Init(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 SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
{
CryptHashData(ctx->hHash, (unsigned char *) data, length, 0);
}
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
{
unsigned long length = 0;
@@ -262,7 +307,7 @@ struct sha256_state {
unsigned long state[8], curlen;
unsigned char buf[64];
};
-typedef struct sha256_state SHA256_CTX;
+typedef struct sha256_state my_sha256_ctx;
/* The K array */
static const unsigned long K[64] = {
@@ -339,7 +384,7 @@ static int sha256_compress(struct sha256_state *md,
}
/* Initialize the hash state */
-static void SHA256_Init(struct sha256_state *md)
+static CURLcode my_sha256_init(struct sha256_state *md)
{
md->curlen = 0;
md->length = 0;
@@ -351,6 +396,8 @@ static void SHA256_Init(struct sha256_state *md)
md->state[5] = 0x9B05688CUL;
md->state[6] = 0x1F83D9ABUL;
md->state[7] = 0x5BE0CD19UL;
+
+ return CURLE_OK;
}
/*
@@ -358,11 +405,11 @@ static void 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 SHA256_Update(struct sha256_state *md,
- const unsigned char *in,
- unsigned long inlen)
+static int my_sha256_update(struct sha256_state *md,
+ const unsigned char *in,
+ unsigned long inlen)
{
unsigned long n;
@@ -399,10 +446,10 @@ static int 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 SHA256_Final(unsigned char *out,
- struct sha256_state *md)
+static int my_sha256_final(unsigned char *out,
+ struct sha256_state *md)
{
int i;
@@ -455,28 +502,34 @@ static int 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)
{
- SHA256_CTX ctx;
+ CURLcode result;
+ my_sha256_ctx ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, input, curlx_uztoui(length));
- 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;
}
const struct HMAC_params Curl_HMAC_SHA256[] = {
{
/* Hash initialization function. */
- CURLX_FUNCTION_CAST(HMAC_hinit_func, SHA256_Init),
+ CURLX_FUNCTION_CAST(HMAC_hinit_func, my_sha256_init),
/* Hash update function. */
- CURLX_FUNCTION_CAST(HMAC_hupdate_func, SHA256_Update),
+ CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_sha256_update),
/* Hash computation end function. */
- CURLX_FUNCTION_CAST(HMAC_hfinal_func, SHA256_Final),
+ CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_sha256_final),
/* Size of hash context structure. */
- sizeof(SHA256_CTX),
+ sizeof(my_sha256_ctx),
/* Maximum key length. */
64,
/* Result size. */
diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c
index 9c43c8f705..403563fdd6 100644
--- a/Utilities/cmcurl/lib/share.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index 02ddaca0a2..6c08293783 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -82,6 +82,7 @@
#include "multiif.h"
#include "url.h"
#include "curl_gethostname.h"
+#include "bufref.h"
#include "curl_sasl.h"
#include "warnless.h"
/* The last 3 #include files should be in this order */
@@ -108,12 +109,12 @@ static CURLcode smtp_parse_url_path(struct Curl_easy *data);
static CURLcode smtp_parse_custom_request(struct Curl_easy *data);
static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
char **address, struct hostname *host);
-static CURLcode smtp_perform_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *mech,
- const char *initresp);
-static CURLcode smtp_continue_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *resp);
-static void smtp_get_message(char *buffer, char **outptr);
+static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech,
+ const struct bufref *initresp);
+static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech,
+ const struct bufref *resp);
+static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech);
+static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out);
/*
* SMTP protocol handler.
@@ -175,13 +176,16 @@ const struct Curl_handler Curl_handler_smtps = {
/* SASL parameters for the smtp protocol */
static const struct SASLproto saslsmtp = {
- "smtp", /* The service name */
- 334, /* Code received when continuation is expected */
- 235, /* Code to receive upon authentication success */
- 512 - 8, /* Maximum initial response length (no max) */
- smtp_perform_auth, /* Send authentication command */
- smtp_continue_auth, /* Send authentication continuation */
- smtp_get_message /* Get SASL response message */
+ "smtp", /* The service name */
+ smtp_perform_auth, /* Send authentication command */
+ smtp_continue_auth, /* Send authentication continuation */
+ smtp_cancel_auth, /* Cancel authentication */
+ smtp_get_message, /* Get SASL response message */
+ 512 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
+ 334, /* Code received when continuation is expected */
+ 235, /* Code to receive upon authentication success */
+ SASL_AUTH_DEFAULT, /* Default mechanisms */
+ SASL_FLAG_BASE64 /* Configuration flags */
};
#ifdef USE_SSL
@@ -218,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];
@@ -248,34 +252,32 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
*
* Gets the authentication message from the response buffer.
*/
-static void smtp_get_message(char *buffer, char **outptr)
+static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
{
- size_t len = strlen(buffer);
- char *message = NULL;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 4) {
/* Find the start of the message */
len -= 4;
- for(message = buffer + 4; *message == ' ' || *message == '\t';
- message++, len--)
+ for(message += 4; *message == ' ' || *message == '\t'; message++, len--)
;
/* Find the end of the message */
- for(; len--;)
+ while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t')
break;
/* Terminate the message */
- if(++len) {
- message[len] = '\0';
- }
+ message[++len] = '\0';
+ Curl_bufref_set(out, message, len, NULL);
}
else
/* junk input => zero length output */
- message = &buffer[len];
+ Curl_bufref_set(out, "", 0, NULL);
- *outptr = message;
+ return CURLE_OK;
}
/***********************************************************************
@@ -421,16 +423,16 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
* authentication mechanism.
*/
static CURLcode smtp_perform_auth(struct Curl_easy *data,
- struct connectdata *conn,
const char *mech,
- const char *initresp)
+ const struct bufref *initresp)
{
CURLcode result = CURLE_OK;
- struct smtp_conn *smtpc = &conn->proto.smtpc;
+ struct smtp_conn *smtpc = &data->conn->proto.smtpc;
+ const char *ir = (const char *) Curl_bufref_ptr(initresp);
- if(initresp) { /* AUTH <mech> ...<crlf> */
+ if(ir) { /* AUTH <mech> ...<crlf> */
/* Send the AUTH command with the initial response */
- result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, initresp);
+ result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, ir);
}
else {
/* Send the AUTH command */
@@ -444,14 +446,33 @@ static CURLcode smtp_perform_auth(struct Curl_easy *data,
*
* smtp_continue_auth()
*
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
*/
static CURLcode smtp_continue_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *resp)
+ const char *mech,
+ const struct bufref *resp)
{
- struct smtp_conn *smtpc = &conn->proto.smtpc;
+ struct smtp_conn *smtpc = &data->conn->proto.smtpc;
+
+ (void)mech;
+
+ return Curl_pp_sendf(data, &smtpc->pp,
+ "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * smtp_cancel_auth()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech)
+{
+ struct smtp_conn *smtpc = &data->conn->proto.smtpc;
- return Curl_pp_sendf(data, &smtpc->pp, "%s", resp);
+ (void)mech;
+
+ return Curl_pp_sendf(data, &smtpc->pp, "*");
}
/***********************************************************************
@@ -469,7 +490,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
saslprogress progress;
/* Check we have enough data to authenticate with, and the
- server supports authentiation, and end the connect phase if not */
+ server supports authentication, and end the connect phase if not */
if(!smtpc->auth_supported ||
!Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
state(data, SMTP_STOP);
@@ -477,7 +498,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
}
/* Calculate the SASL login details */
- result = Curl_sasl_start(&smtpc->sasl, data, conn, FALSE, &progress);
+ result = Curl_sasl_start(&smtpc->sasl, data, FALSE, &progress);
if(!result) {
if(progress == SASL_INPROGRESS)
@@ -506,7 +527,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
if(smtp->rcpt) {
/* We notify the server we are sending UTF-8 data if a) it supports the
- SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
+ SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
either the local address or host name parts. This is regardless of
whether the host name is encoded using IDN ACE */
bool utf8 = FALSE;
@@ -579,7 +600,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
struct connectdata *conn = data->conn;
/* We notify the server we are sending UTF-8 data if a) it supports the
- SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
+ SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
either the local address or host name parts. This is regardless of
whether the host name is encoded using IDN ACE */
bool utf8 = FALSE;
@@ -985,7 +1006,7 @@ static CURLcode smtp_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
- result = Curl_sasl_continue(&smtpc->sasl, data, conn, smtpcode, &progress);
+ result = Curl_sasl_continue(&smtpc->sasl, data, smtpcode, &progress);
if(!result)
switch(progress) {
case SASL_DONE:
@@ -1333,7 +1354,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp);
/* Initialize the SASL storage */
- Curl_sasl_init(&smtpc->sasl, &saslsmtp);
+ Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
/* Initialise the pingpong layer */
Curl_pp_setup(pp);
@@ -1655,8 +1676,6 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn)
struct smtp_conn *smtpc = &conn->proto.smtpc;
const char *ptr = conn->options;
- smtpc->sasl.resetprefs = TRUE;
-
while(!result && ptr && *ptr) {
const char *key = ptr;
const char *value;
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
index db4c80834e..a014aa6684 100644
--- a/Utilities/cmcurl/lib/socks.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c
index 34bfa37d7f..8ef2f8f374 100644
--- a/Utilities/cmcurl/lib/socks_gssapi.c
+++ b/Utilities/cmcurl/lib/socks_gssapi.c
@@ -257,7 +257,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- if(socksreq[1] != 1) { /* status / messgae type */
+ if(socksreq[1] != 1) { /* status / message type */
failf(data, "Invalid GSS-API authentication response type (%d %d).",
socksreq[0], socksreq[1]);
gss_release_name(&gss_status, &server);
@@ -452,7 +452,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- if(socksreq[1] != 2) { /* status / messgae type */
+ if(socksreq[1] != 2) { /* status / message type */
failf(data, "Invalid GSS-API encryption response type (%d %d).",
socksreq[0], socksreq[1]);
gss_delete_sec_context(&gss_status, &gss_context, NULL);
diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c
index cb225b9b5a..ffc8703468 100644
--- a/Utilities/cmcurl/lib/socks_sspi.c
+++ b/Utilities/cmcurl/lib/socks_sspi.c
@@ -277,7 +277,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- if(socksreq[1] != 1) { /* status / messgae type */
+ if(socksreq[1] != 1) { /* status / message type */
failf(data, "Invalid SSPI authentication response type (%u %u).",
(unsigned int)socksreq[0], (unsigned int)socksreq[1]);
free(service_name);
diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c
index a94e2c85e9..bcc0795212 100644
--- a/Utilities/cmcurl/lib/splay.c
+++ b/Utilities/cmcurl/lib/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
@@ -154,7 +154,7 @@ struct Curl_tree *Curl_splaygetbest(struct curltime i,
struct Curl_tree *t,
struct Curl_tree **removed)
{
- static struct curltime tv_zero = {0, 0};
+ static const struct curltime tv_zero = {0, 0};
struct Curl_tree *x;
if(!t) {
diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c
index 8a27197651..07d73a74b7 100644
--- a/Utilities/cmcurl/lib/strerror.c
+++ b/Utilities/cmcurl/lib/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;
}
@@ -453,6 +456,114 @@ curl_share_strerror(CURLSHcode error)
#endif
}
+const char *
+curl_url_strerror(CURLUcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch(error) {
+ case CURLUE_OK:
+ return "No error";
+
+ case CURLUE_BAD_HANDLE:
+ return "An invalid CURLU pointer was passed as argument";
+
+ case CURLUE_BAD_PARTPOINTER:
+ return "An invalid 'part' argument was passed as argument";
+
+ case CURLUE_MALFORMED_INPUT:
+ return "Malformed input to a URL function";
+
+ case CURLUE_BAD_PORT_NUMBER:
+ 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";
+
+ case CURLUE_URLDECODE:
+ return "URL decode error, most likely because of rubbish in the input";
+
+ case CURLUE_OUT_OF_MEMORY:
+ return "A memory function failed";
+
+ case CURLUE_USER_NOT_ALLOWED:
+ return "Credentials was passed in the URL when prohibited";
+
+ case CURLUE_UNKNOWN_PART:
+ return "An unknown part ID was passed to a URL API function";
+
+ case CURLUE_NO_SCHEME:
+ return "No scheme part in the URL";
+
+ case CURLUE_NO_USER:
+ return "No user part in the URL";
+
+ case CURLUE_NO_PASSWORD:
+ return "No password part in the URL";
+
+ case CURLUE_NO_OPTIONS:
+ return "No options part in the URL";
+
+ case CURLUE_NO_HOST:
+ return "No host part in the URL";
+
+ case CURLUE_NO_PORT:
+ return "No port part in the URL";
+
+ case CURLUE_NO_QUERY:
+ return "No query part in the URL";
+
+ case CURLUE_NO_FRAGMENT:
+ 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;
+ }
+
+ return "CURLUcode unknown";
+#else
+ if(error == CURLUE_OK)
+ return "No error";
+ else
+ return "Error";
+#endif
+}
+
#ifdef USE_WINSOCK
/* This is a helper function for Curl_strerror that converts Winsock error
* codes (WSAGetLastError) to error messages.
diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c
index 2939fd0d74..9a6dd9cef6 100644
--- a/Utilities/cmcurl/lib/system_win32.c
+++ b/Utilities/cmcurl/lib/system_win32.c
@@ -102,7 +102,9 @@ CURLcode Curl_win32_init(long flags)
Curl_if_nametoindex = pIfNameToIndex;
}
- if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT,
+ /* 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, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
Curl_isVistaOrGreater = TRUE;
}
diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c
index aae997d0f1..f8c68441ca 100644
--- a/Utilities/cmcurl/lib/tftp.c
+++ b/Utilities/cmcurl/lib/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 */
};
/**********************************************************
@@ -1304,9 +1304,9 @@ static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
/**********************************************************
*
- * tftp_peform
+ * tftp_perform
*
- * Entry point for transfer from tftp_do, sarts state mach
+ * Entry point for transfer from tftp_do, starts state mach
*
**********************************************************/
static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index 05fec7998c..22704fa158 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index 37b6c0e844..9f1013554f 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/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
@@ -622,6 +631,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
set->maxage_conn = 118;
+ set->maxlifetime_conn = 0;
set->http09_allowed = FALSE;
set->httpwant =
#ifdef USE_NGHTTP2
@@ -844,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;
}
@@ -962,21 +972,36 @@ socks_proxy_info_matches(const struct proxy_info *data,
#define socks_proxy_info_matches(x,y) FALSE
#endif
-/* A connection has to have been idle for a shorter time than 'maxage_conn' to
- be subject for reuse. The success rate is just too low after this. */
+/* A connection has to have been idle for a shorter time than 'maxage_conn'
+ (the success rate is just too low after this), or created less than
+ 'maxlifetime_conn' ago, to be subject for reuse. */
static bool conn_maxage(struct Curl_easy *data,
struct connectdata *conn,
struct curltime now)
{
- timediff_t idletime = Curl_timediff(now, conn->lastused);
+ timediff_t idletime, lifetime;
+
+ idletime = Curl_timediff(now, conn->lastused);
idletime /= 1000; /* integer seconds is fine */
if(idletime > data->set.maxage_conn) {
- infof(data, "Too old connection (%ld seconds), disconnect it",
+ infof(data, "Too old connection (%ld seconds idle), disconnect it",
idletime);
return TRUE;
}
+
+ lifetime = Curl_timediff(now, conn->created);
+ lifetime /= 1000; /* integer seconds is fine */
+
+ if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) {
+ infof(data,
+ "Too old connection (%ld seconds since creation), disconnect it",
+ lifetime);
+ return TRUE;
+ }
+
+
return FALSE;
}
@@ -1284,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
@@ -1667,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;
@@ -1934,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)
@@ -1954,7 +1978,8 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
CURLU_DISALLOW_USER : 0) |
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
if(uc) {
- DEBUGF(infof(data, "curl_url_set rejected %s", data->state.url));
+ DEBUGF(infof(data, "curl_url_set rejected %s: %s", data->state.url,
+ curl_url_strerror(uc)));
return Curl_uc_to_curlcode(uc);
}
@@ -2380,6 +2405,11 @@ static CURLcode parse_proxy(struct Curl_easy *data,
CURLcode result = CURLE_OK;
char *scheme = NULL;
+ if(!uhp) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+
/* When parsing the proxy, allowing non-supported schemes since we have
these made up ones for proxies. Guess scheme for URLs without it. */
uc = curl_url_set(uhp, CURLUPART_URL, proxy,
@@ -2571,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;
@@ -2581,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;
@@ -2763,7 +2793,7 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
size_t plen;
size_t olen;
- /* the input length check is because this is called directcly from setopt
+ /* the input length check is because this is called directly from setopt
and isn't going through the regular string length check */
size_t llen = strlen(login);
if(llen > CURL_MAX_INPUT_LENGTH)
@@ -4093,7 +4123,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
/* init the single-transfer specific data */
Curl_free_request_state(data);
memset(&data->req, 0, sizeof(struct SingleRequest));
- data->req.maxdownload = -1;
+ data->req.size = data->req.maxdownload = -1;
/* call the stuff that needs to be called */
result = create_conn(data, &conn, asyncp);
diff --git a/Utilities/cmcurl/lib/urlapi-int.h b/Utilities/cmcurl/lib/urlapi-int.h
index 4257233094..bd6b601751 100644
--- a/Utilities/cmcurl/lib/urlapi-int.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index 7f03862cfa..d29aeb238f 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/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;
@@ -157,23 +161,23 @@ static size_t strlen_url(const char *url, bool relative)
continue;
}
- switch(*ptr) {
- case '?':
- left = FALSE;
- /* FALLTHROUGH */
- default:
- if(urlchar_needs_escaping(*ptr))
- newlen += 2;
- newlen++;
- break;
- case ' ':
+ if(*ptr == ' ') {
if(left)
newlen += 3;
else
newlen++;
- break;
+ continue;
}
+
+ if (*ptr == '?')
+ left = FALSE;
+
+ if(urlchar_needs_escaping(*ptr))
+ newlen += 2;
+
+ newlen++;
}
+
return newlen;
}
@@ -202,19 +206,7 @@ static void strcpy_url(char *output, const char *url, bool relative)
continue;
}
- switch(*iptr) {
- case '?':
- left = FALSE;
- /* FALLTHROUGH */
- default:
- if(urlchar_needs_escaping(*iptr)) {
- msnprintf(optr, 4, "%%%02x", *iptr);
- optr += 3;
- }
- else
- *optr++=*iptr;
- break;
- case ' ':
+ if(*iptr == ' ') {
if(left) {
*optr++='%'; /* add a '%' */
*optr++='2'; /* add a '2' */
@@ -222,41 +214,58 @@ static void strcpy_url(char *output, const char *url, bool relative)
}
else
*optr++='+'; /* add a '+' here */
- break;
+ continue;
}
+
+ if(*iptr == '?')
+ left = FALSE;
+
+ if(urlchar_needs_escaping(*iptr)) {
+ msnprintf(optr, 4, "%%%02x", *iptr);
+ optr += 3;
+ }
+ else
+ *optr++ = *iptr;
}
*optr = 0; /* null-terminate output buffer */
}
/*
- * 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;
}
@@ -420,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()
*
@@ -467,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;
}
@@ -477,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:
@@ -493,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;
}
@@ -516,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;
@@ -558,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])
@@ -579,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);
@@ -635,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);
@@ -644,22 +665,34 @@ 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 {
/* letters from the second string is not ok */
- len = strcspn(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;
@@ -756,10 +789,35 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
return TRUE;
}
+/* return strdup'ed version in 'outp', possibly percent decoded */
+static CURLUcode decode_host(char *hostname, char **outp)
+{
+ char *per = NULL;
+ if(hostname[0] != '[')
+ /* only decode if not an ipv6 numerical */
+ per = strchr(hostname, '%');
+ if(!per) {
+ *outp = strdup(hostname);
+ if(!*outp)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ else {
+ /* might be encoded */
+ size_t dlen;
+ CURLcode result = Curl_urldecode(NULL, hostname, 0,
+ outp, &dlen, REJECT_CTRL);
+ if(result)
+ return CURLUE_BAD_HOSTNAME;
+ }
+
+ return CURLUE_OK;
+}
+
static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
{
char *path;
bool path_alloced = FALSE;
+ bool uncpath = FALSE;
char *hostname;
char *query = NULL;
char *fragment = NULL;
@@ -794,11 +852,14 @@ 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]);
- hostname = NULL; /* no host for file: URLs */
u->scheme = strdup("file");
if(!u->scheme)
return CURLUE_OUT_OF_MEMORY;
@@ -820,10 +881,13 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
*
* o the hostname matches "localhost" (case-insensitively), or
*
- * o the hostname is a FQDN that resolves to this machine.
+ * o the hostname is a FQDN that resolves to this machine, or
+ *
+ * o it is an UNC String transformed to an URI (Windows only, RFC 8089
+ * Appendix E.3).
*
* For brevity, we only consider URLs with empty, "localhost", or
- * "127.0.0.1" hostnames as local.
+ * "127.0.0.1" hostnames as local, otherwise as an UNC String.
*
* Additionally, there is an exception for URLs with a Windows drive
* letter in the authority (which was accidentally omitted from RFC 8089
@@ -832,25 +896,50 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
/* the URL includes a host name, it must match "localhost" or
"127.0.0.1" to be valid */
- if(!checkprefix("localhost/", ptr) &&
- !checkprefix("127.0.0.1/", ptr)) {
+ if(checkprefix("localhost/", ptr) ||
+ checkprefix("127.0.0.1/", ptr)) {
+ ptr += 9; /* now points to the slash after the host */
+ }
+ else {
+#if defined(WIN32)
+ size_t len;
+
+ /* the host name, NetBIOS computer name, can not contain disallowed
+ chars, and the delimiting slash character must be appended to the
+ host name */
+ path = strpbrk(ptr, "/\\:*?\"<>|");
+ if(!path || *path != '/')
+ return CURLUE_BAD_FILE_URL;
+
+ len = path - ptr;
+ if(len) {
+ memcpy(hostname, ptr, len);
+ hostname[len] = 0;
+ uncpath = TRUE;
+ }
+
+ ptr -= 2; /* now points to the // before the host in UNC */
+#else
/* Invalid file://hostname/, expected localhost or 127.0.0.1 or
none */
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_FILE_URL;
+#endif
}
- ptr += 9; /* now points to the slash after the host */
}
path = ptr;
}
+ if(!uncpath)
+ hostname = NULL; /* no host for file: URLs by default */
+
#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
/* Don't allow Windows drive letters when not in Windows.
* This catches both "file:/c:" and "file:c:" */
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 */
@@ -877,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) &&
@@ -885,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;
@@ -902,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;
@@ -912,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);
@@ -926,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);
@@ -942,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)
@@ -952,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;
@@ -987,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;
@@ -1001,22 +1093,27 @@ 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("");
}
else {
- result = hostname_check(u, hostname);
- if(result)
- return result;
+ if(ipv4_normalize(hostname, normalized_ipv4, sizeof(normalized_ipv4)))
+ u->host = strdup(normalized_ipv4);
+ else {
+ result = decode_host(hostname, &u->host);
+ if(result)
+ return result;
+ result = hostname_check(u, u->host);
+ if(result)
+ return result;
+ }
}
-
- if(ipv4_normalize(hostname, normalized_ipv4, sizeof(normalized_ipv4)))
- u->host = strdup(normalized_ipv4);
- else
- u->host = strdup(hostname);
if(!u->host)
return CURLUE_OUT_OF_MEMORY;
-
if((flags & CURLU_GUESS_SCHEME) && !schemep) {
/* legacy curl-style guess based on host name */
if(checkprefix("ftp.", hostname))
@@ -1111,6 +1208,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
char portbuf[7];
bool urldecode = (flags & CURLU_URLDECODE)?1:0;
+ bool urlencode = (flags & CURLU_URLENCODE)?1:0;
bool plusdecode = FALSE;
(void)flags;
if(!u)
@@ -1143,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;
@@ -1228,16 +1327,54 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
if(h && !(h->flags & PROTOPT_URLOPTIONS))
options = NULL;
- if((u->host[0] == '[') && u->zoneid) {
- /* make it '[ host %25 zoneid ]' */
- size_t hostlen = strlen(u->host);
- size_t alen = hostlen + 3 + strlen(u->zoneid) + 1;
- allochost = malloc(alen);
+ if(u->host[0] == '[') {
+ if(u->zoneid) {
+ /* make it '[ host %25 zoneid ]' */
+ size_t hostlen = strlen(u->host);
+ size_t alen = hostlen + 3 + strlen(u->zoneid) + 1;
+ allochost = malloc(alen);
+ if(!allochost)
+ return CURLUE_OUT_OF_MEMORY;
+ memcpy(allochost, u->host, hostlen - 1);
+ msnprintf(&allochost[hostlen - 1], alen - hostlen + 1,
+ "%%25%s]", u->zoneid);
+ }
+ }
+ else if(urlencode) {
+ allochost = curl_easy_escape(NULL, u->host, 0);
if(!allochost)
return CURLUE_OUT_OF_MEMORY;
- memcpy(allochost, u->host, hostlen - 1);
- msnprintf(&allochost[hostlen - 1], alen - hostlen + 1,
- "%%25%s]", u->zoneid);
+ }
+ else {
+ /* only encode '%' in output host name */
+ char *host = u->host;
+ size_t pcount = 0;
+ /* first, count number of percents present in the name */
+ while(*host) {
+ if(*host == '%')
+ pcount++;
+ host++;
+ }
+ /* if there were percents, encode the host name */
+ if(pcount) {
+ size_t hostlen = strlen(u->host);
+ size_t alen = hostlen + 2 * pcount + 1;
+ char *o = allochost = malloc(alen);
+ if(!allochost)
+ return CURLUE_OUT_OF_MEMORY;
+
+ host = u->host;
+ while(*host) {
+ if(*host == '%') {
+ memcpy(o, "%25", 3);
+ o += 3;
+ host++;
+ continue;
+ }
+ *o++ = *host++;
+ }
+ *o = '\0';
+ }
}
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
@@ -1362,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))
@@ -1379,10 +1516,15 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
case CURLUPART_OPTIONS:
storep = &u->options;
break;
- case CURLUPART_HOST:
+ case CURLUPART_HOST: {
+ size_t len = strcspn(part, " \r\n");
+ if(strlen(part) != len)
+ /* hostname with bad content */
+ return CURLUE_BAD_HOSTNAME;
storep = &u->host;
Curl_safefree(u->zoneid);
break;
+ }
case CURLUPART_ZONEID:
storep = &u->zoneid;
break;
@@ -1395,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;
@@ -1424,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;
@@ -1559,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/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index 6ffd97621f..cc9c888709 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -330,7 +330,7 @@ struct digestdata {
char *opaque;
char *qop;
char *algorithm;
- int nc; /* nounce count */
+ int nc; /* nonce count */
BIT(stale); /* set true for re-negotiation */
BIT(userhash);
#endif
@@ -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. */
@@ -1554,6 +1557,7 @@ enum dupstring {
STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
+ STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */
STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */
STRING_PROXY_SERVICE_NAME, /* Proxy service name */
STRING_SERVICE_NAME, /* Service name */
@@ -1651,6 +1655,8 @@ struct UserDefined {
curl_closesocket_callback fclosesocket; /* function for closing the
socket */
void *closesocket_client;
+ curl_prereq_callback fprereq; /* pre-initial request callback */
+ void *prereq_userp; /* pre-initial request user data */
void *seek_client; /* pointer to pass to the seek callback */
/* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
@@ -1675,6 +1681,8 @@ struct UserDefined {
long server_response_timeout; /* in milliseconds, 0 means no timeout */
long maxage_conn; /* in seconds, max idle time to allow a connection that
is to be reused */
+ long maxlifetime_conn; /* in seconds, max time since creation to allow a
+ connection that is to be reused */
long tftp_blksize; /* in bytes, 0 means use default */
curl_off_t filesize; /* size of file to upload, -1 means unknown */
long low_speed_limit; /* bytes/second */
@@ -1744,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 */
@@ -1851,11 +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_get); /* use GET for DoH requests, instead of POST */
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/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
index a04ffab6fb..d8aac66bda 100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c
index 0aa3f1c8ca..04f6590acf 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/version_win32.c b/Utilities/cmcurl/lib/version_win32.c
index b8157e9893..79a2aa6ab4 100644
--- a/Utilities/cmcurl/lib/version_win32.c
+++ b/Utilities/cmcurl/lib/version_win32.c
@@ -5,7 +5,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
@@ -26,11 +26,28 @@
#include <curl/curl.h>
#include "version_win32.h"
+#include "warnless.h"
/* The last #include files should be: */
#include "curl_memory.h"
#include "memdebug.h"
+/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
+ and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
+struct OUR_OSVERSIONINFOEXW {
+ ULONG dwOSVersionInfoSize;
+ ULONG dwMajorVersion;
+ ULONG dwMinorVersion;
+ ULONG dwBuildNumber;
+ ULONG dwPlatformId;
+ WCHAR szCSDVersion[128];
+ USHORT wServicePackMajor;
+ USHORT wServicePackMinor;
+ USHORT wSuiteMask;
+ UCHAR wProductType;
+ UCHAR wReserved;
+};
+
/*
* curlx_verify_windows_version()
*
@@ -40,6 +57,8 @@
*
* 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
@@ -50,6 +69,7 @@
*/
bool curlx_verify_windows_version(const unsigned int majorVersion,
const unsigned int minorVersion,
+ const unsigned int buildVersion,
const PlatformIdentifier platform,
const VersionCondition condition)
{
@@ -101,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;
}
@@ -144,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;
@@ -152,16 +191,31 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
}
#else
ULONGLONG cm = 0;
- OSVERSIONINFOEX osver;
+ 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);
+ static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
+ static bool onetime = true; /* safe because first call is during init */
+
+ if(onetime) {
+ pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
+ (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
+ onetime = false;
+ }
switch(condition) {
case VERSION_LESS_THAN:
majorCondition = VER_LESS;
minorCondition = VER_LESS;
+ buildCondition = VER_LESS;
spMajorCondition = VER_LESS_EQUAL;
spMinorCondition = VER_LESS_EQUAL;
break;
@@ -169,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;
@@ -176,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;
@@ -183,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;
@@ -190,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;
@@ -202,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)
@@ -211,13 +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, 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);
+ }
- if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
- VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
- cm))
- matched = TRUE;
#endif
return matched;
diff --git a/Utilities/cmcurl/lib/version_win32.h b/Utilities/cmcurl/lib/version_win32.h
index 9b1bd88874..38af87fa09 100644
--- a/Utilities/cmcurl/lib/version_win32.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/vquic/ngtcp2.c b/Utilities/cmcurl/lib/vquic/ngtcp2.c
index 9fcfe81a8c..1596049b77 100644
--- a/Utilities/cmcurl/lib/vquic/ngtcp2.c
+++ b/Utilities/cmcurl/lib/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"
@@ -61,6 +63,7 @@
#endif
#define H3_ALPN_H3_29 "\x5h3-29"
+#define H3_ALPN_H3 "\x2h3"
/*
* This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked.
@@ -286,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;
}
@@ -303,9 +327,10 @@ static int quic_init_ssl(struct quicsocket *qs)
SSL_set_app_data(qs->ssl, qs);
SSL_set_connect_state(qs->ssl);
+ SSL_set_quic_use_legacy_codepoint(qs->ssl, 0);
- alpn = (const uint8_t *)H3_ALPN_H3_29;
- alpnlen = sizeof(H3_ALPN_H3_29) - 1;
+ alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
+ alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
if(alpn)
SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
@@ -417,7 +442,7 @@ static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata)
static int quic_init_ssl(struct quicsocket *qs)
{
- gnutls_datum_t alpn = {NULL, 0};
+ gnutls_datum_t alpn[2];
/* this will need some attention when HTTPS proxy over QUIC get fixed */
const char * const hostname = qs->conn->host.name;
int rc;
@@ -439,12 +464,10 @@ static int quic_init_ssl(struct quicsocket *qs)
gnutls_alert_set_read_function(qs->ssl, alert_read_func);
rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters",
- 0xffa5, GNUTLS_EXT_TLS,
- tp_recv_func, tp_send_func,
- NULL, NULL, NULL,
- GNUTLS_EXT_FLAG_TLS |
- GNUTLS_EXT_FLAG_CLIENT_HELLO |
- GNUTLS_EXT_FLAG_EE);
+ NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1, GNUTLS_EXT_TLS,
+ tp_recv_func, tp_send_func, NULL, NULL, NULL,
+ GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_EE);
if(rc < 0) {
H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
gnutls_strerror(rc)));
@@ -484,10 +507,12 @@ static int quic_init_ssl(struct quicsocket *qs)
}
/* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
- alpn.data = (unsigned char *)H3_ALPN_H3_29 + 1;
- alpn.size = sizeof(H3_ALPN_H3_29) - 2;
- if(alpn.data)
- gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0);
+ alpn[0].data = (unsigned char *)H3_ALPN_H3_29 + 1;
+ alpn[0].size = sizeof(H3_ALPN_H3_29) - 2;
+ alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1;
+ alpn[1].size = sizeof(H3_ALPN_H3) - 2;
+
+ gnutls_alpn_set_protocols(qs->ssl, alpn, 2, GNUTLS_ALPN_MANDATORY);
/* set SNI */
gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
@@ -648,6 +673,20 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
return 0;
}
+static void cb_rand(uint8_t *dest, size_t destlen,
+ const ngtcp2_rand_ctx *rand_ctx)
+{
+ CURLcode result;
+ (void)rand_ctx;
+
+ result = Curl_rand(NULL, dest, destlen);
+ if(result) {
+ /* cb_rand is only used for non-cryptographic context. If Curl_rand
+ failed, just fill 0 and call it *random*. */
+ memset(dest, 0, destlen);
+ }
+}
+
static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
uint8_t *token, size_t cidlen,
void *user_data)
@@ -685,7 +724,7 @@ static ngtcp2_callbacks ng_callbacks = {
ngtcp2_crypto_recv_retry_cb,
cb_extend_max_local_streams_bidi,
NULL, /* extend_max_local_streams_uni */
- NULL, /* rand */
+ cb_rand,
cb_get_new_connection_id,
NULL, /* remove_connection_id */
ngtcp2_crypto_update_key_cb, /* update_key */
@@ -703,7 +742,7 @@ static ngtcp2_callbacks ng_callbacks = {
NULL, /* recv_datagram */
NULL, /* ack_datagram */
NULL, /* lost_datagram */
- NULL, /* get_path_challenge_data */
+ ngtcp2_crypto_get_path_challenge_data_cb,
cb_stream_stop_sending
};
@@ -776,7 +815,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
ngtcp2_addr_init(&path.remote, addr, addrlen);
rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path,
- NGTCP2_PROTO_VER_MIN, &ng_callbacks,
+ NGTCP2_PROTO_VER_V1, &ng_callbacks,
&qs->settings, &qs->transport_params, NULL, qs);
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
@@ -792,7 +831,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
void Curl_quic_ver(char *p, size_t len)
{
const ngtcp2_info *ng2 = ngtcp2_version(0);
- nghttp3_info *ht3 = nghttp3_version(0);
+ const nghttp3_info *ht3 = nghttp3_version(0);
(void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
ng2->version_str, ht3->version_str);
}
@@ -1622,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;
@@ -1631,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;
}
/*
@@ -1654,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;
@@ -1702,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/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index a772f1f9b7..581bc1be82 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/vssh/libssh2.c
@@ -81,6 +81,11 @@
#include "select.h"
#include "warnless.h"
#include "curl_path.h"
+#include "strcase.h"
+
+#include <curl_base64.h> /* for base64 encoding/decoding */
+#include <curl_sha256.h>
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -615,40 +620,141 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
- char md5buffer[33];
+ const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256];
+
+ infof(data, "SSH MD5 public key: %s",
+ pubkey_md5 != NULL ? pubkey_md5 : "NULL");
+ infof(data, "SSH SHA256 public key: %s",
+ pubkey_sha256 != NULL ? pubkey_sha256 : "NULL");
- const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
- LIBSSH2_HOSTKEY_HASH_MD5);
+ if(pubkey_sha256) {
+ const char *fingerprint = NULL;
+ char *fingerprint_b64 = NULL;
+ size_t fingerprint_b64_len;
+ size_t pub_pos = 0;
+ size_t b64_pos = 0;
- if(fingerprint) {
+#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
/* The fingerprint points to static storage (!), don't free() it. */
- int i;
- for(i = 0; i < 16; i++)
- msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
- infof(data, "SSH MD5 fingerprint: %s", md5buffer);
- }
+ fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+ LIBSSH2_HOSTKEY_HASH_SHA256);
+#else
+ const char *hostkey;
+ size_t len = 0;
+ unsigned char hash[32];
+
+ hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL);
+ if(hostkey) {
+ if(!Curl_sha256it(hash, (const unsigned char *) hostkey, len))
+ fingerprint = (char *) hash;
+ }
+#endif
- /* Before we authenticate we check the hostkey's MD5 fingerprint
- * against a known fingerprint, if available.
- */
- if(pubkey_md5 && strlen(pubkey_md5) == 32) {
- if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
- if(fingerprint)
- failf(data,
- "Denied establishing ssh session: mismatch md5 fingerprint. "
- "Remote %s is not equal to %s", md5buffer, pubkey_md5);
- else
- failf(data,
- "Denied establishing ssh session: md5 fingerprint not available");
+ if(!fingerprint) {
+ failf(data,
+ "Denied establishing ssh session: sha256 fingerprint "
+ "not available");
+ state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+
+ /* 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) {
+ 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");
+ state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+
+ infof(data, "SSH SHA256 fingerprint: %s", fingerprint_b64);
+
+ /* Find the position of any = padding characters in the public key */
+ while((pubkey_sha256[pub_pos] != '=') && pubkey_sha256[pub_pos]) {
+ pub_pos++;
+ }
+
+ /* Find the position of any = padding characters in the base64 coded
+ * hostkey fingerprint */
+ while((fingerprint_b64[b64_pos] != '=') && fingerprint_b64[b64_pos]) {
+ b64_pos++;
+ }
+
+ /* Before we authenticate we check the hostkey's sha256 fingerprint
+ * against a known fingerprint, if available.
+ */
+ if((pub_pos != b64_pos) ||
+ Curl_strncasecompare(fingerprint_b64, pubkey_sha256, pub_pos) != 1) {
+ free(fingerprint_b64);
+
+ failf(data,
+ "Denied establishing ssh session: mismatch sha256 fingerprint. "
+ "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;
}
- infof(data, "MD5 checksum match!");
+
+ free(fingerprint_b64);
+
+ infof(data, "SHA256 checksum match!");
+ }
+
+ if(pubkey_md5) {
+ char md5buffer[33];
+ const char *fingerprint = NULL;
+
+ fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+ LIBSSH2_HOSTKEY_HASH_MD5);
+
+ if(fingerprint) {
+ /* The fingerprint points to static storage (!), don't free() it. */
+ int i;
+ for(i = 0; i < 16; i++) {
+ msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
+ }
+
+ infof(data, "SSH MD5 fingerprint: %s", md5buffer);
+ }
+
+ /* Before we authenticate we check the hostkey's MD5 fingerprint
+ * against a known fingerprint, if available.
+ */
+ if(pubkey_md5 && strlen(pubkey_md5) == 32) {
+ if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
+ if(fingerprint) {
+ failf(data,
+ "Denied establishing ssh session: mismatch md5 fingerprint. "
+ "Remote %s is not equal to %s", md5buffer, pubkey_md5);
+ }
+ else {
+ failf(data,
+ "Denied establishing ssh session: md5 fingerprint "
+ "not available");
+ }
+ state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+ infof(data, "MD5 checksum match!");
+ }
+ }
+
+ if(!pubkey_md5 && !pubkey_sha256) {
+ return ssh_knownhost(data);
+ }
+ else {
/* as we already matched, we skip the check for known hosts */
return CURLE_OK;
}
- return ssh_knownhost(data);
}
/*
@@ -3610,7 +3716,7 @@ void Curl_ssh_cleanup(void)
void Curl_ssh_version(char *buffer, size_t buflen)
{
- (void)msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION);
+ (void)msnprintf(buffer, buflen, "libssh2/%s", CURL_LIBSSH2_VERSION);
}
/* The SSH session is associated with the *CONNECTION* but the callback user
diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c
index 4b1e2ec5e3..5b4cde91b0 100644
--- a/Utilities/cmcurl/lib/vssh/wolfssh.c
+++ b/Utilities/cmcurl/lib/vssh/wolfssh.c
@@ -449,7 +449,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
switch(sshc->state) {
case SSH_INIT:
state(data, SSH_S_STARTUP);
- /* FALLTHROUGH */
+ break;
+
case SSH_S_STARTUP:
rc = wolfSSH_connect(sshc->ssh_session);
if(rc != WS_SUCCESS)
@@ -838,7 +839,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
state(data, SSH_SFTP_READDIR);
- /* FALLTHROUGH */
+ break;
+
case SSH_SFTP_READDIR:
name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path);
if(!name)
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c
index e87649e2a7..9b772d064d 100644
--- a/Utilities/cmcurl/lib/vtls/bearssl.c
+++ b/Utilities/cmcurl/lib/vtls/bearssl.c
@@ -608,6 +608,7 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
+ bool added = FALSE;
void *oldsession;
br_ssl_session_parameters *session;
@@ -623,10 +624,11 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
Curl_ssl_delsessionid(data, oldsession);
ret = Curl_ssl_addsessionid(data, conn,
SSL_IS_PROXY() ? TRUE : FALSE,
- session, 0, sockindex);
+ session, 0, sockindex, &added);
Curl_ssl_sessionid_unlock(data);
- if(ret) {
+ if(!added)
free(session);
+ if(ret) {
return CURLE_OUT_OF_MEMORY;
}
}
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index 1b145d8ebb..18864aa4b2 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -404,6 +404,7 @@ gtls_connect_step1(struct Curl_easy *data,
const char * const hostname = SSL_HOST_NAME();
long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
const char *tls13support;
+ CURLcode result;
if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
@@ -496,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
@@ -557,31 +559,25 @@ gtls_connect_step1(struct Curl_easy *data,
/* Ensure +SRP comes at the *end* of all relevant strings so that it can be
* removed if a run-time error indicates that SRP is not supported by this
* GnuTLS version */
- switch(SSL_CONN_CONFIG(version)) {
- case CURL_SSLVERSION_TLSv1_3:
- if(!tls13support) {
- failf(data, "This GnuTLS installation does not support TLS 1.3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* FALLTHROUGH */
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2: {
- CURLcode result = set_ssl_version_min_max(data, &prioritylist,
- tls13support);
- if(result)
- return result;
- break;
- }
- case CURL_SSLVERSION_SSLv2:
- case CURL_SSLVERSION_SSLv3:
- default:
- failf(data, "GnuTLS does not support SSLv2 or SSLv3");
+
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2 ||
+ SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) {
+ failf(data, "GnuTLS does not support SSLv2 or SSLv3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_TLSv1_3) {
+ if(!tls13support) {
+ failf(data, "This GnuTLS installation does not support TLS 1.3");
return CURLE_SSL_CONNECT_ERROR;
+ }
}
+ /* At this point we know we have a supported TLS version, so set it */
+ result = set_ssl_version_min_max(data, &prioritylist, tls13support);
+ if(result)
+ return result;
+
#ifdef HAVE_GNUTLS_SRP
/* Only add SRP to the cipher list if SRP is requested. Otherwise
* GnuTLS will disable TLS 1.3 support. */
@@ -636,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)) {
@@ -762,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 {
@@ -783,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;
@@ -798,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);
@@ -809,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;
@@ -824,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;
@@ -1270,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
@@ -1287,6 +1282,7 @@ gtls_connect_step3(struct Curl_easy *data,
if(connect_sessionid) {
bool incache;
+ bool added = FALSE;
void *ssl_sessionid;
/* extract session ID to the allocated buffer */
@@ -1306,10 +1302,11 @@ gtls_connect_step3(struct Curl_easy *data,
result = Curl_ssl_addsessionid(data, conn,
SSL_IS_PROXY() ? TRUE : FALSE,
connect_sessionid, connect_idsize,
- sockindex);
+ sockindex, &added);
Curl_ssl_sessionid_unlock(data);
- if(result) {
+ if(!added)
free(connect_sessionid);
+ if(result) {
result = CURLE_OUT_OF_MEMORY;
}
}
@@ -1354,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/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
index 1a146a3a93..642d5f093a 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index 780d13e188..1d209b2732 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/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
@@ -784,6 +812,7 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
+ bool added = FALSE;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
@@ -807,11 +836,13 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
Curl_ssl_delsessionid(data, old_ssl_sessionid);
retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
- 0, sockindex);
+ 0, sockindex, &added);
Curl_ssl_sessionid_unlock(data);
- if(retcode) {
+ if(!added) {
mbedtls_ssl_session_free(our_ssl_sessionid);
free(our_ssl_sessionid);
+ }
+ if(retcode) {
failf(data, "failed to store ssl session");
return retcode;
}
@@ -1151,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/Utilities/cmcurl/lib/vtls/mesalink.c b/Utilities/cmcurl/lib/vtls/mesalink.c
index 3db9184f79..35a916586e 100644
--- a/Utilities/cmcurl/lib/vtls/mesalink.c
+++ b/Utilities/cmcurl/lib/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 =
@@ -365,7 +365,7 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
if(!incache) {
result =
Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, 0,
- sockindex);
+ sockindex, NULL);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "failed to store ssl session");
@@ -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/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index cf657895f6..2b44f05126 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/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);
@@ -955,7 +957,7 @@ static void display_cert_info(struct Curl_easy *data,
subject = CERT_NameToAscii(&cert->subject);
issuer = CERT_NameToAscii(&cert->issuer);
common_name = CERT_GetCommonName(&cert->subject);
- infof(data, "subject: %s\n", subject);
+ infof(data, "subject: %s", subject);
CERT_GetCertTimes(cert, &notBefore, &notAfter);
PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
@@ -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();
@@ -2250,10 +2252,11 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
case CURLE_OK:
break;
case CURLE_AGAIN:
+ /* CURLE_AGAIN in non-blocking mode is not an error */
if(!blocking)
- /* CURLE_AGAIN in non-blocking mode is not an error */
return CURLE_OK;
- /* FALLTHROUGH */
+ else
+ return result;
default:
return result;
}
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 87f4b02b71..f836c63b07 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/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
@@ -227,6 +242,17 @@
#endif
#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#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 */
@@ -435,18 +461,21 @@ static bool rand_enough(void)
static CURLcode ossl_seed(struct Curl_easy *data)
{
- char fname[256];
-
/* This might get called before it has been added to a multi handle */
if(data->multi && data->multi->ssl_seeded)
return CURLE_OK;
if(rand_enough()) {
- /* OpenSSL 1.1.0+ will return here */
+ /* OpenSSL 1.1.0+ should return here */
if(data->multi)
data->multi->ssl_seeded = TRUE;
return CURLE_OK;
}
+#ifdef HAVE_RANDOM_INIT_BY_DEFAULT
+ /* with OpenSSL 1.1.0+, a failed RAND_status is a showstopper */
+ failf(data, "Insufficient randomness");
+ return CURLE_SSL_CONNECT_ERROR;
+#else
#ifndef RANDOM_FILE
/* if RANDOM_FILE isn't defined, we only perform this if an option tells
@@ -507,19 +536,23 @@ static CURLcode ossl_seed(struct Curl_easy *data)
RAND_add(randb, (int)len, (double)len/2);
} while(!rand_enough());
- /* generates a default path for the random seed file */
- fname[0] = 0; /* blank it first */
- RAND_file_name(fname, sizeof(fname));
- if(fname[0]) {
- /* we got a file name to try */
- RAND_load_file(fname, RAND_LOAD_LENGTH);
- if(rand_enough())
- return CURLE_OK;
+ {
+ /* generates a default path for the random seed file */
+ char fname[256];
+ fname[0] = 0; /* blank it first */
+ RAND_file_name(fname, sizeof(fname));
+ if(fname[0]) {
+ /* we got a file name to try */
+ RAND_load_file(fname, RAND_LOAD_LENGTH);
+ if(rand_enough())
+ return CURLE_OK;
+ }
}
infof(data, "libcurl is now using a weak random seed!");
return (rand_enough() ? CURLE_OK :
- CURLE_SSL_CONNECT_ERROR /* confusing error code */);
+ CURLE_SSL_CONNECT_ERROR /* confusing error code */);
+#endif
}
#ifndef SSL_FILETYPE_ENGINE
@@ -1088,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. */
@@ -1401,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. */
@@ -1639,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 */
@@ -1926,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;
@@ -2493,6 +2534,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
+ bool added = FALSE;
void *old_ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
@@ -2511,9 +2553,11 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
if(!incache) {
if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
- 0 /* unknown size */, sockindex)) {
- /* the session has been put into the session cache */
- res = 1;
+ 0 /* unknown size */, sockindex, &added)) {
+ if(added) {
+ /* the session has been put into the session cache */
+ res = 1;
+ }
}
else
failf(data, "failed to store ssl session");
@@ -2936,7 +2980,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
NULL, cert_name, sizeof(cert_name))) {
strcpy(cert_name, "Unknown");
}
- infof(data, "SSL: Checking cert %s\"\n", cert_name);
+ infof(data, "SSL: Checking cert \"%s\"", cert_name);
#endif
encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
@@ -3052,60 +3096,36 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
}
}
+ if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) {
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
- {
- if(ssl_cafile) {
- if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
- if(verifypeer && !imported_native_ca) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate file: %s", ssl_cafile);
- return CURLE_SSL_CACERT_BADFILE;
- }
- /* Continue with warning if certificate verification isn't required. */
- infof(data, "error setting certificate file, continuing anyway");
- }
- infof(data, " CAfile: %s", ssl_cafile);
+ if(ssl_cafile &&
+ !SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate file: %s", ssl_cafile);
+ return CURLE_SSL_CACERT_BADFILE;
}
- if(ssl_capath) {
- if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
- if(verifypeer && !imported_native_ca) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate path: %s", ssl_capath);
- return CURLE_SSL_CACERT_BADFILE;
- }
- /* Continue with warning if certificate verification isn't required. */
- infof(data, "error setting certificate path, continuing anyway");
- }
- infof(data, " CApath: %s", ssl_capath);
+ if(ssl_capath &&
+ !SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate path: %s", ssl_capath);
+ return CURLE_SSL_CACERT_BADFILE;
}
- }
#else
- if(ssl_cafile || ssl_capath) {
- /* tell SSL where to find CA certificates that are used to verify
- the server's certificate. */
+ /* tell OpenSSL where to find CA certificates that are used to verify the
+ server's certificate. */
if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) {
- if(verifypeer && !imported_native_ca) {
- /* 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 CURLE_SSL_CACERT_BADFILE;
- }
- /* Just continue with a warning if no strict certificate verification
- is required. */
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:");
- }
- else {
- /* Everything is fine. */
- infof(data, "successfully set certificate verify locations:");
+ /* 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 CURLE_SSL_CACERT_BADFILE;
}
+#endif
infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
}
-#endif
#ifdef CURL_CA_FALLBACK
if(verifypeer &&
@@ -3476,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];
@@ -3544,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)
{
@@ -3573,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;
@@ -3657,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;
}
}
@@ -3846,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)
@@ -3884,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;
@@ -4364,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);
@@ -4384,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/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h
index 2f6e1b2db8..28058453c0 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c
index 2ac97ce28e..6dbb1ef3cd 100644
--- a/Utilities/cmcurl/lib/vtls/rustls.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index 722a937c42..0a8e60610d 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/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,16 +713,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- BACKEND->cred->refcount = 1;
+ backend->cred->refcount = 1;
- /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
- */
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]);
@@ -732,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;
@@ -771,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. */
@@ -787,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 "
@@ -818,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");
@@ -827,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)) {
@@ -835,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;
@@ -864,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;
@@ -922,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;
}
@@ -950,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",
@@ -1003,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;
@@ -1031,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;
@@ -1038,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) {
@@ -1078,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;
}
}
@@ -1088,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)
@@ -1107,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);
@@ -1134,19 +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;
- /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
- */
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);
@@ -1155,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"));
@@ -1166,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"));
@@ -1195,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);
}
}
@@ -1249,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;
@@ -1261,7 +1258,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
}
else {
- BACKEND->encdata_offset = 0;
+ backend->encdata_offset = 0;
}
break;
}
@@ -1288,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
@@ -1370,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);
@@ -1377,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);
@@ -1436,13 +1434,14 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
/* save the current session data for possible re-use */
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
+ bool added = FALSE;
struct Curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(data);
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 */
@@ -1451,17 +1450,17 @@ 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);
+ sockindex, &added);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "schannel: failed to store credential handle");
return result;
}
- else {
+ 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"));
}
@@ -1472,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);
@@ -1609,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;
@@ -1636,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;
@@ -1650,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;
@@ -1665,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);
@@ -1678,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 */
@@ -1783,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
@@ -1797,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;
@@ -1816,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;
@@ -1834,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;
@@ -1861,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);
@@ -1891,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
@@ -1907,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 */
@@ -1948,34 +1952,34 @@ 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 */
if(sspi_status == SEC_I_RENEGOTIATE) {
infof(data, "schannel: remote party requests renegotiation");
if(*err && *err != CURLE_AGAIN) {
- infof(data, "schannel: can't renogotiate, an error is pending");
+ 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 renogotiate, "
+ infof(data, "schannel: can't renegotiate, "
"encrypted data available");
goto cleanup;
}
@@ -1997,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");
@@ -2025,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 */
@@ -2046,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)");
@@ -2061,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
@@ -2116,34 +2120,32 @@ 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;
}
-static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- if(conn->ssl[sockindex].use)
- /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
- Curl_ssl_shutdown(data, conn, sockindex);
-}
-
static void schannel_session_free(void *ptr)
{
/* this is expected to be called under sessionid lock */
struct Curl_schannel_cred *cred = ptr;
- cred->refcount--;
- if(cred->refcount == 0) {
- s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
- Curl_safefree(cred);
+ if(cred) {
+ cred->refcount--;
+ if(cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ Curl_safefree(cred);
+ }
}
}
+/* shut down the SSL connection and clean up related memory.
+ this function can be called multiple times on the same connection including
+ if the SSL connection failed (eg connection made but failed handshake). */
static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
int sockindex)
{
@@ -2152,13 +2154,16 @@ 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);
- infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
- hostname, conn->remote_port);
+ if(connssl->use) {
+ infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
+ hostname, conn->remote_port);
+ }
- if(BACKEND->cred && BACKEND->ctxt) {
+ if(connssl->use && backend->cred && backend->ctxt) {
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_status;
@@ -2171,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) {
@@ -2189,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);
@@ -2219,38 +2224,48 @@ 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;
}
+static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
+ int sockindex)
+{
+ if(conn->ssl[sockindex].use)
+ /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */
+ Curl_ssl_shutdown(data, conn, sockindex);
+ else
+ schannel_shutdown(data, conn, sockindex);
+}
+
static int schannel_init(void)
{
return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
@@ -2293,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 */
@@ -2310,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);
@@ -2416,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/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index 1b283d0453..4966cd4945 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index 1e6ed5f06d..f7a20b20b1 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ b/Utilities/cmcurl/lib/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,
@@ -2109,7 +2109,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
}
result = Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
- ssl_sessionid_len, sockindex);
+ ssl_sessionid_len, sockindex, NULL);
Curl_ssl_sessionid_unlock(data);
if(result) {
failf(data, "failed to store ssl session");
@@ -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/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index e5bbe1f5f0..6007bbba0f 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -516,7 +516,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
const bool isProxy,
void *ssl_sessionid,
size_t idsize,
- int sockindex)
+ int sockindex,
+ bool *added)
{
size_t i;
struct Curl_ssl_session *store;
@@ -536,6 +537,10 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
const char *hostname = conn->host.name;
#endif
(void)sockindex;
+
+ if(added)
+ *added = FALSE;
+
if(!data->state.session)
return CURLE_OK;
@@ -609,6 +614,9 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
+ if(added)
+ *added = TRUE;
+
DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
store->scheme, store->name, store->remote_port,
isProxy ? "PROXY" : "server"));
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index beaa83d9e3..c7bbba082d 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -261,7 +261,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
const bool isProxy,
void *ssl_sessionid,
size_t idsize,
- int sockindex);
+ int sockindex,
+ bool *added);
/* Kill a single session ID entry in the cache
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* This will call engine-specific curlssl_session_free function, which must
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index 16fbb89288..8c5b9157b8 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -202,6 +202,43 @@ static int do_file_type(const char *type)
return -1;
}
+#ifdef HAVE_LIBOQS
+struct group_name_map {
+ const word16 group;
+ const char *name;
+};
+
+static const struct group_name_map gnm[] = {
+ { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" },
+ { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" },
+ { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" },
+ { WOLFSSL_NTRU_HPS_LEVEL1, "NTRU_HPS_LEVEL1" },
+ { WOLFSSL_NTRU_HPS_LEVEL3, "NTRU_HPS_LEVEL3" },
+ { WOLFSSL_NTRU_HPS_LEVEL5, "NTRU_HPS_LEVEL5" },
+ { WOLFSSL_NTRU_HRSS_LEVEL3, "NTRU_HRSS_LEVEL3" },
+ { WOLFSSL_SABER_LEVEL1, "SABER_LEVEL1" },
+ { WOLFSSL_SABER_LEVEL3, "SABER_LEVEL3" },
+ { WOLFSSL_SABER_LEVEL5, "SABER_LEVEL5" },
+ { WOLFSSL_KYBER_90S_LEVEL1, "KYBER_90S_LEVEL1" },
+ { WOLFSSL_KYBER_90S_LEVEL3, "KYBER_90S_LEVEL3" },
+ { WOLFSSL_KYBER_90S_LEVEL5, "KYBER_90S_LEVEL5" },
+ { WOLFSSL_P256_NTRU_HPS_LEVEL1, "P256_NTRU_HPS_LEVEL1" },
+ { WOLFSSL_P384_NTRU_HPS_LEVEL3, "P384_NTRU_HPS_LEVEL3" },
+ { WOLFSSL_P521_NTRU_HPS_LEVEL5, "P521_NTRU_HPS_LEVEL5" },
+ { WOLFSSL_P384_NTRU_HRSS_LEVEL3, "P384_NTRU_HRSS_LEVEL3" },
+ { WOLFSSL_P256_SABER_LEVEL1, "P256_SABER_LEVEL1" },
+ { WOLFSSL_P384_SABER_LEVEL3, "P384_SABER_LEVEL3" },
+ { WOLFSSL_P521_SABER_LEVEL5, "P521_SABER_LEVEL5" },
+ { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" },
+ { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" },
+ { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" },
+ { WOLFSSL_P256_KYBER_90S_LEVEL1, "P256_KYBER_90S_LEVEL1" },
+ { WOLFSSL_P384_KYBER_90S_LEVEL3, "P384_KYBER_90S_LEVEL3" },
+ { WOLFSSL_P521_KYBER_90S_LEVEL5, "P521_KYBER_90S_LEVEL5" },
+ { 0, NULL }
+};
+#endif
+
/*
* This function loads all the client/CA certificates and CRLs. Setup the TLS
* layer and do all necessary magic.
@@ -210,11 +247,15 @@ static CURLcode
wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
int sockindex)
{
- char *ciphers;
+ char *ciphers, *curves;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
SSL_METHOD* req_method = NULL;
curl_socket_t sockfd = conn->sock[sockindex];
+#ifdef HAVE_LIBOQS
+ word16 oqsAlg = 0;
+ size_t idx = 0;
+#endif
#ifdef HAVE_SNI
bool sni = FALSE;
#define use_sni(x) sni = (x)
@@ -327,6 +368,26 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
infof(data, "Cipher selection: %s", ciphers);
}
+ curves = SSL_CONN_CONFIG(curves);
+ if(curves) {
+
+#ifdef HAVE_LIBOQS
+ for(idx = 0; gnm[idx].name != NULL; idx++) {
+ if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
+ oqsAlg = gnm[idx].group;
+ break;
+ }
+ }
+
+ if(oqsAlg == 0)
+#endif
+ {
+ if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+ failf(data, "failed setting curves list: '%s'", curves);
+ return CURLE_SSL_CIPHER;
+ }
+ }
+ }
#ifndef NO_FILESYSTEM
/* load trusted cacert */
if(SSL_CONN_CONFIG(CAfile)) {
@@ -439,6 +500,14 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
}
+#ifdef HAVE_LIBOQS
+ if(oqsAlg) {
+ if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
+ failf(data, "unable to use oqs KEM");
+ }
+ }
+#endif
+
#ifdef HAVE_ALPN
if(conn->bits.tls_enable_alpn) {
char protocols[128];
@@ -495,7 +564,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_delsessionid(data, ssl_sessionid);
- infof(data, "Can't use session ID, going on without\n");
+ infof(data, "Can't use session ID, going on without");
}
else
infof(data, "SSL re-using session ID");
@@ -749,7 +818,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
if(!incache) {
result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
- 0, sockindex);
+ 0, sockindex, NULL);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "failed to store ssl session");
diff --git a/Utilities/cmcurl/lib/x509asn1.c b/Utilities/cmcurl/lib/x509asn1.c
index 1bdaeadc80..0341543a2b 100644
--- a/Utilities/cmcurl/lib/x509asn1.c
+++ b/Utilities/cmcurl/lib/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(&param, 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(&param, 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, &param, &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, &param, &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