Procházet zdrojové kódy

Merge branch 'upstream-curl' into update-curl

* upstream-curl:
  curl 2022-01-05 (801bd513)
Brad King před 3 roky
rodič
revize
697e8871a1
100 změnil soubory, kde provedl 3434 přidání a 1945 odebrání
  1. 0 20
      Utilities/cmcurl/CMake/CurlTests.c
  2. 2 2
      Utilities/cmcurl/CMake/FindMbedTLS.cmake
  3. 0 1
      Utilities/cmcurl/CMake/OtherTests.cmake
  4. 86 66
      Utilities/cmcurl/CMakeLists.txt
  5. 39 3
      Utilities/cmcurl/include/curl/curl.h
  6. 4 4
      Utilities/cmcurl/include/curl/curlver.h
  7. 3 2
      Utilities/cmcurl/include/curl/multi.h
  8. 2 0
      Utilities/cmcurl/include/curl/typecheck-gcc.h
  9. 20 1
      Utilities/cmcurl/include/curl/urlapi.h
  10. 1 6
      Utilities/cmcurl/lib/CMakeLists.txt
  11. 5 1
      Utilities/cmcurl/lib/asyn-ares.c
  12. 140 63
      Utilities/cmcurl/lib/c-hyper.c
  13. 4 9
      Utilities/cmcurl/lib/conncache.c
  14. 28 10
      Utilities/cmcurl/lib/connect.c
  15. 2 1
      Utilities/cmcurl/lib/content_encoding.c
  16. 1 1
      Utilities/cmcurl/lib/cookie.c
  17. 0 3
      Utilities/cmcurl/lib/curl_config.h.cmake
  18. 2 2
      Utilities/cmcurl/lib/curl_des.c
  19. 6 4
      Utilities/cmcurl/lib/curl_gssapi.c
  20. 2 2
      Utilities/cmcurl/lib/curl_hmac.h
  21. 4 4
      Utilities/cmcurl/lib/curl_md5.h
  22. 13 6
      Utilities/cmcurl/lib/curl_ntlm_core.c
  23. 69 48
      Utilities/cmcurl/lib/curl_sasl.c
  24. 39 28
      Utilities/cmcurl/lib/curl_sasl.h
  25. 1 1
      Utilities/cmcurl/lib/curl_setup.h
  26. 10 3
      Utilities/cmcurl/lib/curl_sha256.h
  27. 2 2
      Utilities/cmcurl/lib/curl_sspi.c
  28. 2 23
      Utilities/cmcurl/lib/doh.c
  29. 6 4
      Utilities/cmcurl/lib/easy.c
  30. 7 1
      Utilities/cmcurl/lib/easyoptions.c
  31. 15 9
      Utilities/cmcurl/lib/ftp.c
  32. 50 32
      Utilities/cmcurl/lib/hash.c
  33. 6 6
      Utilities/cmcurl/lib/hash.h
  34. 1 1
      Utilities/cmcurl/lib/hostcheck.c
  35. 23 8
      Utilities/cmcurl/lib/hostip.c
  36. 2 2
      Utilities/cmcurl/lib/hostip.h
  37. 41 48
      Utilities/cmcurl/lib/http.c
  38. 2 4
      Utilities/cmcurl/lib/http.h
  39. 25 6
      Utilities/cmcurl/lib/http2.c
  40. 16 5
      Utilities/cmcurl/lib/http_aws_sigv4.c
  41. 6 5
      Utilities/cmcurl/lib/http_ntlm.c
  42. 85 25
      Utilities/cmcurl/lib/http_proxy.c
  43. 2 1
      Utilities/cmcurl/lib/http_proxy.h
  44. 2 2
      Utilities/cmcurl/lib/if2ip.c
  45. 84 73
      Utilities/cmcurl/lib/imap.c
  46. 3 3
      Utilities/cmcurl/lib/inet_pton.c
  47. 4 4
      Utilities/cmcurl/lib/krb5.c
  48. 6 1
      Utilities/cmcurl/lib/ldap.c
  49. 2 2
      Utilities/cmcurl/lib/libcurl.rc
  50. 1 3
      Utilities/cmcurl/lib/llist.c
  51. 13 4
      Utilities/cmcurl/lib/md4.c
  52. 33 9
      Utilities/cmcurl/lib/md5.c
  53. 53 27
      Utilities/cmcurl/lib/mime.c
  54. 1 1
      Utilities/cmcurl/lib/mprintf.c
  55. 178 74
      Utilities/cmcurl/lib/multi.c
  56. 2 0
      Utilities/cmcurl/lib/multihandle.h
  57. 2 2
      Utilities/cmcurl/lib/multiif.h
  58. 477 356
      Utilities/cmcurl/lib/openldap.c
  59. 60 40
      Utilities/cmcurl/lib/pop3.c
  60. 1 1
      Utilities/cmcurl/lib/select.c
  61. 5 3
      Utilities/cmcurl/lib/sendf.c
  62. 38 0
      Utilities/cmcurl/lib/setopt.c
  63. 3 11
      Utilities/cmcurl/lib/setup-win32.h
  64. 97 44
      Utilities/cmcurl/lib/sha256.c
  65. 1 5
      Utilities/cmcurl/lib/share.c
  66. 61 42
      Utilities/cmcurl/lib/smtp.c
  67. 28 5
      Utilities/cmcurl/lib/socks.c
  68. 2 2
      Utilities/cmcurl/lib/socks_gssapi.c
  69. 1 1
      Utilities/cmcurl/lib/socks_sspi.c
  70. 2 2
      Utilities/cmcurl/lib/splay.c
  71. 111 0
      Utilities/cmcurl/lib/strerror.c
  72. 3 1
      Utilities/cmcurl/lib/system_win32.c
  73. 3 3
      Utilities/cmcurl/lib/tftp.c
  74. 1 1
      Utilities/cmcurl/lib/transfer.c
  75. 53 23
      Utilities/cmcurl/lib/url.c
  76. 1 3
      Utilities/cmcurl/lib/urlapi-int.h
  77. 272 130
      Utilities/cmcurl/lib/urlapi.c
  78. 12 2
      Utilities/cmcurl/lib/urldata.h
  79. 5 6
      Utilities/cmcurl/lib/vauth/digest.c
  80. 3 1
      Utilities/cmcurl/lib/vauth/ntlm.c
  81. 101 12
      Utilities/cmcurl/lib/version_win32.c
  82. 2 1
      Utilities/cmcurl/lib/version_win32.h
  83. 87 20
      Utilities/cmcurl/lib/vquic/ngtcp2.c
  84. 130 24
      Utilities/cmcurl/lib/vssh/libssh2.c
  85. 4 2
      Utilities/cmcurl/lib/vssh/wolfssh.c
  86. 4 2
      Utilities/cmcurl/lib/vtls/bearssl.c
  87. 40 39
      Utilities/cmcurl/lib/vtls/gtls.c
  88. 6 2
      Utilities/cmcurl/lib/vtls/gtls.h
  89. 46 14
      Utilities/cmcurl/lib/vtls/mbedtls.c
  90. 49 44
      Utilities/cmcurl/lib/vtls/mesalink.c
  91. 55 52
      Utilities/cmcurl/lib/vtls/nss.c
  92. 168 122
      Utilities/cmcurl/lib/vtls/openssl.c
  93. 6 2
      Utilities/cmcurl/lib/vtls/openssl.h
  94. 33 28
      Utilities/cmcurl/lib/vtls/rustls.c
  95. 203 198
      Utilities/cmcurl/lib/vtls/schannel.c
  96. 3 2
      Utilities/cmcurl/lib/vtls/schannel_verify.c
  97. 16 16
      Utilities/cmcurl/lib/vtls/sectransp.c
  98. 9 1
      Utilities/cmcurl/lib/vtls/vtls.c
  99. 2 1
      Utilities/cmcurl/lib/vtls/vtls.h
  100. 72 3
      Utilities/cmcurl/lib/vtls/wolfssl.c

+ 0 - 20
Utilities/cmcurl/CMake/CurlTests.c

@@ -229,10 +229,6 @@ int main () { ; return 0; }
 #  include <windows.h>
 #  include <windows.h>
 #  ifdef HAVE_WINSOCK2_H
 #  ifdef HAVE_WINSOCK2_H
 #    include <winsock2.h>
 #    include <winsock2.h>
-#  else
-#    ifdef HAVE_WINSOCK_H
-#      include <winsock.h>
-#    endif
 #  endif
 #  endif
 #endif
 #endif
 
 
@@ -258,10 +254,6 @@ main ()
 #  include <windows.h>
 #  include <windows.h>
 #  ifdef HAVE_WINSOCK2_H
 #  ifdef HAVE_WINSOCK2_H
 #    include <winsock2.h>
 #    include <winsock2.h>
-#  else
-#    ifdef HAVE_WINSOCK_H
-#      include <winsock.h>
-#    endif
 #  endif
 #  endif
 #endif
 #endif
 
 
@@ -285,10 +277,6 @@ main ()
 #  include <windows.h>
 #  include <windows.h>
 #  ifdef HAVE_WINSOCK2_H
 #  ifdef HAVE_WINSOCK2_H
 #    include <winsock2.h>
 #    include <winsock2.h>
-#  else
-#    ifdef HAVE_WINSOCK_H
-#      include <winsock.h>
-#    endif
 #  endif
 #  endif
 #endif
 #endif
 
 
@@ -313,10 +301,6 @@ main ()
 #  include <windows.h>
 #  include <windows.h>
 #  ifdef HAVE_WINSOCK2_H
 #  ifdef HAVE_WINSOCK2_H
 #    include <winsock2.h>
 #    include <winsock2.h>
-#  else
-#    ifdef HAVE_WINSOCK_H
-#      include <winsock.h>
-#    endif
 #  endif
 #  endif
 #endif
 #endif
 
 
@@ -403,10 +387,6 @@ main ()
 #  include <windows.h>
 #  include <windows.h>
 #  ifdef HAVE_WINSOCK2_H
 #  ifdef HAVE_WINSOCK2_H
 #    include <winsock2.h>
 #    include <winsock2.h>
-#  else
-#    ifdef HAVE_WINSOCK_H
-#      include <winsock.h>
-#    endif
 #  endif
 #  endif
 #endif
 #endif
 /* includes start */
 /* includes start */

+ 2 - 2
Utilities/cmcurl/CMake/FindMbedTLS.cmake

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #                             \___|\___/|_| \_\_____|
 #
 #
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
 #
 #
 # This software is licensed as described in the file COPYING, which
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
 # 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}")
 set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
 
 
 include(FindPackageHandleStandardArgs)
 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)
     MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
 
 
 mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
 mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)

+ 0 - 1
Utilities/cmcurl/CMake/OtherTests.cmake

@@ -33,7 +33,6 @@ set(signature_call_conv)
 if(HAVE_WINDOWS_H)
 if(HAVE_WINDOWS_H)
   add_header_include(HAVE_WINSOCK2_H "winsock2.h")
   add_header_include(HAVE_WINSOCK2_H "winsock2.h")
   add_header_include(HAVE_WINDOWS_H "windows.h")
   add_header_include(HAVE_WINDOWS_H "windows.h")
-  add_header_include(HAVE_WINSOCK_H "winsock.h")
   set(_source_epilogue
   set(_source_epilogue
       "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif")
       "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif")
   set(signature_call_conv "PASCAL")
   set(signature_call_conv "PASCAL")

+ 86 - 66
Utilities/cmcurl/CMakeLists.txt

@@ -387,6 +387,17 @@ if(ENABLE_IPV6 AND NOT WIN32)
     set(ENABLE_IPV6 OFF
     set(ENABLE_IPV6 OFF
         CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
         CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
   endif()
   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()
 endif()
 
 
 if(0) # This code not needed for building within CMake.
 if(0) # This code not needed for building within CMake.
@@ -479,84 +490,94 @@ if(WIN32)
   check_library_exists_concat("winmm"  getch        HAVE_LIBWINMM)
   check_library_exists_concat("winmm"  getch        HAVE_LIBWINMM)
 endif()
 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)
 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()
 endif()
 
 
+# check SSL libraries
+# TODO support GnuTLS
+option(CURL_ENABLE_SSL "Enable SSL support" ON)
+
 if(APPLE)
 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()
 endif()
 if(WIN32)
 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_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON
-    CMAKE_USE_SCHANNEL OFF)
+    CURL_USE_SCHANNEL OFF)
 endif()
 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)
 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)
   set(openssl_default OFF)
 endif()
 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)
 option(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG "Disable automatic loading of OpenSSL configuration" OFF)
 
 
 count_true(enabled_ssl_options_count
 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")
 if(enabled_ssl_options_count GREATER "1")
   set(CURL_WITH_MULTI_SSL ON)
   set(CURL_WITH_MULTI_SSL ON)
 endif()
 endif()
 
 
-if(CMAKE_USE_SCHANNEL)
+if(CURL_USE_SCHANNEL)
   set(SSL_ENABLED ON)
   set(SSL_ENABLED ON)
   set(USE_SCHANNEL ON) # Windows native SSL/TLS support
   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()
 endif()
 if(CURL_WINDOWS_SSPI)
 if(CURL_WINDOWS_SSPI)
   set(USE_WINDOWS_SSPI ON)
   set(USE_WINDOWS_SSPI ON)
   set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32")
   set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32")
 endif()
 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()
 endif()
 
 
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+if(use_core_foundation)
   find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation")
   find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation")
   if(NOT COREFOUNDATION_FRAMEWORK)
   if(NOT COREFOUNDATION_FRAMEWORK)
       message(FATAL_ERROR "CoreFoundation framework not found")
       message(FATAL_ERROR "CoreFoundation framework not found")
   endif()
   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()
 endif()
 
 
-if(CMAKE_USE_OPENSSL)
+if(CURL_USE_OPENSSL)
   find_package(OpenSSL)
   find_package(OpenSSL)
   if(NOT OpenSSL_FOUND)
   if(NOT OpenSSL_FOUND)
     message(FATAL_ERROR
     message(FATAL_ERROR
@@ -588,9 +609,11 @@ if(CMAKE_USE_OPENSSL)
   if(CURL_CA_PATH)
   if(CURL_CA_PATH)
     add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}")
     add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}")
   endif()
   endif()
+
+  add_definitions(-DOPENSSL_SUPPRESS_DEPRECATED)
 endif()
 endif()
 
 
-if(CMAKE_USE_MBEDTLS)
+if(CURL_USE_MBEDTLS)
   find_package(MbedTLS REQUIRED)
   find_package(MbedTLS REQUIRED)
   set(SSL_ENABLED ON)
   set(SSL_ENABLED ON)
   set(USE_MBEDTLS ON)
   set(USE_MBEDTLS ON)
@@ -598,7 +621,7 @@ if(CMAKE_USE_MBEDTLS)
   include_directories(${MBEDTLS_INCLUDE_DIRS})
   include_directories(${MBEDTLS_INCLUDE_DIRS})
 endif()
 endif()
 
 
-if(CMAKE_USE_BEARSSL)
+if(CURL_USE_BEARSSL)
   find_package(BearSSL REQUIRED)
   find_package(BearSSL REQUIRED)
   set(SSL_ENABLED ON)
   set(SSL_ENABLED ON)
   set(USE_BEARSSL ON)
   set(USE_BEARSSL ON)
@@ -606,7 +629,7 @@ if(CMAKE_USE_BEARSSL)
   include_directories(${BEARSSL_INCLUDE_DIRS})
   include_directories(${BEARSSL_INCLUDE_DIRS})
 endif()
 endif()
 
 
-if(CMAKE_USE_WOLFSSL)
+if(CURL_USE_WOLFSSL)
   find_package(WolfSSL REQUIRED)
   find_package(WolfSSL REQUIRED)
   set(SSL_ENABLED ON)
   set(SSL_ENABLED ON)
   set(USE_WOLFSSL ON)
   set(USE_WOLFSSL ON)
@@ -614,7 +637,7 @@ if(CMAKE_USE_WOLFSSL)
   include_directories(${WolfSSL_INCLUDE_DIRS})
   include_directories(${WolfSSL_INCLUDE_DIRS})
 endif()
 endif()
 
 
-if(CMAKE_USE_NSS)
+if(CURL_USE_NSS)
   find_package(NSS REQUIRED)
   find_package(NSS REQUIRED)
   include_directories(${NSS_INCLUDE_DIRS})
   include_directories(${NSS_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NSS_LIBRARIES})
   list(APPEND CURL_LIBS ${NSS_LIBRARIES})
@@ -695,13 +718,13 @@ if(NOT CURL_DISABLE_LDAP)
     endif()
     endif()
   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_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")
   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()
   endif()
 
 
   # Now that we know, we're not using windows LDAP...
   # 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(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
     else()
     else()
-      if(CMAKE_USE_OPENLDAP)
+      if(CURL_USE_OPENLDAP)
         set(USE_OPENLDAP ON)
         set(USE_OPENLDAP ON)
       endif()
       endif()
       if(CMAKE_LDAP_INCLUDE_DIR)
       if(CMAKE_LDAP_INCLUDE_DIR)
@@ -873,13 +896,13 @@ if(CURL_ZSTD)
 endif()
 endif()
 
 
 #libSSH2
 #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(USE_LIBSSH2 OFF)
 set(HAVE_LIBSSH2 OFF)
 set(HAVE_LIBSSH2 OFF)
 set(HAVE_LIBSSH2_H OFF)
 set(HAVE_LIBSSH2_H OFF)
 
 
-if(CMAKE_USE_LIBSSH2)
+if(CURL_USE_LIBSSH2)
   find_package(LibSSH2)
   find_package(LibSSH2)
   if(LIBSSH2_FOUND)
   if(LIBSSH2_FOUND)
     list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
     list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
@@ -898,9 +921,9 @@ if(CMAKE_USE_LIBSSH2)
 endif()
 endif()
 
 
 # libssh
 # 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)
   find_package(libssh CONFIG)
   if(libssh_FOUND)
   if(libssh_FOUND)
     message(STATUS "Found libssh ${libssh_VERSION}")
     message(STATUS "Found libssh ${libssh_VERSION}")
@@ -911,10 +934,10 @@ if(NOT HAVE_LIBSSH2 AND CMAKE_USE_LIBSSH)
   endif()
   endif()
 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)
   find_package(GSS)
 
 
   set(HAVE_GSSAPI ${GSS_FOUND})
   set(HAVE_GSSAPI ${GSS_FOUND})
@@ -1065,7 +1088,6 @@ endif()
 # Check for header files
 # Check for header files
 if(NOT UNIX)
 if(NOT UNIX)
   check_include_file_concat("windows.h"      HAVE_WINDOWS_H)
   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("ws2tcpip.h"     HAVE_WS2TCPIP_H)
   check_include_file_concat("winsock2.h"     HAVE_WINSOCK2_H)
   check_include_file_concat("winsock2.h"     HAVE_WINSOCK2_H)
   check_include_file_concat("wincrypt.h"     HAVE_WINCRYPT_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})
 foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
   if(TARGET "${_lib}")
   if(TARGET "${_lib}")
     set(_libname "${_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()
       continue()
     endif()
     endif()
     get_target_property(_lib "${_libname}" LOCATION)
     get_target_property(_lib "${_libname}" LOCATION)

+ 39 - 3
Utilities/cmcurl/include/curl/curl.h

@@ -46,8 +46,8 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <limits.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>
 #include <osreldate.h>
 #endif
 #endif
 
 
@@ -73,6 +73,7 @@
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
     defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
     defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
    (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
    (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
+   (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
     defined(__VXWORKS__)
     defined(__VXWORKS__)
 #include <sys/select.h>
 #include <sys/select.h>
 #endif
 #endif
@@ -470,6 +471,20 @@ typedef int (*curl_debug_callback)
         size_t size,       /* size of the data pointed to */
         size_t size,       /* size of the data pointed to */
         void *userptr);    /* whatever the user please */
         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
 /* All possible error codes from all sorts of curl functions. Future versions
    may return other values, stay prepared.
    may return other values, stay prepared.
 
 
@@ -2043,7 +2058,8 @@ typedef enum {
   /* alt-svc cache file name to possibly read from/write to */
   /* alt-svc cache file name to possibly read from/write to */
   CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),
   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),
   CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),
 
 
   /* SASL authorisation identity */
   /* SASL authorisation identity */
@@ -2102,6 +2118,23 @@ typedef enum {
      this option is used only if PROXY_SSL_VERIFYPEER is true */
      this option is used only if PROXY_SSL_VERIFYPEER is true */
   CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
   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 */
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 } 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_mime      curl_mime;      /* Mime context. */
 typedef struct curl_mimepart  curl_mimepart;  /* Mime part 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()
  * NAME curl_mime_init()
  *
  *

+ 4 - 4
Utilities/cmcurl/include/curl/curlver.h

@@ -30,13 +30,13 @@
 
 
 /* This is the version number of the libcurl package from which this header
 /* This is the version number of the libcurl package from which this header
    file origins: */
    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
 /* The numeric version number is also available "in parts" by using these
    defines: */
    defines: */
 #define LIBCURL_VERSION_MAJOR 7
 #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
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
    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
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
    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
  * This is the date and time when the full source package was created. The

+ 3 - 2
Utilities/cmcurl/include/curl/multi.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * 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
   CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
                                callback */
                                callback */
   CURLM_WAKEUP_FAILURE,  /* wakeup is unavailable or failed */
   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
   CURLM_LAST
 } CURLMcode;
 } CURLMcode;
 
 

+ 2 - 0
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_SERVICE_NAME ||                                        \
    (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
    (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
    (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
    (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 ||                          \
    (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
    (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
    (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
    (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
    (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
    (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
@@ -363,6 +364,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_INTERLEAVEDATA ||                                      \
    (option) == CURLOPT_INTERLEAVEDATA ||                                      \
    (option) == CURLOPT_IOCTLDATA ||                                           \
    (option) == CURLOPT_IOCTLDATA ||                                           \
    (option) == CURLOPT_OPENSOCKETDATA ||                                      \
    (option) == CURLOPT_OPENSOCKETDATA ||                                      \
+   (option) == CURLOPT_PREREQDATA ||                                          \
    (option) == CURLOPT_PROGRESSDATA ||                                        \
    (option) == CURLOPT_PROGRESSDATA ||                                        \
    (option) == CURLOPT_READDATA ||                                            \
    (option) == CURLOPT_READDATA ||                                            \
    (option) == CURLOPT_SEEKDATA ||                                            \
    (option) == CURLOPT_SEEKDATA ||                                            \

+ 20 - 1
Utilities/cmcurl/include/curl/urlapi.h

@@ -47,7 +47,20 @@ typedef enum {
   CURLUE_NO_HOST,             /* 14 */
   CURLUE_NO_HOST,             /* 14 */
   CURLUE_NO_PORT,             /* 15 */
   CURLUE_NO_PORT,             /* 15 */
   CURLUE_NO_QUERY,            /* 16 */
   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;
 } CURLUcode;
 
 
 typedef enum {
 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,
 CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
                                    const char *part, unsigned int flags);
                                    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
 #ifdef __cplusplus
 } /* end of extern "C" */
 } /* end of extern "C" */

+ 1 - 6
Utilities/cmcurl/lib/CMakeLists.txt

@@ -120,12 +120,6 @@ endif()
 
 
 target_link_libraries(${LIB_NAME} PRIVATE ${CURL_LIBS})
 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
 set_target_properties(${LIB_NAME} PROPERTIES
   COMPILE_DEFINITIONS BUILDING_LIBCURL
   COMPILE_DEFINITIONS BUILDING_LIBCURL
   OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
   OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
@@ -149,6 +143,7 @@ endif()
 
 
 if(WIN32)
 if(WIN32)
   if(BUILD_SHARED_LIBS)
   if(BUILD_SHARED_LIBS)
+    set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "_USRDLL")
     if(MSVC)
     if(MSVC)
       # Add "_imp" as a suffix before the extension to avoid conflicting with
       # Add "_imp" as a suffix before the extension to avoid conflicting with
       # the statically linked "libcurl.lib"
       # the statically linked "libcurl.lib"

+ 5 - 1
Utilities/cmcurl/lib/asyn-ares.c

@@ -109,7 +109,9 @@ struct thread_data {
   struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
   struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
                                     parts */
                                     parts */
   int last_status;
   int last_status;
+#ifndef HAVE_CARES_GETADDRINFO
   struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
   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
 /* 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;
     nfds = 0;
 
 
   if(!nfds)
   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! */
        above, as otherwise the ares name resolve won't timeout! */
     ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
     ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
                     ARES_SOCKET_BAD);
                     ARES_SOCKET_BAD);
@@ -375,6 +377,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
 
 
   waitperform(data, 0);
   waitperform(data, 0);
 
 
+#ifndef HAVE_CARES_GETADDRINFO
   /* Now that we've checked for any last minute results above, see if there are
   /* 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
      any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
      expires. */
      expires. */
@@ -397,6 +400,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
     ares_cancel((ares_channel)data->state.async.resolver);
     ares_cancel((ares_channel)data->state.async.resolver);
     DEBUGASSERT(res->num_pending == 0);
     DEBUGASSERT(res->num_pending == 0);
   }
   }
+#endif
 
 
   if(res && !res->num_pending) {
   if(res && !res->num_pending) {
     (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
     (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);

+ 140 - 63
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);
   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;
   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;
         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;
       done = TRUE;
       result = CURLE_OK;
       result = CURLE_OK;
     }
     }
@@ -260,6 +263,12 @@ static CURLcode status_line(struct Curl_easy *data,
   if(http_version == HYPER_HTTP_VERSION_1_0)
   if(http_version == HYPER_HTTP_VERSION_1_0)
     data->state.httpwant = CURL_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;
   data->req.httpcode = http_status;
 
 
   result = Curl_http_statusline(data, conn);
   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);
   len = Curl_dyn_len(&data->state.headerb);
   Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
   Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
              len);
              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->info.header_size += (long)len;
   data->req.headerbytecount += (long)len;
   data->req.headerbytecount += (long)len;
   data->req.httpcode = http_status;
   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)
 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,
 CURLcode Curl_hyper_stream(struct Curl_easy *data,
@@ -443,11 +460,9 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
       break;
       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;
       break;
-    }
 
 
     /* Curl_http_auth_act() checks what authentication methods that are
     /* Curl_http_auth_act() checks what authentication methods that are
      * available and decides which one (if any) to use. It will set 'newurl'
      * 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)
   if(result)
     return 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;
     result = CURLE_OUT_OF_MEMORY;
   }
   }
   else
   else
@@ -850,6 +878,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   io = hyper_io_new();
   io = hyper_io_new();
   if(!io) {
   if(!io) {
     failf(data, "Couldn't create hyper IO");
     failf(data, "Couldn't create hyper IO");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
   /* tell Hyper how to read/write network data */
   /* 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();
     h->exec = hyper_executor_new();
     if(!h->exec) {
     if(!h->exec) {
       failf(data, "Couldn't create hyper executor");
       failf(data, "Couldn't create hyper executor");
+      result = CURLE_OUT_OF_MEMORY;
       goto error;
       goto error;
     }
     }
   }
   }
@@ -869,6 +899,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   options = hyper_clientconn_options_new();
   options = hyper_clientconn_options_new();
   if(!options) {
   if(!options) {
     failf(data, "Couldn't create hyper client options");
     failf(data, "Couldn't create hyper client options");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
   if(conn->negnpn == CURL_HTTP_VERSION_2) {
   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);
   handshake = hyper_clientconn_handshake(io, options);
   if(!handshake) {
   if(!handshake) {
     failf(data, "Couldn't create hyper client handshake");
     failf(data, "Couldn't create hyper client handshake");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
   io = NULL;
   io = NULL;
@@ -889,6 +921,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 
 
   if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
   if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
     failf(data, "Couldn't hyper_executor_push the handshake");
     failf(data, "Couldn't hyper_executor_push the handshake");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
   handshake = NULL; /* ownership passed on */
   handshake = NULL; /* ownership passed on */
@@ -896,6 +929,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   task = hyper_executor_poll(h->exec);
   task = hyper_executor_poll(h->exec);
   if(!task) {
   if(!task) {
     failf(data, "Couldn't hyper_executor_poll the handshake");
     failf(data, "Couldn't hyper_executor_poll the handshake");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
 
 
@@ -905,6 +939,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   req = hyper_request_new();
   req = hyper_request_new();
   if(!req) {
   if(!req) {
     failf(data, "Couldn't hyper_request_new");
     failf(data, "Couldn't hyper_request_new");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
 
 
@@ -912,12 +947,14 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     if(HYPERE_OK != hyper_request_set_version(req,
     if(HYPERE_OK != hyper_request_set_version(req,
                                               HYPER_HTTP_VERSION_1_0)) {
                                               HYPER_HTTP_VERSION_1_0)) {
       failf(data, "error setting HTTP version");
       failf(data, "error setting HTTP version");
+      result = CURLE_OUT_OF_MEMORY;
       goto error;
       goto error;
     }
     }
   }
   }
 
 
   if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
   if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
     failf(data, "error setting method");
     failf(data, "error setting method");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
 
 
@@ -928,51 +965,81 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   headers = hyper_request_headers(req);
   headers = hyper_request_headers(req);
   if(!headers) {
   if(!headers) {
     failf(data, "hyper_request_headers");
     failf(data, "hyper_request_headers");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
 
 
   rc = hyper_request_on_informational(req, http1xx_cb, data);
   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);
   result = Curl_http_body(data, conn, httpreq, &te);
   if(result)
   if(result)
-    return result;
-
-  if(data->state.aptr.host &&
-     Curl_hyper_header(data, headers, data->state.aptr.host))
     goto error;
     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] &&
   if(data->set.str[STRING_USERAGENT] &&
      *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";
   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
 #ifndef CURL_DISABLE_PROXY
   if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
   if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
      !Curl_checkheaders(data, "Proxy-Connection") &&
      !Curl_checkheaders(data, "Proxy-Connection") &&
      !Curl_checkProxyheaders(data, conn, "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;
       goto error;
   }
   }
 #endif
 #endif
@@ -981,8 +1048,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
   if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
     data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
     data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
     if(!data->state.aptr.ref)
     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;
       goto error;
   }
   }
 
 
@@ -992,8 +1061,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     data->state.aptr.accept_encoding =
     data->state.aptr.accept_encoding =
       aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
       aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
     if(!data->state.aptr.accept_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;
       goto error;
   }
   }
   else
   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 */
   /* we only consider transfer-encoding magic if libz support is built-in */
   result = Curl_transferencode(data);
   result = Curl_transferencode(data);
   if(result)
   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;
     goto error;
 #endif
 #endif
 
 
   result = cookies(data, conn, headers);
   result = cookies(data, conn, headers);
   if(result)
   if(result)
-    return result;
+    goto error;
 
 
   result = Curl_add_timecondition(data, headers);
   result = Curl_add_timecondition(data, headers);
   if(result)
   if(result)
-    return result;
+    goto error;
 
 
   result = Curl_add_custom_headers(data, FALSE, headers);
   result = Curl_add_custom_headers(data, FALSE, headers);
   if(result)
   if(result)
-    return result;
+    goto error;
 
 
   result = bodysend(data, conn, headers, req, httpreq);
   result = bodysend(data, conn, headers, req, httpreq);
   if(result)
   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;
   data->req.upload_chunky = FALSE;
   sendtask = hyper_clientconn_send(client, req);
   sendtask = hyper_clientconn_send(client, req);
   if(!sendtask) {
   if(!sendtask) {
     failf(data, "hyper_clientconn_send");
     failf(data, "hyper_clientconn_send");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
 
 
   if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
   if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
     failf(data, "Couldn't hyper_executor_push the send");
     failf(data, "Couldn't hyper_executor_push the send");
+    result = CURLE_OUT_OF_MEMORY;
     goto error;
     goto error;
   }
   }
 
 
@@ -1057,7 +1134,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   Curl_safefree(data->state.aptr.proxyuserpwd);
   Curl_safefree(data->state.aptr.proxyuserpwd);
   return CURLE_OK;
   return CURLE_OK;
   error:
   error:
-
+  DEBUGASSERT(result);
   if(io)
   if(io)
     hyper_io_free(io);
     hyper_io_free(io);
 
 
@@ -1067,7 +1144,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(handshake)
   if(handshake)
     hyper_task_free(handshake);
     hyper_task_free(handshake);
 
 
-  return CURLE_OUT_OF_MEMORY;
+  return result;
 }
 }
 
 
 void Curl_hyper_done(struct Curl_easy *data)
 void Curl_hyper_done(struct Curl_easy *data)

+ 4 - 9
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 Curl_conncache_init(struct conncache *connc, int size)
 {
 {
-  int rc;
-
   /* allocate a new easy handle to use when closing cached connections */
   /* allocate a new easy handle to use when closing cached connections */
   connc->closure_handle = curl_easy_init();
   connc->closure_handle = curl_easy_init();
   if(!connc->closure_handle)
   if(!connc->closure_handle)
     return 1; /* bad */
     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)
 void Curl_conncache_destroy(struct conncache *connc)

+ 28 - 10
Utilities/cmcurl/lib/connect.c

@@ -85,7 +85,7 @@
 
 
 static bool verifyconnect(curl_socket_t sockfd, int *error);
 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 */
 /* DragonFlyBSD and Windows use millisecond units */
 #define KEEPALIVE_FACTOR(x) (x *= 1000)
 #define KEEPALIVE_FACTOR(x) (x *= 1000)
 #else
 #else
@@ -629,7 +629,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
 #ifdef ENABLE_IPV6
 #ifdef ENABLE_IPV6
   struct sockaddr_in6 *si6 = NULL;
   struct sockaddr_in6 *si6 = NULL;
 #endif
 #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;
   struct sockaddr_un *su = NULL;
 #else
 #else
   (void)salen;
   (void)salen;
@@ -656,7 +656,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
       }
       }
       break;
       break;
 #endif
 #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:
     case AF_UNIX:
       if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
       if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
         su = (struct sockaddr_un*)sa;
         su = (struct sockaddr_un*)sa;
@@ -894,6 +894,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
         connkeep(conn, "HTTP/3 default");
         connkeep(conn, "HTTP/3 default");
         return CURLE_OK;
         return CURLE_OK;
       }
       }
+      /* When a QUIC connect attempt fails, the better error explanation is in
+         'result' and not in errno */
       if(result) {
       if(result) {
         conn->tempsock[i] = CURL_SOCKET_BAD;
         conn->tempsock[i] = CURL_SOCKET_BAD;
         error = SOCKERRNO;
         error = SOCKERRNO;
@@ -977,6 +979,13 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
         char buffer[STRERROR_LEN];
         char buffer[STRERROR_LEN];
         Curl_printable_address(conn->tempaddr[i], ipaddress,
         Curl_printable_address(conn->tempaddr[i], ipaddress,
                                sizeof(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",
         infof(data, "connect to %s port %u failed: %s",
               ipaddress, conn->port,
               ipaddress, conn->port,
               Curl_strerror(error, buffer, sizeof(buffer)));
               Curl_strerror(error, buffer, sizeof(buffer)));
@@ -988,9 +997,11 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
         ainext(conn, i, TRUE);
         ainext(conn, i, TRUE);
         status = trynextip(data, conn, sockindex, i);
         status = trynextip(data, conn, sockindex, i);
         if((status != CURLE_COULDNT_CONNECT) ||
         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 */
           /* 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 */
     /* no more addresses to try */
     const char *hostname;
     const char *hostname;
     char buffer[STRERROR_LEN];
     char buffer[STRERROR_LEN];
+    CURLcode failreason = result;
 
 
     /* if the first address family runs out of addresses to try before the
     /* if the first address family runs out of addresses to try before the
        happy eyeball timeout, go ahead and try the next family now */
        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)
     if(!result)
       return result;
       return result;
 
 
+    result = failreason;
+
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
     if(conn->bits.socksproxy)
     if(conn->bits.socksproxy)
       hostname = conn->socks_proxy.host.name;
       hostname = conn->socks_proxy.host.name;
@@ -1036,10 +1050,14 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
       hostname = conn->host.name;
       hostname = conn->host.name;
 
 
     failf(data, "Failed to connect to %s port %u after "
     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, 0);
     Curl_quic_disconnect(data, conn, 1);
     Curl_quic_disconnect(data, conn, 1);
@@ -1127,7 +1145,7 @@ void Curl_sndbufset(curl_socket_t sockfd)
   static int detectOsState = DETECT_OS_NONE;
   static int detectOsState = DETECT_OS_NONE;
 
 
   if(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))
                                     VERSION_GREATER_THAN_EQUAL))
       detectOsState = DETECT_OS_VISTA_OR_LATER;
       detectOsState = DETECT_OS_VISTA_OR_LATER;
     else
     else

+ 2 - 1
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. */
         zp->zlib_init = ZLIB_UNINIT;    /* inflateEnd() already called. */
       }
       }
-      /* FALLTHROUGH */
+      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
+      break;
     default:
     default:
       result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
       result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
       break;
       break;

+ 1 - 1
Utilities/cmcurl/lib/cookie.c

@@ -1164,7 +1164,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
   bool fromfile = TRUE;
   bool fromfile = TRUE;
   char *line = NULL;
   char *line = NULL;
 
 
-  if(NULL == inc) {
+  if(!inc) {
     /* we didn't get a struct, create one */
     /* we didn't get a struct, create one */
     c = calloc(1, sizeof(struct CookieInfo));
     c = calloc(1, sizeof(struct CookieInfo));
     if(!c)
     if(!c)

+ 0 - 3
Utilities/cmcurl/lib/curl_config.h.cmake

@@ -702,9 +702,6 @@
 /* Define to 1 if you have the winsock2.h header file. */
 /* Define to 1 if you have the winsock2.h header file. */
 #cmakedefine HAVE_WINSOCK2_H 1
 #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 */
 /* Define this symbol if your OS supports changing the contents of argv */
 #cmakedefine HAVE_WRITABLE_ARGV 1
 #cmakedefine HAVE_WRITABLE_ARGV 1
 
 

+ 2 - 2
Utilities/cmcurl/lib/curl_des.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2015 - 2020, Steve Holme, <[email protected]>.
+ * Copyright (C) 2015 - 2021, Steve Holme, <[email protected]>.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -22,7 +22,7 @@
 
 
 #include "curl_setup.h"
 #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"
 #include "curl_des.h"
 
 

+ 6 - 4
Utilities/cmcurl/lib/curl_gssapi.c

@@ -32,10 +32,12 @@
 #include "curl_memory.h"
 #include "curl_memory.h"
 #include "memdebug.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(
 OM_uint32 Curl_gss_init_sec_context(
     struct Curl_easy *data,
     struct Curl_easy *data,

+ 2 - 2
Utilities/cmcurl/lib/curl_hmac.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -26,7 +26,7 @@
 
 
 #define HMAC_MD5_LENGTH 16
 #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,
 typedef void    (* HMAC_hupdate_func)(void *context,
                                       const unsigned char *data,
                                       const unsigned char *data,
                                       unsigned int len);
                                       unsigned int len);

+ 4 - 4
Utilities/cmcurl/lib/curl_md5.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -27,7 +27,7 @@
 
 
 #define MD5_DIGEST_LEN  16
 #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,
 typedef void (* Curl_MD5_update_func)(void *context,
                                       const unsigned char *data,
                                       const unsigned char *data,
                                       unsigned int len);
                                       unsigned int len);
@@ -49,8 +49,8 @@ struct MD5_context {
 extern const struct MD5_params Curl_DIGEST_MD5[1];
 extern const struct MD5_params Curl_DIGEST_MD5[1];
 extern const struct HMAC_params Curl_HMAC_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);
 struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params);
 CURLcode Curl_MD5_update(struct MD5_context *context,
 CURLcode Curl_MD5_update(struct MD5_context *context,

+ 13 - 6
Utilities/cmcurl/lib/curl_ntlm_core.c

@@ -49,7 +49,14 @@
      in NTLM type-3 messages.
      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
 #ifdef USE_WOLFSSL
 #include <wolfssl/options.h>
 #include <wolfssl/options.h>
@@ -97,7 +104,7 @@
 #elif defined(USE_WIN32_CRYPTO)
 #elif defined(USE_WIN32_CRYPTO)
 #  include <wincrypt.h>
 #  include <wincrypt.h>
 #else
 #else
-#  error "Can't compile NTLM support without a crypto library."
+#  error "Can't compile NTLM support without a crypto library with DES."
 #endif
 #endif
 
 
 #include "urldata.h"
 #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);
   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
  * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
  * key schedule ks is also set.
  * 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);
   DES_set_odd_parity(&key);
 
 
   /* Set the key */
   /* Set the key */
-  DES_set_key(&key, ks);
+  DES_set_key_unchecked(&key, ks);
 }
 }
 
 
 #elif defined(USE_GNUTLS)
 #elif defined(USE_GNUTLS)
@@ -362,7 +369,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
                             const unsigned char *plaintext,
                             const unsigned char *plaintext,
                             unsigned char *results)
                             unsigned char *results)
 {
 {
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
   DES_key_schedule ks;
   DES_key_schedule ks;
 
 
   setup_des_key(keys, DESKEY(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. */
     /* Create LanManager hashed password. */
 
 
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
     DES_key_schedule ks;
     DES_key_schedule ks;
 
 
     setup_des_key(pw, DESKEY(ks));
     setup_des_key(pw, DESKEY(ks));

+ 69 - 48
Utilities/cmcurl/lib/curl_sasl.c

@@ -56,8 +56,8 @@
 
 
 /* Supported mechanisms */
 /* Supported mechanisms */
 static const struct {
 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 */
   unsigned short bit;   /* Flag bit */
 } mechtable[] = {
 } mechtable[] = {
   { "LOGIN",        5,  SASL_MECH_LOGIN },
   { "LOGIN",        5,  SASL_MECH_LOGIN },
@@ -85,8 +85,11 @@ static const struct {
  * conn     [in]     - The connection data.
  * conn     [in]     - The connection data.
  * authused [in]     - The authentication mechanism used.
  * 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)
 #if defined(USE_KERBEROS5)
   /* Cleanup the gssapi structure */
   /* Cleanup the gssapi structure */
   if(authused == SASL_MECH_GSSAPI) {
   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);
     Curl_auth_cleanup_ntlm(&conn->ntlm);
   }
   }
 #endif
 #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.
  * 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->params = params;           /* Set protocol dependent parameters */
   sasl->state = SASL_STOP;         /* Not yet running */
   sasl->state = SASL_STOP;         /* Not yet running */
+  sasl->curmech = NULL;            /* No mechanism yet. */
   sasl->authmechs = SASL_AUTH_NONE; /* No known authentication 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->resetprefs = TRUE;         /* Reset prefmech upon AUTH parsing. */
   sasl->mutual_auth = FALSE;       /* No mutual authentication (GSSAPI only) */
   sasl->mutual_auth = FALSE;       /* No mutual authentication (GSSAPI only) */
   sasl->force_ir = FALSE;          /* Respect external option */
   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,
 static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
                                    struct bufref *out)
                                    struct bufref *out)
 {
 {
-  unsigned char *msg;
-  size_t msglen;
-  char *serverdata = NULL;
   CURLcode result = CURLE_OK;
   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;
   return result;
 }
 }
 
 
 /* Encode the outgoing SASL message. */
 /* 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;
   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;
   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.
  * Calculate the required login details for SASL authentication.
  */
  */
 CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
 CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
-                         struct connectdata *conn,
                          bool force_ir, saslprogress *progress)
                          bool force_ir, saslprogress *progress)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  unsigned int enabledmechs;
+  struct connectdata *conn = data->conn;
+  unsigned short enabledmechs;
   const char *mech = NULL;
   const char *mech = NULL;
   struct bufref resp;
   struct bufref resp;
   saslstate state1 = SASL_STOP;
   saslstate state1 = SASL_STOP;
@@ -471,16 +492,16 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
   }
   }
 
 
   if(!result && mech) {
   if(!result && mech) {
+    sasl->curmech = mech;
     if(Curl_bufref_ptr(&resp))
     if(Curl_bufref_ptr(&resp))
-      result = build_message(data, &resp);
+      result = build_message(sasl, data, &resp);
 
 
     if(sasl->params->maxirlen &&
     if(sasl->params->maxirlen &&
        strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
        strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
       Curl_bufref_free(&resp);
       Curl_bufref_free(&resp);
 
 
     if(!result)
     if(!result)
-      result = sasl->params->sendauth(data, conn, mech,
-                                      (const char *) Curl_bufref_ptr(&resp));
+      result = sasl->params->sendauth(data, mech, &resp);
 
 
     if(!result) {
     if(!result) {
       *progress = SASL_INPROGRESS;
       *progress = SASL_INPROGRESS;
@@ -498,10 +519,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
  * Continue the authentication.
  * Continue the authentication.
  */
  */
 CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
 CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
-                            struct connectdata *conn,
                             int code, saslprogress *progress)
                             int code, saslprogress *progress)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   saslstate newstate = SASL_FINAL;
   saslstate newstate = SASL_FINAL;
   struct bufref resp;
   struct bufref resp;
   const char * const hostname = SSL_HOST_NAME();
   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,
       result = Curl_auth_create_digest_md5_message(data, &serverdata,
                                                    conn->user, conn->passwd,
                                                    conn->user, conn->passwd,
                                                    service, &resp);
                                                    service, &resp);
-    newstate = SASL_DIGESTMD5_RESP;
+    if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
+      newstate = SASL_DIGESTMD5_RESP;
     break;
     break;
   case SASL_DIGESTMD5_RESP:
   case SASL_DIGESTMD5_RESP:
     /* Keep response NULL to output an empty line. */
     /* 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;
     sasl->authmechs ^= sasl->authused;
 
 
     /* Start an alternative SASL authentication */
     /* 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:
   default:
     failf(data, "Unsupported SASL authentication mechanism");
     failf(data, "Unsupported SASL authentication mechanism");
     result = CURLE_UNSUPPORTED_PROTOCOL;  /* Should not happen */
     result = CURLE_UNSUPPORTED_PROTOCOL;  /* Should not happen */
@@ -703,14 +725,13 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
   switch(result) {
   switch(result) {
   case CURLE_BAD_CONTENT_ENCODING:
   case CURLE_BAD_CONTENT_ENCODING:
     /* Cancel dialog */
     /* Cancel dialog */
-    result = sasl->params->sendcont(data, conn, "*");
+    result = sasl->params->cancelauth(data, sasl->curmech);
     newstate = SASL_CANCEL;
     newstate = SASL_CANCEL;
     break;
     break;
   case CURLE_OK:
   case CURLE_OK:
-    result = build_message(data, &resp);
+    result = build_message(sasl, data, &resp);
     if(!result)
     if(!result)
-      result = sasl->params->sendcont(data, conn,
-                                      (const char *) Curl_bufref_ptr(&resp));
+      result = sasl->params->contauth(data, sasl->curmech, &resp);
     break;
     break;
   default:
   default:
     newstate = SASL_STOP;    /* Stop on error */
     newstate = SASL_STOP;    /* Stop on error */

+ 39 - 28
Utilities/cmcurl/lib/curl_sasl.h

@@ -24,6 +24,8 @@
 
 
 #include <curl/curl.h>
 #include <curl/curl.h>
 
 
+#include "bufref.h"
+
 struct Curl_easy;
 struct Curl_easy;
 struct connectdata;
 struct connectdata;
 
 
@@ -46,17 +48,20 @@ struct connectdata;
 #define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
 #define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
 
 
 /* Authentication mechanism strings */
 /* 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 */
 /* SASL machine states */
 typedef enum {
 typedef enum {
@@ -90,30 +95,37 @@ typedef enum {
 /* Protocol dependent SASL parameters */
 /* Protocol dependent SASL parameters */
 struct SASLproto {
 struct SASLproto {
   const char *service;     /* The service name */
   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 */
                            /* 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 */
                            /* 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 */
                            /* 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 */
 /* Per-connection parameters */
 struct SASL {
 struct SASL {
   const struct SASLproto *params; /* Protocol dependent parameters */
   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 authmechs;  /* Accepted authentication mechanisms */
   unsigned short prefmech;   /* Preferred authentication mechanism */
   unsigned short prefmech;   /* Preferred authentication mechanism */
   unsigned short authused;   /* Auth mechanism used for the connection */
   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 */
 /* 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
 /* This is used to cleanup any libraries or curl modules used by the sasl
    functions */
    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 */
 /* Convert a mechanism name to a token */
 unsigned short Curl_sasl_decode_mech(const char *ptr,
 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);
                                          const char *value, size_t len);
 
 
 /* Initializes an SASL structure */
 /* 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 */
 /* Check if we have enough auth data and capabilities to authenticate */
 bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
 bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
 
 
 /* Calculate the required login details for SASL authentication  */
 /* Calculate the required login details for SASL authentication  */
 CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
 CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
-                         struct connectdata *conn,
                          bool force_ir, saslprogress *progress);
                          bool force_ir, saslprogress *progress);
 
 
 /* Continue an SASL authentication  */
 /* Continue an SASL authentication  */
 CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
 CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
-                            struct connectdata *conn,
                             int code, saslprogress *progress);
                             int code, saslprogress *progress);
 
 
 #endif /* HEADER_CURL_SASL_H */
 #endif /* HEADER_CURL_SASL_H */

+ 1 - 1
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(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
 #  if defined(SOCKET) || \
 #  if defined(SOCKET) || \
      defined(USE_WINSOCK) || \
      defined(USE_WINSOCK) || \
-     defined(HAVE_WINSOCK_H) || \
      defined(HAVE_WINSOCK2_H) || \
      defined(HAVE_WINSOCK2_H) || \
      defined(HAVE_WS2TCPIP_H)
      defined(HAVE_WS2TCPIP_H)
 #    error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
 #    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;
        ADDRESS_FAMILY sun_family;
        char sun_path[UNIX_PATH_MAX];
        char sun_path[UNIX_PATH_MAX];
      } SOCKADDR_UN, *PSOCKADDR_UN;
      } SOCKADDR_UN, *PSOCKADDR_UN;
+#    define WIN32_SOCKADDR_UN
 #  endif
 #  endif
 #endif
 #endif
 
 

+ 10 - 3
Utilities/cmcurl/lib/curl_sha256.h

@@ -8,7 +8,7 @@
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
  * Copyright (C) 2017, Florin Petriuc, <[email protected]>
  * Copyright (C) 2017, Florin Petriuc, <[email protected]>
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -28,10 +28,17 @@
 
 
 extern const struct HMAC_params Curl_HMAC_SHA256[1];
 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
 #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
 #endif
 
 

+ 2 - 2
Utilities/cmcurl/lib/curl_sspi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * 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) */
      * have both these DLLs (security.dll forwards calls to secur32.dll) */
 
 
     /* Load SSPI dll into the address space of the calling process */
     /* 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"));
       s_hSecDll = Curl_load_library(TEXT("security.dll"));
     else
     else
       s_hSecDll = Curl_load_library(TEXT("secur32.dll"));
       s_hSecDll = Curl_load_library(TEXT("secur32.dll"));

+ 2 - 23
Utilities/cmcurl/lib/doh.c

@@ -235,25 +235,6 @@ static CURLcode dohprobe(struct Curl_easy *data,
   p->dnstype = dnstype;
   p->dnstype = dnstype;
   Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
   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);
   timeout_ms = Curl_timeleft(data, NULL, TRUE);
   if(timeout_ms <= 0) {
   if(timeout_ms <= 0) {
     result = CURLE_OPERATION_TIMEDOUT;
     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_URL, url);
     ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
     ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
     ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
     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);
     ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
 #ifdef USE_NGHTTP2
 #ifdef USE_NGHTTP2
     ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
     ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);

+ 6 - 4
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 *curl_easy_duphandle(struct Curl_easy *data)
 {
 {
   struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
   struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
-  if(NULL == outcurl)
+  if(!outcurl)
     goto fail;
     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
       /* if not pausing again, force a recv/send check of this connection as
          the data might've been read off the socket already */
          the data might've been read off the socket already */
       data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
       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)
   if(!data->state.done)
     /* This transfer may have been moved in or out of the bundle, update the
     /* This transfer may have been moved in or out of the bundle, update the
        corresponding socket callback, if used */
        corresponding socket callback, if used */
-    Curl_updatesocket(data);
+    result = Curl_updatesocket(data);
 
 
   return result;
   return result;
 }
 }

+ 7 - 1
Utilities/cmcurl/lib/easyoptions.c

@@ -165,10 +165,12 @@ struct curl_easyoption Curl_easyopts[] = {
   {"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0},
   {"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0},
   {"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0},
   {"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0},
   {"MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE, CURLOT_OFF_T, 0},
   {"MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE, CURLOT_OFF_T, 0},
+  {"MAXLIFETIME_CONN", CURLOPT_MAXLIFETIME_CONN, CURLOT_LONG, 0},
   {"MAXREDIRS", CURLOPT_MAXREDIRS, CURLOT_LONG, 0},
   {"MAXREDIRS", CURLOPT_MAXREDIRS, CURLOT_LONG, 0},
   {"MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE, CURLOT_OFF_T, 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},
   {"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0},
   {"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0},
   {"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0},
+  {"MIME_OPTIONS", CURLOPT_MIME_OPTIONS, CURLOT_LONG, 0},
   {"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0},
   {"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0},
   {"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0},
   {"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0},
   {"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS, CURLOT_LONG, 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},
   {"POSTQUOTE", CURLOPT_POSTQUOTE, CURLOT_SLIST, 0},
   {"POSTREDIR", CURLOPT_POSTREDIR, CURLOT_VALUES, 0},
   {"POSTREDIR", CURLOPT_POSTREDIR, CURLOT_VALUES, 0},
   {"PREQUOTE", CURLOPT_PREQUOTE, CURLOT_SLIST, 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},
   {"PRE_PROXY", CURLOPT_PRE_PROXY, CURLOT_STRING, 0},
   {"PRIVATE", CURLOPT_PRIVATE, CURLOT_OBJECT, 0},
   {"PRIVATE", CURLOPT_PRIVATE, CURLOT_OBJECT, 0},
   {"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
   {"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_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0},
   {"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
   {"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
    CURLOT_STRING, 0},
    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_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0},
   {"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
   {"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
   {"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
   {"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
@@ -354,6 +360,6 @@ struct curl_easyoption Curl_easyopts[] = {
  */
  */
 int Curl_easyopts_check(void)
 int Curl_easyopts_check(void)
 {
 {
-  return ((CURLOPT_LASTENTRY%10000) != (310 + 1));
+  return ((CURLOPT_LASTENTRY%10000) != (315 + 1));
 }
 }
 #endif
 #endif

+ 15 - 9
Utilities/cmcurl/lib/ftp.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * 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 */
     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 &&
     if(conn->bits.reuse && ftpc->entrypath &&
        /* no need to go to entrypath when we have an absolute path */
        /* no need to go to entrypath when we have an absolute path */
        !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
        !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
@@ -1009,7 +1004,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
       }
       }
 
 
     /* parse the port */
     /* parse the port */
-    if(ip_end != NULL) {
+    if(ip_end) {
       port_start = strchr(ip_end, ':');
       port_start = strchr(ip_end, ':');
       if(port_start) {
       if(port_start) {
         port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
         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) {
            ftpc->cwdcount && !ftpc->count2) {
           /* try making it */
           /* try making it */
           ftpc->count2++; /* counter to prevent CWD-MKD loops */
           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",
           result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s",
                                  ftpc->dirs[ftpc->cwdcount - 1]);
                                  ftpc->dirs[ftpc->cwdcount - 1]);
           if(!result)
           if(!result)
@@ -4102,6 +4103,11 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
+#ifdef _MSC_VER
+/* warning C4706: assignment within conditional expression */
+#pragma warning(disable:4706)
+#endif
+
 /***********************************************************************
 /***********************************************************************
  *
  *
  * ftp_parse_url_path()
  * 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 */
         /* parse the URL path into separate path components */
-        while((slashPos = strchr(curPos, '/')) != NULL) {
+        while((slashPos = strchr(curPos, '/'))) {
           size_t compLen = slashPos - curPos;
           size_t compLen = slashPos - curPos;
 
 
           /* path starts with a slash: add that as a directory */
           /* 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;
   struct FTP *ftp;
 
 
   data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
   data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
-  if(NULL == ftp)
+  if(!ftp)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
   ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
   ftp->path = &data->state.up.path[1]; /* don't include the initial slash */

+ 50 - 32
Utilities/cmcurl/lib/hash.c

@@ -53,32 +53,25 @@ hash_element_dtor(void *user, void *element)
  * @unittest: 1602
  * @unittest: 1602
  * @unittest: 1603
  * @unittest: 1603
  */
  */
-int
+void
 Curl_hash_init(struct Curl_hash *h,
 Curl_hash_init(struct Curl_hash *h,
                int slots,
                int slots,
                hash_function hfunc,
                hash_function hfunc,
                comp_function comparator,
                comp_function comparator,
                Curl_hash_dtor dtor)
                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->hash_func = hfunc;
   h->comp_func = comparator;
   h->comp_func = comparator;
   h->dtor = dtor;
   h->dtor = dtor;
   h->size = 0;
   h->size = 0;
   h->slots = slots;
   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 *
 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)]
 #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: 1305
  * @unittest: 1602
  * @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_hash_element  *he;
   struct Curl_llist_element *le;
   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) {
   for(le = l->head; le; le = le->next) {
     he = (struct Curl_hash_element *) le->ptr;
     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)
 int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
 {
 {
   struct Curl_llist_element *le;
   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;
   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_element *le;
   struct Curl_llist *l;
   struct Curl_llist *l;
 
 
-  if(h) {
+  DEBUGASSERT(h);
+  if(h->table) {
+    DEBUGASSERT(h->slots);
     l = FETCH_LIST(h, key, key_len);
     l = FETCH_LIST(h, key, key_len);
     for(le = l->head; le; le = le->next) {
     for(le = l->head; le; le = le->next) {
       struct Curl_hash_element *he = le->ptr;
       struct Curl_hash_element *he = le->ptr;
@@ -204,13 +219,13 @@ Curl_hash_apply(Curl_hash *h, void *user,
 void
 void
 Curl_hash_destroy(struct Curl_hash *h)
 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->size = 0;
   h->slots = 0;
   h->slots = 0;
 }
 }
@@ -235,7 +250,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
   struct Curl_llist *list;
   struct Curl_llist *list;
   int i;
   int i;
 
 
-  if(!h)
+  if(!h || !h->table)
     return;
     return;
 
 
   for(i = 0; i < h->slots; ++i) {
   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;
   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 */
   /* Get the next element in the current list, if any */
   if(iter->current_element)
   if(iter->current_element)
     iter->current_element = iter->current_element->next;
     iter->current_element = iter->current_element->next;

+ 6 - 6
Utilities/cmcurl/lib/hash.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * 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;
   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);
 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);
 int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);

+ 1 - 1
Utilities/cmcurl/lib/hostcheck.c

@@ -89,7 +89,7 @@ static int hostmatch(char *hostname, char *pattern)
      match. */
      match. */
   wildcard_enabled = 1;
   wildcard_enabled = 1;
   pattern_label_end = strchr(pattern, '.');
   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 ||
      pattern_wildcard > pattern_label_end ||
      strncasecompare(pattern, "xn--", 4)) {
      strncasecompare(pattern, "xn--", 4)) {
     wildcard_enabled = 0;
     wildcard_enabled = 0;

+ 23 - 8
Utilities/cmcurl/lib/hostip.c

@@ -507,9 +507,6 @@ static struct Curl_addrinfo *get_localhost(int port)
   struct sockaddr_in sa;
   struct sockaddr_in sa;
   unsigned int ipv4;
   unsigned int ipv4;
   unsigned short port16 = (unsigned short)(port & 0xffff);
   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 to clear the sa.sin_zero field */
   memset(&sa, 0, sizeof(sa));
   memset(&sa, 0, sizeof(sa));
@@ -519,6 +516,9 @@ static struct Curl_addrinfo *get_localhost(int port)
     return NULL;
     return NULL;
   memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4));
   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_flags     = 0;
   ca->ai_family    = AF_INET;
   ca->ai_family    = AF_INET;
   ca->ai_socktype  = SOCK_STREAM;
   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 */
   enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   *entry = NULL;
   *entry = NULL;
+#ifndef CURL_DISABLE_DOH
   conn->bits.doh = FALSE; /* default is not */
   conn->bits.doh = FALSE; /* default is not */
+#else
+  (void)allowDOH;
+#endif
 
 
   if(data->share)
   if(data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
     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;
     struct Curl_addrinfo *addr = NULL;
     int respwait = 0;
     int respwait = 0;
+#if !defined(CURL_DISABLE_DOH) || !defined(USE_RESOLVE_ON_IPS)
     struct in_addr in;
     struct in_addr in;
+#endif
+#ifndef CURL_DISABLE_DOH
 #ifndef USE_RESOLVE_ON_IPS
 #ifndef USE_RESOLVE_ON_IPS
     const
     const
 #endif
 #endif
       bool ipnum = FALSE;
       bool ipnum = FALSE;
+#endif
 
 
     /* notify the resolver start callback */
     /* notify the resolver start callback */
     if(data->set.resolver_start) {
     if(data->set.resolver_start) {
@@ -686,6 +694,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
 #endif /* ENABLE_IPV6 */
 #endif /* ENABLE_IPV6 */
 
 
 #else /* if USE_RESOLVE_ON_IPS */
 #else /* if USE_RESOLVE_ON_IPS */
+#ifndef CURL_DISABLE_DOH
     /* First check if this is an IPv4 address string */
     /* First check if this is an IPv4 address string */
     if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
     if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
       /* This is a dotted IP address 123.123.123.123-style */
       /* 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;
         ipnum = TRUE;
     }
     }
 #endif /* ENABLE_IPV6 */
 #endif /* ENABLE_IPV6 */
+#endif /* CURL_DISABLE_DOH */
 
 
 #endif /* !USE_RESOLVE_ON_IPS */
 #endif /* !USE_RESOLVE_ON_IPS */
 
 
@@ -708,8 +718,10 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
 
 
       if(strcasecompare(hostname, "localhost"))
       if(strcasecompare(hostname, "localhost"))
         addr = get_localhost(port);
         addr = get_localhost(port);
+#ifndef CURL_DISABLE_DOH
       else if(allowDOH && data->set.doh && !ipnum)
       else if(allowDOH && data->set.doh && !ipnum)
         addr = Curl_doh(data, hostname, port, &respwait);
         addr = Curl_doh(data, hostname, port, &respwait);
+#endif
       else {
       else {
         /* Check what IP specifics the app has requested and if we can provide
         /* Check what IP specifics the app has requested and if we can provide
          * it. If not, bail out. */
          * 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)
 #if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
   (void)dns;
   (void)dns;
 #endif
 #endif
-
+#ifndef CURL_DISABLE_DOH
   if(data->conn->bits.doh)
   if(data->conn->bits.doh)
     return Curl_doh_is_resolved(data, dns);
     return Curl_doh_is_resolved(data, dns);
+#endif
   return Curl_resolver_is_resolved(data, dns);
   return Curl_resolver_is_resolved(data, dns);
 }
 }
 
 
@@ -1220,10 +1233,12 @@ int Curl_resolv_getsock(struct Curl_easy *data,
                         curl_socket_t *socks)
                         curl_socket_t *socks)
 {
 {
 #ifdef CURLRES_ASYNCH
 #ifdef CURLRES_ASYNCH
+#ifndef CURL_DISABLE_DOH
   if(data->conn->bits.doh)
   if(data->conn->bits.doh)
     /* nothing to wait for during DoH resolve, those handles have their own
     /* nothing to wait for during DoH resolve, those handles have their own
        sockets */
        sockets */
     return GETSOCK_BLANK;
     return GETSOCK_BLANK;
+#endif
   return Curl_resolver_getsock(data, socks);
   return Curl_resolver_getsock(data, socks);
 #else
 #else
   (void)data;
   (void)data;

+ 2 - 2
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,
 void Curl_resolv_unlock(struct Curl_easy *data,
                         struct Curl_dns_entry *dns);
                         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 */
 /* prune old entries from the DNS cache */
 void Curl_hostcache_prune(struct Curl_easy *data);
 void Curl_hostcache_prune(struct Curl_easy *data);

+ 41 - 48
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;
     pwd = data->state.aptr.passwd;
   }
   }
 
 
-  out = aprintf("%s:%s", user, pwd ? pwd : "");
+  out = aprintf("%s:%s", user ? user : "", pwd ? pwd : "");
   if(!out)
   if(!out)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
@@ -1153,7 +1153,6 @@ static bool http_should_fail(struct Curl_easy *data)
   return data->state.authproblem;
   return data->state.authproblem;
 }
 }
 
 
-#ifndef USE_HYPER
 /*
 /*
  * readmoredata() is a "fread() emulation" to provide POST and/or request
  * 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
  * 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;
   return result;
 }
 }
 
 
-#endif
-
 /* end of the add_buffer functions */
 /* end of the add_buffer functions */
 /* ------------------------------------------------------------------------- */
 /* ------------------------------------------------------------------------- */
 
 
@@ -2375,6 +2372,9 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
 #ifndef USE_HYPER
 #ifndef USE_HYPER
   /* Hyper always handles the body separately */
   /* Hyper always handles the body separately */
   curl_off_t included_body = 0;
   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
 #endif
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   struct HTTP *http = data->req.p.http;
   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 */
     /* issue the request */
     result = Curl_buffer_send(r, data, &data->info.request_size, 0,
     result = Curl_buffer_send(r, data, &data->info.request_size, 0,
                               FIRSTSOCKET);
                               FIRSTSOCKET);
-
     if(result)
     if(result)
       failf(data, "Failed sending HTTP request");
       failf(data, "Failed sending HTTP request");
     else
     else
@@ -2902,20 +2901,6 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
                               bool *done)
                               bool *done)
 {
 {
   struct SingleRequest *k = &data->req;
   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(data->req.newurl) {
     if(conn->bits.close) {
     if(conn->bits.close) {
@@ -3326,7 +3311,7 @@ checkhttpprefix(struct Curl_easy *data,
 #ifdef CURL_DOES_CONVERSIONS
 #ifdef CURL_DOES_CONVERSIONS
   /* convert from the network encoding using a scratch area */
   /* convert from the network encoding using a scratch area */
   char *scratch = strdup(s);
   char *scratch = strdup(s);
-  if(NULL == scratch) {
+  if(!scratch) {
     failf(data, "Failed to allocate memory for conversion!");
     failf(data, "Failed to allocate memory for conversion!");
     return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
     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
 #ifdef CURL_DOES_CONVERSIONS
   /* convert from the network encoding using a scratch area */
   /* convert from the network encoding using a scratch area */
   char *scratch = strdup(s);
   char *scratch = strdup(s);
-  if(NULL == scratch) {
+  if(!scratch) {
     failf(data, "Failed to allocate memory for conversion!");
     failf(data, "Failed to allocate memory for conversion!");
     return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
     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;
   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.
  * 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.
       /* 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 we are closing the connection it may result auth failure. */
 #if defined(USE_NTLM)
 #if defined(USE_NTLM)
@@ -4137,31 +4151,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
              reason */
              reason */
           *stop_reading = TRUE;
           *stop_reading = TRUE;
 #endif
 #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
         /* If max download size is *zero* (nothing) we already have
            nothing and can safely return ok now!  But for HTTP/2, we'd
            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
         /* 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
            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");
           failf(data, "Unsupported response code in HTTP response");
           return CURLE_UNSUPPORTED_PROTOCOL;
           return CURLE_UNSUPPORTED_PROTOCOL;
         }
         }

+ 2 - 4
Utilities/cmcurl/lib/http.h

@@ -54,15 +54,11 @@ char *Curl_copy_header_value(const char *header);
 char *Curl_checkProxyheaders(struct Curl_easy *data,
 char *Curl_checkProxyheaders(struct Curl_easy *data,
                              const struct connectdata *conn,
                              const struct connectdata *conn,
                              const char *thisheader);
                              const char *thisheader);
-#ifndef USE_HYPER
 CURLcode Curl_buffer_send(struct dynbuf *in,
 CURLcode Curl_buffer_send(struct dynbuf *in,
                           struct Curl_easy *data,
                           struct Curl_easy *data,
                           curl_off_t *bytes_written,
                           curl_off_t *bytes_written,
                           curl_off_t included_body_bytes,
                           curl_off_t included_body_bytes,
                           int socketindex);
                           int socketindex);
-#else
-#define Curl_buffer_send(a,b,c,d,e) CURLE_OK
-#endif
 
 
 CURLcode Curl_add_timecondition(struct Curl_easy *data,
 CURLcode Curl_add_timecondition(struct Curl_easy *data,
 #ifndef USE_HYPER
 #ifndef USE_HYPER
@@ -289,6 +285,8 @@ struct http_conn {
 #endif
 #endif
 };
 };
 
 
+CURLcode Curl_http_size(struct Curl_easy *data);
+
 CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                                      struct connectdata *conn,
                                      struct connectdata *conn,
                                      ssize_t *nread,
                                      ssize_t *nread,

+ 25 - 6
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;
   const struct http_conn *c = &conn->proto.httpc;
   struct SingleRequest *k = &data->req;
   struct SingleRequest *k = &data->req;
   int bitmap = GETSOCK_BLANK;
   int bitmap = GETSOCK_BLANK;
+  struct HTTP *stream = data->req.p.http;
 
 
   sock[0] = conn->sock[FIRSTSOCKET];
   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 */
        frame so we should always be ready for one */
     bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
     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);
     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
 
 
   return bitmap;
   return bitmap;
@@ -500,10 +505,13 @@ static int set_transfer_url(struct Curl_easy *data,
                             struct curl_pushheaders *hp)
                             struct curl_pushheaders *hp)
 {
 {
   const char *v;
   const char *v;
-  CURLU *u = curl_url();
   CURLUcode uc;
   CURLUcode uc;
   char *url = NULL;
   char *url = NULL;
   int rc = 0;
   int rc = 0;
+  CURLU *u = curl_url();
+
+  if(!u)
+    return 5;
 
 
   v = curl_pushheader_byname(hp, ":scheme");
   v = curl_pushheader_byname(hp, ":scheme");
   if(v) {
   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);
       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;
     return len;
   }
   }
 
 

+ 16 - 5
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;
   char *signed_headers = NULL;
   Curl_HttpReq httpreq;
   Curl_HttpReq httpreq;
   const char *method;
   const char *method;
+  size_t post_data_len;
   const char *post_data = data->set.postfields ? data->set.postfields : "";
   const char *post_data = data->set.postfields ? data->set.postfields : "";
   unsigned char sha_hash[32];
   unsigned char sha_hash[32];
   char sha_hex[65];
   char sha_hex[65];
@@ -281,8 +282,15 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
     goto fail;
     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));
   sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
 
 
   Curl_http_method(data, conn, &method, &httpreq);
   Curl_http_method(data, conn, &method, &httpreq);
@@ -315,13 +323,16 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
     goto fail;
     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));
   sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
 
 
   /*
   /*
    * Google allow to use rsa key instead of HMAC, so this code might change
    * 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 */
   str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
                               "%s\n" /* RequestDateTime */
                               "%s\n" /* RequestDateTime */

+ 6 - 5
Utilities/cmcurl/lib/http_ntlm.c

@@ -198,6 +198,12 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
 #endif
 #endif
 
 
   Curl_bufref_init(&ntlmmsg);
   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) {
   switch(*state) {
   case NTLMSTATE_TYPE1:
   case NTLMSTATE_TYPE1:
   default: /* for the weird cases we (re)start here */
   default: /* for the weird cases we (re)start here */
@@ -246,11 +252,6 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
     }
     }
     break;
     break;
 
 
-  case NTLMSTATE_TYPE3:
-    /* connection is already authenticated,
-     * don't send a header in future requests */
-    *state = NTLMSTATE_LAST;
-    /* FALLTHROUGH */
   case NTLMSTATE_LAST:
   case NTLMSTATE_LAST:
     Curl_safefree(*allocuserpwd);
     Curl_safefree(*allocuserpwd);
     authp->done = TRUE;
     authp->done = TRUE;

+ 85 - 25
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 http_connect_state *s;
   struct connectdata *conn = data->conn;
   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) {
   if(!reinit) {
     CURLcode result;
     CURLcode result;
     DEBUGASSERT(!conn->connect_state);
     DEBUGASSERT(!conn->connect_state);
@@ -198,18 +202,25 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit)
   return CURLE_OK;
   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 connectdata *conn = data->conn;
   struct http_connect_state *s = conn->connect_state;
   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;
     s->tunnel_state = TUNNEL_EXIT;
     Curl_dyn_free(&s->rcvbuf);
     Curl_dyn_free(&s->rcvbuf);
     Curl_dyn_free(&s->req);
     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;
     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!");
     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
         /* This only happens if we've looped here due to authentication
            reasons, and we don't really use the newly cloned URL here
            reasons, and we don't really use the newly cloned URL here
            then. Just free() it. */
            then. Just free() it. */
-      free(data->req.newurl);
-      data->req.newurl = NULL;
+      Curl_safefree(data->req.newurl);
 
 
       /* initialize send-buffer */
       /* initialize send-buffer */
       Curl_dyn_init(req, DYN_HTTP_REQUEST);
       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) {
     if(s->close_connection && data->req.newurl) {
       conn->bits.proxy_connect_closed = TRUE;
       conn->bits.proxy_connect_closed = TRUE;
       infof(data, "Connect me again please");
       infof(data, "Connect me again please");
-      connect_done(data);
+      Curl_connect_done(data);
     }
     }
     else {
     else {
       free(data->req.newurl);
       free(data->req.newurl);
       data->req.newurl = NULL;
       data->req.newurl = NULL;
       /* failure, close this connection to avoid re-use */
       /* failure, close this connection to avoid re-use */
       streamclose(conn, "proxy CONNECT failure");
       streamclose(conn, "proxy CONNECT failure");
-      Curl_closesocket(data, conn, conn->sock[sockindex]);
-      conn->sock[sockindex] = CURL_SOCKET_BAD;
     }
     }
 
 
     /* to back to init state */
     /* to back to init state */
@@ -735,6 +743,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
       io = hyper_io_new();
       io = hyper_io_new();
       if(!io) {
       if(!io) {
         failf(data, "Couldn't create hyper IO");
         failf(data, "Couldn't create hyper IO");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
       /* tell Hyper how to read/write network data */
       /* tell Hyper how to read/write network data */
@@ -750,6 +759,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
         h->exec = hyper_executor_new();
         h->exec = hyper_executor_new();
         if(!h->exec) {
         if(!h->exec) {
           failf(data, "Couldn't create hyper executor");
           failf(data, "Couldn't create hyper executor");
+          result = CURLE_OUT_OF_MEMORY;
           goto error;
           goto error;
         }
         }
       }
       }
@@ -757,6 +767,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
       options = hyper_clientconn_options_new();
       options = hyper_clientconn_options_new();
       if(!options) {
       if(!options) {
         failf(data, "Couldn't create hyper client options");
         failf(data, "Couldn't create hyper client options");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
 
 
@@ -767,6 +778,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
       handshake = hyper_clientconn_handshake(io, options);
       handshake = hyper_clientconn_handshake(io, options);
       if(!handshake) {
       if(!handshake) {
         failf(data, "Couldn't create hyper client handshake");
         failf(data, "Couldn't create hyper client handshake");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
       io = NULL;
       io = NULL;
@@ -774,6 +786,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
 
 
       if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
       if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
         failf(data, "Couldn't hyper_executor_push the handshake");
         failf(data, "Couldn't hyper_executor_push the handshake");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
       handshake = NULL; /* ownership passed on */
       handshake = NULL; /* ownership passed on */
@@ -781,6 +794,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
       task = hyper_executor_poll(h->exec);
       task = hyper_executor_poll(h->exec);
       if(!task) {
       if(!task) {
         failf(data, "Couldn't hyper_executor_poll the handshake");
         failf(data, "Couldn't hyper_executor_poll the handshake");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
 
 
@@ -789,14 +803,24 @@ static CURLcode CONNECT(struct Curl_easy *data,
       req = hyper_request_new();
       req = hyper_request_new();
       if(!req) {
       if(!req) {
         failf(data, "Couldn't hyper_request_new");
         failf(data, "Couldn't hyper_request_new");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
       if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
       if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
                                   strlen("CONNECT"))) {
                                   strlen("CONNECT"))) {
         failf(data, "error setting method");
         failf(data, "error setting method");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         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,
       result = CONNECT_host(data, conn, hostname, remote_port,
                             &hostheader, &host);
                             &hostheader, &host);
       if(result)
       if(result)
@@ -806,6 +830,16 @@ static CURLcode CONNECT(struct Curl_easy *data,
                                strlen(hostheader))) {
                                strlen(hostheader))) {
         failf(data, "error setting path");
         failf(data, "error setting path");
         result = CURLE_OUT_OF_MEMORY;
         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 */
       /* Setup the proxy-authorization header, if any */
       result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
       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,
          (HYPERE_OK != hyper_request_set_version(req,
                                                  HYPER_HTTP_VERSION_1_0))) {
                                                  HYPER_HTTP_VERSION_1_0))) {
         failf(data, "error setting HTTP version");
         failf(data, "error setting HTTP version");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
 
 
       headers = hyper_request_headers(req);
       headers = hyper_request_headers(req);
       if(!headers) {
       if(!headers) {
         failf(data, "hyper_request_headers");
         failf(data, "hyper_request_headers");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         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") &&
       if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
          data->set.str[STRING_USERAGENT]) {
          data->set.str[STRING_USERAGENT]) {
@@ -843,26 +885,33 @@ static CURLcode CONNECT(struct Curl_easy *data,
                                data->set.str[STRING_USERAGENT]);
                                data->set.str[STRING_USERAGENT]);
         if(result)
         if(result)
           goto error;
           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;
           goto error;
         Curl_dyn_free(&ua);
         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;
         goto error;
 
 
       sendtask = hyper_clientconn_send(client, req);
       sendtask = hyper_clientconn_send(client, req);
       if(!sendtask) {
       if(!sendtask) {
         failf(data, "hyper_clientconn_send");
         failf(data, "hyper_clientconn_send");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
 
 
       if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
       if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
         failf(data, "Couldn't hyper_executor_push the send");
         failf(data, "Couldn't hyper_executor_push the send");
+        result = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
 
 
@@ -875,8 +924,11 @@ static CURLcode CONNECT(struct Curl_easy *data,
           if(error)
           if(error)
             hypererr = hyper_task_value(task);
             hypererr = hyper_task_value(task);
           hyper_task_free(task);
           hyper_task_free(task);
-          if(error)
+          if(error) {
+            /* this could probably use a better error code? */
+            result = CURLE_OUT_OF_MEMORY;
             goto error;
             goto error;
+          }
         }
         }
       } while(task);
       } while(task);
       s->tunnel_state = TUNNEL_CONNECT;
       s->tunnel_state = TUNNEL_CONNECT;
@@ -904,20 +956,28 @@ static CURLcode CONNECT(struct Curl_easy *data,
         h->write_waker = NULL;
         h->write_waker = NULL;
       }
       }
     }
     }
-      /* FALLTHROUGH */
+    break;
+
     default:
     default:
       break;
       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);
   } while(data->req.newurl);
 
 
   result = CURLE_OK;
   result = CURLE_OK;
   if(s->tunnel_state == TUNNEL_COMPLETE) {
   if(s->tunnel_state == TUNNEL_COMPLETE) {
-    data->info.httpproxycode = data->req.httpcode;
     if(data->info.httpproxycode/100 != 2) {
     if(data->info.httpproxycode/100 != 2) {
       if(conn->bits.close && data->req.newurl) {
       if(conn->bits.close && data->req.newurl) {
         conn->bits.proxy_connect_closed = TRUE;
         conn->bits.proxy_connect_closed = TRUE;
         infof(data, "Connect me again please");
         infof(data, "Connect me again please");
-        connect_done(data);
+        Curl_connect_done(data);
       }
       }
       else {
       else {
         free(data->req.newurl);
         free(data->req.newurl);
@@ -991,7 +1051,7 @@ CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
   result = CONNECT(data, sockindex, hostname, remote_port);
   result = CONNECT(data, sockindex, hostname, remote_port);
 
 
   if(result || Curl_connect_complete(conn))
   if(result || Curl_connect_complete(conn))
-    connect_done(data);
+    Curl_connect_done(data);
 
 
   return result;
   return result;
 }
 }

+ 2 - 1
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_complete(struct connectdata *conn);
 bool Curl_connect_ongoing(struct connectdata *conn);
 bool Curl_connect_ongoing(struct connectdata *conn);
 int Curl_connect_getsock(struct connectdata *conn);
 int Curl_connect_getsock(struct connectdata *conn);
+void Curl_connect_done(struct Curl_easy *data);
 
 
 #else
 #else
 #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
 #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_complete(x) CURLE_OK
 #define Curl_connect_ongoing(x) FALSE
 #define Curl_connect_ongoing(x) FALSE
 #define Curl_connect_getsock(x) 0
 #define Curl_connect_getsock(x) 0
+#define Curl_connect_done(x)
 #endif
 #endif
 
 
 void Curl_connect_free(struct Curl_easy *data);
 void Curl_connect_free(struct Curl_easy *data);
-void Curl_connect_done(struct Curl_easy *data);
 
 
 /* struct for HTTP CONNECT state data */
 /* struct for HTTP CONNECT state data */
 struct http_connect_state {
 struct http_connect_state {

+ 2 - 2
Utilities/cmcurl/lib/if2ip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * 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) {
   if(getifaddrs(&head) >= 0) {
     for(iface = head; iface != NULL; iface = iface->ifa_next) {
     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(iface->ifa_addr->sa_family == af) {
           if(strcasecompare(iface->ifa_name, interf)) {
           if(strcasecompare(iface->ifa_name, interf)) {
             void *addr;
             void *addr;

+ 84 - 73
Utilities/cmcurl/lib/imap.c

@@ -78,6 +78,7 @@
 #include "multiif.h"
 #include "multiif.h"
 #include "url.h"
 #include "url.h"
 #include "strcase.h"
 #include "strcase.h"
+#include "bufref.h"
 #include "curl_sasl.h"
 #include "curl_sasl.h"
 #include "warnless.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,
 static CURLcode imap_setup_connection(struct Curl_easy *data,
                                       struct connectdata *conn);
                                       struct connectdata *conn);
 static char *imap_atom(const char *str, bool escape_only);
 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_options(struct connectdata *conn);
 static CURLcode imap_parse_url_path(struct Curl_easy *data);
 static CURLcode imap_parse_url_path(struct Curl_easy *data);
 static CURLcode imap_parse_custom_request(struct Curl_easy *data);
 static CURLcode imap_parse_custom_request(struct Curl_easy *data);
 static CURLcode imap_perform_authenticate(struct Curl_easy *data,
 static CURLcode imap_perform_authenticate(struct Curl_easy *data,
-                                          struct connectdata *conn,
                                           const char *mech,
                                           const char *mech,
-                                          const char *initresp);
+                                          const struct bufref *initresp);
 static CURLcode imap_continue_authenticate(struct Curl_easy *data,
 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.
  * IMAP protocol handler.
@@ -180,12 +181,15 @@ const struct Curl_handler Curl_handler_imaps = {
 /* SASL parameters for the imap protocol */
 /* SASL parameters for the imap protocol */
 static const struct SASLproto saslimap = {
 static const struct SASLproto saslimap = {
   "imap",                     /* The service name */
   "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_perform_authenticate,  /* Send authentication command */
   imap_continue_authenticate, /* Send authentication continuation */
   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, "EXPUNGE") &&
            !strcasecompare(imap->custom, "LSUB") &&
            !strcasecompare(imap->custom, "LSUB") &&
            !strcasecompare(imap->custom, "UID") &&
            !strcasecompare(imap->custom, "UID") &&
+           !strcasecompare(imap->custom, "GETQUOTAROOT") &&
            !strcasecompare(imap->custom, "NOOP")))
            !strcasecompare(imap->custom, "NOOP")))
           return FALSE;
           return FALSE;
         break;
         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
   /* 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
      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
      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] == '+') ||
   if(imap && !imap->custom && ((len == 3 && line[0] == '+') ||
      (len >= 2 && !memcmp("+ ", line, 2)))) {
      (len >= 2 && !memcmp("+ ", line, 2)))) {
     switch(imapc->state) {
     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.
  * 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) {
   if(len > 2) {
     /* Find the start of the message */
     /* Find the start of the message */
     len -= 2;
     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 */
     /* Find the end of the message */
-    for(; len--;)
+    while(len--)
       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
          message[len] != '\t')
          message[len] != '\t')
         break;
         break;
 
 
     /* Terminate the message */
     /* Terminate the message */
-    if(++len) {
-      message[len] = '\0';
-    }
+    message[++len] = '\0';
+    Curl_bufref_set(out, message, len, NULL);
   }
   }
   else
   else
     /* junk input => zero length output */
     /* 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 */
   imapc->tls_supported = FALSE;           /* Clear the TLS capability */
 
 
   /* Send the CAPABILITY command */
   /* Send the CAPABILITY command */
-  result = imap_sendf(data, conn, "CAPABILITY");
+  result = imap_sendf(data, "CAPABILITY");
 
 
   if(!result)
   if(!result)
     state(data, IMAP_CAPABILITY);
     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.
  * 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 */
   /* Send the STARTTLS command */
-  CURLcode result = imap_sendf(data, conn, "STARTTLS");
+  CURLcode result = imap_sendf(data, "STARTTLS");
 
 
   if(!result)
   if(!result)
     state(data, IMAP_STARTTLS);
     state(data, IMAP_STARTTLS);
@@ -516,7 +518,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
   passwd = imap_atom(conn->passwd, false);
   passwd = imap_atom(conn->passwd, false);
 
 
   /* Send the LOGIN command */
   /* 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 : "");
                       passwd ? passwd : "");
 
 
   free(user);
   free(user);
@@ -536,20 +538,19 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
  * SASL authentication mechanism.
  * SASL authentication mechanism.
  */
  */
 static CURLcode imap_perform_authenticate(struct Curl_easy *data,
 static CURLcode imap_perform_authenticate(struct Curl_easy *data,
-                                          struct connectdata *conn,
                                           const char *mech,
                                           const char *mech,
-                                          const char *initresp)
+                                          const struct bufref *initresp)
 {
 {
   CURLcode result = CURLE_OK;
   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 */
     /* 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 {
   else {
     /* Send the AUTHENTICATE command */
     /* Send the AUTHENTICATE command */
-    result = imap_sendf(data, conn, "AUTHENTICATE %s", mech);
+    result = imap_sendf(data, "AUTHENTICATE %s", mech);
   }
   }
 
 
   return result;
   return result;
@@ -559,15 +560,34 @@ static CURLcode imap_perform_authenticate(struct Curl_easy *data,
  *
  *
  * imap_continue_authenticate()
  * imap_continue_authenticate()
  *
  *
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
  */
  */
 static CURLcode imap_continue_authenticate(struct Curl_easy *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 */
   /* 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(!result) {
     if(progress == SASL_INPROGRESS)
     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)
 static CURLcode imap_perform_list(struct Curl_easy *data)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  struct connectdata *conn = data->conn;
   struct IMAP *imap = data->req.p.imap;
   struct IMAP *imap = data->req.p.imap;
 
 
   if(imap->custom)
   if(imap->custom)
     /* Send the custom request */
     /* 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 : "");
                         imap->custom_params ? imap->custom_params : "");
   else {
   else {
     /* Make sure the mailbox is in the correct atom format if necessary */
     /* 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;
       return CURLE_OUT_OF_MEMORY;
 
 
     /* Send the LIST command */
     /* Send the LIST command */
-    result = imap_sendf(data, conn, "LIST \"%s\" *", mailbox);
+    result = imap_sendf(data, "LIST \"%s\" *", mailbox);
 
 
     free(mailbox);
     free(mailbox);
   }
   }
@@ -678,7 +696,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
   /* Send the SELECT command */
   /* Send the SELECT command */
-  result = imap_sendf(data, conn, "SELECT %s", mailbox);
+  result = imap_sendf(data, "SELECT %s", mailbox);
 
 
   free(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.
  * 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;
   CURLcode result = CURLE_OK;
   struct IMAP *imap = data->req.p.imap;
   struct IMAP *imap = data->req.p.imap;
@@ -704,21 +721,21 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data,
 
 
     /* Send the FETCH command */
     /* Send the FETCH command */
     if(imap->partial)
     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->uid, imap->section ? imap->section : "",
                           imap->partial);
                           imap->partial);
     else
     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 : "");
                           imap->uid, imap->section ? imap->section : "");
   }
   }
   else if(imap->mindex) {
   else if(imap->mindex) {
     /* Send the FETCH command */
     /* Send the FETCH command */
     if(imap->partial)
     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->mindex, imap->section ? imap->section : "",
                           imap->partial);
                           imap->partial);
     else
     else
-      result = imap_sendf(data, conn, "FETCH %s BODY[%s]",
+      result = imap_sendf(data, "FETCH %s BODY[%s]",
                           imap->mindex, imap->section ? imap->section : "");
                           imap->mindex, imap->section ? imap->section : "");
   }
   }
   else {
   else {
@@ -740,7 +757,6 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data,
 static CURLcode imap_perform_append(struct Curl_easy *data)
 static CURLcode imap_perform_append(struct Curl_easy *data)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  struct connectdata *conn = data->conn;
   struct IMAP *imap = data->req.p.imap;
   struct IMAP *imap = data->req.p.imap;
   char *mailbox;
   char *mailbox;
 
 
@@ -791,7 +807,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
   /* Send the APPEND command */
   /* Send the APPEND command */
-  result = imap_sendf(data, conn,
+  result = imap_sendf(data,
                       "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
                       "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
                       mailbox, data->state.infilesize);
                       mailbox, data->state.infilesize);
 
 
@@ -809,8 +825,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
  *
  *
  * Sends a SEARCH command.
  * 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;
   CURLcode result = CURLE_OK;
   struct IMAP *imap = data->req.p.imap;
   struct IMAP *imap = data->req.p.imap;
@@ -822,7 +837,7 @@ static CURLcode imap_perform_search(struct Curl_easy *data,
   }
   }
 
 
   /* Send the SEARCH command */
   /* Send the SEARCH command */
-  result = imap_sendf(data, conn, "SEARCH %s", imap->query);
+  result = imap_sendf(data, "SEARCH %s", imap->query);
 
 
   if(!result)
   if(!result)
     state(data, IMAP_SEARCH);
     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.
  * 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 */
   /* Send the LOGOUT command */
-  CURLcode result = imap_sendf(data, conn, "LOGOUT");
+  CURLcode result = imap_sendf(data, "LOGOUT");
 
 
   if(!result)
   if(!result)
     state(data, IMAP_LOGOUT);
     state(data, IMAP_LOGOUT);
@@ -938,7 +952,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
     /* PREAUTH is not compatible with STARTTLS. */
     /* PREAUTH is not compatible with STARTTLS. */
     if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
     if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
       /* Switch to TLS connection now */
       /* Switch to TLS connection now */
-      result = imap_perform_starttls(data, conn);
+      result = imap_perform_starttls(data);
     }
     }
     else if(data->set.use_ssl <= CURLUSESSL_TRY)
     else if(data->set.use_ssl <= CURLUSESSL_TRY)
       result = imap_perform_authentication(data, conn);
       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 */
   (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)
   if(!result)
     switch(progress) {
     switch(progress) {
     case SASL_DONE:
     case SASL_DONE:
@@ -1094,9 +1108,9 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
       if(imap->custom)
       if(imap->custom)
         result = imap_perform_list(data);
         result = imap_perform_list(data);
       else if(imap->query)
       else if(imap->query)
-        result = imap_perform_search(data, conn);
+        result = imap_perform_search(data);
       else
       else
-        result = imap_perform_fetch(data, conn);
+        result = imap_perform_fetch(data);
     }
     }
   }
   }
   else {
   else {
@@ -1441,7 +1455,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done)
 
 
   /* Set the default preferred authentication type and mechanism */
   /* Set the default preferred authentication type and mechanism */
   imapc->preftype = IMAP_TYPE_ANY;
   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);
   Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
   /* Initialise the pingpong layer */
   /* Initialise the pingpong layer */
@@ -1568,10 +1582,10 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
     result = imap_perform_list(data);
     result = imap_perform_list(data);
   else if(!imap->custom && selected && (imap->uid || imap->mindex))
   else if(!imap->custom && selected && (imap->uid || imap->mindex))
     /* FETCH from the same mailbox */
     /* FETCH from the same mailbox */
-    result = imap_perform_fetch(data, conn);
+    result = imap_perform_fetch(data);
   else if(!imap->custom && selected && imap->query)
   else if(!imap->custom && selected && imap->query)
     /* SEARCH the current mailbox */
     /* SEARCH the current mailbox */
-    result = imap_perform_search(data, conn);
+    result = imap_perform_search(data);
   else if(imap->mailbox && !selected &&
   else if(imap->mailbox && !selected &&
          (imap->custom || imap->uid || imap->mindex || imap->query))
          (imap->custom || imap->uid || imap->mindex || imap->query))
     /* SELECT the mailbox */
     /* 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
   /* The IMAP session may or may not have been allocated/setup at this
      point! */
      point! */
   if(!dead_connection && conn->bits.protoconnstart) {
   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 */
       (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.
  * 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;
   CURLcode result = CURLE_OK;
-  struct imap_conn *imapc = &conn->proto.imapc;
+  struct imap_conn *imapc = &data->conn->proto.imapc;
 
 
   DEBUGASSERT(fmt);
   DEBUGASSERT(fmt);
 
 
   /* Calculate the tag based on the connection ID and command ID */
   /* Calculate the tag based on the connection ID and command ID */
   msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
   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);
             (++imapc->cmdid)%1000);
 
 
   /* start with a blank buffer */
   /* 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;
   struct imap_conn *imapc = &conn->proto.imapc;
   const char *ptr = conn->options;
   const char *ptr = conn->options;
 
 
-  imapc->sasl.resetprefs = TRUE;
-
   while(!result && ptr && *ptr) {
   while(!result && ptr && *ptr) {
     const char *key = ptr;
     const char *key = ptr;
     const char *value;
     const char *value;

+ 3 - 3
Utilities/cmcurl/lib/inet_pton.c

@@ -1,6 +1,6 @@
 /* This is from the BIND 4.9.4 release, modified to compile by itself */
 /* 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
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * 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);
     pch = strchr((xdigits = xdigits_l), ch);
     if(!pch)
     if(!pch)
       pch = strchr((xdigits = xdigits_u), ch);
       pch = strchr((xdigits = xdigits_u), ch);
-    if(pch != NULL) {
+    if(pch) {
       val <<= 4;
       val <<= 4;
       val |= (pch - xdigits);
       val |= (pch - xdigits);
       if(++saw_xdigit > 4)
       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 >> 8) & 0xff);
     *tp++ = (unsigned char) (val & 0xff);
     *tp++ = (unsigned char) (val & 0xff);
   }
   }
-  if(colonp != NULL) {
+  if(colonp) {
     /*
     /*
      * Since some memmove()'s erroneously fail to handle
      * Since some memmove()'s erroneously fail to handle
      * overlapping regions, we'll do the shift by hand.
      * overlapping regions, we'll do the shift by hand.

+ 4 - 4
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",
   "GSSAPI",
   sizeof(gss_ctx_id_t),
   sizeof(gss_ctx_id_t),
   krb5_init,
   krb5_init,
@@ -684,7 +684,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
   (void) data;
   (void) data;
 
 
   if(!conn->mech)
   if(!conn->mech)
-    /* not inititalized, return error */
+    /* not initialized, return error */
     return -1;
     return -1;
 
 
   DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
   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));
   code = ftp_send_command(data, "PROT %c", level_to_char(level));
 
 
   if(code < 0)
   if(code < 0)
@@ -880,7 +880,7 @@ Curl_sec_login(struct Curl_easy *data, struct connectdata *conn)
 void
 void
 Curl_sec_end(struct connectdata *conn)
 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);
     conn->mech->end(conn->app_data);
   free(conn->app_data);
   free(conn->app_data);
   conn->app_data = NULL;
   conn->app_data = NULL;

+ 6 - 1
Utilities/cmcurl/lib/ldap.c

@@ -464,6 +464,11 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
 #endif
 #endif
 #endif /* CURL_LDAP_USE_SSL */
 #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 {
   else {
     server = ldap_init(host, (int)conn->port);
     server = ldap_init(host, (int)conn->port);
     if(!server) {
     if(!server) {
@@ -590,7 +595,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
       attr_len = strlen(attr);
       attr_len = strlen(attr);
 
 
       vals = ldap_get_values_len(server, entryIterator, attribute);
       vals = ldap_get_values_len(server, entryIterator, attribute);
-      if(vals != NULL) {
+      if(vals) {
         for(i = 0; (vals[i] != NULL); i++) {
         for(i = 0; (vals[i] != NULL); i++) {
           result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
           result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
           if(result) {
           if(result) {

+ 2 - 2
Utilities/cmcurl/lib/libcurl.rc

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -51,7 +51,7 @@ BEGIN
       VALUE "OriginalFilename", "libcurl.dll\0"
       VALUE "OriginalFilename", "libcurl.dll\0"
       VALUE "ProductName",      "The curl library\0"
       VALUE "ProductName",      "The curl library\0"
       VALUE "ProductVersion",   LIBCURL_VERSION "\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"
       VALUE "License",          "https://curl.se/docs/copyright.html\0"
     END
     END
   END
   END

+ 1 - 3
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;
       e->next->prev = NULL;
   }
   }
   else {
   else {
-    if(!e->prev)
-      list->head = e->next;
-    else
+    if(e->prev)
       e->prev->next = e->next;
       e->prev->next = e->next;
 
 
     if(!e->next)
     if(!e->next)

+ 13 - 4
Utilities/cmcurl/lib/md4.c

@@ -27,6 +27,7 @@
 #include "curl_md4.h"
 #include "curl_md4.h"
 #include "warnless.h"
 #include "warnless.h"
 
 
+
 #ifdef USE_OPENSSL
 #ifdef USE_OPENSSL
 #include <openssl/opensslconf.h>
 #include <openssl/opensslconf.h>
 #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
 #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
@@ -35,6 +36,13 @@
 #endif
 #endif
 #endif /* USE_OPENSSL */
 #endif /* USE_OPENSSL */
 
 
+#ifdef USE_WOLFSSL
+#include <wolfssl/options.h>
+#ifdef NO_MD4
+#define OPENSSL_NO_MD4
+#endif
+#endif
+
 #ifdef USE_MBEDTLS
 #ifdef USE_MBEDTLS
 #include <mbedtls/version.h>
 #include <mbedtls/version.h>
 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
 #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);
   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>
 #include <openssl/md4.h>
 
 
 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
 #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) {
   if(!ctx->data) {
     ctx->data = malloc(size);
     ctx->data = malloc(size);
-    if(ctx->data != NULL) {
+    if(ctx->data) {
       memcpy(ctx->data, data, size);
       memcpy(ctx->data, data, size);
       ctx->size = 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)
 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)
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
     mbedtls_md4(ctx->data, ctx->size, result);
     mbedtls_md4(ctx->data, ctx->size, result);
 #else
 #else

+ 33 - 9
Utilities/cmcurl/lib/md5.c

@@ -39,6 +39,20 @@
 #endif
 #endif
 #endif /* USE_MBEDTLS */
 #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)
 #if defined(USE_GNUTLS)
 
 
 #include <nettle/md5.h>
 #include <nettle/md5.h>
@@ -48,9 +62,10 @@
 
 
 typedef struct md5_ctx MD5_CTX;
 typedef struct md5_ctx MD5_CTX;
 
 
-static void MD5_Init(MD5_CTX *ctx)
+static CURLcode MD5_Init(MD5_CTX *ctx)
 {
 {
   md5_init(ctx);
   md5_init(ctx);
+  return CURLE_OK;
 }
 }
 
 
 static void MD5_Update(MD5_CTX *ctx,
 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);
   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 <openssl/md5.h>
 #include "curl_memory.h"
 #include "curl_memory.h"
 /* The last #include file should be: */
 /* 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;
 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)
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_md5_starts(ctx);
   (void) mbedtls_md5_starts(ctx);
 #else
 #else
   (void) mbedtls_md5_starts_ret(ctx);
   (void) mbedtls_md5_starts_ret(ctx);
 #endif
 #endif
+  return CURLE_OK;
 }
 }
 
 
 static void MD5_Update(MD5_CTX *ctx,
 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: */
 /* The last #include file should be: */
 #include "memdebug.h"
 #include "memdebug.h"
 
 
-static void MD5_Init(MD5_CTX *ctx)
+static CURLcode MD5_Init(MD5_CTX *ctx)
 {
 {
   CC_MD5_Init(ctx);
   CC_MD5_Init(ctx);
+  return CURLE_OK;
 }
 }
 
 
 static void MD5_Update(MD5_CTX *ctx,
 static void MD5_Update(MD5_CTX *ctx,
@@ -161,12 +179,13 @@ struct md5_ctx {
 };
 };
 typedef struct md5_ctx 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,
   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
   }
   }
+  return CURLE_OK;
 }
 }
 
 
 static void MD5_Update(MD5_CTX *ctx,
 static void MD5_Update(MD5_CTX *ctx,
@@ -246,7 +265,7 @@ struct md5_ctx {
 };
 };
 typedef struct md5_ctx 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_Update(MD5_CTX *ctx, const void *data, unsigned long size);
 static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
 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;
   return ptr;
 }
 }
 
 
-static void MD5_Init(MD5_CTX *ctx)
+static CURLcode MD5_Init(MD5_CTX *ctx)
 {
 {
   ctx->a = 0x67452301;
   ctx->a = 0x67452301;
   ctx->b = 0xefcdab89;
   ctx->b = 0xefcdab89;
@@ -416,6 +435,8 @@ static void MD5_Init(MD5_CTX *ctx)
 
 
   ctx->lo = 0;
   ctx->lo = 0;
   ctx->hi = 0;
   ctx->hi = 0;
+
+  return CURLE_OK;
 }
 }
 
 
 static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
 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
  * @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)
                 const size_t len)
 {
 {
   MD5_CTX ctx;
   MD5_CTX ctx;
@@ -549,6 +571,8 @@ void Curl_md5it(unsigned char *outbuffer, const unsigned char *input,
   MD5_Init(&ctx);
   MD5_Init(&ctx);
   MD5_Update(&ctx, input, curlx_uztoui(len));
   MD5_Update(&ctx, input, curlx_uztoui(len));
   MD5_Final(outbuffer, &ctx);
   MD5_Final(outbuffer, &ctx);
+
+  return CURLE_OK;
 }
 }
 
 
 struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params)
 struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params)

+ 53 - 27
Utilities/cmcurl/lib/mime.c

@@ -40,6 +40,7 @@
 #include "rand.h"
 #include "rand.h"
 #include "slist.h"
 #include "slist.h"
 #include "strcase.h"
 #include "strcase.h"
+#include "dynbuf.h"
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "curl_memory.h"
@@ -279,29 +280,52 @@ static void mimesetstate(struct mime_state *state,
 
 
 
 
 /* Escape header string into allocated memory. */
 /* 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. */
 /* 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. */
       /* Buffered data size can only be 0, 1 or 2. */
       ptr[2] = ptr[3] = '=';
       ptr[2] = ptr[3] = '=';
       i = 0;
       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;
         i |= (st->buf[st->bufbeg] & 0xFF) << 16;
         ptr[0] = base64[(i >> 18) & 0x3F];
         ptr[0] = base64[(i >> 18) & 0x3F];
         ptr[1] = base64[(i >> 12) & 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;
         cursize += 4;
         st->pos += 4;
         st->pos += 4;
-        break;
       }
       }
     }
     }
   }
   }
@@ -1865,12 +1890,12 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
       char *filename = NULL;
       char *filename = NULL;
 
 
       if(part->name) {
       if(part->name) {
-        name = escape_string(part->name);
+        name = escape_string(part->easy, part->name, strategy);
         if(!name)
         if(!name)
           ret = CURLE_OUT_OF_MEMORY;
           ret = CURLE_OUT_OF_MEMORY;
       }
       }
       if(!ret && part->filename) {
       if(!ret && part->filename) {
-        filename = escape_string(part->filename);
+        filename = escape_string(part->easy, part->filename, strategy);
         if(!filename)
         if(!filename)
           ret = CURLE_OUT_OF_MEMORY;
           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. */
 /* Mime not compiled in: define stubs for externally-referenced functions. */
 curl_mime *curl_mime_init(CURL *easy)
 curl_mime *curl_mime_init(CURL *easy)

+ 1 - 1
Utilities/cmcurl/lib/mprintf.c

@@ -858,7 +858,7 @@ static int dprintf_formatf(
       {
       {
         void *ptr;
         void *ptr;
         ptr = (void *) p->data.ptr;
         ptr = (void *) p->data.ptr;
-        if(ptr != NULL) {
+        if(ptr) {
           /* If the pointer is not NULL, write it as a %#x spec.  */
           /* If the pointer is not NULL, write it as a %#x spec.  */
           base = 16;
           base = 16;
           digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
           digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;

+ 178 - 74
Utilities/cmcurl/lib/multi.c

@@ -243,6 +243,26 @@ static void trhash_dtor(void *nada)
   (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 */
 /* make sure this socket is present in the hash for this handle */
 static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
 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)
   if(!check)
     return NULL; /* major failure */
     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 */
   /* make/add new hash entry */
   if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
   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."
  * 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;
   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))
   if(Curl_conncache_init(&multi->conn_cache, chashsize))
     goto error;
     goto error;
@@ -405,7 +420,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
 
 
   error:
   error:
 
 
-  Curl_hash_destroy(&multi->sockhash);
+  sockhash_destroy(&multi->sockhash);
   Curl_hash_destroy(&multi->hostcache);
   Curl_hash_destroy(&multi->hostcache);
   Curl_conncache_destroy(&multi->conn_cache);
   Curl_conncache_destroy(&multi->conn_cache);
   Curl_llist_destroy(&multi->msglist, NULL);
   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,
 CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
                                 struct Curl_easy *data)
                                 struct Curl_easy *data)
 {
 {
+  CURLMcode rc;
   /* First, make some basic checks that the CURLM handle is a good handle */
   /* First, make some basic checks that the CURLM handle is a good handle */
   if(!GOOD_MULTI_HANDLE(multi))
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
     return CURLM_BAD_HANDLE;
@@ -440,6 +456,15 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
   if(multi->in_callback)
   if(multi->in_callback)
     return CURLM_RECURSIVE_API_CALL;
     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 */
   /* Initialize timeout list for this handle */
   Curl_llist_init(&data->state.timeoutlist, NULL);
   Curl_llist_init(&data->state.timeoutlist, NULL);
 
 
@@ -452,6 +477,34 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
   if(data->set.errorbuffer)
   if(data->set.errorbuffer)
     data->set.errorbuffer[0] = 0;
     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 */
   /* set the easy handle */
   multistate(data, MSTATE_INIT);
   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 */
     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 */
   /* increase the node-counter */
   multi->num_easy++;
   multi->num_easy++;
 
 
   /* increase the alive-counter */
   /* increase the alive-counter */
   multi->num_alive++;
   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);
   CONNCACHE_LOCK(data);
   /* The closure handle only ever has default timeouts set. To improve the
   /* 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
      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;
     data->set.no_signal;
   CONNCACHE_UNLOCK(data);
   CONNCACHE_UNLOCK(data);
 
 
-  Curl_update_timer(multi);
   return CURLM_OK;
   return CURLM_OK;
 }
 }
 
 
 #if 0
 #if 0
 /* Debug-function, used like this:
 /* 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
  * 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;
   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
 #endif
 
 
@@ -562,7 +591,8 @@ static CURLcode multi_done(struct Curl_easy *data,
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   unsigned int i;
   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)
   if(data->state.done)
     /* Stop if multi_done() has already been called */
     /* 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;
   struct Curl_easy *easy = data;
   bool premature;
   bool premature;
   struct Curl_llist_element *e;
   struct Curl_llist_element *e;
+  CURLMcode rc;
 
 
   /* First, make some basic checks that the CURLM handle is a good handle */
   /* First, make some basic checks that the CURLM handle is a good handle */
   if(!GOOD_MULTI_HANDLE(multi))
   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
   /* change state without using multistate(), only to make singlesocket() do
      what we want */
      what we want */
   data->mstate = MSTATE_COMPLETED;
   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 */
   /* Remove the association between the connection and the handle */
   Curl_detach_connnection(data);
   Curl_detach_connnection(data);
@@ -858,7 +892,9 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
 
 
   process_pending_handles(multi);
   process_pending_handles(multi);
 
 
-  Curl_update_timer(multi);
+  rc = Curl_update_timer(multi);
+  if(rc)
+    return rc;
   return CURLM_OK;
   return CURLM_OK;
 }
 }
 
 
@@ -878,6 +914,7 @@ void Curl_detach_connnection(struct Curl_easy *data)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   if(conn) {
   if(conn) {
+    Curl_connect_done(data); /* if mid-CONNECT, shut it down */
     Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
     Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
     Curl_ssl_detach_conn(data, conn);
     Curl_ssl_detach_conn(data, conn);
   }
   }
@@ -1742,6 +1779,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
   if(!GOOD_EASY_HANDLE(data))
   if(!GOOD_EASY_HANDLE(data))
     return CURLM_BAD_EASY_HANDLE;
     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 {
   do {
     /* A "stream" here is a logical stream if the protocol can handle that
     /* A "stream" here is a logical stream if the protocol can handle that
        (HTTP/2), or the full connection for older protocols */
        (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
          down.  If the name has not yet been resolved, it is likely
          that new sockets have been opened in an attempt to contact
          that new sockets have been opened in an attempt to contact
          another resolver. */
          another resolver. */
-      singlesocket(multi, data);
+      rc = singlesocket(multi, data);
+      if(rc)
+        return rc;
 
 
       if(dns) {
       if(dns) {
         /* Perform the next step in the connection phase, and then move on
         /* 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;
       break;
 
 
     case MSTATE_DO:
     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) {
       if(data->set.connect_only) {
         /* keep connection open for application to use the socket */
         /* keep connection open for application to use the socket */
         connkeep(data->conn, "CONNECT_ONLY");
         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;
   *running_handles = multi->num_alive;
 
 
   if(CURLM_OK >= returncode)
   if(CURLM_OK >= returncode)
-    Curl_update_timer(multi);
+    returncode = Curl_update_timer(multi);
 
 
   return returncode;
   return returncode;
 }
 }
@@ -2611,7 +2681,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
 
 
     multi->magic = 0; /* not good anymore */
     multi->magic = 0; /* not good anymore */
 
 
-    /* Firsrt remove all remaining easy handles */
+    /* First remove all remaining easy handles */
     data = multi->easyp;
     data = multi->easyp;
     while(data) {
     while(data) {
       nextdata = data->next;
       nextdata = data->next;
@@ -2640,7 +2710,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
     /* Close all the connections in the connection cache */
     /* Close all the connections in the connection cache */
     Curl_conncache_close_all_connections(&multi->conn_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_conncache_destroy(&multi->conn_cache);
     Curl_llist_destroy(&multi->msglist, NULL);
     Curl_llist_destroy(&multi->msglist, NULL);
     Curl_llist_destroy(&multi->pending, NULL);
     Curl_llist_destroy(&multi->pending, NULL);
@@ -2715,6 +2785,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
   int num;
   int num;
   unsigned int curraction;
   unsigned int curraction;
   unsigned char actions[MAX_SOCKSPEREASYHANDLE];
   unsigned char actions[MAX_SOCKSPEREASYHANDLE];
+  int rc;
 
 
   for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
   for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
     socks[i] = CURL_SOCKET_BAD;
     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! */
       /* add 'data' to the transfer hash on this socket! */
       if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
       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;
         return CURLM_OUT_OF_MEMORY;
+      }
     }
     }
 
 
     comboaction = (entry->writers? CURL_POLL_OUT : 0) |
     comboaction = (entry->writers? CURL_POLL_OUT : 0) |
@@ -2798,9 +2871,14 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
       /* same, continue */
       /* same, continue */
       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 */
     entry->action = comboaction; /* store the current action state */
   }
   }
@@ -2835,10 +2913,14 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
       if(oldactions & CURL_POLL_IN)
       if(oldactions & CURL_POLL_IN)
         entry->readers--;
         entry->readers--;
       if(!entry->users) {
       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);
         sh_delentry(entry, &multi->sockhash, s);
       }
       }
       else {
       else {
@@ -2857,9 +2939,11 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
   return CURLM_OK;
   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);
       struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
 
 
       if(entry) {
       if(entry) {
+        int rc = 0;
         if(multi->socket_cb)
         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 */
         /* now remove it from the socket hash */
         sh_delentry(entry, &multi->sockhash, s);
         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;
     return CURLM_RECURSIVE_API_CALL;
   result = multi_socket(multi, FALSE, s, 0, running_handles);
   result = multi_socket(multi, FALSE, s, 0, running_handles);
   if(CURLM_OK >= result)
   if(CURLM_OK >= result)
-    Curl_update_timer(multi);
+    result = Curl_update_timer(multi);
   return result;
   return result;
 }
 }
 
 
@@ -3162,7 +3251,7 @@ CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
     return CURLM_RECURSIVE_API_CALL;
     return CURLM_RECURSIVE_API_CALL;
   result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
   result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
   if(CURLM_OK >= result)
   if(CURLM_OK >= result)
-    Curl_update_timer(multi);
+    result = Curl_update_timer(multi);
   return result;
   return result;
 }
 }
 
 
@@ -3173,14 +3262,19 @@ CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
     return CURLM_RECURSIVE_API_CALL;
     return CURLM_RECURSIVE_API_CALL;
   result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
   result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
   if(CURLM_OK >= result)
   if(CURLM_OK >= result)
-    Curl_update_timer(multi);
+    result = Curl_update_timer(multi);
   return result;
   return result;
 }
 }
 
 
 static CURLMcode multi_timeout(struct Curl_multi *multi,
 static CURLMcode multi_timeout(struct Curl_multi *multi,
                                long *timeout_ms)
                                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) {
   if(multi->timetree) {
     /* we have a tree of expire times */
     /* 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
  * Tell the application it should update its timers, if it subscribes to the
  * update timer callback.
  * update timer callback.
  */
  */
-void Curl_update_timer(struct Curl_multi *multi)
+CURLMcode Curl_update_timer(struct Curl_multi *multi)
 {
 {
   long timeout_ms;
   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)) {
   if(multi_timeout(multi, &timeout_ms)) {
-    return;
+    return CURLM_OK;
   }
   }
   if(timeout_ms < 0) {
   if(timeout_ms < 0) {
     static const struct curltime none = {0, 0};
     static const struct curltime none = {0, 0};
@@ -3248,10 +3343,14 @@ void Curl_update_timer(struct Curl_multi *multi)
       multi->timer_lastcall = none;
       multi->timer_lastcall = none;
       /* there's no timeout now but there was one previously, tell the app to
       /* there's no timeout now but there was one previously, tell the app to
          disable it */
          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
   /* 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
    * if this is the same (fixed) time as we got in a previous call and then
    * avoid calling the callback again. */
    * avoid calling the callback again. */
   if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
   if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
-    return;
+    return CURLM_OK;
 
 
   multi->timer_lastcall = multi->timetree->key;
   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;
 }
 }
 
 
 /*
 /*

+ 2 - 0
Utilities/cmcurl/lib/multihandle.h

@@ -156,6 +156,8 @@ struct Curl_multi {
 #ifdef USE_OPENSSL
 #ifdef USE_OPENSSL
   bool ssl_seeded;
   bool ssl_seeded;
 #endif
 #endif
+  bool dead; /* a callback returned error, everything needs to crash and
+                burn */
 };
 };
 
 
 #endif /* HEADER_CURL_MULTIHANDLE_H */
 #endif /* HEADER_CURL_MULTIHANDLE_H */

+ 2 - 2
Utilities/cmcurl/lib/multiif.h

@@ -26,11 +26,11 @@
  * Prototypes for library-wide functions provided by multi.c
  * 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(struct Curl_easy *data, timediff_t milli, expire_id);
 void Curl_expire_clear(struct Curl_easy *data);
 void Curl_expire_clear(struct Curl_easy *data);
 void Curl_expire_done(struct Curl_easy *data, expire_id id);
 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,
 void Curl_attach_connnection(struct Curl_easy *data,
                              struct connectdata *conn);
                              struct connectdata *conn);
 void Curl_detach_connnection(struct Curl_easy *data);
 void Curl_detach_connnection(struct Curl_easy *data);

+ 477 - 356
Utilities/cmcurl/lib/openldap.c

@@ -70,6 +70,17 @@
  */
  */
 /* #define CURL_OPENLDAP_DEBUG */
 /* #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
 #ifndef _LDAP_PVT_H
 extern int ldap_pvt_url_scheme2proto(const char *);
 extern int ldap_pvt_url_scheme2proto(const char *);
 extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
 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
 #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 {
 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;
   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 {
 struct ldapreqinfo {
@@ -173,194 +168,379 @@ struct ldapreqinfo {
   int nument;
   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) {
   if(rc != LDAP_URL_SUCCESS) {
     const char *msg = "url parsing problem";
     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];
       msg = url_errs[rc];
-    }
     failf(data, "LDAP local: %s", msg);
     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);
   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
 #ifdef USE_SSL
 static Sockbuf_IO ldapsb_tls;
 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 connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   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
 #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);
   rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
   if(rc) {
   if(rc) {
     failf(data, "LDAP local: Cannot connect to %s, %s",
     failf(data, "LDAP local: Cannot connect to %s, %s",
           hosturl, ldap_err2string(rc));
           hosturl, ldap_err2string(rc));
+    free(hosturl);
     return CURLE_COULDNT_CONNECT;
     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
 #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;
       return result;
   }
   }
 #endif
 #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 connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   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 {
     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,
 static CURLcode oldap_disconnect(struct Curl_easy *data,
@@ -373,7 +553,7 @@ static CURLcode oldap_disconnect(struct Curl_easy *data,
   if(li) {
   if(li) {
     if(li->ld) {
     if(li->ld) {
 #ifdef USE_SSL
 #ifdef USE_SSL
-      if(conn->ssl[FIRSTSOCKET].use) {
+      if(ssl_installed(conn)) {
         Sockbuf *sb;
         Sockbuf *sb;
         ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
         ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
         ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
         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 connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapreqinfo *lr;
   struct ldapreqinfo *lr;
-  CURLcode status = CURLE_OK;
-  int rc = 0;
-  LDAPURLDesc *ludp = NULL;
+  CURLcode result;
+  int rc;
+  LDAPURLDesc *lud;
   int msgid;
   int msgid;
 
 
   connkeep(conn, "OpenLDAP do");
   connkeep(conn, "OpenLDAP do");
 
 
   infof(data, "LDAP local: %s", data->state.url);
   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,
 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;
   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,
 static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
                           size_t len, CURLcode *err)
                           size_t len, CURLcode *err)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapreqinfo *lr = data->req.p.ldap;
   struct ldapreqinfo *lr = data->req.p.ldap;
-  int rc, ret;
+  int rc;
   LDAPMessage *msg = NULL;
   LDAPMessage *msg = NULL;
-  LDAPMessage *ent;
   BerElement *ber = NULL;
   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)len;
   (void)buf;
   (void)buf;
   (void)sockindex;
   (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) {
   if(rc < 0) {
     failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
     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)
   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;
       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++;
     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) {
     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_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;
       int i;
 
 
       if(!bv.bv_val)
       if(!bv.bv_val)
         break;
         break;
 
 
-      if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
-        binary = 1;
-      else
-        binary = 0;
-
       if(!bvals) {
       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;
         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++) {
       for(i = 0; bvals[i].bv_val != NULL; i++) {
         int binval = 0;
         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) {
         if(!binary) {
           /* check for leading or trailing whitespace */
           /* check for leading or trailing whitespace */
           if(ISSPACE(bvals[i].bv_val[0]) ||
           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;
             binval = 1;
           else {
           else {
             /* check for unprintable characters */
             /* check for unprintable characters */
             unsigned int j;
             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])) {
               if(!ISPRINT(bvals[i].bv_val[j])) {
                 binval = 1;
                 binval = 1;
                 break;
                 break;
@@ -622,80 +781,42 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
         if(binary || binval) {
         if(binary || binval) {
           char *val_b64 = NULL;
           char *val_b64 = NULL;
           size_t val_b64_sz = 0;
           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);
       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);
     ber_free(ber, 0);
+
+    if(!result)
+      result = client_write(data, "\n", NULL, 0, NULL);
+    if(!result)
+      result = CURLE_AGAIN;
+    break;
   }
   }
+
   ldap_msgfree(msg);
   ldap_msgfree(msg);
-  return ret;
+  *err = result;
+  return result? -1: 0;
 }
 }
 
 
 #ifdef USE_SSL
 #ifdef USE_SSL

+ 60 - 40
Utilities/cmcurl/lib/pop3.c

@@ -78,6 +78,7 @@
 #include "select.h"
 #include "select.h"
 #include "multiif.h"
 #include "multiif.h"
 #include "url.h"
 #include "url.h"
+#include "bufref.h"
 #include "curl_sasl.h"
 #include "curl_sasl.h"
 #include "curl_md5.h"
 #include "curl_md5.h"
 #include "warnless.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_options(struct connectdata *conn);
 static CURLcode pop3_parse_url_path(struct Curl_easy *data);
 static CURLcode pop3_parse_url_path(struct Curl_easy *data);
 static CURLcode pop3_parse_custom_request(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.
  * POP3 protocol handler.
@@ -170,13 +171,16 @@ const struct Curl_handler Curl_handler_pop3s = {
 
 
 /* SASL parameters for the pop3 protocol */
 /* SASL parameters for the pop3 protocol */
 static const struct SASLproto saslpop3 = {
 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
 #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.
  * 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) {
   if(len > 2) {
     /* Find the start of the message */
     /* Find the start of the message */
     len -= 2;
     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 */
     /* Find the end of the message */
-    for(; len--;)
+    while(len--)
       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
          message[len] != '\t')
          message[len] != '\t')
         break;
         break;
 
 
     /* Terminate the message */
     /* Terminate the message */
-    if(++len) {
-      message[len] = '\0';
-    }
+    message[++len] = '\0';
+    Curl_bufref_set(out, message, len, NULL);
   }
   }
   else
   else
     /* junk input => zero length output */
     /* 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.
  * authentication mechanism.
  */
  */
 static CURLcode pop3_perform_auth(struct Curl_easy *data,
 static CURLcode pop3_perform_auth(struct Curl_easy *data,
-                                  struct connectdata *conn,
                                   const char *mech,
                                   const char *mech,
-                                  const char *initresp)
+                                  const struct bufref *initresp)
 {
 {
   CURLcode result = CURLE_OK;
   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 */
     /* 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 {
   else {
     /* Send the AUTH command */
     /* Send the AUTH command */
@@ -497,15 +499,33 @@ static CURLcode pop3_perform_auth(struct Curl_easy *data,
  *
  *
  * pop3_continue_auth()
  * pop3_continue_auth()
  *
  *
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
  */
  */
 static CURLcode pop3_continue_auth(struct Curl_easy *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) {
   if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
     /* Calculate the SASL login details */
     /* 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(!result)
       if(progress == SASL_INPROGRESS)
       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 */
   (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)
   if(!result)
     switch(progress) {
     switch(progress) {
     case SASL_DONE:
     case SASL_DONE:
@@ -1011,7 +1031,9 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
       break;
       break;
 
 
     case POP3_QUIT:
     case POP3_QUIT:
-      /* fallthrough, just stop! */
+      state(data, POP3_STOP);
+      break;
+
     default:
     default:
       /* internal error */
       /* internal error */
       state(data, POP3_STOP);
       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 */
   /* Set the default preferred authentication type and mechanism */
   pop3c->preftype = POP3_TYPE_ANY;
   pop3c->preftype = POP3_TYPE_ANY;
-  Curl_sasl_init(&pop3c->sasl, &saslpop3);
+  Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
 
 
   /* Initialise the pingpong layer */
   /* Initialise the pingpong layer */
   Curl_pp_setup(pp);
   Curl_pp_setup(pp);
@@ -1343,8 +1365,6 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   const char *ptr = conn->options;
   const char *ptr = conn->options;
 
 
-  pop3c->sasl.resetprefs = TRUE;
-
   while(!result && ptr && *ptr) {
   while(!result && ptr && *ptr) {
     const char *key = ptr;
     const char *key = ptr;
     const char *value;
     const char *value;

+ 1 - 1
Utilities/cmcurl/lib/select.c

@@ -64,7 +64,7 @@
  * Waiting indefinitely with this function is not allowed, a
  * Waiting indefinitely with this function is not allowed, a
  * zero or negative timeout value will return immediately.
  * zero or negative timeout value will return immediately.
  * Timeout resolution, accuracy, as well as maximum supported
  * 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.
  * for the intended use of this function in the library.
  *
  *
  * Return values:
  * Return values:

+ 5 - 3
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)
 /* 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 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
    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
    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;
   struct connectdata *conn = data->conn;
 
 
-  DEBUGASSERT(len);
-  DEBUGASSERT(type <= 3);
+  DEBUGASSERT(!(type & ~CLIENTWRITE_BOTH));
+
+  if(!len)
+    return CURLE_OK;
 
 
   /* FTP data may need conversion. */
   /* FTP data may need conversion. */
   if((type & CLIENTWRITE_BODY) &&
   if((type & CLIENTWRITE_BODY) &&

+ 38 - 0
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;
         data->set.ssl.primary.verifypeer;
     }
     }
     break;
     break;
+#ifndef CURL_DISABLE_DOH
   case CURLOPT_DOH_SSL_VERIFYPEER:
   case CURLOPT_DOH_SSL_VERIFYPEER:
     /*
     /*
      * Enable peer SSL verifying for DoH.
      * 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)) ?
     data->set.doh_verifypeer = (0 != va_arg(param, long)) ?
       TRUE : FALSE;
       TRUE : FALSE;
     break;
     break;
+#endif
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_SSL_VERIFYPEER:
   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;
         data->set.ssl.primary.verifyhost;
     }
     }
     break;
     break;
+#ifndef CURL_DISABLE_DOH
   case CURLOPT_DOH_SSL_VERIFYHOST:
   case CURLOPT_DOH_SSL_VERIFYHOST:
     /*
     /*
      * Enable verification of the host name in the peer certificate for DoH
      * 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 */
     /* Treat both 1 and 2 as TRUE */
     data->set.doh_verifyhost = (bool)((arg & 3) ? TRUE : FALSE);
     data->set.doh_verifyhost = (bool)((arg & 3) ? TRUE : FALSE);
     break;
     break;
+#endif
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_SSL_VERIFYHOST:
   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;
         data->set.ssl.primary.verifystatus;
     }
     }
     break;
     break;
+#ifndef CURL_DISABLE_DOH
   case CURLOPT_DOH_SSL_VERIFYSTATUS:
   case CURLOPT_DOH_SSL_VERIFYSTATUS:
     /*
     /*
      * Enable certificate status verifying for DoH.
      * 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)) ?
     data->set.doh_verifystatus = (0 != va_arg(param, long)) ?
       TRUE : FALSE;
       TRUE : FALSE;
     break;
     break;
+#endif
   case CURLOPT_SSL_CTX_FUNCTION:
   case CURLOPT_SSL_CTX_FUNCTION:
     /*
     /*
      * Set a SSL_CTX callback
      * 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 *));
                             va_arg(param, char *));
     break;
     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:
   case CURLOPT_SSH_KNOWNHOSTS:
     /*
     /*
      * Store the file name to read known hosts from.
      * 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
      * disable libcurl transfer encoding is used
      */
      */
+#ifndef USE_HYPER
     data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
     data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
     break;
     break;
+#else
+    return CURLE_NOT_BUILT_IN; /* hyper doesn't support */
+#endif
 
 
   case CURLOPT_HTTP_CONTENT_DECODING:
   case CURLOPT_HTTP_CONTENT_DECODING:
     /*
     /*
@@ -2596,6 +2615,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
     break;
 #endif
 #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:
   case CURLOPT_SASL_AUTHZID:
     /* Authorisation identity (identity to act as) */
     /* Authorisation identity (identity to act as) */
     result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID],
     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;
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.maxage_conn = arg;
     data->set.maxage_conn = arg;
     break;
     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:
   case CURLOPT_TRAILERFUNCTION:
 #ifndef CURL_DISABLE_HTTP
 #ifndef CURL_DISABLE_HTTP
     data->set.trailer_callback = va_arg(param, curl_trailer_callback);
     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;
       return result;
     break;
     break;
 #endif
 #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:
   default:
     /* unknown tag and its companion, just ignore: */
     /* unknown tag and its companion, just ignore: */
     result = CURLE_UNKNOWN_OPTION;
     result = CURLE_UNKNOWN_OPTION;

+ 3 - 11
Utilities/cmcurl/lib/setup-win32.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -25,11 +25,11 @@
 /*
 /*
  * Include header files for windows builds before redefining anything.
  * Include header files for windows builds before redefining anything.
  * Use this preprocessor block only to include or exclude windows.h,
  * 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
  * 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
  * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
  * never be included when __CYGWIN__ is defined.  configure script takes
  * 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.
  * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
  */
  */
 
 
@@ -47,10 +47,6 @@
 #    ifdef HAVE_WS2TCPIP_H
 #    ifdef HAVE_WS2TCPIP_H
 #      include <ws2tcpip.h>
 #      include <ws2tcpip.h>
 #    endif
 #    endif
-#  else
-#    ifdef HAVE_WINSOCK_H
-#      include <winsock.h>
-#    endif
 #  endif
 #  endif
 #  include <tchar.h>
 #  include <tchar.h>
 #  ifdef UNICODE
 #  ifdef UNICODE
@@ -67,10 +63,6 @@
 
 
 #ifdef HAVE_WINSOCK2_H
 #ifdef HAVE_WINSOCK2_H
 #  define USE_WINSOCK 2
 #  define USE_WINSOCK 2
-#else
-#  ifdef HAVE_WINSOCK_H
-#    error "WinSock version 1 is no longer supported, version 2 is required!"
-#  endif
 #endif
 #endif
 
 
 /*
 /*

+ 97 - 44
Utilities/cmcurl/lib/sha256.c

@@ -29,11 +29,18 @@
 #include "curl_sha256.h"
 #include "curl_sha256.h"
 #include "curl_hmac.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)
 #if defined(USE_OPENSSL)
 
 
 #include <openssl/opensslv.h>
 #include <openssl/opensslv.h>
 
 
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
+#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL)
 #define USE_OPENSSL_SHA256
 #define USE_OPENSSL_SHA256
 #endif
 #endif
 
 
@@ -63,7 +70,40 @@
 #if defined(USE_OPENSSL_SHA256)
 #if defined(USE_OPENSSL_SHA256)
 
 
 /* When OpenSSL is available we use the SHA256-function from OpenSSL */
 /* 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)
 #elif defined(USE_GNUTLS)
 
 
@@ -74,21 +114,22 @@
 /* The last #include file should be: */
 /* The last #include file should be: */
 #include "memdebug.h"
 #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);
   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);
   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);
   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: */
 /* The last #include file should be: */
 #include "memdebug.h"
 #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)
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_sha256_starts(ctx, 0);
   (void) mbedtls_sha256_starts(ctx, 0);
 #else
 #else
   (void) mbedtls_sha256_starts_ret(ctx, 0);
   (void) mbedtls_sha256_starts_ret(ctx, 0);
 #endif
 #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)
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_sha256_update(ctx, data, length);
   (void) mbedtls_sha256_update(ctx, data, length);
@@ -124,7 +166,7 @@ static void SHA256_Update(SHA256_CTX *ctx,
 #endif
 #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)
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_sha256_finish(ctx, digest);
   (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: */
 /* The last #include file should be: */
 #include "memdebug.h"
 #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);
   (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);
   (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);
   (void) CC_SHA256_Final(digest, ctx);
 }
 }
@@ -172,28 +215,30 @@ struct sha256_ctx {
   HCRYPTPROV hCryptProv;
   HCRYPTPROV hCryptProv;
   HCRYPTHASH hHash;
   HCRYPTHASH hHash;
 };
 };
-typedef struct sha256_ctx SHA256_CTX;
+typedef struct sha256_ctx my_sha256_ctx;
 
 
 #if !defined(CALG_SHA_256)
 #if !defined(CALG_SHA_256)
 #define CALG_SHA_256 0x0000800c
 #define CALG_SHA_256 0x0000800c
 #endif
 #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,
   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
     CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
     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);
   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;
   unsigned long length = 0;
 
 
@@ -262,7 +307,7 @@ struct sha256_state {
   unsigned long state[8], curlen;
   unsigned long state[8], curlen;
   unsigned char buf[64];
   unsigned char buf[64];
 };
 };
-typedef struct sha256_state SHA256_CTX;
+typedef struct sha256_state my_sha256_ctx;
 
 
 /* The K array */
 /* The K array */
 static const unsigned long K[64] = {
 static const unsigned long K[64] = {
@@ -339,7 +384,7 @@ static int sha256_compress(struct sha256_state *md,
 }
 }
 
 
 /* Initialize the hash state */
 /* 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->curlen = 0;
   md->length = 0;
   md->length = 0;
@@ -351,6 +396,8 @@ static void SHA256_Init(struct sha256_state *md)
   md->state[5] = 0x9B05688CUL;
   md->state[5] = 0x9B05688CUL;
   md->state[6] = 0x1F83D9ABUL;
   md->state[6] = 0x1F83D9ABUL;
   md->state[7] = 0x5BE0CD19UL;
   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 md     The hash state
    @param in     The data to hash
    @param in     The data to hash
    @param inlen  The length of the data (octets)
    @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;
   unsigned long n;
 
 
@@ -399,10 +446,10 @@ static int SHA256_Update(struct sha256_state *md,
    Terminate the hash to get the digest
    Terminate the hash to get the digest
    @param md  The hash state
    @param md  The hash state
    @param out [out] The destination of the hash (32 bytes)
    @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;
   int i;
 
 
@@ -455,28 +502,34 @@ static int SHA256_Final(unsigned char *out,
  * output [in/out] - The output buffer.
  * output [in/out] - The output buffer.
  * input  [in]     - The input data.
  * input  [in]     - The input data.
  * length [in]     - The input length.
  * 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)
                    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[] = {
 const struct HMAC_params Curl_HMAC_SHA256[] = {
   {
   {
     /* Hash initialization function. */
     /* Hash initialization function. */
-    CURLX_FUNCTION_CAST(HMAC_hinit_func, SHA256_Init),
+    CURLX_FUNCTION_CAST(HMAC_hinit_func, my_sha256_init),
     /* Hash update function. */
     /* Hash update function. */
-    CURLX_FUNCTION_CAST(HMAC_hupdate_func, SHA256_Update),
+    CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_sha256_update),
     /* Hash computation end function. */
     /* 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. */
     /* Size of hash context structure. */
-    sizeof(SHA256_CTX),
+    sizeof(my_sha256_ctx),
     /* Maximum key length. */
     /* Maximum key length. */
     64,
     64,
     /* Result size. */
     /* Result size. */

+ 1 - 5
Utilities/cmcurl/lib/share.c

@@ -39,11 +39,7 @@ curl_share_init(void)
   if(share) {
   if(share) {
     share->magic = CURL_GOOD_SHARE;
     share->magic = CURL_GOOD_SHARE;
     share->specifier |= (1<<CURL_LOCK_DATA_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;
   return share;

+ 61 - 42
Utilities/cmcurl/lib/smtp.c

@@ -82,6 +82,7 @@
 #include "multiif.h"
 #include "multiif.h"
 #include "url.h"
 #include "url.h"
 #include "curl_gethostname.h"
 #include "curl_gethostname.h"
+#include "bufref.h"
 #include "curl_sasl.h"
 #include "curl_sasl.h"
 #include "warnless.h"
 #include "warnless.h"
 /* The last 3 #include files should be in this order */
 /* 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_custom_request(struct Curl_easy *data);
 static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
 static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
                                    char **address, struct hostname *host);
                                    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.
  * SMTP protocol handler.
@@ -175,13 +176,16 @@ const struct Curl_handler Curl_handler_smtps = {
 
 
 /* SASL parameters for the smtp protocol */
 /* SASL parameters for the smtp protocol */
 static const struct SASLproto saslsmtp = {
 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
 #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
   /* 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
      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. */
      only send the response code instead as per Section 4.2. */
   if(line[3] == ' ' || len == 5) {
   if(line[3] == ' ' || len == 5) {
     char tmpline[6];
     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.
  * 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) {
   if(len > 4) {
     /* Find the start of the message */
     /* Find the start of the message */
     len -= 4;
     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 */
     /* Find the end of the message */
-    for(; len--;)
+    while(len--)
       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
          message[len] != '\t')
          message[len] != '\t')
         break;
         break;
 
 
     /* Terminate the message */
     /* Terminate the message */
-    if(++len) {
-      message[len] = '\0';
-    }
+    message[++len] = '\0';
+    Curl_bufref_set(out, message, len, NULL);
   }
   }
   else
   else
     /* junk input => zero length output */
     /* 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.
  * authentication mechanism.
  */
  */
 static CURLcode smtp_perform_auth(struct Curl_easy *data,
 static CURLcode smtp_perform_auth(struct Curl_easy *data,
-                                  struct connectdata *conn,
                                   const char *mech,
                                   const char *mech,
-                                  const char *initresp)
+                                  const struct bufref *initresp)
 {
 {
   CURLcode result = CURLE_OK;
   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 */
     /* 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 {
   else {
     /* Send the AUTH command */
     /* Send the AUTH command */
@@ -444,14 +446,33 @@ static CURLcode smtp_perform_auth(struct Curl_easy *data,
  *
  *
  * smtp_continue_auth()
  * smtp_continue_auth()
  *
  *
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
  */
  */
 static CURLcode smtp_continue_auth(struct Curl_easy *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;
   saslprogress progress;
 
 
   /* Check we have enough data to authenticate with, and the
   /* 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 ||
   if(!smtpc->auth_supported ||
      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
     state(data, SMTP_STOP);
     state(data, SMTP_STOP);
@@ -477,7 +498,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
   }
   }
 
 
   /* Calculate the SASL login details */
   /* 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(!result) {
     if(progress == SASL_INPROGRESS)
     if(progress == SASL_INPROGRESS)
@@ -506,7 +527,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
 
 
   if(smtp->rcpt) {
   if(smtp->rcpt) {
     /* We notify the server we are sending UTF-8 data if a) it supports the
     /* 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
        either the local address or host name parts. This is regardless of
        whether the host name is encoded using IDN ACE */
        whether the host name is encoded using IDN ACE */
     bool utf8 = FALSE;
     bool utf8 = FALSE;
@@ -579,7 +600,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
 
 
   /* We notify the server we are sending UTF-8 data if a) it supports the
   /* 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
      either the local address or host name parts. This is regardless of
      whether the host name is encoded using IDN ACE */
      whether the host name is encoded using IDN ACE */
   bool utf8 = FALSE;
   bool utf8 = FALSE;
@@ -985,7 +1006,7 @@ static CURLcode smtp_state_auth_resp(struct Curl_easy *data,
 
 
   (void)instate; /* no use for this yet */
   (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)
   if(!result)
     switch(progress) {
     switch(progress) {
     case SASL_DONE:
     case SASL_DONE:
@@ -1333,7 +1354,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
   PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp);
   PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp);
 
 
   /* Initialize the SASL storage */
   /* Initialize the SASL storage */
-  Curl_sasl_init(&smtpc->sasl, &saslsmtp);
+  Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
 
 
   /* Initialise the pingpong layer */
   /* Initialise the pingpong layer */
   Curl_pp_setup(pp);
   Curl_pp_setup(pp);
@@ -1655,8 +1676,6 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn)
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   const char *ptr = conn->options;
   const char *ptr = conn->options;
 
 
-  smtpc->sasl.resetprefs = TRUE;
-
   while(!result && ptr && *ptr) {
   while(!result && ptr && *ptr) {
     const char *key = ptr;
     const char *key = ptr;
     const char *value;
     const char *value;

+ 28 - 5
Utilities/cmcurl/lib/socks.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -38,6 +38,7 @@
 #include "timeval.h"
 #include "timeval.h"
 #include "socks.h"
 #include "socks.h"
 #include "multiif.h" /* for getsock macros */
 #include "multiif.h" /* for getsock macros */
+#include "inet_pton.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -856,10 +857,32 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
     socksreq[len++] = 0; /* must be zero */
     socksreq[len++] = 0; /* must be zero */
 
 
     if(!socks5_resolve_local) {
     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)",
       infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
             hostname, remote_port);
             hostname, remote_port);
     }
     }

+ 2 - 2
Utilities/cmcurl/lib/socks_gssapi.c

@@ -257,7 +257,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_COULDNT_CONNECT;
       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).",
       failf(data, "Invalid GSS-API authentication response type (%d %d).",
             socksreq[0], socksreq[1]);
             socksreq[0], socksreq[1]);
       gss_release_name(&gss_status, &server);
       gss_release_name(&gss_status, &server);
@@ -452,7 +452,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     return CURLE_COULDNT_CONNECT;
     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).",
     failf(data, "Invalid GSS-API encryption response type (%d %d).",
           socksreq[0], socksreq[1]);
           socksreq[0], socksreq[1]);
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     gss_delete_sec_context(&gss_status, &gss_context, NULL);

+ 1 - 1
Utilities/cmcurl/lib/socks_sspi.c

@@ -277,7 +277,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_COULDNT_CONNECT;
       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).",
       failf(data, "Invalid SSPI authentication response type (%u %u).",
             (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
             (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
       free(service_name);
       free(service_name);

+ 2 - 2
Utilities/cmcurl/lib/splay.c

@@ -107,7 +107,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
   if(!node)
   if(!node)
     return t;
     return t;
 
 
-  if(t != NULL) {
+  if(t) {
     t = Curl_splay(i, t);
     t = Curl_splay(i, t);
     if(compare(i, t->key) == 0) {
     if(compare(i, t->key) == 0) {
       /* There already exists a node in the tree with the very same key. Build
       /* 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 *t,
                                     struct Curl_tree **removed)
                                     struct Curl_tree **removed)
 {
 {
-  static struct curltime tv_zero = {0, 0};
+  static const struct curltime tv_zero = {0, 0};
   struct Curl_tree *x;
   struct Curl_tree *x;
 
 
   if(!t) {
   if(!t) {

+ 111 - 0
Utilities/cmcurl/lib/strerror.c

@@ -404,6 +404,9 @@ curl_multi_strerror(CURLMcode error)
   case CURLM_BAD_FUNCTION_ARGUMENT:
   case CURLM_BAD_FUNCTION_ARGUMENT:
     return "A libcurl function was given a bad 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:
   case CURLM_LAST:
     break;
     break;
   }
   }
@@ -453,6 +456,114 @@ curl_share_strerror(CURLSHcode error)
 #endif
 #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
 #ifdef USE_WINSOCK
 /* This is a helper function for Curl_strerror that converts Winsock error
 /* This is a helper function for Curl_strerror that converts Winsock error
  * codes (WSAGetLastError) to error messages.
  * codes (WSAGetLastError) to error messages.

+ 3 - 1
Utilities/cmcurl/lib/system_win32.c

@@ -102,7 +102,9 @@ CURLcode Curl_win32_init(long flags)
       Curl_if_nametoindex = pIfNameToIndex;
       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)) {
                                   VERSION_GREATER_THAN_EQUAL)) {
     Curl_isVistaOrGreater = TRUE;
     Curl_isVistaOrGreater = TRUE;
   }
   }

+ 3 - 3
Utilities/cmcurl/lib/tftp.c

@@ -186,7 +186,7 @@ const struct Curl_handler Curl_handler_tftp = {
   PORT_TFTP,                            /* defport */
   PORT_TFTP,                            /* defport */
   CURLPROTO_TFTP,                       /* protocol */
   CURLPROTO_TFTP,                       /* protocol */
   CURLPROTO_TFTP,                       /* family */
   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)
 static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)

+ 1 - 1
Utilities/cmcurl/lib/transfer.c

@@ -1631,7 +1631,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
 
 
   if((type != FOLLOW_RETRY) &&
   if((type != FOLLOW_RETRY) &&
      (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
      (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
     /* If this is not redirect due to a 401 or 407 response and an absolute
        URL: don't allow a custom port number */
        URL: don't allow a custom port number */
     disallowport = TRUE;
     disallowport = TRUE;

+ 53 - 23
Utilities/cmcurl/lib/url.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * 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 "curl_memory.h"
 #include "memdebug.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);
 static void conn_free(struct connectdata *conn);
 
 
 /* Some parts of the code (e.g. chunked encoding) assume this buffer has at
 /* 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
  * This is the internal function curl_easy_cleanup() calls. This should
  * cleanup and free all resources associated with this sessionhandle.
  * 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)
 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
    * libcurl 7.10 introduced SSL verification *by default*! This needs to be
    * switched off unless wanted.
    * switched off unless wanted.
    */
    */
+#ifndef CURL_DISABLE_DOH
   set->doh_verifyhost = TRUE;
   set->doh_verifyhost = TRUE;
   set->doh_verifypeer = TRUE;
   set->doh_verifypeer = TRUE;
+#endif
   set->ssl.primary.verifypeer = TRUE;
   set->ssl.primary.verifypeer = TRUE;
   set->ssl.primary.verifyhost = TRUE;
   set->ssl.primary.verifyhost = TRUE;
 #ifdef USE_TLS_SRP
 #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->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
   set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
   set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
   set->maxage_conn = 118;
   set->maxage_conn = 118;
+  set->maxlifetime_conn = 0;
   set->http09_allowed = FALSE;
   set->http09_allowed = FALSE;
   set->httpwant =
   set->httpwant =
 #ifdef USE_NGHTTP2
 #ifdef USE_NGHTTP2
@@ -844,7 +854,7 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
     return CURLE_OK;
     return CURLE_OK;
   }
   }
 
 
-  if(conn->dns_entry != NULL) {
+  if(conn->dns_entry) {
     Curl_resolv_unlock(data, conn->dns_entry);
     Curl_resolv_unlock(data, conn->dns_entry);
     conn->dns_entry = NULL;
     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
 #define socks_proxy_info_matches(x,y) FALSE
 #endif
 #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,
 static bool conn_maxage(struct Curl_easy *data,
                         struct connectdata *conn,
                         struct connectdata *conn,
                         struct curltime now)
                         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 */
   idletime /= 1000; /* integer seconds is fine */
 
 
   if(idletime > data->set.maxage_conn) {
   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);
           idletime);
     return TRUE;
     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;
   return FALSE;
 }
 }
 
 
@@ -1284,13 +1309,12 @@ ConnectionExists(struct Curl_easy *data,
             if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete)
             if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete)
               continue;
               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
 #endif
@@ -1667,7 +1691,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
      data becomes proxy backend data). */
      data becomes proxy backend data). */
   {
   {
     size_t sslsize = Curl_ssl->sizeof_ssl_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) {
     if(!ssl) {
       free(conn);
       free(conn);
       return NULL;
       return NULL;
@@ -1934,7 +1958,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
   if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
   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],
     char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
                         data->state.url);
                         data->state.url);
     if(!url)
     if(!url)
@@ -1954,7 +1978,8 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
                      CURLU_DISALLOW_USER : 0) |
                      CURLU_DISALLOW_USER : 0) |
                     (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
                     (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
     if(uc) {
     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);
       return Curl_uc_to_curlcode(uc);
     }
     }
 
 
@@ -2380,6 +2405,11 @@ static CURLcode parse_proxy(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   char *scheme = NULL;
   char *scheme = NULL;
 
 
+  if(!uhp) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
   /* When parsing the proxy, allowing non-supported schemes since we have
   /* When parsing the proxy, allowing non-supported schemes since we have
      these made up ones for proxies. Guess scheme for URLs without it. */
      these made up ones for proxies. Guess scheme for URLs without it. */
   uc = curl_url_set(uhp, CURLUPART_URL, proxy,
   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]) {
   if(data->set.str[STRING_PROXY]) {
     proxy = strdup(data->set.str[STRING_PROXY]);
     proxy = strdup(data->set.str[STRING_PROXY]);
     /* if global proxy is set, this is it */
     /* if global proxy is set, this is it */
-    if(NULL == proxy) {
+    if(!proxy) {
       failf(data, "memory shortage");
       failf(data, "memory shortage");
       result = CURLE_OUT_OF_MEMORY;
       result = CURLE_OUT_OF_MEMORY;
       goto out;
       goto out;
@@ -2581,7 +2611,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
   if(data->set.str[STRING_PRE_PROXY]) {
   if(data->set.str[STRING_PRE_PROXY]) {
     socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
     socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
     /* if global socks proxy is set, this is it */
     /* if global socks proxy is set, this is it */
-    if(NULL == socksproxy) {
+    if(!socksproxy) {
       failf(data, "memory shortage");
       failf(data, "memory shortage");
       result = CURLE_OUT_OF_MEMORY;
       result = CURLE_OUT_OF_MEMORY;
       goto out;
       goto out;
@@ -2763,7 +2793,7 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
   size_t plen;
   size_t plen;
   size_t olen;
   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 */
      and isn't going through the regular string length check */
   size_t llen = strlen(login);
   size_t llen = strlen(login);
   if(llen > CURL_MAX_INPUT_LENGTH)
   if(llen > CURL_MAX_INPUT_LENGTH)
@@ -4093,7 +4123,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
   /* init the single-transfer specific data */
   /* init the single-transfer specific data */
   Curl_free_request_state(data);
   Curl_free_request_state(data);
   memset(&data->req, 0, sizeof(struct SingleRequest));
   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 */
   /* call the stuff that needs to be called */
   result = create_conn(data, &conn, asyncp);
   result = create_conn(data, &conn, asyncp);

+ 1 - 3
Utilities/cmcurl/lib/urlapi-int.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -22,8 +22,6 @@
  *
  *
  ***************************************************************************/
  ***************************************************************************/
 #include "curl_setup.h"
 #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);
 bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen);
 
 

+ 272 - 130
Utilities/cmcurl/lib/urlapi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -30,6 +30,7 @@
 #include "escape.h"
 #include "escape.h"
 #include "curl_ctype.h"
 #include "curl_ctype.h"
 #include "inet_pton.h"
 #include "inet_pton.h"
+#include "inet_ntop.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -50,6 +51,9 @@
    ((str)[1] == ':' || (str)[1] == '|') && \
    ((str)[1] == ':' || (str)[1] == '|') && \
    ((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0))
    ((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. */
 /* Internal representation of CURLU. Point to URL-encoded strings. */
 struct Curl_URL {
 struct Curl_URL {
   char *scheme;
   char *scheme;
@@ -157,23 +161,23 @@ static size_t strlen_url(const char *url, bool relative)
       continue;
       continue;
     }
     }
 
 
-    switch(*ptr) {
-    case '?':
-      left = FALSE;
-      /* FALLTHROUGH */
-    default:
-      if(urlchar_needs_escaping(*ptr))
-        newlen += 2;
-      newlen++;
-      break;
-    case ' ':
+    if(*ptr == ' ') {
       if(left)
       if(left)
         newlen += 3;
         newlen += 3;
       else
       else
         newlen++;
         newlen++;
-      break;
+      continue;
     }
     }
+
+    if (*ptr == '?')
+      left = FALSE;
+
+    if(urlchar_needs_escaping(*ptr))
+      newlen += 2;
+
+    newlen++;
   }
   }
+
   return newlen;
   return newlen;
 }
 }
 
 
@@ -202,19 +206,7 @@ static void strcpy_url(char *output, const char *url, bool relative)
       continue;
       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) {
       if(left) {
         *optr++='%'; /* add a '%' */
         *optr++='%'; /* add a '%' */
         *optr++='2'; /* add a '2' */
         *optr++='2'; /* add a '2' */
@@ -222,41 +214,58 @@ static void strcpy_url(char *output, const char *url, bool relative)
       }
       }
       else
       else
         *optr++='+'; /* add a '+' here */
         *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 */
   *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)
 bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen)
 {
 {
   size_t i;
   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
 #ifdef WIN32
   if(STARTS_WITH_DRIVE_PREFIX(url))
   if(STARTS_WITH_DRIVE_PREFIX(url))
     return FALSE;
     return FALSE;
 #endif
 #endif
-  for(i = 0; i < buflen && url[i]; ++i) {
+  for(i = 0; i < MAX_SCHEME_LEN; ++i) {
     char s = url[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;
       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;
   return FALSE;
 }
 }
@@ -420,6 +429,29 @@ static char *concat_url(const char *base, const char *relurl)
   return newest;
   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()
  * parse_hostname_login()
  *
  *
@@ -467,7 +499,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
                                    (h && (h->flags & PROTOPT_URLOPTIONS)) ?
                                    (h && (h->flags & PROTOPT_URLOPTIONS)) ?
                                    &optionsp:NULL);
                                    &optionsp:NULL);
   if(ccode) {
   if(ccode) {
-    result = CURLUE_MALFORMED_INPUT;
+    result = CURLUE_BAD_LOGIN;
     goto out;
     goto out;
   }
   }
 
 
@@ -477,15 +509,28 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
       result = CURLUE_USER_NOT_ALLOWED;
       result = CURLUE_USER_NOT_ALLOWED;
       goto out;
       goto out;
     }
     }
-
+    if(junkscan(userp, flags)) {
+      result = CURLUE_BAD_USER;
+      goto out;
+    }
     u->user = userp;
     u->user = userp;
   }
   }
 
 
-  if(passwdp)
+  if(passwdp) {
+    if(junkscan(passwdp, flags)) {
+      result = CURLUE_BAD_PASSWORD;
+      goto out;
+    }
     u->password = passwdp;
     u->password = passwdp;
+  }
 
 
-  if(optionsp)
+  if(optionsp) {
+    if(junkscan(optionsp, flags)) {
+      result = CURLUE_BAD_LOGIN;
+      goto out;
+    }
     u->options = optionsp;
     u->options = optionsp;
+  }
 
 
   return CURLUE_OK;
   return CURLUE_OK;
   out:
   out:
@@ -493,6 +538,9 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
   free(userp);
   free(userp);
   free(passwdp);
   free(passwdp);
   free(optionsp);
   free(optionsp);
+  u->user = NULL;
+  u->password = NULL;
+  u->options = NULL;
 
 
   return result;
   return result;
 }
 }
@@ -516,19 +564,19 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
       int zonelen = len;
       int zonelen = len;
       if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) {
       if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) {
         if(']' != endbracket)
         if(']' != endbracket)
-          return CURLUE_MALFORMED_INPUT;
+          return CURLUE_BAD_IPV6;
         portptr = &hostname[--zonelen + len + 1];
         portptr = &hostname[--zonelen + len + 1];
       }
       }
       else
       else
-        return CURLUE_MALFORMED_INPUT;
+        return CURLUE_BAD_IPV6;
     }
     }
     else
     else
-      return CURLUE_MALFORMED_INPUT;
+      return CURLUE_BAD_IPV6;
 
 
     /* this is a RFC2732-style specified IP-address */
     /* this is a RFC2732-style specified IP-address */
     if(portptr && *portptr) {
     if(portptr && *portptr) {
       if(*portptr != ':')
       if(*portptr != ':')
-        return CURLUE_MALFORMED_INPUT;
+        return CURLUE_BAD_IPV6;
     }
     }
     else
     else
       portptr = NULL;
       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 */
     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;
       return CURLUE_BAD_PORT_NUMBER;
 
 
     if(rest[0])
     if(rest[0])
@@ -579,46 +625,20 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
   return CURLUE_OK;
   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)
 static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
 {
 {
   size_t len;
   size_t len;
   size_t hlen = strlen(hostname);
   size_t hlen = strlen(hostname);
 
 
   if(hostname[0] == '[') {
   if(hostname[0] == '[') {
-#ifdef ENABLE_IPV6
-    char dest[16]; /* fits a binary IPv6 address */
-#endif
     const char *l = "0123456789abcdefABCDEF:.";
     const char *l = "0123456789abcdefABCDEF:.";
     if(hlen < 4) /* '[::]' is the shortest possible valid string */
     if(hlen < 4) /* '[::]' is the shortest possible valid string */
-      return CURLUE_MALFORMED_INPUT;
+      return CURLUE_BAD_IPV6;
     hostname++;
     hostname++;
     hlen -= 2;
     hlen -= 2;
 
 
     if(hostname[hlen] != ']')
     if(hostname[hlen] != ']')
-      return CURLUE_MALFORMED_INPUT;
+      return CURLUE_BAD_IPV6;
 
 
     /* only valid letters are ok */
     /* only valid letters are ok */
     len = strspn(hostname, l);
     len = strspn(hostname, l);
@@ -635,6 +655,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
         while(*h && (*h != ']') && (i < 15))
         while(*h && (*h != ']') && (i < 15))
           zoneid[i++] = *h++;
           zoneid[i++] = *h++;
         if(!i || (']' != *h))
         if(!i || (']' != *h))
+          /* impossible to reach? */
           return CURLUE_MALFORMED_INPUT;
           return CURLUE_MALFORMED_INPUT;
         zoneid[i] = 0;
         zoneid[i] = 0;
         u->zoneid = strdup(zoneid);
         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 */
         hostname[len + 1] = 0; /* terminate the hostname */
       }
       }
       else
       else
-        return CURLUE_MALFORMED_INPUT;
+        return CURLUE_BAD_IPV6;
       /* hostname is fine */
       /* hostname is fine */
     }
     }
 #ifdef ENABLE_IPV6
 #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
 #endif
   }
   }
   else {
   else {
     /* letters from the second string is not ok */
     /* letters from the second string is not ok */
-    len = strcspn(hostname, " ");
+    len = strcspn(hostname, " \r\n");
     if(hlen != len)
     if(hlen != len)
       /* hostname with bad content */
       /* hostname with bad content */
-      return CURLUE_MALFORMED_INPUT;
+      return CURLUE_BAD_HOSTNAME;
   }
   }
   if(!hostname[0])
   if(!hostname[0])
     return CURLUE_NO_HOST;
     return CURLUE_NO_HOST;
@@ -756,10 +789,35 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
   return TRUE;
   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)
 static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
 {
 {
   char *path;
   char *path;
   bool path_alloced = FALSE;
   bool path_alloced = FALSE;
+  bool uncpath = FALSE;
   char *hostname;
   char *hostname;
   char *query = NULL;
   char *query = NULL;
   char *fragment = NULL;
   char *fragment = NULL;
@@ -794,11 +852,14 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
   }
   }
 
 
   /* handle the file: scheme */
   /* 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 */
     /* path has been allocated large enough to hold this */
     strcpy(path, &url[5]);
     strcpy(path, &url[5]);
 
 
-    hostname = NULL; /* no host for file: URLs */
     u->scheme = strdup("file");
     u->scheme = strdup("file");
     if(!u->scheme)
     if(!u->scheme)
       return CURLUE_OUT_OF_MEMORY;
       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 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
        * 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
        * Additionally, there is an exception for URLs with a Windows drive
        * letter in the authority (which was accidentally omitted from RFC 8089
        * 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)) {
       if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
         /* the URL includes a host name, it must match "localhost" or
         /* the URL includes a host name, it must match "localhost" or
            "127.0.0.1" to be valid */
            "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
           /* Invalid file://hostname/, expected localhost or 127.0.0.1 or
              none */
              none */
-          return CURLUE_MALFORMED_INPUT;
+          return CURLUE_BAD_FILE_URL;
+#endif
         }
         }
-        ptr += 9; /* now points to the slash after the host */
       }
       }
 
 
       path = ptr;
       path = ptr;
     }
     }
 
 
+    if(!uncpath)
+        hostname = NULL; /* no host for file: URLs by default */
+
 #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
 #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
     /* Don't allow Windows drive letters when not in Windows.
     /* Don't allow Windows drive letters when not in Windows.
      * This catches both "file:/c:" and "file:c:" */
      * This catches both "file:/c:" and "file:c:" */
     if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
     if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
        STARTS_WITH_URL_DRIVE_PREFIX(path)) {
        STARTS_WITH_URL_DRIVE_PREFIX(path)) {
       /* File drive letters are only accepted in MSDOS/Windows */
       /* File drive letters are only accepted in MSDOS/Windows */
-      return CURLUE_MALFORMED_INPUT;
+      return CURLUE_BAD_FILE_URL;
     }
     }
 #else
 #else
     /* If the path starts with a slash and a drive letter, ditch the slash */
     /* 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))
       if((i < 1) || (i>3))
         /* less than one or more than three slashes */
         /* less than one or more than three slashes */
-        return CURLUE_MALFORMED_INPUT;
+        return CURLUE_BAD_SLASHES;
 
 
       schemep = schemebuf;
       schemep = schemebuf;
       if(!Curl_builtin_scheme(schemep) &&
       if(!Curl_builtin_scheme(schemep) &&
@@ -885,13 +974,13 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
         return CURLUE_UNSUPPORTED_SCHEME;
         return CURLUE_UNSUPPORTED_SCHEME;
 
 
       if(junkscan(schemep, flags))
       if(junkscan(schemep, flags))
-        return CURLUE_MALFORMED_INPUT;
+        return CURLUE_BAD_SCHEME;
     }
     }
     else {
     else {
       /* no scheme! */
       /* no scheme! */
 
 
       if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME)))
       if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME)))
-        return CURLUE_MALFORMED_INPUT;
+        return CURLUE_BAD_SCHEME;
       if(flags & CURLU_DEFAULT_SCHEME)
       if(flags & CURLU_DEFAULT_SCHEME)
         schemep = 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 */
     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++;
       p++;
 
 
     len = p - hostp;
     len = p - hostp;
@@ -912,7 +1002,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
     }
     }
     else {
     else {
       if(!(flags & CURLU_NO_AUTHORITY))
       if(!(flags & CURLU_NO_AUTHORITY))
-        return CURLUE_MALFORMED_INPUT;
+        return CURLUE_NO_HOST;
     }
     }
 
 
     len = strlen(p);
     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]) {
   if((flags & CURLU_URLENCODE) && path[0]) {
     /* worst case output length is 3x the original! */
     /* worst case output length is 3x the original! */
     char *newp = malloc(strlen(path) * 3);
     char *newp = malloc(strlen(path) * 3);
@@ -942,6 +1029,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
   fragment = strchr(path, '#');
   fragment = strchr(path, '#');
   if(fragment) {
   if(fragment) {
     *fragment++ = 0;
     *fragment++ = 0;
+    if(junkscan(fragment, flags))
+      return CURLUE_BAD_FRAGMENT;
     if(fragment[0]) {
     if(fragment[0]) {
       u->fragment = strdup(fragment);
       u->fragment = strdup(fragment);
       if(!u->fragment)
       if(!u->fragment)
@@ -952,12 +1041,17 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
   query = strchr(path, '?');
   query = strchr(path, '?');
   if(query) {
   if(query) {
     *query++ = 0;
     *query++ = 0;
+    if(junkscan(query, flags))
+      return CURLUE_BAD_QUERY;
     /* done even if the query part is a blank string */
     /* done even if the query part is a blank string */
     u->query = strdup(query);
     u->query = strdup(query);
     if(!u->query)
     if(!u->query)
       return CURLUE_OUT_OF_MEMORY;
       return CURLUE_OUT_OF_MEMORY;
   }
   }
 
 
+  if(junkscan(path, flags))
+    return CURLUE_BAD_PATH;
+
   if(!path[0])
   if(!path[0])
     /* if there's no path left set, unset */
     /* if there's no path left set, unset */
     path = NULL;
     path = NULL;
@@ -987,12 +1081,10 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
 
 
   if(hostname) {
   if(hostname) {
     char normalized_ipv4[sizeof("255.255.255.255") + 1];
     char normalized_ipv4[sizeof("255.255.255.255") + 1];
+
     /*
     /*
      * Parse the login details and strip them out of the host name.
      * 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);
     result = parse_hostname_login(u, &hostname, flags);
     if(result)
     if(result)
       return result;
       return result;
@@ -1001,22 +1093,27 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
     if(result)
     if(result)
       return result;
       return result;
 
 
+    if(junkscan(hostname, flags))
+      return CURLUE_BAD_HOSTNAME;
+
     if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) {
     if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) {
       /* Skip hostname check, it's allowed to be empty. */
       /* Skip hostname check, it's allowed to be empty. */
+      u->host = strdup("");
     }
     }
     else {
     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)
     if(!u->host)
       return CURLUE_OUT_OF_MEMORY;
       return CURLUE_OUT_OF_MEMORY;
-
     if((flags & CURLU_GUESS_SCHEME) && !schemep) {
     if((flags & CURLU_GUESS_SCHEME) && !schemep) {
       /* legacy curl-style guess based on host name */
       /* legacy curl-style guess based on host name */
       if(checkprefix("ftp.", hostname))
       if(checkprefix("ftp.", hostname))
@@ -1111,6 +1208,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
   CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
   CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
   char portbuf[7];
   char portbuf[7];
   bool urldecode = (flags & CURLU_URLDECODE)?1:0;
   bool urldecode = (flags & CURLU_URLDECODE)?1:0;
+  bool urlencode = (flags & CURLU_URLENCODE)?1:0;
   bool plusdecode = FALSE;
   bool plusdecode = FALSE;
   (void)flags;
   (void)flags;
   if(!u)
   if(!u)
@@ -1143,6 +1241,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
     break;
     break;
   case CURLUPART_ZONEID:
   case CURLUPART_ZONEID:
     ptr = u->zoneid;
     ptr = u->zoneid;
+    ifmissing = CURLUE_NO_ZONEID;
     break;
     break;
   case CURLUPART_PORT:
   case CURLUPART_PORT:
     ptr = u->port;
     ptr = u->port;
@@ -1228,16 +1327,54 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
       if(h && !(h->flags & PROTOPT_URLOPTIONS))
       if(h && !(h->flags & PROTOPT_URLOPTIONS))
         options = NULL;
         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)
         if(!allochost)
           return CURLUE_OUT_OF_MEMORY;
           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",
       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:
   case CURLUPART_SCHEME:
     if(strlen(part) > MAX_SCHEME_LEN)
     if(strlen(part) > MAX_SCHEME_LEN)
       /* too long */
       /* too long */
-      return CURLUE_MALFORMED_INPUT;
+      return CURLUE_BAD_SCHEME;
     if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
     if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
        /* verify that it is a fine scheme */
        /* verify that it is a fine scheme */
        !Curl_builtin_scheme(part))
        !Curl_builtin_scheme(part))
@@ -1379,10 +1516,15 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
   case CURLUPART_OPTIONS:
   case CURLUPART_OPTIONS:
     storep = &u->options;
     storep = &u->options;
     break;
     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;
     storep = &u->host;
     Curl_safefree(u->zoneid);
     Curl_safefree(u->zoneid);
     break;
     break;
+  }
   case CURLUPART_ZONEID:
   case CURLUPART_ZONEID:
     storep = &u->zoneid;
     storep = &u->zoneid;
     break;
     break;
@@ -1395,7 +1537,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
       return CURLUE_BAD_PORT_NUMBER;
       return CURLUE_BAD_PORT_NUMBER;
     if(*endp)
     if(*endp)
       /* weirdly provided number, not good! */
       /* weirdly provided number, not good! */
-      return CURLUE_MALFORMED_INPUT;
+      return CURLUE_BAD_PORT_NUMBER;
     storep = &u->port;
     storep = &u->port;
   }
   }
   break;
   break;
@@ -1424,7 +1566,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
     char *redired_url;
     char *redired_url;
     CURLU *handle2;
     CURLU *handle2;
 
 
-    if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN + 1)) {
+    if(Curl_is_absolute_url(part, NULL, 0)) {
       handle2 = curl_url();
       handle2 = curl_url();
       if(!handle2)
       if(!handle2)
         return CURLUE_OUT_OF_MEMORY;
         return CURLUE_OUT_OF_MEMORY;
@@ -1559,7 +1701,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
       else {
       else {
         if(hostname_check(u, (char *)newp)) {
         if(hostname_check(u, (char *)newp)) {
           free((char *)newp);
           free((char *)newp);
-          return CURLUE_MALFORMED_INPUT;
+          return CURLUE_BAD_HOSTNAME;
         }
         }
       }
       }
     }
     }

+ 12 - 2
Utilities/cmcurl/lib/urldata.h

@@ -330,7 +330,7 @@ struct digestdata {
   char *opaque;
   char *opaque;
   char *qop;
   char *qop;
   char *algorithm;
   char *algorithm;
-  int nc; /* nounce count */
+  int nc; /* nonce count */
   BIT(stale); /* set true for re-negotiation */
   BIT(stale); /* set true for re-negotiation */
   BIT(userhash);
   BIT(userhash);
 #endif
 #endif
@@ -518,7 +518,9 @@ struct ConnectBits {
   BIT(tls_enable_npn);  /* TLS NPN extension? */
   BIT(tls_enable_npn);  /* TLS NPN extension? */
   BIT(tls_enable_alpn); /* TLS ALPN extension? */
   BIT(tls_enable_alpn); /* TLS ALPN extension? */
   BIT(connect_only);
   BIT(connect_only);
+#ifndef CURL_DISABLE_DOH
   BIT(doh);
   BIT(doh);
+#endif
 #ifdef USE_UNIX_SOCKETS
 #ifdef USE_UNIX_SOCKETS
   BIT(abstract_unix_socket);
   BIT(abstract_unix_socket);
 #endif
 #endif
@@ -835,6 +837,7 @@ struct Curl_handler {
 #define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
 #define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
 #define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in
 #define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in
                                        user name and password */
                                        user name and password */
+#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol can't proxy over TCP */
 
 
 #define CONNCHECK_NONE 0                 /* No checks */
 #define CONNCHECK_NONE 0                 /* No checks */
 #define CONNCHECK_ISDEAD (1<<0)          /* Check if the connection is dead. */
 #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_PRIVATE_KEY, /* path to the private key file for auth */
   STRING_SSH_PUBLIC_KEY,  /* path to the public 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_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_SSH_KNOWNHOSTS,  /* file name of knownhosts file */
   STRING_PROXY_SERVICE_NAME, /* Proxy service name */
   STRING_PROXY_SERVICE_NAME, /* Proxy service name */
   STRING_SERVICE_NAME,    /* Service name */
   STRING_SERVICE_NAME,    /* Service name */
@@ -1651,6 +1655,8 @@ struct UserDefined {
   curl_closesocket_callback fclosesocket; /* function for closing the
   curl_closesocket_callback fclosesocket; /* function for closing the
                                              socket */
                                              socket */
   void *closesocket_client;
   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 */
   void *seek_client;    /* pointer to pass to the seek callback */
   /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
   /* 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 server_response_timeout; /* in milliseconds, 0 means no timeout */
   long maxage_conn;     /* in seconds, max idle time to allow a connection that
   long maxage_conn;     /* in seconds, max idle time to allow a connection that
                            is to be reused */
                            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 */
   long tftp_blksize;    /* in bytes, 0 means use default */
   curl_off_t filesize;  /* size of file to upload, -1 means unknown */
   curl_off_t filesize;  /* size of file to upload, -1 means unknown */
   long low_speed_limit; /* bytes/second */
   long low_speed_limit; /* bytes/second */
@@ -1744,6 +1752,7 @@ struct UserDefined {
   unsigned int scope_id;  /* Scope id for IPv6 */
   unsigned int scope_id;  /* Scope id for IPv6 */
   long allowed_protocols;
   long allowed_protocols;
   long redir_protocols;
   long redir_protocols;
+  long mime_options;      /* Mime option flags. */
   struct curl_slist *mail_rcpt; /* linked list of mail recipients */
   struct curl_slist *mail_rcpt; /* linked list of mail recipients */
   /* Common RTSP header options */
   /* Common RTSP header options */
   Curl_RtspReq rtspreq; /* RTSP request type */
   Curl_RtspReq rtspreq; /* RTSP request type */
@@ -1851,11 +1860,12 @@ struct UserDefined {
                            header */
                            header */
   BIT(abstract_unix_socket);
   BIT(abstract_unix_socket);
   BIT(disallow_username_in_url); /* disallow username in url */
   BIT(disallow_username_in_url); /* disallow username in url */
+#ifndef CURL_DISABLE_DOH
   BIT(doh); /* DNS-over-HTTPS enabled */
   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_verifypeer);     /* DoH certificate peer verification */
   BIT(doh_verifyhost);     /* DoH certificate hostname verification */
   BIT(doh_verifyhost);     /* DoH certificate hostname verification */
   BIT(doh_verifystatus);   /* DoH certificate status verification */
   BIT(doh_verifystatus);   /* DoH certificate status verification */
+#endif
   BIT(http09_allowed); /* allow HTTP/0.9 responses */
   BIT(http09_allowed); /* allow HTTP/0.9 responses */
   BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
   BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
                                 recipients */
                                 recipients */

+ 5 - 6
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;
     return CURLE_OUT_OF_MEMORY;
 
 
   token = strtok_r(tmp, ",", &tok_buf);
   token = strtok_r(tmp, ",", &tok_buf);
-  while(token != NULL) {
+  while(token) {
     if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
     if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
       *value |= DIGEST_QOP_VALUE_AUTH;
       *value |= DIGEST_QOP_VALUE_AUTH;
     else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
     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;
           return CURLE_OUT_OF_MEMORY;
 
 
         token = strtok_r(tmp, ",", &tok_buf);
         token = strtok_r(tmp, ",", &tok_buf);
-        while(token != NULL) {
+        while(token) {
           if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
           if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
             foundAuth = TRUE;
             foundAuth = TRUE;
           }
           }
@@ -666,8 +666,8 @@ static CURLcode auth_create_digest_http_message(
                   struct digestdata *digest,
                   struct digestdata *digest,
                   char **outptr, size_t *outlen,
                   char **outptr, size_t *outlen,
                   void (*convert_to_ascii)(unsigned char *, unsigned char *),
                   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;
   CURLcode result;
   unsigned char hashbuf[32]; /* 32 bytes/256 bits */
   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)
            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)
   if(!hashthis)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 

+ 3 - 1
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, &ntlm->nonce[0], 8);
     memcpy(tmp + 8, entropy, 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
     /* 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 */
        Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */

+ 101 - 12
Utilities/cmcurl/lib/version_win32.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2016 - 2020, Steve Holme, <[email protected]>.
+ * Copyright (C) 2016 - 2021, Steve Holme, <[email protected]>.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -26,11 +26,28 @@
 
 
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include "version_win32.h"
 #include "version_win32.h"
+#include "warnless.h"
 
 
 /* The last #include files should be: */
 /* The last #include files should be: */
 #include "curl_memory.h"
 #include "curl_memory.h"
 #include "memdebug.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()
  * curlx_verify_windows_version()
  *
  *
@@ -40,6 +57,8 @@
  *
  *
  * majorVersion [in] - The major version number.
  * majorVersion [in] - The major version number.
  * minorVersion [in] - The minor 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.
  * platform     [in] - The optional platform identifier.
  * condition    [in] - The test condition used to specifier whether we are
  * condition    [in] - The test condition used to specifier whether we are
  *                     checking a version less then, equal to or greater than
  *                     checking a version less then, equal to or greater than
@@ -50,6 +69,7 @@
  */
  */
 bool curlx_verify_windows_version(const unsigned int majorVersion,
 bool curlx_verify_windows_version(const unsigned int majorVersion,
                                   const unsigned int minorVersion,
                                   const unsigned int minorVersion,
+                                  const unsigned int buildVersion,
                                   const PlatformIdentifier platform,
                                   const PlatformIdentifier platform,
                                   const VersionCondition condition)
                                   const VersionCondition condition)
 {
 {
@@ -101,34 +121,52 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
     case VERSION_LESS_THAN:
     case VERSION_LESS_THAN:
       if(osver.dwMajorVersion < majorVersion ||
       if(osver.dwMajorVersion < majorVersion ||
         (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;
         matched = TRUE;
       break;
       break;
 
 
     case VERSION_LESS_THAN_EQUAL:
     case VERSION_LESS_THAN_EQUAL:
       if(osver.dwMajorVersion < majorVersion ||
       if(osver.dwMajorVersion < majorVersion ||
         (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;
         matched = TRUE;
       break;
       break;
 
 
     case VERSION_EQUAL:
     case VERSION_EQUAL:
       if(osver.dwMajorVersion == majorVersion &&
       if(osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion == minorVersion)
+         osver.dwMinorVersion == minorVersion &&
+        (buildVersion == 0 ||
+         osver.dwBuildNumber == buildVersion))
         matched = TRUE;
         matched = TRUE;
       break;
       break;
 
 
     case VERSION_GREATER_THAN_EQUAL:
     case VERSION_GREATER_THAN_EQUAL:
       if(osver.dwMajorVersion > majorVersion ||
       if(osver.dwMajorVersion > majorVersion ||
         (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;
         matched = TRUE;
       break;
       break;
 
 
     case VERSION_GREATER_THAN:
     case VERSION_GREATER_THAN:
       if(osver.dwMajorVersion > majorVersion ||
       if(osver.dwMajorVersion > majorVersion ||
         (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;
         matched = TRUE;
       break;
       break;
     }
     }
@@ -144,6 +182,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
       case PLATFORM_WINNT:
       case PLATFORM_WINNT:
         if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
         if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
           matched = FALSE;
           matched = FALSE;
+        break;
 
 
       default: /* like platform == PLATFORM_DONT_CARE */
       default: /* like platform == PLATFORM_DONT_CARE */
         break;
         break;
@@ -152,16 +191,31 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
   }
   }
 #else
 #else
   ULONGLONG cm = 0;
   ULONGLONG cm = 0;
-  OSVERSIONINFOEX osver;
+  struct OUR_OSVERSIONINFOEXW osver;
   BYTE majorCondition;
   BYTE majorCondition;
   BYTE minorCondition;
   BYTE minorCondition;
+  BYTE buildCondition;
   BYTE spMajorCondition;
   BYTE spMajorCondition;
   BYTE spMinorCondition;
   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) {
   switch(condition) {
   case VERSION_LESS_THAN:
   case VERSION_LESS_THAN:
     majorCondition = VER_LESS;
     majorCondition = VER_LESS;
     minorCondition = VER_LESS;
     minorCondition = VER_LESS;
+    buildCondition = VER_LESS;
     spMajorCondition = VER_LESS_EQUAL;
     spMajorCondition = VER_LESS_EQUAL;
     spMinorCondition = VER_LESS_EQUAL;
     spMinorCondition = VER_LESS_EQUAL;
     break;
     break;
@@ -169,6 +223,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
   case VERSION_LESS_THAN_EQUAL:
   case VERSION_LESS_THAN_EQUAL:
     majorCondition = VER_LESS_EQUAL;
     majorCondition = VER_LESS_EQUAL;
     minorCondition = VER_LESS_EQUAL;
     minorCondition = VER_LESS_EQUAL;
+    buildCondition = VER_LESS_EQUAL;
     spMajorCondition = VER_LESS_EQUAL;
     spMajorCondition = VER_LESS_EQUAL;
     spMinorCondition = VER_LESS_EQUAL;
     spMinorCondition = VER_LESS_EQUAL;
     break;
     break;
@@ -176,6 +231,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
   case VERSION_EQUAL:
   case VERSION_EQUAL:
     majorCondition = VER_EQUAL;
     majorCondition = VER_EQUAL;
     minorCondition = VER_EQUAL;
     minorCondition = VER_EQUAL;
+    buildCondition = VER_EQUAL;
     spMajorCondition = VER_GREATER_EQUAL;
     spMajorCondition = VER_GREATER_EQUAL;
     spMinorCondition = VER_GREATER_EQUAL;
     spMinorCondition = VER_GREATER_EQUAL;
     break;
     break;
@@ -183,6 +239,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
   case VERSION_GREATER_THAN_EQUAL:
   case VERSION_GREATER_THAN_EQUAL:
     majorCondition = VER_GREATER_EQUAL;
     majorCondition = VER_GREATER_EQUAL;
     minorCondition = VER_GREATER_EQUAL;
     minorCondition = VER_GREATER_EQUAL;
+    buildCondition = VER_GREATER_EQUAL;
     spMajorCondition = VER_GREATER_EQUAL;
     spMajorCondition = VER_GREATER_EQUAL;
     spMinorCondition = VER_GREATER_EQUAL;
     spMinorCondition = VER_GREATER_EQUAL;
     break;
     break;
@@ -190,6 +247,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
   case VERSION_GREATER_THAN:
   case VERSION_GREATER_THAN:
     majorCondition = VER_GREATER;
     majorCondition = VER_GREATER;
     minorCondition = VER_GREATER;
     minorCondition = VER_GREATER;
+    buildCondition = VER_GREATER;
     spMajorCondition = VER_GREATER_EQUAL;
     spMajorCondition = VER_GREATER_EQUAL;
     spMinorCondition = VER_GREATER_EQUAL;
     spMinorCondition = VER_GREATER_EQUAL;
     break;
     break;
@@ -202,6 +260,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
   osver.dwOSVersionInfoSize = sizeof(osver);
   osver.dwOSVersionInfoSize = sizeof(osver);
   osver.dwMajorVersion = majorVersion;
   osver.dwMajorVersion = majorVersion;
   osver.dwMinorVersion = minorVersion;
   osver.dwMinorVersion = minorVersion;
+  osver.dwBuildNumber = buildVersion;
   if(platform == PLATFORM_WINDOWS)
   if(platform == PLATFORM_WINDOWS)
     osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
     osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
   else if(platform == PLATFORM_WINNT)
   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_MINORVERSION, minorCondition);
   cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
   cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
   cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
   cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
-  if(platform != PLATFORM_DONT_CARE)
+
+  if(platform != PLATFORM_DONT_CARE) {
     cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
     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
 #endif
 
 
   return matched;
   return matched;

+ 2 - 1
Utilities/cmcurl/lib/version_win32.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2016 - 2020, Steve Holme, <[email protected]>.
+ * Copyright (C) 2016 - 2021, Steve Holme, <[email protected]>.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * 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 */
 /* This is used to verify if we are running on a specific windows version */
 bool curlx_verify_windows_version(const unsigned int majorVersion,
 bool curlx_verify_windows_version(const unsigned int majorVersion,
                                   const unsigned int minorVersion,
                                   const unsigned int minorVersion,
+                                  const unsigned int buildVersion,
                                   const PlatformIdentifier platform,
                                   const PlatformIdentifier platform,
                                   const VersionCondition condition);
                                   const VersionCondition condition);
 
 

+ 87 - 20
Utilities/cmcurl/lib/vquic/ngtcp2.c

@@ -29,8 +29,10 @@
 #ifdef USE_OPENSSL
 #ifdef USE_OPENSSL
 #include <openssl/err.h>
 #include <openssl/err.h>
 #include <ngtcp2/ngtcp2_crypto_openssl.h>
 #include <ngtcp2/ngtcp2_crypto_openssl.h>
+#include "vtls/openssl.h"
 #elif defined(USE_GNUTLS)
 #elif defined(USE_GNUTLS)
 #include <ngtcp2/ngtcp2_crypto_gnutls.h>
 #include <ngtcp2/ngtcp2_crypto_gnutls.h>
+#include "vtls/gtls.h"
 #endif
 #endif
 #include "urldata.h"
 #include "urldata.h"
 #include "sendf.h"
 #include "sendf.h"
@@ -61,6 +63,7 @@
 #endif
 #endif
 
 
 #define H3_ALPN_H3_29 "\x5h3-29"
 #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.
  * 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);
     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;
   return ssl_ctx;
 }
 }
 
 
@@ -303,9 +327,10 @@ static int quic_init_ssl(struct quicsocket *qs)
 
 
   SSL_set_app_data(qs->ssl, qs);
   SSL_set_app_data(qs->ssl, qs);
   SSL_set_connect_state(qs->ssl);
   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)
   if(alpn)
     SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
     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)
 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 */
   /* this will need some attention when HTTPS proxy over QUIC get fixed */
   const char * const hostname = qs->conn->host.name;
   const char * const hostname = qs->conn->host.name;
   int rc;
   int rc;
@@ -439,12 +464,10 @@ static int quic_init_ssl(struct quicsocket *qs)
   gnutls_alert_set_read_function(qs->ssl, alert_read_func);
   gnutls_alert_set_read_function(qs->ssl, alert_read_func);
 
 
   rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters",
   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) {
   if(rc < 0) {
     H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
     H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
                    gnutls_strerror(rc)));
                    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 */
   /* 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 */
   /* set SNI */
   gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
   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;
   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,
 static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
                                     uint8_t *token, size_t cidlen,
                                     uint8_t *token, size_t cidlen,
                                     void *user_data)
                                     void *user_data)
@@ -685,7 +724,7 @@ static ngtcp2_callbacks ng_callbacks = {
   ngtcp2_crypto_recv_retry_cb,
   ngtcp2_crypto_recv_retry_cb,
   cb_extend_max_local_streams_bidi,
   cb_extend_max_local_streams_bidi,
   NULL, /* extend_max_local_streams_uni */
   NULL, /* extend_max_local_streams_uni */
-  NULL, /* rand  */
+  cb_rand,
   cb_get_new_connection_id,
   cb_get_new_connection_id,
   NULL, /* remove_connection_id */
   NULL, /* remove_connection_id */
   ngtcp2_crypto_update_key_cb, /* update_key */
   ngtcp2_crypto_update_key_cb, /* update_key */
@@ -703,7 +742,7 @@ static ngtcp2_callbacks ng_callbacks = {
   NULL, /* recv_datagram */
   NULL, /* recv_datagram */
   NULL, /* ack_datagram */
   NULL, /* ack_datagram */
   NULL, /* lost_datagram */
   NULL, /* lost_datagram */
-  NULL, /* get_path_challenge_data */
+  ngtcp2_crypto_get_path_challenge_data_cb,
   cb_stream_stop_sending
   cb_stream_stop_sending
 };
 };
 
 
@@ -776,7 +815,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
   ngtcp2_addr_init(&path.remote, addr, addrlen);
   ngtcp2_addr_init(&path.remote, addr, addrlen);
 
 
   rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path,
   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);
                               &qs->settings, &qs->transport_params, NULL, qs);
   if(rc)
   if(rc)
     return CURLE_QUIC_CONNECT_ERROR;
     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)
 void Curl_quic_ver(char *p, size_t len)
 {
 {
   const ngtcp2_info *ng2 = ngtcp2_version(0);
   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",
   (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
                   ng2->version_str, ht3->version_str);
                   ng2->version_str, ht3->version_str);
 }
 }
@@ -1622,8 +1661,10 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
   return sent;
   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->recv[FIRSTSOCKET] = ngh3_stream_recv;
   conn->send[FIRSTSOCKET] = ngh3_stream_send;
   conn->send[FIRSTSOCKET] = ngh3_stream_send;
   conn->handler = &Curl_handler_http3;
   conn->handler = &Curl_handler_http3;
@@ -1631,6 +1672,27 @@ static void ng_has_connected(struct connectdata *conn, int tempindex)
   conn->httpversion = 30;
   conn->httpversion = 30;
   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
   conn->quic = &conn->hequic[tempindex];
   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;
     goto error;
 
 
   if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
   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;
   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);
     rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts);
     if(rv) {
     if(rv) {
       /* TODO Send CONNECTION_CLOSE if possible */
       /* 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;
       return CURLE_RECV_ERROR;
     }
     }
   }
   }

+ 130 - 24
Utilities/cmcurl/lib/vssh/libssh2.c

@@ -81,6 +81,11 @@
 #include "select.h"
 #include "select.h"
 #include "warnless.h"
 #include "warnless.h"
 #include "curl_path.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 */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -615,40 +620,141 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   struct ssh_conn *sshc = &conn->proto.sshc;
   const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
   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. */
     /* 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);
       state(data, SSH_SESSION_FREE);
       sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
       sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
       return sshc->actualcode;
       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 */
     /* as we already matched, we skip the check for known hosts */
     return CURLE_OK;
     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 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
 /* The SSH session is associated with the *CONNECTION* but the callback user

+ 4 - 2
Utilities/cmcurl/lib/vssh/wolfssh.c

@@ -449,7 +449,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
     switch(sshc->state) {
     switch(sshc->state) {
     case SSH_INIT:
     case SSH_INIT:
       state(data, SSH_S_STARTUP);
       state(data, SSH_S_STARTUP);
-      /* FALLTHROUGH */
+      break;
+
     case SSH_S_STARTUP:
     case SSH_S_STARTUP:
       rc = wolfSSH_connect(sshc->ssh_session);
       rc = wolfSSH_connect(sshc->ssh_session);
       if(rc != WS_SUCCESS)
       if(rc != WS_SUCCESS)
@@ -838,7 +839,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
         break;
         break;
       }
       }
       state(data, SSH_SFTP_READDIR);
       state(data, SSH_SFTP_READDIR);
-      /* FALLTHROUGH */
+      break;
+
     case SSH_SFTP_READDIR:
     case SSH_SFTP_READDIR:
       name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path);
       name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path);
       if(!name)
       if(!name)

+ 4 - 2
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)) {
   if(SSL_SET_OPTION(primary.sessionid)) {
     bool incache;
     bool incache;
+    bool added = FALSE;
     void *oldsession;
     void *oldsession;
     br_ssl_session_parameters *session;
     br_ssl_session_parameters *session;
 
 
@@ -623,10 +624,11 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
       Curl_ssl_delsessionid(data, oldsession);
       Curl_ssl_delsessionid(data, oldsession);
     ret = Curl_ssl_addsessionid(data, conn,
     ret = Curl_ssl_addsessionid(data, conn,
                                 SSL_IS_PROXY() ? TRUE : FALSE,
                                 SSL_IS_PROXY() ? TRUE : FALSE,
-                                session, 0, sockindex);
+                                session, 0, sockindex, &added);
     Curl_ssl_sessionid_unlock(data);
     Curl_ssl_sessionid_unlock(data);
-    if(ret) {
+    if(!added)
       free(session);
       free(session);
+    if(ret) {
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
   }
   }

+ 40 - 39
Utilities/cmcurl/lib/vtls/gtls.c

@@ -404,6 +404,7 @@ gtls_connect_step1(struct Curl_easy *data,
   const char * const hostname = SSL_HOST_NAME();
   const char * const hostname = SSL_HOST_NAME();
   long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
   long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
   const char *tls13support;
   const char *tls13support;
+  CURLcode result;
 
 
   if(connssl->state == ssl_connection_complete)
   if(connssl->state == ssl_connection_complete)
     /* to make us tolerant against being called more than once for the
     /* 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 */
   /* use system ca certificate store as fallback */
   if(SSL_CONN_CONFIG(verifypeer) &&
   if(SSL_CONN_CONFIG(verifypeer) &&
      !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
      !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
+    /* this ignores errors on purpose */
     gnutls_certificate_set_x509_system_trust(backend->cred);
     gnutls_certificate_set_x509_system_trust(backend->cred);
   }
   }
 #endif
 #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
   /* 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
    * removed if a run-time error indicates that SRP is not supported by this
    * GnuTLS version */
    * 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;
       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
 #ifdef HAVE_GNUTLS_SRP
   /* Only add SRP to the cipher list if SRP is requested. Otherwise
   /* Only add SRP to the cipher list if SRP is requested. Otherwise
    * GnuTLS will disable TLS 1.3 support. */
    * GnuTLS will disable TLS 1.3 support. */
@@ -636,7 +632,10 @@ gtls_connect_step1(struct Curl_easy *data,
     cur++;
     cur++;
     infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
     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)) {
   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;
   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
 
 
   /* if a path wasn't specified, don't pin */
   /* if a path wasn't specified, don't pin */
-  if(NULL == pinnedpubkey)
+  if(!pinnedpubkey)
     return CURLE_OK;
     return CURLE_OK;
 
 
-  if(NULL == cert)
+  if(!cert)
     return result;
     return result;
 
 
   do {
   do {
@@ -783,7 +782,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
       break; /* failed */
       break; /* failed */
 
 
     buff1 = malloc(len1);
     buff1 = malloc(len1);
-    if(NULL == buff1)
+    if(!buff1)
       break; /* failed */
       break; /* failed */
 
 
     len2 = len1;
     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);
     result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
   } while(0);
   } while(0);
 
 
-  if(NULL != key)
+  if(key)
     gnutls_pubkey_deinit(key);
     gnutls_pubkey_deinit(key);
 
 
   Curl_safefree(buff1);
   Curl_safefree(buff1);
@@ -809,10 +808,11 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
 static Curl_recv gtls_recv;
 static Curl_recv gtls_recv;
 static Curl_send gtls_send;
 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;
   unsigned int cert_list_size;
   const gnutls_datum_t *chainp;
   const gnutls_datum_t *chainp;
@@ -824,9 +824,6 @@ gtls_connect_step3(struct Curl_easy *data,
   size_t size;
   size_t size;
   time_t certclock;
   time_t certclock;
   const char *ptr;
   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;
   int rc;
   gnutls_datum_t proto;
   gnutls_datum_t proto;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
@@ -1270,8 +1267,6 @@ gtls_connect_step3(struct Curl_easy *data,
   }
   }
 
 
   conn->ssl[sockindex].state = ssl_connection_complete;
   conn->ssl[sockindex].state = ssl_connection_complete;
-  conn->recv[sockindex] = gtls_recv;
-  conn->send[sockindex] = gtls_send;
 
 
   if(SSL_SET_OPTION(primary.sessionid)) {
   if(SSL_SET_OPTION(primary.sessionid)) {
     /* we always unconditionally get the session id here, as even if we
     /* 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) {
     if(connect_sessionid) {
       bool incache;
       bool incache;
+      bool added = FALSE;
       void *ssl_sessionid;
       void *ssl_sessionid;
 
 
       /* extract session ID to the allocated buffer */
       /* extract session ID to the allocated buffer */
@@ -1306,10 +1302,11 @@ gtls_connect_step3(struct Curl_easy *data,
       result = Curl_ssl_addsessionid(data, conn,
       result = Curl_ssl_addsessionid(data, conn,
                                      SSL_IS_PROXY() ? TRUE : FALSE,
                                      SSL_IS_PROXY() ? TRUE : FALSE,
                                      connect_sessionid, connect_idsize,
                                      connect_sessionid, connect_idsize,
-                                     sockindex);
+                                     sockindex, &added);
       Curl_ssl_sessionid_unlock(data);
       Curl_ssl_sessionid_unlock(data);
-      if(result) {
+      if(!added)
         free(connect_sessionid);
         free(connect_sessionid);
+      if(result) {
         result = CURLE_OUT_OF_MEMORY;
         result = CURLE_OUT_OF_MEMORY;
       }
       }
     }
     }
@@ -1354,9 +1351,13 @@ gtls_connect_common(struct Curl_easy *data,
 
 
   /* Finish connecting once the handshake is done */
   /* Finish connecting once the handshake is done */
   if(ssl_connect_1 == connssl->connecting_state) {
   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)
     if(rc)
       return rc;
       return rc;
+    conn->recv[sockindex] = gtls_recv;
+    conn->send[sockindex] = gtls_send;
   }
   }
 
 
   *done = ssl_connect_1 == connssl->connecting_state;
   *done = ssl_connect_1 == connssl->connecting_state;

+ 6 - 2
Utilities/cmcurl/lib/vtls/gtls.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -27,7 +27,11 @@
 #ifdef USE_GNUTLS
 #ifdef USE_GNUTLS
 
 
 #include "urldata.h"
 #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;
 extern const struct Curl_ssl Curl_ssl_gnutls;
 
 
 #endif /* USE_GNUTLS */
 #endif /* USE_GNUTLS */

+ 46 - 14
Utilities/cmcurl/lib/vtls/mbedtls.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2012 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2022, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <[email protected]>
  * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <[email protected]>
  *
  *
  * This software is licensed as described in the file COPYING, which
  * 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_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   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 bool verifypeer = SSL_CONN_CONFIG(verifypeer);
   const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
   const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
   char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
   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 */
   /* Load the trusted CA */
   mbedtls_x509_crt_init(&backend->cacert);
   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);
     ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile);
 
 
     if(ret<0) {
     if(ret<0) {
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
       failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
       failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
             ssl_cafile, -ret, errorbuf);
             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) {
   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);
                                  ssl_cert_blob->len);
+    free(newblob);
 
 
     if(ret) {
     if(ret) {
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
       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;
     mbedtls_x509_crt *p = NULL;
     unsigned char *pubkey = NULL;
     unsigned char *pubkey = NULL;
 
 
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
     if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) ||
     if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) ||
        !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) {
        !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) {
 #else
 #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
     /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
        needs a non-const key, for now.
        needs a non-const key, for now.
        https://github.com/ARMmbed/mbedtls/issues/396 */
        https://github.com/ARMmbed/mbedtls/issues/396 */
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
     if(mbedtls_x509_crt_parse_der(p,
     if(mbedtls_x509_crt_parse_der(p,
                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) {
                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) {
@@ -710,7 +738,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
       goto pinnedpubkey_error;
       goto pinnedpubkey_error;
     }
     }
 
 
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
     size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey,
     size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey,
                                        PUB_DER_MAX_BYTES);
                                        PUB_DER_MAX_BYTES);
 #else
 #else
@@ -784,6 +812,7 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
     mbedtls_ssl_session *our_ssl_sessionid;
     mbedtls_ssl_session *our_ssl_sessionid;
     void *old_ssl_sessionid = NULL;
     void *old_ssl_sessionid = NULL;
     bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
     bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
+    bool added = FALSE;
 
 
     our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
     our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
     if(!our_ssl_sessionid)
     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);
       Curl_ssl_delsessionid(data, old_ssl_sessionid);
 
 
     retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
     retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
-                                    0, sockindex);
+                                    0, sockindex, &added);
     Curl_ssl_sessionid_unlock(data);
     Curl_ssl_sessionid_unlock(data);
-    if(retcode) {
+    if(!added) {
       mbedtls_ssl_session_free(our_ssl_sessionid);
       mbedtls_ssl_session_free(our_ssl_sessionid);
       free(our_ssl_sessionid);
       free(our_ssl_sessionid);
+    }
+    if(retcode) {
       failf(data, "failed to store ssl session");
       failf(data, "failed to store ssl session");
       return retcode;
       return retcode;
     }
     }
@@ -1151,6 +1182,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
   { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
   { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
 
 
   SSLSUPP_CA_PATH |
   SSLSUPP_CA_PATH |
+  SSLSUPP_CAINFO_BLOB |
   SSLSUPP_PINNEDPUBKEY |
   SSLSUPP_PINNEDPUBKEY |
   SSLSUPP_SSL_CTX,
   SSLSUPP_SSL_CTX,
 
 

+ 49 - 44
Utilities/cmcurl/lib/vtls/mesalink.c

@@ -68,8 +68,6 @@ struct ssl_backend_data
   SSL *handle;
   SSL *handle;
 };
 };
 
 
-#define BACKEND connssl->backend
-
 static Curl_recv mesalink_recv;
 static Curl_recv mesalink_recv;
 static Curl_send mesalink_send;
 static Curl_send mesalink_send;
 
 
@@ -100,9 +98,9 @@ mesalink_connect_step1(struct Curl_easy *data,
 #endif
 #endif
   const char * const hostname = SSL_HOST_NAME();
   const char * const hostname = SSL_HOST_NAME();
   size_t hostname_len = strlen(hostname);
   size_t hostname_len = strlen(hostname);
-
   SSL_METHOD *req_method = NULL;
   SSL_METHOD *req_method = NULL;
   curl_socket_t sockfd = conn->sock[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
+  struct ssl_backend_data *backend = connssl->backend;
 
 
   if(connssl->state == ssl_connection_complete)
   if(connssl->state == ssl_connection_complete)
     return CURLE_OK;
     return CURLE_OK;
@@ -139,22 +137,22 @@ mesalink_connect_step1(struct Curl_easy *data,
     return CURLE_OUT_OF_MEMORY;
     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!");
     failf(data, "SSL: couldn't create a context!");
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
   }
   }
 
 
   SSL_CTX_set_verify(
   SSL_CTX_set_verify(
-    BACKEND->ctx, SSL_CONN_CONFIG(verifypeer) ?
+    backend->ctx, SSL_CONN_CONFIG(verifypeer) ?
       SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
       SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
 
 
   if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath)) {
   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)) {
       if(SSL_CONN_CONFIG(verifypeer)) {
         failf(data,
         failf(data,
               "error setting certificate verify locations: "
               "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)) {
   if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
     int file_type = do_file_type(SSL_SET_OPTION(cert_type));
     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),
                                           SSL_SET_OPTION(primary.clientcert),
                                           file_type) != 1) {
                                           file_type) != 1) {
       failf(data, "unable to use client certificate (no key or wrong pass"
       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));
     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");
       failf(data, "unable to set private key");
       return CURLE_SSL_CONNECT_ERROR;
       return CURLE_SSL_CONNECT_ERROR;
     }
     }
@@ -204,7 +202,7 @@ mesalink_connect_step1(struct Curl_easy *data,
   ciphers = SSL_CONN_CONFIG(cipher_list);
   ciphers = SSL_CONN_CONFIG(cipher_list);
   if(ciphers) {
   if(ciphers) {
 #ifdef MESALINK_HAVE_CIPHER
 #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);
       failf(data, "failed setting cipher list: %s", ciphers);
       return CURLE_SSL_CIPHER;
       return CURLE_SSL_CIPHER;
     }
     }
@@ -212,10 +210,10 @@ mesalink_connect_step1(struct Curl_easy *data,
     infof(data, "Cipher selection: %s", ciphers);
     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)!");
     failf(data, "SSL: couldn't create a context (handle)!");
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
   }
   }
@@ -227,7 +225,7 @@ mesalink_connect_step1(struct Curl_easy *data,
 #endif
 #endif
   ) {
   ) {
     /* hostname is not a valid IP address */
     /* 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,
       failf(data,
             "WARNING: failed to configure server name indication (SNI) "
             "WARNING: failed to configure server name indication (SNI) "
             "TLS extension\n");
             "TLS extension\n");
@@ -244,7 +242,7 @@ mesalink_connect_step1(struct Curl_easy *data,
        || strncmp(hostname, "[::1]", 5) == 0
        || strncmp(hostname, "[::1]", 5) == 0
 #endif
 #endif
     ) {
     ) {
-      SSL_set_tlsext_host_name(BACKEND->handle, "localhost");
+      SSL_set_tlsext_host_name(backend->handle, "localhost");
     }
     }
     else
     else
 #endif
 #endif
@@ -264,12 +262,12 @@ mesalink_connect_step1(struct Curl_easy *data,
                               SSL_IS_PROXY() ? TRUE : FALSE,
                               SSL_IS_PROXY() ? TRUE : FALSE,
                               &ssl_sessionid, NULL, sockindex)) {
                               &ssl_sessionid, NULL, sockindex)) {
       /* we got a session id, use it! */
       /* 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);
         Curl_ssl_sessionid_unlock(data);
         failf(
         failf(
           data,
           data,
           "SSL: SSL_set_session failed: %s",
           "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;
         return CURLE_SSL_CONNECT_ERROR;
       }
       }
       /* Informational message */
       /* Informational message */
@@ -279,7 +277,7 @@ mesalink_connect_step1(struct Curl_easy *data,
   }
   }
 #endif /* MESALINK_HAVE_SESSION */
 #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");
     failf(data, "SSL: SSL_set_fd failed");
     return CURLE_SSL_CONNECT_ERROR;
     return CURLE_SSL_CONNECT_ERROR;
   }
   }
@@ -294,13 +292,14 @@ mesalink_connect_step2(struct Curl_easy *data,
 {
 {
   int ret = -1;
   int ret = -1;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  struct ssl_backend_data *backend = connssl->backend;
 
 
   conn->recv[sockindex] = mesalink_recv;
   conn->recv[sockindex] = mesalink_recv;
   conn->send[sockindex] = mesalink_send;
   conn->send[sockindex] = mesalink_send;
 
 
-  ret = SSL_connect(BACKEND->handle);
+  ret = SSL_connect(backend->handle);
   if(ret != SSL_SUCCESS) {
   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) {
     if(SSL_ERROR_WANT_CONNECT == detail || SSL_ERROR_WANT_READ == detail) {
       connssl->connecting_state = ssl_connect_2_reading;
       connssl->connecting_state = ssl_connect_2_reading;
@@ -327,8 +326,8 @@ mesalink_connect_step2(struct Curl_easy *data,
   connssl->connecting_state = ssl_connect_3;
   connssl->connecting_state = ssl_connect_3;
   infof(data,
   infof(data,
         "SSL connection using %s / %s",
         "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;
   return CURLE_OK;
 }
 }
@@ -347,8 +346,9 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
     SSL_SESSION *our_ssl_sessionid;
     SSL_SESSION *our_ssl_sessionid;
     void *old_ssl_sessionid = NULL;
     void *old_ssl_sessionid = NULL;
     bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
     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);
     Curl_ssl_sessionid_lock(data);
     incache =
     incache =
@@ -365,7 +365,7 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
     if(!incache) {
     if(!incache) {
       result =
       result =
         Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, 0,
         Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, 0,
-                              sockindex);
+                              sockindex, NULL);
       if(result) {
       if(result) {
         Curl_ssl_sessionid_unlock(data);
         Curl_ssl_sessionid_unlock(data);
         failf(data, "failed to store ssl session");
         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 connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  struct ssl_backend_data *backend = connssl->backend;
   char error_buffer[MESALINK_MAX_ERROR_SZ];
   char error_buffer[MESALINK_MAX_ERROR_SZ];
   int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
   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) {
   if(rc < 0) {
-    int err = SSL_get_error(BACKEND->handle, rc);
+    int err = SSL_get_error(backend->handle, rc);
     switch(err) {
     switch(err) {
     case SSL_ERROR_WANT_READ:
     case SSL_ERROR_WANT_READ:
     case SSL_ERROR_WANT_WRITE:
     case SSL_ERROR_WANT_WRITE:
@@ -415,17 +416,18 @@ static void
 mesalink_close(struct Curl_easy *data, struct connectdata *conn, int sockindex)
 mesalink_close(struct Curl_easy *data, struct connectdata *conn, int sockindex)
 {
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  struct ssl_backend_data *backend = connssl->backend;
 
 
   (void) data;
   (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 connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[num];
   struct ssl_connect_data *connssl = &conn->ssl[num];
+  struct ssl_backend_data *backend = connssl->backend;
   char error_buffer[MESALINK_MAX_ERROR_SZ];
   char error_buffer[MESALINK_MAX_ERROR_SZ];
   int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
   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) {
   if(nread <= 0) {
-    int err = SSL_get_error(BACKEND->handle, nread);
+    int err = SSL_get_error(backend->handle, nread);
 
 
     switch(err) {
     switch(err) {
     case SSL_ERROR_ZERO_RETURN: /* no more data */
     case SSL_ERROR_ZERO_RETURN: /* no more data */
@@ -485,12 +488,13 @@ mesalink_shutdown(struct Curl_easy *data,
 {
 {
   int retval = 0;
   int retval = 0;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  struct ssl_backend_data *backend = connssl->backend;
 
 
   (void) data;
   (void) data;
 
 
-  if(BACKEND->handle) {
-    SSL_free(BACKEND->handle);
-    BACKEND->handle = NULL;
+  if(backend->handle) {
+    SSL_free(backend->handle);
+    backend->handle = NULL;
   }
   }
   return retval;
   return retval;
 }
 }
@@ -636,8 +640,9 @@ static void *
 mesalink_get_internals(struct ssl_connect_data *connssl,
 mesalink_get_internals(struct ssl_connect_data *connssl,
                        CURLINFO info UNUSED_PARAM)
                        CURLINFO info UNUSED_PARAM)
 {
 {
+  struct ssl_backend_data *backend = connssl->backend;
   (void)info;
   (void)info;
-  return BACKEND->handle;
+  return backend->handle;
 }
 }
 
 
 const struct Curl_ssl Curl_ssl_mesalink = {
 const struct Curl_ssl Curl_ssl_mesalink = {

+ 55 - 52
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;
   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 */
   /* use accessors to avoid dynamic linking issues after an update of NSS */
   const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
   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);
     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;
   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)))
     while((*cipher) && (ISSPACE(*cipher)))
       ++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;
       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;
       return SECFailure;
     }
     }
+    if(end)
+      cipher = ++end;
+    else
+      break;
   }
   }
 
 
   return SECSuccess;
   return SECSuccess;
@@ -782,7 +784,7 @@ static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
 {
 {
   (void)slot; /* unused */
   (void)slot; /* unused */
 
 
-  if(retry || NULL == arg)
+  if(retry || !arg)
     return NULL;
     return NULL;
   else
   else
     return (char *)PORT_Strdup((char *)arg);
     return (char *)PORT_Strdup((char *)arg);
@@ -955,7 +957,7 @@ static void display_cert_info(struct Curl_easy *data,
   subject = CERT_NameToAscii(&cert->subject);
   subject = CERT_NameToAscii(&cert->subject);
   issuer = CERT_NameToAscii(&cert->issuer);
   issuer = CERT_NameToAscii(&cert->issuer);
   common_name = CERT_GetCommonName(&cert->subject);
   common_name = CERT_GetCommonName(&cert->subject);
-  infof(data, "subject: %s\n", subject);
+  infof(data, "subject: %s", subject);
 
 
   CERT_GetCertTimes(cert, &notBefore, &notAfter);
   CERT_GetCertTimes(cert, &notBefore, &notAfter);
   PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
   PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
@@ -1168,7 +1170,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
     struct SECKEYPrivateKeyStr *key;
     struct SECKEYPrivateKeyStr *key;
 
 
     PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
     PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
-    if(NULL == slot) {
+    if(!slot) {
       failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
       failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
       return SECFailure;
       return SECFailure;
     }
     }
@@ -1182,7 +1184,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
 
 
     cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
     cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
     SECITEM_FreeItem(&cert_der, PR_FALSE);
     SECITEM_FreeItem(&cert_der, PR_FALSE);
-    if(NULL == cert) {
+    if(!cert) {
       failf(data, "NSS: client certificate from file not found");
       failf(data, "NSS: client certificate from file not found");
       PK11_FreeSlot(slot);
       PK11_FreeSlot(slot);
       return SECFailure;
       return SECFailure;
@@ -1190,7 +1192,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
 
 
     key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
     key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
     PK11_FreeSlot(slot);
     PK11_FreeSlot(slot);
-    if(NULL == key) {
+    if(!key) {
       failf(data, "NSS: private key from file not found");
       failf(data, "NSS: private key from file not found");
       CERT_DestroyCertificate(cert);
       CERT_DestroyCertificate(cert);
       return SECFailure;
       return SECFailure;
@@ -1207,9 +1209,9 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
   /* use the default NSS hook */
   /* use the default NSS hook */
   if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
   if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
                                           pRetCert, pRetKey)
                                           pRetCert, pRetKey)
-      || NULL == *pRetCert) {
+     || !*pRetCert) {
 
 
-    if(NULL == nickname)
+    if(!nickname)
       failf(data, "NSS: client certificate not found (nickname not "
       failf(data, "NSS: client certificate not found (nickname not "
             "specified)");
             "specified)");
     else
     else
@@ -1220,7 +1222,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
 
 
   /* get certificate nickname if any */
   /* get certificate nickname if any */
   nickname = (*pRetCert)->nickname;
   nickname = (*pRetCert)->nickname;
-  if(NULL == nickname)
+  if(!nickname)
     nickname = "[unknown]";
     nickname = "[unknown]";
 
 
   if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
   if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
@@ -1229,7 +1231,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
     return SECFailure;
     return SECFailure;
   }
   }
 
 
-  if(NULL == *pRetKey) {
+  if(!*pRetKey) {
     failf(data, "NSS: private key not found for certificate: %s", nickname);
     failf(data, "NSS: private key not found for certificate: %s", nickname);
     return SECFailure;
     return SECFailure;
   }
   }
@@ -1344,7 +1346,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
   PRErrorCode err;
   PRErrorCode err;
   const char *err_name;
   const char *err_name;
 
 
-  if(nss_context != NULL)
+  if(nss_context)
     return CURLE_OK;
     return CURLE_OK;
 
 
   memset((void *) &initparams, '\0', sizeof(initparams));
   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);
                                   NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
     free(certpath);
     free(certpath);
 
 
-    if(nss_context != NULL)
+    if(nss_context)
       return CURLE_OK;
       return CURLE_OK;
 
 
     err = PR_GetError();
     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_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
          | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
          | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
          | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
          | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
-  if(nss_context != NULL)
+  if(nss_context)
     return CURLE_OK;
     return CURLE_OK;
 
 
   err = PR_GetError();
   err = PR_GetError();
@@ -2250,10 +2252,11 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
   case CURLE_OK:
   case CURLE_OK:
     break;
     break;
   case CURLE_AGAIN:
   case CURLE_AGAIN:
+    /* CURLE_AGAIN in non-blocking mode is not an error */
     if(!blocking)
     if(!blocking)
-      /* CURLE_AGAIN in non-blocking mode is not an error */
       return CURLE_OK;
       return CURLE_OK;
-    /* FALLTHROUGH */
+    else
+      return result;
   default:
   default:
     return result;
     return result;
   }
   }

+ 168 - 122
Utilities/cmcurl/lib/vtls/openssl.c

@@ -171,6 +171,21 @@
 #define OPENSSL_load_builtin_modules(x)
 #define OPENSSL_load_builtin_modules(x)
 #endif
 #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.
  * Whether SSL_CTX_set_keylog_callback is available.
  * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
  * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
@@ -227,6 +242,17 @@
 #endif
 #endif
 #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 ssl_backend_data {
   struct Curl_easy *logger; /* transfer handle to pass trace logs to, only
   struct Curl_easy *logger; /* transfer handle to pass trace logs to, only
                                using sockindex 0 */
                                using sockindex 0 */
@@ -435,18 +461,21 @@ static bool rand_enough(void)
 
 
 static CURLcode ossl_seed(struct Curl_easy *data)
 static CURLcode ossl_seed(struct Curl_easy *data)
 {
 {
-  char fname[256];
-
   /* This might get called before it has been added to a multi handle */
   /* This might get called before it has been added to a multi handle */
   if(data->multi && data->multi->ssl_seeded)
   if(data->multi && data->multi->ssl_seeded)
     return CURLE_OK;
     return CURLE_OK;
 
 
   if(rand_enough()) {
   if(rand_enough()) {
-    /* OpenSSL 1.1.0+ will return here */
+    /* OpenSSL 1.1.0+ should return here */
     if(data->multi)
     if(data->multi)
       data->multi->ssl_seeded = TRUE;
       data->multi->ssl_seeded = TRUE;
     return CURLE_OK;
     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
 #ifndef RANDOM_FILE
   /* if RANDOM_FILE isn't defined, we only perform this if an option tells
   /* 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);
     RAND_add(randb, (int)len, (double)len/2);
   } while(!rand_enough());
   } 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!");
   infof(data, "libcurl is now using a weak random seed!");
   return (rand_enough() ? CURLE_OK :
   return (rand_enough() ? CURLE_OK :
-    CURLE_SSL_CONNECT_ERROR /* confusing error code */);
+          CURLE_SSL_CONNECT_ERROR /* confusing error code */);
+#endif
 }
 }
 
 
 #ifndef SSL_FILETYPE_ENGINE
 #ifndef SSL_FILETYPE_ENGINE
@@ -1088,7 +1121,8 @@ int cert_stuff(struct Curl_easy *data,
       EVP_PKEY_free(pktmp);
       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
       /* If RSA is used, don't check the private key if its flags indicate
        * it doesn't support it. */
        * it doesn't support it. */
@@ -1401,6 +1435,12 @@ static void ossl_closeone(struct Curl_easy *data,
   if(backend->handle) {
   if(backend->handle) {
     char buf[32];
     char buf[32];
     set_logger(conn, data);
     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.
     /* Maybe the server has already sent a close notify alert.
        Read it to avoid an RST on the TCP connection. */
        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
    hostname. In this case, the iPAddress subjectAltName must be present
    in the certificate and must exactly match the IP in the URI.
    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;
   bool matched = FALSE;
   int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
   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 */
   /* Compute the certificate's ID */
-  cert = SSL_get_peer_certificate(backend->handle);
+  cert = SSL_get1_peer_certificate(backend->handle);
   if(!cert) {
   if(!cert) {
     failf(data, "Error getting peer certificate");
     failf(data, "Error getting peer certificate");
     result = CURLE_SSL_INVALIDCERTSTATUS;
     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)) {
   if(SSL_SET_OPTION(primary.sessionid)) {
     bool incache;
     bool incache;
+    bool added = FALSE;
     void *old_ssl_sessionid = NULL;
     void *old_ssl_sessionid = NULL;
 
 
     Curl_ssl_sessionid_lock(data);
     Curl_ssl_sessionid_lock(data);
@@ -2511,9 +2553,11 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
 
 
     if(!incache) {
     if(!incache) {
       if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
       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
       else
         failf(data, "failed to store ssl session");
         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))) {
                                NULL, cert_name, sizeof(cert_name))) {
           strcpy(cert_name, "Unknown");
           strcpy(cert_name, "Unknown");
         }
         }
-        infof(data, "SSL: Checking cert %s\"\n", cert_name);
+        infof(data, "SSL: Checking cert \"%s\"", cert_name);
 #endif
 #endif
 
 
         encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
         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)
 #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
   /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
   /* 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
 #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(!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, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
     infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
     infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
   }
   }
-#endif
 
 
 #ifdef CURL_CA_FALLBACK
 #ifdef CURL_CA_FALLBACK
   if(verifypeer &&
   if(verifypeer &&
@@ -3476,10 +3496,7 @@ static void pubkey_show(struct Curl_easy *data,
                         int num,
                         int num,
                         const char *type,
                         const char *type,
                         const char *name,
                         const char *name,
-#ifdef HAVE_OPAQUE_RSA_DSA_DH
-                        const
-#endif
-                        BIGNUM *bn)
+                        const BIGNUM *bn)
 {
 {
   char *ptr;
   char *ptr;
   char namebuf[32];
   char namebuf[32];
@@ -3544,12 +3561,6 @@ typedef size_t numcert_t;
 typedef int numcert_t;
 typedef int numcert_t;
 #endif
 #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,
 static CURLcode get_cert_chain(struct Curl_easy *data,
                                struct ssl_connect_data *connssl)
                                struct ssl_connect_data *connssl)
 {
 {
@@ -3573,6 +3584,9 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
   }
   }
 
 
   mem = BIO_new(BIO_s_mem());
   mem = BIO_new(BIO_s_mem());
+  if(!mem) {
+    return CURLE_OUT_OF_MEMORY;
+  }
 
 
   for(i = 0; i < (int)numcerts; i++) {
   for(i = 0; i < (int)numcerts; i++) {
     ASN1_INTEGER *num;
     ASN1_INTEGER *num;
@@ -3657,92 +3671,115 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
       switch(pktype) {
       switch(pktype) {
       case EVP_PKEY_RSA:
       case EVP_PKEY_RSA:
       {
       {
-        OSSL3_CONST RSA *rsa;
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+        RSA *rsa;
 #ifdef HAVE_OPAQUE_EVP_PKEY
 #ifdef HAVE_OPAQUE_EVP_PKEY
         rsa = EVP_PKEY_get0_RSA(pubkey);
         rsa = EVP_PKEY_get0_RSA(pubkey);
 #else
 #else
         rsa = pubkey->pkey.rsa;
         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);
           RSA_get0_key(rsa, &n, &e, NULL);
+#endif /* HAVE_EVP_PKEY_GET_PARAMS */
           BIO_printf(mem, "%d", BN_num_bits(n));
           BIO_printf(mem, "%d", 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);
           push_certinfo("RSA Public Key", i);
           print_pubkey_BN(rsa, n, i);
           print_pubkey_BN(rsa, n, i);
           print_pubkey_BN(rsa, e, 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;
         break;
       }
       }
       case EVP_PKEY_DSA:
       case EVP_PKEY_DSA:
       {
       {
 #ifndef OPENSSL_NO_DSA
 #ifndef OPENSSL_NO_DSA
-        OSSL3_CONST DSA *dsa;
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+        DSA *dsa;
 #ifdef HAVE_OPAQUE_EVP_PKEY
 #ifdef HAVE_OPAQUE_EVP_PKEY
         dsa = EVP_PKEY_get0_DSA(pubkey);
         dsa = EVP_PKEY_get0_DSA(pubkey);
 #else
 #else
         dsa = pubkey->pkey.dsa;
         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_pqg(dsa, &p, &q, &g);
           DSA_get0_key(dsa, &pub_key, NULL);
           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, p, i);
           print_pubkey_BN(dsa, q, i);
           print_pubkey_BN(dsa, q, i);
           print_pubkey_BN(dsa, g, i);
           print_pubkey_BN(dsa, g, i);
           print_pubkey_BN(dsa, pub_key, 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 */
 #endif /* !OPENSSL_NO_DSA */
         break;
         break;
       }
       }
       case EVP_PKEY_DH:
       case EVP_PKEY_DH:
       {
       {
-        OSSL3_CONST DH *dh;
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+        DH *dh;
 #ifdef HAVE_OPAQUE_EVP_PKEY
 #ifdef HAVE_OPAQUE_EVP_PKEY
         dh = EVP_PKEY_get0_DH(pubkey);
         dh = EVP_PKEY_get0_DH(pubkey);
 #else
 #else
         dh = pubkey->pkey.dh;
         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_pqg(dh, &p, &q, &g);
           DH_get0_key(dh, &pub_key, NULL);
           DH_get0_key(dh, &pub_key, NULL);
+#endif /* HAVE_EVP_PKEY_GET_PARAMS */
           print_pubkey_BN(dh, p, i);
           print_pubkey_BN(dh, p, i);
           print_pubkey_BN(dh, q, i);
           print_pubkey_BN(dh, q, i);
           print_pubkey_BN(dh, g, 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);
           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;
         break;
       }
       }
       }
       }
@@ -3846,11 +3883,20 @@ static CURLcode servercert(struct Curl_easy *data,
   BIO *mem = BIO_new(BIO_s_mem());
   BIO *mem = BIO_new(BIO_s_mem());
   struct ssl_backend_data *backend = connssl->backend;
   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)
   if(data->set.ssl.certinfo)
     /* we've been asked to gather certificate info! */
     /* we've been asked to gather certificate info! */
     (void)get_cert_chain(data, connssl);
     (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) {
   if(!backend->server_cert) {
     BIO_free(mem);
     BIO_free(mem);
     if(!strict)
     if(!strict)
@@ -3884,7 +3930,7 @@ static CURLcode servercert(struct Curl_easy *data,
   BIO_free(mem);
   BIO_free(mem);
 
 
   if(SSL_CONN_CONFIG(verifyhost)) {
   if(SSL_CONN_CONFIG(verifyhost)) {
-    result = verifyhost(data, conn, backend->server_cert);
+    result = Curl_ossl_verifyhost(data, conn, backend->server_cert);
     if(result) {
     if(result) {
       X509_free(backend->server_cert);
       X509_free(backend->server_cert);
       backend->server_cert = NULL;
       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)
 static size_t ossl_version(char *buffer, size_t size)
 {
 {
 #ifdef LIBRESSL_VERSION_NUMBER
 #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;
   char *p;
   int count;
   int count;
   const char *ver = OpenSSL_version(OPENSSL_VERSION);
   const char *ver = OpenSSL_version(OPENSSL_VERSION);
@@ -4384,6 +4424,12 @@ static size_t ossl_version(char *buffer, size_t size)
       *p = '_';
       *p = '_';
   }
   }
   return count;
   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
 #endif
 #elif defined(OPENSSL_IS_BORINGSSL)
 #elif defined(OPENSSL_IS_BORINGSSL)
   return msnprintf(buffer, size, OSSL_PACKAGE);
   return msnprintf(buffer, size, OSSL_PACKAGE);

+ 6 - 2
Utilities/cmcurl/lib/vtls/openssl.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -26,11 +26,15 @@
 
 
 #ifdef USE_OPENSSL
 #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"
 #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;
 extern const struct Curl_ssl Curl_ssl_openssl;
 
 
 #endif /* USE_OPENSSL */
 #endif /* USE_OPENSSL */

+ 33 - 28
Utilities/cmcurl/lib/vtls/rustls.c

@@ -27,7 +27,7 @@
 #include "curl_printf.h"
 #include "curl_printf.h"
 
 
 #include <errno.h>
 #include <errno.h>
-#include <crustls.h>
+#include <rustls.h>
 
 
 #include "inet_pton.h"
 #include "inet_pton.h"
 #include "urldata.h"
 #include "urldata.h"
@@ -138,11 +138,6 @@ cr_recv(struct Curl_easy *data, int sockindex,
     *err = CURLE_READ_ERROR;
     *err = CURLE_READ_ERROR;
     return -1;
     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);
   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,
       (uint8_t *)plainbuf + plain_bytes_copied,
       plainlen - plain_bytes_copied,
       plainlen - plain_bytes_copied,
       &n);
       &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) {
     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;
       *err = CURLE_READ_ERROR;
       return -1;
       return -1;
     }
     }
     else if(n == 0) {
     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;
       break;
     }
     }
     else {
     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;
     *err = CURLE_AGAIN;
     return -1;
     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();
   config_builder = rustls_client_config_builder_new();
 #ifdef USE_HTTP2
 #ifdef USE_HTTP2
   infof(data, "offering ALPN for HTTP/1.1 and HTTP/2");
   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
 #else
   infof(data, "offering ALPN for HTTP/1.1 only");
   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
 #endif
   if(!verifypeer) {
   if(!verifypeer) {
     rustls_client_config_builder_dangerous_set_certificate_verifier(
     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;
   size_t len = 0;
 
 
   rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
   rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
-  if(NULL == protocol) {
+  if(!protocol) {
     infof(data, "ALPN, server did not agree to a protocol");
     infof(data, "ALPN, server did not agree to a protocol");
     return;
     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
     * Connection has been established according to rustls. Set send/recv
     * handlers, and update the state machine.
     * 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)) {
     if(!rustls_connection_is_handshaking(rconn)) {
       infof(data, "Done handshaking");
       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 = {
 const struct Curl_ssl Curl_ssl_rustls = {
   { CURLSSLBACKEND_RUSTLS, "rustls" },
   { CURLSSLBACKEND_RUSTLS, "rustls" },
   SSLSUPP_TLS13_CIPHERSUITES,      /* supports */
   SSLSUPP_TLS13_CIPHERSUITES,      /* supports */
@@ -550,7 +555,7 @@ const struct Curl_ssl Curl_ssl_rustls = {
 
 
   Curl_none_init,                  /* init */
   Curl_none_init,                  /* init */
   Curl_none_cleanup,               /* cleanup */
   Curl_none_cleanup,               /* cleanup */
-  rustls_version,                  /* version */
+  cr_version,                      /* version */
   Curl_none_check_cxn,             /* check_cxn */
   Curl_none_check_cxn,             /* check_cxn */
   Curl_none_shutdown,              /* shutdown */
   Curl_none_shutdown,              /* shutdown */
   cr_data_pending,                 /* data_pending */
   cr_data_pending,                 /* data_pending */

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 203 - 198
Utilities/cmcurl/lib/vtls/schannel.c


+ 3 - 2
Utilities/cmcurl/lib/vtls/schannel_verify.c

@@ -355,7 +355,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
   DWORD i;
   DWORD i;
 
 
   /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
   /* 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)) {
                                   VERSION_GREATER_THAN_EQUAL)) {
 #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
 #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
     /* CertGetNameString will provide the 8-bit character string without
     /* 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+.
      * 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 "
       failf(data, "schannel: this version of Windows is too old to support "
             "certificate verification via CA bundle file.");
             "certificate verification via CA bundle file.");
       result = CURLE_SSL_CACERT_BADFILE;
       result = CURLE_SSL_CACERT_BADFILE;

+ 16 - 16
Utilities/cmcurl/lib/vtls/sectransp.c

@@ -997,14 +997,14 @@ CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
 #else
 #else
 #if CURL_BUILD_MAC_10_7
 #if CURL_BUILD_MAC_10_7
   /* Lion & later: Get the long description if we can. */
   /* Lion & later: Get the long description if we can. */
-  if(SecCertificateCopyLongDescription != NULL)
+  if(SecCertificateCopyLongDescription)
     server_cert_summary =
     server_cert_summary =
       SecCertificateCopyLongDescription(NULL, cert, NULL);
       SecCertificateCopyLongDescription(NULL, cert, NULL);
   else
   else
 #endif /* CURL_BUILD_MAC_10_7 */
 #endif /* CURL_BUILD_MAC_10_7 */
 #if CURL_BUILD_MAC_10_6
 #if CURL_BUILD_MAC_10_6
   /* Snow Leopard: Get the certificate summary. */
   /* Snow Leopard: Get the certificate summary. */
-  if(SecCertificateCopySubjectSummary != NULL)
+  if(SecCertificateCopySubjectSummary)
     server_cert_summary = SecCertificateCopySubjectSummary(cert);
     server_cert_summary = SecCertificateCopySubjectSummary(cert);
   else
   else
 #endif /* CURL_BUILD_MAC_10_6 */
 #endif /* CURL_BUILD_MAC_10_6 */
@@ -1118,7 +1118,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
   /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
   /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
      kSecClassIdentity was introduced in Lion. If both exist, let's use them
      kSecClassIdentity was introduced in Lion. If both exist, let's use them
      to find the certificate. */
      to find the certificate. */
-  if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
+  if(SecItemCopyMatching && kSecClassIdentity) {
     CFTypeRef keys[5];
     CFTypeRef keys[5];
     CFTypeRef values[5];
     CFTypeRef values[5];
     CFDictionaryRef query_dict;
     CFDictionaryRef query_dict;
@@ -1248,7 +1248,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
     CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
     CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
       password ? 1L : 0L, NULL, NULL);
       password ? 1L : 0L, NULL, NULL);
 
 
-    if(options != NULL) {
+    if(options) {
       status = SecPKCS12Import(pkcs_data, options, &items);
       status = SecPKCS12Import(pkcs_data, options, &items);
       CFRelease(options);
       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 CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-  if(SSLSetProtocolVersionMax != NULL) {
+  if(SSLSetProtocolVersionMax) {
     SSLProtocol darwin_ver_min = kTLSProtocol1;
     SSLProtocol darwin_ver_min = kTLSProtocol1;
     SSLProtocol darwin_ver_max = kTLSProtocol1;
     SSLProtocol darwin_ver_max = kTLSProtocol1;
     CURLcode result = sectransp_version_from_curl(&darwin_ver_min,
     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) {
       if(tls_name) {
         table_cipher_name = ciphertable[i].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;
         table_cipher_name = ciphertable[i].alias_name;
       }
       }
       else {
       else {
@@ -1688,7 +1688,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
 #endif /* CURL_BUILD_MAC */
 #endif /* CURL_BUILD_MAC */
 
 
 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
 #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)
     if(backend->ssl_ctx)
       CFRelease(backend->ssl_ctx);
       CFRelease(backend->ssl_ctx);
     backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
     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 */
   /* 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 CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-  if(SSLSetProtocolVersionMax != NULL) {
+  if(SSLSetProtocolVersionMax) {
     switch(conn->ssl_config.version) {
     switch(conn->ssl_config.version) {
     case CURL_SSLVERSION_TLSv1:
     case CURL_SSLVERSION_TLSv1:
       (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
       (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)
   Darwin 15.x.x is El Capitan (10.11)
   */
   */
 #if CURL_BUILD_MAC
 #if CURL_BUILD_MAC
-  if(SSLSetSessionOption != NULL && darwinver_maj >= 13) {
+  if(SSLSetSessionOption && darwinver_maj >= 13) {
 #else
 #else
-  if(SSLSetSessionOption != NULL) {
+  if(SSLSetSessionOption) {
 #endif /* CURL_BUILD_MAC */
 #endif /* CURL_BUILD_MAC */
     bool break_on_auth = !conn->ssl_config.verifypeer ||
     bool break_on_auth = !conn->ssl_config.verifypeer ||
       ssl_cafile || ssl_cablob;
       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
 #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
   /* We want to enable 1/n-1 when using a CBC cipher unless the user
      specifically doesn't want us doing that: */
      specifically doesn't want us doing that: */
-  if(SSLSetSessionOption != NULL) {
+  if(SSLSetSessionOption) {
     SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
     SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
                         !SSL_SET_OPTION(enable_beast));
                         !SSL_SET_OPTION(enable_beast));
     SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
     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,
       result = Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
-                                     ssl_sessionid_len, sockindex);
+                                     ssl_sessionid_len, sockindex, NULL);
       Curl_ssl_sessionid_unlock(data);
       Curl_ssl_sessionid_unlock(data);
       if(result) {
       if(result) {
         failf(data, "failed to store ssl session");
         failf(data, "failed to store ssl session");
@@ -2521,7 +2521,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
   } while(0);
   } while(0);
 
 
   Curl_safefree(realpubkey);
   Curl_safefree(realpubkey);
-  if(publicKeyBits != NULL)
+  if(publicKeyBits)
     CFRelease(publicKeyBits);
     CFRelease(publicKeyBits);
 
 
   return result;
   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
      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
      a different symbol to make sure this code is only executed under
      Lion or later. */
      Lion or later. */
-  if(SecTrustEvaluateAsync != NULL) {
+  if(SecTrustEvaluateAsync) {
 #pragma unused(server_certs)
 #pragma unused(server_certs)
     err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
     err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
     /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
     /* 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) {
   if(backend->ssl_ctx) {
     (void)SSLClose(backend->ssl_ctx);
     (void)SSLClose(backend->ssl_ctx);
 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-    if(SSLCreateContext != NULL)
+    if(SSLCreateContext)
       CFRelease(backend->ssl_ctx);
       CFRelease(backend->ssl_ctx);
 #if CURL_SUPPORT_MAC_10_8
 #if CURL_SUPPORT_MAC_10_8
     else
     else
@@ -3329,7 +3329,7 @@ static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
 static bool sectransp_false_start(void)
 static bool sectransp_false_start(void)
 {
 {
 #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
 #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
-  if(SSLSetSessionOption != NULL)
+  if(SSLSetSessionOption)
     return TRUE;
     return TRUE;
 #endif
 #endif
   return FALSE;
   return FALSE;

+ 9 - 1
Utilities/cmcurl/lib/vtls/vtls.c

@@ -516,7 +516,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
                                const bool isProxy,
                                const bool isProxy,
                                void *ssl_sessionid,
                                void *ssl_sessionid,
                                size_t idsize,
                                size_t idsize,
-                               int sockindex)
+                               int sockindex,
+                               bool *added)
 {
 {
   size_t i;
   size_t i;
   struct Curl_ssl_session *store;
   struct Curl_ssl_session *store;
@@ -536,6 +537,10 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
   const char *hostname = conn->host.name;
   const char *hostname = conn->host.name;
 #endif
 #endif
   (void)sockindex;
   (void)sockindex;
+
+  if(added)
+    *added = FALSE;
+
   if(!data->state.session)
   if(!data->state.session)
     return CURLE_OK;
     return CURLE_OK;
 
 
@@ -609,6 +614,9 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
   }
   }
 
 
+  if(added)
+    *added = TRUE;
+
   DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
   DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
                store->scheme, store->name, store->remote_port,
                store->scheme, store->name, store->remote_port,
                isProxy ? "PROXY" : "server"));
                isProxy ? "PROXY" : "server"));

+ 2 - 1
Utilities/cmcurl/lib/vtls/vtls.h

@@ -261,7 +261,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
                                const bool isProxy,
                                const bool isProxy,
                                void *ssl_sessionid,
                                void *ssl_sessionid,
                                size_t idsize,
                                size_t idsize,
-                               int sockindex);
+                               int sockindex,
+                               bool *added);
 /* Kill a single session ID entry in the cache
 /* Kill a single session ID entry in the cache
  * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
  * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
  * This will call engine-specific curlssl_session_free function, which must
  * This will call engine-specific curlssl_session_free function, which must

+ 72 - 3
Utilities/cmcurl/lib/vtls/wolfssl.c

@@ -202,6 +202,43 @@ static int do_file_type(const char *type)
   return -1;
   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
  * This function loads all the client/CA certificates and CRLs. Setup the TLS
  * layer and do all necessary magic.
  * layer and do all necessary magic.
@@ -210,11 +247,15 @@ static CURLcode
 wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
 wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
                      int sockindex)
                      int sockindex)
 {
 {
-  char *ciphers;
+  char *ciphers, *curves;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   struct ssl_backend_data *backend = connssl->backend;
   SSL_METHOD* req_method = NULL;
   SSL_METHOD* req_method = NULL;
   curl_socket_t sockfd = conn->sock[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
+#ifdef HAVE_LIBOQS
+  word16 oqsAlg = 0;
+  size_t idx = 0;
+#endif
 #ifdef HAVE_SNI
 #ifdef HAVE_SNI
   bool sni = FALSE;
   bool sni = FALSE;
 #define use_sni(x)  sni = (x)
 #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);
     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
 #ifndef NO_FILESYSTEM
   /* load trusted cacert */
   /* load trusted cacert */
   if(SSL_CONN_CONFIG(CAfile)) {
   if(SSL_CONN_CONFIG(CAfile)) {
@@ -439,6 +500,14 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     return CURLE_OUT_OF_MEMORY;
     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
 #ifdef HAVE_ALPN
   if(conn->bits.tls_enable_alpn) {
   if(conn->bits.tls_enable_alpn) {
     char protocols[128];
     char protocols[128];
@@ -495,7 +564,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
       /* we got a session id, use it! */
       /* 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_delsessionid(data, 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
       else
         infof(data, "SSL re-using session ID");
         infof(data, "SSL re-using session ID");
@@ -749,7 +818,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
 
 
       if(!incache) {
       if(!incache) {
         result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
         result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
-                                       0, sockindex);
+                                       0, sockindex, NULL);
         if(result) {
         if(result) {
           Curl_ssl_sessionid_unlock(data);
           Curl_ssl_sessionid_unlock(data);
           failf(data, "failed to store ssl session");
           failf(data, "failed to store ssl session");

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů