diff options
author | Brad King <brad.king@kitware.com> | 2020-06-24 12:13:02 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2020-06-24 12:13:02 (GMT) |
commit | 0ef8fa5000cddd5b0c3908a765a2c2d482bc2fdf (patch) | |
tree | 7f02ed6d5e482522263c1ad8e027132363055678 /Utilities | |
parent | 39f7cfad31aed063a1199a5d67c99c53a182b746 (diff) | |
parent | 5717fdc114a704cddae629e20e6588191360e98a (diff) | |
download | CMake-0ef8fa5000cddd5b0c3908a765a2c2d482bc2fdf.zip CMake-0ef8fa5000cddd5b0c3908a765a2c2d482bc2fdf.tar.gz CMake-0ef8fa5000cddd5b0c3908a765a2c2d482bc2fdf.tar.bz2 |
Merge branch 'upstream-curl' into update-curl
* upstream-curl:
curl 2020-06-23 (e9db32a0)
Diffstat (limited to 'Utilities')
172 files changed, 8362 insertions, 4702 deletions
diff --git a/Utilities/cmcurl/CMake/CMakeConfigurableFile.in b/Utilities/cmcurl/CMake/CMakeConfigurableFile.in index df2c382..2bafe2c 100644 --- a/Utilities/cmcurl/CMake/CMakeConfigurableFile.in +++ b/Utilities/cmcurl/CMake/CMakeConfigurableFile.in @@ -1 +1,22 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### @CMAKE_CONFIGURABLE_FILE_CONTENT@ diff --git a/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake b/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake index 8e5fd67..aaac9fe 100644 --- a/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake +++ b/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### include(CheckCSourceCompiles) option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) diff --git a/Utilities/cmcurl/CMake/FindBearSSL.cmake b/Utilities/cmcurl/CMake/FindBearSSL.cmake index 20d239a..a8f72c9 100644 --- a/Utilities/cmcurl/CMake/FindBearSSL.cmake +++ b/Utilities/cmcurl/CMake/FindBearSSL.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### find_path(BEARSSL_INCLUDE_DIRS bearssl.h) find_library(BEARSSL_LIBRARY bearssl) diff --git a/Utilities/cmcurl/CMake/FindBrotli.cmake b/Utilities/cmcurl/CMake/FindBrotli.cmake index 351b8f7..c43172b 100644 --- a/Utilities/cmcurl/CMake/FindBrotli.cmake +++ b/Utilities/cmcurl/CMake/FindBrotli.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### include(FindPackageHandleStandardArgs) find_path(BROTLI_INCLUDE_DIR "brotli/decode.h") diff --git a/Utilities/cmcurl/CMake/FindCARES.cmake b/Utilities/cmcurl/CMake/FindCARES.cmake index 3d1bae6..9160ae5 100644 --- a/Utilities/cmcurl/CMake/FindCARES.cmake +++ b/Utilities/cmcurl/CMake/FindCARES.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### # - Find c-ares # Find the c-ares includes and library # This module defines diff --git a/Utilities/cmcurl/CMake/FindGSS.cmake b/Utilities/cmcurl/CMake/FindGSS.cmake index a2f150c..02111a2 100644 --- a/Utilities/cmcurl/CMake/FindGSS.cmake +++ b/Utilities/cmcurl/CMake/FindGSS.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### # - Try to find the GSS Kerberos library # Once done this will define # diff --git a/Utilities/cmcurl/CMake/FindLibSSH2.cmake b/Utilities/cmcurl/CMake/FindLibSSH2.cmake index 91e17c1..4cdf3e3 100644 --- a/Utilities/cmcurl/CMake/FindLibSSH2.cmake +++ b/Utilities/cmcurl/CMake/FindLibSSH2.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### # - Try to find the libssh2 library # Once done this will define # diff --git a/Utilities/cmcurl/CMake/FindMbedTLS.cmake b/Utilities/cmcurl/CMake/FindMbedTLS.cmake index a916395..2ebe721 100644 --- a/Utilities/cmcurl/CMake/FindMbedTLS.cmake +++ b/Utilities/cmcurl/CMake/FindMbedTLS.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### find_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h) find_library(MBEDTLS_LIBRARY mbedtls) diff --git a/Utilities/cmcurl/CMake/FindNGHTTP2.cmake b/Utilities/cmcurl/CMake/FindNGHTTP2.cmake index 5138e99..e1eba05 100644 --- a/Utilities/cmcurl/CMake/FindNGHTTP2.cmake +++ b/Utilities/cmcurl/CMake/FindNGHTTP2.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### include(FindPackageHandleStandardArgs) find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h") diff --git a/Utilities/cmcurl/CMake/FindNGHTTP3.cmake b/Utilities/cmcurl/CMake/FindNGHTTP3.cmake new file mode 100644 index 0000000..73ce9e1 --- /dev/null +++ b/Utilities/cmcurl/CMake/FindNGHTTP3.cmake @@ -0,0 +1,76 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + +#[=======================================================================[.rst: +FindNGHTTP3 +---------- + +Find the nghttp3 library + +Result Variables +^^^^^^^^^^^^^^^^ + +``NGHTTP3_FOUND`` + System has nghttp3 +``NGHTTP3_INCLUDE_DIRS`` + The nghttp3 include directories. +``NGHTTP3_LIBRARIES`` + The libraries needed to use nghttp3 +``NGHTTP3_VERSION`` + version of nghttp3. +#]=======================================================================] + +if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(PC_NGHTTP3 libnghttp3) +endif() + +find_path(NGHTTP3_INCLUDE_DIR nghttp3/nghttp3.h + HINTS + ${PC_NGHTTP3_INCLUDEDIR} + ${PC_NGHTTP3_INCLUDE_DIRS} +) + +find_library(NGHTTP3_LIBRARY NAMES nghttp3 + HINTS + ${PC_NGHTTP3_LIBDIR} + ${PC_NGHTTP3_LIBRARY_DIRS} +) + +if(PC_NGHTTP3_VERSION) + set(NGHTTP3_VERSION ${PC_NGHTTP3_VERSION}) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NGHTTP3 + REQUIRED_VARS + NGHTTP3_LIBRARY + NGHTTP3_INCLUDE_DIR + VERSION_VAR NGHTTP3_VERSION +) + +if(NGHTTP3_FOUND) + set(NGHTTP3_LIBRARIES ${NGHTTP3_LIBRARY}) + set(NGHTTP3_INCLUDE_DIRS ${NGHTTP3_INCLUDE_DIR}) +endif() + +mark_as_advanced(NGHTTP3_INCLUDE_DIRS NGHTTP3_LIBRARIES) diff --git a/Utilities/cmcurl/CMake/FindNGTCP2.cmake b/Utilities/cmcurl/CMake/FindNGTCP2.cmake new file mode 100644 index 0000000..a1ed8cd --- /dev/null +++ b/Utilities/cmcurl/CMake/FindNGTCP2.cmake @@ -0,0 +1,113 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + +#[=======================================================================[.rst: +FindNGTCP2 +---------- + +Find the ngtcp2 library + +This module accepts optional COMPONENTS to control the crypto library (these are +mutually exclusive):: + + OpenSSL: Use libngtcp2_crypto_openssl + GnuTLS: Use libngtcp2_crypto_gnutls + +Result Variables +^^^^^^^^^^^^^^^^ + +``NGTCP2_FOUND`` + System has ngtcp2 +``NGTCP2_INCLUDE_DIRS`` + The ngtcp2 include directories. +``NGTCP2_LIBRARIES`` + The libraries needed to use ngtcp2 +``NGTCP2_VERSION`` + version of ngtcp2. +#]=======================================================================] + +if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(PC_NGTCP2 libngtcp2) +endif() + +find_path(NGTCP2_INCLUDE_DIR ngtcp2/ngtcp2.h + HINTS + ${PC_NGTCP2_INCLUDEDIR} + ${PC_NGTCP2_INCLUDE_DIRS} +) + +find_library(NGTCP2_LIBRARY NAMES ngtcp2 + HINTS + ${PC_NGTCP2_LIBDIR} + ${PC_NGTCP2_LIBRARY_DIRS} +) + +if(PC_NGTCP2_VERSION) + set(NGTCP2_VERSION ${PC_NGTCP2_VERSION}) +endif() + +if(NGTCP2_FIND_COMPONENTS) + set(NGTCP2_CRYPTO_BACKEND "") + foreach(component IN LISTS NGTCP2_FIND_COMPONENTS) + if(component MATCHES "^(OpenSSL|GnuTLS)") + if(NGTCP2_CRYPTO_BACKEND) + message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected") + endif() + set(NGTCP2_CRYPTO_BACKEND ${component}) + endif() + endforeach() + + if(NGTCP2_CRYPTO_BACKEND) + string(TOLOWER "ngtcp2_crypto_${NGTCP2_CRYPTO_BACKEND}" _crypto_library) + if(UNIX) + pkg_search_module(PC_${_crypto_library} lib${_crypto_library}) + endif() + find_library(${_crypto_library}_LIBRARY + NAMES + ${_crypto_library} + HINTS + ${PC_${_crypto_library}_LIBDIR} + ${PC_${_crypto_library}_LIBRARY_DIRS} + ) + if(${_crypto_library}_LIBRARY) + set(NGTCP2_${NGTCP2_CRYPTO_BACKEND}_FOUND TRUE) + set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library}_LIBRARY}) + endif() + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NGTCP2 + REQUIRED_VARS + NGTCP2_LIBRARY + NGTCP2_INCLUDE_DIR + VERSION_VAR NGTCP2_VERSION + HANDLE_COMPONENTS +) + +if(NGTCP2_FOUND) + set(NGTCP2_LIBRARIES ${NGTCP2_LIBRARY} ${NGTCP2_CRYPTO_LIBRARY}) + set(NGTCP2_INCLUDE_DIRS ${NGTCP2_INCLUDE_DIR}) +endif() + +mark_as_advanced(NGTCP2_INCLUDE_DIRS NGTCP2_LIBRARIES) diff --git a/Utilities/cmcurl/CMake/FindNSS.cmake b/Utilities/cmcurl/CMake/FindNSS.cmake index 0043ce8..5fdb2b7 100644 --- a/Utilities/cmcurl/CMake/FindNSS.cmake +++ b/Utilities/cmcurl/CMake/FindNSS.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### if(UNIX) find_package(PkgConfig QUIET) pkg_search_module(PC_NSS nss) diff --git a/Utilities/cmcurl/CMake/FindQUICHE.cmake b/Utilities/cmcurl/CMake/FindQUICHE.cmake new file mode 100644 index 0000000..01d1758 --- /dev/null +++ b/Utilities/cmcurl/CMake/FindQUICHE.cmake @@ -0,0 +1,68 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + +#[=======================================================================[.rst: +FindQUICHE +---------- + +Find the quiche library + +Result Variables +^^^^^^^^^^^^^^^^ + +``QUICHE_FOUND`` + System has quiche +``QUICHE_INCLUDE_DIRS`` + The quiche include directories. +``QUICHE_LIBRARIES`` + The libraries needed to use quiche +#]=======================================================================] +if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(PC_QUICHE quiche) +endif() + +find_path(QUICHE_INCLUDE_DIR quiche.h + HINTS + ${PC_QUICHE_INCLUDEDIR} + ${PC_QUICHE_INCLUDE_DIRS} +) + +find_library(QUICHE_LIBRARY NAMES quiche + HINTS + ${PC_QUICHE_LIBDIR} + ${PC_QUICHE_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(QUICHE + REQUIRED_VARS + QUICHE_LIBRARY + QUICHE_INCLUDE_DIR +) + +if(QUICHE_FOUND) + set(QUICHE_LIBRARIES ${QUICHE_LIBRARY}) + set(QUICHE_INCLUDE_DIRS ${QUICHE_INCLUDE_DIR}) +endif() + +mark_as_advanced(QUICHE_INCLUDE_DIRS QUICHE_LIBRARIES) diff --git a/Utilities/cmcurl/CMake/FindWolfSSL.cmake b/Utilities/cmcurl/CMake/FindWolfSSL.cmake new file mode 100644 index 0000000..54df1a8 --- /dev/null +++ b/Utilities/cmcurl/CMake/FindWolfSSL.cmake @@ -0,0 +1,34 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### +find_path(WolfSSL_INCLUDE_DIR NAMES wolfssl/ssl.h) +find_library(WolfSSL_LIBRARY NAMES wolfssl) +mark_as_advanced(WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WolfSSL + REQUIRED_VARS WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY + ) + +if(WolfSSL_FOUND) + set(WolfSSL_INCLUDE_DIRS ${WolfSSL_INCLUDE_DIR}) + set(WolfSSL_LIBRARIES ${WolfSSL_LIBRARY}) +endif() diff --git a/Utilities/cmcurl/CMake/Macros.cmake b/Utilities/cmcurl/CMake/Macros.cmake index 7f71345..65a41e4 100644 --- a/Utilities/cmcurl/CMake/Macros.cmake +++ b/Utilities/cmcurl/CMake/Macros.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### #File defines convenience macros for available feature testing # This macro checks if the symbol exists in the library and if it diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake index 30315dc..8c9a491 100644 --- a/Utilities/cmcurl/CMake/OtherTests.cmake +++ b/Utilities/cmcurl/CMake/OtherTests.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### include(CheckCSourceCompiles) # The begin of the sources (macros and includes) set(_source_epilogue "#undef inline") @@ -49,6 +70,9 @@ if(curl_cv_recv) unset(curl_cv_func_recv_test CACHE) check_c_source_compiles(" ${_source_epilogue} + #ifdef WINSOCK_API_LINKAGE + WINSOCK_API_LINKAGE + #endif extern ${recv_retv} ${signature_call_conv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4}); int main(void) { @@ -122,6 +146,9 @@ if(curl_cv_send) unset(curl_cv_func_send_test CACHE) check_c_source_compiles(" ${_source_epilogue} + #ifdef WINSOCK_API_LINKAGE + WINSOCK_API_LINKAGE + #endif extern ${send_retv} ${signature_call_conv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4}); int main(void) { diff --git a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake index 4c4c63b..7c020bd 100644 --- a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake +++ b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### if(NOT UNIX) if(WIN32) set(HAVE_LIBDL 0) diff --git a/Utilities/cmcurl/CMake/Utilities.cmake b/Utilities/cmcurl/CMake/Utilities.cmake index ffc411a..59b17d0 100644 --- a/Utilities/cmcurl/CMake/Utilities.cmake +++ b/Utilities/cmcurl/CMake/Utilities.cmake @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### # File containing various utilities # Returns a list of arguments that evaluate to true diff --git a/Utilities/cmcurl/CMake/cmake_uninstall.cmake.in b/Utilities/cmcurl/CMake/cmake_uninstall.cmake.in index 5178fd8..74e56a2 100644 --- a/Utilities/cmcurl/CMake/cmake_uninstall.cmake.in +++ b/Utilities/cmcurl/CMake/cmake_uninstall.cmake.in @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif() diff --git a/Utilities/cmcurl/CMake/curl-config.cmake.in b/Utilities/cmcurl/CMake/curl-config.cmake.in index 1294e17..ae8cc30 100644 --- a/Utilities/cmcurl/CMake/curl-config.cmake.in +++ b/Utilities/cmcurl/CMake/curl-config.cmake.in @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### @PACKAGE_INIT@ include(CMakeFindDependencyMacro) diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt index 90d104f..cf6ad9b 100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@ -118,7 +118,6 @@ endif() # The output .so file lacks the soname number which we currently have within the lib/Makefile.am file # Add full (4 or 5 libs) SSL support # Add INSTALL target (EXTRA_DIST variables in Makefile.am may be moved to Makefile.inc so that CMake/CPack is aware of what's to include). -# Add CTests(?) # Check on all possible platforms # Test with as many configurations possible (With or without any option) # Create scripts that help keeping the CMake build system up to date (to reduce maintenance). According to Tetetest: @@ -274,6 +273,8 @@ option(CURL_DISABLE_SMTP "to disable SMTP" OFF) mark_as_advanced(CURL_DISABLE_SMTP) option(CURL_DISABLE_GOPHER "to disable Gopher" OFF) mark_as_advanced(CURL_DISABLE_GOPHER) +option(CURL_ENABLE_MQTT "to enable MQTT" OFF) +mark_as_advanced(CURL_ENABLE_MQTT) if(HTTP_ONLY) set(CURL_DISABLE_FTP ON) @@ -323,10 +324,6 @@ cmake_dependent_option(ENABLE_MANUAL "to provide the built-in manual" ON "NROFF_USEFUL;PERL_FOUND" OFF) -if(NOT PERL_FOUND) - message(STATUS "Perl not found, testing disabled.") - set(BUILD_TESTING OFF) -endif() if(ENABLE_MANUAL) set(USE_MANUAL ON) endif() @@ -337,6 +334,7 @@ set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}") set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS}) if(CURL_STATIC_CRT) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") endif() @@ -411,7 +409,7 @@ if(WIN32) endif() # check SSL libraries -# TODO support GnuTLS and WolfSSL +# TODO support GnuTLS if(APPLE) option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF) @@ -424,9 +422,10 @@ 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) set(openssl_default ON) -if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS) +if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS OR CMAKE_USE_WOLFSSL) set(openssl_default OFF) endif() @@ -437,6 +436,7 @@ count_true(enabled_ssl_options_count CMAKE_USE_MBEDTLS CMAKE_USE_BEARSSL CMAKE_USE_NSS + CMAKE_USE_WOLFSSL ) if(enabled_ssl_options_count GREATER "1") set(CURL_WITH_MULTI_SSL ON) @@ -523,6 +523,14 @@ if(CMAKE_USE_BEARSSL) include_directories(${BEARSSL_INCLUDE_DIRS}) endif() +if(CMAKE_USE_WOLFSSL) + find_package(WolfSSL REQUIRED) + set(SSL_ENABLED ON) + set(USE_WOLFSSL ON) + list(APPEND CURL_LIBS ${WolfSSL_LIBRARIES}) + include_directories(${WolfSSL_INCLUDE_DIRS}) +endif() + if(CMAKE_USE_NSS) find_package(NSS REQUIRED) include_directories(${NSS_INCLUDE_DIRS}) @@ -543,6 +551,56 @@ if(USE_NGHTTP2) list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES}) endif() +function(CheckQuicSupportInOpenSSL) + # Be sure that the OpenSSL library actually supports QUIC. + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") + set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}") + check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD) + if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD) + message(FATAL_ERROR "QUIC support is missing in OpenSSL/boringssl. Try setting -DOPENSSL_ROOT_DIR") + endif() + cmake_pop_check_state() +endfunction() + +option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF) +if(USE_NGTCP2) + if(USE_OPENSSL) + find_package(NGTCP2 REQUIRED OpenSSL) + CheckQuicSupportInOpenSSL() + elseif(USE_GNUTLS) + # TODO add GnuTLS support as vtls library. + find_package(NGTCP2 REQUIRED GnuTLS) + else() + message(FATAL_ERROR "ngtcp2 requires OpenSSL or GnuTLS") + endif() + set(USE_NGTCP2 ON) + include_directories(${NGTCP2_INCLUDE_DIRS}) + list(APPEND CURL_LIBS ${NGTCP2_LIBRARIES}) + + find_package(NGHTTP3 REQUIRED) + set(USE_NGHTTP3 ON) + include_directories(${NGHTTP3_INCLUDE_DIRS}) + list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES}) +endif() + +option(USE_QUICHE "Use quiche library for HTTP/3 support" OFF) +if(USE_QUICHE) + if(USE_NGTCP2) + message(FATAL_ERROR "Only one HTTP/3 backend can be selected!") + endif() + find_package(QUICHE REQUIRED) + CheckQuicSupportInOpenSSL() + set(USE_QUICHE ON) + include_directories(${QUICHE_INCLUDE_DIRS}) + list(APPEND CURL_LIBS ${QUICHE_LIBRARIES}) + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES "${QUICHE_INCLUDE_DIRS}") + set(CMAKE_REQUIRED_LIBRARIES "${QUICHE_LIBRARIES}") + check_symbol_exists(quiche_conn_set_qlog_fd "quiche.h" HAVE_QUICHE_CONN_SET_QLOG_FD) + cmake_pop_check_state() +endif() + if(WIN32) set(USE_WIN32_CRYPTO ON) endif() @@ -744,6 +802,20 @@ if(CMAKE_USE_LIBSSH2) endif() endif() +# libssh +option(CMAKE_USE_LIBSSH "Use libSSH" OFF) +mark_as_advanced(CMAKE_USE_LIBSSH) +if(NOT HAVE_LIBSSH2 AND CMAKE_USE_LIBSSH) + find_package(libssh CONFIG) + if(libssh_FOUND) + message(STATUS "Found libssh ${libssh_VERSION}") + # Use imported target for include and library paths. + list(APPEND CURL_LIBS ssh) + set(USE_LIBSSH ON) + set(HAVE_LIBSSH_LIBSSH_H 1) + 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) @@ -812,6 +884,8 @@ else() unset(USE_UNIX_SOCKETS CACHE) endif() +option(ENABLE_ALT_SVC "Enable alt-svc support" OFF) +set(USE_ALTSVC ${ENABLE_ALT_SVC}) if(0) # This code not needed for building within CMake. # @@ -882,7 +956,7 @@ elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT) endif() if(CURL_CA_PATH_SET AND NOT USE_OPENSSL AND NOT USE_MBEDTLS) - message(FATAL_ERROR + message(STATUS "CA path only supported by OpenSSL, GnuTLS or mbed TLS. " "Set CURL_CA_PATH=none or enable one of those TLS backends.") endif() @@ -926,7 +1000,6 @@ check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H) check_include_file_concat("arpa/tftp.h" HAVE_ARPA_TFTP_H) check_include_file_concat("assert.h" HAVE_ASSERT_H) check_include_file_concat("crypto.h" HAVE_CRYPTO_H) -check_include_file_concat("des.h" HAVE_DES_H) check_include_file_concat("err.h" HAVE_ERR_H) check_include_file_concat("errno.h" HAVE_ERRNO_H) check_include_file_concat("fcntl.h" HAVE_FCNTL_H) @@ -1314,7 +1387,7 @@ function(transform_makefile_inc INPUT_FILE OUTPUT_FILE) string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace $() with ${} string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace @@ with ${}, even if that may not be read by CMake scripts. file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT}) - + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${INPUT_FILE}") endfunction() if(0) # This code not needed for building within CMake. @@ -1350,8 +1423,10 @@ install(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmcurl) #----------------------------------------------------------------------------- if(0) # This code not needed for building within CMake. -include(CTest) -if(BUILD_TESTING) +option(BUILD_TESTING "Build tests" "${PERL_FOUND}") +if(NOT PERL_FOUND) + message(STATUS "Perl not found, testing disabled.") +elseif(BUILD_TESTING) add_subdirectory(tests) endif() @@ -1385,6 +1460,7 @@ _add_if("Largefile" (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND # TODO SSP1 (WinSSL) check is missing _add_if("SSPI" USE_WINDOWS_SSPI) _add_if("GSS-API" HAVE_GSSAPI) +_add_if("alt-svc" ENABLE_ALT_SVC) # TODO SSP1 missing for SPNEGO _add_if("SPNEGO" NOT CURL_DISABLE_CRYPTO_AUTH AND (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) @@ -1399,6 +1475,8 @@ _add_if("NTLM_WB" use_ntlm AND NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED) _add_if("TLS-SRP" USE_TLS_SRP) # TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header _add_if("HTTP2" USE_NGHTTP2) +_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE) +_add_if("MultiSSL" CURL_WITH_MULTI_SSL) _add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS)) string(REPLACE ";" " " SUPPORT_FEATURES "${_items}") message(STATUS "Enabled features: ${SUPPORT_FEATURES}") @@ -1428,10 +1506,11 @@ _add_if("SMB" NOT CURL_DISABLE_SMB AND use_ntlm) _add_if("SMBS" NOT CURL_DISABLE_SMB AND SSL_ENABLED AND use_ntlm) _add_if("SMTP" NOT CURL_DISABLE_SMTP) _add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED) -_add_if("SCP" USE_LIBSSH2) -_add_if("SFTP" USE_LIBSSH2) +_add_if("SCP" USE_LIBSSH2 OR USE_LIBSSH) +_add_if("SFTP" USE_LIBSSH2 OR USE_LIBSSH) _add_if("RTSP" NOT CURL_DISABLE_RTSP) _add_if("RTMP" USE_LIBRTMP) +_add_if("MQTT" CURL_ENABLE_MQTT) if(_items) list(SORT _items) endif() @@ -1446,6 +1525,7 @@ _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP) _add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS) _add_if("BearSSL" SSL_ENABLED AND USE_BEARSSL) _add_if("NSS" SSL_ENABLED AND USE_NSS) +_add_if("wolfSSL" SSL_ENABLED AND USE_WOLFSSL) if(_items) list(SORT _items) endif() @@ -1459,25 +1539,43 @@ set(CONFIGURE_OPTIONS "") # TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB? set(CPPFLAG_CURL_STATICLIB "") set(CURLVERSION "${CURL_VERSION}") -if(BUILD_SHARED_LIBS) - set(ENABLE_SHARED "yes") - set(ENABLE_STATIC "no") -else() - set(ENABLE_SHARED "no") - set(ENABLE_STATIC "yes") -endif() set(exec_prefix "\${prefix}") set(includedir "\${prefix}/include") set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") set(LIBCURL_LIBS "") set(libdir "${CMAKE_INSTALL_PREFIX}/lib") foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS}) + if(TARGET "${_lib}") + set(_libname "${_lib}") + get_target_property(_libtype "${_libname}" TYPE) + if(_libtype STREQUAL INTERFACE_LIBRARY) + # Interface libraries can occur when an external project embeds curl and + # defined targets such as ZLIB::ZLIB by themselves. Ignore these as + # reading the LOCATION property will error out. Assume the user won't need + # this information in the .pc file. + continue() + endif() + get_target_property(_lib "${_libname}" LOCATION) + if(NOT _lib) + message(WARNING "Bad lib in library list: ${_libname}") + continue() + endif() + endif() if(_lib MATCHES ".*/.*" OR _lib MATCHES "^-") set(LIBCURL_LIBS "${LIBCURL_LIBS} ${_lib}") else() set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") endif() endforeach() +if(BUILD_SHARED_LIBS) + set(ENABLE_SHARED "yes") + set(ENABLE_STATIC "no") + set(LIBCURL_NO_SHARED "") +else() + set(ENABLE_SHARED "no") + set(ENABLE_STATIC "yes") + set(LIBCURL_NO_SHARED "${LIBCURL_LIBS}") +endif() # "a" (Linux) or "lib" (Windows) string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") set(prefix "${CMAKE_INSTALL_PREFIX}") diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h index 7e99d5e..735c206 100644 --- a/Utilities/cmcurl/include/curl/curl.h +++ b/Utilities/cmcurl/include/curl/curl.h @@ -833,6 +833,15 @@ typedef enum { if possible. The OpenSSL backend has this ability. */ #define CURLSSLOPT_NO_PARTIALCHAIN (1<<2) +/* - REVOKE_BEST_EFFORT tells libcurl to ignore certificate revocation offline + checks and ignore missing revocation list for those SSL backends where such + behavior is present. */ +#define CURLSSLOPT_REVOKE_BEST_EFFORT (1<<3) + +/* - CURLSSLOPT_NATIVE_CA tells libcurl to use standard certificate store of + operating system. Currently implemented under MS-Windows. */ +#define CURLSSLOPT_NATIVE_CA (1<<4) + /* The default connection attempt delay in milliseconds for happy eyeballs. CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document this value, keep them in sync. */ @@ -932,6 +941,7 @@ typedef enum { #define CURLPROTO_GOPHER (1<<25) #define CURLPROTO_SMB (1<<26) #define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_MQTT (1<<28) #define CURLPROTO_ALL (~0) /* enable everything */ /* long may be 32 or 64 bits, but we should never depend on anything else @@ -940,6 +950,7 @@ typedef enum { #define CURLOPTTYPE_OBJECTPOINT 10000 #define CURLOPTTYPE_FUNCTIONPOINT 20000 #define CURLOPTTYPE_OFF_T 30000 +#define CURLOPTTYPE_BLOB 40000 /* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the string options from the header file */ @@ -1949,6 +1960,17 @@ typedef enum { /* allow RCPT TO command to fail for some recipients */ CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290), + /* the private SSL-certificate as a "blob" */ + CURLOPT(CURLOPT_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 291), + CURLOPT(CURLOPT_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 292), + CURLOPT(CURLOPT_PROXY_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 293), + CURLOPT(CURLOPT_PROXY_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 294), + CURLOPT(CURLOPT_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 295), + + /* Issuer certificate for proxy */ + CURLOPT(CURLOPT_PROXY_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 296), + CURLOPT(CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 297), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -2105,8 +2127,8 @@ CURL_EXTERN int curl_strequal(const char *s1, const char *s2); CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); /* Mime/form handling support. */ -typedef struct curl_mime_s curl_mime; /* Mime context. */ -typedef struct curl_mimepart_s curl_mimepart; /* Mime part context. */ +typedef struct curl_mime curl_mime; /* Mime context. */ +typedef struct curl_mimepart curl_mimepart; /* Mime part context. */ /* * NAME curl_mime_init() @@ -2428,7 +2450,7 @@ CURL_EXTERN CURLcode curl_global_init(long flags); * initialize libcurl and set user defined memory management callback * functions. Users can implement memory management routines to check for * memory leaks, check for mis-use of the curl library etc. User registered - * callback routines with be invoked by this library instead of the system + * callback routines will be invoked by this library instead of the system * memory management routines like malloc, free etc. */ CURL_EXTERN CURLcode curl_global_init_mem(long flags, @@ -2480,10 +2502,11 @@ struct curl_slist { * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. */ -typedef struct { +struct curl_ssl_backend { curl_sslbackend id; const char *name; -} curl_ssl_backend; +}; +typedef struct curl_ssl_backend curl_ssl_backend; typedef enum { CURLSSLSET_OK = 0, @@ -2724,6 +2747,7 @@ typedef enum { CURLVERSION_FOURTH, CURLVERSION_FIFTH, CURLVERSION_SIXTH, + CURLVERSION_SEVENTH, CURLVERSION_LAST /* never actually use this */ } CURLversion; @@ -2732,9 +2756,9 @@ typedef enum { meant to be a built-in version number for what kind of struct the caller expects. If the struct ever changes, we redefine the NOW to another enum from above. */ -#define CURLVERSION_NOW CURLVERSION_SIXTH +#define CURLVERSION_NOW CURLVERSION_SEVENTH -typedef struct { +struct curl_version_info_data { CURLversion age; /* age of the returned struct */ const char *version; /* LIBCURL_VERSION */ unsigned int version_num; /* LIBCURL_VERSION_NUM */ @@ -2771,7 +2795,15 @@ typedef struct { const char *nghttp2_version; /* human readable string. */ const char *quic_version; /* human readable quic (+ HTTP/3) library + version or NULL */ -} curl_version_info_data; + + /* These fields were added in CURLVERSION_SEVENTH */ + const char *cainfo; /* the built-in default CURLOPT_CAINFO, might + be NULL */ + const char *capath; /* the built-in default CURLOPT_CAPATH, might + be NULL */ + +}; +typedef struct curl_version_info_data curl_version_info_data; #define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ #define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported @@ -2805,8 +2837,6 @@ typedef struct { #define CURL_VERSION_ALTSVC (1<<24) /* Alt-Svc handling built-in */ #define CURL_VERSION_HTTP3 (1<<25) /* HTTP3 support built-in */ -#define CURL_VERSION_ESNI (1<<26) /* ESNI support */ - /* * NAME curl_version_info() * diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h index 8fd0874..4c2e432 100644 --- a/Utilities/cmcurl/include/curl/curlver.h +++ b/Utilities/cmcurl/include/curl/curlver.h @@ -30,16 +30,16 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.69.0" +#define LIBCURL_VERSION "7.71.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 69 +#define LIBCURL_VERSION_MINOR 71 #define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier - parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will always follow this syntax: 0xXXYYZZ @@ -57,7 +57,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x074500 +#define LIBCURL_VERSION_NUM 0x074700 /* * This is the date and time when the full source package was created. The diff --git a/Utilities/cmcurl/include/curl/easy.h b/Utilities/cmcurl/include/curl/easy.h index 592f5d3..9aef133 100644 --- a/Utilities/cmcurl/include/curl/easy.h +++ b/Utilities/cmcurl/include/curl/easy.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,6 +25,17 @@ extern "C" { #endif +/* Flag bits in the curl_blob struct: */ +#define CURL_BLOB_COPY 1 /* tell libcurl to copy the data */ +#define CURL_BLOB_NOCOPY 0 /* tell libcurl to NOT copy the data */ + +struct curl_blob { + void *data; + size_t len; + unsigned int flags; /* bit 0 is defined, the rest are reserved and should be + left zeroes */ +}; + CURL_EXTERN CURL *curl_easy_init(void); CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); diff --git a/Utilities/cmcurl/include/curl/multi.h b/Utilities/cmcurl/include/curl/multi.h index bda9bb7..3039e78 100644 --- a/Utilities/cmcurl/include/curl/multi.h +++ b/Utilities/cmcurl/include/curl/multi.h @@ -377,12 +377,10 @@ typedef enum { will not be considered for pipelining */ CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10), - /* a list of site names(+port) that are blacklisted from - pipelining */ + /* a list of site names(+port) that are blocked from pipelining */ CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11), - /* a list of server types that are blacklisted from - pipelining */ + /* a list of server types that are blocked from pipelining */ CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12), /* maximum number of open connections in total */ diff --git a/Utilities/cmcurl/include/curl/typecheck-gcc.h b/Utilities/cmcurl/include/curl/typecheck-gcc.h index 03c84fc..f8cb921 100644 --- a/Utilities/cmcurl/include/curl/typecheck-gcc.h +++ b/Utilities/cmcurl/include/curl/typecheck-gcc.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -248,7 +248,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) #define curlcheck_off_t_option(option) \ - ((option) > CURLOPTTYPE_OFF_T) + (((option) > CURLOPTTYPE_OFF_T) && ((option) < CURLOPTTYPE_BLOB)) /* evaluates to true if option takes a char* argument */ #define curlcheck_string_option(option) \ @@ -392,8 +392,9 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, /* groups of curl_easy_getinfo infos that take the same type of argument */ /* evaluates to true if info expects a pointer to char * argument */ -#define curlcheck_string_info(info) \ - (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) +#define curlcheck_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG && \ + (info) != CURLINFO_PRIVATE) /* evaluates to true if info expects a pointer to long argument */ #define curlcheck_long_info(info) \ diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt index 230c7cf..32bea68 100644 --- a/Utilities/cmcurl/lib/CMakeLists.txt +++ b/Utilities/cmcurl/lib/CMakeLists.txt @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### set(LIB_NAME cmcurl) if(BUILD_SHARED_LIBS) @@ -96,6 +117,11 @@ add_library( ${CMAKE_CURL_SSL_DLLS} ) +add_library( + ${PROJECT_NAME}::${LIB_NAME} + ALIAS ${LIB_NAME} + ) + if(NOT BUILD_SHARED_LIBS) set_target_properties(${LIB_NAME} PROPERTIES INTERFACE_COMPILE_DEFINITIONS CURL_STATICLIB) endif() @@ -146,7 +172,7 @@ install(TARGETS ${LIB_NAME} export(TARGETS ${LIB_NAME} APPEND FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake - NAMESPACE CURL:: + NAMESPACE ${PROJECT_NAME}:: ) endif() diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc index 46ded90..723b826 100644 --- a/Utilities/cmcurl/lib/Makefile.inc +++ b/Utilities/cmcurl/lib/Makefile.inc @@ -20,71 +20,66 @@ # ########################################################################### -LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ - vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \ - vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c \ - vauth/spnego_gssapi.c vauth/spnego_sspi.c +LIB_VAUTH_CFILES = vauth/cleartext.c vauth/cram.c vauth/digest.c \ + vauth/digest_sspi.c vauth/krb5_gssapi.c vauth/krb5_sspi.c vauth/ntlm.c \ + vauth/ntlm_sspi.c vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \ + vauth/vauth.c -LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h +LIB_VAUTH_HFILES = vauth/digest.h vauth/ntlm.h vauth/vauth.h -LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/mbedtls_threadlock.c vtls/wolfssl.c vtls/schannel.c \ - vtls/schannel_verify.c vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c \ - vtls/mesalink.c vtls/bearssl.c +LIB_VTLS_CFILES = vtls/bearssl.c vtls/gskit.c vtls/gtls.c vtls/keylog.c \ + vtls/mbedtls.c vtls/mbedtls_threadlock.c vtls/mesalink.c vtls/nss.c \ + vtls/openssl.c vtls/schannel.c vtls/schannel_verify.c vtls/sectransp.c \ + vtls/vtls.c vtls/wolfssl.c -LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h vtls/nssg.h \ - vtls/mbedtls_threadlock.h vtls/wolfssl.h vtls/schannel.h \ - vtls/sectransp.h vtls/gskit.h vtls/mbedtls.h vtls/mesalink.h \ - vtls/bearssl.h +LIB_VTLS_HFILES = vtls/bearssl.h vtls/gskit.h vtls/gtls.h vtls/keylog.h \ + vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/mesalink.h vtls/nssg.h \ + vtls/openssl.h vtls/schannel.h vtls/sectransp.h vtls/vtls.h vtls/wolfssl.h -LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c +LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c vquic/vquic.c -LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h +LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h vquic/vquic.h -LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c vssh/wolfssh.c +LIB_VSSH_CFILES = vssh/libssh.c vssh/libssh2.c vssh/wolfssh.c LIB_VSSH_HFILES = vssh/ssh.h -LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ - cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ - ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ - getinfo.c transfer.c strcase.c easy.c security.c curl_fnmatch.c \ - fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ - strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ - http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ - strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ - inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ - curl_addrinfo.c socks_gssapi.c socks_sspi.c \ - curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ - pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ - openldap.c curl_gethostname.c gopher.c idn_win32.c \ - http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ - http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \ - curl_multibyte.c hostcheck.c conncache.c dotdot.c \ - x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ - mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \ - doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c rename.c +LIB_CFILES = altsvc.c amigaos.c asyn-ares.c asyn-thread.c base64.c \ + conncache.c connect.c content_encoding.c cookie.c curl_addrinfo.c \ + curl_ctype.c curl_des.c curl_endian.c curl_fnmatch.c curl_get_line.c \ + curl_gethostname.c curl_gssapi.c curl_memrchr.c curl_multibyte.c \ + curl_ntlm_core.c curl_ntlm_wb.c curl_path.c curl_range.c curl_rtmp.c \ + curl_sasl.c curl_sspi.c curl_threads.c dict.c dotdot.c easy.c escape.c \ + file.c fileinfo.c formdata.c ftp.c url.c ftplistparser.c getenv.c getinfo.c \ + gopher.c hash.c hmac.c hostasyn.c hostcheck.c hostip.c hostip4.c hostip6.c \ + hostsyn.c http.c http2.c http_chunks.c http_digest.c http_negotiate.c \ + http_ntlm.c http_proxy.c idn_win32.c if2ip.c imap.c inet_ntop.c inet_pton.c \ + krb5.c ldap.c llist.c md4.c md5.c memdebug.c mime.c mprintf.c mqtt.c \ + multi.c netrc.c non-ascii.c nonblock.c openldap.c parsedate.c pingpong.c \ + pop3.c progress.c psl.c doh.c rand.c rename.c rtsp.c security.c select.c \ + sendf.c setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \ + socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c \ + strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c \ + transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c dynbuf.c -LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ - formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ - speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ - strcase.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ - wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ - hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ - http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ - inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ - easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ - socks.h curl_base64.h curl_addrinfo.h curl_sspi.h \ - slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ - rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ - curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ - http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ - curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ - curl_setup_once.h multihandle.h setup-vms.h dotdot.h \ - x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ - curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \ - curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \ - curl_get_line.h altsvc.h quic.h socketpair.h rename.h +LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h \ + content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h \ + curl_des.h curl_endian.h curl_fnmatch.h curl_get_line.h curl_gethostname.h \ + curl_gssapi.h curl_hmac.h curl_ldap.h curl_md4.h curl_md5.h curl_memory.h \ + curl_memrchr.h curl_multibyte.h curl_ntlm_core.h curl_ntlm_wb.h curl_path.h \ + curl_printf.h curl_range.h curl_rtmp.h curl_sasl.h curl_sec.h curl_setup.h \ + curl_setup_once.h curl_sha256.h curl_sspi.h curl_threads.h curlx.h dict.h \ + dotdot.h easyif.h escape.h file.h fileinfo.h formdata.h ftp.h url.h \ + ftplistparser.h getinfo.h gopher.h hash.h hostcheck.h hostip.h http.h \ + http2.h http_chunks.h http_digest.h http_negotiate.h http_ntlm.h \ + http_proxy.h if2ip.h imap.h inet_ntop.h inet_pton.h llist.h memdebug.h \ + mime.h mqtt.h multihandle.h multiif.h netrc.h non-ascii.h nonblock.h \ + parsedate.h pingpong.h pop3.h progress.h psl.h doh.h quic.h rand.h rename.h \ + rtsp.h select.h sendf.h setopt.h setup-vms.h share.h sigpipe.h slist.h \ + smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \ + strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h \ + timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h \ + x509asn1.h dynbuf.h LIB_RCFILES = libcurl.rc diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c index c39d86e..c2ec489 100644 --- a/Utilities/cmcurl/lib/altsvc.c +++ b/Utilities/cmcurl/lib/altsvc.c @@ -50,8 +50,10 @@ #define MAX_ALTSVC_ALPNLENSTR "10" #define MAX_ALTSVC_ALPNLEN 10 -#if (defined(USE_QUICHE) || defined(USE_NGTCP2)) && !defined(UNITTESTS) -#define H3VERSION "h3-27" +#if defined(USE_QUICHE) && !defined(UNITTESTS) +#define H3VERSION "h3-29" +#elif defined(USE_NGTCP2) && !defined(UNITTESTS) +#define H3VERSION "h3-29" #else #define H3VERSION "h3" #endif @@ -167,7 +169,6 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line) as->prio = prio; as->persist = persist ? 1 : 0; Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); - asi->num++; /* one more entry */ } } @@ -408,7 +409,6 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid, strcasecompare(srchost, as->src.host)) { Curl_llist_remove(&asi->list, e, NULL); altsvc_free(as); - asi->num--; } } } @@ -429,6 +429,8 @@ static time_t debugtime(void *unused) #define time(x) debugtime(x) #endif +#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r') + /* * Curl_altsvc_parse() takes an incoming alt-svc response header and stores * the data correctly in the cache. @@ -474,7 +476,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, dstalpnid = alpn2alpnid(alpnbuf); p++; if(*p == '\"') { - const char *dsthost; + const char *dsthost = ""; const char *value_ptr; char option[32]; unsigned long num; @@ -518,12 +520,12 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, /* Handle the optional 'ma' and 'persist' flags. Unknown flags are skipped. */ for(;;) { - while(*p && ISBLANK(*p) && *p != ';' && *p != ',') + while(ISBLANK(*p)) p++; - if(!*p || *p == ',') + if(*p != ';') break; p++; /* pass the semicolon */ - if(!*p) + if(!*p || ISNEWLINE(*p)) break; result = getalnum(&p, option, sizeof(option)); if(result) { @@ -573,7 +575,6 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, as->expires = maxage + time(NULL); as->persist = persist; Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); - asi->num++; /* one more entry */ infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport, Curl_alpnid2str(dstalpnid)); } diff --git a/Utilities/cmcurl/lib/altsvc.h b/Utilities/cmcurl/lib/altsvc.h index 248e71e..578a4fb 100644 --- a/Utilities/cmcurl/lib/altsvc.h +++ b/Utilities/cmcurl/lib/altsvc.h @@ -52,7 +52,6 @@ struct altsvc { struct altsvcinfo { char *filename; struct curl_llist list; /* list of entries */ - size_t num; /* number of alt-svc entries */ long flags; /* the publicly set bitmask */ }; diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c index b76e665..ba5160b 100644 --- a/Utilities/cmcurl/lib/asyn-ares.c +++ b/Utilities/cmcurl/lib/asyn-ares.c @@ -87,7 +87,8 @@ struct ResolverResults { int num_pending; /* number of ares_gethostbyname() requests */ - Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ + struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares + parts */ int last_status; struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ }; @@ -285,7 +286,7 @@ int Curl_resolver_getsock(struct connectdata *conn, * return number of sockets it worked on */ -static int waitperform(struct connectdata *conn, int timeout_ms) +static int waitperform(struct connectdata *conn, timediff_t timeout_ms) { struct Curl_easy *data = conn->data; int nfds; @@ -352,8 +353,8 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, conn->async.os_specific; CURLcode result = CURLE_OK; - if(dns) - *dns = NULL; + DEBUGASSERT(dns); + *dns = NULL; waitperform(conn, 0); @@ -381,19 +382,18 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, } if(res && !res->num_pending) { - if(dns) { - (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai); - /* temp_ai ownership is moved to the connection, so we need not free-up - them */ - res->temp_ai = NULL; - } + (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai); + /* temp_ai ownership is moved to the connection, so we need not free-up + them */ + res->temp_ai = NULL; + if(!conn->async.dns) { failf(data, "Could not resolve: %s (%s)", conn->async.hostname, ares_strerror(conn->async.status)); result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: CURLE_COULDNT_RESOLVE_HOST; } - else if(dns) + else *dns = conn->async.dns; destroy_async_data(&conn->async); @@ -408,7 +408,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, * Waits for a resolve to finish. This function should be avoided since using * this risk getting the multi interface to "hang". * - * If 'entry' is non-NULL, make it point to the resolved dns entry + * 'entry' MUST be non-NULL. * * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. @@ -420,10 +420,9 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_easy *data = conn->data; timediff_t timeout; struct curltime now = Curl_now(); - struct Curl_dns_entry *temp_entry; - if(entry) - *entry = NULL; /* clear on entry */ + DEBUGASSERT(entry); + *entry = NULL; /* clear on entry */ timeout = Curl_timeleft(data, &now, TRUE); if(timeout < 0) { @@ -438,9 +437,13 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, while(!result) { struct timeval *tvp, tv, store; int itimeout; - int timeout_ms; + timediff_t timeout_ms; - itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout; +#if TIMEDIFF_T_MAX > INT_MAX + itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout; +#else + itimeout = (int)timeout; +#endif store.tv_sec = itimeout/1000; store.tv_usec = (itimeout%1000)*1000; @@ -451,12 +454,12 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, second is left, otherwise just use 1000ms to make sure the progress callback gets called frequent enough */ if(!tvp->tv_sec) - timeout_ms = (int)(tvp->tv_usec/1000); + timeout_ms = (timediff_t)(tvp->tv_usec/1000); else timeout_ms = 1000; waitperform(conn, timeout_ms); - result = Curl_resolver_is_resolved(conn, entry?&temp_entry:NULL); + result = Curl_resolver_is_resolved(conn, entry); if(result || conn->async.done) break; @@ -471,7 +474,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, else if(timediff > timeout) timeout = -1; else - timeout -= (long)timediff; + timeout -= timediff; now = now2; /* for next loop */ } if(timeout < 0) @@ -496,9 +499,9 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, /* Connects results to the list */ static void compound_results(struct ResolverResults *res, - Curl_addrinfo *ai) + struct Curl_addrinfo *ai) { - Curl_addrinfo *ai_tail; + struct Curl_addrinfo *ai_tail; if(!ai) return; ai_tail = ai; @@ -540,7 +543,7 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */ res->num_pending--; if(CURL_ASYNC_SUCCESS == status) { - Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port); + struct Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port); if(ai) { compound_results(res, ai); } @@ -619,10 +622,10 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */ * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. */ -Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { char *bufp; struct Curl_easy *data = conn->data; diff --git a/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c index 68dcbb3..a60f4f0 100644 --- a/Utilities/cmcurl/lib/asyn-thread.c +++ b/Utilities/cmcurl/lib/asyn-thread.c @@ -158,7 +158,7 @@ static bool init_resolve_thread(struct connectdata *conn, /* Data for synchronization between resolver thread and its parent */ struct thread_sync_data { - curl_mutex_t * mtx; + curl_mutex_t *mtx; int done; char *hostname; /* hostname to resolve, Curl_async.hostname @@ -169,7 +169,7 @@ struct thread_sync_data { curl_socket_t sock_pair[2]; /* socket pair */ #endif int sock_error; - Curl_addrinfo *res; + struct Curl_addrinfo *res; #ifdef HAVE_GETADDRINFO struct addrinfo hints; #endif @@ -179,7 +179,7 @@ struct thread_sync_data { struct thread_data { curl_thread_t thread_hnd; unsigned int poll_interval; - time_t interval_end; + timediff_t interval_end; struct thread_sync_data tsd; }; @@ -190,7 +190,7 @@ static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn) /* Destroy resolver thread synchronization data */ static -void destroy_thread_sync_data(struct thread_sync_data * tsd) +void destroy_thread_sync_data(struct thread_sync_data *tsd) { if(tsd->mtx) { Curl_mutex_destroy(tsd->mtx); @@ -216,7 +216,7 @@ void destroy_thread_sync_data(struct thread_sync_data * tsd) /* Initialize resolver thread synchronization data */ static -int init_thread_sync_data(struct thread_data * td, +int init_thread_sync_data(struct thread_data *td, const char *hostname, int port, const struct addrinfo *hints) @@ -494,11 +494,14 @@ static CURLcode resolver_error(struct connectdata *conn) const char *host_or_proxy; CURLcode result; +#ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy) { host_or_proxy = "proxy"; result = CURLE_COULDNT_RESOLVE_PROXY; } - else { + else +#endif + { host_or_proxy = "host"; result = CURLE_COULDNT_RESOLVE_HOST; } @@ -509,6 +512,9 @@ static CURLcode resolver_error(struct connectdata *conn) return result; } +/* + * 'entry' may be NULL and then no data is returned + */ static CURLcode thread_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **entry, bool report) @@ -593,6 +599,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct thread_data *td = (struct thread_data*) conn->async.os_specific; int done = 0; + DEBUGASSERT(entry); *entry = NULL; if(!td) { @@ -618,8 +625,8 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, else { /* poll for name lookup done with exponential backoff up to 250ms */ /* should be fine even if this converts to 32 bit */ - time_t elapsed = (time_t)Curl_timediff(Curl_now(), - data->progress.t_startsingle); + timediff_t elapsed = Curl_timediff(Curl_now(), + data->progress.t_startsingle); if(elapsed < 0) elapsed = 0; @@ -644,7 +651,7 @@ int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *socks) { int ret_val = 0; - time_t milli; + timediff_t milli; timediff_t ms; struct Curl_easy *data = conn->data; struct resdata *reslv = (struct resdata *)data->state.resolver; @@ -668,7 +675,7 @@ int Curl_resolver_getsock(struct connectdata *conn, if(ms < 3) milli = 0; else if(ms <= 50) - milli = (time_t)ms/3; + milli = ms/3; else if(ms <= 250) milli = 50; else @@ -686,10 +693,10 @@ int Curl_resolver_getsock(struct connectdata *conn, /* * Curl_getaddrinfo() - for platforms without getaddrinfo */ -Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { struct Curl_easy *data = conn->data; struct resdata *reslv = (struct resdata *)data->state.resolver; @@ -714,10 +721,10 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, /* * Curl_resolver_getaddrinfo() - for getaddrinfo */ -Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { struct addrinfo hints; int pf = PF_INET; diff --git a/Utilities/cmcurl/lib/asyn.h b/Utilities/cmcurl/lib/asyn.h index 081c3fe..be2796c 100644 --- a/Utilities/cmcurl/lib/asyn.h +++ b/Utilities/cmcurl/lib/asyn.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -153,10 +153,10 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, * Each resolver backend must of course make sure to return data in the * correct format to comply with this. */ -Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp); +struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp); #ifndef CURLRES_ASYNCH /* convert these functions if an asynch resolver isn't used */ diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c index cbd3bb1..d21a00c 100644 --- a/Utilities/cmcurl/lib/conncache.c +++ b/Utilities/cmcurl/lib/conncache.c @@ -49,53 +49,51 @@ static void conn_llist_dtor(void *user, void *element) conn->bundle = NULL; } -static CURLcode bundle_create(struct Curl_easy *data, - struct connectbundle **cb_ptr) +static CURLcode bundle_create(struct connectbundle **bundlep) { - (void)data; - DEBUGASSERT(*cb_ptr == NULL); - *cb_ptr = malloc(sizeof(struct connectbundle)); - if(!*cb_ptr) + DEBUGASSERT(*bundlep == NULL); + *bundlep = malloc(sizeof(struct connectbundle)); + if(!*bundlep) return CURLE_OUT_OF_MEMORY; - (*cb_ptr)->num_connections = 0; - (*cb_ptr)->multiuse = BUNDLE_UNKNOWN; + (*bundlep)->num_connections = 0; + (*bundlep)->multiuse = BUNDLE_UNKNOWN; - Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor); + Curl_llist_init(&(*bundlep)->conn_list, (curl_llist_dtor) conn_llist_dtor); return CURLE_OK; } -static void bundle_destroy(struct connectbundle *cb_ptr) +static void bundle_destroy(struct connectbundle *bundle) { - if(!cb_ptr) + if(!bundle) return; - Curl_llist_destroy(&cb_ptr->conn_list, NULL); + Curl_llist_destroy(&bundle->conn_list, NULL); - free(cb_ptr); + free(bundle); } /* Add a connection to a bundle */ -static void bundle_add_conn(struct connectbundle *cb_ptr, +static void bundle_add_conn(struct connectbundle *bundle, struct connectdata *conn) { - Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn, + Curl_llist_insert_next(&bundle->conn_list, bundle->conn_list.tail, conn, &conn->bundle_node); - conn->bundle = cb_ptr; - cb_ptr->num_connections++; + conn->bundle = bundle; + bundle->num_connections++; } /* Remove a connection from a bundle */ -static int bundle_remove_conn(struct connectbundle *cb_ptr, +static int bundle_remove_conn(struct connectbundle *bundle, struct connectdata *conn) { struct curl_llist_element *curr; - curr = cb_ptr->conn_list.head; + curr = bundle->conn_list.head; while(curr) { if(curr->ptr == conn) { - Curl_llist_remove(&cb_ptr->conn_list, curr, NULL); - cb_ptr->num_connections--; + Curl_llist_remove(&bundle->conn_list, curr, NULL); + bundle->num_connections--; conn->bundle = NULL; return 1; /* we removed a handle */ } @@ -145,12 +143,15 @@ static void hashkey(struct connectdata *conn, char *buf, const char *hostname; long port = conn->remote_port; +#ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { hostname = conn->http_proxy.host.name; port = conn->port; } - else if(conn->bits.conn_to_host) - hostname = conn->conn_to_host.name; + else +#endif + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; else hostname = conn->host.name; @@ -162,20 +163,15 @@ static void hashkey(struct connectdata *conn, char *buf, msnprintf(buf, len, "%ld%s", port, hostname); } -void Curl_conncache_unlock(struct Curl_easy *data) -{ - CONN_UNLOCK(data); -} - /* Returns number of connections currently held in the connection cache. Locks/unlocks the cache itself! */ size_t Curl_conncache_size(struct Curl_easy *data) { size_t num; - CONN_LOCK(data); + CONNCACHE_LOCK(data); num = data->state.conn_cache->num_conn; - CONN_UNLOCK(data); + CONNCACHE_UNLOCK(data); return num; } @@ -188,7 +184,7 @@ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, const char **hostp) { struct connectbundle *bundle = NULL; - CONN_LOCK(conn->data); + CONNCACHE_LOCK(conn->data); if(connc) { char key[HASHKEY_SIZE]; hashkey(conn, key, sizeof(key), hostp); @@ -235,8 +231,7 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc, struct connectdata *conn) { CURLcode result = CURLE_OK; - struct connectbundle *bundle; - struct connectbundle *new_bundle = NULL; + struct connectbundle *bundle = NULL; struct Curl_easy *data = conn->data; /* *find_bundle() locks the connection cache */ @@ -245,20 +240,19 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc, int rc; char key[HASHKEY_SIZE]; - result = bundle_create(data, &new_bundle); + result = bundle_create(&bundle); if(result) { goto unlock; } hashkey(conn, key, sizeof(key), NULL); - rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle); + rc = conncache_add_bundle(data->state.conn_cache, key, bundle); if(!rc) { - bundle_destroy(new_bundle); + bundle_destroy(bundle); result = CURLE_OUT_OF_MEMORY; goto unlock; } - bundle = new_bundle; } bundle_add_conn(bundle, conn); @@ -270,15 +264,17 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc, conn->connection_id, connc->num_conn)); unlock: - CONN_UNLOCK(data); + CONNCACHE_UNLOCK(data); return result; } /* - * Removes the connectdata object from the connection cache *and* clears the - * ->data pointer association. Pass TRUE/FALSE in the 'lock' argument - * depending on if the parent function already holds the lock or not. + * Removes the connectdata object from the connection cache, but does *not* + * clear the conn->data association. The transfer still owns this connection. + * + * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function + * already holds the lock or not. */ void Curl_conncache_remove_conn(struct Curl_easy *data, struct connectdata *conn, bool lock) @@ -290,7 +286,7 @@ void Curl_conncache_remove_conn(struct Curl_easy *data, due to a failed connection attempt, before being added to a bundle */ if(bundle) { if(lock) { - CONN_LOCK(data); + CONNCACHE_LOCK(data); } bundle_remove_conn(bundle, conn); if(bundle->num_connections == 0) @@ -301,9 +297,8 @@ void Curl_conncache_remove_conn(struct Curl_easy *data, DEBUGF(infof(data, "The cache now contains %zu members\n", connc->num_conn)); } - conn->data = NULL; /* clear the association */ if(lock) { - CONN_UNLOCK(data); + CONNCACHE_UNLOCK(data); } } } @@ -332,7 +327,7 @@ bool Curl_conncache_foreach(struct Curl_easy *data, if(!connc) return FALSE; - CONN_LOCK(data); + CONNCACHE_LOCK(data); Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); @@ -350,12 +345,12 @@ bool Curl_conncache_foreach(struct Curl_easy *data, curr = curr->next; if(1 == func(conn, param)) { - CONN_UNLOCK(data); + CONNCACHE_UNLOCK(data); return TRUE; } } } - CONN_UNLOCK(data); + CONNCACHE_UNLOCK(data); return FALSE; } @@ -494,7 +489,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) now = Curl_now(); - CONN_LOCK(data); + CONNCACHE_LOCK(data); Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); @@ -531,7 +526,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) connc->num_conn)); conn_candidate->data = data; /* associate! */ } - CONN_UNLOCK(data); + CONNCACHE_UNLOCK(data); return conn_candidate; } @@ -539,6 +534,11 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) void Curl_conncache_close_all_connections(struct conncache *connc) { struct connectdata *conn; + char buffer[READBUFFER_MIN + 1]; + if(!connc->closure_handle) + return; + connc->closure_handle->state.buffer = buffer; + connc->closure_handle->set.buffer_size = READBUFFER_MIN; conn = conncache_find_first_connection(connc); while(conn) { @@ -548,12 +548,14 @@ void Curl_conncache_close_all_connections(struct conncache *connc) sigpipe_ignore(conn->data, &pipe_st); /* This will remove the connection from the cache */ connclose(conn, "kill all"); + Curl_conncache_remove_conn(conn->data, conn, TRUE); (void)Curl_disconnect(connc->closure_handle, conn, FALSE); sigpipe_restore(&pipe_st); conn = conncache_find_first_connection(connc); } + connc->closure_handle->state.buffer = NULL; if(connc->closure_handle) { SIGPIPE_VARIABLE(pipe_st); sigpipe_ignore(connc->closure_handle, &pipe_st); diff --git a/Utilities/cmcurl/lib/conncache.h b/Utilities/cmcurl/lib/conncache.h index e3e4c9c..3dda21c 100644 --- a/Utilities/cmcurl/lib/conncache.h +++ b/Utilities/cmcurl/lib/conncache.h @@ -45,21 +45,21 @@ struct conncache { #ifdef CURLDEBUG /* the debug versions of these macros make extra certain that the lock is never doubly locked or unlocked */ -#define CONN_LOCK(x) if((x)->share) { \ +#define CONNCACHE_LOCK(x) if((x)->share) { \ Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \ DEBUGASSERT(!(x)->state.conncache_lock); \ (x)->state.conncache_lock = TRUE; \ } -#define CONN_UNLOCK(x) if((x)->share) { \ +#define CONNCACHE_UNLOCK(x) if((x)->share) { \ DEBUGASSERT((x)->state.conncache_lock); \ (x)->state.conncache_lock = FALSE; \ Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \ } #else -#define CONN_LOCK(x) if((x)->share) \ +#define CONNCACHE_LOCK(x) if((x)->share) \ Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE) -#define CONN_UNLOCK(x) if((x)->share) \ +#define CONNCACHE_UNLOCK(x) if((x)->share) \ Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT) #endif @@ -77,7 +77,6 @@ void Curl_conncache_destroy(struct conncache *connc); struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, struct conncache *connc, const char **hostp); -void Curl_conncache_unlock(struct Curl_easy *data); /* returns number of connections currently held in the connection cache */ size_t Curl_conncache_size(struct Curl_easy *data); diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c index 0a7475c..29293f0 100644 --- a/Utilities/cmcurl/lib/connect.c +++ b/Utilities/cmcurl/lib/connect.c @@ -166,12 +166,13 @@ tcpkeepalive(struct Curl_easy *data, static CURLcode singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, /* start connecting to this */ - int sockindex); /* 0 or 1 among the temp ones */ + const struct Curl_addrinfo *ai, /* start connecting to this */ + int tempindex); /* 0 or 1 among the temp ones */ /* * Curl_timeleft() returns the amount of milliseconds left allowed for the - * transfer/connection. If the value is negative, the timeout time has already + * transfer/connection. If the value is 0, there's no timeout (ie there's + * infinite time left). If the value is negative, the timeout time has already * elapsed. * * The start time is stored in progress.t_startsingle - as set with @@ -555,13 +556,27 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) return rc; } -/* Used within the multi interface. Try next IP address, return TRUE if no +/* update tempaddr[tempindex] (to the next entry), makes sure to stick + to the correct family */ +static struct Curl_addrinfo *ainext(struct connectdata *conn, + int tempindex, + bool next) /* use next entry? */ +{ + struct Curl_addrinfo *ai = conn->tempaddr[tempindex]; + if(ai && next) + ai = ai->ai_next; + while(ai && (ai->ai_family != conn->tempfamily[tempindex])) + ai = ai->ai_next; + conn->tempaddr[tempindex] = ai; + return ai; +} + +/* Used within the multi interface. Try next IP address, returns error if no more address exists or error */ static CURLcode trynextip(struct connectdata *conn, int sockindex, int tempindex) { - const int other = tempindex ^ 1; CURLcode result = CURLE_COULDNT_CONNECT; /* First clean up after the failed socket. @@ -572,38 +587,15 @@ static CURLcode trynextip(struct connectdata *conn, conn->tempsock[tempindex] = CURL_SOCKET_BAD; if(sockindex == FIRSTSOCKET) { - Curl_addrinfo *ai = NULL; - int family = AF_UNSPEC; - - if(conn->tempaddr[tempindex]) { - /* find next address in the same protocol family */ - family = conn->tempaddr[tempindex]->ai_family; - ai = conn->tempaddr[tempindex]->ai_next; - } -#ifdef ENABLE_IPV6 - else if(conn->tempaddr[0]) { - /* happy eyeballs - try the other protocol family */ - int firstfamily = conn->tempaddr[0]->ai_family; - family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; - ai = conn->tempaddr[0]->ai_next; - } -#endif + struct Curl_addrinfo *ai = conn->tempaddr[tempindex]; while(ai) { - if(conn->tempaddr[other]) { - /* we can safely skip addresses of the other protocol family */ - while(ai && ai->ai_family != family) - ai = ai->ai_next; - } - if(ai) { result = singleipconnect(conn, ai, tempindex); if(result == CURLE_COULDNT_CONNECT) { - ai = ai->ai_next; + ai = ainext(conn, tempindex, TRUE); continue; } - - conn->tempaddr[tempindex] = ai; } break; } @@ -688,58 +680,56 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, connection */ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) { - if(conn->transport != TRNSPRT_TCP) - /* there's no TCP connection! */ - return; - + if(conn->transport == TRNSPRT_TCP) { #if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME) - if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { - struct Curl_easy *data = conn->data; - char buffer[STRERROR_LEN]; - struct Curl_sockaddr_storage ssrem; - struct Curl_sockaddr_storage ssloc; - curl_socklen_t plen; - curl_socklen_t slen; + if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { + struct Curl_easy *data = conn->data; + char buffer[STRERROR_LEN]; + struct Curl_sockaddr_storage ssrem; + struct Curl_sockaddr_storage ssloc; + curl_socklen_t plen; + curl_socklen_t slen; #ifdef HAVE_GETPEERNAME - plen = sizeof(struct Curl_sockaddr_storage); - if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) { - int error = SOCKERRNO; - failf(data, "getpeername() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return; - } + plen = sizeof(struct Curl_sockaddr_storage); + if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) { + int error = SOCKERRNO; + failf(data, "getpeername() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } #endif #ifdef HAVE_GETSOCKNAME - slen = sizeof(struct Curl_sockaddr_storage); - memset(&ssloc, 0, sizeof(ssloc)); - if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) { - int error = SOCKERRNO; - failf(data, "getsockname() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return; - } + slen = sizeof(struct Curl_sockaddr_storage); + memset(&ssloc, 0, sizeof(ssloc)); + if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) { + int error = SOCKERRNO; + failf(data, "getsockname() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } #endif #ifdef HAVE_GETPEERNAME - if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, - conn->primary_ip, &conn->primary_port)) { - failf(data, "ssrem inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return; - } - memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); + if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, + conn->primary_ip, &conn->primary_port)) { + failf(data, "ssrem inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } + memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); #endif #ifdef HAVE_GETSOCKNAME - if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, - conn->local_ip, &conn->local_port)) { - failf(data, "ssloc inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return; - } + if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, + conn->local_ip, &conn->local_port)) { + failf(data, "ssloc inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } #endif - } + } #else /* !HAVE_GETSOCKNAME && !HAVE_GETPEERNAME */ - (void)sockfd; /* unused */ + (void)sockfd; /* unused */ #endif + } /* end of TCP-only section */ /* persist connection info in session handle */ Curl_persistconninfo(conn); @@ -757,8 +747,8 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex, { CURLcode result = CURLE_OK; - if(conn->bits.socksproxy) { #ifndef CURL_DISABLE_PROXY + if(conn->bits.socksproxy) { /* for the secondary socket (FTP), use the "connect to host" * but ignore the "connect to port" (use the secondary port) */ @@ -791,11 +781,12 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex, failf(conn->data, "unknown proxytype option given"); result = CURLE_COULDNT_CONNECT; } /* switch proxytype */ -#else - (void)sockindex; -#endif /* CURL_DISABLE_PROXY */ } else +#else + (void)conn; + (void)sockindex; +#endif /* CURL_DISABLE_PROXY */ *done = TRUE; /* no SOCKS proxy, so consider us connected */ return result; @@ -816,6 +807,7 @@ static void post_SOCKS(struct connectdata *conn, Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */ Curl_updateconninfo(conn, conn->sock[sockindex]); Curl_verboseconnect(conn); + conn->data->info.numconnects++; /* to track the number of connections made */ } /* @@ -831,8 +823,8 @@ CURLcode Curl_is_connected(struct connectdata *conn, timediff_t allow; int error = 0; struct curltime now; - int rc; - int i; + int rc = 0; + unsigned int i; DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); @@ -867,47 +859,50 @@ CURLcode Curl_is_connected(struct connectdata *conn, const int other = i ^ 1; if(conn->tempsock[i] == CURL_SOCKET_BAD) continue; - + error = 0; #ifdef ENABLE_QUIC if(conn->transport == TRNSPRT_QUIC) { result = Curl_quic_is_connected(conn, i, connected); - if(result) { - error = SOCKERRNO; - goto error; - } - if(*connected) { + if(!result && *connected) { /* use this socket from now on */ conn->sock[sockindex] = conn->tempsock[i]; conn->ip_addr = conn->tempaddr[i]; conn->tempsock[i] = CURL_SOCKET_BAD; + post_SOCKS(conn, sockindex, connected); connkeep(conn, "HTTP/3 default"); + return CURLE_OK; } - return result; + if(result) + error = SOCKERRNO; } + else #endif - + { #ifdef mpeix - /* Call this function once now, and ignore the results. We do this to - "clear" the error state on the socket so that we can later read it - reliably. This is reported necessary on the MPE/iX operating system. */ - (void)verifyconnect(conn->tempsock[i], NULL); + /* Call this function once now, and ignore the results. We do this to + "clear" the error state on the socket so that we can later read it + reliably. This is reported necessary on the MPE/iX operating + system. */ + (void)verifyconnect(conn->tempsock[i], NULL); #endif - /* check socket for connect */ - rc = SOCKET_WRITABLE(conn->tempsock[i], 0); + /* check socket for connect */ + rc = SOCKET_WRITABLE(conn->tempsock[i], 0); + } if(rc == 0) { /* no connection yet */ - error = 0; - if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) { + if(Curl_timediff(now, conn->connecttime) >= + conn->timeoutms_per_addr[i]) { infof(data, "After %" CURL_FORMAT_TIMEDIFF_T - "ms connect time, move on!\n", conn->timeoutms_per_addr); + "ms connect time, move on!\n", conn->timeoutms_per_addr[i]); error = ETIMEDOUT; } /* should we try another protocol family? */ - if(i == 0 && conn->tempaddr[1] == NULL && + if(i == 0 && !conn->bits.parallel_connect && (Curl_timediff(now, conn->connecttime) >= data->set.happy_eyeballs_timeout)) { + conn->bits.parallel_connect = TRUE; /* starting now */ trynextip(conn, sockindex, 1); } } @@ -944,9 +939,6 @@ CURLcode Curl_is_connected(struct connectdata *conn, else if(rc & CURL_CSELECT_ERR) (void)verifyconnect(conn->tempsock[i], &error); -#ifdef ENABLE_QUIC - error: -#endif /* * The connection failed here, we should attempt to connect to the "next * address" for the given host. But first remember the latest error. @@ -959,15 +951,16 @@ CURLcode Curl_is_connected(struct connectdata *conn, #ifndef CURL_DISABLE_VERBOSE_STRINGS char ipaddress[MAX_IPADR_LEN]; char buffer[STRERROR_LEN]; - Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN); -#endif + Curl_printable_address(conn->tempaddr[i], ipaddress, + sizeof(ipaddress)); infof(data, "connect to %s port %ld failed: %s\n", ipaddress, conn->port, Curl_strerror(error, buffer, sizeof(buffer))); +#endif - conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? + conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ? allow : allow / 2; - + ainext(conn, i, TRUE); status = trynextip(conn, sockindex, i); if((status != CURLE_COULDNT_CONNECT) || conn->tempsock[other] == CURL_SOCKET_BAD) @@ -977,25 +970,28 @@ CURLcode Curl_is_connected(struct connectdata *conn, } } - if(result) { + if(result && + (conn->tempsock[0] == CURL_SOCKET_BAD) && + (conn->tempsock[1] == CURL_SOCKET_BAD)) { /* no more addresses to try */ const char *hostname; char buffer[STRERROR_LEN]; - /* if the first address family runs out of addresses to try before - the happy eyeball timeout, go ahead and try the next family now */ - if(conn->tempaddr[1] == NULL) { - result = trynextip(conn, sockindex, 1); - if(!result) - return result; - } + /* if the first address family runs out of addresses to try before the + happy eyeball timeout, go ahead and try the next family now */ + result = trynextip(conn, sockindex, 1); + if(!result) + return result; +#ifndef CURL_DISABLE_PROXY if(conn->bits.socksproxy) hostname = conn->socks_proxy.host.name; else if(conn->bits.httpproxy) hostname = conn->http_proxy.host.name; - else if(conn->bits.conn_to_host) - hostname = conn->conn_to_host.name; + else +#endif + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; else hostname = conn->host.name; @@ -1003,6 +999,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, hostname, conn->port, Curl_strerror(error, buffer, sizeof(buffer))); + Curl_quic_disconnect(conn, 0); + Curl_quic_disconnect(conn, 1); + #ifdef WSAETIMEDOUT if(WSAETIMEDOUT == data->state.os_errno) result = CURLE_OPERATION_TIMEDOUT; @@ -1011,6 +1010,8 @@ CURLcode Curl_is_connected(struct connectdata *conn, result = CURLE_OPERATION_TIMEDOUT; #endif } + else + result = CURLE_OK; /* still trying */ return result; } @@ -1112,8 +1113,8 @@ void Curl_sndbufset(curl_socket_t sockfd) * having connected. */ static CURLcode singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, - int sockindex) + const struct Curl_addrinfo *ai, + int tempindex) { struct Curl_sockaddr_ex addr; int rc = -1; @@ -1129,15 +1130,12 @@ static CURLcode singleipconnect(struct connectdata *conn, int optval = 1; #endif char buffer[STRERROR_LEN]; - curl_socket_t *sockp = &conn->tempsock[sockindex]; + curl_socket_t *sockp = &conn->tempsock[tempindex]; *sockp = CURL_SOCKET_BAD; result = Curl_socket(conn, ai, &addr, &sockfd); if(result) - /* Failed to create the socket, but still return OK since we signal the - lack of socket as well. This allows the parent function to keep looping - over alternative addresses/socket families etc. */ - return CURLE_OK; + return result; /* store remote address and port used in this connection attempt */ if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen, @@ -1205,8 +1203,10 @@ static CURLcode singleipconnect(struct connectdata *conn, (void)curlx_nonblock(sockfd, TRUE); conn->connecttime = Curl_now(); - if(conn->num_addr > 1) - Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME); + if(conn->num_addr > 1) { + Curl_expire(data, conn->timeoutms_per_addr[0], EXPIRE_DNS_PER_NAME); + Curl_expire(data, conn->timeoutms_per_addr[1], EXPIRE_DNS_PER_NAME2); + } /* Connect TCP and QUIC sockets */ if(!isconnected && (conn->transport != TRNSPRT_UDP)) { @@ -1257,7 +1257,7 @@ static CURLcode singleipconnect(struct connectdata *conn, else if(conn->transport == TRNSPRT_QUIC) { /* pass in 'sockfd' separately since it hasn't been put into the tempsock array at this point */ - result = Curl_quic_connect(conn, sockfd, sockindex, + result = Curl_quic_connect(conn, sockfd, tempindex, &addr.sa_addr, addr.addrlen); if(result) error = SOCKERRNO; @@ -1315,7 +1315,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ struct Curl_easy *data = conn->data; struct curltime before = Curl_now(); CURLcode result = CURLE_COULDNT_CONNECT; - + int i; timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE); if(timeout_ms < 0) { @@ -1325,30 +1325,37 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ } conn->num_addr = Curl_num_addresses(remotehost->addr); - conn->tempaddr[0] = remotehost->addr; - conn->tempaddr[1] = NULL; - conn->tempsock[0] = CURL_SOCKET_BAD; - conn->tempsock[1] = CURL_SOCKET_BAD; + conn->tempaddr[0] = conn->tempaddr[1] = remotehost->addr; + conn->tempsock[0] = conn->tempsock[1] = CURL_SOCKET_BAD; /* Max time for the next connection attempt */ - conn->timeoutms_per_addr = + conn->timeoutms_per_addr[0] = conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2; - - /* start connecting to first IP */ - while(conn->tempaddr[0]) { - result = singleipconnect(conn, conn->tempaddr[0], 0); - if(!result) - break; - conn->tempaddr[0] = conn->tempaddr[0]->ai_next; + conn->timeoutms_per_addr[1] = + conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2; + + conn->tempfamily[0] = conn->tempaddr[0]? + conn->tempaddr[0]->ai_family:0; + conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ? + AF_INET : AF_INET6; + ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */ + + DEBUGF(infof(data, "family0 == %s, family1 == %s\n", + conn->tempfamily[0] == AF_INET ? "v4" : "v6", + conn->tempfamily[1] == AF_INET ? "v4" : "v6")); + + /* get through the list in family order in case of quick failures */ + for(i = 0; (i < 2) && result; i++) { + while(conn->tempaddr[i]) { + result = singleipconnect(conn, conn->tempaddr[i], i); + if(!result) + break; + ainext(conn, i, TRUE); + } } - - if(conn->tempsock[0] == CURL_SOCKET_BAD) { - if(!result) - result = CURLE_COULDNT_CONNECT; + if(result) return result; - } - data->info.numconnects++; /* to track the number of connections made */ Curl_expire(conn->data, data->set.happy_eyeballs_timeout, EXPIRE_HAPPY_EYEBALLS); @@ -1448,11 +1455,11 @@ int Curl_closesocket(struct connectdata *conn, curl_socket_t sock) { if(conn && conn->fclosesocket) { - if((sock == conn->sock[SECONDARYSOCKET]) && conn->sock_accepted) + if((sock == conn->sock[SECONDARYSOCKET]) && conn->bits.sock_accepted) /* if this socket matches the second socket, and that was created with accept, then we MUST NOT call the callback but clear the accepted status */ - conn->sock_accepted = FALSE; + conn->bits.sock_accepted = FALSE; else { int rc; Curl_multi_closed(conn->data, sock); @@ -1482,7 +1489,7 @@ int Curl_closesocket(struct connectdata *conn, * */ CURLcode Curl_socket(struct connectdata *conn, - const Curl_addrinfo *ai, + const struct Curl_addrinfo *ai, struct Curl_sockaddr_ex *addr, curl_socket_t *sockfd) { @@ -1564,6 +1571,7 @@ void Curl_conncontrol(struct connectdata *conn, /* close if a connection, or a stream that isn't multiplexed */ bool closeit = (ctrl == CONNCTRL_CONNECTION) || ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM)); + DEBUGASSERT(conn); if((ctrl == CONNCTRL_STREAM) && (conn->handler->flags & PROTOPT_STREAM)) DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); @@ -1579,6 +1587,7 @@ void Curl_conncontrol(struct connectdata *conn, bool Curl_conn_data_pending(struct connectdata *conn, int sockindex) { int readable; + DEBUGASSERT(conn); if(Curl_ssl_data_pending(conn, sockindex) || Curl_recv_has_postponed_data(conn, sockindex)) diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h index b23085a..6fd9ea8 100644 --- a/Utilities/cmcurl/lib/connect.h +++ b/Utilities/cmcurl/lib/connect.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -105,7 +105,7 @@ struct Curl_sockaddr_ex { * */ CURLcode Curl_socket(struct connectdata *conn, - const Curl_addrinfo *ai, + const struct Curl_addrinfo *ai, struct Curl_sockaddr_ex *addr, curl_socket_t *sockfd); diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c index 6d47537..e2e68a1 100644 --- a/Utilities/cmcurl/lib/content_encoding.c +++ b/Utilities/cmcurl/lib/content_encoding.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -81,11 +81,11 @@ typedef enum { } zlibInitState; /* Writer parameters. */ -typedef struct { +struct zlib_params { zlibInitState zlib_init; /* zlib init state */ uInt trailerlen; /* Remaining trailer byte count. */ z_stream z; /* State structure for zlib. */ -} zlib_params; +}; static voidpf @@ -133,7 +133,8 @@ exit_zlib(struct connectdata *conn, return result; } -static CURLcode process_trailer(struct connectdata *conn, zlib_params *zp) +static CURLcode process_trailer(struct connectdata *conn, + struct zlib_params *zp) { z_stream *z = &zp->z; CURLcode result = CURLE_OK; @@ -157,9 +158,10 @@ static CURLcode process_trailer(struct connectdata *conn, zlib_params *zp) } static CURLcode inflate_stream(struct connectdata *conn, - contenc_writer *writer, zlibInitState started) + struct contenc_writer *writer, + zlibInitState started) { - zlib_params *zp = (zlib_params *) &writer->params; + struct zlib_params *zp = (struct zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ uInt nread = z->avail_in; Bytef *orig_in = z->next_in; @@ -259,9 +261,9 @@ static CURLcode inflate_stream(struct connectdata *conn, /* Deflate handler. */ static CURLcode deflate_init_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { - zlib_params *zp = (zlib_params *) &writer->params; + struct zlib_params *zp = (struct zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ if(!writer->downstream) @@ -278,10 +280,10 @@ static CURLcode deflate_init_writer(struct connectdata *conn, } static CURLcode deflate_unencode_write(struct connectdata *conn, - contenc_writer *writer, + struct contenc_writer *writer, const char *buf, size_t nbytes) { - zlib_params *zp = (zlib_params *) &writer->params; + struct zlib_params *zp = (struct zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ /* Set the compressed input when this function is called */ @@ -296,29 +298,29 @@ static CURLcode deflate_unencode_write(struct connectdata *conn, } static void deflate_close_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { - zlib_params *zp = (zlib_params *) &writer->params; + struct zlib_params *zp = (struct zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ exit_zlib(conn, z, &zp->zlib_init, CURLE_OK); } -static const content_encoding deflate_encoding = { +static const struct content_encoding deflate_encoding = { "deflate", NULL, deflate_init_writer, deflate_unencode_write, deflate_close_writer, - sizeof(zlib_params) + sizeof(struct zlib_params) }; /* Gzip handler. */ static CURLcode gzip_init_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { - zlib_params *zp = (zlib_params *) &writer->params; + struct zlib_params *zp = (struct zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ if(!writer->downstream) @@ -432,10 +434,10 @@ static enum { #endif static CURLcode gzip_unencode_write(struct connectdata *conn, - contenc_writer *writer, + struct contenc_writer *writer, const char *buf, size_t nbytes) { - zlib_params *zp = (zlib_params *) &writer->params; + struct zlib_params *zp = (struct zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ if(zp->zlib_init == ZLIB_INIT_GZIP) { @@ -560,33 +562,31 @@ static CURLcode gzip_unencode_write(struct connectdata *conn, } static void gzip_close_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { - zlib_params *zp = (zlib_params *) &writer->params; + struct zlib_params *zp = (struct zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ exit_zlib(conn, z, &zp->zlib_init, CURLE_OK); } -static const content_encoding gzip_encoding = { +static const struct content_encoding gzip_encoding = { "gzip", "x-gzip", gzip_init_writer, gzip_unencode_write, gzip_close_writer, - sizeof(zlib_params) + sizeof(struct zlib_params) }; #endif /* HAVE_LIBZ */ #ifdef HAVE_BROTLI - /* Writer parameters. */ -typedef struct { +struct brotli_params { BrotliDecoderState *br; /* State structure for brotli. */ -} brotli_params; - +}; static CURLcode brotli_map_error(BrotliDecoderErrorCode be) { @@ -627,10 +627,9 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be) } static CURLcode brotli_init_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { - brotli_params *bp = (brotli_params *) &writer->params; - + struct brotli_params *bp = (struct brotli_params *) &writer->params; (void) conn; if(!writer->downstream) @@ -641,10 +640,10 @@ static CURLcode brotli_init_writer(struct connectdata *conn, } static CURLcode brotli_unencode_write(struct connectdata *conn, - contenc_writer *writer, + struct contenc_writer *writer, const char *buf, size_t nbytes) { - brotli_params *bp = (brotli_params *) &writer->params; + struct brotli_params *bp = (struct brotli_params *) &writer->params; const uint8_t *src = (const uint8_t *) buf; char *decomp; uint8_t *dst; @@ -689,10 +688,9 @@ static CURLcode brotli_unencode_write(struct connectdata *conn, } static void brotli_close_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { - brotli_params *bp = (brotli_params *) &writer->params; - + struct brotli_params *bp = (struct brotli_params *) &writer->params; (void) conn; if(bp->br) { @@ -701,40 +699,40 @@ static void brotli_close_writer(struct connectdata *conn, } } -static const content_encoding brotli_encoding = { +static const struct content_encoding brotli_encoding = { "br", NULL, brotli_init_writer, brotli_unencode_write, brotli_close_writer, - sizeof(brotli_params) + sizeof(struct brotli_params) }; #endif /* Identity handler. */ static CURLcode identity_init_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { (void) conn; return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR; } static CURLcode identity_unencode_write(struct connectdata *conn, - contenc_writer *writer, + struct contenc_writer *writer, const char *buf, size_t nbytes) { return Curl_unencode_write(conn, writer->downstream, buf, nbytes); } static void identity_close_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { (void) conn; (void) writer; } -static const content_encoding identity_encoding = { +static const struct content_encoding identity_encoding = { "identity", "none", identity_init_writer, @@ -745,7 +743,7 @@ static const content_encoding identity_encoding = { /* supported content encodings table. */ -static const content_encoding * const encodings[] = { +static const struct content_encoding * const encodings[] = { &identity_encoding, #ifdef HAVE_LIBZ &deflate_encoding, @@ -762,8 +760,8 @@ static const content_encoding * const encodings[] = { char *Curl_all_content_encodings(void) { size_t len = 0; - const content_encoding * const *cep; - const content_encoding *ce; + const struct content_encoding * const *cep; + const struct content_encoding *ce; char *ace; for(cep = encodings; *cep; cep++) { @@ -796,14 +794,14 @@ char *Curl_all_content_encodings(void) /* Real client writer: no downstream. */ static CURLcode client_init_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { (void) conn; return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK; } static CURLcode client_unencode_write(struct connectdata *conn, - contenc_writer *writer, + struct contenc_writer *writer, const char *buf, size_t nbytes) { struct Curl_easy *data = conn->data; @@ -818,13 +816,13 @@ static CURLcode client_unencode_write(struct connectdata *conn, } static void client_close_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { (void) conn; (void) writer; } -static const content_encoding client_encoding = { +static const struct content_encoding client_encoding = { NULL, NULL, client_init_writer, @@ -836,14 +834,14 @@ static const content_encoding client_encoding = { /* Deferred error dummy writer. */ static CURLcode error_init_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { (void) conn; return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR; } static CURLcode error_unencode_write(struct connectdata *conn, - contenc_writer *writer, + struct contenc_writer *writer, const char *buf, size_t nbytes) { char *all = Curl_all_content_encodings(); @@ -861,13 +859,13 @@ static CURLcode error_unencode_write(struct connectdata *conn, } static void error_close_writer(struct connectdata *conn, - contenc_writer *writer) + struct contenc_writer *writer) { (void) conn; (void) writer; } -static const content_encoding error_encoding = { +static const struct content_encoding error_encoding = { NULL, NULL, error_init_writer, @@ -877,12 +875,13 @@ static const content_encoding error_encoding = { }; /* Create an unencoding writer stage using the given handler. */ -static contenc_writer *new_unencoding_writer(struct connectdata *conn, - const content_encoding *handler, - contenc_writer *downstream) +static struct contenc_writer * +new_unencoding_writer(struct connectdata *conn, + const struct content_encoding *handler, + struct contenc_writer *downstream) { - size_t sz = offsetof(contenc_writer, params) + handler->paramsize; - contenc_writer *writer = (contenc_writer *) calloc(1, sz); + size_t sz = offsetof(struct contenc_writer, params) + handler->paramsize; + struct contenc_writer *writer = (struct contenc_writer *)calloc(1, sz); if(writer) { writer->handler = handler; @@ -897,7 +896,8 @@ static contenc_writer *new_unencoding_writer(struct connectdata *conn, } /* Write data using an unencoding writer stack. */ -CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer, +CURLcode Curl_unencode_write(struct connectdata *conn, + struct contenc_writer *writer, const char *buf, size_t nbytes) { if(!nbytes) @@ -910,7 +910,7 @@ void Curl_unencode_cleanup(struct connectdata *conn) { struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; - contenc_writer *writer = k->writer_stack; + struct contenc_writer *writer = k->writer_stack; while(writer) { k->writer_stack = writer->downstream; @@ -921,12 +921,13 @@ void Curl_unencode_cleanup(struct connectdata *conn) } /* Find the content encoding by name. */ -static const content_encoding *find_encoding(const char *name, size_t len) +static const struct content_encoding *find_encoding(const char *name, + size_t len) { - const content_encoding * const *cep; + const struct content_encoding * const *cep; for(cep = encodings; *cep; cep++) { - const content_encoding *ce = *cep; + const struct content_encoding *ce = *cep; if((strncasecompare(name, ce->name, len) && !ce->name[len]) || (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len])) return ce; @@ -962,8 +963,8 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn, Curl_httpchunk_init(conn); /* init our chunky engine. */ } else if(namelen) { - const content_encoding *encoding = find_encoding(name, namelen); - contenc_writer *writer; + const struct content_encoding *encoding = find_encoding(name, namelen); + struct contenc_writer *writer; if(!k->writer_stack) { k->writer_stack = new_unencoding_writer(conn, &client_encoding, NULL); @@ -997,7 +998,8 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn, return CURLE_NOT_BUILT_IN; } -CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer, +CURLcode Curl_unencode_write(struct connectdata *conn, + struct contenc_writer *writer, const char *buf, size_t nbytes) { (void) conn; diff --git a/Utilities/cmcurl/lib/content_encoding.h b/Utilities/cmcurl/lib/content_encoding.h index 4cd52be..bdd3f1c 100644 --- a/Utilities/cmcurl/lib/content_encoding.h +++ b/Utilities/cmcurl/lib/content_encoding.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,31 +23,31 @@ ***************************************************************************/ #include "curl_setup.h" -/* Decoding writer. */ -typedef struct contenc_writer_s contenc_writer; -typedef struct content_encoding_s content_encoding; - -struct contenc_writer_s { - const content_encoding *handler; /* Encoding handler. */ - contenc_writer *downstream; /* Downstream writer. */ +struct contenc_writer { + const struct content_encoding *handler; /* Encoding handler. */ + struct contenc_writer *downstream; /* Downstream writer. */ void *params; /* Encoding-specific storage (variable length). */ }; /* Content encoding writer. */ -struct content_encoding_s { +struct content_encoding { const char *name; /* Encoding name. */ const char *alias; /* Encoding name alias. */ - CURLcode (*init_writer)(struct connectdata *conn, contenc_writer *writer); - CURLcode (*unencode_write)(struct connectdata *conn, contenc_writer *writer, + CURLcode (*init_writer)(struct connectdata *conn, + struct contenc_writer *writer); + CURLcode (*unencode_write)(struct connectdata *conn, + struct contenc_writer *writer, const char *buf, size_t nbytes); - void (*close_writer)(struct connectdata *conn, contenc_writer *writer); + void (*close_writer)(struct connectdata *conn, + struct contenc_writer *writer); size_t paramsize; }; CURLcode Curl_build_unencoding_stack(struct connectdata *conn, const char *enclist, int maybechunked); -CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer, +CURLcode Curl_unencode_write(struct connectdata *conn, + struct contenc_writer *writer, const char *buf, size_t nbytes); void Curl_unencode_cleanup(struct connectdata *conn); char *Curl_all_content_encodings(void); diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c index 69bc042..68054e1 100644 --- a/Utilities/cmcurl/lib/cookie.c +++ b/Utilities/cmcurl/lib/cookie.c @@ -245,18 +245,17 @@ pathmatched: */ static const char *get_top_domain(const char * const domain, size_t *outlen) { - size_t len; + size_t len = 0; const char *first = NULL, *last; - if(!domain) - return NULL; - - len = strlen(domain); - last = memrchr(domain, '.', len); - if(last) { - first = memrchr(domain, '.', (last - domain)); - if(first) - len -= (++first - domain); + if(domain) { + len = strlen(domain); + last = memrchr(domain, '.', len); + if(last) { + first = memrchr(domain, '.', (last - domain)); + if(first) + len -= (++first - domain); + } } if(outlen) diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c index 16c4779..947d0d3 100644 --- a/Utilities/cmcurl/lib/curl_addrinfo.c +++ b/Utilities/cmcurl/lib/curl_addrinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -50,10 +50,6 @@ # define in_addr_t unsigned long #endif -#if defined(WIN32) && defined(USE_UNIX_SOCKETS) -#include <afunix.h> -#endif - #include <stddef.h> #include "curl_addrinfo.h" @@ -82,16 +78,13 @@ #endif void -Curl_freeaddrinfo(Curl_addrinfo *cahead) +Curl_freeaddrinfo(struct Curl_addrinfo *cahead) { - Curl_addrinfo *vqualifier canext; - Curl_addrinfo *ca; + struct Curl_addrinfo *vqualifier canext; + struct Curl_addrinfo *ca; - for(ca = cahead; ca != NULL; ca = canext) { - free(ca->ai_addr); - free(ca->ai_canonname); + for(ca = cahead; ca; ca = canext) { canext = ca->ai_next; - free(ca); } } @@ -116,13 +109,13 @@ int Curl_getaddrinfo_ex(const char *nodename, const char *servname, const struct addrinfo *hints, - Curl_addrinfo **result) + struct Curl_addrinfo **result) { const struct addrinfo *ai; struct addrinfo *aihead; - Curl_addrinfo *cafirst = NULL; - Curl_addrinfo *calast = NULL; - Curl_addrinfo *ca; + struct Curl_addrinfo *cafirst = NULL; + struct Curl_addrinfo *calast = NULL; + struct Curl_addrinfo *ca; size_t ss_size; int error; @@ -135,7 +128,7 @@ Curl_getaddrinfo_ex(const char *nodename, /* traverse the addrinfo list */ for(ai = aihead; ai != NULL; ai = ai->ai_next) { - + size_t namelen = ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0; /* ignore elements with unsupported address family, */ /* settle family-specific sockaddr structure size. */ if(ai->ai_family == AF_INET) @@ -155,7 +148,7 @@ Curl_getaddrinfo_ex(const char *nodename, if((size_t)ai->ai_addrlen < ss_size) continue; - ca = malloc(sizeof(Curl_addrinfo)); + ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen); if(!ca) { error = EAI_MEMORY; break; @@ -173,22 +166,12 @@ Curl_getaddrinfo_ex(const char *nodename, ca->ai_canonname = NULL; ca->ai_next = NULL; - ca->ai_addr = malloc(ss_size); - if(!ca->ai_addr) { - error = EAI_MEMORY; - free(ca); - break; - } + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); memcpy(ca->ai_addr, ai->ai_addr, ss_size); - if(ai->ai_canonname != NULL) { - ca->ai_canonname = strdup(ai->ai_canonname); - if(!ca->ai_canonname) { - error = EAI_MEMORY; - free(ca->ai_addr); - free(ca); - break; - } + if(namelen) { + ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size); + memcpy(ca->ai_canonname, ai->ai_canonname, namelen); } /* if the return list is empty, this becomes the first element */ @@ -256,7 +239,6 @@ Curl_getaddrinfo_ex(const char *nodename, * struct sockaddr *ai_addr; * struct Curl_addrinfo *ai_next; * }; - * typedef struct Curl_addrinfo Curl_addrinfo; * * hostent defined in <netdb.h> * @@ -273,12 +255,12 @@ Curl_getaddrinfo_ex(const char *nodename, * #define h_addr h_addr_list[0] */ -Curl_addrinfo * +struct Curl_addrinfo * Curl_he2ai(const struct hostent *he, int port) { - Curl_addrinfo *ai; - Curl_addrinfo *prevai = NULL; - Curl_addrinfo *firstai = NULL; + struct Curl_addrinfo *ai; + struct Curl_addrinfo *prevai = NULL; + struct Curl_addrinfo *firstai = NULL; struct sockaddr_in *addr; #ifdef ENABLE_IPV6 struct sockaddr_in6 *addr6; @@ -294,8 +276,8 @@ Curl_he2ai(const struct hostent *he, int port) DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL)); for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { - size_t ss_size; + size_t namelen = strlen(he->h_name) + 1; /* include zero termination */ #ifdef ENABLE_IPV6 if(he->h_addrtype == AF_INET6) ss_size = sizeof(struct sockaddr_in6); @@ -303,24 +285,17 @@ Curl_he2ai(const struct hostent *he, int port) #endif ss_size = sizeof(struct sockaddr_in); - ai = calloc(1, sizeof(Curl_addrinfo)); + /* allocate memory to told the struct, the address and the name */ + ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen); if(!ai) { result = CURLE_OUT_OF_MEMORY; break; } - ai->ai_canonname = strdup(he->h_name); - if(!ai->ai_canonname) { - result = CURLE_OUT_OF_MEMORY; - free(ai); - break; - } - ai->ai_addr = calloc(1, ss_size); - if(!ai->ai_addr) { - result = CURLE_OUT_OF_MEMORY; - free(ai->ai_canonname); - free(ai); - break; - } + /* put the address after the struct */ + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); + /* then put the name after the address */ + ai->ai_canonname = (char *)ai->ai_addr + ss_size; + memcpy(ai->ai_canonname, he->h_name, namelen); if(!firstai) /* store the pointer we want to return from this function */ @@ -393,10 +368,10 @@ struct namebuff { * given address/host */ -Curl_addrinfo * +struct Curl_addrinfo * Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) { - Curl_addrinfo *ai; + struct Curl_addrinfo *ai; #if defined(__VMS) && \ defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) @@ -469,7 +444,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) * Given an IPv4 or IPv6 dotted string address, this converts it to a proper * allocated Curl_addrinfo struct and returns it. */ -Curl_addrinfo *Curl_str2addr(char *address, int port) +struct Curl_addrinfo *Curl_str2addr(char *address, int port) { struct in_addr in; if(Curl_inet_pton(AF_INET, address, &in) > 0) @@ -492,22 +467,19 @@ Curl_addrinfo *Curl_str2addr(char *address, int port) * struct initialized with this path. * Set '*longpath' to TRUE if the error is a too long path. */ -Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract) +struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, + bool abstract) { - Curl_addrinfo *ai; + struct Curl_addrinfo *ai; struct sockaddr_un *sa_un; size_t path_len; *longpath = FALSE; - ai = calloc(1, sizeof(Curl_addrinfo)); + ai = calloc(1, sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_un)); if(!ai) return NULL; - ai->ai_addr = calloc(1, sizeof(struct sockaddr_un)); - if(!ai->ai_addr) { - free(ai); - return NULL; - } + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); sa_un = (void *) ai->ai_addr; sa_un->sun_family = AF_UNIX; @@ -515,7 +487,6 @@ Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract) /* sun_path must be able to store the NUL-terminated path */ path_len = strlen(path) + 1; if(path_len > sizeof(sa_un->sun_path)) { - free(ai->ai_addr); free(ai); *longpath = TRUE; return NULL; @@ -598,9 +569,9 @@ curl_dbg_getaddrinfo(const char *hostname, * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X * 10.11.5. */ -void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port) +void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port) { - Curl_addrinfo *ca; + struct Curl_addrinfo *ca; struct sockaddr_in *addr; #ifdef ENABLE_IPV6 struct sockaddr_in6 *addr6; diff --git a/Utilities/cmcurl/lib/curl_addrinfo.h b/Utilities/cmcurl/lib/curl_addrinfo.h index 205e121..a0cade6 100644 --- a/Utilities/cmcurl/lib/curl_addrinfo.h +++ b/Utilities/cmcurl/lib/curl_addrinfo.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,7 +40,6 @@ # include <stdlib.h> #endif - /* * Curl_addrinfo is our internal struct definition that we use to allow * consistent internal handling of this data. We use this even when the @@ -58,29 +57,29 @@ struct Curl_addrinfo { struct sockaddr *ai_addr; struct Curl_addrinfo *ai_next; }; -typedef struct Curl_addrinfo Curl_addrinfo; void -Curl_freeaddrinfo(Curl_addrinfo *cahead); +Curl_freeaddrinfo(struct Curl_addrinfo *cahead); #ifdef HAVE_GETADDRINFO int Curl_getaddrinfo_ex(const char *nodename, const char *servname, const struct addrinfo *hints, - Curl_addrinfo **result); + struct Curl_addrinfo **result); #endif -Curl_addrinfo * +struct Curl_addrinfo * Curl_he2ai(const struct hostent *he, int port); -Curl_addrinfo * +struct Curl_addrinfo * Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); -Curl_addrinfo *Curl_str2addr(char *dotted, int port); +struct Curl_addrinfo *Curl_str2addr(char *dotted, int port); #ifdef USE_UNIX_SOCKETS -Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract); +struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, + bool abstract); #endif #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ @@ -98,7 +97,7 @@ curl_dbg_getaddrinfo(const char *hostname, const char *service, #ifdef HAVE_GETADDRINFO #ifdef USE_RESOLVE_ON_IPS -void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port); +void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port); #else #define Curl_addrinfo_set_port(x,y) #endif diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake index aa52b6a..00ae658 100644 --- a/Utilities/cmcurl/lib/curl_config.h.cmake +++ b/Utilities/cmcurl/lib/curl_config.h.cmake @@ -1,3 +1,24 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ /* lib/curl_config.h.in. Generated somehow by cmake. */ #include <cm3p/kwiml/abi.h> @@ -35,6 +56,9 @@ /* to disable LDAPS */ #cmakedefine CURL_DISABLE_LDAPS 1 +/* to enable MQTT */ +#undef CURL_ENABLE_MQTT + /* to disable POP3 */ #cmakedefine CURL_DISABLE_POP3 1 @@ -138,9 +162,6 @@ /* Define to 1 if you have the <crypto.h> header file. */ #cmakedefine HAVE_CRYPTO_H 1 -/* Define to 1 if you have the <des.h> header file. */ -#cmakedefine HAVE_DES_H 1 - /* Define to 1 if you have the <dlfcn.h> header file. */ #cmakedefine HAVE_DLFCN_H 1 @@ -400,6 +421,9 @@ /* Define to 1 if you have the <libssh2.h> header file. */ #cmakedefine HAVE_LIBSSH2_H 1 +/* Define to 1 if you have the <libssh/libssh.h> header file. */ +#cmakedefine HAVE_LIBSSH_LIBSSH_H 1 + /* if zlib is available */ #cmakedefine HAVE_LIBZ 1 @@ -948,6 +972,12 @@ ${SIZEOF_TIME_T_CODE} /* if BearSSL is enabled */ #cmakedefine USE_BEARSSL 1 +/* if WolfSSL is enabled */ +#cmakedefine USE_WOLFSSL 1 + +/* if libSSH is in use */ +#cmakedefine USE_LIBSSH 1 + /* if libSSH2 is in use */ #cmakedefine USE_LIBSSH2 1 @@ -969,9 +999,24 @@ ${SIZEOF_TIME_T_CODE} /* to enable NGHTTP2 */ #cmakedefine USE_NGHTTP2 1 +/* to enable NGTCP2 */ +#cmakedefine USE_NGTCP2 1 + +/* to enable NGHTTP3 */ +#cmakedefine USE_NGHTTP3 1 + +/* to enable quiche */ +#cmakedefine USE_QUICHE 1 + +/* Define to 1 if you have the quiche_conn_set_qlog_fd function. */ +#cmakedefine HAVE_QUICHE_CONN_SET_QLOG_FD 1 + /* if Unix domain sockets are enabled */ #cmakedefine USE_UNIX_SOCKETS +/* to enable alt-svc */ +#cmakedefine USE_ALTSVC 1 + /* to enable SSPI support */ #cmakedefine USE_WINDOWS_SSPI 1 diff --git a/Utilities/cmcurl/lib/curl_hmac.h b/Utilities/cmcurl/lib/curl_hmac.h index 3ff799b..9b70c84 100644 --- a/Utilities/cmcurl/lib/curl_hmac.h +++ b/Utilities/cmcurl/lib/curl_hmac.h @@ -34,37 +34,35 @@ typedef void (* HMAC_hfinal_func)(unsigned char *result, void *context); /* Per-hash function HMAC parameters. */ - -typedef struct { - HMAC_hinit_func hmac_hinit; /* Initialize context procedure. */ +struct HMAC_params { + HMAC_hinit_func + hmac_hinit; /* Initialize context procedure. */ HMAC_hupdate_func hmac_hupdate; /* Update context with data. */ HMAC_hfinal_func hmac_hfinal; /* Get final result procedure. */ unsigned int hmac_ctxtsize; /* Context structure size. */ unsigned int hmac_maxkeylen; /* Maximum key length (bytes). */ unsigned int hmac_resultlen; /* Result length (bytes). */ -} HMAC_params; +}; /* HMAC computation context. */ - -typedef struct { - const HMAC_params *hmac_hash; /* Hash function definition. */ +struct HMAC_context { + const struct HMAC_params *hmac_hash; /* Hash function definition. */ void *hmac_hashctxt1; /* Hash function context 1. */ void *hmac_hashctxt2; /* Hash function context 2. */ -} HMAC_context; +}; /* Prototypes. */ - -HMAC_context * Curl_HMAC_init(const HMAC_params *hashparams, - const unsigned char *key, - unsigned int keylen); -int Curl_HMAC_update(HMAC_context *context, +struct HMAC_context *Curl_HMAC_init(const struct HMAC_params *hashparams, + const unsigned char *key, + unsigned int keylen); +int Curl_HMAC_update(struct HMAC_context *context, const unsigned char *data, unsigned int len); -int Curl_HMAC_final(HMAC_context *context, unsigned char *result); +int Curl_HMAC_final(struct HMAC_context *context, unsigned char *result); -CURLcode Curl_hmacit(const HMAC_params *hashparams, +CURLcode Curl_hmacit(const struct HMAC_params *hashparams, const unsigned char *key, const size_t keylen, const unsigned char *data, const size_t datalen, unsigned char *output); diff --git a/Utilities/cmcurl/lib/curl_md5.h b/Utilities/cmcurl/lib/curl_md5.h index dd46441..e06c68e 100644 --- a/Utilities/cmcurl/lib/curl_md5.h +++ b/Utilities/cmcurl/lib/curl_md5.h @@ -33,30 +33,30 @@ typedef void (* Curl_MD5_update_func)(void *context, unsigned int len); typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context); -typedef struct { +struct MD5_params { Curl_MD5_init_func md5_init_func; /* Initialize context procedure */ Curl_MD5_update_func md5_update_func; /* Update context with data */ Curl_MD5_final_func md5_final_func; /* Get final result procedure */ unsigned int md5_ctxtsize; /* Context structure size */ unsigned int md5_resultlen; /* Result length (bytes) */ -} MD5_params; +}; -typedef struct { - const MD5_params *md5_hash; /* Hash function definition */ +struct MD5_context { + const struct MD5_params *md5_hash; /* Hash function definition */ void *md5_hashctx; /* Hash function context */ -} MD5_context; +}; -extern const MD5_params Curl_DIGEST_MD5[1]; -extern const HMAC_params Curl_HMAC_MD5[1]; +extern const struct MD5_params Curl_DIGEST_MD5[1]; +extern const struct HMAC_params Curl_HMAC_MD5[1]; void Curl_md5it(unsigned char *output, const unsigned char *input, const size_t len); -MD5_context * Curl_MD5_init(const MD5_params *md5params); -CURLcode Curl_MD5_update(MD5_context *context, +struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params); +CURLcode Curl_MD5_update(struct MD5_context *context, const unsigned char *data, unsigned int len); -CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result); +CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result); #endif diff --git a/Utilities/cmcurl/lib/curl_multibyte.c b/Utilities/cmcurl/lib/curl_multibyte.c index e384344..2c8925b5 100644 --- a/Utilities/cmcurl/lib/curl_multibyte.c +++ b/Utilities/cmcurl/lib/curl_multibyte.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -20,24 +20,21 @@ * ***************************************************************************/ -#include "curl_setup.h" - -#include <curl/curl.h> +/* + * This file is 'mem-include-scan' clean. See test 1132. + */ -#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ - defined(USE_WIN32_LDAP)) && defined(UNICODE)) +#include "curl_setup.h" - /* - * MultiByte conversions using Windows kernel32 library. - */ +#if defined(WIN32) #include "curl_multibyte.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" +/* + * MultiByte conversions using Windows kernel32 library. + */ -wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8) +wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8) { wchar_t *str_w = NULL; @@ -59,7 +56,7 @@ wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8) return str_w; } -char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w) +char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w) { char *str_utf8 = NULL; @@ -81,4 +78,76 @@ char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w) return str_utf8; } -#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ +#endif /* WIN32 */ + +#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES) + +FILE *curlx_win32_fopen(const char *filename, const char *mode) +{ +#ifdef _UNICODE + FILE *result = NULL; + wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); + wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode); + if(filename_w && mode_w) + result = _wfopen(filename_w, mode_w); + free(filename_w); + free(mode_w); + if(result) + return result; +#endif + + return (fopen)(filename, mode); +} + +int curlx_win32_stat(const char *path, struct_stat *buffer) +{ + int result = -1; +#ifdef _UNICODE + wchar_t *path_w = curlx_convert_UTF8_to_wchar(path); +#endif /* _UNICODE */ + +#if defined(USE_WIN32_SMALL_FILES) +#if defined(_UNICODE) + if(path_w) + result = _wstat(path_w, buffer); + else +#endif /* _UNICODE */ + result = _stat(path, buffer); +#else /* USE_WIN32_SMALL_FILES */ +#if defined(_UNICODE) + if(path_w) + result = _wstati64(path_w, buffer); + else +#endif /* _UNICODE */ + result = _stati64(path, buffer); +#endif /* USE_WIN32_SMALL_FILES */ + +#ifdef _UNICODE + free(path_w); +#endif + + return result; +} + +int curlx_win32_access(const char *path, int mode) +{ + int result = -1; +#ifdef _UNICODE + wchar_t *path_w = curlx_convert_UTF8_to_wchar(path); +#endif /* _UNICODE */ + +#if defined(_UNICODE) + if(path_w) + result = _waccess(path_w, mode); + else +#endif /* _UNICODE */ + result = _access(path, mode); + +#ifdef _UNICODE + free(path_w); +#endif + + return result; +} + +#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */ diff --git a/Utilities/cmcurl/lib/curl_multibyte.h b/Utilities/cmcurl/lib/curl_multibyte.h index 3becf41..5f8c05a 100644 --- a/Utilities/cmcurl/lib/curl_multibyte.h +++ b/Utilities/cmcurl/lib/curl_multibyte.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,48 +23,43 @@ ***************************************************************************/ #include "curl_setup.h" -#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ - defined(USE_WIN32_LDAP)) && defined(UNICODE)) +#if defined(WIN32) /* * MultiByte conversions using Windows kernel32 library. */ -wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8); -char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w); +wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8); +char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w); -#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ - - -#if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI) || \ - defined(USE_WIN32_LDAP) +#endif /* WIN32 */ /* - * Macros Curl_convert_UTF8_to_tchar(), Curl_convert_tchar_to_UTF8() - * and Curl_unicodefree() main purpose is to minimize the number of + * Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8() + * and curlx_unicodefree() main purpose is to minimize the number of * preprocessor conditional directives needed by code using these * to differentiate UNICODE from non-UNICODE builds. * - * When building with UNICODE defined, this two macros - * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8() + * When building with UNICODE defined, these two macros + * curlx_convert_UTF8_to_tchar() and curlx_convert_tchar_to_UTF8() * return a pointer to a newly allocated memory area holding result. * When the result is no longer needed, allocated memory is intended - * to be free'ed with Curl_unicodefree(). + * to be free'ed with curlx_unicodefree(). * * When building without UNICODE defined, this macros - * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8() - * return the pointer received as argument. Curl_unicodefree() does + * curlx_convert_UTF8_to_tchar() and curlx_convert_tchar_to_UTF8() + * return the pointer received as argument. curlx_unicodefree() does * no actual free'ing of this pointer it is simply set to NULL. */ -#ifdef UNICODE +#if defined(UNICODE) && defined(WIN32) -#define Curl_convert_UTF8_to_tchar(ptr) Curl_convert_UTF8_to_wchar((ptr)) -#define Curl_convert_tchar_to_UTF8(ptr) Curl_convert_wchar_to_UTF8((ptr)) -#define Curl_unicodefree(ptr) \ +#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr)) +#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr)) +#define curlx_unicodefree(ptr) \ do { \ if(ptr) { \ - free(ptr); \ + (free)(ptr); \ (ptr) = NULL; \ } \ } while(0) @@ -78,9 +73,9 @@ typedef union { #else -#define Curl_convert_UTF8_to_tchar(ptr) (ptr) -#define Curl_convert_tchar_to_UTF8(ptr) (ptr) -#define Curl_unicodefree(ptr) \ +#define curlx_convert_UTF8_to_tchar(ptr) (ptr) +#define curlx_convert_tchar_to_UTF8(ptr) (ptr) +#define curlx_unicodefree(ptr) \ do {(ptr) = NULL;} while(0) typedef union { @@ -90,8 +85,6 @@ typedef union { const unsigned char *const_tbyte_ptr; } xcharp_u; -#endif /* UNICODE */ - -#endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI || USE_WIN32_LDAP */ +#endif /* UNICODE && WIN32 */ #endif /* HEADER_CURL_MULTIBYTE_H */ diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c index f9b823b..0eefb15 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.c +++ b/Utilities/cmcurl/lib/curl_ntlm_core.c @@ -52,13 +52,18 @@ #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) -#ifdef USE_OPENSSL +#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) + +#ifdef USE_WOLFSSL +#include <wolfssl/options.h> +#endif # include <openssl/des.h> # include <openssl/md5.h> # include <openssl/ssl.h> # include <openssl/rand.h> -# if (OPENSSL_VERSION_NUMBER < 0x00907001L) +# if (defined(OPENSSL_VERSION_NUMBER) && \ + (OPENSSL_VERSION_NUMBER < 0x00907001L)) && !defined(USE_WOLFSSL) # define DES_key_schedule des_key_schedule # define DES_cblock des_cblock # define DES_set_odd_parity des_set_odd_parity @@ -78,14 +83,12 @@ #elif defined(USE_GNUTLS) # include <gcrypt.h> -# define MD5_DIGEST_LENGTH 16 #elif defined(USE_NSS) # include <nss.h> # include <pk11pub.h> # include <hasht.h> -# define MD5_DIGEST_LENGTH MD5_LENGTH #elif defined(USE_MBEDTLS) @@ -138,7 +141,7 @@ static void extend_key_56_to_64(const unsigned char *key_56, char *key) key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); } -#ifdef USE_OPENSSL +#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) /* * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The * key schedule ks is also set. @@ -342,7 +345,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out, /* Acquire the crypto provider */ if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) return FALSE; /* Setup the key blob structure */ @@ -387,7 +390,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results) { -#ifdef USE_OPENSSL +#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) DES_key_schedule ks; setup_des_key(keys, DESKEY(ks)); @@ -462,7 +465,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, { /* Create LanManager hashed password. */ -#ifdef USE_OPENSSL +#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) DES_key_schedule ks; setup_des_key(pw, DESKEY(ks)); diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.h b/Utilities/cmcurl/lib/curl_ntlm_core.h index e1643d6..7895b64 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.h +++ b/Utilities/cmcurl/lib/curl_ntlm_core.h @@ -29,6 +29,7 @@ /* If NSS is the first available SSL backend (see order in curl_ntlm_core.c) then it must be initialized to be used by NTLM. */ #if !defined(USE_OPENSSL) && \ + !defined(USE_WOLFSSL) && \ !defined(USE_GNUTLS_NETTLE) && \ !defined(USE_GNUTLS) && \ defined(USE_NSS) @@ -37,7 +38,10 @@ #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) -#ifdef USE_OPENSSL +#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) +#ifdef USE_WOLFSSL +# include <wolfssl/options.h> +#endif # include <openssl/ssl.h> #endif diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c index f820b84..17a92f8 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_wb.c +++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c @@ -261,15 +261,11 @@ done: static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, const char *input, curlntlm state) { - char *buf = malloc(NTLM_BUFSIZE); size_t len_in = strlen(input), len_out = 0; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - if(!buf) - return CURLE_OUT_OF_MEMORY; + struct dynbuf b; + char *ptr = NULL; + unsigned char *buf = (unsigned char *)data->state.buffer; + Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE); while(len_in > 0) { ssize_t written = swrite(ntlm->ntlm_auth_hlpr_socket, input, len_in); @@ -285,10 +281,8 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, } /* Read one line */ while(1) { - ssize_t size; - char *newbuf; - - size = sread(ntlm->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE); + ssize_t size = + sread(ntlm->ntlm_auth_hlpr_socket, buf, data->set.buffer_size); if(size == -1) { if(errno == EINTR) continue; @@ -297,48 +291,41 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, else if(size == 0) goto done; - len_out += size; - if(buf[len_out - 1] == '\n') { - buf[len_out - 1] = '\0'; - break; - } + if(Curl_dyn_addn(&b, buf, size)) + goto done; - if(len_out > MAX_NTLM_WB_RESPONSE) { - failf(data, "too large ntlm_wb response!"); - free(buf); - return CURLE_OUT_OF_MEMORY; + len_out = Curl_dyn_len(&b); + ptr = Curl_dyn_ptr(&b); + if(len_out && ptr[len_out - 1] == '\n') { + ptr[len_out - 1] = '\0'; + break; /* done! */ } - - newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE); - if(!newbuf) - return CURLE_OUT_OF_MEMORY; - - buf = newbuf; + /* loop */ } /* Samba/winbind installed but not configured */ if(state == NTLMSTATE_TYPE1 && len_out == 3 && - buf[0] == 'P' && buf[1] == 'W') + ptr[0] == 'P' && ptr[1] == 'W') goto done; /* invalid response */ if(len_out < 4) goto done; if(state == NTLMSTATE_TYPE1 && - (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' ')) + (ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' ')) goto done; if(state == NTLMSTATE_TYPE2 && - (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') && - (buf[0]!='A' || buf[1]!='F' || buf[2]!=' ')) + (ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') && + (ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' ')) goto done; - ntlm->response = aprintf("%.*s", len_out - 4, buf + 3); - free(buf); + ntlm->response = strdup(ptr + 3); + Curl_dyn_free(&b); if(!ntlm->response) return CURLE_OUT_OF_MEMORY; return CURLE_OK; done: - free(buf); + Curl_dyn_free(&b); return CURLE_REMOTE_ACCESS_DENIED; } @@ -389,8 +376,7 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn, * This is for creating ntlm header output by delegating challenge/response * to Samba's winbind daemon helper ntlm_auth. */ -CURLcode Curl_output_ntlm_wb(struct connectdata *conn, - bool proxy) +CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy) { /* point to the address of the pointer that holds the string to send to the server, which is for a plain host or for a HTTP proxy */ @@ -400,6 +386,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, struct ntlmdata *ntlm; curlntlm *state; struct auth *authp; + struct Curl_easy *data = conn->data; CURLcode res = CURLE_OK; @@ -407,14 +394,18 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, DEBUGASSERT(conn->data); if(proxy) { - allocuserpwd = &conn->allocptr.proxyuserpwd; +#ifndef CURL_DISABLE_PROXY + allocuserpwd = &data->state.aptr.proxyuserpwd; userp = conn->http_proxy.user; ntlm = &conn->proxyntlm; state = &conn->proxy_ntlm_state; authp = &conn->data->state.authproxy; +#else + return CURLE_NOT_BUILT_IN; +#endif } else { - allocuserpwd = &conn->allocptr.userpwd; + allocuserpwd = &data->state.aptr.userpwd; userp = conn->user; ntlm = &conn->ntlm; state = &conn->http_ntlm_state; diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c index 8c1c866..83fe896 100644 --- a/Utilities/cmcurl/lib/curl_sasl.c +++ b/Utilities/cmcurl/lib/curl_sasl.c @@ -264,9 +264,14 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, size_t len = 0; saslstate state1 = SASL_STOP; saslstate state2 = SASL_FINAL; +#ifndef CURL_DISABLE_PROXY const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; +#else + const char * const hostname = conn->host.name; + const long int port = conn->remote_port; +#endif #if defined(USE_KERBEROS5) || defined(USE_NTLM) const char *service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : @@ -417,18 +422,23 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, struct Curl_easy *data = conn->data; saslstate newstate = SASL_FINAL; char *resp = NULL; +#ifndef CURL_DISABLE_PROXY const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; +#else + const char * const hostname = conn->host.name; + const long int port = conn->remote_port; +#endif #if !defined(CURL_DISABLE_CRYPTO_AUTH) char *chlg = NULL; size_t chlglen = 0; #endif -#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ - defined(USE_NTLM) +#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ + defined(USE_NTLM) const char *service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : - sasl->params->service; + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; char *serverdata; #endif size_t len = 0; diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h index ecd6afb..dadfff9 100644 --- a/Utilities/cmcurl/lib/curl_setup.h +++ b/Utilities/cmcurl/lib/curl_setup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -235,64 +235,20 @@ #endif /* - * Use getaddrinfo to resolve the IPv4 address literal. If the current network - * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, - * performing this task will result in a synthesized IPv6 address. - */ -#ifdef __APPLE__ -#define USE_RESOLVE_ON_IPS 1 -#endif - -/* - * Include header files for windows builds before redefining anything. - * Use this preprocessor block only to include or exclude windows.h, - * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs - * to any other further and independent block. Under Cygwin things work - * just as under linux (e.g. <sys/socket.h>) and the winsock headers should - * never be included when __CYGWIN__ is defined. configure script takes - * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, - * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + * Windows setup file includes some system headers. */ #ifdef HAVE_WINDOWS_H -# if defined(UNICODE) && !defined(_UNICODE) -# define _UNICODE -# endif -# if defined(_UNICODE) && !defined(UNICODE) -# define UNICODE -# endif -# include <winerror.h> -# include <windows.h> -# ifdef HAVE_WINSOCK2_H -# include <winsock2.h> -# ifdef HAVE_WS2TCPIP_H -# include <ws2tcpip.h> -# endif -# else -# ifdef HAVE_WINSOCK_H -# include <winsock.h> -# endif -# endif -# include <tchar.h> -# ifdef UNICODE - typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); -# endif +# include "setup-win32.h" #endif /* - * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else - * define USE_WINSOCK to 1 if we have and use WINSOCK API, else - * undefine USE_WINSOCK. + * Use getaddrinfo to resolve the IPv4 address literal. If the current network + * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, + * performing this task will result in a synthesized IPv6 address. */ - -#undef USE_WINSOCK - -#ifdef HAVE_WINSOCK2_H -# define USE_WINSOCK 2 -#else -# ifdef HAVE_WINSOCK_H -# define USE_WINSOCK 1 -# endif +#ifdef __APPLE__ +#define USE_RESOLVE_ON_IPS 1 #endif #ifdef USE_LWIPSOCK @@ -390,9 +346,14 @@ # undef fstat # define fstat(fdes,stp) _fstati64(fdes, stp) # undef stat -# define stat(fname,stp) _stati64(fname, stp) +# define stat(fname,stp) curlx_win32_stat(fname, stp) # define struct_stat struct _stati64 # define LSEEK_ERROR (__int64)-1 +# define fopen(fname,mode) curlx_win32_fopen(fname, mode) +# define access(fname,mode) curlx_win32_access(fname, mode) + int curlx_win32_stat(const char *path, struct_stat *buffer); + FILE *curlx_win32_fopen(const char *filename, const char *mode); + int curlx_win32_access(const char *path, int mode); #endif /* @@ -407,8 +368,13 @@ # undef lseek # define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) # define fstat(fdes,stp) _fstat(fdes, stp) -# define stat(fname,stp) _stat(fname, stp) +# define stat(fname,stp) curlx_win32_stat(fname, stp) # define struct_stat struct _stat +# define fopen(fname,mode) curlx_win32_fopen(fname, mode) +# define access(fname,mode) curlx_win32_access(fname, mode) + int curlx_win32_stat(const char *path, struct_stat *buffer); + FILE *curlx_win32_fopen(const char *filename, const char *mode); + int curlx_win32_access(const char *path, int mode); # endif # define LSEEK_ERROR (long)-1 #endif @@ -686,10 +652,11 @@ int netware_init(void); /* Single point where USE_NTLM definition might be defined */ #if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH) -#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \ - defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) || \ - defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \ - defined(USE_MBEDTLS) +#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \ + defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) || \ + defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \ + defined(USE_MBEDTLS) || \ + (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_SET_ODD_PARITY)) #define USE_NTLM diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h index 8890f38..e7c00de 100644 --- a/Utilities/cmcurl/lib/curl_setup_once.h +++ b/Utilities/cmcurl/lib/curl_setup_once.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -481,6 +481,8 @@ typedef int sig_atomic_t; #ifdef __VMS #define argv_item_t __char_ptr32 +#elif defined(_UNICODE) +#define argv_item_t wchar_t * #else #define argv_item_t char * #endif diff --git a/Utilities/cmcurl/lib/curl_sspi.c b/Utilities/cmcurl/lib/curl_sspi.c index f7cc10f..83ece9a 100644 --- a/Utilities/cmcurl/lib/curl_sspi.c +++ b/Utilities/cmcurl/lib/curl_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -151,7 +151,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, /* Initialize the identity */ memset(identity, 0, sizeof(*identity)); - useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp); + useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)userp); if(!useranddomain.tchar_ptr) return CURLE_OUT_OF_MEMORY; @@ -173,7 +173,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, /* Setup the identity's user and length */ dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); if(!dup_user.tchar_ptr) { - Curl_unicodefree(useranddomain.tchar_ptr); + curlx_unicodefree(useranddomain.tchar_ptr); return CURLE_OUT_OF_MEMORY; } identity->User = dup_user.tbyte_ptr; @@ -183,7 +183,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, /* Setup the identity's domain and length */ dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1)); if(!dup_domain.tchar_ptr) { - Curl_unicodefree(useranddomain.tchar_ptr); + curlx_unicodefree(useranddomain.tchar_ptr); return CURLE_OUT_OF_MEMORY; } _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen); @@ -192,22 +192,22 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, identity->DomainLength = curlx_uztoul(domlen); dup_domain.tchar_ptr = NULL; - Curl_unicodefree(useranddomain.tchar_ptr); + curlx_unicodefree(useranddomain.tchar_ptr); /* Setup the identity's password and length */ - passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp); + passwd.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)passwdp); if(!passwd.tchar_ptr) return CURLE_OUT_OF_MEMORY; dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); if(!dup_passwd.tchar_ptr) { - Curl_unicodefree(passwd.tchar_ptr); + curlx_unicodefree(passwd.tchar_ptr); return CURLE_OUT_OF_MEMORY; } identity->Password = dup_passwd.tbyte_ptr; identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); dup_passwd.tchar_ptr = NULL; - Curl_unicodefree(passwd.tchar_ptr); + curlx_unicodefree(passwd.tchar_ptr); /* Setup the identity's flags */ identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY; diff --git a/Utilities/cmcurl/lib/curl_threads.c b/Utilities/cmcurl/lib/curl_threads.c index 064c075..b5f10a2 100644 --- a/Utilities/cmcurl/lib/curl_threads.c +++ b/Utilities/cmcurl/lib/curl_threads.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -48,7 +48,7 @@ struct curl_actual_call { static void *curl_thread_create_thunk(void *arg) { - struct curl_actual_call * ac = arg; + struct curl_actual_call *ac = arg; unsigned int (*func)(void *) = ac->func; void *real_arg = ac->arg; diff --git a/Utilities/cmcurl/lib/curlx.h b/Utilities/cmcurl/lib/curlx.h index 3e9b516..a8bae14 100644 --- a/Utilities/cmcurl/lib/curlx.h +++ b/Utilities/cmcurl/lib/curlx.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -53,6 +53,16 @@ curlx_uztosi() */ +#include "curl_multibyte.h" +/* "curl_multibyte.h" provides these functions and macros: + + curlx_convert_UTF8_to_wchar() + curlx_convert_wchar_to_UTF8() + curlx_convert_UTF8_to_tchar() + curlx_convert_tchar_to_UTF8() + curlx_unicodefree() +*/ + /* Now setup curlx_ * names for the functions that are to become curlx_ and be removed from a future libcurl official API: curlx_getenv diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c index 208a233..c802dee 100644 --- a/Utilities/cmcurl/lib/dict.c +++ b/Utilities/cmcurl/lib/dict.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -46,6 +46,8 @@ #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> +#elif defined(HAVE_UNISTD_H) +#include <unistd.h> #endif #include "urldata.h" diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c index aaa8f15..ebb2c24 100644 --- a/Utilities/cmcurl/lib/doh.c +++ b/Utilities/cmcurl/lib/doh.c @@ -35,13 +35,13 @@ #include "curl_base64.h" #include "connect.h" #include "strdup.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define DNS_CLASS_IN 0x01 -#define DOH_MAX_RESPONSE_SIZE 3000 /* bytes */ #ifndef CURL_DISABLE_VERBOSE_STRINGS static const char * const errors[]={ @@ -174,23 +174,14 @@ UNITTEST DOHcode doh_encode(const char *host, } static size_t -doh_write_cb(void *contents, size_t size, size_t nmemb, void *userp) +doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; - struct dohresponse *mem = (struct dohresponse *)userp; + struct dynbuf *mem = (struct dynbuf *)userp; - if((mem->size + realsize) > DOH_MAX_RESPONSE_SIZE) - /* suspiciously much for us */ + if(Curl_dyn_addn(mem, contents, realsize)) return 0; - mem->memory = Curl_saferealloc(mem->memory, mem->size + realsize); - if(!mem->memory) - /* out of memory! */ - return 0; - - memcpy(&(mem->memory[mem->size]), contents, realsize); - mem->size += realsize; - return realsize; } @@ -238,10 +229,7 @@ static CURLcode dohprobe(struct Curl_easy *data, } p->dnstype = dnstype; - p->serverdoh.memory = NULL; - /* the memory will be grown as needed by realloc in the doh_write_cb - function */ - p->serverdoh.size = 0; + 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 @@ -272,7 +260,7 @@ static CURLcode dohprobe(struct Curl_easy *data, if(!result) { /* pass in the struct pointer via a local variable to please coverity and the gcc typecheck helpers */ - struct dohresponse *resp = &p->serverdoh; + struct dynbuf *resp = &p->serverdoh; ERROR_CHECK_SETOPT(CURLOPT_URL, url); ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb); ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp); @@ -318,6 +306,9 @@ static CURLcode dohprobe(struct Curl_easy *data, } if(data->set.proxy_ssl.no_revoke) ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); + else if(data->set.proxy_ssl.revoke_best_effort) + ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, + CURLSSLOPT_REVOKE_BEST_EFFORT); if(data->set.str[STRING_SSL_CAPATH_PROXY]) { ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAPATH, data->set.str[STRING_SSL_CAPATH_PROXY]); @@ -351,6 +342,8 @@ static CURLcode dohprobe(struct Curl_easy *data, } if(data->set.ssl.no_revoke) ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); + else if(data->set.ssl.revoke_best_effort) + ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_REVOKE_BEST_EFFORT); if(data->set.ssl.fsslctx) ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx); if(data->set.ssl.fsslctxp) @@ -380,10 +373,10 @@ static CURLcode dohprobe(struct Curl_easy *data, * 'Curl_addrinfo *' with the address information. */ -Curl_addrinfo *Curl_doh(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +struct Curl_addrinfo *Curl_doh(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; @@ -396,6 +389,7 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn, /* start clean, consider allocating this struct on demand */ memset(&data->req.doh, 0, sizeof(struct dohdata)); + conn->bits.doh = TRUE; data->req.doh.host = hostname; data->req.doh.port = port; data->req.doh.headers = @@ -434,7 +428,7 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn, return NULL; } -static DOHcode skipqname(unsigned char *doh, size_t dohlen, +static DOHcode skipqname(const unsigned char *doh, size_t dohlen, unsigned int *indexp) { unsigned char length; @@ -458,12 +452,12 @@ static DOHcode skipqname(unsigned char *doh, size_t dohlen, return DOH_OK; } -static unsigned short get16bit(unsigned char *doh, int index) +static unsigned short get16bit(const unsigned char *doh, int index) { return (unsigned short)((doh[index] << 8) | doh[index + 1]); } -static unsigned int get32bit(unsigned char *doh, int index) +static unsigned int get32bit(const unsigned char *doh, int index) { /* make clang and gcc optimize this to bswap by incrementing the pointer first. */ @@ -475,7 +469,7 @@ static unsigned int get32bit(unsigned char *doh, int index) return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3]; } -static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d) +static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d) { /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { @@ -487,7 +481,9 @@ static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d) return DOH_OK; } -static DOHcode store_aaaa(unsigned char *doh, int index, struct dohentry *d) +static DOHcode store_aaaa(const unsigned char *doh, + int index, + struct dohentry *d) { /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { @@ -499,38 +495,12 @@ static DOHcode store_aaaa(unsigned char *doh, int index, struct dohentry *d) return DOH_OK; } -static DOHcode cnameappend(struct cnamestore *c, - unsigned char *src, - size_t len) -{ - if(!c->alloc) { - c->allocsize = len + 1; - c->alloc = malloc(c->allocsize); - if(!c->alloc) - return DOH_OUT_OF_MEM; - } - else if(c->allocsize < (c->allocsize + len + 1)) { - char *ptr; - c->allocsize += len + 1; - ptr = realloc(c->alloc, c->allocsize); - if(!ptr) { - free(c->alloc); - return DOH_OUT_OF_MEM; - } - c->alloc = ptr; - } - memcpy(&c->alloc[c->len], src, len); - c->len += len; - c->alloc[c->len] = 0; /* keep it zero terminated */ - return DOH_OK; -} - -static DOHcode store_cname(unsigned char *doh, +static DOHcode store_cname(const unsigned char *doh, size_t dohlen, unsigned int index, struct dohentry *d) { - struct cnamestore *c; + struct dynbuf *c; unsigned int loop = 128; /* a valid DNS name can never loop this much */ unsigned char length; @@ -559,18 +529,15 @@ static DOHcode store_cname(unsigned char *doh, index++; if(length) { - DOHcode rc; - if(c->len) { - rc = cnameappend(c, (unsigned char *)".", 1); - if(rc) - return rc; + if(Curl_dyn_len(c)) { + if(Curl_dyn_add(c, ".")) + return DOH_OUT_OF_MEM; } if((index + length) > dohlen) return DOH_DNS_BAD_LABEL; - rc = cnameappend(c, &doh[index], length); - if(rc) - return rc; + if(Curl_dyn_addn(c, &doh[index], length)) + return DOH_OUT_OF_MEM; index += length; } } while(length && --loop); @@ -580,7 +547,7 @@ static DOHcode store_cname(unsigned char *doh, return DOH_OK; } -static DOHcode rdata(unsigned char *doh, +static DOHcode rdata(const unsigned char *doh, size_t dohlen, unsigned short rdlength, unsigned short type, @@ -623,14 +590,17 @@ static DOHcode rdata(unsigned char *doh, return DOH_OK; } -static void init_dohentry(struct dohentry *de) +UNITTEST void de_init(struct dohentry *de) { + int i; memset(de, 0, sizeof(*de)); de->ttl = INT_MAX; + for(i = 0; i < DOH_MAX_CNAME; i++) + Curl_dyn_init(&de->cname[i], DYN_DOH_CNAME); } -UNITTEST DOHcode doh_decode(unsigned char *doh, +UNITTEST DOHcode doh_decode(const unsigned char *doh, size_t dohlen, DNStype dnstype, struct dohentry *d) @@ -770,12 +740,12 @@ UNITTEST DOHcode doh_decode(unsigned char *doh, #ifndef CURL_DISABLE_VERBOSE_STRINGS static void showdoh(struct Curl_easy *data, - struct dohentry *d) + const struct dohentry *d) { int i; infof(data, "TTL: %u seconds\n", d->ttl); for(i = 0; i < d->numaddr; i++) { - struct dohaddr *a = &d->addr[i]; + const struct dohaddr *a = &d->addr[i]; if(a->type == DNS_TYPE_A) { infof(data, "DOH A: %u.%u.%u.%u\n", a->ip.v4[0], a->ip.v4[1], @@ -801,7 +771,7 @@ static void showdoh(struct Curl_easy *data, } } for(i = 0; i < d->numcname; i++) { - infof(data, "CNAME: %s\n", d->cname[i].alloc); + infof(data, "CNAME: %s\n", Curl_dyn_ptr(&d->cname[i])); } } #else @@ -821,18 +791,19 @@ static void showdoh(struct Curl_easy *data, * must be an associated call later to Curl_freeaddrinfo(). */ -static Curl_addrinfo * +static struct Curl_addrinfo * doh2ai(const struct dohentry *de, const char *hostname, int port) { - Curl_addrinfo *ai; - Curl_addrinfo *prevai = NULL; - Curl_addrinfo *firstai = NULL; + struct Curl_addrinfo *ai; + struct Curl_addrinfo *prevai = NULL; + struct Curl_addrinfo *firstai = NULL; struct sockaddr_in *addr; #ifdef ENABLE_IPV6 struct sockaddr_in6 *addr6; #endif CURLcode result = CURLE_OK; int i; + size_t hostlen = strlen(hostname) + 1; /* include zero terminator */ if(!de) /* no input == no output! */ @@ -855,24 +826,14 @@ doh2ai(const struct dohentry *de, const char *hostname, int port) addrtype = AF_INET; } - ai = calloc(1, sizeof(Curl_addrinfo)); + ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen); if(!ai) { result = CURLE_OUT_OF_MEMORY; break; } - ai->ai_canonname = strdup(hostname); - if(!ai->ai_canonname) { - result = CURLE_OUT_OF_MEMORY; - free(ai); - break; - } - ai->ai_addr = calloc(1, ss_size); - if(!ai->ai_addr) { - result = CURLE_OUT_OF_MEMORY; - free(ai->ai_canonname); - free(ai); - break; - } + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); + ai->ai_canonname = (void *)((char *)ai->ai_addr + ss_size); + memcpy(ai->ai_canonname, hostname, hostlen); if(!firstai) /* store the pointer we want to return from this function */ @@ -934,7 +895,7 @@ UNITTEST void de_cleanup(struct dohentry *d) { int i = 0; for(i = 0; i < d->numcname; i++) { - free(d->cname[i].alloc); + Curl_dyn_free(&d->cname[i]); } } @@ -952,7 +913,9 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn, CURLE_COULDNT_RESOLVE_HOST; } else if(!data->req.doh.pending) { - DOHcode rc[DOH_PROBE_SLOTS]; + DOHcode rc[DOH_PROBE_SLOTS] = { + DOH_OK, DOH_OK + }; struct dohentry de; int slot; /* remove DOH handles from multi handle and close them */ @@ -961,17 +924,19 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn, Curl_close(&data->req.doh.probe[slot].easy); } /* parse the responses, create the struct and return it! */ - init_dohentry(&de); + de_init(&de); for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) { - rc[slot] = doh_decode(data->req.doh.probe[slot].serverdoh.memory, - data->req.doh.probe[slot].serverdoh.size, - data->req.doh.probe[slot].dnstype, + struct dnsprobe *p = &data->req.doh.probe[slot]; + if(!p->dnstype) + continue; + rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh), + Curl_dyn_len(&p->serverdoh), + p->dnstype, &de); - Curl_safefree(data->req.doh.probe[slot].serverdoh.memory); + Curl_dyn_free(&p->serverdoh); if(rc[slot]) { infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]), - type2name(data->req.doh.probe[slot].dnstype), - data->req.doh.host); + type2name(p->dnstype), data->req.doh.host); } } /* next slot */ diff --git a/Utilities/cmcurl/lib/doh.h b/Utilities/cmcurl/lib/doh.h index fc053ed..bbd4c1a 100644 --- a/Utilities/cmcurl/lib/doh.h +++ b/Utilities/cmcurl/lib/doh.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2018 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,10 +32,10 @@ * and returns a 'Curl_addrinfo *' with the address information. */ -Curl_addrinfo *Curl_doh(struct connectdata *conn, - const char *hostname, - int port, - int *waitp); +struct Curl_addrinfo *Curl_doh(struct connectdata *conn, + const char *hostname, + int port, + int *waitp); CURLcode Curl_doh_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns); @@ -70,12 +70,6 @@ typedef enum { #define DOH_MAX_ADDR 24 #define DOH_MAX_CNAME 4 -struct cnamestore { - size_t len; /* length of cname */ - char *alloc; /* allocated pointer */ - size_t allocsize; /* allocated size */ -}; - struct dohaddr { int type; union { @@ -85,11 +79,11 @@ struct dohaddr { }; struct dohentry { - unsigned int ttl; - int numaddr; + struct dynbuf cname[DOH_MAX_CNAME]; struct dohaddr addr[DOH_MAX_ADDR]; + int numaddr; + unsigned int ttl; int numcname; - struct cnamestore cname[DOH_MAX_CNAME]; }; @@ -99,10 +93,11 @@ DOHcode doh_encode(const char *host, unsigned char *dnsp, /* buffer */ size_t len, /* buffer size */ size_t *olen); /* output length */ -DOHcode doh_decode(unsigned char *doh, +DOHcode doh_decode(const unsigned char *doh, size_t dohlen, DNStype dnstype, struct dohentry *d); +void de_init(struct dohentry *d); void de_cleanup(struct dohentry *d); #endif diff --git a/Utilities/cmcurl/lib/dynbuf.c b/Utilities/cmcurl/lib/dynbuf.c new file mode 100644 index 0000000..dfc1d05 --- /dev/null +++ b/Utilities/cmcurl/lib/dynbuf.c @@ -0,0 +1,227 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "strdup.h" +#include "dynbuf.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define MIN_FIRST_ALLOC 32 + +#define DYNINIT 0xbee51da /* random pattern */ + +/* + * Init a dynbuf struct. + */ +void Curl_dyn_init(struct dynbuf *s, size_t toobig) +{ + DEBUGASSERT(s); + DEBUGASSERT(toobig); + s->bufr = NULL; + s->leng = 0; + s->allc = 0; + s->toobig = toobig; +#ifdef DEBUGBUILD + s->init = DYNINIT; +#endif +} + +/* + * free the buffer and re-init the necessary fields. It doesn't touch the + * 'init' field and thus this buffer can be reused to add data to again. + */ +void Curl_dyn_free(struct dynbuf *s) +{ + DEBUGASSERT(s); + Curl_safefree(s->bufr); + s->leng = s->allc = 0; +} + +/* + * Store/append an chunk of memory to the dynbuf. + */ +static CURLcode dyn_nappend(struct dynbuf *s, + const unsigned char *mem, size_t len) +{ + size_t indx = s->leng; + size_t a = s->allc; + size_t fit = len + indx + 1; /* new string + old string + zero byte */ + + /* try to detect if there's rubbish in the struct */ + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(s->toobig); + DEBUGASSERT(indx < s->toobig); + DEBUGASSERT(!s->leng || s->bufr); + + if(fit > s->toobig) { + Curl_dyn_free(s); + return CURLE_OUT_OF_MEMORY; + } + else if(!a) { + DEBUGASSERT(!indx); + /* first invoke */ + if(fit < MIN_FIRST_ALLOC) + a = MIN_FIRST_ALLOC; + else + a = fit; + } + else { + while(a < fit) + a *= 2; + } + + if(a != s->allc) { + s->bufr = Curl_saferealloc(s->bufr, a); + if(!s->bufr) { + s->leng = s->allc = 0; + return CURLE_OUT_OF_MEMORY; + } + s->allc = a; + } + + if(len) + memcpy(&s->bufr[indx], mem, len); + s->leng = indx + len; + s->bufr[s->leng] = 0; + return CURLE_OK; +} + +/* + * Clears the string, keeps the allocation. This can also be called on a + * buffer that already was freed. + */ +void Curl_dyn_reset(struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(s->leng) + s->bufr[0] = 0; + s->leng = 0; +} + +#ifdef USE_NGTCP2 +/* + * Specify the size of the tail to keep (number of bytes from the end of the + * buffer). The rest will be dropped. + */ +CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(trail > s->leng) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(trail == s->leng) + return CURLE_OK; + else if(!trail) { + Curl_dyn_reset(s); + } + else { + memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail); + s->leng = trail; + } + return CURLE_OK; + +} +#endif + +/* + * Appends a buffer with length. + */ +CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return dyn_nappend(s, mem, len); +} + +/* + * Append a zero terminated string at the end. + */ +CURLcode Curl_dyn_add(struct dynbuf *s, const char *str) +{ + size_t n = strlen(str); + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return dyn_nappend(s, (unsigned char *)str, n); +} + +/* + * Append a string printf()-style + */ +CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...) +{ + char *str; + va_list ap; + va_start(ap, fmt); + str = vaprintf(fmt, ap); /* this allocs a new string to append */ + va_end(ap); + + if(str) { + CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str)); + free(str); + return result; + } + /* If we failed, we cleanup the whole buffer and return error */ + Curl_dyn_free(s); + return CURLE_OUT_OF_MEMORY; +} + +/* + * Returns a pointer to the buffer. + */ +char *Curl_dyn_ptr(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return s->bufr; +} + +/* + * Returns an unsigned pointer to the buffer. + */ +unsigned char *Curl_dyn_uptr(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return (unsigned char *)s->bufr; +} + +/* + * Returns the length of the buffer. + */ +size_t Curl_dyn_len(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return s->leng; +} diff --git a/Utilities/cmcurl/lib/dynbuf.h b/Utilities/cmcurl/lib/dynbuf.h new file mode 100644 index 0000000..7809bec --- /dev/null +++ b/Utilities/cmcurl/lib/dynbuf.h @@ -0,0 +1,63 @@ +#ifndef HEADER_CURL_DYNBUF_H +#define HEADER_CURL_DYNBUF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +struct dynbuf { + char *bufr; /* point to a zero terminated allocated buffer */ + size_t leng; /* number of bytes *EXCLUDING* the zero terminator */ + size_t allc; /* size of the current allocation */ + size_t toobig; /* size limit for the buffer */ +#ifdef DEBUGBUILD + int init; /* detect API usage mistakes */ +#endif +}; + +void Curl_dyn_init(struct dynbuf *s, size_t toobig); +void Curl_dyn_free(struct dynbuf *s); +CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len) + WARN_UNUSED_RESULT; +CURLcode Curl_dyn_add(struct dynbuf *s, const char *str) + WARN_UNUSED_RESULT; +CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...) + WARN_UNUSED_RESULT; +void Curl_dyn_reset(struct dynbuf *s); +CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail); +char *Curl_dyn_ptr(const struct dynbuf *s); +unsigned char *Curl_dyn_uptr(const struct dynbuf *s); +size_t Curl_dyn_len(const struct dynbuf *s); + +/* Dynamic buffer max sizes */ +#define DYN_DOH_RESPONSE 3000 +#define DYN_DOH_CNAME 256 +#define DYN_PAUSE_BUFFER (64 * 1024 * 1024) +#define DYN_HAXPROXY 2048 +#define DYN_HTTP_REQUEST (128*1024) +#define DYN_H2_HEADERS (128*1024) +#define DYN_H2_TRAILER 4096 +#define DYN_APRINTF 8000000 +#define DYN_RTSP_REQ_HEADER (64*1024) +#define DYN_TRAILERS (64*1024) +#define DYN_PROXY_CONNECT_HEADERS 16384 +#define DYN_QLOG_NAME 1024 +#define DYN_H1_TRAILER DYN_H2_TRAILER +#endif diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c index 1a69127..292cca7 100644 --- a/Utilities/cmcurl/lib/easy.c +++ b/Utilities/cmcurl/lib/easy.c @@ -77,14 +77,13 @@ #include "http_digest.h" #include "system_win32.h" #include "http2.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" -void Curl_version_init(void); - /* true globals -- for curl_global_init() and curl_global_cleanup() */ static unsigned int initialized; static long init_flags; @@ -201,8 +200,6 @@ static CURLcode global_init(long flags, bool memoryfuncs) init_flags = flags; - Curl_version_init(); - return CURLE_OK; fail: @@ -513,7 +510,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) before = Curl_now(); /* wait for activity or timeout */ - pollrc = Curl_poll(fds, numfds, (int)ev->ms); + pollrc = Curl_poll(fds, numfds, ev->ms); after = Curl_now(); @@ -684,6 +681,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) mcode = curl_multi_add_handle(multi, data); if(mcode) { curl_multi_cleanup(multi); + data->multi_easy = NULL; if(mcode == CURLM_OUT_OF_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_FAILED_INIT; @@ -766,6 +764,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) { CURLcode result = CURLE_OK; enum dupstring i; + enum dupblob j; /* Copy src->set into dst->set first, then deal with the strings afterwards */ @@ -782,6 +781,16 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) return result; } + /* clear all blob pointers first */ + memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *)); + /* duplicate all blobs */ + for(j = (enum dupblob)0; j < BLOB_LAST; j++) { + result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]); + /* Curl_setstropt return CURLE_BAD_FUNCTION_ARGUMENT with blob */ + if(result) + return result; + } + /* duplicate memory areas pointed to */ i = STRING_COPYPOSTFIELDS; if(src->set.postfieldsize && src->set.str[i]) { @@ -820,19 +829,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) * the likeliness of us forgetting to init a buffer here in the future. */ outcurl->set.buffer_size = data->set.buffer_size; - outcurl->state.buffer = malloc(outcurl->set.buffer_size + 1); - if(!outcurl->state.buffer) - goto fail; - - outcurl->state.headerbuff = malloc(HEADERSIZE); - if(!outcurl->state.headerbuff) - goto fail; - outcurl->state.headersize = HEADERSIZE; /* copy all userdefined values */ if(dupset(outcurl, data)) goto fail; + Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER); + /* the connection cache is setup on demand */ outcurl->state.conn_cache = NULL; @@ -887,6 +890,28 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) data->state.resolver)) goto fail; +#ifdef USE_ARES + { + CURLcode rc; + + rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + } +#endif /* USE_ARES */ + Curl_convert_setup(outcurl); Curl_initinfo(outcurl); @@ -903,7 +928,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) curl_slist_free_all(outcurl->change.cookielist); outcurl->change.cookielist = NULL; Curl_safefree(outcurl->state.buffer); - Curl_safefree(outcurl->state.headerbuff); + Curl_dyn_free(&outcurl->state.headerb); Curl_safefree(outcurl->change.url); Curl_safefree(outcurl->change.referer); Curl_freeset(outcurl); @@ -919,8 +944,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) */ void curl_easy_reset(struct Curl_easy *data) { - long old_buffer_size = data->set.buffer_size; - Curl_free_request_state(data); /* zero out UserDefined data: */ @@ -944,18 +967,6 @@ void curl_easy_reset(struct Curl_easy *data) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) Curl_http_auth_cleanup_digest(data); #endif - - /* resize receive buffer */ - if(old_buffer_size != data->set.buffer_size) { - char *newbuff = realloc(data->state.buffer, data->set.buffer_size + 1); - if(!newbuff) { - DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n")); - /* nothing we can do here except use the old size */ - data->set.buffer_size = old_buffer_size; - } - else - data->state.buffer = newbuff; - } } /* @@ -973,16 +984,37 @@ void curl_easy_reset(struct Curl_easy *data) */ CURLcode curl_easy_pause(struct Curl_easy *data, int action) { - struct SingleRequest *k = &data->req; + struct SingleRequest *k; CURLcode result = CURLE_OK; + int oldstate; + int newstate; - /* first switch off both pause bits */ - int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); + if(!GOOD_EASY_HANDLE(data) || !data->conn) + /* crazy input, don't continue */ + return CURLE_BAD_FUNCTION_ARGUMENT; + + k = &data->req; + oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); - /* set the new desired pause bits */ - newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | + /* first switch off both pause bits then set the new pause bits */ + newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) | + ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0); + if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) { + /* Not changing any pause state, return */ + DEBUGF(infof(data, "pause: no change, early return\n")); + return CURLE_OK; + } + + /* Unpause parts in active mime tree. */ + if((k->keepon & ~newstate & KEEP_SEND_PAUSE) && + (data->mstate == CURLM_STATE_PERFORM || + data->mstate == CURLM_STATE_TOOFAST) && + data->state.fread_func == (curl_read_callback) Curl_mime_read) { + Curl_mime_unpause(data->state.in); + } + /* put it back in the keepon */ k->keepon = newstate; @@ -1001,7 +1033,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) /* copy the structs to allow for immediate re-pausing */ for(i = 0; i < data->state.tempcount; i++) { writebuf[i] = data->state.tempwrite[i]; - data->state.tempwrite[i].buf = NULL; + Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER); } data->state.tempcount = 0; @@ -1015,9 +1047,10 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) /* even if one function returns error, this loops through and frees all buffers */ if(!result) - result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf, - writebuf[i].len); - free(writebuf[i].buf); + result = Curl_client_write(conn, writebuf[i].type, + Curl_dyn_ptr(&writebuf[i].b), + Curl_dyn_len(&writebuf[i].b)); + Curl_dyn_free(&writebuf[i].b); } /* recover previous owner of the connection */ @@ -1033,8 +1066,11 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) to have this handle checked soon */ if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) { - data->state.drain++; Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */ + + /* force a recv/send check of this connection, as the data might've been + read off the socket already */ + data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT; if(data->multi) Curl_update_timer(data->multi); } diff --git a/Utilities/cmcurl/lib/easyif.h b/Utilities/cmcurl/lib/easyif.h index 8a309c5..eda0d62 100644 --- a/Utilities/cmcurl/lib/easyif.h +++ b/Utilities/cmcurl/lib/easyif.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c index 7121db3..f3c558e 100644 --- a/Utilities/cmcurl/lib/escape.c +++ b/Utilities/cmcurl/lib/escape.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -79,57 +79,42 @@ char *curl_unescape(const char *string, int length) char *curl_easy_escape(struct Curl_easy *data, const char *string, int inlength) { - size_t alloc; - char *ns; - char *testing_ptr = NULL; - size_t newlen; - size_t strindex = 0; size_t length; CURLcode result; + struct dynbuf d; if(inlength < 0) return NULL; - alloc = (inlength?(size_t)inlength:strlen(string)) + 1; - newlen = alloc; - - ns = malloc(alloc); - if(!ns) - return NULL; + Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH); - length = alloc-1; + length = (inlength?(size_t)inlength:strlen(string)); while(length--) { unsigned char in = *string; /* we need to treat the characters unsigned */ - if(Curl_isunreserved(in)) - /* just copy this */ - ns[strindex++] = in; + if(Curl_isunreserved(in)) { + /* append this */ + if(Curl_dyn_addn(&d, &in, 1)) + return NULL; + } else { /* encode it */ - newlen += 2; /* the size grows with two, since this'll become a %XX */ - if(newlen > alloc) { - alloc *= 2; - testing_ptr = Curl_saferealloc(ns, alloc); - if(!testing_ptr) - return NULL; - ns = testing_ptr; - } - + char encoded[4]; result = Curl_convert_to_network(data, (char *)&in, 1); if(result) { /* Curl_convert_to_network calls failf if unsuccessful */ - free(ns); + Curl_dyn_free(&d); return NULL; } - msnprintf(&ns[strindex], 4, "%%%02X", in); - - strindex += 3; + msnprintf(encoded, sizeof(encoded), "%%%02X", in); + if(Curl_dyn_add(&d, encoded)) + return NULL; } string++; } - ns[strindex] = 0; /* terminate it */ - return ns; + + return Curl_dyn_ptr(&d); } /* @@ -149,12 +134,17 @@ CURLcode Curl_urldecode(struct Curl_easy *data, char **ostring, size_t *olen, bool reject_ctrl) { - size_t alloc = (length?length:strlen(string)) + 1; - char *ns = malloc(alloc); + size_t alloc; + char *ns; size_t strindex = 0; unsigned long hex; CURLcode result = CURLE_OK; + DEBUGASSERT(string); + + alloc = (length?length:strlen(string)) + 1; + ns = malloc(alloc); + if(!ns) return CURLE_OUT_OF_MEMORY; diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c index 2492370..576a794 100644 --- a/Utilities/cmcurl/lib/file.c +++ b/Utilities/cmcurl/lib/file.c @@ -136,7 +136,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) struct Curl_easy *data = conn->data; char *real_path; struct FILEPROTO *file = data->req.protop; - int fd = -1; + int fd; #ifdef DOS_FILESYSTEM size_t i; char *actual_path; @@ -181,9 +181,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) return CURLE_URL_MALFORMAT; } - if(strncmp("\\\\", actual_path, 2)) - /* refuse to open path that starts with two backslashes */ - fd = open_readonly(actual_path, O_RDONLY|O_BINARY); + fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else if(memchr(real_path, 0, real_path_len)) { diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c index 50a37e0..dfa44bc 100644 --- a/Utilities/cmcurl/lib/formdata.c +++ b/Utilities/cmcurl/lib/formdata.c @@ -123,11 +123,11 @@ AddHttpPost(char *name, size_t namelength, * parent_form_info is NULL. * ***************************************************************************/ -static FormInfo * AddFormInfo(char *value, - char *contenttype, - FormInfo *parent_form_info) +static struct FormInfo *AddFormInfo(char *value, + char *contenttype, + struct FormInfo *parent_form_info) { - FormInfo *form_info; + struct FormInfo *form_info; form_info = calloc(1, sizeof(struct FormInfo)); if(form_info) { if(value) @@ -204,7 +204,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, struct curl_httppost **last_post, va_list params) { - FormInfo *first_form, *current_form, *form = NULL; + struct FormInfo *first_form, *current_form, *form = NULL; CURLFORMcode return_value = CURL_FORMADD_OK; const char *prevtype = NULL; struct curl_httppost *post = NULL; @@ -521,7 +521,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, if(CURL_FORMADD_OK != return_value) { /* On error, free allocated fields for all nodes of the FormInfo linked list without deallocating nodes. List nodes are deallocated later on */ - FormInfo *ptr; + struct FormInfo *ptr; for(ptr = first_form; ptr != NULL; ptr = ptr->more) { if(ptr->name_alloc) { Curl_safefree(ptr->name); @@ -650,7 +650,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, /* On error, free allocated fields for nodes of the FormInfo linked list which are not already owned by the httppost linked list without deallocating nodes. List nodes are deallocated later on */ - FormInfo *ptr; + struct FormInfo *ptr; for(ptr = form; ptr != NULL; ptr = ptr->more) { if(ptr->name_alloc) { Curl_safefree(ptr->name); @@ -676,7 +676,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, fields given that these have either been deallocated or are owned now by the httppost linked list */ while(first_form) { - FormInfo *ptr = first_form->more; + struct FormInfo *ptr = first_form->more; free(first_form); first_form = ptr; } @@ -728,14 +728,10 @@ int curl_formget(struct curl_httppost *form, void *arg, if(!nread) break; - switch(nread) { - default: - if(append(arg, buffer, nread) != nread) - result = CURLE_READ_ERROR; - break; - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: - break; + if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) { + result = CURLE_READ_ERROR; + if(nread == CURL_READFUNC_ABORT) + result = CURLE_ABORTED_BY_CALLBACK; } } diff --git a/Utilities/cmcurl/lib/formdata.h b/Utilities/cmcurl/lib/formdata.h index cb20805..3766d38 100644 --- a/Utilities/cmcurl/lib/formdata.h +++ b/Utilities/cmcurl/lib/formdata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,7 +27,7 @@ #ifndef CURL_DISABLE_MIME /* used by FormAdd for temporary storage */ -typedef struct FormInfo { +struct FormInfo { char *name; bool name_alloc; size_t namelength; @@ -45,7 +45,7 @@ typedef struct FormInfo { char *userp; /* pointer for the read callback */ struct curl_slist *contentheader; struct FormInfo *more; -} FormInfo; +}; CURLcode Curl_getformdata(struct Curl_easy *data, curl_mimepart *, diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c index 7292e01..562b6d2 100644 --- a/Utilities/cmcurl/lib/ftp.c +++ b/Utilities/cmcurl/lib/ftp.c @@ -113,7 +113,7 @@ static CURLcode ftp_parse_url_path(struct connectdata *conn); static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done); #ifndef CURL_DISABLE_VERBOSE_STRINGS static void ftp_pasv_verbose(struct connectdata *conn, - Curl_addrinfo *ai, + struct Curl_addrinfo *ai, char *newhost, /* ascii version */ int port); #endif @@ -136,7 +136,7 @@ static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks); static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks); static CURLcode ftp_doing(struct connectdata *conn, bool *dophase_done); -static CURLcode ftp_setup_connection(struct connectdata * conn); +static CURLcode ftp_setup_connection(struct connectdata *conn); static CURLcode init_wc_data(struct connectdata *conn); static CURLcode wc_statemach(struct connectdata *conn); @@ -221,6 +221,9 @@ static void close_secondarysocket(struct connectdata *conn) conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; } conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; +#ifndef CURL_DISABLE_PROXY + conn->bits.proxy_ssl_connected[SECONDARYSOCKET] = FALSE; +#endif } /* @@ -291,7 +294,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn) conn->sock[SECONDARYSOCKET] = s; (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ - conn->sock_accepted = TRUE; + conn->bits.sock_accepted = TRUE; if(data->set.fsockopt) { int error = 0; @@ -334,7 +337,7 @@ static timediff_t ftp_timeleft_accept(struct Curl_easy *data) now = Curl_now(); /* check if the generic timeout possibly is set shorter */ - other = Curl_timeleft(data, &now, FALSE); + other = Curl_timeleft(data, &now, FALSE); if(other && (other < timeout_ms)) /* note that this also works fine for when other happens to be negative due to it already having elapsed */ @@ -386,7 +389,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) if(pp->cache_size && pp->cache && pp->cache[0] > '3') { /* Data connection could not be established, let's return */ infof(data, "There is negative response in cache while serv connect\n"); - Curl_GetFTPResponse(&nread, conn, &ftpcode); + (void)Curl_GetFTPResponse(&nread, conn, &ftpcode); return CURLE_FTP_ACCEPT_FAILED; } @@ -408,7 +411,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) } else if(result & CURL_CSELECT_IN) { infof(data, "Ctrl conn has data while waiting for data conn\n"); - Curl_GetFTPResponse(&nread, conn, &ftpcode); + (void)Curl_GetFTPResponse(&nread, conn, &ftpcode); if(ftpcode/100 > 3) return CURLE_FTP_ACCEPT_FAILED; @@ -632,8 +635,8 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ while(!*ftpcode && !result) { /* check and reset timeout value every lap */ - time_t timeout = Curl_pp_state_timeout(pp, FALSE); - time_t interval_ms; + timediff_t timeout = Curl_pp_state_timeout(pp, FALSE); + timediff_t interval_ms; if(timeout <= 0) { failf(data, "FTP response timeout"); @@ -815,6 +818,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks) if(FTP_STOP == ftpc->state) { int bits = GETSOCK_READSOCK(0); + bool any = FALSE; /* if stopped and still in this state, then we're also waiting for a connect on the secondary connection */ @@ -829,10 +833,11 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks) if(conn->tempsock[i] != CURL_SOCKET_BAD) { socks[s] = conn->tempsock[i]; bits |= GETSOCK_WRITESOCK(s++); + any = TRUE; } } } - else { + if(!any) { socks[1] = conn->sock[SECONDARYSOCKET]; bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1); } @@ -913,7 +918,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, char myhost[MAX_IPADR_LEN + 1] = ""; struct Curl_sockaddr_storage ss; - Curl_addrinfo *res, *ai; + struct Curl_addrinfo *res, *ai; curl_socklen_t sslen; char hbuf[NI_MAXHOST]; struct sockaddr *sa = (struct sockaddr *)&ss; @@ -1293,7 +1298,7 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn) struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = CURLE_OK; /* - Here's the excecutive summary on what to do: + Here's the executive summary on what to do: PASV is RFC959, expect: 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) @@ -1759,7 +1764,11 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn) { CURLcode result = CURLE_OK; - if(conn->bits.ipv6 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)) { + if(conn->bits.ipv6 +#ifndef CURL_DISABLE_PROXY + && !(conn->bits.tunnel_proxy || conn->bits.socksproxy) +#endif + ) { /* We can't disable EPSV when doing IPv6, so this is instead a fail */ failf(conn->data, "Failed EPSV attempt, exiting\n"); return CURLE_WEIRD_SERVER_REPLY; @@ -1784,9 +1793,10 @@ static char *control_address(struct connectdata *conn) If a proxy tunnel is used, returns the original host name instead, because the effective control connection address is the proxy address, not the ftp host. */ +#ifndef CURL_DISABLE_PROXY if(conn->bits.tunnel_proxy || conn->bits.socksproxy) return conn->host.name; - +#endif return conn->ip_addr_str; } @@ -1903,6 +1913,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, return CURLE_FTP_WEIRD_PASV_REPLY; } +#ifndef CURL_DISABLE_PROXY if(conn->bits.proxy) { /* * This connection uses a proxy and we need to connect to the proxy again @@ -1925,7 +1936,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, return CURLE_COULDNT_RESOLVE_PROXY; } } - else { + else +#endif + { /* normal, direct, ftp connection */ rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, FALSE, &addr); if(rc == CURLRESOLV_PENDING) @@ -2634,9 +2647,12 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) #endif if(data->set.use_ssl && - (!conn->ssl[FIRSTSOCKET].use || - (conn->bits.proxy_ssl_connected[FIRSTSOCKET] && - !conn->proxy_ssl[FIRSTSOCKET].use))) { + (!conn->ssl[FIRSTSOCKET].use +#ifndef CURL_DISABLE_PROXY + || (conn->bits.proxy_ssl_connected[FIRSTSOCKET] && + !conn->proxy_ssl[FIRSTSOCKET].use) +#endif + )) { /* We don't have a SSL/TLS connection yet, but FTPS is requested. Try a FTPS connection now */ @@ -3231,9 +3247,9 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, } if(conn->ssl[SECONDARYSOCKET].use) { - /* The secondary socket is using SSL so we must close down that part - first before we close the socket for real */ - Curl_ssl_close(conn, SECONDARYSOCKET); + /* The secondary socket used SSL so we must close down that part first + before we close the socket for real */ + result = Curl_ssl_shutdown(conn, SECONDARYSOCKET); /* Note that we keep "use" set to TRUE since that (next) connection is still requested to use SSL */ @@ -3249,7 +3265,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, * data has been transferred. This happens when doing through NATs etc that * abandon old silent connections. */ - long old_time = pp->response_time; + timediff_t old_time = pp->response_time; pp->response_time = 60*1000; /* give it only a minute for now */ pp->response = Curl_now(); /* timeout relative now */ @@ -3442,7 +3458,7 @@ static CURLcode ftp_nb_type(struct connectdata *conn, #ifndef CURL_DISABLE_VERBOSE_STRINGS static void ftp_pasv_verbose(struct connectdata *conn, - Curl_addrinfo *ai, + struct Curl_addrinfo *ai, char *newhost, /* ascii version */ int port) { @@ -3500,6 +3516,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) } } +#ifndef CURL_DISABLE_PROXY result = Curl_proxy_connect(conn, SECONDARYSOCKET); if(result) return result; @@ -3510,7 +3527,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) if(conn->bits.tunnel_proxy && conn->bits.httpproxy && Curl_connect_ongoing(conn)) return result; - +#endif if(ftpc->state) { /* already in a state so skip the initial commands. @@ -4338,7 +4355,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn) char command; *type = 0; /* it was in the middle of the hostname */ command = Curl_raw_toupper(type[6]); - conn->bits.type_set = TRUE; switch(command) { case 'A': /* ASCII mode */ diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h index 984347f..06421c6 100644 --- a/Utilities/cmcurl/lib/ftp.h +++ b/Utilities/cmcurl/lib/ftp.h @@ -150,7 +150,6 @@ struct ftp_conn { connection to */ char *newhost; /* this is the pair to connect the DATA... */ unsigned short newport; /* connection to */ - }; #define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */ diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c index 2b8f230..6d5bd5f 100644 --- a/Utilities/cmcurl/lib/getinfo.c +++ b/Utilities/cmcurl/lib/getinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -147,6 +147,33 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, long *to_long; } lptr; +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_LOCAL_PORT: + *param_longp = (long)val; + return CURLE_OK; + default: + break; + } + } + /* use another variable for this to allow different values */ + timestr = getenv("CURL_DEBUG_SIZE"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_HEADER_SIZE: + case CURLINFO_REQUEST_SIZE: + *param_longp = (long)val; + return CURLE_OK; + default: + break; + } + } +#endif + switch(info) { case CURLINFO_RESPONSE_CODE: *param_longp = data->info.httpcode; @@ -171,9 +198,11 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, case CURLINFO_SSL_VERIFYRESULT: *param_longp = data->set.ssl.certverifyresult; break; +#ifndef CURL_DISABLE_PROXY case CURLINFO_PROXY_SSL_VERIFYRESULT: *param_longp = data->set.proxy_ssl.certverifyresult; break; +#endif case CURLINFO_REDIRECT_COUNT: *param_longp = data->set.followlocation; break; @@ -212,8 +241,11 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, *param_longp = data->info.conn_local_port; break; case CURLINFO_CONDITION_UNMET: - /* return if the condition prevented the document to get transferred */ - *param_longp = data->info.timecond ? 1L : 0L; + if(data->info.httpcode == 304) + *param_longp = 1L; + else + /* return if the condition prevented the document to get transferred */ + *param_longp = data->info.timecond ? 1L : 0L; break; case CURLINFO_RTSP_CLIENT_CSEQ: *param_longp = data->state.rtsp_next_client_CSeq; @@ -258,6 +290,27 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, curl_off_t *param_offt) { +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_TOTAL_TIME_T: + case CURLINFO_NAMELOOKUP_TIME_T: + case CURLINFO_CONNECT_TIME_T: + case CURLINFO_APPCONNECT_TIME_T: + case CURLINFO_PRETRANSFER_TIME_T: + case CURLINFO_STARTTRANSFER_TIME_T: + case CURLINFO_REDIRECT_TIME_T: + case CURLINFO_SPEED_DOWNLOAD_T: + case CURLINFO_SPEED_UPLOAD_T: + *param_offt = (curl_off_t)val; + return CURLE_OK; + default: + break; + } + } +#endif switch(info) { case CURLINFO_FILETIME_T: *param_offt = (curl_off_t)data->info.filetime; @@ -269,7 +322,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, *param_offt = data->progress.downloaded; break; case CURLINFO_SPEED_DOWNLOAD_T: - *param_offt = data->progress.dlspeed; + *param_offt = data->progress.dlspeed; break; case CURLINFO_SPEED_UPLOAD_T: *param_offt = data->progress.ulspeed; @@ -282,7 +335,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? data->progress.size_ul:-1; break; - case CURLINFO_TOTAL_TIME_T: + case CURLINFO_TOTAL_TIME_T: *param_offt = data->progress.timespent; break; case CURLINFO_NAMELOOKUP_TIME_T: @@ -316,6 +369,27 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, double *param_doublep) { +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_TOTAL_TIME: + case CURLINFO_NAMELOOKUP_TIME: + case CURLINFO_CONNECT_TIME: + case CURLINFO_APPCONNECT_TIME: + case CURLINFO_PRETRANSFER_TIME: + case CURLINFO_STARTTRANSFER_TIME: + case CURLINFO_REDIRECT_TIME: + case CURLINFO_SPEED_DOWNLOAD: + case CURLINFO_SPEED_UPLOAD: + *param_doublep = (double)val; + return CURLE_OK; + default: + break; + } + } +#endif switch(info) { case CURLINFO_TOTAL_TIME: *param_doublep = DOUBLE_SECS(data->progress.timespent); @@ -336,13 +410,13 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer); break; case CURLINFO_SIZE_UPLOAD: - *param_doublep = (double)data->progress.uploaded; + *param_doublep = (double)data->progress.uploaded; break; case CURLINFO_SIZE_DOWNLOAD: *param_doublep = (double)data->progress.downloaded; break; case CURLINFO_SPEED_DOWNLOAD: - *param_doublep = (double)data->progress.dlspeed; + *param_doublep = (double)data->progress.dlspeed; break; case CURLINFO_SPEED_UPLOAD: *param_doublep = (double)data->progress.ulspeed; diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c index b296c62..c48098f 100644 --- a/Utilities/cmcurl/lib/gopher.c +++ b/Utilities/cmcurl/lib/gopher.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,6 +28,7 @@ #include <curl/curl.h> #include "transfer.h" #include "sendf.h" +#include "connect.h" #include "progress.h" #include "gopher.h" #include "select.h" @@ -83,8 +84,10 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) char *query = data->state.up.query; char *sel = NULL; char *sel_org = NULL; + timediff_t timeout_ms; ssize_t amount, k; size_t len; + int what; *done = TRUE; /* unconditionally */ @@ -139,19 +142,29 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) else break; + timeout_ms = Curl_timeleft(conn->data, NULL, FALSE); + if(timeout_ms < 0) { + result = CURLE_OPERATION_TIMEDOUT; + break; + } + if(!timeout_ms) + timeout_ms = TIMEDIFF_T_MAX; + /* Don't busyloop. The entire loop thing is a work-around as it causes a BLOCKING behavior which is a NO-NO. This function should rather be split up in a do and a doing piece where the pieces that aren't possible to send now will be sent in the doing function repeatedly until the entire request is sent. - - Wait a while for the socket to be writable. Note that this doesn't - acknowledge the timeout. */ - if(SOCKET_WRITABLE(sockfd, 100) < 0) { + what = SOCKET_WRITABLE(sockfd, timeout_ms); + if(what < 0) { result = CURLE_SEND_ERROR; break; } + else if(!what) { + result = CURLE_OPERATION_TIMEDOUT; + break; + } } free(sel_org); diff --git a/Utilities/cmcurl/lib/hmac.c b/Utilities/cmcurl/lib/hmac.c index ae68827..e4fea8a 100644 --- a/Utilities/cmcurl/lib/hmac.c +++ b/Utilities/cmcurl/lib/hmac.c @@ -48,13 +48,13 @@ static const unsigned char hmac_opad = 0x5C; -HMAC_context * -Curl_HMAC_init(const HMAC_params * hashparams, +struct HMAC_context * +Curl_HMAC_init(const struct HMAC_params *hashparams, const unsigned char *key, unsigned int keylen) { size_t i; - HMAC_context *ctxt; + struct HMAC_context *ctxt; unsigned char *hkey; unsigned char b; @@ -101,7 +101,7 @@ Curl_HMAC_init(const HMAC_params * hashparams, return ctxt; } -int Curl_HMAC_update(HMAC_context * ctxt, +int Curl_HMAC_update(struct HMAC_context *ctxt, const unsigned char *data, unsigned int len) { @@ -111,9 +111,9 @@ int Curl_HMAC_update(HMAC_context * ctxt, } -int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result) +int Curl_HMAC_final(struct HMAC_context *ctxt, unsigned char *result) { - const HMAC_params * hashparams = ctxt->hmac_hash; + const struct HMAC_params *hashparams = ctxt->hmac_hash; /* Do not get result if called with a null parameter: only release storage. */ @@ -147,12 +147,13 @@ int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result) * * Returns CURLE_OK on success. */ -CURLcode Curl_hmacit(const HMAC_params *hashparams, +CURLcode Curl_hmacit(const struct HMAC_params *hashparams, const unsigned char *key, const size_t keylen, const unsigned char *data, const size_t datalen, unsigned char *output) { - HMAC_context *ctxt = Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen)); + struct HMAC_context *ctxt = + Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen)); if(!ctxt) return CURLE_OUT_OF_MEMORY; diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c index 99d872b..ed9190f 100644 --- a/Utilities/cmcurl/lib/hostasyn.c +++ b/Utilities/cmcurl/lib/hostasyn.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -117,10 +117,10 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, * name resolve layers (selected at build-time). They all take this same set * of arguments */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { return Curl_resolver_getaddrinfo(conn, hostname, port, waitp); } diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c index c0feb79..dd5916e 100644 --- a/Utilities/cmcurl/lib/hostip.c +++ b/Utilities/cmcurl/lib/hostip.c @@ -120,7 +120,7 @@ static void freednsentry(void *freethis); /* * Return # of addresses in a Curl_addrinfo struct */ -int Curl_num_addresses(const Curl_addrinfo *addr) +int Curl_num_addresses(const struct Curl_addrinfo *addr) { int i = 0; while(addr) { @@ -131,39 +131,36 @@ int Curl_num_addresses(const Curl_addrinfo *addr) } /* - * Curl_printable_address() returns a printable version of the 1st address + * Curl_printable_address() stores a printable version of the 1st address * given in the 'ai' argument. The result will be stored in the buf that is * bufsize bytes big. * - * If the conversion fails, it returns NULL. + * If the conversion fails, the target buffer is empty. */ -const char * -Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize) +void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf, + size_t bufsize) { - const struct sockaddr_in *sa4; - const struct in_addr *ipaddr4; -#ifdef ENABLE_IPV6 - const struct sockaddr_in6 *sa6; - const struct in6_addr *ipaddr6; -#endif + DEBUGASSERT(bufsize); + buf[0] = 0; switch(ai->ai_family) { - case AF_INET: - sa4 = (const void *)ai->ai_addr; - ipaddr4 = &sa4->sin_addr; - return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, - bufsize); + case AF_INET: { + const struct sockaddr_in *sa4 = (const void *)ai->ai_addr; + const struct in_addr *ipaddr4 = &sa4->sin_addr; + (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize); + break; + } #ifdef ENABLE_IPV6 - case AF_INET6: - sa6 = (const void *)ai->ai_addr; - ipaddr6 = &sa6->sin6_addr; - return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, - bufsize); + case AF_INET6: { + const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr; + const struct in6_addr *ipaddr6 = &sa6->sin6_addr; + (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize); + break; + } #endif - default: - break; + default: + break; } - return NULL; } /* @@ -337,7 +334,7 @@ Curl_fetch_addr(struct connectdata *conn, #ifndef CURL_DISABLE_SHUFFLE_DNS UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, - Curl_addrinfo **addr); + struct Curl_addrinfo **addr); /* * Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo' * struct by re-linking its linked list. @@ -351,13 +348,13 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, * @unittest: 1608 */ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, - Curl_addrinfo **addr) + struct Curl_addrinfo **addr) { CURLcode result = CURLE_OK; const int num_addrs = Curl_num_addresses(*addr); if(num_addrs > 1) { - Curl_addrinfo **nodes; + struct Curl_addrinfo **nodes; infof(data, "Shuffling %i addresses", num_addrs); nodes = malloc(num_addrs*sizeof(*nodes)); @@ -376,7 +373,7 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, if(rnd) { /* Fisher-Yates shuffle */ if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) { - Curl_addrinfo *swap_tmp; + struct Curl_addrinfo *swap_tmp; for(i = num_addrs - 1; i > 0; i--) { swap_tmp = nodes[rnd[i] % (i + 1)]; nodes[rnd[i] % (i + 1)] = nodes[i]; @@ -415,7 +412,7 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, */ struct Curl_dns_entry * Curl_cache_addr(struct Curl_easy *data, - Curl_addrinfo *addr, + struct Curl_addrinfo *addr, const char *hostname, int port) { @@ -495,6 +492,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn, enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */ *entry = NULL; + conn->bits.doh = FALSE; /* default is not */ if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); @@ -513,11 +511,13 @@ enum resolve_t Curl_resolv(struct connectdata *conn, if(!dns) { /* The entry was not in the cache. Resolve it to IP address */ - Curl_addrinfo *addr = NULL; + struct Curl_addrinfo *addr = NULL; int respwait = 0; -#ifndef USE_RESOLVE_ON_IPS struct in_addr in; +#ifndef USE_RESOLVE_ON_IPS + const #endif + bool ipnum = FALSE; /* notify the resolver start callback */ if(data->set.resolver_start) { @@ -544,6 +544,22 @@ enum resolve_t Curl_resolv(struct connectdata *conn, addr = Curl_ip2addr(AF_INET6, &in6, hostname, port); } #endif /* ENABLE_IPV6 */ + +#else /* if USE_RESOLVE_ON_IPS */ + /* First check if this is an IPv4 address string */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) + /* This is a dotted IP address 123.123.123.123-style */ + ipnum = TRUE; +#ifdef ENABLE_IPV6 + else { + struct in6_addr in6; + /* check if this is an IPv6 address string */ + if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) + /* This is an IPv6 address literal */ + ipnum = TRUE; + } +#endif /* ENABLE_IPV6 */ + #endif /* !USE_RESOLVE_ON_IPS */ if(!addr) { @@ -552,7 +568,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn, if(!Curl_ipvalid(conn)) return CURLRESOLV_ERROR; - if(allowDOH && data->set.doh) { + if(allowDOH && data->set.doh && !ipnum) { addr = Curl_doh(conn, hostname, port, &respwait); } else { @@ -890,7 +906,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) } else { struct Curl_dns_entry *dns; - Curl_addrinfo *head = NULL, *tail = NULL; + struct Curl_addrinfo *head = NULL, *tail = NULL; size_t entry_len; char address[64]; #if !defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -924,7 +940,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) while(*end_ptr) { size_t alen; - Curl_addrinfo *ai; + struct Curl_addrinfo *ai; addr_begin = end_ptr + 1; addr_end = strchr(addr_begin, ','); @@ -1047,7 +1063,7 @@ CURLcode Curl_resolv_check(struct connectdata *conn, (void)dns; #endif - if(conn->data->set.doh) + if(conn->bits.doh) return Curl_doh_is_resolved(conn, dns); return Curl_resolver_is_resolved(conn, dns); } @@ -1056,7 +1072,7 @@ int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *socks) { #ifdef CURLRES_ASYNCH - if(conn->data->set.doh) + if(conn->bits.doh) /* nothing to wait for during DOH resolve, those handles have their own sockets */ return GETSOCK_BLANK; @@ -1085,10 +1101,12 @@ CURLcode Curl_once_resolved(struct connectdata *conn, result = Curl_setup_conn(conn, protocol_done); - if(result) - /* We're not allowed to return failure with memory left allocated - in the connectdata struct, free those here */ - Curl_disconnect(conn->data, conn, TRUE); /* close the connection */ - + if(result) { + struct Curl_easy *data = conn->data; + DEBUGASSERT(data); + Curl_detach_connnection(data); + Curl_conncache_remove_conn(data, conn, TRUE); + Curl_disconnect(data, conn, TRUE); + } return result; } diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h index baf1e58..374b06c 100644 --- a/Utilities/cmcurl/lib/hostip.h +++ b/Utilities/cmcurl/lib/hostip.h @@ -64,7 +64,7 @@ struct connectdata; struct curl_hash *Curl_global_host_cache_init(void); struct Curl_dns_entry { - Curl_addrinfo *addr; + struct Curl_addrinfo *addr; /* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */ time_t timestamp; /* use-counter, use Curl_resolv_unlock to release reference */ @@ -117,10 +117,10 @@ bool Curl_ipvalid(struct connectdata *conn); * name resolve layers (selected at build-time). They all take this same set * of arguments */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp); +struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp); /* unlock a previously resolved dns entry */ @@ -134,7 +134,7 @@ int Curl_mk_dnscache(struct curl_hash *hash); void Curl_hostcache_prune(struct Curl_easy *data); /* Return # of addresses in a Curl_addrinfo struct */ -int Curl_num_addresses(const Curl_addrinfo *addr); +int Curl_num_addresses(const struct Curl_addrinfo *addr); #if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, @@ -146,7 +146,7 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, #endif /* IPv4 threadsafe resolve function used for synch and asynch builds */ -Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port); +struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port); CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect); @@ -158,15 +158,15 @@ CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect); */ CURLcode Curl_addrinfo_callback(struct connectdata *conn, int status, - Curl_addrinfo *ai); + struct Curl_addrinfo *ai); /* * Curl_printable_address() returns a printable version of the 1st address * given in the 'ip' argument. The result will be stored in the buf that is * bufsize bytes big. */ -const char *Curl_printable_address(const Curl_addrinfo *ip, - char *buf, size_t bufsize); +void Curl_printable_address(const struct Curl_addrinfo *ip, + char *buf, size_t bufsize); /* * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. @@ -187,7 +187,7 @@ Curl_fetch_addr(struct connectdata *conn, * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * -Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr, +Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, const char *hostname, int port); #ifndef INADDR_NONE diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c index d5009a3..eae9416 100644 --- a/Utilities/cmcurl/lib/hostip4.c +++ b/Utilities/cmcurl/lib/hostip4.c @@ -88,12 +88,12 @@ bool Curl_ipvalid(struct connectdata *conn) * flavours have thread-safe versions of the plain gethostbyname() etc. * */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { - Curl_addrinfo *ai = NULL; + struct Curl_addrinfo *ai = NULL; #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)conn; @@ -119,13 +119,13 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, * implying that only threadsafe code and function calls may be used. * */ -Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, - int port) +struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, + int port) { #if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3) int res; #endif - Curl_addrinfo *ai = NULL; + struct Curl_addrinfo *ai = NULL; struct hostent *h = NULL; struct hostent *buf = NULL; diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c index 41ff986..1121575 100644 --- a/Utilities/cmcurl/lib/hostip6.c +++ b/Utilities/cmcurl/lib/hostip6.c @@ -103,20 +103,16 @@ bool Curl_ipvalid(struct connectdata *conn) #if defined(CURLRES_SYNCH) #ifdef DEBUG_ADDRINFO -static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) +static void dump_addrinfo(struct connectdata *conn, + const struct Curl_addrinfo *ai) { printf("dump_addrinfo:\n"); for(; ai; ai = ai->ai_next) { char buf[INET6_ADDRSTRLEN]; printf(" fam %2d, CNAME %s, ", ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>"); - if(Curl_printable_address(ai, buf, sizeof(buf))) - printf("%s\n", buf); - else { - char buffer[STRERROR_LEN]; - printf("failed; %s\n", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); - } + Curl_printable_address(ai, buf, sizeof(buf)); + printf("%s\n", buf); } } #else @@ -132,13 +128,13 @@ static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { struct addrinfo hints; - Curl_addrinfo *res; + struct Curl_addrinfo *res; int error; char sbuf[12]; char *sbufptr = NULL; diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index bff3adc..482f9ad 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -292,12 +292,16 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) char *out; if(proxy) { - userp = &conn->allocptr.proxyuserpwd; +#ifndef CURL_DISABLE_PROXY + userp = &data->state.aptr.proxyuserpwd; user = conn->http_proxy.user; pwd = conn->http_proxy.passwd; +#else + return CURLE_NOT_BUILT_IN; +#endif } else { - userp = &conn->allocptr.userpwd; + userp = &data->state.aptr.userpwd; user = conn->user; pwd = conn->passwd; } @@ -340,8 +344,9 @@ static CURLcode http_output_bearer(struct connectdata *conn) { char **userp; CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; - userp = &conn->allocptr.userpwd; + userp = &data->state.aptr.userpwd; free(*userp); *userp = aprintf("Authorization: Bearer %s\r\n", conn->data->set.str[STRING_BEARER]); @@ -427,7 +432,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) skip this rewinding stuff */ return CURLE_OK; - switch(data->set.httpreq) { + switch(data->state.httpreq) { case HTTPREQ_GET: case HTTPREQ_HEAD: return CURLE_OK; @@ -448,7 +453,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) } else { /* figure out how much data we are expected to send */ - switch(data->set.httpreq) { + switch(data->state.httpreq) { case HTTPREQ_POST: case HTTPREQ_PUT: if(data->state.infilesize != -1) @@ -578,6 +583,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) conn->data->set.httpversion = CURL_HTTP_VERSION_1_1; } } +#ifndef CURL_DISABLE_PROXY if(conn->bits.proxy_user_passwd && ((data->req.httpcode == 407) || (conn->bits.authneg && data->req.httpcode < 300))) { @@ -586,10 +592,11 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) if(!pickproxy) data->state.authproblem = TRUE; } +#endif if(pickhost || pickproxy) { - if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD) && + if((data->state.httpreq != HTTPREQ_GET) && + (data->state.httpreq != HTTPREQ_HEAD) && !conn->bits.rewindaftersend) { result = http_perhapsrewind(conn); if(result) @@ -610,8 +617,8 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) authentication is not "done" yet and no authentication seems to be required and we didn't try HEAD or GET */ - if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD)) { + if((data->state.httpreq != HTTPREQ_GET) && + (data->state.httpreq != HTTPREQ_HEAD)) { data->req.newurl = strdup(data->change.url); /* clone URL */ if(!data->req.newurl) return CURLE_OUT_OF_MEMORY; @@ -689,10 +696,13 @@ output_auth_headers(struct connectdata *conn, #endif if(authstatus->picked == CURLAUTH_BASIC) { /* Basic */ - if((proxy && conn->bits.proxy_user_passwd && - !Curl_checkProxyheaders(conn, "Proxy-authorization")) || - (!proxy && conn->bits.user_passwd && - !Curl_checkheaders(conn, "Authorization"))) { + if( +#ifndef CURL_DISABLE_PROXY + (proxy && conn->bits.proxy_user_passwd && + !Curl_checkProxyheaders(conn, "Proxy-authorization")) || +#endif + (!proxy && conn->bits.user_passwd && + !Curl_checkheaders(conn, "Authorization"))) { auth = "Basic"; result = http_output_basic(conn, proxy); if(result) @@ -719,10 +729,15 @@ output_auth_headers(struct connectdata *conn, } if(auth) { +#ifndef CURL_DISABLE_PROXY infof(data, "%s auth using %s with user '%s'\n", proxy ? "Proxy" : "Server", auth, proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") : - (conn->user ? conn->user : "")); + (conn->user ? conn->user : "")); +#else + infof(data, "Server auth using %s with user '%s'\n", + auth, conn->user ? conn->user : ""); +#endif authstatus->multipass = (!authstatus->done) ? TRUE : FALSE; } else @@ -762,7 +777,10 @@ Curl_http_output_auth(struct connectdata *conn, authhost = &data->state.authhost; authproxy = &data->state.authproxy; - if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || + if( +#ifndef CURL_DISABLE_PROXY + (conn->bits.httpproxy && conn->bits.proxy_user_passwd) || +#endif conn->bits.user_passwd || data->set.str[STRING_BEARER]) /* continue please */; else { @@ -1067,8 +1085,10 @@ static int http_should_fail(struct connectdata *conn) */ if((httpcode == 401) && !conn->bits.user_passwd) return TRUE; +#ifndef CURL_DISABLE_PROXY if((httpcode == 407) && !conn->bits.proxy_user_passwd) return TRUE; +#endif return data->state.authproblem; } @@ -1125,49 +1145,20 @@ static size_t readmoredata(char *buffer, return fullsize; } -/* ------------------------------------------------------------------------- */ -/* add_buffer functions */ - -/* - * Curl_add_buffer_init() sets up and returns a fine buffer struct - */ -Curl_send_buffer *Curl_add_buffer_init(void) -{ - return calloc(1, sizeof(Curl_send_buffer)); -} - -/* - * Curl_add_buffer_free() frees all associated resources. - */ -void Curl_add_buffer_free(Curl_send_buffer **inp) -{ - Curl_send_buffer *in; - if(!inp) - return; - in = *inp; - if(in) { /* deal with NULL input */ - free(in->buffer); - free(in); - } - *inp = NULL; -} - /* - * Curl_add_buffer_send() sends a header buffer and frees all associated + * Curl_buffer_send() sends a header buffer and frees all associated * memory. Body data may be appended to the header data if desired. * * Returns CURLcode */ -CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, - struct connectdata *conn, - - /* add the number of sent bytes to this - counter */ - curl_off_t *bytes_written, - - /* how much of the buffer contains body data */ - size_t included_body_bytes, - int socketindex) +CURLcode Curl_buffer_send(struct dynbuf *in, + struct connectdata *conn, + /* add the number of sent bytes to this + counter */ + curl_off_t *bytes_written, + /* how much of the buffer contains body data */ + size_t included_body_bytes, + int socketindex) { ssize_t amount; CURLcode result; @@ -1178,7 +1169,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, size_t sendsize; curl_socket_t sockfd; size_t headersize; - Curl_send_buffer *in = *inp; DEBUGASSERT(socketindex <= SECONDARYSOCKET); @@ -1187,8 +1177,8 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, /* The looping below is required since we use non-blocking sockets, but due to the circumstances we will just loop and try again and again etc */ - ptr = in->buffer; - size = in->size_used; + ptr = Curl_dyn_ptr(in); + size = Curl_dyn_len(in); headersize = size - included_body_bytes; /* the initial part that isn't body is header */ @@ -1199,12 +1189,15 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, /* Curl_convert_to_network calls failf if unsuccessful */ if(result) { /* conversion failed, free memory and return to the caller */ - Curl_add_buffer_free(inp); + Curl_dyn_free(in); return result; } - if((conn->handler->flags & PROTOPT_SSL || - conn->http_proxy.proxytype == CURLPROXY_HTTPS) + if((conn->handler->flags & PROTOPT_SSL +#ifndef CURL_DISABLE_PROXY + || conn->http_proxy.proxytype == CURLPROXY_HTTPS +#endif + ) && conn->httpversion != 20) { /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk when we speak HTTPS, as if only a fraction of it is sent now, this data @@ -1223,14 +1216,27 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, result = Curl_get_upload_buffer(data); if(result) { /* malloc failed, free memory and return to the caller */ - Curl_add_buffer_free(&in); + Curl_dyn_free(in); return result; } memcpy(data->state.ulbuf, ptr, sendsize); ptr = data->state.ulbuf; } - else + else { +#ifdef CURLDEBUG + /* Allow debug builds override this logic to force short initial sends */ + char *p = getenv("CURL_SMALLREQSEND"); + if(p) { + size_t altsize = (size_t)strtoul(p, NULL, 10); + if(altsize) + sendsize = CURLMIN(size, altsize); + else + sendsize = size; + } + else +#endif sendsize = size; + } result = Curl_write(conn, sockfd, ptr, sendsize, &amount); @@ -1273,7 +1279,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, size -= amount; - ptr = in->buffer + amount; + ptr = Curl_dyn_ptr(in) + amount; /* backup the currently set pointers */ http->backup.fread_func = data->state.fread_func; @@ -1287,7 +1293,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, http->postdata = ptr; http->postsize = (curl_off_t)size; - http->send_buffer = in; + http->send_buffer = *in; /* copy the whole struct */ http->sending = HTTPSEND_REQUEST; return CURLE_OK; @@ -1307,92 +1313,11 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, return CURLE_SEND_ERROR; } } - Curl_add_buffer_free(&in); + Curl_dyn_free(in); return result; } - -/* - * add_bufferf() add the formatted input to the buffer. - */ -CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) -{ - char *s; - va_list ap; - Curl_send_buffer *in = *inp; - va_start(ap, fmt); - s = vaprintf(fmt, ap); /* this allocs a new string to append */ - va_end(ap); - - if(s) { - CURLcode result = Curl_add_buffer(inp, s, strlen(s)); - free(s); - return result; - } - /* If we failed, we cleanup the whole buffer and return error */ - free(in->buffer); - free(in); - *inp = NULL; - return CURLE_OUT_OF_MEMORY; -} - -/* - * Curl_add_buffer() appends a memory chunk to the existing buffer - */ -CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, - size_t size) -{ - char *new_rb; - Curl_send_buffer *in = *inp; - - if(~size < in->size_used) { - /* If resulting used size of send buffer would wrap size_t, cleanup - the whole buffer and return error. Otherwise the required buffer - size will fit into a single allocatable memory chunk */ - Curl_safefree(in->buffer); - free(in); - *inp = NULL; - return CURLE_OUT_OF_MEMORY; - } - - if(!in->buffer || - ((in->size_used + size) > (in->size_max - 1))) { - /* If current buffer size isn't enough to hold the result, use a - buffer size that doubles the required size. If this new size - would wrap size_t, then just use the largest possible one */ - size_t new_size; - - if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) || - (~(size * 2) < (in->size_used * 2))) - new_size = (size_t)-1; - else - new_size = (in->size_used + size) * 2; - - if(in->buffer) - /* we have a buffer, enlarge the existing one */ - new_rb = Curl_saferealloc(in->buffer, new_size); - else - /* create a new buffer */ - new_rb = malloc(new_size); - - if(!new_rb) { - /* If we failed, we cleanup the whole buffer and return error */ - free(in); - *inp = NULL; - return CURLE_OUT_OF_MEMORY; - } - - in->buffer = new_rb; - in->size_max = new_size; - } - memcpy(&in->buffer[in->size_used], inptr, size); - - in->size_used += size; - - return CURLE_OK; -} - /* end of the add_buffer functions */ /* ------------------------------------------------------------------------- */ @@ -1465,6 +1390,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) function to make the re-use checks properly be able to check this bit. */ connkeep(conn, "HTTP default"); +#ifndef CURL_DISABLE_PROXY /* the CONNECT procedure might not have been completed */ result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) @@ -1481,7 +1407,6 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; -#ifndef CURL_DISABLE_PROXY if(conn->data->set.haproxyprotocol) { /* add HAProxy PROXY protocol header */ result = add_haproxy_protocol_header(conn); @@ -1517,7 +1442,7 @@ static int http_getsock_do(struct connectdata *conn, static CURLcode add_haproxy_protocol_header(struct connectdata *conn) { char proxy_header[128]; - Curl_send_buffer *req_buffer; + struct dynbuf req; CURLcode result; char tcp_version[5]; @@ -1538,19 +1463,14 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn) conn->data->info.conn_local_port, conn->data->info.conn_primary_port); - req_buffer = Curl_add_buffer_init(); - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&req, DYN_HAXPROXY); - result = Curl_add_bufferf(&req_buffer, proxy_header); + result = Curl_dyn_add(&req, proxy_header); if(result) return result; - result = Curl_add_buffer_send(&req_buffer, - conn, - &conn->data->info.request_size, - 0, - FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &conn->data->info.request_size, + 0, FIRSTSOCKET); return result; } @@ -1611,14 +1531,11 @@ CURLcode Curl_http_done(struct connectdata *conn, if(!http) return CURLE_OK; - if(http->send_buffer) { - Curl_add_buffer_free(&http->send_buffer); - } - + Curl_dyn_free(&http->send_buffer); Curl_http2_done(data, premature); Curl_quic_done(data, premature); - Curl_mime_cleanpart(&http->form); + Curl_dyn_reset(&data->state.headerb); if(status) return status; @@ -1684,7 +1601,7 @@ static const char *get_http_string(const struct Curl_easy *data, /* check and possibly add an Expect: header */ static CURLcode expect100(struct Curl_easy *data, struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { CURLcode result = CURLE_OK; data->state.expect100header = FALSE; /* default to false unless it is set @@ -1700,8 +1617,7 @@ static CURLcode expect100(struct Curl_easy *data, Curl_compareheader(ptr, "Expect:", "100-continue"); } else { - result = Curl_add_bufferf(&req_buffer, - "Expect: 100-continue\r\n"); + result = Curl_dyn_add(req, "Expect: 100-continue\r\n"); if(!result) data->state.expect100header = TRUE; } @@ -1720,7 +1636,7 @@ enum proxy_use { will return an error code if one of the headers is not formatted correctly */ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, - Curl_send_buffer **buffer, + struct dynbuf *b, struct Curl_easy *handle) { char *ptr = NULL; @@ -1746,8 +1662,10 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, /* only add correctly formatted trailers */ ptr = strchr(trailers->data, ':'); if(ptr && *(ptr + 1) == ' ') { - result = Curl_add_bufferf(buffer, "%s%s", trailers->data, - endofline_native); + result = Curl_dyn_add(b, trailers->data); + if(result) + return result; + result = Curl_dyn_add(b, endofline_native); if(result) return result; } @@ -1755,14 +1673,13 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, infof(handle, "Malformatted trailing header ! Skipping trailer."); trailers = trailers->next; } - result = Curl_add_buffer(buffer, endofline_network, - strlen(endofline_network)); + result = Curl_dyn_add(b, endofline_network); return result; } CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { char *ptr; struct curl_slist *h[2]; @@ -1771,6 +1688,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, struct Curl_easy *data = conn->data; int i; +#ifndef CURL_DISABLE_PROXY enum proxy_use proxy; if(is_connect) @@ -1797,6 +1715,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, h[0] = data->set.headers; break; } +#else + (void)is_connect; + h[0] = data->set.headers; +#endif /* loop through one or two lists */ for(i = 0; i < numlists; i++) { @@ -1824,7 +1746,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, /* copy the source */ semicolonp = strdup(headers->data); if(!semicolonp) { - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(req); return CURLE_OUT_OF_MEMORY; } /* put a colon where the semicolon is */ @@ -1848,16 +1770,16 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, CURLcode result = CURLE_OK; char *compare = semicolonp ? semicolonp : headers->data; - if(conn->allocptr.host && + if(data->state.aptr.host && /* a Host: header was sent already, don't pass on any custom Host: header as that will produce *two* in the same request! */ checkprefix("Host:", compare)) ; - else if(data->set.httpreq == HTTPREQ_POST_FORM && + else if(data->state.httpreq == HTTPREQ_POST_FORM && /* this header (extended by formdata.c) is sent later */ checkprefix("Content-Type:", compare)) ; - else if(data->set.httpreq == HTTPREQ_POST_MIME && + else if(data->state.httpreq == HTTPREQ_POST_MIME && /* this header is sent later */ checkprefix("Content-Type:", compare)) ; @@ -1866,7 +1788,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, we will force length zero then */ checkprefix("Content-Length:", compare)) ; - else if(conn->allocptr.te && + else if(data->state.aptr.te && /* when asking for Transfer-Encoding, don't pass on a custom Connection: */ checkprefix("Connection:", compare)) @@ -1885,7 +1807,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, !strcasecompare(data->state.first_host, conn->host.name))) ; else { - result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare); + result = Curl_dyn_addf(req, "%s\r\n", compare); } if(semicolonp) free(semicolonp); @@ -1902,7 +1824,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, #ifndef CURL_DISABLE_PARSEDATE CURLcode Curl_add_timecondition(const struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { struct Curl_easy *data = conn->data; const struct tm *tm; @@ -1961,17 +1883,17 @@ CURLcode Curl_add_timecondition(const struct connectdata *conn, tm->tm_min, tm->tm_sec); - result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr)); + result = Curl_dyn_add(req, datestr); return result; } #else /* disabled */ CURLcode Curl_add_timecondition(const struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { (void)conn; - (void)req_buffer; + (void)req; return CURLE_OK; } #endif @@ -1994,13 +1916,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) const char *te = ""; /* transfer-encoding */ const char *ptr; const char *request; - Curl_HttpReq httpreq = data->set.httpreq; + Curl_HttpReq httpreq = data->state.httpreq; #if !defined(CURL_DISABLE_COOKIES) char *addcookies = NULL; #endif curl_off_t included_body = 0; const char *httpstring; - Curl_send_buffer *req_buffer; + struct dynbuf req; curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ char *altused = NULL; @@ -2028,13 +1950,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) #ifdef USE_NGHTTP2 if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { +#ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* We don't support HTTP/2 proxies yet. Also it's debatable whether or not this setting should apply to HTTP/2 proxies. */ infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n"); break; } - +#endif DEBUGF(infof(data, "HTTP/2 over clean TCP\n")); conn->httpversion = 20; @@ -2108,8 +2031,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) with the user-agent string specified, we erase the previously made string here. */ if(Curl_checkheaders(conn, "User-Agent")) { - free(conn->allocptr.uagent); - conn->allocptr.uagent = NULL; + free(data->state.aptr.uagent); + data->state.aptr.uagent = NULL; } /* setup the authentication headers */ @@ -2137,14 +2060,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else conn->bits.authneg = FALSE; - Curl_safefree(conn->allocptr.ref); + Curl_safefree(data->state.aptr.ref); if(data->change.referer && !Curl_checkheaders(conn, "Referer")) { - conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); - if(!conn->allocptr.ref) + data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer); + if(!data->state.aptr.ref) return CURLE_OUT_OF_MEMORY; } else - conn->allocptr.ref = NULL; + data->state.aptr.ref = NULL; #if !defined(CURL_DISABLE_COOKIES) if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie")) @@ -2153,15 +2076,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!Curl_checkheaders(conn, "Accept-Encoding") && data->set.str[STRING_ENCODING]) { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = + Curl_safefree(data->state.aptr.accept_encoding); + data->state.aptr.accept_encoding = aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); - if(!conn->allocptr.accept_encoding) + if(!data->state.aptr.accept_encoding) return CURLE_OUT_OF_MEMORY; } else { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = NULL; + Curl_safefree(data->state.aptr.accept_encoding); + data->state.aptr.accept_encoding = NULL; } #ifdef HAVE_LIBZ @@ -2177,7 +2100,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) char *cptr = Curl_checkheaders(conn, "Connection"); #define TE_HEADER "TE: gzip\r\n" - Curl_safefree(conn->allocptr.te); + Curl_safefree(data->state.aptr.te); if(cptr) { cptr = Curl_copy_header_value(cptr); @@ -2186,11 +2109,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } /* Create the (updated) Connection: header */ - conn->allocptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, + data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, cptr ? cptr : "", (cptr && *cptr) ? ", ":""); free(cptr); - if(!conn->allocptr.te) + if(!data->state.aptr.te) return CURLE_OUT_OF_MEMORY; } #endif @@ -2273,7 +2196,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) te = "Transfer-Encoding: chunked\r\n"; } - Curl_safefree(conn->allocptr.host); + Curl_safefree(data->state.aptr.host); ptr = Curl_checkheaders(conn, "Host"); if(ptr && (!data->state.this_is_a_follow || @@ -2308,19 +2231,19 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(colon) *colon = 0; /* The host must not include an embedded port number */ } - Curl_safefree(conn->allocptr.cookiehost); - conn->allocptr.cookiehost = cookiehost; + Curl_safefree(data->state.aptr.cookiehost); + data->state.aptr.cookiehost = cookiehost; } #endif if(strcmp("Host:", ptr)) { - conn->allocptr.host = aprintf("Host:%s\r\n", &ptr[5]); - if(!conn->allocptr.host) + data->state.aptr.host = aprintf("Host:%s\r\n", &ptr[5]); + if(!data->state.aptr.host) return CURLE_OUT_OF_MEMORY; } else /* when clearing the header */ - conn->allocptr.host = NULL; + data->state.aptr.host = NULL; } else { /* When building Host: headers, we must put the host name within @@ -2332,18 +2255,18 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (conn->remote_port == PORT_HTTP)) ) /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include the port number in the host string */ - conn->allocptr.host = aprintf("Host: %s%s%s\r\n", + data->state.aptr.host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"", host, conn->bits.ipv6_ip?"]":""); else - conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n", + data->state.aptr.host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"", host, conn->bits.ipv6_ip?"]":"", conn->remote_port); - if(!conn->allocptr.host) + if(!data->state.aptr.host) /* without Host: we can't make a nice request */ return CURLE_OUT_OF_MEMORY; } @@ -2424,7 +2347,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->set.prefer_ascii ? 'a' : 'i'); } } - if(conn->bits.user_passwd && !conn->bits.userpwd_in_url) + if(conn->bits.user_passwd) paste_ftp_userpwd = TRUE; } } @@ -2514,21 +2437,21 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && !Curl_checkheaders(conn, "Range")) { /* if a line like this was already allocated, free the previous one */ - free(conn->allocptr.rangeline); - conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", + free(data->state.aptr.rangeline); + data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n", data->state.range); } else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && !Curl_checkheaders(conn, "Content-Range")) { /* if a line like this was already allocated, free the previous one */ - free(conn->allocptr.rangeline); + free(data->state.aptr.rangeline); if(data->set.set_resume_from < 0) { /* Upload resume was asked for, but we don't know the size of the remote part so we tell the server (and act accordingly) that we upload the whole file (again) */ - conn->allocptr.rangeline = + data->state.aptr.rangeline = aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T "/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.infilesize - 1, data->state.infilesize); @@ -2538,7 +2461,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* This is because "resume" was selected */ curl_off_t total_expected_size = data->state.resume_from + data->state.infilesize; - conn->allocptr.rangeline = + data->state.aptr.rangeline = aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T "/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.range, total_expected_size-1, @@ -2547,11 +2470,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else { /* Range was selected and then we just pass the incoming range and append total size */ - conn->allocptr.rangeline = + data->state.aptr.rangeline = aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.range, data->state.infilesize); } - if(!conn->allocptr.rangeline) + if(!data->state.aptr.rangeline) return CURLE_OUT_OF_MEMORY; } } @@ -2559,14 +2482,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) httpstring = get_http_string(data, conn); /* initialize a dynamic send-buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&req, DYN_HTTP_REQUEST); /* add the main request stuff */ /* GET/HEAD/POST/PUT */ - result = Curl_add_bufferf(&req_buffer, "%s ", request); + result = Curl_dyn_addf(&req, "%s ", request); if(result) return result; @@ -2579,21 +2499,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* url */ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { char *url = data->set.str[STRING_TEMP_URL]; - result = Curl_add_buffer(&req_buffer, url, strlen(url)); + result = Curl_dyn_add(&req, url); Curl_safefree(data->set.str[STRING_TEMP_URL]); } else #endif if(paste_ftp_userpwd) - result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s", - conn->user, conn->passwd, - path + sizeof("ftp://") - 1); + result = Curl_dyn_addf(&req, "ftp://%s:%s@%s", conn->user, conn->passwd, + path + sizeof("ftp://") - 1); else { - result = Curl_add_buffer(&req_buffer, path, strlen(path)); + result = Curl_dyn_add(&req, path); if(result) return result; if(query) - result = Curl_add_bufferf(&req_buffer, "?%s", query); + result = Curl_dyn_addf(&req, "?%s", query); } if(result) return result; @@ -2602,59 +2521,65 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(conn->bits.altused && !Curl_checkheaders(conn, "Alt-Used")) { altused = aprintf("Alt-Used: %s:%d\r\n", conn->conn_to_host.name, conn->conn_to_port); - if(!altused) + if(!altused) { + Curl_dyn_free(&req); return CURLE_OUT_OF_MEMORY; + } } #endif result = - Curl_add_bufferf(&req_buffer, - "%s" /* ftp typecode (;type=x) */ - " HTTP/%s\r\n" /* HTTP version */ - "%s" /* host */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - "%s" /* range */ - "%s" /* user agent */ - "%s" /* accept */ - "%s" /* TE: */ - "%s" /* accept-encoding */ - "%s" /* referer */ - "%s" /* Proxy-Connection */ - "%s" /* transfer-encoding */ - "%s",/* Alt-Used */ - - ftp_typecode, - httpstring, - (conn->allocptr.host?conn->allocptr.host:""), - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - conn->allocptr.userpwd?conn->allocptr.userpwd:"", - (data->state.use_range && conn->allocptr.rangeline)? - conn->allocptr.rangeline:"", - (data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && - conn->allocptr.uagent)? - conn->allocptr.uagent:"", - http->p_accept?http->p_accept:"", - conn->allocptr.te?conn->allocptr.te:"", - (data->set.str[STRING_ENCODING] && - *data->set.str[STRING_ENCODING] && - conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)? - conn->allocptr.ref:"" /* Referer: <data> */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkProxyheaders(conn, "Proxy-Connection"))? - "Proxy-Connection: Keep-Alive\r\n":"", - te, - altused ? altused : "" + Curl_dyn_addf(&req, + "%s" /* ftp typecode (;type=x) */ + " HTTP/%s\r\n" /* HTTP version */ + "%s" /* host */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + "%s" /* range */ + "%s" /* user agent */ + "%s" /* accept */ + "%s" /* TE: */ + "%s" /* accept-encoding */ + "%s" /* referer */ + "%s" /* Proxy-Connection */ + "%s" /* transfer-encoding */ + "%s",/* Alt-Used */ + + ftp_typecode, + httpstring, + (data->state.aptr.host?data->state.aptr.host:""), + data->state.aptr.proxyuserpwd? + data->state.aptr.proxyuserpwd:"", + data->state.aptr.userpwd?data->state.aptr.userpwd:"", + (data->state.use_range && data->state.aptr.rangeline)? + data->state.aptr.rangeline:"", + (data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && + data->state.aptr.uagent)? + data->state.aptr.uagent:"", + http->p_accept?http->p_accept:"", + data->state.aptr.te?data->state.aptr.te:"", + (data->set.str[STRING_ENCODING] && + *data->set.str[STRING_ENCODING] && + data->state.aptr.accept_encoding)? + data->state.aptr.accept_encoding:"", + (data->change.referer && data->state.aptr.ref)? + data->state.aptr.ref:"" /* Referer: <data> */, +#ifndef CURL_DISABLE_PROXY + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkProxyheaders(conn, "Proxy-Connection"))? + "Proxy-Connection: Keep-Alive\r\n":"", +#else + "", +#endif + te, + altused ? altused : "" ); /* clear userpwd and proxyuserpwd to avoid re-using old credentials * from re-used connections */ - Curl_safefree(conn->allocptr.userpwd); - Curl_safefree(conn->allocptr.proxyuserpwd); + Curl_safefree(data->state.aptr.userpwd); + Curl_safefree(data->state.aptr.proxyuserpwd); free(altused); if(result) @@ -2665,7 +2590,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (data->set.httpversion == CURL_HTTP_VERSION_2)) { /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done over SSL */ - result = Curl_http2_request_upgrade(req_buffer, conn); + result = Curl_http2_request_upgrade(&req, conn); if(result) return result; } @@ -2678,8 +2603,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(data->cookies && data->state.cookie_engine) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); co = Curl_cookie_getlist(data->cookies, - conn->allocptr.cookiehost? - conn->allocptr.cookiehost:host, + data->state.aptr.cookiehost? + data->state.aptr.cookiehost:host, data->state.up.path, (conn->handler->protocol&CURLPROTO_HTTPS)? TRUE:FALSE); @@ -2691,13 +2616,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) while(co) { if(co->value) { if(0 == count) { - result = Curl_add_bufferf(&req_buffer, "Cookie: "); + result = Curl_dyn_add(&req, "Cookie: "); if(result) break; } - result = Curl_add_bufferf(&req_buffer, - "%s%s=%s", count?"; ":"", - co->name, co->value); + result = Curl_dyn_addf(&req, "%s%s=%s", count?"; ":"", + co->name, co->value); if(result) break; count++; @@ -2708,26 +2632,25 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(addcookies && !result) { if(!count) - result = Curl_add_bufferf(&req_buffer, "Cookie: "); + result = Curl_dyn_add(&req, "Cookie: "); if(!result) { - result = Curl_add_bufferf(&req_buffer, "%s%s", count?"; ":"", - addcookies); + result = Curl_dyn_addf(&req, "%s%s", count?"; ":"", addcookies); count++; } } if(count && !result) - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; } #endif - result = Curl_add_timecondition(conn, req_buffer); + result = Curl_add_timecondition(conn, &req); if(result) return result; - result = Curl_add_custom_headers(conn, FALSE, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, &req); if(result) return result; @@ -2750,20 +2673,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if((postsize != -1) && !data->req.upload_chunky && (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* only add Content-Length if not uploading chunked */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } if(postsize != 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers */ + /* end of headers */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; @@ -2771,8 +2694,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_pgrsSetUploadSize(data, postsize); /* this sends the buffer and frees all the buffer resources */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending PUT request"); else @@ -2788,12 +2711,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* This is form posting using mime data. */ if(conn->bits.authneg) { /* nothing to post! */ - result = Curl_add_bufferf(&req_buffer, "Content-Length: 0\r\n\r\n"); + result = Curl_dyn_add(&req, "Content-Length: 0\r\n\r\n"); if(result) return result; - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending POST request"); else @@ -2811,9 +2734,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } @@ -2824,7 +2747,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) struct curl_slist *hdr; for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) { - result = Curl_add_bufferf(&req_buffer, "%s\r\n", hdr->data); + result = Curl_dyn_addf(&req, "%s\r\n", hdr->data); if(result) return result; } @@ -2841,7 +2764,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_compareheader(ptr, "Expect:", "100-continue"); } else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } @@ -2849,7 +2772,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->state.expect100header = FALSE; /* make the request end in a true CRLF */ - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; @@ -2862,8 +2785,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; /* this sends the buffer and frees all the buffer resources */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending POST request"); else @@ -2891,17 +2814,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } if(!Curl_checkheaders(conn, "Content-Type")) { - result = Curl_add_bufferf(&req_buffer, - "Content-Type: application/" - "x-www-form-urlencoded\r\n"); + result = Curl_dyn_add(&req, "Content-Type: application/" + "x-www-form-urlencoded\r\n"); if(result) return result; } @@ -2916,7 +2837,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_compareheader(ptr, "Expect:", "100-continue"); } else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } @@ -2937,31 +2858,32 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) is no magic limit but only set to prevent really huge POSTs to get the data duplicated with malloc() and family. */ - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; if(!data->req.upload_chunky) { /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ - result = Curl_add_buffer(&req_buffer, data->set.postfields, - (size_t)postsize); + result = Curl_dyn_addn(&req, data->set.postfields, + (size_t)postsize); included_body = postsize; } else { if(postsize) { /* Append the POST data chunky-style */ - result = Curl_add_bufferf(&req_buffer, "%x\r\n", (int)postsize); + result = Curl_dyn_addf(&req, "%x\r\n", (int)postsize); if(!result) { - result = Curl_add_buffer(&req_buffer, data->set.postfields, - (size_t)postsize); + result = Curl_dyn_addn(&req, data->set.postfields, + (size_t)postsize); if(!result) - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); included_body = postsize + 2; } } if(!result) - result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); + result = Curl_dyn_add(&req, "\x30\x0d\x0a\x0d\x0a"); /* 0 CR LF CR LF */ included_body += 5; } @@ -2983,21 +2905,22 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, http->postsize); - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; } } else { - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; if(data->req.upload_chunky && conn->bits.authneg) { /* Chunky upload is selected and we're negotiating auth still, send end-of-data only */ - result = Curl_add_buffer(&req_buffer, - "\x30\x0d\x0a\x0d\x0a", 5); + result = Curl_dyn_add(&req, (char *)"\x30\x0d\x0a\x0d\x0a"); /* 0 CR LF CR LF */ if(result) return result; @@ -3017,8 +2940,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } /* issue the request */ - result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, - (size_t)included_body, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, + (size_t)included_body, FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP POST request"); @@ -3028,13 +2951,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) break; default: - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; /* issue the request */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP request"); @@ -3044,7 +2967,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(result) return result; - if(!postsize) + if(!postsize && (http->sending != HTTPSEND_REQUEST)) data->req.upload_done = TRUE; if(data->req.writebytecount) { @@ -3179,55 +3102,10 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, return checkhttpprefix(data, s, len); } -/* - * header_append() copies a chunk of data to the end of the already received - * header. We make sure that the full string fit in the allocated header - * buffer, or else we enlarge it. - */ -static CURLcode header_append(struct Curl_easy *data, - struct SingleRequest *k, - size_t length) -{ - /* length is at most the size of a full read buffer, for which the upper - bound is CURL_MAX_READ_SIZE. There is thus no chance of overflow in this - calculation. */ - size_t newsize = k->hbuflen + length; - if(newsize > CURL_MAX_HTTP_HEADER) { - /* The reason to have a max limit for this is to avoid the risk of a bad - server feeding libcurl with a never-ending header that will cause - reallocs infinitely */ - failf(data, "Rejected %zu bytes header (max is %d)!", newsize, - CURL_MAX_HTTP_HEADER); - return CURLE_OUT_OF_MEMORY; - } - if(newsize >= data->state.headersize) { - /* We enlarge the header buffer as it is too small */ - char *newbuff; - size_t hbufp_index; - - newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2); - hbufp_index = k->hbufp - data->state.headerbuff; - newbuff = realloc(data->state.headerbuff, newsize); - if(!newbuff) { - failf(data, "Failed to alloc memory for big header!"); - return CURLE_OUT_OF_MEMORY; - } - data->state.headersize = newsize; - data->state.headerbuff = newbuff; - k->hbufp = data->state.headerbuff + hbufp_index; - } - memcpy(k->hbufp, k->str_start, length); - k->hbufp += length; - k->hbuflen += length; - *k->hbufp = 0; - - return CURLE_OK; -} - static void print_http_error(struct Curl_easy *data) { struct SingleRequest *k = &data->req; - char *beg = k->p; + char *beg = Curl_dyn_ptr(&data->state.headerb); /* make sure that data->req.p points to the HTTP status line */ if(!strncmp(beg, "HTTP", 4)) { @@ -3265,14 +3143,17 @@ static void print_http_error(struct Curl_easy *data) * Read any HTTP header lines from the server and pass them to the client app. */ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, - struct connectdata *conn, - ssize_t *nread, - bool *stop_reading) + struct connectdata *conn, + ssize_t *nread, + bool *stop_reading) { CURLcode result; struct SingleRequest *k = &data->req; ssize_t onread = *nread; char *ostr = k->str; + char *headp; + char *str_start; + char *end_ptr; /* header line within buffer loop */ do { @@ -3281,22 +3162,25 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, int writetype; /* str_start is start of line within buf */ - k->str_start = k->str; + str_start = k->str; /* data is in network encoding so use 0x0a instead of '\n' */ - k->end_ptr = memchr(k->str_start, 0x0a, *nread); + end_ptr = memchr(str_start, 0x0a, *nread); - if(!k->end_ptr) { + if(!end_ptr) { /* Not a complete header line within buffer, append the data to the end of the headerbuff. */ - result = header_append(data, k, *nread); + result = Curl_dyn_addn(&data->state.headerb, str_start, *nread); if(result) return result; if(!k->headerline) { /* check if this looks like a protocol header */ - statusline st = checkprotoprefix(data, conn, data->state.headerbuff, - k->hbuflen); + statusline st = + checkprotoprefix(data, conn, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(st == STATUS_BAD) { /* this is not the beginning of a protocol first header line */ k->header = FALSE; @@ -3314,28 +3198,26 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } /* decrease the size of the remaining (supposed) header line */ - rest_length = (k->end_ptr - k->str) + 1; + rest_length = (end_ptr - k->str) + 1; *nread -= (ssize_t)rest_length; - k->str = k->end_ptr + 1; /* move past new line */ + k->str = end_ptr + 1; /* move past new line */ - full_length = k->str - k->str_start; + full_length = k->str - str_start; - result = header_append(data, k, full_length); + result = Curl_dyn_addn(&data->state.headerb, str_start, full_length); if(result) return result; - k->end_ptr = k->hbufp; - k->p = data->state.headerbuff; - /**** - * We now have a FULL header line that p points to + * We now have a FULL header line in 'headerb'. *****/ if(!k->headerline) { /* the first read header */ - statusline st = checkprotoprefix(data, conn, data->state.headerbuff, - k->hbuflen); + statusline st = checkprotoprefix(data, conn, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); if(st == STATUS_BAD) { streamclose(conn, "bad HTTP: No end-of-message indicator"); /* this is not the beginning of a protocol first header line */ @@ -3358,26 +3240,27 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } - /* headers are in network encoding so - use 0x0a and 0x0d instead of '\n' and '\r' */ - if((0x0a == *k->p) || (0x0d == *k->p)) { + /* headers are in network encoding so use 0x0a and 0x0d instead of '\n' + and '\r' */ + headp = Curl_dyn_ptr(&data->state.headerb); + if((0x0a == *headp) || (0x0d == *headp)) { size_t headerlen; /* Zero-length header line means end of headers! */ #ifdef CURL_DOES_CONVERSIONS - if(0x0d == *k->p) { - *k->p = '\r'; /* replace with CR in host encoding */ - k->p++; /* pass the CR byte */ + if(0x0d == *headp) { + *headp = '\r'; /* replace with CR in host encoding */ + headp++; /* pass the CR byte */ } - if(0x0a == *k->p) { - *k->p = '\n'; /* replace with LF in host encoding */ - k->p++; /* pass the LF byte */ + if(0x0a == *headp) { + *headp = '\n'; /* replace with LF in host encoding */ + headp++; /* pass the LF byte */ } #else - if('\r' == *k->p) - k->p++; /* pass the \r byte */ - if('\n' == *k->p) - k->p++; /* pass the \n byte */ + if('\r' == *headp) + headp++; /* pass the \r byte */ + if('\n' == *headp) + headp++; /* pass the \n byte */ #endif /* CURL_DOES_CONVERSIONS */ if(100 <= k->httpcode && 199 >= k->httpcode) { @@ -3438,7 +3321,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if((k->size == -1) && !k->chunk && !conn->bits.close && (conn->httpversion == 11) && !(conn->handler->protocol & CURLPROTO_RTSP) && - data->set.httpreq != HTTPREQ_HEAD) { + data->state.httpreq != HTTPREQ_HEAD) { /* On HTTP 1.1, when connection is not to get closed, but no Content-Length nor Transfer-Encoding chunked have been received, according to RFC2616 section 4.4 point 5, we @@ -3496,10 +3379,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(data->set.include_header) writetype |= CLIENTWRITE_BODY; - headerlen = k->p - data->state.headerbuff; - + headerlen = Curl_dyn_len(&data->state.headerb); result = Curl_client_write(conn, writetype, - data->state.headerbuff, + Curl_dyn_ptr(&data->state.headerb), headerlen); if(result) return result; @@ -3534,7 +3416,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * continue sending even if it gets discarded */ - switch(data->set.httpreq) { + switch(data->state.httpreq) { case HTTPREQ_PUT: case HTTPREQ_POST: case HTTPREQ_POST_FORM: @@ -3652,14 +3534,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, - k->str_start, headerlen); + str_start, headerlen); break; /* exit header line loop */ } - /* We continue reading headers, so reset the line-based - header parsing variables hbufp && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; + /* We continue reading headers, reset the line-based header */ + Curl_dyn_reset(&data->state.headerb); continue; } @@ -3678,12 +3558,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #define SCRATCHSIZE 21 CURLcode res; char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */ - /* We can't really convert this yet because we - don't know if it's the 1st header line or the body. - So we do a partial conversion into a scratch area, - leaving the data at k->p as-is. + /* We can't really convert this yet because we don't know if it's the + 1st header line or the body. So we do a partial conversion into a + scratch area, leaving the data at 'headp' as-is. */ - strncpy(&scratch[0], k->p, SCRATCHSIZE); + strncpy(&scratch[0], headp, SCRATCHSIZE); scratch[SCRATCHSIZE] = 0; /* null terminate */ res = Curl_convert_from_network(data, &scratch[0], @@ -3692,7 +3571,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* Curl_convert_from_network calls failf if unsuccessful */ return res; #else -#define HEADER1 k->p /* no conversion needed, just use k->p */ +#define HEADER1 headp /* no conversion needed, just use headp */ #endif /* CURL_DOES_CONVERSIONS */ if(conn->handler->protocol & PROTO_FAMILY_HTTP) { @@ -3743,7 +3622,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, compare header line against list of aliases */ if(!nc) { - if(checkhttpprefix(data, k->p, k->hbuflen) == STATUS_DONE) { + statusline check = + checkhttpprefix(data, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(check == STATUS_DONE) { nc = 1; k->httpcode = 200; conn->httpversion = 10; @@ -3789,15 +3672,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * depending on how authentication is working. Other codes * are definitely errors, so give up here. */ - if(data->state.resume_from && data->set.httpreq == HTTPREQ_GET && + if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET && k->httpcode == 416) { /* "Requested Range Not Satisfiable", just proceed and pretend this is no error */ k->ignorebody = TRUE; /* Avoid appending error msg to good data. */ } else if(data->set.http_fail_on_error && (k->httpcode >= 400) && - ((k->httpcode != 401) || !conn->bits.user_passwd) && - ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) { + ((k->httpcode != 401) || !conn->bits.user_passwd) +#ifndef CURL_DISABLE_PROXY + && ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) +#endif + ) { /* serious error, go home! */ print_http_error(data); return CURLE_HTTP_RETURNED_ERROR; @@ -3813,9 +3699,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, else if(conn->httpversion == 20 || (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n")); - - /* HTTP/2 cannot blacklist multiplexing since it is a core - functionality of the protocol */ + /* HTTP/2 cannot avoid multiplexing since it is a core functionality + of the protocol */ conn->bundle->multiuse = BUNDLE_MULTIPLEX; } else if(conn->httpversion >= 11 && @@ -3855,16 +3740,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } - result = Curl_convert_from_network(data, k->p, strlen(k->p)); + result = Curl_convert_from_network(data, headp, strlen(headp)); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) return result; /* Check for Content-Length: header lines to get size */ if(!k->http_bodyless && - !data->set.ignorecl && checkprefix("Content-Length:", k->p)) { + !data->set.ignorecl && checkprefix("Content-Length:", headp)) { curl_off_t contentlength; - CURLofft offt = curlx_strtoofft(k->p + 15, NULL, 10, &contentlength); + CURLofft offt = curlx_strtoofft(headp + 15, NULL, 10, &contentlength); if(offt == CURL_OFFT_OK) { if(data->set.max_filesize && @@ -3895,8 +3780,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } /* check for Content-Type: header lines to get the MIME-type */ - else if(checkprefix("Content-Type:", k->p)) { - char *contenttype = Curl_copy_header_value(k->p); + else if(checkprefix("Content-Type:", headp)) { + char *contenttype = Curl_copy_header_value(headp); if(!contenttype) return CURLE_OUT_OF_MEMORY; if(!*contenttype) @@ -3907,10 +3792,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, data->info.contenttype = contenttype; } } +#ifndef CURL_DISABLE_PROXY else if((conn->httpversion == 10) && conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "keep-alive")) { + Curl_compareheader(headp, "Proxy-Connection:", "keep-alive")) { /* * When a HTTP/1.0 reply comes when using a proxy, the * 'Proxy-Connection: keep-alive' line tells us the @@ -3922,8 +3807,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } else if((conn->httpversion == 11) && conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "close")) { + Curl_compareheader(headp, "Proxy-Connection:", "close")) { /* * We get a HTTP/1.1 response from a proxy and it says it'll * close down after this transfer. @@ -3931,8 +3815,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, connclose(conn, "Proxy-Connection: asked to close after done"); infof(data, "HTTP/1.1 proxy connection set close!\n"); } +#endif else if((conn->httpversion == 10) && - Curl_compareheader(k->p, "Connection:", "keep-alive")) { + Curl_compareheader(headp, "Connection:", "keep-alive")) { /* * A HTTP/1.0 reply with the 'Connection: keep-alive' line * tells us the connection will be kept alive for our @@ -3942,7 +3827,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, connkeep(conn, "Connection keep-alive"); infof(data, "HTTP/1.0 connection set to keep alive!\n"); } - else if(Curl_compareheader(k->p, "Connection:", "close")) { + else if(Curl_compareheader(headp, "Connection:", "close")) { /* * [RFC 2616, section 8.1.2.1] * "Connection: close" is HTTP/1.1 language and means that @@ -3951,7 +3836,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, */ streamclose(conn, "Connection: close used"); } - else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", k->p)) { + else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) { /* One or more encodings. We check for chunked and/or a compression algorithm. */ /* @@ -3963,11 +3848,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * of chunks, and a chunk-data set to zero signals the * end-of-chunks. */ - result = Curl_build_unencoding_stack(conn, k->p + 18, TRUE); + result = Curl_build_unencoding_stack(conn, headp + 18, TRUE); if(result) return result; } - else if(!k->http_bodyless && checkprefix("Content-Encoding:", k->p) && + else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) && data->set.str[STRING_ENCODING]) { /* * Process Content-Encoding. Look for the values: identity, @@ -3976,24 +3861,24 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * 2616). zlib cannot handle compress. However, errors are * handled further down when the response body is processed */ - result = Curl_build_unencoding_stack(conn, k->p + 17, FALSE); + result = Curl_build_unencoding_stack(conn, headp + 17, FALSE); if(result) return result; } - else if(checkprefix("Retry-After:", k->p)) { + else if(checkprefix("Retry-After:", headp)) { /* Retry-After = HTTP-date / delay-seconds */ curl_off_t retry_after = 0; /* zero for unknown or "now" */ - time_t date = Curl_getdate_capped(&k->p[12]); + time_t date = Curl_getdate_capped(&headp[12]); if(-1 == date) { /* not a date, try it as a decimal number */ - (void)curlx_strtoofft(&k->p[12], NULL, 10, &retry_after); + (void)curlx_strtoofft(&headp[12], NULL, 10, &retry_after); } else /* convert date to number of seconds into the future */ retry_after = date - time(NULL); data->info.retry_after = retry_after; /* store it */ } - else if(!k->http_bodyless && checkprefix("Content-Range:", k->p)) { + else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) { /* Content-Range: bytes [num]- Content-Range: bytes: [num]- Content-Range: [num]- @@ -4005,7 +3890,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, The forth means the requested range was unsatisfied. */ - char *ptr = k->p + 14; + char *ptr = headp + 14; /* Move forward until first digit or asterisk */ while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') @@ -4024,34 +3909,34 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #if !defined(CURL_DISABLE_COOKIES) else if(data->cookies && data->state.cookie_engine && - checkprefix("Set-Cookie:", k->p)) { + checkprefix("Set-Cookie:", headp)) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_add(data, - data->cookies, TRUE, FALSE, k->p + 11, + data->cookies, TRUE, FALSE, headp + 11, /* If there is a custom-set Host: name, use it here, or else use real peer host name. */ - conn->allocptr.cookiehost? - conn->allocptr.cookiehost:conn->host.name, + data->state.aptr.cookiehost? + data->state.aptr.cookiehost:conn->host.name, data->state.up.path, (conn->handler->protocol&CURLPROTO_HTTPS)? TRUE:FALSE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } #endif - else if(!k->http_bodyless && checkprefix("Last-Modified:", k->p) && + else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) && (data->set.timecondition || data->set.get_filetime) ) { - k->timeofdoc = Curl_getdate_capped(k->p + strlen("Last-Modified:")); + k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:")); if(data->set.get_filetime) data->info.filetime = k->timeofdoc; } - else if((checkprefix("WWW-Authenticate:", k->p) && + else if((checkprefix("WWW-Authenticate:", headp) && (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", k->p) && + (checkprefix("Proxy-authenticate:", headp) && (407 == k->httpcode))) { bool proxy = (k->httpcode == 407) ? TRUE : FALSE; - char *auth = Curl_copy_header_value(k->p); + char *auth = Curl_copy_header_value(headp); if(!auth) return CURLE_OUT_OF_MEMORY; @@ -4063,11 +3948,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return result; } #ifdef USE_SPNEGO - else if(checkprefix("Persistent-Auth", k->p)) { + else if(checkprefix("Persistent-Auth", headp)) { struct negotiatedata *negdata = &conn->negotiate; struct auth *authp = &data->state.authhost; if(authp->picked == CURLAUTH_NEGOTIATE) { - char *persistentauth = Curl_copy_header_value(k->p); + char *persistentauth = Curl_copy_header_value(headp); if(!persistentauth) return CURLE_OUT_OF_MEMORY; negdata->noauthpersist = checkprefix("false", persistentauth)? @@ -4080,10 +3965,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #endif else if((k->httpcode >= 300 && k->httpcode < 400) && - checkprefix("Location:", k->p) && + checkprefix("Location:", headp) && !data->req.location) { /* this is the URL that the server advises us to use instead */ - char *location = Curl_copy_header_value(k->p); + char *location = Curl_copy_header_value(headp); if(!location) return CURLE_OUT_OF_MEMORY; if(!*location) @@ -4108,7 +3993,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #ifdef USE_ALTSVC /* If enabled, the header is incoming and this is over HTTPS */ - else if(data->asi && checkprefix("Alt-Svc:", k->p) && + else if(data->asi && checkprefix("Alt-Svc:", headp) && ((conn->handler->flags & PROTOPT_SSL) || #ifdef CURLDEBUG /* allow debug builds to circumvent the HTTPS restriction */ @@ -4120,7 +4005,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* the ALPN of the current request */ enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1; result = Curl_altsvc_parse(data, data->asi, - &k->p[ strlen("Alt-Svc:") ], + &headp[ strlen("Alt-Svc:") ], id, conn->host.name, curlx_uitous(conn->remote_port)); if(result) @@ -4128,7 +4013,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #endif else if(conn->handler->protocol & CURLPROTO_RTSP) { - result = Curl_rtsp_parseheader(conn, k->p); + result = Curl_rtsp_parseheader(conn, headp); if(result) return result; } @@ -4142,18 +4027,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, writetype |= CLIENTWRITE_BODY; if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, k->p, (size_t)k->hbuflen); + Curl_debug(data, CURLINFO_HEADER_IN, headp, + Curl_dyn_len(&data->state.headerb)); - result = Curl_client_write(conn, writetype, k->p, k->hbuflen); + result = Curl_client_write(conn, writetype, headp, + Curl_dyn_len(&data->state.headerb)); if(result) return result; - data->info.header_size += (long)k->hbuflen; - data->req.headerbytecount += (long)k->hbuflen; + data->info.header_size += Curl_dyn_len(&data->state.headerb); + data->req.headerbytecount += Curl_dyn_len(&data->state.headerb); - /* reset hbufp pointer && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; + Curl_dyn_reset(&data->state.headerb); } while(*k->str); /* header line within buffer */ diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h index 4c1825f..641bc0b 100644 --- a/Utilities/cmcurl/lib/http.h +++ b/Utilities/cmcurl/lib/http.h @@ -44,38 +44,19 @@ char *Curl_copy_header_value(const char *header); char *Curl_checkProxyheaders(const struct connectdata *conn, const char *thisheader); -/* ------------------------------------------------------------------------- */ -/* - * The add_buffer series of functions are used to build one large memory chunk - * from repeated function invokes. Used so that the entire HTTP request can - * be sent in one go. - */ -struct Curl_send_buffer { - char *buffer; - size_t size_max; - size_t size_used; -}; -typedef struct Curl_send_buffer Curl_send_buffer; - -Curl_send_buffer *Curl_add_buffer_init(void); -void Curl_add_buffer_free(Curl_send_buffer **inp); -CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) - WARN_UNUSED_RESULT; -CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, - size_t size) WARN_UNUSED_RESULT; -CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, - struct connectdata *conn, - curl_off_t *bytes_written, - size_t included_body_bytes, - int socketindex); +CURLcode Curl_buffer_send(struct dynbuf *in, + struct connectdata *conn, + curl_off_t *bytes_written, + size_t included_body_bytes, + int socketindex); CURLcode Curl_add_timecondition(const struct connectdata *conn, - Curl_send_buffer *buf); + struct dynbuf *buf); CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, - Curl_send_buffer *req_buffer); + struct dynbuf *req_buffer); CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, - Curl_send_buffer **buffer, + struct dynbuf *buf, struct Curl_easy *handle); /* protocol-specific functions set up to be called by the main engine */ @@ -154,9 +135,9 @@ struct HTTP { } sending; #ifndef CURL_DISABLE_HTTP - Curl_send_buffer *send_buffer; /* used if the request couldn't be sent in - one chunk, points to an allocated - send_buffer struct */ + struct dynbuf send_buffer; /* used if the request couldn't be sent in one + chunk, points to an allocated send_buffer + struct */ #endif #ifdef USE_NGHTTP2 /*********** for HTTP/2 we store stream-local data here *************/ @@ -164,10 +145,9 @@ struct HTTP { bool bodystarted; /* We store non-final and final response headers here, per-stream */ - Curl_send_buffer *header_recvbuf; + struct dynbuf header_recvbuf; size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into upper layer */ - Curl_send_buffer *trailer_recvbuf; int status_code; /* HTTP status code */ const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ size_t pauselen; /* the number of bytes left in data */ @@ -201,9 +181,7 @@ struct HTTP { #ifdef USE_NGHTTP3 size_t unacked_window; struct h3out *h3out; /* per-stream buffers for upload */ - char *overflow_buf; /* excess data received during a single Curl_read */ - size_t overflow_buflen; /* amount of data currently in overflow_buf */ - size_t overflow_bufsize; /* size of the overflow_buf allocation */ + struct dynbuf overflow; /* excess data received during a single Curl_read */ #endif }; diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c index 72b38a3..6199001 100644 --- a/Utilities/cmcurl/lib/http2.c +++ b/Utilities/cmcurl/lib/http2.c @@ -36,6 +36,7 @@ #include "connect.h" #include "strtoofft.h" #include "strdup.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -124,8 +125,7 @@ static int http2_getsock(struct connectdata *conn, static void http2_stream_free(struct HTTP *http) { if(http) { - Curl_add_buffer_free(&http->header_recvbuf); - Curl_add_buffer_free(&http->trailer_recvbuf); + Curl_dyn_free(&http->header_recvbuf); for(; http->push_headers_used > 0; --http->push_headers_used) { free(http->push_headers[http->push_headers_used - 1]); } @@ -258,16 +258,14 @@ static unsigned int http2_conncheck(struct connectdata *check, void Curl_http2_setup_req(struct Curl_easy *data) { struct HTTP *http = data->req.protop; - - http->nread_header_recvbuf = 0; http->bodystarted = FALSE; http->status_code = -1; http->pausedata = NULL; http->pauselen = 0; http->closed = FALSE; http->close_handled = FALSE; - http->mem = data->state.buffer; - http->len = data->set.buffer_size; + http->mem = NULL; + http->len = 0; http->memlen = 0; } @@ -333,7 +331,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = { int Curl_http2_ver(char *p, size_t len) { nghttp2_info *h2 = nghttp2_version(0); - return msnprintf(p, len, " nghttp2/%s", h2->version_str); + return msnprintf(p, len, "nghttp2/%s", h2->version_str); } /* @@ -463,15 +461,9 @@ static struct Curl_easy *duphandle(struct Curl_easy *data) } else { second->req.protop = http; - http->header_recvbuf = Curl_add_buffer_init(); - if(!http->header_recvbuf) { - free(http); - (void)Curl_close(&second); - } - else { - Curl_http2_setup_req(second); - second->state.stream_weight = data->state.stream_weight; - } + Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS); + Curl_http2_setup_req(second); + second->state.stream_weight = data->state.stream_weight; } } return second; @@ -668,15 +660,17 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, stream->status_code = -1; } - result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2); + result = Curl_dyn_add(&stream->header_recvbuf, "\r\n"); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf; + left = Curl_dyn_len(&stream->header_recvbuf) - + stream->nread_header_recvbuf; ncopy = CURLMIN(stream->len, left); memcpy(&stream->mem[stream->memlen], - stream->header_recvbuf->buffer + stream->nread_header_recvbuf, + Curl_dyn_ptr(&stream->header_recvbuf) + + stream->nread_header_recvbuf, ncopy); stream->nread_header_recvbuf += ncopy; @@ -852,12 +846,6 @@ static int on_begin_headers(nghttp2_session *session, return 0; } - if(!stream->trailer_recvbuf) { - stream->trailer_recvbuf = Curl_add_buffer_init(); - if(!stream->trailer_recvbuf) { - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - } return 0; } @@ -973,26 +961,19 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, } if(stream->bodystarted) { - /* This is trailer fields. */ - /* 4 is for ": " and "\r\n". */ - uint32_t n = (uint32_t)(namelen + valuelen + 4); - + /* This is a trailer */ + struct dynbuf trail; H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen, value)); - - result = Curl_add_buffer(&stream->trailer_recvbuf, &n, sizeof(n)); - if(result) - return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->trailer_recvbuf, name, namelen); - if(result) - return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->trailer_recvbuf, ": ", 2); - if(result) - return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->trailer_recvbuf, value, valuelen); - if(result) - return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->trailer_recvbuf, "\r\n\0", 3); + Curl_dyn_init(&trail, DYN_H2_TRAILER); + result = Curl_dyn_addf(&trail, + "%.*s: %.*s\r\n", namelen, name, + valuelen, value); + if(!result) + result = Curl_client_write(conn, CLIENTWRITE_HEADER, + Curl_dyn_ptr(&trail), + Curl_dyn_len(&trail)); + Curl_dyn_free(&trail); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -1007,14 +988,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, stream->status_code = decode_status_code(value, valuelen); DEBUGASSERT(stream->status_code != -1); - result = Curl_add_buffer(&stream->header_recvbuf, "HTTP/2 ", 7); + result = Curl_dyn_add(&stream->header_recvbuf, "HTTP/2 "); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen); + result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* the space character after the status code is mandatory */ - result = Curl_add_buffer(&stream->header_recvbuf, " \r\n", 3); + result = Curl_dyn_add(&stream->header_recvbuf, " \r\n"); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* if we receive data for another handle, wake that up */ @@ -1029,16 +1010,16 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, /* nghttp2 guarantees that namelen > 0, and :status was already received, and this is not pseudo-header field . */ /* convert to a HTTP1-style header */ - result = Curl_add_buffer(&stream->header_recvbuf, name, namelen); + result = Curl_dyn_addn(&stream->header_recvbuf, name, namelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->header_recvbuf, ": ", 2); + result = Curl_dyn_add(&stream->header_recvbuf, ": "); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen); + result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2); + result = Curl_dyn_add(&stream->header_recvbuf, "\r\n"); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* if we receive data for another handle, wake that up */ @@ -1139,17 +1120,14 @@ void Curl_http2_done(struct Curl_easy *data, bool premature) /* there might be allocated resources done before this got the 'h2' pointer setup */ - if(http->header_recvbuf) { - Curl_add_buffer_free(&http->header_recvbuf); - Curl_add_buffer_free(&http->trailer_recvbuf); - if(http->push_headers) { - /* if they weren't used and then freed before */ - for(; http->push_headers_used > 0; --http->push_headers_used) { - free(http->push_headers[http->push_headers_used - 1]); - } - free(http->push_headers); - http->push_headers = NULL; + Curl_dyn_free(&http->header_recvbuf); + if(http->push_headers) { + /* if they weren't used and then freed before */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); } + free(http->push_headers); + http->push_headers = NULL; } if(!httpc->h2) /* not HTTP/2 ? */ @@ -1238,7 +1216,7 @@ static CURLcode http2_init(struct connectdata *conn) /* * Append headers to ask for a HTTP1.1 to HTTP2 upgrade. */ -CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, +CURLcode Curl_http2_request_upgrade(struct dynbuf *req, struct connectdata *conn) { CURLcode result; @@ -1257,7 +1235,7 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, httpc->local_settings_num); if(!binlen) { failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); - Curl_add_buffer_free(&req); + Curl_dyn_free(req); return CURLE_FAILED_INIT; } conn->proto.httpc.binlen = binlen; @@ -1265,15 +1243,15 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen, &base64, &blen); if(result) { - Curl_add_buffer_free(&req); + Curl_dyn_free(req); return result; } - result = Curl_add_bufferf(&req, - "Connection: Upgrade, HTTP2-Settings\r\n" - "Upgrade: %s\r\n" - "HTTP2-Settings: %s\r\n", - NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); + result = Curl_dyn_addf(req, + "Connection: Upgrade, HTTP2-Settings\r\n" + "Upgrade: %s\r\n" + "HTTP2-Settings: %s\r\n", + NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); free(base64); k->upgr101 = UPGR101_REQUESTED; @@ -1367,10 +1345,11 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn) struct HTTP *stream = conn->data->req.protop; + struct http_conn *httpc = &conn->proto.httpc; + nghttp2_session *h2 = httpc->h2; + if(stream->upload_left) { /* If the stream still thinks there's data left to upload. */ - struct http_conn *httpc = &conn->proto.httpc; - nghttp2_session *h2 = httpc->h2; stream->upload_left = 0; /* DONE! */ @@ -1380,6 +1359,23 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn) (void)h2_process_pending_input(conn, httpc, &result); } + + /* If nghttp2 still has pending frames unsent */ + if(nghttp2_session_want_write(h2)) { + struct Curl_easy *data = conn->data; + struct SingleRequest *k = &data->req; + int rv; + + H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)\n", data)); + + /* re-set KEEP_SEND to make sure we are called again */ + k->keepon |= KEEP_SEND; + + /* and attempt to send the pending frames */ + rv = h2_session_send(data, h2); + if(rv != 0) + result = CURLE_SEND_ERROR; + } } return result; } @@ -1388,8 +1384,6 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, struct Curl_easy *data, struct HTTP *stream, CURLcode *err) { - char *trailer_pos, *trailer_end; - CURLcode result; struct http_conn *httpc = &conn->proto.httpc; if(httpc->pause_stream_id == stream->stream_id) { @@ -1432,25 +1426,6 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, return -1; } - if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) { - trailer_pos = stream->trailer_recvbuf->buffer; - trailer_end = trailer_pos + stream->trailer_recvbuf->size_used; - - for(; trailer_pos < trailer_end;) { - uint32_t n; - memcpy(&n, trailer_pos, sizeof(n)); - trailer_pos += sizeof(n); - - result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n); - if(result) { - *err = result; - return -1; - } - - trailer_pos += n + 1; - } - } - stream->close_handled = TRUE; H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); @@ -1541,13 +1516,13 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, */ if(stream->bodystarted && - stream->nread_header_recvbuf < stream->header_recvbuf->size_used) { - /* If there is body data pending for this stream to return, do that */ + stream->nread_header_recvbuf < Curl_dyn_len(&stream->header_recvbuf)) { + /* If there is header data pending for this stream to return, do that */ size_t left = - stream->header_recvbuf->size_used - stream->nread_header_recvbuf; + Curl_dyn_len(&stream->header_recvbuf) - stream->nread_header_recvbuf; size_t ncopy = CURLMIN(len, left); - memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf, - ncopy); + memcpy(mem, Curl_dyn_ptr(&stream->header_recvbuf) + + stream->nread_header_recvbuf, ncopy); stream->nread_header_recvbuf += ncopy; H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", @@ -1727,8 +1702,6 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, return retlen; } - /* If this stream is closed, return 0 to signal the http routine to close - the connection */ if(stream->closed) return 0; *err = CURLE_AGAIN; @@ -2058,7 +2031,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, h2_pri_spec(conn->data, &pri_spec); - switch(conn->data->set.httpreq) { + switch(conn->data->state.httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: @@ -2129,13 +2102,11 @@ CURLcode Curl_http2_setup(struct connectdata *conn) struct http_conn *httpc = &conn->proto.httpc; struct HTTP *stream = conn->data->req.protop; + DEBUGASSERT(conn->data->state.buffer); + stream->stream_id = -1; - if(!stream->header_recvbuf) { - stream->header_recvbuf = Curl_add_buffer_init(); - if(!stream->header_recvbuf) - return CURLE_OUT_OF_MEMORY; - } + Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS); if((conn->handler == &Curl_handler_http2_ssl) || (conn->handler == &Curl_handler_http2)) @@ -2148,7 +2119,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn) result = http2_init(conn); if(result) { - Curl_add_buffer_free(&stream->header_recvbuf); + Curl_dyn_free(&stream->header_recvbuf); return result; } @@ -2156,6 +2127,8 @@ CURLcode Curl_http2_setup(struct connectdata *conn) stream->upload_left = 0; stream->upload_mem = NULL; stream->upload_len = 0; + stream->mem = conn->data->state.buffer; + stream->len = conn->data->set.buffer_size; httpc->inbuflen = 0; httpc->nread_inbuf = 0; diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h index 1989aff..e82b212 100644 --- a/Utilities/cmcurl/lib/http2.h +++ b/Utilities/cmcurl/lib/http2.h @@ -42,7 +42,7 @@ const char *Curl_http2_strerror(uint32_t err); CURLcode Curl_http2_init(struct connectdata *conn); void Curl_http2_init_state(struct UrlState *state); void Curl_http2_init_userset(struct UserDefined *set); -CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, +CURLcode Curl_http2_request_upgrade(struct dynbuf *req, struct connectdata *conn); CURLcode Curl_http2_setup(struct connectdata *conn); CURLcode Curl_http2_switched(struct connectdata *conn, diff --git a/Utilities/cmcurl/lib/http_chunks.c b/Utilities/cmcurl/lib/http_chunks.c index b6ffa41..767f806 100644 --- a/Utilities/cmcurl/lib/http_chunks.c +++ b/Utilities/cmcurl/lib/http_chunks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,7 @@ #include "urldata.h" /* it includes http_chunks.h */ #include "sendf.h" /* for the client write stuff */ - +#include "dynbuf.h" #include "content_encoding.h" #include "http.h" #include "non-ascii.h" /* for Curl_convert_to_network prototype */ @@ -93,6 +93,7 @@ void Curl_httpchunk_init(struct connectdata *conn) chunk->hexindex = 0; /* start at 0 */ chunk->dataleft = 0; /* no data left yet! */ chunk->state = CHUNK_HEX; /* we get hex first! */ + Curl_dyn_init(&conn->trailer, DYN_H1_TRAILER); } /* @@ -177,7 +178,6 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, /* we're now expecting data to come, unless size was zero! */ if(0 == ch->datasize) { ch->state = CHUNK_TRAILER; /* now check for trailers */ - conn->trlPos = 0; } else ch->state = CHUNK_DATA; @@ -229,32 +229,33 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, case CHUNK_TRAILER: if((*datap == 0x0d) || (*datap == 0x0a)) { + char *tr = Curl_dyn_ptr(&conn->trailer); /* this is the end of a trailer, but if the trailer was zero bytes there was no trailer and we move on */ - if(conn->trlPos) { - /* we allocate trailer with 3 bytes extra room to fit this */ - conn->trailer[conn->trlPos++] = 0x0d; - conn->trailer[conn->trlPos++] = 0x0a; - conn->trailer[conn->trlPos] = 0; + if(tr) { + size_t trlen; + result = Curl_dyn_add(&conn->trailer, (char *)"\x0d\x0a"); + if(result) + return CHUNKE_OUT_OF_MEMORY; + tr = Curl_dyn_ptr(&conn->trailer); + trlen = Curl_dyn_len(&conn->trailer); /* Convert to host encoding before calling Curl_client_write */ - result = Curl_convert_from_network(conn->data, conn->trailer, - conn->trlPos); + result = Curl_convert_from_network(conn->data, tr, trlen); if(result) /* Curl_convert_from_network calls failf if unsuccessful */ /* Treat it as a bad chunk */ return CHUNKE_BAD_CHUNK; if(!data->set.http_te_skip) { - result = Curl_client_write(conn, CLIENTWRITE_HEADER, - conn->trailer, conn->trlPos); + result = Curl_client_write(conn, CLIENTWRITE_HEADER, tr, trlen); if(result) { *extrap = result; return CHUNKE_PASSTHRU_ERROR; } } - conn->trlPos = 0; + Curl_dyn_reset(&conn->trailer); ch->state = CHUNK_TRAILER_CR; if(*datap == 0x0a) /* already on the LF */ @@ -267,25 +268,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, } } else { - /* conn->trailer is assumed to be freed in url.c on a - connection basis */ - if(conn->trlPos >= conn->trlMax) { - /* we always allocate three extra bytes, just because when the full - header has been received we append CRLF\0 */ - char *ptr; - if(conn->trlMax) { - conn->trlMax *= 2; - ptr = realloc(conn->trailer, conn->trlMax + 3); - } - else { - conn->trlMax = 128; - ptr = malloc(conn->trlMax + 3); - } - if(!ptr) - return CHUNKE_OUT_OF_MEMORY; - conn->trailer = ptr; - } - conn->trailer[conn->trlPos++]=*datap; + result = Curl_dyn_addn(&conn->trailer, datap, 1); + if(result) + return CHUNKE_OUT_OF_MEMORY; } datap++; length--; diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c index 9616c30..b06dc0d 100644 --- a/Utilities/cmcurl/lib/http_digest.c +++ b/Utilities/cmcurl/lib/http_digest.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -94,15 +94,19 @@ CURLcode Curl_output_digest(struct connectdata *conn, struct auth *authp; if(proxy) { +#ifdef CURL_DISABLE_PROXY + return CURLE_NOT_BUILT_IN; +#else digest = &data->state.proxydigest; - allocuserpwd = &conn->allocptr.proxyuserpwd; + allocuserpwd = &data->state.aptr.proxyuserpwd; userp = conn->http_proxy.user; passwdp = conn->http_proxy.passwd; authp = &data->state.authproxy; +#endif } else { digest = &data->state.digest; - allocuserpwd = &conn->allocptr.userpwd; + allocuserpwd = &data->state.aptr.userpwd; userp = conn->user; passwdp = conn->passwd; authp = &data->state.authhost; diff --git a/Utilities/cmcurl/lib/http_digest.h b/Utilities/cmcurl/lib/http_digest.h index 73410ae..96e39a7 100644 --- a/Utilities/cmcurl/lib/http_digest.h +++ b/Utilities/cmcurl/lib/http_digest.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c index 8e1f3bf..0a19ec2 100644 --- a/Utilities/cmcurl/lib/http_negotiate.c +++ b/Utilities/cmcurl/lib/http_negotiate.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -52,6 +52,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, curlnegotiate state; if(proxy) { +#ifndef CURL_DISABLE_PROXY userp = conn->http_proxy.user; passwdp = conn->http_proxy.passwd; service = data->set.str[STRING_PROXY_SERVICE_NAME] ? @@ -59,6 +60,9 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, host = conn->http_proxy.host.name; neg_ctx = &conn->proxyneg; state = conn->proxy_negotiate_state; +#else + return CURLE_NOT_BUILT_IN; +#endif } else { userp = conn->user; @@ -119,7 +123,8 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) struct auth *authp = proxy ? &conn->data->state.authproxy : &conn->data->state.authhost; curlnegotiate *state = proxy ? &conn->proxy_negotiate_state : - &conn->http_negotiate_state; + &conn->http_negotiate_state; + struct Curl_easy *data = conn->data; char *base64 = NULL; size_t len = 0; char *userp; @@ -164,15 +169,15 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) return result; userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", - base64); + base64); if(proxy) { - Curl_safefree(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = userp; + Curl_safefree(data->state.aptr.proxyuserpwd); + data->state.aptr.proxyuserpwd = userp; } else { - Curl_safefree(conn->allocptr.userpwd); - conn->allocptr.userpwd = userp; + Curl_safefree(data->state.aptr.userpwd); + data->state.aptr.userpwd = userp; } free(base64); diff --git a/Utilities/cmcurl/lib/http_negotiate.h b/Utilities/cmcurl/lib/http_negotiate.h index 4f0ac16..a737f6f 100644 --- a/Utilities/cmcurl/lib/http_negotiate.h +++ b/Utilities/cmcurl/lib/http_negotiate.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -33,6 +33,8 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy); void Curl_http_auth_cleanup_negotiate(struct connectdata *conn); -#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ +#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */ +#define Curl_http_auth_cleanup_negotiate(x) +#endif #endif /* HEADER_CURL_HTTP_NEGOTIATE_H */ diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c index 342b242..cab543c 100644 --- a/Utilities/cmcurl/lib/http_ntlm.c +++ b/Utilities/cmcurl/lib/http_ntlm.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -131,12 +131,15 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) struct ntlmdata *ntlm; curlntlm *state; struct auth *authp; + struct Curl_easy *data = conn->data; + DEBUGASSERT(conn); - DEBUGASSERT(conn->data); + DEBUGASSERT(data); if(proxy) { - allocuserpwd = &conn->allocptr.proxyuserpwd; +#ifndef CURL_DISABLE_PROXY + allocuserpwd = &data->state.aptr.proxyuserpwd; userp = conn->http_proxy.user; passwdp = conn->http_proxy.passwd; service = conn->data->set.str[STRING_PROXY_SERVICE_NAME] ? @@ -145,9 +148,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) ntlm = &conn->proxyntlm; state = &conn->proxy_ntlm_state; authp = &conn->data->state.authproxy; +#else + return CURLE_NOT_BUILT_IN; +#endif } else { - allocuserpwd = &conn->allocptr.userpwd; + allocuserpwd = &data->state.aptr.userpwd; userp = conn->user; passwdp = conn->passwd; service = conn->data->set.str[STRING_SERVICE_NAME] ? diff --git a/Utilities/cmcurl/lib/http_ntlm.h b/Utilities/cmcurl/lib/http_ntlm.h index 003714d..3ebdf97 100644 --- a/Utilities/cmcurl/lib/http_ntlm.h +++ b/Utilities/cmcurl/lib/http_ntlm.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,6 +35,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); void Curl_http_auth_cleanup_ntlm(struct connectdata *conn); -#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ +#else /* !CURL_DISABLE_HTTP && USE_NTLM */ +#define Curl_http_auth_cleanup_ntlm(x) +#endif #endif /* HEADER_CURL_HTTP_NTLM_H */ diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c index 75c7a60..f188cbf 100644 --- a/Utilities/cmcurl/lib/http_proxy.c +++ b/Utilities/cmcurl/lib/http_proxy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -72,6 +72,7 @@ static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex) CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) { + struct Curl_easy *data = conn->data; if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) { const CURLcode result = https_proxy_connect(conn, sockindex); if(result) @@ -127,7 +128,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) conn->data->req.protop = prot_save; if(CURLE_OK != result) return result; - Curl_safefree(conn->allocptr.proxyuserpwd); + Curl_safefree(data->state.aptr.proxyuserpwd); #else return CURLE_NOT_BUILT_IN; #endif @@ -158,15 +159,15 @@ static CURLcode connect_init(struct connectdata *conn, bool reinit) return CURLE_OUT_OF_MEMORY; infof(conn->data, "allocate connect buffer!\n"); conn->connect_state = s; + Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS); } else { DEBUGASSERT(conn->connect_state); s = conn->connect_state; + Curl_dyn_reset(&s->rcvbuf); } s->tunnel_state = TUNNEL_INIT; s->keepon = TRUE; - s->line_start = s->connect_buffer; - s->ptr = s->line_start; s->cl = 0; s->close_connection = FALSE; return CURLE_OK; @@ -176,6 +177,7 @@ static void connect_done(struct connectdata *conn) { struct http_connect_state *s = conn->connect_state; s->tunnel_state = TUNNEL_COMPLETE; + Curl_dyn_free(&s->rcvbuf); infof(conn->data, "CONNECT phase completed!\n"); } @@ -190,6 +192,8 @@ static CURLcode CONNECT(struct connectdata *conn, CURLcode result; curl_socket_t tunnelsocket = conn->sock[sockindex]; struct http_connect_state *s = conn->connect_state; + char *linep; + size_t perline; #define SELECT_OK 0 #define SELECT_ERROR 1 @@ -204,7 +208,7 @@ static CURLcode CONNECT(struct connectdata *conn, if(TUNNEL_INIT == s->tunnel_state) { /* BEGIN CONNECT PHASE */ char *host_port; - Curl_send_buffer *req_buffer; + struct dynbuf req; infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); @@ -215,17 +219,12 @@ static CURLcode CONNECT(struct connectdata *conn, free(data->req.newurl); data->req.newurl = NULL; - /* initialize a dynamic send-buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; - host_port = aprintf("%s:%d", hostname, remote_port); - if(!host_port) { - Curl_add_buffer_free(&req_buffer); + if(!host_port) return CURLE_OUT_OF_MEMORY; - } + + /* initialize a dynamic send-buffer */ + Curl_dyn_init(&req, DYN_HTTP_REQUEST); /* Setup the proxy-authorization header, if any */ result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE); @@ -236,8 +235,8 @@ static CURLcode CONNECT(struct connectdata *conn, char *host = NULL; const char *proxyconn = ""; const char *useragent = ""; - const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? - "1.0" : "1.1"; + const char *httpv = + (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; bool ipv6_ip = conn->bits.ipv6_ip; char *hostheader; @@ -248,7 +247,7 @@ static CURLcode CONNECT(struct connectdata *conn, aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", remote_port); if(!hostheader) { - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(&req); return CURLE_OUT_OF_MEMORY; } @@ -256,7 +255,7 @@ static CURLcode CONNECT(struct connectdata *conn, host = aprintf("Host: %s\r\n", hostheader); if(!host) { free(hostheader); - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(&req); return CURLE_OUT_OF_MEMORY; } } @@ -265,52 +264,49 @@ static CURLcode CONNECT(struct connectdata *conn, if(!Curl_checkProxyheaders(conn, "User-Agent") && data->set.str[STRING_USERAGENT]) - useragent = conn->allocptr.uagent; + useragent = data->state.aptr.uagent; result = - Curl_add_bufferf(&req_buffer, - "CONNECT %s HTTP/%s\r\n" - "%s" /* Host: */ - "%s" /* Proxy-Authorization */ - "%s" /* User-Agent */ - "%s", /* Proxy-Connection */ - hostheader, - http, - host?host:"", - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - useragent, - proxyconn); + Curl_dyn_addf(&req, + "CONNECT %s HTTP/%s\r\n" + "%s" /* Host: */ + "%s" /* Proxy-Authorization */ + "%s" /* User-Agent */ + "%s", /* Proxy-Connection */ + hostheader, + httpv, + host?host:"", + data->state.aptr.proxyuserpwd? + data->state.aptr.proxyuserpwd:"", + useragent, + proxyconn); if(host) free(host); free(hostheader); if(!result) - result = Curl_add_custom_headers(conn, TRUE, req_buffer); + result = Curl_add_custom_headers(conn, TRUE, &req); if(!result) /* CRLF terminate the request */ - result = Curl_add_bufferf(&req_buffer, "\r\n"); + result = Curl_dyn_add(&req, "\r\n"); if(!result) { /* Send the connect request to the proxy */ /* BLOCKING */ - result = - Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, sockindex); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + sockindex); } - req_buffer = NULL; if(result) failf(data, "Failed sending CONNECT to proxy"); } - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(&req); if(result) return result; s->tunnel_state = TUNNEL_CONNECT; - s->perline = 0; } /* END CONNECT PHASE */ check = Curl_timeleft(data, NULL, TRUE); @@ -330,16 +326,11 @@ static CURLcode CONNECT(struct connectdata *conn, while(s->keepon) { ssize_t gotbytes; - - /* make sure we have space to read more data */ - if(s->ptr >= &s->connect_buffer[CONNECT_BUFFER_SIZE]) { - failf(data, "CONNECT response too large!"); - return CURLE_RECV_ERROR; - } + char byte; /* Read one byte at a time to avoid a race condition. Wait at most one second before looping to ensure continuous pgrsUpdates. */ - result = Curl_read(conn, tunnelsocket, s->ptr, 1, &gotbytes); + result = Curl_read(conn, tunnelsocket, &byte, 1, &gotbytes); if(result == CURLE_AGAIN) /* socket buffer drained, return */ return CURLE_OK; @@ -366,11 +357,9 @@ static CURLcode CONNECT(struct connectdata *conn, break; } - if(s->keepon > TRUE) { /* This means we are currently ignoring a response-body */ - s->ptr = s->connect_buffer; if(s->cl) { /* A Content-Length based body: simply count down the counter and make sure to break out of the loop when we're done! */ @@ -390,7 +379,7 @@ static CURLcode CONNECT(struct connectdata *conn, /* now parse the chunked piece of data so that we can properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, s->ptr, 1, &tookcareof, &extra); + r = Curl_httpchunk_read(conn, &byte, 1, &tookcareof, &extra); if(r == CHUNKE_STOP) { /* we're done reading chunks! */ infof(data, "chunk reading DONE\n"); @@ -402,25 +391,27 @@ static CURLcode CONNECT(struct connectdata *conn, continue; } - s->perline++; /* amount of bytes in this line so far */ + if(Curl_dyn_addn(&s->rcvbuf, &byte, 1)) { + failf(data, "CONNECT response too large!"); + return CURLE_RECV_ERROR; + } /* if this is not the end of a header line then continue */ - if(*s->ptr != 0x0a) { - s->ptr++; + if(byte != 0x0a) continue; - } + + linep = Curl_dyn_ptr(&s->rcvbuf); + perline = Curl_dyn_len(&s->rcvbuf); /* amount of bytes in this line */ /* convert from the network encoding */ - result = Curl_convert_from_network(data, s->line_start, - (size_t)s->perline); + result = Curl_convert_from_network(data, linep, perline); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) return result; /* output debug if that is requested */ if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - s->line_start, (size_t)s->perline); + Curl_debug(data, CURLINFO_HEADER_IN, linep, perline); if(!data->set.suppress_connect_headers) { /* send the header to the callback */ @@ -428,23 +419,22 @@ static CURLcode CONNECT(struct connectdata *conn, if(data->set.include_header) writetype |= CLIENTWRITE_BODY; - result = Curl_client_write(conn, writetype, - s->line_start, s->perline); + result = Curl_client_write(conn, writetype, linep, perline); if(result) return result; } - data->info.header_size += (long)s->perline; - data->req.headerbytecount += (long)s->perline; + data->info.header_size += (long)perline; + data->req.headerbytecount += (long)perline; /* Newlines are CRLF, so the CR is ignored as the line isn't really terminated until the LF comes. Treat a following CR as end-of-headers as well.*/ - if(('\r' == s->line_start[0]) || - ('\n' == s->line_start[0])) { + if(('\r' == linep[0]) || + ('\n' == linep[0])) { /* end of response-headers from the proxy */ - s->ptr = s->connect_buffer; + if((407 == k->httpcode) && !data->state.authproblem) { /* If we get a 407 response code with content length when we have no auth problem, we must ignore the @@ -461,21 +451,18 @@ static CURLcode CONNECT(struct connectdata *conn, infof(data, "Ignore chunked response-body\n"); - /* We set ignorebody true here since the chunked - decoder function will acknowledge that. Pay - attention so that this is cleared again when this - function returns! */ + /* We set ignorebody true here since the chunked decoder + function will acknowledge that. Pay attention so that this is + cleared again when this function returns! */ k->ignorebody = TRUE; - if(s->line_start[1] == '\n') { - /* this can only be a LF if the letter at index 0 - was a CR */ - s->line_start++; - } + if(linep[1] == '\n') + /* this can only be a LF if the letter at index 0 was a CR */ + linep++; - /* now parse the chunked piece of data so that we can - properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, s->line_start + 1, 1, &gotbytes, + /* now parse the chunked piece of data so that we can properly + tell when the stream ends */ + r = Curl_httpchunk_read(conn, linep + 1, 1, &gotbytes, &extra); if(r == CHUNKE_STOP) { /* we're done reading chunks! */ @@ -500,14 +487,13 @@ static CURLcode CONNECT(struct connectdata *conn, continue; } - s->line_start[s->perline] = 0; /* zero terminate the buffer */ - if((checkprefix("WWW-Authenticate:", s->line_start) && + if((checkprefix("WWW-Authenticate:", linep) && (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", s->line_start) && + (checkprefix("Proxy-authenticate:", linep) && (407 == k->httpcode))) { bool proxy = (k->httpcode == 407) ? TRUE : FALSE; - char *auth = Curl_copy_header_value(s->line_start); + char *auth = Curl_copy_header_value(linep); if(!auth) return CURLE_OUT_OF_MEMORY; @@ -518,7 +504,7 @@ static CURLcode CONNECT(struct connectdata *conn, if(result) return result; } - else if(checkprefix("Content-Length:", s->line_start)) { + else if(checkprefix("Content-Length:", linep)) { if(k->httpcode/100 == 2) { /* A client MUST ignore any Content-Length or Transfer-Encoding header fields received in a successful response to CONNECT. @@ -527,13 +513,13 @@ static CURLcode CONNECT(struct connectdata *conn, k->httpcode); } else { - (void)curlx_strtoofft(s->line_start + + (void)curlx_strtoofft(linep + strlen("Content-Length:"), NULL, 10, &s->cl); } } - else if(Curl_compareheader(s->line_start, "Connection:", "close")) + else if(Curl_compareheader(linep, "Connection:", "close")) s->close_connection = TRUE; - else if(checkprefix("Transfer-Encoding:", s->line_start)) { + else if(checkprefix("Transfer-Encoding:", linep)) { if(k->httpcode/100 == 2) { /* A client MUST ignore any Content-Length or Transfer-Encoding header fields received in a successful response to CONNECT. @@ -541,7 +527,7 @@ static CURLcode CONNECT(struct connectdata *conn, infof(data, "Ignoring Transfer-Encoding in " "CONNECT %03d response\n", k->httpcode); } - else if(Curl_compareheader(s->line_start, + else if(Curl_compareheader(linep, "Transfer-Encoding:", "chunked")) { infof(data, "CONNECT responded chunked\n"); s->chunked_encoding = TRUE; @@ -549,19 +535,16 @@ static CURLcode CONNECT(struct connectdata *conn, Curl_httpchunk_init(conn); } } - else if(Curl_compareheader(s->line_start, - "Proxy-Connection:", "close")) + else if(Curl_compareheader(linep, "Proxy-Connection:", "close")) s->close_connection = TRUE; - else if(2 == sscanf(s->line_start, "HTTP/1.%d %d", + else if(2 == sscanf(linep, "HTTP/1.%d %d", &subversion, &k->httpcode)) { /* store the HTTP code from the proxy */ data->info.httpproxycode = k->httpcode; } - s->perline = 0; /* line starts over here */ - s->ptr = s->connect_buffer; - s->line_start = s->ptr; + Curl_dyn_reset(&s->rcvbuf); } /* while there's buffer left and loop is requested */ if(Curl_pgrsUpdate(conn)) @@ -622,6 +605,7 @@ static CURLcode CONNECT(struct connectdata *conn, if(conn->bits.proxy_connect_closed) /* this is not an error, just part of the connection negotiation */ return CURLE_OK; + Curl_dyn_free(&s->rcvbuf); failf(data, "Received HTTP code %d from proxy after CONNECT", data->req.httpcode); return CURLE_RECV_ERROR; @@ -632,8 +616,8 @@ static CURLcode CONNECT(struct connectdata *conn, /* If a proxy-authorization header was used for the proxy, then we should make sure that it isn't accidentally used for the document request after we've connected. So let's free and clear it here. */ - Curl_safefree(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = NULL; + Curl_safefree(data->state.aptr.proxyuserpwd); + data->state.aptr.proxyuserpwd = NULL; data->state.authproxy.done = TRUE; data->state.authproxy.multipass = FALSE; @@ -643,6 +627,7 @@ static CURLcode CONNECT(struct connectdata *conn, data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */ conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the document request */ + Curl_dyn_free(&s->rcvbuf); return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h index e19fa85..29988a6 100644 --- a/Utilities/cmcurl/lib/http_proxy.h +++ b/Utilities/cmcurl/lib/http_proxy.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,5 +47,6 @@ bool Curl_connect_ongoing(struct connectdata *conn); #endif void Curl_connect_free(struct Curl_easy *data); +void Curl_connect_done(struct Curl_easy *data); #endif /* HEADER_CURL_HTTP_PROXY_H */ diff --git a/Utilities/cmcurl/lib/idn_win32.c b/Utilities/cmcurl/lib/idn_win32.c index 8dc300b..2f5850d 100644 --- a/Utilities/cmcurl/lib/idn_win32.c +++ b/Utilities/cmcurl/lib/idn_win32.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -72,13 +72,13 @@ bool curl_win32_idn_to_ascii(const char *in, char **out) { bool success = FALSE; - wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); + wchar_t *in_w = curlx_convert_UTF8_to_wchar(in); if(in_w) { wchar_t punycode[IDN_MAX_LENGTH]; int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH); free(in_w); if(chars) { - *out = Curl_convert_wchar_to_UTF8(punycode); + *out = curlx_convert_wchar_to_UTF8(punycode); if(*out) success = TRUE; } @@ -91,7 +91,7 @@ bool curl_win32_ascii_to_idn(const char *in, char **out) { bool success = FALSE; - wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); + wchar_t *in_w = curlx_convert_UTF8_to_wchar(in); if(in_w) { size_t in_len = wcslen(in_w) + 1; wchar_t unicode[IDN_MAX_LENGTH]; @@ -99,7 +99,7 @@ bool curl_win32_ascii_to_idn(const char *in, char **out) unicode, IDN_MAX_LENGTH); free(in_w); if(chars) { - *out = Curl_convert_wchar_to_UTF8(unicode); + *out = curlx_convert_wchar_to_UTF8(unicode); if(*out) success = TRUE; } diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c index d003de6..b283f67 100644 --- a/Utilities/cmcurl/lib/if2ip.c +++ b/Utilities/cmcurl/lib/if2ip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -129,11 +129,11 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); if(ifscope != remote_scope) { - /* We are interested only in interface addresses whose - scope matches the remote address we want to - connect to: global for global, link-local for - link-local, etc... */ - if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; + /* We are interested only in interface addresses whose scope + matches the remote address we want to connect to: global + for global, link-local for link-local, etc... */ + if(res == IF2IP_NOT_FOUND) + res = IF2IP_AF_NOT_SUPPORTED; continue; } diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c index 66172bd..14c76f0 100644 --- a/Utilities/cmcurl/lib/imap.c +++ b/Utilities/cmcurl/lib/imap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -187,7 +187,7 @@ static void imap_to_imaps(struct connectdata *conn) conn->handler = &Curl_handler_imaps; /* Set the connection's upgraded to TLS flag */ - conn->tls_upgraded = TRUE; + conn->bits.tls_upgraded = TRUE; } #else #define imap_to_imaps(x) Curl_nop_stmt @@ -1710,7 +1710,7 @@ static CURLcode imap_setup_connection(struct connectdata *conn) return result; /* Clear the TLS upgraded flag */ - conn->tls_upgraded = FALSE; + conn->bits.tls_upgraded = FALSE; return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c index 771edb4..2730658 100644 --- a/Utilities/cmcurl/lib/ldap.c +++ b/Utilities/cmcurl/lib/ldap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -75,7 +75,7 @@ /* Use our own implementation. */ -typedef struct { +struct ldap_urldesc { char *lud_host; int lud_port; #if defined(USE_WIN32_LDAP) @@ -95,10 +95,10 @@ typedef struct { size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the "real" struct so can only be used in code without HAVE_LDAP_URL_PARSE defined */ -} CURL_LDAPURLDesc; +}; #undef LDAPURLDesc -#define LDAPURLDesc CURL_LDAPURLDesc +#define LDAPURLDesc struct ldap_urldesc static int _ldap_url_parse(const struct connectdata *conn, LDAPURLDesc **ludp); @@ -239,13 +239,13 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server, PTCHAR inpass = NULL; if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) { - inuser = Curl_convert_UTF8_to_tchar((char *) user); - inpass = Curl_convert_UTF8_to_tchar((char *) passwd); + inuser = curlx_convert_UTF8_to_tchar((char *) user); + inpass = curlx_convert_UTF8_to_tchar((char *) passwd); rc = ldap_simple_bind_s(server, inuser, inpass); - Curl_unicodefree(inuser); - Curl_unicodefree(inpass); + curlx_unicodefree(inuser); + curlx_unicodefree(inpass); } #if defined(USE_WINDOWS_SSPI) else { @@ -306,7 +306,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) ldap_ssl ? "encrypted" : "cleartext"); #if defined(USE_WIN32_LDAP) - host = Curl_convert_UTF8_to_tchar(conn->host.name); + host = curlx_convert_UTF8_to_tchar(conn->host.name); if(!host) { result = CURLE_OUT_OF_MEMORY; @@ -517,7 +517,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) size_t name_len; #if defined(USE_WIN32_LDAP) TCHAR *dn = ldap_get_dn(server, entryIterator); - name = Curl_convert_tchar_to_UTF8(dn); + name = curlx_convert_tchar_to_UTF8(dn); if(!name) { ldap_memfree(dn); @@ -533,7 +533,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); if(result) { #if defined(USE_WIN32_LDAP) - Curl_unicodefree(name); + curlx_unicodefree(name); #endif ldap_memfree(dn); @@ -544,7 +544,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) name_len); if(result) { #if defined(USE_WIN32_LDAP) - Curl_unicodefree(name); + curlx_unicodefree(name); #endif ldap_memfree(dn); @@ -554,7 +554,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); if(result) { #if defined(USE_WIN32_LDAP) - Curl_unicodefree(name); + curlx_unicodefree(name); #endif ldap_memfree(dn); @@ -564,7 +564,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) dlsize += name_len + 5; #if defined(USE_WIN32_LDAP) - Curl_unicodefree(name); + curlx_unicodefree(name); #endif ldap_memfree(dn); } @@ -576,7 +576,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) BerValue **vals; size_t attr_len; #if defined(USE_WIN32_LDAP) - char *attr = Curl_convert_tchar_to_UTF8(attribute); + char *attr = curlx_convert_tchar_to_UTF8(attribute); if(!attr) { if(ber) ber_free(ber, 0); @@ -597,7 +597,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); + curlx_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) @@ -611,7 +611,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); + curlx_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) @@ -624,7 +624,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); + curlx_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) @@ -646,7 +646,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); + curlx_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) @@ -662,7 +662,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); + curlx_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) @@ -680,7 +680,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); + curlx_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) @@ -696,7 +696,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); + curlx_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) @@ -714,7 +714,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) /* Free the attribute as we are done with it */ #if defined(USE_WIN32_LDAP) - Curl_unicodefree(attr); + curlx_unicodefree(attr); #endif ldap_memfree(attribute); @@ -746,7 +746,7 @@ quit: #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */ #if defined(USE_WIN32_LDAP) - Curl_unicodefree(host); + curlx_unicodefree(host); #endif /* no data to transfer */ @@ -892,10 +892,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) #if defined(USE_WIN32_LDAP) /* Convert the unescaped string to a tchar */ - ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped); + ludp->lud_dn = curlx_convert_UTF8_to_tchar(unescaped); /* Free the unescaped string as we are done with it */ - Curl_unicodefree(unescaped); + curlx_unicodefree(unescaped); if(!ludp->lud_dn) { rc = LDAP_NO_MEMORY; @@ -960,10 +960,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) #if defined(USE_WIN32_LDAP) /* Convert the unescaped string to a tchar */ - ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped); + ludp->lud_attrs[i] = curlx_convert_UTF8_to_tchar(unescaped); /* Free the unescaped string as we are done with it */ - Curl_unicodefree(unescaped); + curlx_unicodefree(unescaped); if(!ludp->lud_attrs[i]) { free(attributes); @@ -1027,10 +1027,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) #if defined(USE_WIN32_LDAP) /* Convert the unescaped string to a tchar */ - ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped); + ludp->lud_filter = curlx_convert_UTF8_to_tchar(unescaped); /* Free the unescaped string as we are done with it */ - Curl_unicodefree(unescaped); + curlx_unicodefree(unescaped); if(!ludp->lud_filter) { rc = LDAP_NO_MEMORY; diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c index 38f1b2b..0fab52d 100644 --- a/Utilities/cmcurl/lib/md4.c +++ b/Utilities/cmcurl/lib/md4.c @@ -29,6 +29,10 @@ #ifdef USE_OPENSSL #include <openssl/opensslconf.h> +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */ +#define OPENSSL_NO_MD4 +#endif #endif /* USE_OPENSSL */ #ifdef USE_MBEDTLS @@ -135,10 +139,11 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) /* The last #include file should be: */ #include "memdebug.h" -typedef struct { +struct md4_ctx { HCRYPTPROV hCryptProv; HCRYPTHASH hHash; -} MD4_CTX; +}; +typedef struct md4_ctx MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { @@ -146,7 +151,7 @@ static void MD4_Init(MD4_CTX *ctx) ctx->hHash = 0; if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { CryptCreateHash(ctx->hCryptProv, CALG_MD4, 0, 0, &ctx->hHash); } } @@ -180,10 +185,11 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) /* The last #include file should be: */ #include "memdebug.h" -typedef struct { +struct md4_ctx { void *data; unsigned long size; -} MD4_CTX; +}; +typedef struct md4_ctx MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { @@ -262,12 +268,13 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) /* Any 32-bit or wider unsigned integer data type will do */ typedef unsigned int MD4_u32plus; -typedef struct { +struct md4_ctx { MD4_u32plus lo, hi; MD4_u32plus a, b, c, d; unsigned char buffer[64]; MD4_u32plus block[16]; -} MD4_CTX; +}; +typedef struct md4_ctx MD4_CTX; static void MD4_Init(MD4_CTX *ctx); static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size); diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c index 3f601b3..557a51e 100644 --- a/Utilities/cmcurl/lib/md5.c +++ b/Utilities/cmcurl/lib/md5.c @@ -179,15 +179,16 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) /* The last #include file should be: */ #include "memdebug.h" -typedef struct { +struct md5_ctx { HCRYPTPROV hCryptProv; HCRYPTHASH hHash; -} MD5_CTX; +}; +typedef struct md5_ctx MD5_CTX; static void MD5_Init(MD5_CTX *ctx) { - if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, - PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); } } @@ -261,12 +262,13 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) /* Any 32-bit or wider unsigned integer data type will do */ typedef unsigned int MD5_u32plus; -typedef struct { +struct md5_ctx { MD5_u32plus lo, hi; MD5_u32plus a, b, c, d; unsigned char buffer[64]; MD5_u32plus block[16]; -} MD5_CTX; +}; +typedef struct md5_ctx MD5_CTX; static void MD5_Init(MD5_CTX *ctx); static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); @@ -528,7 +530,7 @@ static void MD5_Final(unsigned char *result, MD5_CTX *ctx) #endif /* CRYPTO LIBS */ -const HMAC_params Curl_HMAC_MD5[] = { +const struct HMAC_params Curl_HMAC_MD5[] = { { /* Hash initialization function. */ CURLX_FUNCTION_CAST(HMAC_hinit_func, MD5_Init), @@ -545,7 +547,7 @@ const HMAC_params Curl_HMAC_MD5[] = { } }; -const MD5_params Curl_DIGEST_MD5[] = { +const struct MD5_params Curl_DIGEST_MD5[] = { { /* Digest initialization function */ CURLX_FUNCTION_CAST(Curl_MD5_init_func, MD5_Init), @@ -573,9 +575,9 @@ void Curl_md5it(unsigned char *outbuffer, const unsigned char *input, MD5_Final(outbuffer, &ctx); } -MD5_context *Curl_MD5_init(const MD5_params *md5params) +struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params) { - MD5_context *ctxt; + struct MD5_context *ctxt; /* Create MD5 context */ ctxt = malloc(sizeof(*ctxt)); @@ -597,7 +599,7 @@ MD5_context *Curl_MD5_init(const MD5_params *md5params) return ctxt; } -CURLcode Curl_MD5_update(MD5_context *context, +CURLcode Curl_MD5_update(struct MD5_context *context, const unsigned char *data, unsigned int len) { @@ -606,7 +608,7 @@ CURLcode Curl_MD5_update(MD5_context *context, return CURLE_OK; } -CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result) +CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result) { (*context->md5_hash->md5_final_func)(result, context->md5_hashctx); diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c index ede6009..1c6b151 100644 --- a/Utilities/cmcurl/lib/memdebug.c +++ b/Utilities/cmcurl/lib/memdebug.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -328,7 +328,7 @@ void curl_dbg_free(void *ptr, int line, const char *source) (Curl_cfree)(mem); } - if(source) + if(source && ptr) curl_dbg_log("MEM %s:%d free(%p)\n", source, line, (void *)ptr); } diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c index 2571287..4a87c4a 100644 --- a/Utilities/cmcurl/lib/mime.c +++ b/Utilities/cmcurl/lib/mime.c @@ -26,6 +26,7 @@ #include "mime.h" #include "non-ascii.h" +#include "warnless.h" #include "urldata.h" #include "sendf.h" @@ -52,6 +53,10 @@ #define READ_ERROR ((size_t) -1) +#define STOP_FILLING ((size_t) -2) + +static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, + void *instream, bool *hasread); /* Encoders. */ static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, @@ -66,7 +71,7 @@ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, curl_mimepart *part); static curl_off_t encoder_qp_size(curl_mimepart *part); -static const mime_encoder encoders[] = { +static const struct mime_encoder encoders[] = { {"binary", encoder_nop_read, encoder_nop_size}, {"8bit", encoder_nop_read, encoder_nop_size}, {"7bit", encoder_7bit_read, encoder_nop_size}, @@ -264,7 +269,8 @@ static char *Curl_basename(char *path) /* Set readback state. */ -static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr) +static void mimesetstate(struct mime_state *state, + enum mimestate tok, void *ptr) { state->state = tok; state->ptr = ptr; @@ -337,7 +343,7 @@ static char *strippath(const char *fullfile) } /* Initialize data encoder state. */ -static void cleanup_encoder_state(mime_encoder_state *p) +static void cleanup_encoder_state(struct mime_encoder_state *p) { p->pos = 0; p->bufbeg = 0; @@ -347,17 +353,22 @@ static void cleanup_encoder_state(mime_encoder_state *p) /* Dummy encoder. This is used for 8bit and binary content encodings. */ static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part) + struct curl_mimepart *part) { - mime_encoder_state *st = &part->encstate; + struct mime_encoder_state *st = &part->encstate; size_t insize = st->bufend - st->bufbeg; (void) ateof; + if(!size) + return STOP_FILLING; + if(size > insize) size = insize; + if(size) - memcpy(buffer, st->buf, size); + memcpy(buffer, st->buf + st->bufbeg, size); + st->bufbeg += size; return size; } @@ -372,11 +383,14 @@ static curl_off_t encoder_nop_size(curl_mimepart *part) static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, curl_mimepart *part) { - mime_encoder_state *st = &part->encstate; + struct mime_encoder_state *st = &part->encstate; size_t cursize = st->bufend - st->bufbeg; (void) ateof; + if(!size) + return STOP_FILLING; + if(size > cursize) size = cursize; @@ -395,7 +409,7 @@ static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, curl_mimepart *part) { - mime_encoder_state *st = &part->encstate; + struct mime_encoder_state *st = &part->encstate; size_t cursize = 0; int i; char *ptr = buffer; @@ -404,8 +418,11 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, /* Line full ? */ if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) { /* Yes, we need 2 characters for CRLF. */ - if(size < 2) + if(size < 2) { + if(!cursize) + return STOP_FILLING; break; + } *ptr++ = '\r'; *ptr++ = '\n'; st->pos = 0; @@ -414,7 +431,12 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, } /* Be sure there is enough space and input data for a base64 group. */ - if(size < 4 || st->bufend - st->bufbeg < 3) + if(size < 4) { + if(!cursize) + return STOP_FILLING; + break; + } + if(st->bufend - st->bufbeg < 3) break; /* Encode three bytes as four characters. */ @@ -431,25 +453,31 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, } /* If at eof, we have to flush the buffered data. */ - if(ateof && size >= 4) { - /* Buffered data size can only be 0, 1 or 2. */ - ptr[2] = ptr[3] = '='; - i = 0; - switch(st->bufend - st->bufbeg) { - case 2: - i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; - /* FALLTHROUGH */ - case 1: - i |= (st->buf[st->bufbeg] & 0xFF) << 16; - ptr[0] = base64[(i >> 18) & 0x3F]; - ptr[1] = base64[(i >> 12) & 0x3F]; - if(++st->bufbeg != st->bufend) { - ptr[2] = base64[(i >> 6) & 0x3F]; - st->bufbeg++; + if(ateof) { + if(size < 4) { + if(!cursize) + return STOP_FILLING; + } + else { + /* Buffered data size can only be 0, 1 or 2. */ + ptr[2] = ptr[3] = '='; + i = 0; + switch(st->bufend - st->bufbeg) { + case 2: + i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; + /* FALLTHROUGH */ + case 1: + i |= (st->buf[st->bufbeg] & 0xFF) << 16; + ptr[0] = base64[(i >> 18) & 0x3F]; + ptr[1] = base64[(i >> 12) & 0x3F]; + if(++st->bufbeg != st->bufend) { + ptr[2] = base64[(i >> 6) & 0x3F]; + st->bufbeg++; + } + cursize += 4; + st->pos += 4; + break; } - cursize += 4; - st->pos += 4; - break; } } @@ -485,7 +513,7 @@ static curl_off_t encoder_base64_size(curl_mimepart *part) * Check if a CRLF or end of data is in input buffer at current position + n. * Return -1 if more data needed, 1 if CRLF or end of data, else 0. */ -static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n) +static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n) { n += st->bufbeg; if(n >= st->bufend && ateof) @@ -502,7 +530,7 @@ static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n) static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, curl_mimepart *part) { - mime_encoder_state *st = &part->encstate; + struct mime_encoder_state *st = &part->encstate; char *ptr = buffer; size_t cursize = 0; int softlinebreak; @@ -567,7 +595,6 @@ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, switch(qp_lookahead_eol(st, ateof, consumed)) { case -1: /* Need more data. */ return cursize; - break; case 0: /* Not followed by a CRLF. */ softlinebreak = 1; break; @@ -581,8 +608,11 @@ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, } /* If the output buffer would overflow, do not store. */ - if(len > size) + if(len > size) { + if(!cursize) + return STOP_FILLING; break; + } /* Append to output buffer. */ memcpy(ptr, buf, len); @@ -612,16 +642,18 @@ static size_t mime_mem_read(char *buffer, size_t size, size_t nitems, void *instream) { curl_mimepart *part = (curl_mimepart *) instream; - size_t sz = (size_t) part->datasize - part->state.offset; + size_t sz = curlx_sotouz(part->datasize - part->state.offset); (void) size; /* Always 1.*/ + if(!nitems) + return STOP_FILLING; + if(sz > nitems) sz = nitems; if(sz) - memcpy(buffer, (char *) &part->data[part->state.offset], sz); + memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz); - part->state.offset += sz; return sz; } @@ -641,7 +673,7 @@ static int mime_mem_seek(void *instream, curl_off_t offset, int whence) if(offset < 0 || offset > part->datasize) return CURL_SEEKFUNC_FAIL; - part->state.offset = (size_t) offset; + part->state.offset = offset; return CURL_SEEKFUNC_OK; } @@ -653,7 +685,7 @@ static void mime_mem_free(void *ptr) /* Named file callbacks. */ /* Argument is a pointer to the mime part. */ -static int mime_open_file(curl_mimepart * part) +static int mime_open_file(curl_mimepart *part) { /* Open a MIMEKIND_FILE part. */ @@ -668,6 +700,9 @@ static size_t mime_file_read(char *buffer, size_t size, size_t nitems, { curl_mimepart *part = (curl_mimepart *) instream; + if(!nitems) + return STOP_FILLING; + if(mime_open_file(part)) return READ_ERROR; @@ -705,21 +740,22 @@ static void mime_file_free(void *ptr) /* Argument is a pointer to the mime structure. */ /* Readback a byte string segment. */ -static size_t readback_bytes(mime_state *state, +static size_t readback_bytes(struct mime_state *state, char *buffer, size_t bufsize, const char *bytes, size_t numbytes, const char *trail) { size_t sz; + size_t offset = curlx_sotouz(state->offset); - if(numbytes > state->offset) { - sz = numbytes - state->offset; - bytes += state->offset; + if(numbytes > offset) { + sz = numbytes - offset; + bytes += offset; } else { size_t tsz = strlen(trail); - sz = state->offset - numbytes; + sz = offset - numbytes; if(sz >= tsz) return 0; bytes = trail + sz; @@ -736,25 +772,79 @@ static size_t readback_bytes(mime_state *state, /* Read a non-encoded part content. */ static size_t read_part_content(curl_mimepart *part, - char *buffer, size_t bufsize) + char *buffer, size_t bufsize, bool *hasread) { size_t sz = 0; - if(part->readfunc) - sz = part->readfunc(buffer, 1, bufsize, part->arg); + switch(part->lastreadstatus) { + case 0: + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + return part->lastreadstatus; + default: + break; + } + + /* If we can determine we are at end of part data, spare a read. */ + if(part->datasize != (curl_off_t) -1 && + part->state.offset >= part->datasize) { + /* sz is already zero. */ + } + else { + switch(part->kind) { + case MIMEKIND_MULTIPART: + /* + * Cannot be processed as other kinds since read function requires + * an additional parameter and is highly recursive. + */ + sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread); + break; + case MIMEKIND_FILE: + if(part->fp && feof(part->fp)) + break; /* At EOF. */ + /* FALLTHROUGH */ + default: + if(part->readfunc) { + if(!(part->flags & MIME_FAST_READ)) { + if(*hasread) + return STOP_FILLING; + *hasread = TRUE; + } + sz = part->readfunc(buffer, 1, bufsize, part->arg); + } + break; + } + } + + switch(sz) { + case STOP_FILLING: + break; + case 0: + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + part->lastreadstatus = sz; + break; + default: + part->state.offset += sz; + part->lastreadstatus = sz; + break; + } + return sz; } /* Read and encode part content. */ -static size_t read_encoded_part_content(curl_mimepart *part, - char *buffer, size_t bufsize) +static size_t read_encoded_part_content(curl_mimepart *part, char *buffer, + size_t bufsize, bool *hasread) { - mime_encoder_state *st = &part->encstate; + struct mime_encoder_state *st = &part->encstate; size_t cursize = 0; size_t sz; bool ateof = FALSE; - while(bufsize) { + for(;;) { if(st->bufbeg < st->bufend || ateof) { /* Encode buffered data. */ sz = part->encoder->encodefunc(buffer, bufsize, ateof, part); @@ -763,9 +853,8 @@ static size_t read_encoded_part_content(curl_mimepart *part, if(ateof) return cursize; break; - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: case READ_ERROR: + case STOP_FILLING: return cursize? cursize: sz; default: cursize += sz; @@ -787,7 +876,7 @@ static size_t read_encoded_part_content(curl_mimepart *part, if(st->bufend >= sizeof(st->buf)) return cursize? cursize: READ_ERROR; /* Buffer full. */ sz = read_part_content(part, st->buf + st->bufend, - sizeof(st->buf) - st->bufend); + sizeof(st->buf) - st->bufend, hasread); switch(sz) { case 0: ateof = TRUE; @@ -795,6 +884,7 @@ static size_t read_encoded_part_content(curl_mimepart *part, case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: + case STOP_FILLING: return cursize? cursize: sz; default: st->bufend += sz; @@ -802,12 +892,12 @@ static size_t read_encoded_part_content(curl_mimepart *part, } } - return cursize; + /* NOTREACHED */ } /* Readback a mime part. */ static size_t readback_part(curl_mimepart *part, - char *buffer, size_t bufsize) + char *buffer, size_t bufsize, bool *hasread) { size_t cursize = 0; #ifdef CURL_DOES_CONVERSIONS @@ -866,9 +956,9 @@ static size_t readback_part(curl_mimepart *part, break; case MIMESTATE_CONTENT: if(part->encoder) - sz = read_encoded_part_content(part, buffer, bufsize); + sz = read_encoded_part_content(part, buffer, bufsize, hasread); else - sz = read_part_content(part, buffer, bufsize); + sz = read_part_content(part, buffer, bufsize, hasread); switch(sz) { case 0: mimesetstate(&part->state, MIMESTATE_END, NULL); @@ -881,6 +971,7 @@ static size_t readback_part(curl_mimepart *part, case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: + case STOP_FILLING: return cursize? cursize: sz; } break; @@ -909,9 +1000,9 @@ static size_t readback_part(curl_mimepart *part, return cursize; } -/* Readback from mime. */ +/* Readback from mime. Warning: not a read callback function. */ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, - void *instream) + void *instream, bool *hasread) { curl_mime *mime = (curl_mime *) instream; size_t cursize = 0; @@ -932,7 +1023,7 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, #endif mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart); /* The first boundary always follows the header termination empty line, - so is always preceded by a CRLK. We can then spare 2 characters + so is always preceded by a CRLF. We can then spare 2 characters by skipping the leading CRLF in boundary. */ mime->state.offset += 2; break; @@ -962,11 +1053,12 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, mimesetstate(&mime->state, MIMESTATE_END, NULL); break; } - sz = readback_part(part, buffer, nitems); + sz = readback_part(part, buffer, nitems, hasread); switch(sz) { case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: + case STOP_FILLING: return cursize? cursize: sz; case 0: #ifdef CURL_DOES_CONVERSIONS @@ -1031,6 +1123,7 @@ static int mime_part_rewind(curl_mimepart *part) if(res == CURL_SEEKFUNC_OK) mimesetstate(&part->state, targetstate, NULL); + part->lastreadstatus = 1; /* Successful read status. */ return res; } @@ -1073,6 +1166,8 @@ static void cleanup_part_content(curl_mimepart *part) part->datasize = (curl_off_t) 0; /* No size yet. */ cleanup_encoder_state(&part->encstate); part->kind = MIMEKIND_NONE; + part->flags &= ~MIME_FAST_READ; + part->lastreadstatus = 1; /* Successful read status. */ } static void mime_subparts_free(void *ptr) @@ -1238,6 +1333,7 @@ void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy) { memset((char *) part, 0, sizeof(*part)); part->easy = easy; + part->lastreadstatus = 1; /* Successful read status. */ mimesetstate(&part->state, MIMESTATE_BEGIN, NULL); } @@ -1328,6 +1424,7 @@ CURLcode curl_mime_data(curl_mimepart *part, part->readfunc = mime_mem_read; part->seekfunc = mime_mem_seek; part->freefunc = mime_mem_free; + part->flags |= MIME_FAST_READ; part->kind = MIMEKIND_DATA; } @@ -1405,7 +1502,7 @@ CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) { CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; - const mime_encoder *mep; + const struct mime_encoder *mep; if(!part) return result; @@ -1502,7 +1599,7 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part, } subparts->parent = part; - part->readfunc = mime_subparts_read; + /* Subparts are processed internally: no read callback. */ part->seekfunc = mime_subparts_seek; part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind; part->arg = subparts; @@ -1524,9 +1621,23 @@ CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) { curl_mimepart *part = (curl_mimepart *) instream; + size_t ret; + bool hasread; (void) size; /* Always 1. */ - return readback_part(part, buffer, nitems); + + do { + hasread = FALSE; + ret = readback_part(part, buffer, nitems, &hasread); + /* + * If this is not possible to get some data without calling more than + * one read callback (probably because a content encoder is not able to + * deliver a new bunch for the few data accumulated so far), force another + * read until we get enough data or a special exit code. + */ + } while(ret == STOP_FILLING); + + return ret; } /* Rewind mime stream. */ @@ -1667,6 +1778,23 @@ const char *Curl_mime_contenttype(const char *filename) return NULL; } +static bool content_type_match(const char *contenttype, const char *target) +{ + size_t len = strlen(target); + + if(contenttype && strncasecompare(contenttype, target, len)) + switch(contenttype[len]) { + case '\0': + case '\t': + case '\r': + case '\n': + case ' ': + case ';': + return TRUE; + } + return FALSE; +} + CURLcode Curl_mime_prepare_headers(curl_mimepart *part, const char *contenttype, const char *disposition, @@ -1718,7 +1846,7 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part, boundary = mime->boundary; } else if(contenttype && !customct && - strcasecompare(contenttype, "text/plain")) + content_type_match(contenttype, "text/plain")) if(strategy == MIMESTRATEGY_MAIL || !part->filename) contenttype = NULL; @@ -1794,7 +1922,7 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part, curl_mimepart *subpart; disposition = NULL; - if(strcasecompare(contenttype, "multipart/form-data")) + if(content_type_match(contenttype, "multipart/form-data")) disposition = "form-data"; for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) { ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy); @@ -1805,6 +1933,26 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part, return ret; } +/* Recursively reset paused status in the given part. */ +void Curl_mime_unpause(curl_mimepart *part) +{ + if(part) { + if(part->lastreadstatus == CURL_READFUNC_PAUSE) + part->lastreadstatus = 1; /* Successful read status. */ + if(part->kind == MIMEKIND_MULTIPART) { + curl_mime *mime = (curl_mime *) part->arg; + + if(mime) { + curl_mimepart *subpart; + + for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) + Curl_mime_unpause(subpart); + } + } + } +} + + #else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ /* Mime not compiled in: define stubs for externally-referenced functions. */ diff --git a/Utilities/cmcurl/lib/mime.h b/Utilities/cmcurl/lib/mime.h index 4312125..50b7ea6 100644 --- a/Utilities/cmcurl/lib/mime.h +++ b/Utilities/cmcurl/lib/mime.h @@ -31,6 +31,7 @@ /* Part flags. */ #define MIME_USERHEADERS_OWNER (1 << 0) #define MIME_BODY_ONLY (1 << 1) +#define MIME_FAST_READ (1 << 2) #define FILE_CONTENTTYPE_DEFAULT "application/octet-stream" #define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed" @@ -68,43 +69,43 @@ enum mimestrategy { }; /* Content transfer encoder. */ -typedef struct { +struct mime_encoder { const char * name; /* Encoding name. */ size_t (*encodefunc)(char *buffer, size_t size, bool ateof, curl_mimepart *part); /* Encoded read. */ curl_off_t (*sizefunc)(curl_mimepart *part); /* Encoded size. */ -} mime_encoder; +}; /* Content transfer encoder state. */ -typedef struct { +struct mime_encoder_state { size_t pos; /* Position on output line. */ size_t bufbeg; /* Next data index in input buffer. */ size_t bufend; /* First unused byte index in input buffer. */ char buf[ENCODING_BUFFER_SIZE]; /* Input buffer. */ -} mime_encoder_state; +}; /* Mime readback state. */ -typedef struct { +struct mime_state { enum mimestate state; /* Current state token. */ void *ptr; /* State-dependent pointer. */ - size_t offset; /* State-dependent offset. */ -} mime_state; + curl_off_t offset; /* State-dependent offset. */ +}; /* minimum buffer size for the boundary string */ #define MIME_BOUNDARY_LEN (24 + MIME_RAND_BOUNDARY_CHARS + 1) /* A mime multipart. */ -struct curl_mime_s { +struct curl_mime { struct Curl_easy *easy; /* The associated easy handle. */ curl_mimepart *parent; /* Parent part. */ curl_mimepart *firstpart; /* First part. */ curl_mimepart *lastpart; /* Last part. */ char boundary[MIME_BOUNDARY_LEN]; /* The part boundary. */ - mime_state state; /* Current readback state. */ + struct mime_state state; /* Current readback state. */ }; /* A mime part. */ -struct curl_mimepart_s { +struct curl_mimepart { struct Curl_easy *easy; /* The associated easy handle. */ curl_mime *parent; /* Parent mime structure. */ curl_mimepart *nextpart; /* Forward linked list. */ @@ -122,9 +123,10 @@ struct curl_mimepart_s { char *name; /* Data name. */ curl_off_t datasize; /* Expected data size. */ unsigned int flags; /* Flags. */ - mime_state state; /* Current readback state. */ - const mime_encoder *encoder; /* Content data encoder. */ - mime_encoder_state encstate; /* Data encoder state. */ + struct mime_state state; /* Current readback state. */ + const struct mime_encoder *encoder; /* Content data encoder. */ + struct mime_encoder_state encstate; /* Data encoder state. */ + size_t lastreadstatus; /* Last read callback returned status. */ }; CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); @@ -133,20 +135,23 @@ CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) /* Prototypes. */ -void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy); -void Curl_mime_cleanpart(curl_mimepart *part); -CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src); -CURLcode Curl_mime_set_subparts(curl_mimepart *part, - curl_mime *subparts, int take_ownership); -CURLcode Curl_mime_prepare_headers(curl_mimepart *part, +void Curl_mime_initpart(struct curl_mimepart *part, struct Curl_easy *easy); +void Curl_mime_cleanpart(struct curl_mimepart *part); +CURLcode Curl_mime_duppart(struct curl_mimepart *dst, + const curl_mimepart *src); +CURLcode Curl_mime_set_subparts(struct curl_mimepart *part, + struct curl_mime *subparts, + int take_ownership); +CURLcode Curl_mime_prepare_headers(struct curl_mimepart *part, const char *contenttype, const char *disposition, enum mimestrategy strategy); -curl_off_t Curl_mime_size(curl_mimepart *part); +curl_off_t Curl_mime_size(struct curl_mimepart *part); size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream); -CURLcode Curl_mime_rewind(curl_mimepart *part); +CURLcode Curl_mime_rewind(struct curl_mimepart *part); const char *Curl_mime_contenttype(const char *filename); +void Curl_mime_unpause(struct curl_mimepart *part); #else /* if disabled */ @@ -158,6 +163,7 @@ const char *Curl_mime_contenttype(const char *filename); #define Curl_mime_size(x) (curl_off_t) -1 #define Curl_mime_read NULL #define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN) +#define Curl_mime_unpause(x) #endif diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c index bc00913..63c9d11 100644 --- a/Utilities/cmcurl/lib/mprintf.c +++ b/Utilities/cmcurl/lib/mprintf.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1999 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1999 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,6 +36,7 @@ */ #include "curl_setup.h" +#include "dynbuf.h" #include <curl/mprintf.h> #include "curl_memory.h" @@ -145,7 +146,7 @@ enum { FLAGS_FLOATG = 1<<19 /* %g or %G */ }; -typedef struct { +struct va_stack { FormatType type; int flags; long width; /* width OR width parameter number */ @@ -159,7 +160,7 @@ typedef struct { } num; double dnum; } data; -} va_stack_t; +}; struct nsprintf { char *buffer; @@ -168,11 +169,9 @@ struct nsprintf { }; struct asprintf { - char *buffer; /* allocated buffer */ - size_t len; /* length of string */ - size_t alloc; /* length of alloc */ - int fail; /* (!= 0) if an alloc has failed and thus - the output is not the complete data */ + struct dynbuf b; + bool fail; /* if an alloc has failed and thus the output is not the complete + data */ }; static long dprintf_DollarString(char *input, char **end) @@ -224,8 +223,8 @@ static bool dprintf_IsQualifierNoDollar(const char *fmt) * ******************************************************************/ -static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, - va_list arglist) +static int dprintf_Pass1(const char *format, struct va_stack *vto, + char **endpos, va_list arglist) { char *fmt = (char *)format; int param_num = 0; @@ -571,13 +570,11 @@ static int dprintf_formatf( long param; /* current parameter to read */ long param_num = 0; /* parameter counter */ - va_stack_t vto[MAX_PARAMETERS]; + struct va_stack vto[MAX_PARAMETERS]; char *endpos[MAX_PARAMETERS]; char **end; - char work[BUFFSIZE]; - - va_stack_t *p; + struct va_stack *p; /* 'workend' points to the final buffer byte position, but with an extra byte as margin to avoid the (false?) warning Coverity gives us @@ -1031,35 +1028,10 @@ static int alloc_addbyter(int output, FILE *data) struct asprintf *infop = (struct asprintf *)data; unsigned char outc = (unsigned char)output; - if(!infop->buffer) { - infop->buffer = malloc(32); - if(!infop->buffer) { - infop->fail = 1; - return -1; /* fail */ - } - infop->alloc = 32; - infop->len = 0; - } - else if(infop->len + 1 >= infop->alloc) { - char *newptr = NULL; - size_t newsize = infop->alloc*2; - - /* detect wrap-around or other overflow problems */ - if(newsize > infop->alloc) - newptr = realloc(infop->buffer, newsize); - - if(!newptr) { - infop->fail = 1; - return -1; /* fail */ - } - infop->buffer = newptr; - infop->alloc = newsize; + if(Curl_dyn_addn(&infop->b, &outc, 1)) { + infop->fail = 1; + return -1; /* fail */ } - - infop->buffer[ infop->len ] = outc; - - infop->len++; - return outc; /* fputc() returns like this on success */ } @@ -1068,24 +1040,18 @@ char *curl_maprintf(const char *format, ...) va_list ap_save; /* argument pointer */ int retcode; struct asprintf info; - - info.buffer = NULL; - info.len = 0; - info.alloc = 0; + Curl_dyn_init(&info.b, DYN_APRINTF); info.fail = 0; va_start(ap_save, format); retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); va_end(ap_save); if((-1 == retcode) || info.fail) { - if(info.alloc) - free(info.buffer); + Curl_dyn_free(&info.b); return NULL; } - if(info.alloc) { - info.buffer[info.len] = 0; /* we terminate this with a zero byte */ - return info.buffer; - } + if(Curl_dyn_len(&info.b)) + return Curl_dyn_ptr(&info.b); return strdup(""); } @@ -1093,23 +1059,16 @@ char *curl_mvaprintf(const char *format, va_list ap_save) { int retcode; struct asprintf info; - - info.buffer = NULL; - info.len = 0; - info.alloc = 0; + Curl_dyn_init(&info.b, DYN_APRINTF); info.fail = 0; retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); if((-1 == retcode) || info.fail) { - if(info.alloc) - free(info.buffer); + Curl_dyn_free(&info.b); return NULL; } - - if(info.alloc) { - info.buffer[info.len] = 0; /* we terminate this with a zero byte */ - return info.buffer; - } + if(Curl_dyn_len(&info.b)) + return Curl_dyn_ptr(&info.b); return strdup(""); } diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c new file mode 100644 index 0000000..d09aab4 --- /dev/null +++ b/Utilities/cmcurl/lib/mqtt.c @@ -0,0 +1,627 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2019, Björn Stenberg, <bjorn@haxx.se> + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef CURL_ENABLE_MQTT + +#include "urldata.h" +#include <curl/curl.h> +#include "transfer.h" +#include "sendf.h" +#include "progress.h" +#include "mqtt.h" +#include "select.h" +#include "strdup.h" +#include "url.h" +#include "escape.h" +#include "warnless.h" +#include "curl_printf.h" +#include "curl_memory.h" +#include "multiif.h" +#include "rand.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#define MQTT_MSG_CONNECT 0x10 +#define MQTT_MSG_CONNACK 0x20 +#define MQTT_MSG_PUBLISH 0x30 +#define MQTT_MSG_SUBSCRIBE 0x82 +#define MQTT_MSG_SUBACK 0x90 +#define MQTT_MSG_DISCONNECT 0xe0 + +#define MQTT_CONNACK_LEN 2 +#define MQTT_SUBACK_LEN 3 +#define MQTT_CLIENTID_LEN 12 /* "curl0123abcd" */ + +/* + * Forward declarations. + */ + +static CURLcode mqtt_do(struct connectdata *conn, bool *done); +static CURLcode mqtt_doing(struct connectdata *conn, bool *done); +static int mqtt_getsock(struct connectdata *conn, curl_socket_t *sock); +static CURLcode mqtt_setup_conn(struct connectdata *conn); + +/* + * MQTT protocol handler. + */ + +const struct Curl_handler Curl_handler_mqtt = { + "MQTT", /* scheme */ + mqtt_setup_conn, /* setup_connection */ + mqtt_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + mqtt_doing, /* doing */ + ZERO_NULL, /* proto_getsock */ + mqtt_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ + PORT_MQTT, /* defport */ + CURLPROTO_MQTT, /* protocol */ + PROTOPT_NONE /* flags */ +}; + +static CURLcode mqtt_setup_conn(struct connectdata *conn) +{ + /* allocate the HTTP-specific struct for the Curl_easy, only to survive + during this request */ + struct MQTT *mq; + struct Curl_easy *data = conn->data; + DEBUGASSERT(data->req.protop == NULL); + + mq = calloc(1, sizeof(struct MQTT)); + if(!mq) + return CURLE_OUT_OF_MEMORY; + data->req.protop = mq; + return CURLE_OK; +} + +static CURLcode mqtt_send(struct connectdata *conn, + char *buf, size_t len) +{ + CURLcode result = CURLE_OK; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + struct Curl_easy *data = conn->data; + struct MQTT *mq = data->req.protop; + ssize_t n; + result = Curl_write(conn, sockfd, buf, len, &n); + if(!result && data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n); + if(len != (size_t)n) { + size_t nsend = len - n; + char *sendleftovers = Curl_memdup(&buf[n], nsend); + if(!sendleftovers) + return CURLE_OUT_OF_MEMORY; + mq->sendleftovers = sendleftovers; + mq->nsend = nsend; + } + return result; +} + +/* Generic function called by the multi interface to figure out what socket(s) + to wait for and for what actions during the DOING and PROTOCONNECT + states */ +static int mqtt_getsock(struct connectdata *conn, + curl_socket_t *sock) +{ + sock[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(FIRSTSOCKET); +} + +static CURLcode mqtt_connect(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + const size_t client_id_offset = 14; + const size_t packetlen = client_id_offset + MQTT_CLIENTID_LEN; + char client_id[MQTT_CLIENTID_LEN + 1] = "curl"; + const size_t curl_len = strlen("curl"); + char packet[32] = { + MQTT_MSG_CONNECT, /* packet type */ + 0x00, /* remaining length */ + 0x00, 0x04, /* protocol length */ + 'M','Q','T','T', /* protocol name */ + 0x04, /* protocol level */ + 0x02, /* CONNECT flag: CleanSession */ + 0x00, 0x3c, /* keep-alive 0 = disabled */ + 0x00, 0x00 /* payload1 length */ + }; + packet[1] = (packetlen - 2) & 0x7f; + packet[client_id_offset - 1] = MQTT_CLIENTID_LEN; + + result = Curl_rand_hex(conn->data, (unsigned char *)&client_id[curl_len], + MQTT_CLIENTID_LEN - curl_len + 1); + memcpy(&packet[client_id_offset], client_id, MQTT_CLIENTID_LEN); + infof(conn->data, "Using client id '%s'\n", client_id); + if(!result) + result = mqtt_send(conn, packet, packetlen); + return result; +} + +static CURLcode mqtt_disconnect(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + result = mqtt_send(conn, (char *)"\xe0\x00", 2); + return result; +} + +static CURLcode mqtt_verify_connack(struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + unsigned char readbuf[MQTT_CONNACK_LEN]; + ssize_t nread; + struct Curl_easy *data = conn->data; + + result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread); + if(result) + goto fail; + + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread); + + /* fixme */ + if(nread < MQTT_CONNACK_LEN) { + result = CURLE_WEIRD_SERVER_REPLY; + goto fail; + } + + /* verify CONNACK */ + if(readbuf[0] != 0x00 || readbuf[1] != 0x00) { + failf(data, "Expected %02x%02x but got %02x%02x", + 0x00, 0x00, readbuf[0], readbuf[1]); + result = CURLE_WEIRD_SERVER_REPLY; + } + +fail: + return result; +} + +static CURLcode mqtt_get_topic(struct connectdata *conn, + char **topic, size_t *topiclen) +{ + CURLcode result = CURLE_OK; + char *path = conn->data->state.up.path; + + if(strlen(path) > 1) { + result = Curl_urldecode(conn->data, path + 1, 0, topic, topiclen, FALSE); + } + else { + failf(conn->data, "Error: No topic specified."); + result = CURLE_URL_MALFORMAT; + } + return result; +} + + +static int mqtt_encode_len(char *buf, size_t len) +{ + unsigned char encoded; + int i; + + for(i = 0; (len > 0) && (i<4); i++) { + encoded = len % 0x80; + len /= 0x80; + if(len) + encoded |= 0x80; + buf[i] = encoded; + } + + return i; +} + +static CURLcode mqtt_subscribe(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + char *topic = NULL; + size_t topiclen; + unsigned char *packet = NULL; + size_t packetlen; + char encodedsize[4]; + size_t n; + + result = mqtt_get_topic(conn, &topic, &topiclen); + if(result) + goto fail; + + conn->proto.mqtt.packetid++; + + packetlen = topiclen + 5; /* packetid + topic (has a two byte length field) + + 2 bytes topic length + QoS byte */ + n = mqtt_encode_len((char *)encodedsize, packetlen); + packetlen += n + 1; /* add one for the control packet type byte */ + + packet = malloc(packetlen); + if(!packet) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + packet[0] = MQTT_MSG_SUBSCRIBE; + memcpy(&packet[1], encodedsize, n); + packet[1 + n] = (conn->proto.mqtt.packetid >> 8) & 0xff; + packet[2 + n] = conn->proto.mqtt.packetid & 0xff; + packet[3 + n] = (topiclen >> 8) & 0xff; + packet[4 + n ] = topiclen & 0xff; + memcpy(&packet[5 + n], topic, topiclen); + packet[5 + n + topiclen] = 0; /* QoS zero */ + + result = mqtt_send(conn, (char *)packet, packetlen); + +fail: + free(topic); + free(packet); + return result; +} + +/* + * Called when the first byte was already read. + */ +static CURLcode mqtt_verify_suback(struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + unsigned char readbuf[MQTT_SUBACK_LEN]; + ssize_t nread; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + + result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_SUBACK_LEN, &nread); + if(result) + goto fail; + + if(conn->data->set.verbose) + Curl_debug(conn->data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread); + + /* fixme */ + if(nread < MQTT_SUBACK_LEN) { + result = CURLE_WEIRD_SERVER_REPLY; + goto fail; + } + + /* verify SUBACK */ + if(readbuf[0] != ((mqtt->packetid >> 8) & 0xff) || + readbuf[1] != (mqtt->packetid & 0xff) || + readbuf[2] != 0x00) + result = CURLE_WEIRD_SERVER_REPLY; + +fail: + return result; +} + +static CURLcode mqtt_publish(struct connectdata *conn) +{ + CURLcode result; + char *payload = conn->data->set.postfields; + size_t payloadlen = (size_t)conn->data->set.postfieldsize; + char *topic = NULL; + size_t topiclen; + unsigned char *pkt = NULL; + size_t i = 0; + size_t remaininglength; + size_t encodelen; + char encodedbytes[4]; + + result = mqtt_get_topic(conn, &topic, &topiclen); + if(result) + goto fail; + + remaininglength = payloadlen + 2 + topiclen; + encodelen = mqtt_encode_len(encodedbytes, remaininglength); + + /* add the control byte and the encoded remaining length */ + pkt = malloc(remaininglength + 1 + encodelen); + if(!pkt) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + /* assemble packet */ + pkt[i++] = MQTT_MSG_PUBLISH; + memcpy(&pkt[i], encodedbytes, encodelen); + i += encodelen; + pkt[i++] = (topiclen >> 8) & 0xff; + pkt[i++] = (topiclen & 0xff); + memcpy(&pkt[i], topic, topiclen); + i += topiclen; + memcpy(&pkt[i], payload, payloadlen); + i += payloadlen; + result = mqtt_send(conn, (char *)pkt, i); + +fail: + free(pkt); + free(topic); + return result; +} + +static size_t mqtt_decode_len(unsigned char *buf, + size_t buflen, size_t *lenbytes) +{ + size_t len = 0; + size_t mult = 1; + size_t i; + unsigned char encoded = 128; + + for(i = 0; (i < buflen) && (encoded & 128); i++) { + encoded = buf[i]; + len += (encoded & 127) * mult; + mult *= 128; + } + + if(lenbytes) + *lenbytes = i; + + return len; +} + +#ifdef CURLDEBUG +static const char *statenames[]={ + "MQTT_FIRST", + "MQTT_REMAINING_LENGTH", + "MQTT_CONNACK", + "MQTT_SUBACK", + "MQTT_SUBACK_COMING", + "MQTT_PUBWAIT", + "MQTT_PUB_REMAIN", + + "NOT A STATE" +}; +#endif + +/* The only way to change state */ +static void mqstate(struct connectdata *conn, + enum mqttstate state, + enum mqttstate nextstate) /* used if state == FIRST */ +{ + struct mqtt_conn *mqtt = &conn->proto.mqtt; +#ifdef CURLDEBUG + infof(conn->data, "%s (from %s) (next is %s)\n", + statenames[state], + statenames[mqtt->state], + (state == MQTT_FIRST)? statenames[nextstate] : ""); +#endif + mqtt->state = state; + if(state == MQTT_FIRST) + mqtt->nextstate = nextstate; +} + + +/* for the publish packet */ +#define MQTT_HEADER_LEN 5 /* max 5 bytes */ + +static CURLcode mqtt_read_publish(struct connectdata *conn, + bool *done) +{ + CURLcode result = CURLE_OK; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + ssize_t nread; + struct Curl_easy *data = conn->data; + unsigned char *pkt = (unsigned char *)data->state.buffer; + size_t remlen; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + struct MQTT *mq = data->req.protop; + unsigned char packet; + + switch(mqtt->state) { + MQTT_SUBACK_COMING: + case MQTT_SUBACK_COMING: + result = mqtt_verify_suback(conn); + if(result) + break; + + mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT); + break; + + case MQTT_SUBACK: + case MQTT_PUBWAIT: + /* we are expecting PUBLISH or SUBACK */ + packet = mq->firstbyte & 0xf0; + if(packet == MQTT_MSG_PUBLISH) + mqstate(conn, MQTT_PUB_REMAIN, MQTT_NOSTATE); + else if(packet == MQTT_MSG_SUBACK) { + mqstate(conn, MQTT_SUBACK_COMING, MQTT_NOSTATE); + goto MQTT_SUBACK_COMING; + } + else if(packet == MQTT_MSG_DISCONNECT) { + infof(data, "Got DISCONNECT\n"); + *done = TRUE; + goto end; + } + else { + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + + /* -- switched state -- */ + remlen = mq->remaining_length; + infof(data, "Remaining length: %zd bytes\n", remlen); + Curl_pgrsSetDownloadSize(data, remlen); + data->req.bytecount = 0; + data->req.size = remlen; + mq->npacket = remlen; /* get this many bytes */ + /* FALLTHROUGH */ + case MQTT_PUB_REMAIN: { + /* read rest of packet, but no more. Cap to buffer size */ + struct SingleRequest *k = &data->req; + size_t rest = mq->npacket; + if(rest > (size_t)data->set.buffer_size) + rest = (size_t)data->set.buffer_size; + result = Curl_read(conn, sockfd, (char *)pkt, rest, &nread); + if(result) { + if(CURLE_AGAIN == result) { + infof(data, "EEEE AAAAGAIN\n"); + } + goto end; + } + if(!nread) { + infof(data, "server disconnected\n"); + result = CURLE_PARTIAL_FILE; + goto end; + } + if(data->set.verbose) + Curl_debug(data, CURLINFO_DATA_IN, (char *)pkt, (size_t)nread); + + mq->npacket -= nread; + k->bytecount += nread; + Curl_pgrsSetDownloadCounter(data, k->bytecount); + + /* if QoS is set, message contains packet id */ + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)pkt, nread); + if(result) + goto end; + + if(!mq->npacket) + /* no more PUBLISH payload, back to subscribe wait state */ + mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT); + break; + } + default: + DEBUGASSERT(NULL); /* illegal state */ + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + end: + return result; +} + +static CURLcode mqtt_do(struct connectdata *conn, bool *done) +{ + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; + + *done = FALSE; /* unconditionally */ + + result = mqtt_connect(conn); + if(result) { + failf(data, "Error %d sending MQTT CONN request", result); + return result; + } + mqstate(conn, MQTT_FIRST, MQTT_CONNACK); + return CURLE_OK; +} + +static CURLcode mqtt_doing(struct connectdata *conn, bool *done) +{ + CURLcode result = CURLE_OK; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + struct Curl_easy *data = conn->data; + struct MQTT *mq = data->req.protop; + ssize_t nread; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + unsigned char *pkt = (unsigned char *)data->state.buffer; + unsigned char byte; + + *done = FALSE; + + if(mq->nsend) { + /* send the remainder of an outgoing packet */ + char *ptr = mq->sendleftovers; + result = mqtt_send(conn, mq->sendleftovers, mq->nsend); + free(ptr); + if(result) + return result; + } + + infof(data, "mqtt_doing: state [%d]\n", (int) mqtt->state); + switch(mqtt->state) { + case MQTT_FIRST: + /* Read the initial byte only */ + result = Curl_read(conn, sockfd, (char *)&mq->firstbyte, 1, &nread); + if(result) + break; + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1); + /* remember the first byte */ + mq->npacket = 0; + mqstate(conn, MQTT_REMAINING_LENGTH, MQTT_NOSTATE); + /* FALLTHROUGH */ + case MQTT_REMAINING_LENGTH: + do { + result = Curl_read(conn, sockfd, (char *)&byte, 1, &nread); + if(result) + break; + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1); + pkt[mq->npacket++] = byte; + } while((byte & 0x80) && (mq->npacket < 4)); + if(result) + break; + mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL); + mq->npacket = 0; + if(mq->remaining_length) { + mqstate(conn, mqtt->nextstate, MQTT_NOSTATE); + break; + } + mqstate(conn, MQTT_FIRST, MQTT_FIRST); + + if(mq->firstbyte == MQTT_MSG_DISCONNECT) { + infof(data, "Got DISCONNECT\n"); + *done = TRUE; + } + break; + case MQTT_CONNACK: + result = mqtt_verify_connack(conn); + if(result) + break; + + if(conn->data->state.httpreq == HTTPREQ_POST) { + result = mqtt_publish(conn); + if(!result) { + result = mqtt_disconnect(conn); + *done = TRUE; + } + mqtt->nextstate = MQTT_FIRST; + } + else { + result = mqtt_subscribe(conn); + if(!result) { + mqstate(conn, MQTT_FIRST, MQTT_SUBACK); + } + } + break; + + case MQTT_SUBACK: + case MQTT_PUBWAIT: + case MQTT_PUB_REMAIN: + result = mqtt_read_publish(conn, done); + break; + + default: + failf(conn->data, "State not handled yet"); + *done = TRUE; + break; + } + + if(result == CURLE_AGAIN) + result = CURLE_OK; + return result; +} + +#endif /* CURL_ENABLE_MQTT */ diff --git a/Utilities/cmcurl/lib/mqtt.h b/Utilities/cmcurl/lib/mqtt.h new file mode 100644 index 0000000..37463d5 --- /dev/null +++ b/Utilities/cmcurl/lib/mqtt.h @@ -0,0 +1,59 @@ +#ifndef HEADER_CURL_MQTT_H +#define HEADER_CURL_MQTT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2019 - 2020, Björn Stenberg, <bjorn@haxx.se> + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#ifdef CURL_ENABLE_MQTT +extern const struct Curl_handler Curl_handler_mqtt; +#endif + +enum mqttstate { + MQTT_FIRST, /* 0 */ + MQTT_REMAINING_LENGTH, /* 1 */ + MQTT_CONNACK, /* 2 */ + MQTT_SUBACK, /* 3 */ + MQTT_SUBACK_COMING, /* 4 - the SUBACK remainder */ + MQTT_PUBWAIT, /* 5 - wait for publish */ + MQTT_PUB_REMAIN, /* 6 - wait for the remainder of the publish */ + + MQTT_NOSTATE /* 7 - never used an actual state */ +}; + +struct mqtt_conn { + enum mqttstate state; + enum mqttstate nextstate; /* switch to this after remaining length is + done */ + unsigned int packetid; +}; + +/* protocol-specific transfer-related data */ +struct MQTT { + char *sendleftovers; + size_t nsend; /* size of sendleftovers */ + + /* when receiving */ + size_t npacket; /* byte counter */ + unsigned char firstbyte; + size_t remaining_length; +}; + +#endif /* HEADER_CURL_MQTT_H */ diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c index cef2805..b106c94 100644 --- a/Utilities/cmcurl/lib/multi.c +++ b/Utilities/cmcurl/lib/multi.c @@ -79,7 +79,6 @@ static CURLMcode add_next_timeout(struct curltime now, static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms); static void process_pending_handles(struct Curl_multi *multi); -static void detach_connnection(struct Curl_easy *data); #ifdef DEBUGBUILD static const char * const statename[]={ @@ -112,7 +111,7 @@ static void Curl_init_completed(struct Curl_easy *data) /* Important: reset the conn pointer so that we don't point to memory that could be freed anytime */ - detach_connnection(data); + Curl_detach_connnection(data); Curl_expire_clear(data); /* stop all timers */ } @@ -169,9 +168,11 @@ static void mstate(struct Curl_easy *data, CURLMstate state } #endif - if(state == CURLM_STATE_COMPLETED) + if(state == CURLM_STATE_COMPLETED) { /* changing to COMPLETED means there's one less easy handle 'alive' */ + DEBUGASSERT(data->multi->num_alive > 0); data->multi->num_alive--; + } /* if this state has an init-function, run it */ if(finit[state]) @@ -373,6 +374,11 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ multi->max_concurrent_streams = 100; multi->ipv6_works = Curl_ipv6works(NULL); +#ifdef USE_WINSOCK + multi->wsa_event = WSACreateEvent(); + if(multi->wsa_event == WSA_INVALID_EVENT) + goto error; +#else #ifdef ENABLE_WAKEUP if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) { multi->wakeup_pair[0] = CURL_SOCKET_BAD; @@ -386,6 +392,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ multi->wakeup_pair[1] = CURL_SOCKET_BAD; } #endif +#endif return multi; @@ -506,6 +513,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, easy handle is added */ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + CONNCACHE_LOCK(data); /* The closure handle only ever has default timeouts set. To improve the state somewhat we clone the timeouts from each added handle so that the closure handle always has the same timeouts as the most recently added @@ -515,6 +523,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, data->set.server_response_timeout; data->state.conn_cache->closure_handle->set.no_signal = data->set.no_signal; + CONNCACHE_UNLOCK(data); Curl_update_timer(multi); return CURLM_OK; @@ -589,14 +598,14 @@ static CURLcode multi_done(struct Curl_easy *data, process_pending_handles(data->multi); /* connection / multiplex */ - CONN_LOCK(data); - detach_connnection(data); + CONNCACHE_LOCK(data); + Curl_detach_connnection(data); if(CONN_INUSE(conn)) { /* Stop if still used. */ /* conn->data must not remain pointing to this transfer since it is going away! Find another to own it! */ conn->data = conn->easyq.head->ptr; - CONN_UNLOCK(data); + CONNCACHE_UNLOCK(data); DEBUGF(infof(data, "Connection still in use %zu, " "no more multi_done now!\n", conn->easyq.size)); @@ -615,7 +624,7 @@ static CURLcode multi_done(struct Curl_easy *data, /* if the transfer was completed in a paused state there can be buffered data left to free */ for(i = 0; i < data->state.tempcount; i++) { - free(data->state.tempwrite[i].buf); + Curl_dyn_free(&data->state.tempwrite[i].b); } data->state.tempcount = 0; @@ -647,7 +656,8 @@ static CURLcode multi_done(struct Curl_easy *data, || (premature && !(conn->handler->flags & PROTOPT_STREAM))) { CURLcode res2; connclose(conn, "disconnecting"); - CONN_UNLOCK(data); + Curl_conncache_remove_conn(data, conn, FALSE); + CONNCACHE_UNLOCK(data); res2 = Curl_disconnect(data, conn, premature); /* If we had an error already, make sure we return that one. But @@ -657,16 +667,20 @@ static CURLcode multi_done(struct Curl_easy *data, } else { char buffer[256]; + const char *host = +#ifndef CURL_DISABLE_PROXY + conn->bits.socksproxy ? + conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : +#endif + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname; /* create string before returning the connection */ msnprintf(buffer, sizeof(buffer), "Connection #%ld to host %s left intact", - conn->connection_id, - conn->bits.socksproxy ? conn->socks_proxy.host.dispname : - conn->bits.httpproxy ? conn->http_proxy.host.dispname : - conn->bits.conn_to_host ? conn->conn_to_host.dispname : - conn->host.dispname); + conn->connection_id, host); /* the connection is no longer in use by this transfer */ - CONN_UNLOCK(data); + CONNCACHE_UNLOCK(data); if(Curl_conncache_return_conn(data, conn)) { /* remember the most recently used connection */ data->state.lastconnect = conn; @@ -676,6 +690,7 @@ static CURLcode multi_done(struct Curl_easy *data, data->state.lastconnect = NULL; } + Curl_safefree(data->state.buffer); Curl_free_request_state(data); return result; } @@ -700,6 +715,10 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, if(!data->multi) return CURLM_OK; /* it is already removed so let's say it is fine! */ + /* Prevent users from trying to remove an easy handle from the wrong multi */ + if(data->multi != multi) + return CURLM_BAD_EASY_HANDLE; + if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; @@ -774,8 +793,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, vanish with this handle */ /* Remove the association between the connection and the handle */ - if(data->conn) - detach_connnection(data); + Curl_detach_connnection(data); #ifdef USE_LIBPSL /* Remove the PSL association. */ @@ -824,9 +842,13 @@ bool Curl_multiplex_wanted(const struct Curl_multi *multi) return (multi && (multi->multiplexing)); } -/* This is the only function that should clear data->conn. This will - occasionally be called with the pointer already cleared. */ -static void detach_connnection(struct Curl_easy *data) +/* + * Curl_detach_connnection() removes the given transfer from the connection. + * + * This is the only function that should clear data->conn. This will + * occasionally be called with the data->conn pointer already cleared. + */ +void Curl_detach_connnection(struct Curl_easy *data) { struct connectdata *conn = data->conn; if(conn) @@ -834,7 +856,11 @@ static void detach_connnection(struct Curl_easy *data) data->conn = NULL; } -/* This is the only function that should assign data->conn */ +/* + * Curl_attach_connnection() attaches this transfer to this connection. + * + * This is the only function that should assign data->conn + */ void Curl_attach_connnection(struct Curl_easy *data, struct connectdata *conn) { @@ -853,9 +879,11 @@ static int waitconnect_getsock(struct connectdata *conn, int rc = 0; #ifdef USE_SSL +#ifndef CURL_DISABLE_PROXY if(CONNECT_FIRSTSOCKET_PROXY_SSL()) return Curl_ssl_getsock(conn, sock); #endif +#endif if(SOCKS_STATE(conn->cnnct.state)) return Curl_SOCKS_getsock(conn, sock, FIRSTSOCKET); @@ -1045,11 +1073,15 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, unsigned int i; unsigned int nfds = 0; unsigned int curlfds; - bool ufds_malloc = FALSE; long timeout_internal; int retcode = 0; +#ifndef USE_WINSOCK struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; struct pollfd *ufds = &a_few_on_stack[0]; + bool ufds_malloc = FALSE; +#else + DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT); +#endif if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -1095,11 +1127,16 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, nfds += extra_nfds; /* add the externally provided ones */ #ifdef ENABLE_WAKEUP +#ifdef USE_WINSOCK + if(use_wakeup) { +#else if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { +#endif ++nfds; } #endif +#ifndef USE_WINSOCK if(nfds > NUM_POLLS_ON_STACK) { /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes big, so at 2^29 sockets this value might wrap. When a process gets @@ -1110,7 +1147,9 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, return CURLM_OUT_OF_MEMORY; ufds_malloc = TRUE; } + nfds = 0; +#endif /* only do the second loop if we found descriptors in the first stage run above */ @@ -1123,22 +1162,36 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; - +#ifdef USE_WINSOCK + long mask = 0; +#endif if(bitmap & GETSOCK_READSOCK(i)) { +#ifdef USE_WINSOCK + mask |= FD_READ; +#else ufds[nfds].fd = sockbunch[i]; ufds[nfds].events = POLLIN; ++nfds; +#endif s = sockbunch[i]; } if(bitmap & GETSOCK_WRITESOCK(i)) { +#ifdef USE_WINSOCK + mask |= FD_WRITE; +#else ufds[nfds].fd = sockbunch[i]; ufds[nfds].events = POLLOUT; ++nfds; +#endif s = sockbunch[i]; } if(s == CURL_SOCKET_BAD) { break; } +#ifdef USE_WINSOCK + if(WSAEventSelect(s, multi->wsa_event, mask) != 0) + return CURLM_INTERNAL_ERROR; +#endif } data = data->next; /* check next handle */ @@ -1147,6 +1200,17 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, /* Add external file descriptions from poll-like struct curl_waitfd */ for(i = 0; i < extra_nfds; i++) { +#ifdef USE_WINSOCK + long events = 0; + if(extra_fds[i].events & CURL_WAIT_POLLIN) + events |= FD_READ; + if(extra_fds[i].events & CURL_WAIT_POLLPRI) + events |= FD_OOB; + if(extra_fds[i].events & CURL_WAIT_POLLOUT) + events |= FD_WRITE; + if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, events) != 0) + return CURLM_INTERNAL_ERROR; +#else ufds[nfds].fd = extra_fds[i].fd; ufds[nfds].events = 0; if(extra_fds[i].events & CURL_WAIT_POLLIN) @@ -1156,28 +1220,61 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, if(extra_fds[i].events & CURL_WAIT_POLLOUT) ufds[nfds].events |= POLLOUT; ++nfds; +#endif } #ifdef ENABLE_WAKEUP +#ifndef USE_WINSOCK if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { ufds[nfds].fd = multi->wakeup_pair[0]; ufds[nfds].events = POLLIN; ++nfds; } #endif +#endif if(nfds) { int pollrc; /* wait... */ +#ifdef USE_WINSOCK + DWORD waitrc = WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, + timeout_ms, FALSE); + /* WSA_WAIT_EVENT_0 is 0, so waitrc >= WSA_WAIT_EVENT_0 warns */ + if(waitrc == WSA_WAIT_EVENT_0) + pollrc = 1; + else + pollrc = -1; +#else pollrc = Curl_poll(ufds, nfds, timeout_ms); +#endif if(pollrc > 0) { +#ifdef USE_WINSOCK + retcode = 0; +#else retcode = pollrc; +#endif /* copy revents results from the poll to the curl_multi_wait poll struct, the bit values of the actual underlying poll() implementation may not be the same as the ones in the public libcurl API! */ for(i = 0; i < extra_nfds; i++) { unsigned short mask = 0; +#ifdef USE_WINSOCK + WSANETWORKEVENTS events = {0}; + if(WSAEnumNetworkEvents(extra_fds[i].fd, multi->wsa_event, + &events) == 0) { + if(events.lNetworkEvents & FD_READ) + mask |= CURL_WAIT_POLLIN; + if(events.lNetworkEvents & FD_WRITE) + mask |= CURL_WAIT_POLLOUT; + if(events.lNetworkEvents & FD_OOB) + mask |= CURL_WAIT_POLLPRI; + + if(events.lNetworkEvents != 0) + retcode++; + } + WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0); +#else unsigned r = ufds[curlfds + i].revents; if(r & POLLIN) @@ -1186,24 +1283,53 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, mask |= CURL_WAIT_POLLOUT; if(r & POLLPRI) mask |= CURL_WAIT_POLLPRI; +#endif extra_fds[i].revents = mask; } +#ifdef USE_WINSOCK + /* Count up all our own sockets that had activity, + and remove them from the event. */ + if(curlfds) { + data = multi->easyp; + while(data) { + bitmap = multi_getsock(data, sockbunch); + + for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) { + if(bitmap & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))) { + WSANETWORKEVENTS events = {0}; + if(WSAEnumNetworkEvents(sockbunch[i], multi->wsa_event, + &events) == 0) { + if(events.lNetworkEvents != 0) + retcode++; + } + WSAEventSelect(sockbunch[i], multi->wsa_event, 0); + } + else + break; + } + + data = data->next; + } + } + + WSAResetEvent(multi->wsa_event); +#else #ifdef ENABLE_WAKEUP if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { if(ufds[curlfds + extra_nfds].revents & POLLIN) { char buf[64]; + ssize_t nread; while(1) { /* the reading socket is non-blocking, try to read data from it until it receives an error (except EINTR). In normal cases it will get EAGAIN or EWOULDBLOCK when there is no more data, breaking the loop. */ - if(sread(multi->wakeup_pair[0], buf, sizeof(buf)) <= 0) { -#ifndef USE_WINSOCK - if(EINTR == SOCKERRNO) + nread = sread(multi->wakeup_pair[0], buf, sizeof(buf)); + if(nread <= 0) { + if(nread < 0 && EINTR == SOCKERRNO) continue; -#endif break; } } @@ -1212,11 +1338,14 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, } } #endif +#endif } } +#ifndef USE_WINSOCK if(ufds_malloc) free(ufds); +#endif if(ret) *ret = retcode; if(!extrawait || nfds) @@ -1233,7 +1362,7 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi, timeout */ else if((sleep_ms < 0) && extrawait) sleep_ms = timeout_ms; - Curl_wait_ms((int)sleep_ms); + Curl_wait_ms(sleep_ms); } } @@ -1271,6 +1400,10 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi) return CURLM_BAD_HANDLE; #ifdef ENABLE_WAKEUP +#ifdef USE_WINSOCK + if(WSASetEvent(multi->wsa_event)) + return CURLM_OK; +#else /* the wakeup_pair variable is only written during init and cleanup, making it safe to access from another thread after the init part and before cleanup */ @@ -1304,6 +1437,7 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi) } } #endif +#endif return CURLM_WAKEUP_FAILURE; } @@ -1474,7 +1608,7 @@ static CURLcode protocol_connect(struct connectdata *conn, } if(!conn->bits.protoconnstart) { - +#ifndef CURL_DISABLE_PROXY result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) return result; @@ -1488,7 +1622,7 @@ static CURLcode protocol_connect(struct connectdata *conn, /* when using an HTTP tunnel proxy, await complete tunnel establishment before proceeding further. Return CURLE_OK so we'll be called again */ return CURLE_OK; - +#endif if(conn->handler->connect_it) { /* is there a protocol-specific connect() procedure? */ @@ -1507,6 +1641,21 @@ static CURLcode protocol_connect(struct connectdata *conn, return result; /* pass back status */ } +/* + * Curl_preconnect() is called immediately before a connect starts. When a + * redirect is followed, this is then called multiple times during a single + * transfer. + */ +CURLcode Curl_preconnect(struct Curl_easy *data) +{ + if(!data->state.buffer) { + data->state.buffer = malloc(data->set.buffer_size + 1); + if(!data->state.buffer) + return CURLE_OUT_OF_MEMORY; + } + return CURLE_OK; +} + static CURLMcode multi_runsingle(struct Curl_multi *multi, struct curltime now, @@ -1534,19 +1683,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, bool stream_error = FALSE; rc = CURLM_OK; - DEBUGASSERT((data->mstate <= CURLM_STATE_CONNECT) || - (data->mstate >= CURLM_STATE_DONE) || - data->conn); - if(!data->conn && - data->mstate > CURLM_STATE_CONNECT && - data->mstate < CURLM_STATE_DONE) { - /* In all these states, the code will blindly access 'data->conn' - so this is precaution that it isn't NULL. And it silences static - analyzers. */ - failf(data, "In state %d with no conn, bail out!\n", data->mstate); - return CURLM_INTERNAL_ERROR; - } - if(multi_ischanged(multi, TRUE)) { DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n")); process_pending_handles(multi); /* multiplexed */ @@ -1627,6 +1763,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, case CURLM_STATE_CONNECT: /* Connect. We want to get a connection identifier filled in. */ + /* init this transfer. */ + result = Curl_preconnect(data); + if(result) + break; + Curl_pgrsTime(data, TIMER_STARTSINGLE); if(data->set.timeout) Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT); @@ -1684,9 +1825,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, const char *hostname; DEBUGASSERT(conn); +#ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy) hostname = conn->http_proxy.host.name; - else if(conn->bits.conn_to_host) + else +#endif + if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else hostname = conn->host.name; @@ -1752,7 +1896,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ DEBUGASSERT(data->conn); result = Curl_http_connect(data->conn, &protocol_connected); - +#ifndef CURL_DISABLE_PROXY if(data->conn->bits.proxy_connect_closed) { rc = CURLM_CALL_MULTI_PERFORM; /* connect back to proxy again */ @@ -1760,15 +1904,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multi_done(data, CURLE_OK, FALSE); multistate(data, CURLM_STATE_CONNECT); } - else if(!result) { - if((data->conn->http_proxy.proxytype != CURLPROXY_HTTPS || - data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) && - Curl_connect_complete(data->conn)) { - rc = CURLM_CALL_MULTI_PERFORM; - /* initiate protocol connect phase */ - multistate(data, CURLM_STATE_SENDPROTOCONNECT); + else +#endif + if(!result) { + if( +#ifndef CURL_DISABLE_PROXY + (data->conn->http_proxy.proxytype != CURLPROXY_HTTPS || + data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) && +#endif + Curl_connect_complete(data->conn)) { + rc = CURLM_CALL_MULTI_PERFORM; + /* initiate protocol connect phase */ + multistate(data, CURLM_STATE_SENDPROTOCONNECT); + } } - } else if(result) stream_error = TRUE; break; @@ -1780,17 +1929,25 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected); if(connected && !result) { #ifndef CURL_DISABLE_HTTP - if((data->conn->http_proxy.proxytype == CURLPROXY_HTTPS && - !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) || - Curl_connect_ongoing(data->conn)) { + if( +#ifndef CURL_DISABLE_PROXY + (data->conn->http_proxy.proxytype == CURLPROXY_HTTPS && + !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) || +#endif + Curl_connect_ongoing(data->conn)) { multistate(data, CURLM_STATE_WAITPROXYCONNECT); break; } #endif rc = CURLM_CALL_MULTI_PERFORM; - multistate(data, data->conn->bits.tunnel_proxy? +#ifndef CURL_DISABLE_PROXY + multistate(data, + data->conn->bits.tunnel_proxy? CURLM_STATE_WAITPROXYCONNECT: CURLM_STATE_SENDPROTOCONNECT); +#else + multistate(data, CURLM_STATE_SENDPROTOCONNECT); +#endif } else if(result) { /* failure detected */ @@ -2056,7 +2213,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, char *newurl = NULL; bool retry = FALSE; bool comeback = FALSE; - + DEBUGASSERT(data->state.buffer); /* check if over send speed */ send_timeout_ms = 0; if(data->set.max_send_speed > 0) @@ -2229,8 +2386,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, * access free'd data, if the connection is free'd and the handle * removed before we perform the processing in CURLM_STATE_COMPLETED */ - if(data->conn) - detach_connnection(data); + Curl_detach_connnection(data); } #ifndef CURL_DISABLE_FTP @@ -2282,7 +2438,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* This is where we make sure that the conn pointer is reset. We don't have to do this in every case block above where a failure is detected */ - detach_connnection(data); + Curl_detach_connnection(data); + + /* remove connection from cache */ + Curl_conncache_remove_conn(data, conn, TRUE); /* disconnect properly */ Curl_disconnect(data, conn, dead_connection); @@ -2437,10 +2596,14 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) Curl_hash_destroy(&multi->hostcache); Curl_psl_destroy(&multi->psl); +#ifdef USE_WINSOCK + WSACloseEvent(multi->wsa_event); +#else #ifdef ENABLE_WAKEUP sclose(multi->wakeup_pair[0]); sclose(multi->wakeup_pair[1]); #endif +#endif free(multi); return CURLM_OK; diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h index 91eca16..94bbad7 100644 --- a/Utilities/cmcurl/lib/multihandle.h +++ b/Utilities/cmcurl/lib/multihandle.h @@ -138,10 +138,14 @@ struct Curl_multi { previous callback */ unsigned int max_concurrent_streams; +#ifdef USE_WINSOCK + WSAEVENT wsa_event; /* winsock event used for waits */ +#else #ifdef ENABLE_WAKEUP curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup 0 is used for read, 1 is used for write */ #endif +#endif /* multiplexing wanted */ bool multiplexing; bool recheckstate; /* see Curl_multi_connchanged */ diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h index bde755e..7d574df 100644 --- a/Utilities/cmcurl/lib/multiif.h +++ b/Utilities/cmcurl/lib/multiif.h @@ -33,9 +33,11 @@ void Curl_expire_done(struct Curl_easy *data, expire_id id); void Curl_update_timer(struct Curl_multi *multi); void Curl_attach_connnection(struct Curl_easy *data, struct connectdata *conn); +void Curl_detach_connnection(struct Curl_easy *data); bool Curl_multiplex_wanted(const struct Curl_multi *multi); void Curl_set_in_callback(struct Curl_easy *data, bool value); bool Curl_is_in_callback(struct Curl_easy *easy); +CURLcode Curl_preconnect(struct Curl_easy *data); /* Internal version of curl_multi_init() accepts size parameters for the socket and connection hashes */ diff --git a/Utilities/cmcurl/lib/nwlib.c b/Utilities/cmcurl/lib/nwlib.c index 7bf5f51..beec0b3 100644 --- a/Utilities/cmcurl/lib/nwlib.c +++ b/Utilities/cmcurl/lib/nwlib.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,21 +36,19 @@ /* The last #include file should be: */ #include "memdebug.h" -typedef struct -{ +struct libthreaddata { int _errno; void *twentybytes; -} libthreaddata_t; +}; -typedef struct -{ +struct libdata { int x; int y; int z; void *tenbytes; NXKey_t perthreadkey; /* if -1, no key obtained... */ NXMutex_t *lock; -} libdata_t; +}; int gLibId = -1; void *gLibHandle = (void *) NULL; @@ -60,7 +58,8 @@ NXMutex_t *gLibLock = (NXMutex_t *) NULL; /* internal library function prototypes... */ int DisposeLibraryData(void *); void DisposeThreadData(void *); -int GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata); +int GetOrSetUpData(int id, struct libdata **data, + struct libthreaddata **threaddata); int _NonAppStart(void *NLMHandle, @@ -154,24 +153,24 @@ int _NonAppCheckUnload(void) return 0; } -int GetOrSetUpData(int id, libdata_t **appData, - libthreaddata_t **threadData) +int GetOrSetUpData(int id, struct libdata **appData, + struct libthreaddata **threadData) { int err; - libdata_t *app_data; - libthreaddata_t *thread_data; + struct libdata *app_data; + struct libthreaddata *thread_data; NXKey_t key; NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0); err = 0; - thread_data = (libthreaddata_t *) NULL; + thread_data = (struct libthreaddata_t *) NULL; /* * Attempt to get our data for the application calling us. This is where we * store whatever application-specific information we need to carry in * support of calling applications. */ - app_data = (libdata_t *) get_app_data(id); + app_data = (struct libdata *) get_app_data(id); if(!app_data) { /* @@ -184,9 +183,9 @@ int GetOrSetUpData(int id, libdata_t **appData, */ NXLock(gLibLock); - app_data = (libdata_t *) get_app_data(id); + app_data = (struct libdata *) get_app_data(id); if(!app_data) { - app_data = calloc(1, sizeof(libdata_t)); + app_data = calloc(1, sizeof(struct libdata)); if(app_data) { app_data->tenbytes = malloc(10); @@ -249,7 +248,7 @@ int GetOrSetUpData(int id, libdata_t **appData, * a pointer is not very important, this just helps to demonstrate that * we can have arbitrarily complex per-thread data. */ - thread_data = malloc(sizeof(libthreaddata_t)); + thread_data = malloc(sizeof(struct libthreaddata)); if(thread_data) { thread_data->_errno = 0; @@ -257,7 +256,7 @@ int GetOrSetUpData(int id, libdata_t **appData, if(!thread_data->twentybytes) { free(thread_data); - thread_data = (libthreaddata_t *) NULL; + thread_data = (struct libthreaddata *) NULL; err = ENOMEM; } @@ -265,7 +264,7 @@ int GetOrSetUpData(int id, libdata_t **appData, if(err) { free(thread_data->twentybytes); free(thread_data); - thread_data = (libthreaddata_t *) NULL; + thread_data = (struct libthreaddata *) NULL; } } } @@ -295,7 +294,7 @@ int DisposeLibraryData(void *data) void DisposeThreadData(void *data) { if(data) { - void *twentybytes = ((libthreaddata_t *) data)->twentybytes; + void *twentybytes = ((struct libthreaddata *) data)->twentybytes; free(twentybytes); free(data); diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c index 734ca5f..782d6a0 100644 --- a/Utilities/cmcurl/lib/openldap.c +++ b/Utilities/cmcurl/lib/openldap.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, Howard Chu, <hyc@openldap.org> - * Copyright (C) 2011 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2011 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -162,10 +162,10 @@ struct ldapconninfo { bool didbind; }; -typedef struct ldapreqinfo { +struct ldapreqinfo { int msgid; int nument; -} ldapreqinfo; +}; static CURLcode ldap_setup_connection(struct connectdata *conn) { @@ -374,7 +374,7 @@ static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection) static CURLcode ldap_do(struct connectdata *conn, bool *done) { struct ldapconninfo *li = conn->proto.ldapc; - ldapreqinfo *lr; + struct ldapreqinfo *lr; CURLcode status = CURLE_OK; int rc = 0; LDAPURLDesc *ludp = NULL; @@ -406,7 +406,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); return CURLE_LDAP_SEARCH_FAILED; } - lr = calloc(1, sizeof(ldapreqinfo)); + lr = calloc(1, sizeof(struct ldapreqinfo)); if(!lr) return CURLE_OUT_OF_MEMORY; lr->msgid = msgid; @@ -419,7 +419,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) static CURLcode ldap_done(struct connectdata *conn, CURLcode res, bool premature) { - ldapreqinfo *lr = conn->data->req.protop; + struct ldapreqinfo *lr = conn->data->req.protop; (void)res; (void)premature; @@ -443,7 +443,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, { struct ldapconninfo *li = conn->proto.ldapc; struct Curl_easy *data = conn->data; - ldapreqinfo *lr = data->req.protop; + struct ldapreqinfo *lr = data->req.protop; int rc, ret; LDAPMessage *msg = NULL; LDAPMessage *ent; diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c index d071005..ced832e 100644 --- a/Utilities/cmcurl/lib/pingpong.c +++ b/Utilities/cmcurl/lib/pingpong.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,12 +44,12 @@ /* Returns timeout in ms. 0 or negative number means the timeout has already triggered */ -time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting) +timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting) { struct connectdata *conn = pp->conn; struct Curl_easy *data = conn->data; - time_t timeout_ms; /* in milliseconds */ - long response_time = (data->set.server_response_timeout)? + timediff_t timeout_ms; /* in milliseconds */ + timediff_t response_time = (data->set.server_response_timeout)? data->set.server_response_timeout: pp->response_time; /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine @@ -60,12 +60,12 @@ time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting) /* Without a requested timeout, we only wait 'response_time' seconds for the full response to arrive before we bail out */ timeout_ms = response_time - - (time_t)Curl_timediff(Curl_now(), pp->response); /* spent time */ + Curl_timediff(Curl_now(), pp->response); /* spent time */ if(data->set.timeout && !disconnecting) { /* if timeout is requested, find out how much remaining time we have */ - time_t timeout2_ms = data->set.timeout - /* timeout time */ - (time_t)Curl_timediff(Curl_now(), conn->now); /* spent time */ + timediff_t timeout2_ms = data->set.timeout - /* timeout time */ + Curl_timediff(Curl_now(), conn->now); /* spent time */ /* pick the lowest number */ timeout_ms = CURLMIN(timeout_ms, timeout2_ms); @@ -83,8 +83,8 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block, struct connectdata *conn = pp->conn; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc; - time_t interval_ms; - time_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting); + timediff_t interval_ms; + timediff_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting); struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; diff --git a/Utilities/cmcurl/lib/pingpong.h b/Utilities/cmcurl/lib/pingpong.h index 849a7c0..e874799 100644 --- a/Utilities/cmcurl/lib/pingpong.h +++ b/Utilities/cmcurl/lib/pingpong.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -60,9 +60,8 @@ struct pingpong { size_t sendsize; /* total size of the sendthis buffer */ struct curltime response; /* set to Curl_now() when a command has been sent off, used to time-out response reading */ - long response_time; /* When no timeout is given, this is the amount of - milliseconds we await for a server response. */ - + timediff_t response_time; /* When no timeout is given, this is the amount of + milliseconds we await for a server response. */ struct connectdata *conn; /* points to the connectdata struct that this belongs to */ @@ -89,7 +88,7 @@ void Curl_pp_init(struct pingpong *pp); /* Returns timeout in ms. 0 or negative number means the timeout has already triggered */ -time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting); +timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting); /*********************************************************************** diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c index 57c1373..2f490b2 100644 --- a/Utilities/cmcurl/lib/pop3.c +++ b/Utilities/cmcurl/lib/pop3.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -178,7 +178,7 @@ static void pop3_to_pop3s(struct connectdata *conn) conn->handler = &Curl_handler_pop3s; /* Set the connection's upgraded to TLS flag */ - conn->tls_upgraded = TRUE; + conn->bits.tls_upgraded = TRUE; } #else #define pop3_to_pop3s(x) Curl_nop_stmt @@ -412,7 +412,7 @@ static CURLcode pop3_perform_apop(struct connectdata *conn) CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; size_t i; - MD5_context *ctxt; + struct MD5_context *ctxt; unsigned char digest[MD5_DIGEST_LEN]; char secret[2 * MD5_DIGEST_LEN + 1]; @@ -1312,7 +1312,7 @@ static CURLcode pop3_setup_connection(struct connectdata *conn) return result; /* Clear the TLS upgraded flag */ - conn->tls_upgraded = FALSE; + conn->bits.tls_upgraded = FALSE; return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c index 60a941a..8951384 100644 --- a/Utilities/cmcurl/lib/progress.c +++ b/Utilities/cmcurl/lib/progress.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -282,9 +282,9 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize, * stay below 'limit'. */ if(size < CURL_OFF_T_MAX/1000) - minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit); + minimum = (timediff_t) (CURL_OFF_T_C(1000) * size / limit); else { - minimum = (time_t) (size / limit); + minimum = (timediff_t) (size / limit); if(minimum < TIMEDIFF_T_MAX/1000) minimum *= 1000; else diff --git a/Utilities/cmcurl/lib/quic.h b/Utilities/cmcurl/lib/quic.h index 1eb23e9..8e7df90 100644 --- a/Utilities/cmcurl/lib/quic.h +++ b/Utilities/cmcurl/lib/quic.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,11 +47,13 @@ int Curl_quic_ver(char *p, size_t len); CURLcode Curl_quic_done_sending(struct connectdata *conn); void Curl_quic_done(struct Curl_easy *data, bool premature); bool Curl_quic_data_pending(const struct Curl_easy *data); +void Curl_quic_disconnect(struct connectdata *conn, int tempindex); #else /* ENABLE_QUIC */ #define Curl_quic_done_sending(x) #define Curl_quic_done(x,y) #define Curl_quic_data_pending(x) +#define Curl_quic_disconnect(x,y) #endif /* !ENABLE_QUIC */ #endif /* HEADER_CURL_QUIC_H */ diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c index bba4c16..dbd7dc6 100644 --- a/Utilities/cmcurl/lib/rtsp.c +++ b/Utilities/cmcurl/lib/rtsp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -233,7 +233,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) CURLcode result = CURLE_OK; Curl_RtspReq rtspreq = data->set.rtspreq; struct RTSP *rtsp = data->req.protop; - Curl_send_buffer *req_buffer; + struct dynbuf req_buffer; curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */ curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */ @@ -333,12 +333,12 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(rtspreq == RTSPREQ_SETUP && !p_transport) { /* New Transport: setting? */ if(data->set.str[STRING_RTSP_TRANSPORT]) { - Curl_safefree(conn->allocptr.rtsp_transport); + Curl_safefree(data->state.aptr.rtsp_transport); - conn->allocptr.rtsp_transport = + data->state.aptr.rtsp_transport = aprintf("Transport: %s\r\n", data->set.str[STRING_RTSP_TRANSPORT]); - if(!conn->allocptr.rtsp_transport) + if(!data->state.aptr.rtsp_transport) return CURLE_OUT_OF_MEMORY; } else { @@ -347,7 +347,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) return CURLE_BAD_FUNCTION_ARGUMENT; } - p_transport = conn->allocptr.rtsp_transport; + p_transport = data->state.aptr.rtsp_transport; } /* Accept Headers for DESCRIBE requests */ @@ -359,14 +359,14 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* Accept-Encoding header */ if(!Curl_checkheaders(conn, "Accept-Encoding") && data->set.str[STRING_ENCODING]) { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = + Curl_safefree(data->state.aptr.accept_encoding); + data->state.aptr.accept_encoding = aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); - if(!conn->allocptr.accept_encoding) + if(!data->state.aptr.accept_encoding) return CURLE_OUT_OF_MEMORY; - p_accept_encoding = conn->allocptr.accept_encoding; + p_accept_encoding = data->state.aptr.accept_encoding; } } @@ -374,13 +374,13 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) it might have been used in the proxy connect, but if we have got a header with the user-agent string specified, we erase the previously made string here. */ - if(Curl_checkheaders(conn, "User-Agent") && conn->allocptr.uagent) { - Curl_safefree(conn->allocptr.uagent); - conn->allocptr.uagent = NULL; + if(Curl_checkheaders(conn, "User-Agent") && data->state.aptr.uagent) { + Curl_safefree(data->state.aptr.uagent); + data->state.aptr.uagent = NULL; } else if(!Curl_checkheaders(conn, "User-Agent") && data->set.str[STRING_USERAGENT]) { - p_uagent = conn->allocptr.uagent; + p_uagent = data->state.aptr.uagent; } /* setup the authentication headers */ @@ -388,17 +388,17 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(result) return result; - p_proxyuserpwd = conn->allocptr.proxyuserpwd; - p_userpwd = conn->allocptr.userpwd; + p_proxyuserpwd = data->state.aptr.proxyuserpwd; + p_userpwd = data->state.aptr.userpwd; /* Referrer */ - Curl_safefree(conn->allocptr.ref); + Curl_safefree(data->state.aptr.ref); if(data->change.referer && !Curl_checkheaders(conn, "Referer")) - conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); + data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer); else - conn->allocptr.ref = NULL; + data->state.aptr.ref = NULL; - p_referrer = conn->allocptr.ref; + p_referrer = data->state.aptr.ref; /* * Range Header @@ -411,9 +411,9 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* Check to see if there is a range set in the custom headers */ if(!Curl_checkheaders(conn, "Range") && data->state.range) { - Curl_safefree(conn->allocptr.rangeline); - conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range); - p_range = conn->allocptr.rangeline; + Curl_safefree(data->state.aptr.rangeline); + data->state.aptr.rangeline = aprintf("Range: %s\r\n", data->state.range); + p_range = data->state.aptr.rangeline; } } @@ -430,16 +430,13 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } /* Initialize a dynamic send buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER); result = - Curl_add_bufferf(&req_buffer, - "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ - "CSeq: %ld\r\n", /* CSeq */ - p_request, p_stream_uri, rtsp->CSeq_sent); + Curl_dyn_addf(&req_buffer, + "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ + "CSeq: %ld\r\n", /* CSeq */ + p_request, p_stream_uri, rtsp->CSeq_sent); if(result) return result; @@ -448,7 +445,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) * to make comparison easier */ if(p_session_id) { - result = Curl_add_bufferf(&req_buffer, "Session: %s\r\n", p_session_id); + result = Curl_dyn_addf(&req_buffer, "Session: %s\r\n", p_session_id); if(result) return result; } @@ -456,42 +453,42 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* * Shared HTTP-like options */ - result = Curl_add_bufferf(&req_buffer, - "%s" /* transport */ - "%s" /* accept */ - "%s" /* accept-encoding */ - "%s" /* range */ - "%s" /* referrer */ - "%s" /* user-agent */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - , - p_transport ? p_transport : "", - p_accept ? p_accept : "", - p_accept_encoding ? p_accept_encoding : "", - p_range ? p_range : "", - p_referrer ? p_referrer : "", - p_uagent ? p_uagent : "", - p_proxyuserpwd ? p_proxyuserpwd : "", - p_userpwd ? p_userpwd : ""); + result = Curl_dyn_addf(&req_buffer, + "%s" /* transport */ + "%s" /* accept */ + "%s" /* accept-encoding */ + "%s" /* range */ + "%s" /* referrer */ + "%s" /* user-agent */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + , + p_transport ? p_transport : "", + p_accept ? p_accept : "", + p_accept_encoding ? p_accept_encoding : "", + p_range ? p_range : "", + p_referrer ? p_referrer : "", + p_uagent ? p_uagent : "", + p_proxyuserpwd ? p_proxyuserpwd : "", + p_userpwd ? p_userpwd : ""); /* * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM * with basic and digest, it will be freed anyway by the next request */ - Curl_safefree(conn->allocptr.userpwd); - conn->allocptr.userpwd = NULL; + Curl_safefree(data->state.aptr.userpwd); + data->state.aptr.userpwd = NULL; if(result) return result; if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) { - result = Curl_add_timecondition(conn, req_buffer); + result = Curl_add_timecondition(conn, &req_buffer); if(result) return result; } - result = Curl_add_custom_headers(conn, FALSE, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, &req_buffer); if(result) return result; @@ -501,14 +498,14 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(data->set.upload) { putsize = data->state.infilesize; - data->set.httpreq = HTTPREQ_PUT; + data->state.httpreq = HTTPREQ_PUT; } else { postsize = (data->state.infilesize != -1)? data->state.infilesize: (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0); - data->set.httpreq = HTTPREQ_POST; + data->state.httpreq = HTTPREQ_POST; } if(putsize > 0 || postsize > 0) { @@ -516,9 +513,9 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) * actually set a custom Content-Length in the headers */ if(!Curl_checkheaders(conn, "Content-Length")) { result = - Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", - (data->set.upload ? putsize : postsize)); + Curl_dyn_addf(&req_buffer, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", + (data->set.upload ? putsize : postsize)); if(result) return result; } @@ -526,8 +523,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { if(!Curl_checkheaders(conn, "Content-Type")) { - result = Curl_add_bufferf(&req_buffer, - "Content-Type: text/parameters\r\n"); + result = Curl_dyn_addf(&req_buffer, + "Content-Type: text/parameters\r\n"); if(result) return result; } @@ -535,8 +532,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(rtspreq == RTSPREQ_ANNOUNCE) { if(!Curl_checkheaders(conn, "Content-Type")) { - result = Curl_add_bufferf(&req_buffer, - "Content-Type: application/sdp\r\n"); + result = Curl_dyn_addf(&req_buffer, + "Content-Type: application/sdp\r\n"); if(result) return result; } @@ -546,7 +543,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } else if(rtspreq == RTSPREQ_GET_PARAMETER) { /* Check for an empty GET_PARAMETER (heartbeat) request */ - data->set.httpreq = HTTPREQ_HEAD; + data->state.httpreq = HTTPREQ_HEAD; data->set.opt_no_body = TRUE; } } @@ -554,20 +551,20 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* RTSP never allows chunked transfer */ data->req.forbidchunk = TRUE; /* Finish the request buffer */ - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req_buffer, "\r\n"); if(result) return result; if(postsize > 0) { - result = Curl_add_buffer(&req_buffer, data->set.postfields, - (size_t)postsize); + result = Curl_dyn_addn(&req_buffer, data->set.postfields, + (size_t)postsize); if(result) return result; } /* issue the request */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req_buffer, conn, + &data->info.request_size, 0, FIRSTSOCKET); if(result) { failf(data, "Failed sending RTSP request"); return result; diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c index ae23155..6832b42 100644 --- a/Utilities/cmcurl/lib/select.c +++ b/Utilities/cmcurl/lib/select.c @@ -22,8 +22,12 @@ #include "curl_setup.h" +#include <limits.h> + #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> +#elif defined(HAVE_UNISTD_H) +#include <unistd.h> #endif #if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) @@ -48,11 +52,9 @@ #include "urldata.h" #include "connect.h" #include "select.h" +#include "timeval.h" #include "warnless.h" -/* Convenience local macros */ -#define ELAPSED_MS() (int)Curl_timediff(Curl_now(), initial_tv) - /* * Internal function used for waiting a specific amount of ms * in Curl_socket_check() and Curl_poll() when no file descriptor @@ -69,7 +71,7 @@ * -1 = system call error, invalid timeout value, or interrupted * 0 = specified timeout has elapsed */ -int Curl_wait_ms(int timeout_ms) +int Curl_wait_ms(timediff_t timeout_ms) { int r = 0; @@ -81,16 +83,44 @@ int Curl_wait_ms(int timeout_ms) } #if defined(MSDOS) delay(timeout_ms); -#elif defined(USE_WINSOCK) - Sleep(timeout_ms); +#elif defined(WIN32) + /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */ +#if TIMEDIFF_T_MAX >= ULONG_MAX + if(timeout_ms >= ULONG_MAX) + timeout_ms = ULONG_MAX-1; + /* don't use ULONG_MAX, because that is equal to INFINITE */ +#endif + Sleep((ULONG)timeout_ms); #else #if defined(HAVE_POLL_FINE) - r = poll(NULL, 0, timeout_ms); + /* prevent overflow, timeout_ms is typecast to int. */ +#if TIMEDIFF_T_MAX > INT_MAX + if(timeout_ms > INT_MAX) + timeout_ms = INT_MAX; +#endif + r = poll(NULL, 0, (int)timeout_ms); #else { struct timeval pending_tv; - pending_tv.tv_sec = timeout_ms / 1000; - pending_tv.tv_usec = (timeout_ms % 1000) * 1000; + timediff_t tv_sec = timeout_ms / 1000; + timediff_t tv_usec = (timeout_ms % 1000) * 1000; /* max=999999 */ +#ifdef HAVE_SUSECONDS_T +#if TIMEDIFF_T_MAX > TIME_T_MAX + /* tv_sec overflow check in case time_t is signed */ + if(tv_sec > TIME_T_MAX) + tv_sec = TIME_T_MAX; +#endif + pending_tv.tv_sec = (time_t)tv_sec; + pending_tv.tv_usec = (suseconds_t)tv_usec; +#else +#if TIMEDIFF_T_MAX > INT_MAX + /* tv_sec overflow check in case time_t is signed */ + if(tv_sec > INT_MAX) + tv_sec = INT_MAX; +#endif + pending_tv.tv_sec = (int)tv_sec; + pending_tv.tv_usec = (int)tv_usec; +#endif r = select(0, NULL, NULL, NULL, &pending_tv); } #endif /* HAVE_POLL_FINE */ @@ -101,6 +131,98 @@ int Curl_wait_ms(int timeout_ms) } /* + * This is a wrapper around select() to aid in Windows compatibility. + * A negative timeout value makes this function wait indefinitely, + * unless no valid file descriptor is given, when this happens the + * negative timeout is ignored and the function times out immediately. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * N = number of signalled file descriptors + */ +int Curl_select(curl_socket_t maxfd, /* highest socket number */ + fd_set *fds_read, /* sockets ready for reading */ + fd_set *fds_write, /* sockets ready for writing */ + fd_set *fds_err, /* sockets with errors */ + timediff_t timeout_ms) /* milliseconds to wait */ +{ + struct timeval pending_tv; + struct timeval *ptimeout; + int r; + +#ifdef USE_WINSOCK + /* WinSock select() can't handle zero events. See the comment below. */ + if((!fds_read || fds_read->fd_count == 0) && + (!fds_write || fds_write->fd_count == 0) && + (!fds_err || fds_err->fd_count == 0)) { + r = Curl_wait_ms(timeout_ms); + return r; + } +#endif + + ptimeout = &pending_tv; + if(timeout_ms < 0) { + ptimeout = NULL; + } + else if(timeout_ms > 0) { + timediff_t tv_sec = timeout_ms / 1000; + timediff_t tv_usec = (timeout_ms % 1000) * 1000; /* max=999999 */ +#ifdef HAVE_SUSECONDS_T +#if TIMEDIFF_T_MAX > TIME_T_MAX + /* tv_sec overflow check in case time_t is signed */ + if(tv_sec > TIME_T_MAX) + tv_sec = TIME_T_MAX; +#endif + pending_tv.tv_sec = (time_t)tv_sec; + pending_tv.tv_usec = (suseconds_t)tv_usec; +#elif defined(WIN32) /* maybe also others in the future */ +#if TIMEDIFF_T_MAX > LONG_MAX + /* tv_sec overflow check on Windows there we know it is long */ + if(tv_sec > LONG_MAX) + tv_sec = LONG_MAX; +#endif + pending_tv.tv_sec = (long)tv_sec; + pending_tv.tv_usec = (long)tv_usec; +#else +#if TIMEDIFF_T_MAX > INT_MAX + /* tv_sec overflow check in case time_t is signed */ + if(tv_sec > INT_MAX) + tv_sec = INT_MAX; +#endif + pending_tv.tv_sec = (int)tv_sec; + pending_tv.tv_usec = (int)tv_usec; +#endif + } + else { + pending_tv.tv_sec = 0; + pending_tv.tv_usec = 0; + } + +#ifdef USE_WINSOCK + /* WinSock select() must not be called with an fd_set that contains zero + fd flags, or it will return WSAEINVAL. But, it also can't be called + with no fd_sets at all! From the documentation: + + Any two of the parameters, readfds, writefds, or exceptfds, can be + given as null. At least one must be non-null, and any non-null + descriptor set must contain at least one handle to a socket. + + It is unclear why WinSock doesn't just handle this for us instead of + calling this an error. + */ + r = select((int)maxfd + 1, + fds_read && fds_read->fd_count ? fds_read : NULL, + fds_write && fds_write->fd_count ? fds_write : NULL, + fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout); +#else + r = select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout); +#endif + + return r; +} + +/* * Wait for read or write events on a set of file descriptors. It uses poll() * when a fine poll() is available, in order to avoid limits with FD_SETSIZE, * otherwise select() is used. An error is returned if select() is being used @@ -123,33 +245,24 @@ int Curl_wait_ms(int timeout_ms) int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ curl_socket_t readfd1, curl_socket_t writefd, /* socket to write to */ - time_t timeout_ms) /* milliseconds to wait */ + timediff_t timeout_ms) /* milliseconds to wait */ { #ifdef HAVE_POLL_FINE struct pollfd pfd[3]; int num; #else - struct timeval pending_tv; - struct timeval *ptimeout; fd_set fds_read; fd_set fds_write; fd_set fds_err; curl_socket_t maxfd; #endif - int pending_ms = 0; int r; int ret; -#if SIZEOF_TIME_T != SIZEOF_INT - /* wrap-around precaution */ - if(timeout_ms >= INT_MAX) - timeout_ms = INT_MAX; -#endif - if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { /* no sockets, just wait */ - r = Curl_wait_ms((int)timeout_ms); + r = Curl_wait_ms(timeout_ms); return r; } @@ -158,10 +271,6 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ when function is called with a zero timeout or a negative timeout value indicating a blocking call should be performed. */ - if(timeout_ms > 0) { - pending_ms = (int)timeout_ms; - } - #ifdef HAVE_POLL_FINE num = 0; @@ -184,16 +293,9 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ num++; } - if(timeout_ms < 0) - pending_ms = -1; - else if(!timeout_ms) - pending_ms = 0; - r = poll(pfd, num, pending_ms); - - if(r < 0) - return -1; - if(r == 0) - return 0; + r = Curl_poll(pfd, num, timeout_ms); + if(r <= 0) + return r; ret = 0; num = 0; @@ -249,46 +351,17 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ maxfd = writefd; } - ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; - - if(timeout_ms > 0) { - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - } - else if(!timeout_ms) { - pending_tv.tv_sec = 0; - pending_tv.tv_usec = 0; - } - - /* WinSock select() must not be called with an fd_set that contains zero - fd flags, or it will return WSAEINVAL. But, it also can't be called - with no fd_sets at all! From the documentation: - - Any two of the parameters, readfds, writefds, or exceptfds, can be - given as null. At least one must be non-null, and any non-null - descriptor set must contain at least one handle to a socket. - - We know that we have at least one bit set in at least two fd_sets in + /* We know that we have at least one bit set in at least two fd_sets in this case, but we may have no bits set in either fds_read or fd_write, so check for that and handle it. Luckily, with WinSock, we can _also_ ask how many bits are set on an fd_set. - It is unclear why WinSock doesn't just handle this for us instead of - calling this an error. - Note also that WinSock ignores the first argument, so we don't worry about the fact that maxfd is computed incorrectly with WinSock (since curl_socket_t is unsigned in such cases and thus -1 is the largest value). */ -#ifdef USE_WINSOCK - r = select((int)maxfd + 1, - fds_read.fd_count ? &fds_read : NULL, - fds_write.fd_count ? &fds_write : NULL, - &fds_err, ptimeout); -#else - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); -#endif + r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms); if(r < 0) return -1; @@ -334,11 +407,11 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ * 0 = timeout * N = number of structures with non zero revent fields */ -int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) +int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms) { -#ifndef HAVE_POLL_FINE - struct timeval pending_tv; - struct timeval *ptimeout; +#ifdef HAVE_POLL_FINE + int pending_ms; +#else fd_set fds_read; fd_set fds_write; fd_set fds_err; @@ -346,7 +419,6 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) #endif bool fds_none = TRUE; unsigned int i; - int pending_ms = 0; int r; if(ufds) { @@ -358,6 +430,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) } } if(fds_none) { + /* no sockets, just wait */ r = Curl_wait_ms(timeout_ms); return r; } @@ -367,15 +440,18 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) when function is called with a zero timeout or a negative timeout value indicating a blocking call should be performed. */ - if(timeout_ms > 0) { - pending_ms = timeout_ms; - } - #ifdef HAVE_POLL_FINE - if(timeout_ms < 0) + /* prevent overflow, timeout_ms is typecast to int. */ +#if TIMEDIFF_T_MAX > INT_MAX + if(timeout_ms > INT_MAX) + timeout_ms = INT_MAX; +#endif + if(timeout_ms > 0) + pending_ms = (int)timeout_ms; + else if(timeout_ms < 0) pending_ms = -1; - else if(!timeout_ms) + else pending_ms = 0; r = poll(ufds, nfds, pending_ms); @@ -418,39 +494,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) } } -#ifdef USE_WINSOCK - /* WinSock select() can't handle zero events. See the comment about this in - Curl_check_socket(). */ - if(fds_read.fd_count == 0 && fds_write.fd_count == 0 - && fds_err.fd_count == 0) { - r = Curl_wait_ms(timeout_ms); - return r; - } -#endif - - ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; - - if(timeout_ms > 0) { - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - } - else if(!timeout_ms) { - pending_tv.tv_sec = 0; - pending_tv.tv_usec = 0; - } - -#ifdef USE_WINSOCK - r = select((int)maxfd + 1, - /* WinSock select() can't handle fd_sets with zero bits set, so - don't give it such arguments. See the comment about this in - Curl_check_socket(). - */ - fds_read.fd_count ? &fds_read : NULL, - fds_write.fd_count ? &fds_write : NULL, - fds_err.fd_count ? &fds_err : NULL, ptimeout); -#else - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); -#endif + r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms); if(r < 0) return -1; diff --git a/Utilities/cmcurl/lib/select.h b/Utilities/cmcurl/lib/select.h index ec3021a..95181f4 100644 --- a/Utilities/cmcurl/lib/select.h +++ b/Utilities/cmcurl/lib/select.h @@ -72,20 +72,26 @@ struct pollfd therefore defined here */ #define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1) +int Curl_select(curl_socket_t maxfd, + fd_set *fds_read, + fd_set *fds_write, + fd_set *fds_err, + timediff_t timeout_ms); + int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, curl_socket_t writefd, - time_t timeout_ms); + timediff_t timeout_ms); #define SOCKET_READABLE(x,z) \ - Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, (time_t)z) + Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z) #define SOCKET_WRITABLE(x,z) \ - Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, (time_t)z) + Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z) -int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); -int Curl_wait_ms(int timeout_ms); +int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms); +int Curl_wait_ms(timediff_t timeout_ms); #ifdef TPF int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, - fd_set* excepts, struct timeval* tv); + fd_set* excepts, struct timeval *tv); #endif /* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c index 6ef47aa..147ecbf 100644 --- a/Utilities/cmcurl/lib/sendf.c +++ b/Utilities/cmcurl/lib/sendf.c @@ -267,7 +267,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) size_t len; char error[CURL_ERROR_SIZE + 2]; va_start(ap, fmt); - mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); + (void)mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); len = strlen(error); if(data->set.errorbuffer && !data->state.errorbuf) { @@ -498,7 +498,6 @@ static CURLcode pausewrite(struct Curl_easy *data, is again enabled */ struct SingleRequest *k = &data->req; struct UrlState *s = &data->state; - char *dupl; unsigned int i; bool newtype = TRUE; @@ -518,44 +517,21 @@ static CURLcode pausewrite(struct Curl_easy *data, else i = 0; - if(!newtype) { - /* append new data to old data */ - - /* figure out the new size of the data to save */ - size_t newlen = len + s->tempwrite[i].len; - /* allocate the new memory area */ - char *newptr = realloc(s->tempwrite[i].buf, newlen); - if(!newptr) - return CURLE_OUT_OF_MEMORY; - /* copy the new data to the end of the new area */ - memcpy(newptr + s->tempwrite[i].len, ptr, len); - - /* update the pointer and the size */ - s->tempwrite[i].buf = newptr; - s->tempwrite[i].len = newlen; - - len = newlen; /* for the debug output below */ - } - else { - dupl = Curl_memdup(ptr, len); - if(!dupl) - return CURLE_OUT_OF_MEMORY; - + if(newtype) { /* store this information in the state struct for later use */ - s->tempwrite[i].buf = dupl; - s->tempwrite[i].len = len; + Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER); s->tempwrite[i].type = type; if(newtype) s->tempcount++; } + if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len)) + return CURLE_OUT_OF_MEMORY; + /* mark the connection as RECV paused */ k->keepon |= KEEP_RECV_PAUSE; - DEBUGF(infof(data, "Paused %zu bytes in buffer for type %02x\n", - len, type)); - return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c index 2e494a6..90edf6a 100644 --- a/Utilities/cmcurl/lib/setopt.c +++ b/Utilities/cmcurl/lib/setopt.c @@ -77,6 +77,37 @@ CURLcode Curl_setstropt(char **charp, const char *s) return CURLE_OK; } +CURLcode Curl_setblobopt(struct curl_blob **blobp, + const struct curl_blob *blob) +{ + /* free the previous storage at `blobp' and replace by a dynamic storage + copy of blob. If CURL_BLOB_COPY is set, the data is copied. */ + + Curl_safefree(*blobp); + + if(blob) { + struct curl_blob *nblob; + if(blob->len > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + nblob = (struct curl_blob *) + malloc(sizeof(struct curl_blob) + + ((blob->flags & CURL_BLOB_COPY) ? blob->len : 0)); + if(!nblob) + return CURLE_OUT_OF_MEMORY; + *nblob = *blob; + if(blob->flags & CURL_BLOB_COPY) { + /* put the data after the blob struct in memory */ + nblob->data = (char *)nblob + sizeof(struct curl_blob); + memcpy(nblob->data, blob->data, blob->len); + } + + *blobp = nblob; + return CURLE_OK; + } + + return CURLE_OK; +} + static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) { CURLcode result = CURLE_OK; @@ -240,6 +271,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Do not include the body part in the output data stream. */ data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE; + if(data->set.opt_no_body) + /* in HTTP lingo, no body means using the HEAD request... */ + data->set.method = HTTPREQ_HEAD; break; case CURLOPT_FAILONERROR: /* @@ -261,13 +295,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE; if(data->set.upload) { /* If this is HTTP, PUT is what's needed to "upload" */ - data->set.httpreq = HTTPREQ_PUT; + data->set.method = HTTPREQ_PUT; data->set.opt_no_body = FALSE; /* this is implied */ } else /* In HTTP, the opposite of upload is GET (unless NOBODY is true as then this can be changed to HEAD later on) */ - data->set.httpreq = HTTPREQ_GET; + data->set.method = HTTPREQ_GET; break; case CURLOPT_REQUEST_TARGET: result = Curl_setstropt(&data->set.str[STRING_TARGET], @@ -363,7 +397,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; case CURLOPT_SSLVERSION: +#ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLVERSION: +#endif /* * Set explicit SSL version to try to connect with, as some SSL * implementations are lame. @@ -371,9 +407,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) #ifdef USE_SSL { long version, version_max; - struct ssl_primary_config *primary = (option == CURLOPT_SSLVERSION ? - &data->set.ssl.primary : - &data->set.proxy_ssl.primary); + struct ssl_primary_config *primary = &data->set.ssl.primary; +#ifndef CURL_DISABLE_PROXY + if(option != CURLOPT_SSLVERSION) + primary = &data->set.proxy_ssl.primary; +#endif arg = va_arg(param, long); @@ -481,11 +519,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) CURLOPT_POSTFIELDS isn't used and the POST data is read off the callback! */ if(va_arg(param, long)) { - data->set.httpreq = HTTPREQ_POST; + data->set.method = HTTPREQ_POST; data->set.opt_no_body = FALSE; /* this is implied */ } else - data->set.httpreq = HTTPREQ_GET; + data->set.method = HTTPREQ_GET; break; case CURLOPT_COPYPOSTFIELDS: @@ -532,7 +570,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) } data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS]; - data->set.httpreq = HTTPREQ_POST; + data->set.method = HTTPREQ_POST; break; case CURLOPT_POSTFIELDS: @@ -542,7 +580,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.postfields = va_arg(param, void *); /* Release old copied data. */ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); - data->set.httpreq = HTTPREQ_POST; + data->set.method = HTTPREQ_POST; break; case CURLOPT_POSTFIELDSIZE: @@ -588,7 +626,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Set to make us do HTTP POST */ data->set.httppost = va_arg(param, struct curl_httppost *); - data->set.httpreq = HTTPREQ_POST_FORM; + data->set.method = HTTPREQ_POST_FORM; data->set.opt_no_body = FALSE; /* this is implied */ break; #endif /* CURL_DISABLE_HTTP */ @@ -600,7 +638,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_mime_set_subparts(&data->set.mimepost, va_arg(param, curl_mime *), FALSE); if(!result) { - data->set.httpreq = HTTPREQ_POST_MIME; + data->set.method = HTTPREQ_POST_MIME; data->set.opt_no_body = FALSE; /* this is implied */ } break; @@ -795,7 +833,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Set to force us do HTTP GET */ if(va_arg(param, long)) { - data->set.httpreq = HTTPREQ_GET; + data->set.method = HTTPREQ_GET; data->set.upload = FALSE; /* switch off upload */ data->set.opt_no_body = FALSE; /* this is implied */ } @@ -905,7 +943,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) va_arg(param, char *)); /* we don't set - data->set.httpreq = HTTPREQ_CUSTOM; + data->set.method = HTTPREQ_CUSTOM; here, we continue as if we were using the already set type and this just changes the actual request keyword */ break; @@ -1606,6 +1644,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG], va_arg(param, char *)); break; + case CURLOPT_SSLCERT_BLOB: + /* + * Blob that holds file name of the SSL certificate to use + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_ORIG], + va_arg(param, struct curl_blob *)); + break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLCERT: /* @@ -1614,6 +1659,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY], va_arg(param, char *)); break; + case CURLOPT_PROXY_SSLCERT_BLOB: + /* + * Blob that holds file name of the SSL certificate to use for proxy + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY], + va_arg(param, struct curl_blob *)); + break; #endif case CURLOPT_SSLCERTTYPE: /* @@ -1638,6 +1690,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG], va_arg(param, char *)); break; + case CURLOPT_SSLKEY_BLOB: + /* + * Blob that holds file name of the SSL key to use + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_ORIG], + va_arg(param, struct curl_blob *)); + break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLKEY: /* @@ -1646,6 +1705,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY], va_arg(param, char *)); break; + case CURLOPT_PROXY_SSLKEY_BLOB: + /* + * Blob that holds file name of the SSL key to use for proxy + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY], + va_arg(param, struct curl_blob *)); + break; #endif case CURLOPT_SSLKEYTYPE: /* @@ -1970,6 +2036,30 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG], va_arg(param, char *)); break; + case CURLOPT_ISSUERCERT_BLOB: + /* + * Blob that holds Issuer certificate to check certificates issuer + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG], + va_arg(param, struct curl_blob *)); + break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_ISSUERCERT: + /* + * Set Issuer certificate file + * to check certificates issuer + */ + result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_ISSUERCERT_BLOB: + /* + * Blob that holds Issuer certificate to check certificates issuer + */ + result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY], + va_arg(param, struct curl_blob *)); + break; +#endif #ifndef CURL_DISABLE_TELNET case CURLOPT_TELNETOPTIONS: /* @@ -1993,7 +2083,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) arg = READBUFFER_MIN; /* Resize if new size */ - if(arg != data->set.buffer_size) { + if((arg != data->set.buffer_size) && data->state.buffer) { char *newbuff = realloc(data->state.buffer, arg + 1); if(!newbuff) { DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n")); @@ -2134,6 +2224,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); + data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); + data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA); break; #ifndef CURL_DISABLE_PROXY @@ -2143,6 +2235,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); + data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA); + data->set.proxy_ssl.revoke_best_effort = + !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); break; #endif @@ -2245,7 +2340,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_SSL_SESSIONID_CACHE: data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE; +#ifndef CURL_DISABLE_PROXY data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid; +#endif break; #ifdef USE_SSH @@ -2547,9 +2644,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_PROXY_TLSAUTH_USERNAME: result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], va_arg(param, char *)); +#ifndef CURL_DISABLE_PROXY if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && !data->set.proxy_ssl.authtype) data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ +#endif break; case CURLOPT_TLSAUTH_PASSWORD: result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG], @@ -2560,9 +2659,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_PROXY_TLSAUTH_PASSWORD: result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], va_arg(param, char *)); +#ifndef CURL_DISABLE_PROXY if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && !data->set.proxy_ssl.authtype) data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ +#endif break; case CURLOPT_TLSAUTH_TYPE: argptr = va_arg(param, char *); @@ -2572,6 +2673,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) else data->set.ssl.authtype = CURL_TLSAUTH_NONE; break; +#ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_TLSAUTH_TYPE: argptr = va_arg(param, char *); if(!argptr || @@ -2581,18 +2683,35 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE; break; #endif +#endif #ifdef USE_ARES case CURLOPT_DNS_SERVERS: - result = Curl_set_dns_servers(data, va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]); break; case CURLOPT_DNS_INTERFACE: - result = Curl_set_dns_interface(data, va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]); break; case CURLOPT_DNS_LOCAL_IP4: - result = Curl_set_dns_local_ip4(data, va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]); break; case CURLOPT_DNS_LOCAL_IP6: - result = Curl_set_dns_local_ip6(data, va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], + va_arg(param, char *)); + if(result) + return result; + result = Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]); break; #endif case CURLOPT_TCP_KEEPALIVE: diff --git a/Utilities/cmcurl/lib/setopt.h b/Utilities/cmcurl/lib/setopt.h index 5e347dd..5fc4368 100644 --- a/Utilities/cmcurl/lib/setopt.h +++ b/Utilities/cmcurl/lib/setopt.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,6 +23,8 @@ ***************************************************************************/ CURLcode Curl_setstropt(char **charp, const char *s); +CURLcode Curl_setblobopt(struct curl_blob **blobp, + const struct curl_blob *blob); CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg); #endif /* HEADER_CURL_SETOPT_H */ diff --git a/Utilities/cmcurl/lib/setup-os400.h b/Utilities/cmcurl/lib/setup-os400.h index 629fd94..b693cb3 100644 --- a/Utilities/cmcurl/lib/setup-os400.h +++ b/Utilities/cmcurl/lib/setup-os400.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -200,10 +200,10 @@ extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status, /* Some socket functions must be wrapped to process textual addresses like AF_UNIX. */ -extern int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen); -extern int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen); +extern int Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen); +extern int Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen); extern int Curl_os400_sendto(int sd, char *buffer, int buflen, int flags, - struct sockaddr * dstaddr, int addrlen); + struct sockaddr *dstaddr, int addrlen); extern int Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags, struct sockaddr *fromaddr, int *addrlen); extern int Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen); diff --git a/Utilities/cmcurl/lib/setup-vms.h b/Utilities/cmcurl/lib/setup-vms.h index 6c454ae..0e39c9f 100644 --- a/Utilities/cmcurl/lib/setup-vms.h +++ b/Utilities/cmcurl/lib/setup-vms.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -73,7 +73,7 @@ char *decc$getenv(const char *__name); # endif #endif - struct passwd * decc_getpwuid(uid_t uid); + struct passwd *decc_getpwuid(uid_t uid); #ifdef __DECC # if __INITIAL_POINTER_SIZE == 32 @@ -138,9 +138,9 @@ static char *vms_getenv(const char *envvar) static struct passwd vms_passwd_cache; -static struct passwd * vms_getpwuid(uid_t uid) +static struct passwd *vms_getpwuid(uid_t uid) { - struct passwd * my_passwd; + struct passwd *my_passwd; /* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */ #ifdef __DECC diff --git a/Utilities/cmcurl/lib/setup-win32.h b/Utilities/cmcurl/lib/setup-win32.h new file mode 100644 index 0000000..45b5847 --- /dev/null +++ b/Utilities/cmcurl/lib/setup-win32.h @@ -0,0 +1,123 @@ +#ifndef HEADER_CURL_SETUP_WIN32_H +#define HEADER_CURL_SETUP_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Include header files for windows builds before redefining anything. + * Use this preprocessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. <sys/socket.h>) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# if defined(UNICODE) && !defined(_UNICODE) +# define _UNICODE +# endif +# if defined(_UNICODE) && !defined(UNICODE) +# define UNICODE +# endif +# include <winerror.h> +# include <windows.h> +# ifdef HAVE_WINSOCK2_H +# include <winsock2.h> +# ifdef HAVE_WS2TCPIP_H +# include <ws2tcpip.h> +# endif +# else +# ifdef HAVE_WINSOCK_H +# include <winsock.h> +# endif +# endif +# include <tchar.h> +# ifdef UNICODE + typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Define _WIN32_WINNT_[OS] symbols because not all Windows build systems have + * those symbols to compare against, and even those that do may be missing + * newer symbols. + */ + +#ifndef _WIN32_WINNT_NT4 +#define _WIN32_WINNT_NT4 0x0400 /* Windows NT 4.0 */ +#endif +#ifndef _WIN32_WINNT_WIN2K +#define _WIN32_WINNT_WIN2K 0x0500 /* Windows 2000 */ +#endif +#ifndef _WIN32_WINNT_WINXP +#define _WIN32_WINNT_WINXP 0x0501 /* Windows XP */ +#endif +#ifndef _WIN32_WINNT_WS03 +#define _WIN32_WINNT_WS03 0x0502 /* Windows Server 2003 */ +#endif +#ifndef _WIN32_WINNT_WIN6 +#define _WIN32_WINNT_WIN6 0x0600 /* Windows Vista */ +#endif +#ifndef _WIN32_WINNT_VISTA +#define _WIN32_WINNT_VISTA 0x0600 /* Windows Vista */ +#endif +#ifndef _WIN32_WINNT_WS08 +#define _WIN32_WINNT_WS08 0x0600 /* Windows Server 2008 */ +#endif +#ifndef _WIN32_WINNT_LONGHORN +#define _WIN32_WINNT_LONGHORN 0x0600 /* Windows Vista */ +#endif +#ifndef _WIN32_WINNT_WIN7 +#define _WIN32_WINNT_WIN7 0x0601 /* Windows 7 */ +#endif +#ifndef _WIN32_WINNT_WIN8 +#define _WIN32_WINNT_WIN8 0x0602 /* Windows 8 */ +#endif +#ifndef _WIN32_WINNT_WINBLUE +#define _WIN32_WINNT_WINBLUE 0x0603 /* Windows 8.1 */ +#endif +#ifndef _WIN32_WINNT_WINTHRESHOLD +#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 /* Windows 10 */ +#endif +#ifndef _WIN32_WINNT_WIN10 +#define _WIN32_WINNT_WIN10 0x0A00 /* Windows 10 */ +#endif + +#endif /* HEADER_CURL_SETUP_WIN32_H */ diff --git a/Utilities/cmcurl/lib/sha256.c b/Utilities/cmcurl/lib/sha256.c index 9721418..ee5d273 100644 --- a/Utilities/cmcurl/lib/sha256.c +++ b/Utilities/cmcurl/lib/sha256.c @@ -161,6 +161,81 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) #endif } +#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ + (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) + +#include <CommonCrypto/CommonDigest.h> + +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +typedef CC_SHA256_CTX SHA256_CTX; + +static void SHA256_Init(SHA256_CTX *ctx) +{ + (void) CC_SHA256_Init(ctx); +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *data, + unsigned int length) +{ + (void) CC_SHA256_Update(ctx, data, length); +} + +static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +{ + (void) CC_SHA256_Final(digest, ctx); +} + +#elif defined(USE_WIN32_CRYPTO) + +#include <wincrypt.h> + +struct sha256_ctx { + HCRYPTPROV hCryptProv; + HCRYPTHASH hHash; +}; +typedef struct sha256_ctx SHA256_CTX; + +#if !defined(CALG_SHA_256) +#define CALG_SHA_256 0x0000800c +#endif + +static void SHA256_Init(SHA256_CTX *ctx) +{ + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash); + } +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *data, + unsigned int length) +{ + CryptHashData(ctx->hHash, (unsigned char *) data, length, 0); +} + +static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +{ + unsigned long length = 0; + + CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); + if(length == SHA256_DIGEST_LENGTH) + CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); + + if(ctx->hHash) + CryptDestroyHash(ctx->hHash); + + if(ctx->hCryptProv) + CryptReleaseContext(ctx->hCryptProv, 0); +} + #else /* When no other crypto library is available we use this code segment */ @@ -206,7 +281,7 @@ do { \ } while(0) #endif -typedef struct sha256_state { +struct sha256_state { #ifdef HAVE_LONGLONG unsigned long long length; #else @@ -214,7 +289,8 @@ typedef struct sha256_state { #endif unsigned long state[8], curlen; unsigned char buf[64]; -} SHA256_CTX; +}; +typedef struct sha256_state SHA256_CTX; /* The K array */ static const unsigned long K[64] = { diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c index 3d51086..a2d8960 100644 --- a/Utilities/cmcurl/lib/share.c +++ b/Utilities/cmcurl/lib/share.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -70,7 +70,7 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) case CURLSHOPT_SHARE: /* this is a type this share will share */ type = va_arg(param, int); - share->specifier |= (1<<type); + switch(type) { case CURL_LOCK_DATA_DNS: break; @@ -102,7 +102,7 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) #endif break; - case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */ + case CURL_LOCK_DATA_CONNECT: if(Curl_conncache_init(&share->conn_cache, 103)) res = CURLSHE_NOMEM; break; @@ -116,6 +116,8 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) default: res = CURLSHE_BAD_OPTION; } + if(!res) + share->specifier |= (1<<type); break; case CURLSHOPT_UNSHARE: diff --git a/Utilities/cmcurl/lib/smb.h b/Utilities/cmcurl/lib/smb.h index 9ce6b56..136a89c 100644 --- a/Utilities/cmcurl/lib/smb.h +++ b/Utilities/cmcurl/lib/smb.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies - * Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -193,7 +193,6 @@ struct smb_nt_create_response { unsigned int ext_file_attributes; curl_off_t allocation_size; curl_off_t end_of_file; - } PACK; struct smb_read { diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c index e187287..ec93648 100644 --- a/Utilities/cmcurl/lib/smtp.c +++ b/Utilities/cmcurl/lib/smtp.c @@ -183,7 +183,7 @@ static void smtp_to_smtps(struct connectdata *conn) conn->handler = &Curl_handler_smtps; /* Set the connection's upgraded to TLS flag */ - conn->tls_upgraded = TRUE; + conn->bits.tls_upgraded = TRUE; } #else #define smtp_to_smtps(x) Curl_nop_stmt @@ -625,8 +625,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) utf8 = TRUE; if(host.name) { - free(from); - from = aprintf("<%s@%s>", address, host.name); + auth = aprintf("<%s@%s>", address, host.name); Curl_free_idnconverted_hostname(&host); } @@ -636,8 +635,6 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) auth = aprintf("<%s>", address); free(address); - if(!from) - return CURLE_OUT_OF_MEMORY; } else /* Empty AUTH, RFC-2554, sect. 5 */ @@ -1620,7 +1617,7 @@ static CURLcode smtp_setup_connection(struct connectdata *conn) CURLcode result; /* Clear the TLS upgraded flag */ - conn->tls_upgraded = FALSE; + conn->bits.tls_upgraded = FALSE; /* Initialise the SMTP layer */ result = smtp_init(conn); @@ -1741,10 +1738,10 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn) * Notes: * * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor - * that convertion then we shall return success. This allow the caller to send + * that conversion then we shall return success. This allow the caller to send * the data to the server as a U-label (as per RFC-6531 sect. 3.2). * - * If an mailbox '@' seperator cannot be located then the mailbox is considered + * If an mailbox '@' separator cannot be located then the mailbox is considered * to be either a local mailbox or an invalid mailbox (depending on what the * calling function deems it to be) then the input will simply be returned in * the address part with the host name being NULL. @@ -1765,7 +1762,7 @@ static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma, if(dup[length - 1] == '>') dup[length - 1] = '\0'; - /* Extract the host name from the addresss (if we can) */ + /* Extract the host name from the address (if we can) */ host->name = strpbrk(dup, "@"); if(host->name) { *host->name = '\0'; diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c index 0fb97e1..b2215fe 100644 --- a/Utilities/cmcurl/lib/socks.c +++ b/Utilities/cmcurl/lib/socks.c @@ -62,13 +62,15 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ int result; *n = 0; for(;;) { - timediff_t timeleft = Curl_timeleft(conn->data, NULL, TRUE); - if(timeleft < 0) { + timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, TRUE); + if(timeout_ms < 0) { /* we already got the timeout */ result = CURLE_OPERATION_TIMEDOUT; break; } - if(SOCKET_READABLE(sockfd, timeleft) <= 0) { + if(!timeout_ms) + timeout_ms = TIMEDIFF_T_MAX; + if(SOCKET_READABLE(sockfd, timeout_ms) <= 0) { result = ~CURLE_OK; break; } @@ -205,6 +207,8 @@ CURLcode Curl_SOCKS4(const char *proxy_user, switch(sx->state) { case CONNECT_SOCKS_INIT: + /* SOCKS4 can only do IPv4, insist! */ + conn->ip_version = CURL_IPRESOLVE_V4; if(conn->bits.httpproxy) infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n", protocol4a ? "a" : "", hostname, remote_port); @@ -261,13 +265,13 @@ CURLcode Curl_SOCKS4(const char *proxy_user, } else { result = Curl_resolv_check(data->conn, &dns); - /* stay in the state or error out */ - return result; + if(!dns) + return result; } /* FALLTHROUGH */ CONNECT_RESOLVED: case CONNECT_RESOLVED: { - Curl_addrinfo *hp = NULL; + struct Curl_addrinfo *hp = NULL; char buf[64]; /* * We cannot use 'hostent' as a struct that Curl_resolv() returns. It @@ -378,6 +382,11 @@ CURLcode Curl_SOCKS4(const char *proxy_user, curl_easy_strerror(result)); return CURLE_COULDNT_CONNECT; } + else if(!result && !actualread) { + /* connection closed */ + failf(data, "connection to proxy closed"); + return CURLE_COULDNT_CONNECT; + } else if(actualread != sx->outstanding) { /* remain in reading state */ sx->outstanding -= actualread; @@ -588,6 +597,11 @@ CURLcode Curl_SOCKS5(const char *proxy_user, failf(data, "Unable to receive initial SOCKS5 response."); return CURLE_COULDNT_CONNECT; } + else if(!result && !actualread) { + /* connection closed */ + failf(data, "Connection to proxy closed"); + return CURLE_COULDNT_CONNECT; + } else if(actualread != sx->outstanding) { /* remain in reading state */ sx->outstanding -= actualread; @@ -629,11 +643,10 @@ CURLcode Curl_SOCKS5(const char *proxy_user, failf(data, "No authentication method was acceptable."); return CURLE_COULDNT_CONNECT; } - failf(data, - "Undocumented SOCKS5 mode attempted to be used by server."); - return CURLE_COULDNT_CONNECT; } - break; + failf(data, + "Undocumented SOCKS5 mode attempted to be used by server."); + return CURLE_COULDNT_CONNECT; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) case CONNECT_GSSAPI_INIT: /* GSSAPI stuff done non-blocking */ @@ -714,15 +727,19 @@ CURLcode Curl_SOCKS5(const char *proxy_user, failf(data, "Unable to receive SOCKS5 sub-negotiation response."); return CURLE_COULDNT_CONNECT; } - if(actualread != sx->outstanding) { + else if(!result && !actualread) { + /* connection closed */ + failf(data, "connection to proxy closed"); + return CURLE_COULDNT_CONNECT; + } + else if(actualread != sx->outstanding) { /* remain in state */ sx->outstanding -= actualread; sx->outp += actualread; return CURLE_OK; } - /* ignore the first (VER) byte */ - if(socksreq[1] != 0) { /* status */ + else if(socksreq[1] != 0) { /* status */ failf(data, "User was rejected by the SOCKS5 server (%d %d).", socksreq[0], socksreq[1]); return CURLE_COULDNT_CONNECT; @@ -763,13 +780,14 @@ CURLcode Curl_SOCKS5(const char *proxy_user, if(!dns) { result = Curl_resolv_check(data->conn, &dns); - /* stay in the state or error out */ - return result; + if(!dns) + return result; } /* FALLTHROUGH */ CONNECT_RESOLVED: case CONNECT_RESOLVED: { - Curl_addrinfo *hp = NULL; + struct Curl_addrinfo *hp = NULL; + size_t destlen; if(dns) hp = dns->addr; if(!hp) { @@ -778,13 +796,9 @@ CURLcode Curl_SOCKS5(const char *proxy_user, return CURLE_COULDNT_RESOLVE_HOST; } - if(Curl_printable_address(hp, dest, sizeof(dest))) { - size_t destlen = strlen(dest); - msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port); - } - else { - strcpy(dest, "unknown"); - } + Curl_printable_address(hp, dest, sizeof(dest)); + destlen = strlen(dest); + msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port); len = 0; socksreq[len++] = 5; /* version (SOCKS5) */ @@ -890,6 +904,11 @@ CURLcode Curl_SOCKS5(const char *proxy_user, failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } + else if(!result && !actualread) { + /* connection closed */ + failf(data, "connection to proxy closed"); + return CURLE_COULDNT_CONNECT; + } else if(actualread != sx->outstanding) { /* remain in state */ sx->outstanding -= actualread; @@ -934,6 +953,13 @@ CURLcode Curl_SOCKS5(const char *proxy_user, /* IPv6 */ len = 4 + 16 + 2; } + else if(socksreq[3] == 1) { + len = 4 + 4 + 2; + } + else { + failf(data, "SOCKS5 reply has wrong address type."); + return CURLE_COULDNT_CONNECT; + } /* At this point we already read first 10 bytes */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) @@ -960,7 +986,12 @@ CURLcode Curl_SOCKS5(const char *proxy_user, failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } - if(actualread != sx->outstanding) { + else if(!result && !actualread) { + /* connection closed */ + failf(data, "connection to proxy closed"); + return CURLE_COULDNT_CONNECT; + } + else if(actualread != sx->outstanding) { /* remain in state */ sx->outstanding -= actualread; sx->outp += actualread; diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c index 97ee718..2e36b99 100644 --- a/Utilities/cmcurl/lib/socks_gssapi.c +++ b/Utilities/cmcurl/lib/socks_gssapi.c @@ -115,7 +115,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc* gss_token = GSS_C_NO_BUFFER; + gss_buffer_desc *gss_token = GSS_C_NO_BUFFER; gss_name_t server = GSS_C_NO_NAME; gss_name_t gss_client_name = GSS_C_NO_NAME; unsigned short us_length; @@ -227,7 +227,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_send_token); gss_release_buffer(&gss_status, &gss_recv_token); - if(gss_major_status != GSS_S_CONTINUE_NEEDED) break; + if(gss_major_status != GSS_S_CONTINUE_NEEDED) + break; /* analyse response */ @@ -327,7 +328,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, user[gss_send_token.length] = '\0'; gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); - infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user); + infof(data, "SOCKS5 server authenticated user %s with GSS-API.\n",user); free(user); user = NULL; diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c index d5be64a..2f1fd36 100644 --- a/Utilities/cmcurl/lib/socks_sspi.c +++ b/Utilities/cmcurl/lib/socks_sspi.c @@ -160,7 +160,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, for(;;) { TCHAR *sname; - sname = Curl_convert_UTF8_to_tchar(service_name); + sname = curlx_convert_UTF8_to_tchar(service_name); if(!sname) return CURLE_OUT_OF_MEMORY; @@ -180,7 +180,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, &sspi_ret_flags, &expiry); - Curl_unicodefree(sname); + curlx_unicodefree(sname); if(sspi_recv_token.pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); @@ -327,7 +327,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, failf(data, "Failed to determine user name."); return CURLE_COULDNT_CONNECT; } - infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n", + infof(data, "SOCKS5 server authenticated user %s with GSS-API.\n", names.sUserName); s_pSecFn->FreeContextBuffer(names.sUserName); diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c index 4bf4c65..c3b58e5 100644 --- a/Utilities/cmcurl/lib/telnet.c +++ b/Utilities/cmcurl/lib/telnet.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -1315,7 +1315,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) DWORD readfile_read; int err; #else - int interval_ms; + timediff_t interval_ms; struct pollfd pfd[2]; int poll_cnt; curl_off_t total_dl = 0; diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c index 346f293..4f2f973 100644 --- a/Utilities/cmcurl/lib/tftp.c +++ b/Utilities/cmcurl/lib/tftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -115,11 +115,11 @@ typedef enum { TFTP_ERR_NORESPONSE } tftp_error_t; -typedef struct tftp_packet { +struct tftp_packet { unsigned char *data; -} tftp_packet_t; +}; -typedef struct tftp_state_data { +struct tftp_state_data { tftp_state_t state; tftp_mode_t mode; tftp_error_t error; @@ -140,21 +140,21 @@ typedef struct tftp_state_data { int sbytes; int blksize; int requested_blksize; - tftp_packet_t rpacket; - tftp_packet_t spacket; -} tftp_state_data_t; + struct tftp_packet rpacket; + struct tftp_packet spacket; +}; /* Forward declarations */ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event); -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event); +static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event); +static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event); static CURLcode tftp_connect(struct connectdata *conn, bool *done); static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode tftp_do(struct connectdata *conn, bool *done); static CURLcode tftp_done(struct connectdata *conn, CURLcode, bool premature); -static CURLcode tftp_setup_connection(struct connectdata * conn); +static CURLcode tftp_setup_connection(struct connectdata *conn); static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done); static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done); static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks); @@ -196,7 +196,7 @@ const struct Curl_handler Curl_handler_tftp = { * * **********************************************************/ -static CURLcode tftp_set_timeouts(tftp_state_data_t *state) +static CURLcode tftp_set_timeouts(struct tftp_state_data *state) { time_t maxtime, timeout; timediff_t timeout_ms; @@ -279,25 +279,25 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) * **********************************************************/ -static void setpacketevent(tftp_packet_t *packet, unsigned short num) +static void setpacketevent(struct tftp_packet *packet, unsigned short num) { packet->data[0] = (unsigned char)(num >> 8); packet->data[1] = (unsigned char)(num & 0xff); } -static void setpacketblock(tftp_packet_t *packet, unsigned short num) +static void setpacketblock(struct tftp_packet *packet, unsigned short num) { packet->data[2] = (unsigned char)(num >> 8); packet->data[3] = (unsigned char)(num & 0xff); } -static unsigned short getrpacketevent(const tftp_packet_t *packet) +static unsigned short getrpacketevent(const struct tftp_packet *packet) { return (unsigned short)((packet->data[0] << 8) | packet->data[1]); } -static unsigned short getrpacketblock(const tftp_packet_t *packet) +static unsigned short getrpacketblock(const struct tftp_packet *packet) { return (unsigned short)((packet->data[2] << 8) | packet->data[3]); } @@ -330,7 +330,7 @@ static const char *tftp_option_get(const char *buf, size_t len, return &buf[loc]; } -static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, +static CURLcode tftp_parse_option_ack(struct tftp_state_data *state, const char *ptr, int len) { const char *tmp = ptr; @@ -403,7 +403,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, return CURLE_OK; } -static CURLcode tftp_option_add(tftp_state_data_t *state, size_t *csize, +static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize, char *buf, const char *option) { if(( strlen(option) + *csize + 1) > (size_t)state->blksize) @@ -413,7 +413,7 @@ static CURLcode tftp_option_add(tftp_state_data_t *state, size_t *csize, return CURLE_OK; } -static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, +static CURLcode tftp_connect_for_tx(struct tftp_state_data *state, tftp_event_t event) { CURLcode result; @@ -429,7 +429,7 @@ static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, return tftp_tx(state, event); } -static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, +static CURLcode tftp_connect_for_rx(struct tftp_state_data *state, tftp_event_t event) { CURLcode result; @@ -445,7 +445,8 @@ static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, return tftp_rx(state, event); } -static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) +static CURLcode tftp_send_first(struct tftp_state_data *state, + tftp_event_t event) { size_t sbytes; ssize_t senddata; @@ -598,7 +599,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) * Event handler for the RX state * **********************************************************/ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) +static CURLcode tftp_rx(struct tftp_state_data *state, + tftp_event_t event) { ssize_t sbytes; int rblock; @@ -720,7 +722,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) * Event handler for the TX state * **********************************************************/ -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) +static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event) { struct Curl_easy *data = state->conn->data; ssize_t sbytes; @@ -920,7 +922,7 @@ static CURLcode tftp_translate_code(tftp_error_t error) * The tftp state machine event dispatcher * **********************************************************/ -static CURLcode tftp_state_machine(tftp_state_data_t *state, +static CURLcode tftp_state_machine(struct tftp_state_data *state, tftp_event_t event) { CURLcode result = CURLE_OK; @@ -961,7 +963,7 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, **********************************************************/ static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection) { - tftp_state_data_t *state = conn->proto.tftpc; + struct tftp_state_data *state = conn->proto.tftpc; (void) dead_connection; /* done, free dynamically allocated pkt buffers */ @@ -983,13 +985,13 @@ static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection) **********************************************************/ static CURLcode tftp_connect(struct connectdata *conn, bool *done) { - tftp_state_data_t *state; + struct tftp_state_data *state; int blksize; int need_blksize; blksize = TFTP_BLKSIZE_DEFAULT; - state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t)); + state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data)); if(!state) return CURLE_OUT_OF_MEMORY; @@ -1078,7 +1080,7 @@ static CURLcode tftp_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; + struct tftp_state_data *state = conn->proto.tftpc; (void)status; /* unused */ (void)premature; /* not used */ @@ -1119,7 +1121,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn) curl_socklen_t fromlen; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; + struct tftp_state_data *state = conn->proto.tftpc; struct SingleRequest *k = &data->req; /* Receive the packet */ @@ -1206,8 +1208,8 @@ static CURLcode tftp_receive_packet(struct connectdata *conn) **********************************************************/ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) { - time_t current; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; + time_t current; + struct tftp_state_data *state = conn->proto.tftpc; if(event) *event = TFTP_EVENT_NONE; @@ -1244,7 +1246,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) tftp_event_t event; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; + struct tftp_state_data *state = conn->proto.tftpc; long timeout_ms = tftp_state_timeout(conn, &event); *done = FALSE; @@ -1328,7 +1330,7 @@ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done) static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) { CURLcode result = CURLE_OK; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; + struct tftp_state_data *state = conn->proto.tftpc; *dophase_done = FALSE; @@ -1358,7 +1360,7 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) static CURLcode tftp_do(struct connectdata *conn, bool *done) { - tftp_state_data_t *state; + struct tftp_state_data *state; CURLcode result; *done = FALSE; @@ -1369,7 +1371,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done) return result; } - state = (tftp_state_data_t *)conn->proto.tftpc; + state = conn->proto.tftpc; if(!state) return CURLE_TFTP_ILLEGAL; @@ -1384,7 +1386,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done) return result; } -static CURLcode tftp_setup_connection(struct connectdata * conn) +static CURLcode tftp_setup_connection(struct connectdata *conn) { struct Curl_easy *data = conn->data; char *type; diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c index 8270761..133a478 100644 --- a/Utilities/cmcurl/lib/transfer.c +++ b/Utilities/cmcurl/lib/transfer.c @@ -48,6 +48,8 @@ #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> +#elif defined(HAVE_UNISTD_H) +#include <unistd.h> #endif #ifndef HAVE_SOCKET @@ -126,12 +128,13 @@ static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems, void *raw) { struct Curl_easy *data = (struct Curl_easy *)raw; - Curl_send_buffer *trailers_buf = data->state.trailers_buf; - size_t bytes_left = trailers_buf->size_used-data->state.trailers_bytes_sent; + struct dynbuf *trailers_buf = &data->state.trailers_buf; + size_t bytes_left = Curl_dyn_len(trailers_buf) - + data->state.trailers_bytes_sent; size_t to_copy = (size*nitems < bytes_left) ? size*nitems : bytes_left; if(to_copy) { memcpy(buffer, - &trailers_buf->buffer[data->state.trailers_bytes_sent], + Curl_dyn_ptr(trailers_buf) + data->state.trailers_bytes_sent, to_copy); data->state.trailers_bytes_sent += to_copy; } @@ -141,8 +144,8 @@ static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems, static size_t Curl_trailers_left(void *raw) { struct Curl_easy *data = (struct Curl_easy *)raw; - Curl_send_buffer *trailers_buf = data->state.trailers_buf; - return trailers_buf->size_used - data->state.trailers_bytes_sent; + struct dynbuf *trailers_buf = &data->state.trailers_buf; + return Curl_dyn_len(trailers_buf) - data->state.trailers_bytes_sent; } #endif @@ -184,11 +187,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, infof(data, "Moving trailers state machine from initialized to sending.\n"); data->state.trailers_state = TRAILERS_SENDING; - data->state.trailers_buf = Curl_add_buffer_init(); - if(!data->state.trailers_buf) { - failf(data, "Unable to allocate trailing headers buffer !"); - return CURLE_OUT_OF_MEMORY; - } + Curl_dyn_init(&data->state.trailers_buf, DYN_TRAILERS); + data->state.trailers_bytes_sent = 0; Curl_set_in_callback(data, true); trailers_ret_code = data->set.trailer_callback(&trailers, @@ -204,7 +204,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, result = CURLE_ABORTED_BY_CALLBACK; } if(result) { - Curl_add_buffer_free(&data->state.trailers_buf); + Curl_dyn_free(&data->state.trailers_buf); curl_slist_free_all(trailers); return result; } @@ -367,7 +367,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, #ifndef CURL_DISABLE_HTTP if(data->state.trailers_state == TRAILERS_SENDING && !Curl_trailers_left(data)) { - Curl_add_buffer_free(&data->state.trailers_buf); + Curl_dyn_free(&data->state.trailers_buf); data->state.trailers_state = TRAILERS_DONE; data->set.trailer_data = NULL; data->set.trailer_callback = NULL; @@ -433,8 +433,8 @@ CURLcode Curl_readrewind(struct connectdata *conn) } if(data->set.postfields) ; /* do nothing */ - else if(data->set.httpreq == HTTPREQ_POST_MIME || - data->set.httpreq == HTTPREQ_POST_FORM) { + else if(data->state.httpreq == HTTPREQ_POST_MIME || + data->state.httpreq == HTTPREQ_POST_FORM) { if(Curl_mime_rewind(mimepart)) { failf(data, "Cannot rewind mime/post data"); return CURLE_SEND_FAIL_REWIND; @@ -558,6 +558,8 @@ static CURLcode readwrite_data(struct Curl_easy *data, size_t excess = 0; /* excess bytes read */ bool readmore = FALSE; /* used by RTP to signal for more data */ int maxloops = 100; + char *buf = data->state.buffer; + DEBUGASSERT(buf); *done = FALSE; *comeback = FALSE; @@ -568,17 +570,20 @@ static CURLcode readwrite_data(struct Curl_easy *data, bool is_empty_data = FALSE; size_t buffersize = data->set.buffer_size; size_t bytestoread = buffersize; +#ifdef USE_NGHTTP2 + bool is_http2 = ((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (conn->httpversion == 20)); +#endif if( -#if defined(USE_NGHTTP2) +#ifdef USE_NGHTTP2 /* For HTTP/2, read data without caring about the content length. This is safe because body in HTTP/2 is always segmented thanks to its framing layer. Meanwhile, we have to call Curl_read to ensure that http2_handle_stream_close is called when we read all incoming bytes for a particular stream. */ - !((conn->handler->protocol & PROTO_FAMILY_HTTP) && - conn->httpversion == 20) && + !is_http2 && #endif k->size != -1 && !k->header) { /* make sure we don't read too much */ @@ -589,7 +594,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, if(bytestoread) { /* receive data from the network! */ - result = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread); + result = Curl_read(conn, conn->sockfd, buf, bytestoread, &nread); /* read would've blocked */ if(CURLE_AGAIN == result) @@ -616,21 +621,25 @@ static CURLcode readwrite_data(struct Curl_easy *data, /* indicates data of zero size, i.e. empty file */ is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE; - /* NUL terminate, allowing string ops to be used */ if(0 < nread || is_empty_data) { - k->buf[nread] = 0; + buf[nread] = 0; } else { - /* if we receive 0 or less here, the server closed the connection - and we bail out from this! */ - DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n")); + /* if we receive 0 or less here, either the http2 stream is closed or the + server closed the connection and we bail out from this! */ +#ifdef USE_NGHTTP2 + if(is_http2 && !nread) + DEBUGF(infof(data, "nread == 0, stream closed, bailing\n")); + else +#endif + DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n")); k->keepon &= ~KEEP_RECV; break; } /* Default buffer to use when we write the buffer, it may be changed in the flow below before the actual storing is done. */ - k->str = k->buf; + k->str = buf; if(conn->handler->readwrite) { result = conn->handler->readwrite(data, conn, &nread, &readmore); @@ -679,7 +688,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, /* This is not an 'else if' since it may be a rest from the header parsing, where the beginning of the buffer is headers and the end is non-headers. */ - if(k->str && !k->header && (nread > 0 || is_empty_data)) { + if(!k->header && (nread > 0 || is_empty_data)) { if(data->set.opt_no_body) { /* data arrives although we want none, bail out */ @@ -710,7 +719,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, infof(data, "Ignoring the response-body\n"); } if(data->state.resume_from && !k->content_range && - (data->set.httpreq == HTTPREQ_GET) && + (data->state.httpreq == HTTPREQ_GET) && !k->ignorebody) { if(k->size == data->state.resume_from) { @@ -760,8 +769,9 @@ static CURLcode readwrite_data(struct Curl_easy *data, /* pass data to the debug function before it gets "dechunked" */ if(data->set.verbose) { if(k->badheader) { - Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff, - (size_t)k->hbuflen); + Curl_debug(data, CURLINFO_DATA_IN, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); if(k->badheader == HEADER_PARTHEADER) Curl_debug(data, CURLINFO_DATA_IN, k->str, (size_t)nread); @@ -812,9 +822,9 @@ static CURLcode readwrite_data(struct Curl_easy *data, /* Account for body content stored in the header buffer */ if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) { - DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n", - k->hbuflen)); - k->bytecount += k->hbuflen; + size_t headlen = Curl_dyn_len(&data->state.headerb); + DEBUGF(infof(data, "Increasing bytecount by %zu\n", headlen)); + k->bytecount += headlen; } if((-1 != k->maxdownload) && @@ -829,6 +839,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, ", maxdownload = %" CURL_FORMAT_CURL_OFF_T ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n", excess, k->size, k->maxdownload, k->bytecount); + connclose(conn, "excess found in a read"); } nread = (ssize_t) (k->maxdownload - k->bytecount); @@ -848,15 +859,16 @@ static CURLcode readwrite_data(struct Curl_easy *data, if(k->badheader && !k->ignorebody) { /* we parsed a piece of data wrongly assuming it was a header and now we output it as body instead */ + size_t headlen = Curl_dyn_len(&data->state.headerb); /* Don't let excess data pollute body writes */ - if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload) + if(k->maxdownload == -1 || (curl_off_t)headlen <= k->maxdownload) result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, - k->hbuflen); + Curl_dyn_ptr(&data->state.headerb), + headlen); else result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, + Curl_dyn_ptr(&data->state.headerb), (size_t)k->maxdownload); if(result) @@ -890,14 +902,14 @@ static CURLcode readwrite_data(struct Curl_easy *data, } /* if(!header and data to read) */ - if(conn->handler->readwrite && excess && !conn->bits.stream_was_rewound) { + if(conn->handler->readwrite && excess) { /* Parse the excess data */ k->str += nread; - if(&k->str[excess] > &k->buf[data->set.buffer_size]) { + if(&k->str[excess] > &buf[data->set.buffer_size]) { /* the excess amount was too excessive(!), make sure it doesn't read out of buffer */ - excess = &k->buf[data->set.buffer_size] - k->str; + excess = &buf[data->set.buffer_size] - k->str; } nread = (ssize_t)excess; @@ -1217,8 +1229,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, else fd_write = CURL_SOCKET_BAD; - if(data->state.drain) { - data->state.drain--; + if(conn->data->state.drain) { select_res |= CURL_CSELECT_IN; DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n")); } @@ -1235,9 +1246,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, /* We go ahead and do a read if we have a readable socket or if the stream was rewound (in which case we have data in a buffer) */ - if((k->keepon & KEEP_RECV) && - ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { - + if((k->keepon & KEEP_RECV) && (select_res & CURL_CSELECT_IN)) { result = readwrite_data(data, conn, k, &didwhat, done, comeback); if(result || *done) return result; @@ -1440,6 +1449,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) } } + data->state.httpreq = data->set.method; data->change.url = data->set.str[STRING_SET_URL]; /* Init the SSL session ID cache here. We do it here since we want to do it @@ -1459,12 +1469,11 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) data->state.authhost.want = data->set.httpauth; data->state.authproxy.want = data->set.proxyauth; Curl_safefree(data->info.wouldredirect); - data->info.wouldredirect = NULL; - if(data->set.httpreq == HTTPREQ_PUT) + if(data->state.httpreq == HTTPREQ_PUT) data->state.infilesize = data->set.filesize; - else if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD)) { + else if((data->state.httpreq != HTTPREQ_GET) && + (data->state.httpreq != HTTPREQ_HEAD)) { data->state.infilesize = data->set.postfieldsize; if(data->set.postfields && (data->state.infilesize == -1)) data->state.infilesize = (curl_off_t)strlen(data->set.postfields); @@ -1675,12 +1684,12 @@ CURLcode Curl_follow(struct Curl_easy *data, * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and * can be overridden with CURLOPT_POSTREDIR. */ - if((data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM - || data->set.httpreq == HTTPREQ_POST_MIME) + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) && !(data->set.keep_post & CURL_REDIR_POST_301)) { infof(data, "Switch from POST to GET\n"); - data->set.httpreq = HTTPREQ_GET; + data->state.httpreq = HTTPREQ_GET; } break; case 302: /* Found */ @@ -1700,22 +1709,29 @@ CURLcode Curl_follow(struct Curl_easy *data, * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and * can be overridden with CURLOPT_POSTREDIR. */ - if((data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM - || data->set.httpreq == HTTPREQ_POST_MIME) + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) && !(data->set.keep_post & CURL_REDIR_POST_302)) { infof(data, "Switch from POST to GET\n"); - data->set.httpreq = HTTPREQ_GET; + data->state.httpreq = HTTPREQ_GET; } break; case 303: /* See Other */ - /* Disable both types of POSTs, unless the user explicitly - asks for POST after POST */ - if(data->set.httpreq != HTTPREQ_GET - && !(data->set.keep_post & CURL_REDIR_POST_303)) { - data->set.httpreq = HTTPREQ_GET; /* enforce GET request */ - infof(data, "Disables POST, goes with %s\n", + /* 'See Other' location is not the resource but a substitute for the + * resource. In this case we switch the method to GET/HEAD, unless the + * method is POST and the user specified to keep it as POST. + * https://github.com/curl/curl/issues/5237#issuecomment-614641049 + */ + if(data->state.httpreq != HTTPREQ_GET && + ((data->state.httpreq != HTTPREQ_POST && + data->state.httpreq != HTTPREQ_POST_FORM && + data->state.httpreq != HTTPREQ_POST_MIME) || + !(data->set.keep_post & CURL_REDIR_POST_303))) { + data->state.httpreq = HTTPREQ_GET; + data->set.upload = false; + infof(data, "Switch to %s\n", data->set.opt_no_body?"HEAD":"GET"); } break; @@ -1782,6 +1798,12 @@ CURLcode Curl_retry_request(struct connectdata *conn, retry = TRUE; } if(retry) { +#define CONN_MAX_RETRIES 5 + if(conn->retrycount++ >= CONN_MAX_RETRIES) { + failf(data, "Connection died, tried %d times before giving up", + CONN_MAX_RETRIES); + return CURLE_SEND_ERROR; + } infof(conn->data, "Connection died, retrying a fresh connect\n"); *url = strdup(conn->data->change.url); if(!*url) @@ -1824,15 +1846,21 @@ Curl_setup_transfer( { struct SingleRequest *k = &data->req; struct connectdata *conn = data->conn; + struct HTTP *http = data->req.protop; + bool httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) && + (http->sending == HTTPSEND_REQUEST)); DEBUGASSERT(conn != NULL); DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); - if(conn->bits.multiplex || conn->httpversion == 20) { + if(conn->bits.multiplex || conn->httpversion == 20 || httpsending) { /* when multiplexing, the read/write sockets need to be the same! */ conn->sockfd = sockindex == -1 ? ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) : conn->sock[sockindex]; conn->writesockfd = conn->sockfd; + if(httpsending) + /* special and very HTTP-specific */ + writesockindex = FIRSTSOCKET; } else { conn->sockfd = sockindex == -1 ? @@ -1860,7 +1888,6 @@ Curl_setup_transfer( k->keepon |= KEEP_RECV; if(writesockindex != -1) { - struct HTTP *http = data->req.protop; /* HTTP 1.1 magic: Even if we require a 100-return code before uploading data, we might diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c index 47fc66a..8225e61 100644 --- a/Utilities/cmcurl/lib/url.c +++ b/Utilities/cmcurl/lib/url.c @@ -114,6 +114,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "http_ntlm.h" #include "curl_rtmp.h" #include "gopher.h" +#include "mqtt.h" #include "http_proxy.h" #include "conncache.h" #include "multihandle.h" @@ -121,6 +122,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "strdup.h" #include "setopt.h" #include "altsvc.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -140,19 +142,21 @@ static unsigned int get_protocol_family(unsigned int protocol); /* - * Protocol table. + * Protocol table. Schemes (roughly) in 2019 popularity order: + * + * HTTPS, HTTP, FTP, FTPS, SFTP, FILE, SCP, SMTP, LDAP, IMAPS, TELNET, IMAP, + * LDAPS, SMTPS, TFTP, SMB, POP3, GOPHER POP3S, RTSP, RTMP, SMBS, DICT */ - static const struct Curl_handler * const protocols[] = { -#ifndef CURL_DISABLE_HTTP - &Curl_handler_http, -#endif - #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) &Curl_handler_https, #endif +#ifndef CURL_DISABLE_HTTP + &Curl_handler_http, +#endif + #ifndef CURL_DISABLE_FTP &Curl_handler_ftp, #endif @@ -161,12 +165,23 @@ static const struct Curl_handler * const protocols[] = { &Curl_handler_ftps, #endif -#ifndef CURL_DISABLE_TELNET - &Curl_handler_telnet, +#if defined(USE_SSH) + &Curl_handler_sftp, #endif -#ifndef CURL_DISABLE_DICT - &Curl_handler_dict, +#ifndef CURL_DISABLE_FILE + &Curl_handler_file, +#endif + +#if defined(USE_SSH) && !defined(USE_WOLFSSH) + &Curl_handler_scp, +#endif + +#ifndef CURL_DISABLE_SMTP + &Curl_handler_smtp, +#ifdef USE_SSL + &Curl_handler_smtps, +#endif #endif #ifndef CURL_DISABLE_LDAP @@ -178,22 +193,6 @@ static const struct Curl_handler * const protocols[] = { #endif #endif -#ifndef CURL_DISABLE_FILE - &Curl_handler_file, -#endif - -#ifndef CURL_DISABLE_TFTP - &Curl_handler_tftp, -#endif - -#if defined(USE_SSH) && !defined(USE_WOLFSSH) - &Curl_handler_scp, -#endif - -#if defined(USE_SSH) - &Curl_handler_sftp, -#endif - #ifndef CURL_DISABLE_IMAP &Curl_handler_imap, #ifdef USE_SSL @@ -201,6 +200,14 @@ static const struct Curl_handler * const protocols[] = { #endif #endif +#ifndef CURL_DISABLE_TELNET + &Curl_handler_telnet, +#endif + +#ifndef CURL_DISABLE_TFTP + &Curl_handler_tftp, +#endif + #ifndef CURL_DISABLE_POP3 &Curl_handler_pop3, #ifdef USE_SSL @@ -217,17 +224,14 @@ static const struct Curl_handler * const protocols[] = { #endif #endif -#ifndef CURL_DISABLE_SMTP - &Curl_handler_smtp, -#ifdef USE_SSL - &Curl_handler_smtps, -#endif -#endif - #ifndef CURL_DISABLE_RTSP &Curl_handler_rtsp, #endif +#ifdef CURL_ENABLE_MQTT + &Curl_handler_mqtt, +#endif + #ifndef CURL_DISABLE_GOPHER &Curl_handler_gopher, #endif @@ -241,6 +245,10 @@ static const struct Curl_handler * const protocols[] = { &Curl_handler_rtmpts, #endif +#ifndef CURL_DISABLE_DICT + &Curl_handler_dict, +#endif + (struct Curl_handler *) NULL }; @@ -273,10 +281,16 @@ void Curl_freeset(struct Curl_easy *data) { /* Free all dynamic strings stored in the data->set substructure. */ enum dupstring i; + enum dupblob j; + for(i = (enum dupstring)0; i < STRING_LAST; i++) { Curl_safefree(data->set.str[i]); } + for(j = (enum dupblob)0; j < BLOB_LAST; j++) { + Curl_safefree(data->set.blobs[j]); + } + if(data->change.referer_alloc) { Curl_safefree(data->change.referer); data->change.referer_alloc = FALSE; @@ -375,7 +389,7 @@ CURLcode Curl_close(struct Curl_easy **datap) up_free(data); Curl_safefree(data->state.buffer); - Curl_safefree(data->state.headerbuff); + Curl_dyn_free(&data->state.headerb); Curl_safefree(data->state.ulbuf); Curl_flush_cookies(data, TRUE); #ifdef USE_ALTSVC @@ -402,9 +416,20 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } + Curl_safefree(data->state.aptr.proxyuserpwd); + Curl_safefree(data->state.aptr.uagent); + Curl_safefree(data->state.aptr.userpwd); + Curl_safefree(data->state.aptr.accept_encoding); + Curl_safefree(data->state.aptr.te); + Curl_safefree(data->state.aptr.rangeline); + Curl_safefree(data->state.aptr.ref); + Curl_safefree(data->state.aptr.host); + Curl_safefree(data->state.aptr.cookiehost); + Curl_safefree(data->state.aptr.rtsp_transport); + #ifndef CURL_DISABLE_DOH - free(data->req.doh.probe[0].serverdoh.memory); - free(data->req.doh.probe[1].serverdoh.memory); + Curl_dyn_free(&data->req.doh.probe[0].serverdoh); + Curl_dyn_free(&data->req.doh.probe[1].serverdoh); curl_slist_free_all(data->req.doh.headers); #endif @@ -448,7 +473,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->postfieldsize = -1; /* unknown size */ set->maxredirs = -1; /* allow any amount by default */ - set->httpreq = HTTPREQ_GET; /* Default HTTP request */ + set->method = HTTPREQ_GET; /* Default HTTP request */ set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ #ifndef CURL_DISABLE_FTP set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ @@ -487,7 +512,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) type */ set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by default */ +#ifndef CURL_DISABLE_PROXY set->proxy_ssl = set->ssl; +#endif set->new_file_perms = 0644; /* Default permissions */ set->new_directory_perms = 0755; /* Default permissions */ @@ -596,38 +623,22 @@ CURLcode Curl_open(struct Curl_easy **curl) return result; } - /* We do some initial setup here, all those fields that can't be just 0 */ - - data->state.buffer = malloc(READBUFFER_SIZE + 1); - if(!data->state.buffer) { - DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n")); - result = CURLE_OUT_OF_MEMORY; - } - else { - data->state.headerbuff = malloc(HEADERSIZE); - if(!data->state.headerbuff) { - DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); - result = CURLE_OUT_OF_MEMORY; - } - else { - result = Curl_init_userdefined(data); - - data->state.headersize = HEADERSIZE; - Curl_convert_init(data); - Curl_initinfo(data); + result = Curl_init_userdefined(data); + if(!result) { + Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); + Curl_convert_init(data); + Curl_initinfo(data); - /* most recent connection is not yet defined */ - data->state.lastconnect = NULL; + /* most recent connection is not yet defined */ + data->state.lastconnect = NULL; - data->progress.flags |= PGRS_HIDE; - data->state.current_speed = -1; /* init to negative == impossible */ - } + data->progress.flags |= PGRS_HIDE; + data->state.current_speed = -1; /* init to negative == impossible */ } if(result) { Curl_resolver_cleanup(data->state.resolver); - free(data->state.buffer); - free(data->state.headerbuff); + Curl_dyn_free(&data->state.headerb); Curl_freeset(data); free(data); data = NULL; @@ -679,9 +690,7 @@ static void conn_reset_all_postponed_data(struct connectdata *conn) static void conn_shutdown(struct connectdata *conn) { - if(!conn) - return; - + DEBUGASSERT(conn); infof(conn->data, "Closing connection %ld\n", conn->connection_id); DEBUGASSERT(conn->data); @@ -702,54 +711,40 @@ static void conn_shutdown(struct connectdata *conn) Curl_closesocket(conn, conn->tempsock[0]); if(CURL_SOCKET_BAD != conn->tempsock[1]) Curl_closesocket(conn, conn->tempsock[1]); - - /* unlink ourselves. this should be called last since other shutdown - procedures need a valid conn->data and this may clear it. */ - Curl_conncache_remove_conn(conn->data, conn, TRUE); } static void conn_free(struct connectdata *conn) { - if(!conn) - return; + DEBUGASSERT(conn); Curl_free_idnconverted_hostname(&conn->host); Curl_free_idnconverted_hostname(&conn->conn_to_host); +#ifndef CURL_DISABLE_PROXY Curl_free_idnconverted_hostname(&conn->http_proxy.host); Curl_free_idnconverted_hostname(&conn->socks_proxy.host); - - Curl_safefree(conn->user); - Curl_safefree(conn->passwd); - Curl_safefree(conn->sasl_authzid); - Curl_safefree(conn->options); Curl_safefree(conn->http_proxy.user); Curl_safefree(conn->socks_proxy.user); Curl_safefree(conn->http_proxy.passwd); Curl_safefree(conn->socks_proxy.passwd); - Curl_safefree(conn->allocptr.proxyuserpwd); - Curl_safefree(conn->allocptr.uagent); - Curl_safefree(conn->allocptr.userpwd); - Curl_safefree(conn->allocptr.accept_encoding); - Curl_safefree(conn->allocptr.te); - Curl_safefree(conn->allocptr.rangeline); - Curl_safefree(conn->allocptr.ref); - Curl_safefree(conn->allocptr.host); - Curl_safefree(conn->allocptr.cookiehost); - Curl_safefree(conn->allocptr.rtsp_transport); - Curl_safefree(conn->trailer); + Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ + Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ + Curl_free_primary_ssl_config(&conn->proxy_ssl_config); +#endif + Curl_safefree(conn->user); + Curl_safefree(conn->passwd); + Curl_safefree(conn->sasl_authzid); + Curl_safefree(conn->options); + Curl_dyn_free(&conn->trailer); Curl_safefree(conn->host.rawalloc); /* host name buffer */ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ Curl_safefree(conn->hostname_resolve); Curl_safefree(conn->secondaryhostname); - Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ - Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ Curl_safefree(conn->connect_state); conn_reset_all_postponed_data(conn); Curl_llist_destroy(&conn->easyq, NULL); Curl_safefree(conn->localdev); Curl_free_primary_ssl_config(&conn->ssl_config); - Curl_free_primary_ssl_config(&conn->proxy_ssl_config); #ifdef USE_UNIX_SOCKETS Curl_safefree(conn->unix_domain_socket); @@ -778,13 +773,17 @@ static void conn_free(struct connectdata *conn) CURLcode Curl_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection) { - if(!conn) - return CURLE_OK; /* this is closed and fine already */ + /* there must be a connection to close */ + DEBUGASSERT(conn); - if(!data) { - DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n")); - return CURLE_OK; - } + /* it must be removed from the connection cache */ + DEBUGASSERT(!conn->bundle); + + /* there must be an associated transfer */ + DEBUGASSERT(data); + + /* the transfer must be detached from the connection */ + DEBUGASSERT(!data->conn); /* * If this connection isn't marked to force-close, leave it open if there @@ -800,16 +799,11 @@ CURLcode Curl_disconnect(struct Curl_easy *data, conn->dns_entry = NULL; } - Curl_hostcache_prune(data); /* kill old DNS cache entries */ - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) /* Cleanup NTLM connection-related data */ Curl_http_auth_cleanup_ntlm(conn); -#endif -#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) + /* Cleanup NEGOTIATE connection-related data */ Curl_http_auth_cleanup_negotiate(conn); -#endif /* the protocol specific disconnect handler and conn_shutdown need a transfer for the connection! */ @@ -871,8 +865,8 @@ static int IsMultiplexingPossible(const struct Curl_easy *handle, #ifndef CURL_DISABLE_PROXY static bool -proxy_info_matches(const struct proxy_info* data, - const struct proxy_info* needle) +proxy_info_matches(const struct proxy_info *data, + const struct proxy_info *needle) { if((data->proxytype == needle->proxytype) && (data->port == needle->port) && @@ -883,8 +877,8 @@ proxy_info_matches(const struct proxy_info* data, } static bool -socks_proxy_info_matches(const struct proxy_info* data, - const struct proxy_info* needle) +socks_proxy_info_matches(const struct proxy_info *data, + const struct proxy_info *needle) { if(!proxy_info_matches(data, needle)) return FALSE; @@ -1006,8 +1000,12 @@ static int call_extract_if_dead(struct connectdata *conn, void *param) static void prune_dead_connections(struct Curl_easy *data) { struct curltime now = Curl_now(); - timediff_t elapsed = + timediff_t elapsed; + + CONNCACHE_LOCK(data); + elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup); + CONNCACHE_UNLOCK(data); if(elapsed >= 1000L) { struct prunedead prune; @@ -1015,10 +1013,17 @@ static void prune_dead_connections(struct Curl_easy *data) prune.extracted = NULL; while(Curl_conncache_foreach(data, data->state.conn_cache, &prune, call_extract_if_dead)) { + /* unlocked */ + + /* remove connection from cache */ + Curl_conncache_remove_conn(data, prune.extracted, TRUE); + /* disconnect it */ (void)Curl_disconnect(data, prune.extracted, /* dead_connection */TRUE); } + CONNCACHE_LOCK(data); data->state.conn_cache->last_cleanup = now; + CONNCACHE_UNLOCK(data); } } @@ -1051,10 +1056,14 @@ ConnectionExists(struct Curl_easy *data, bool wantNTLMhttp = ((data->state.authhost.want & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && (needle->handler->protocol & PROTO_FAMILY_HTTP)); +#ifndef CURL_DISABLE_PROXY bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd && ((data->state.authproxy.want & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && (needle->handler->protocol & PROTO_FAMILY_HTTP))); +#else + bool wantProxyNTLMhttp = FALSE; +#endif #endif *force_reuse = FALSE; @@ -1078,7 +1087,7 @@ ConnectionExists(struct Curl_easy *data, if(data->set.pipewait) { infof(data, "Server doesn't support multiplex yet, wait\n"); *waitpipe = TRUE; - Curl_conncache_unlock(data); + CONNCACHE_UNLOCK(data); return FALSE; /* no re-use */ } @@ -1151,7 +1160,8 @@ ConnectionExists(struct Curl_easy *data, continue; if(strcmp(needle->unix_domain_socket, check->unix_domain_socket)) continue; - if(needle->abstract_unix_socket != check->abstract_unix_socket) + if(needle->bits.abstract_unix_socket != + check->bits.abstract_unix_socket) continue; } else if(check->unix_domain_socket) @@ -1162,10 +1172,11 @@ ConnectionExists(struct Curl_easy *data, (check->handler->flags&PROTOPT_SSL)) /* don't do mixed SSL and non-SSL connections */ if(get_protocol_family(check->handler->protocol) != - needle->handler->protocol || !check->tls_upgraded) + needle->handler->protocol || !check->bits.tls_upgraded) /* except protocols that have been upgraded via TLS */ continue; +#ifndef CURL_DISABLE_PROXY if(needle->bits.httpproxy != check->bits.httpproxy || needle->bits.socksproxy != check->bits.socksproxy) continue; @@ -1174,7 +1185,7 @@ ConnectionExists(struct Curl_easy *data, !socks_proxy_info_matches(&needle->socks_proxy, &check->socks_proxy)) continue; - +#endif if(needle->bits.conn_to_host != check->bits.conn_to_host) /* don't mix connections that use the "connect to host" feature and * connections that don't use this feature */ @@ -1185,6 +1196,7 @@ ConnectionExists(struct Curl_easy *data, * connections that don't use this feature */ continue; +#ifndef CURL_DISABLE_PROXY if(needle->bits.httpproxy) { if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy)) continue; @@ -1211,6 +1223,7 @@ ConnectionExists(struct Curl_easy *data, } } } +#endif DEBUGASSERT(!check->data || GOOD_EASY_HANDLE(check->data)); @@ -1253,15 +1266,18 @@ ConnectionExists(struct Curl_easy *data, } } - if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || - needle->bits.tunnel_proxy) { + if((needle->handler->flags&PROTOPT_SSL) +#ifndef CURL_DISABLE_PROXY + || !needle->bits.httpproxy || needle->bits.tunnel_proxy +#endif + ) { /* The requested connection does not use a HTTP proxy or it uses SSL or it is a non-SSL protocol tunneled or it is a non-SSL protocol which is allowed to be upgraded via TLS */ if((strcasecompare(needle->handler->scheme, check->handler->scheme) || (get_protocol_family(check->handler->protocol) == - needle->handler->protocol && check->tls_upgraded)) && + needle->handler->protocol && check->bits.tls_upgraded)) && (!needle->bits.conn_to_host || strcasecompare( needle->conn_to_host.name, check->conn_to_host.name)) && (!needle->bits.conn_to_port || @@ -1323,6 +1339,7 @@ ConnectionExists(struct Curl_easy *data, continue; } +#ifndef CURL_DISABLE_PROXY /* Same for Proxy NTLM authentication */ if(wantProxyNTLMhttp) { /* Both check->http_proxy.user and check->http_proxy.passwd can be @@ -1338,7 +1355,7 @@ ConnectionExists(struct Curl_easy *data, /* Proxy connection is using NTLM auth but we don't want NTLM */ continue; } - +#endif if(wantNTLMhttp || wantProxyNTLMhttp) { /* Credentials are already checked, we can use this connection */ chosen = check; @@ -1402,11 +1419,12 @@ ConnectionExists(struct Curl_easy *data, if(chosen) { /* mark it as used before releasing the lock */ chosen->data = data; /* own it! */ - Curl_conncache_unlock(data); + Curl_attach_connnection(data, chosen); + CONNCACHE_UNLOCK(data); *usethis = chosen; return TRUE; /* yes, we found one to use! */ } - Curl_conncache_unlock(data); + CONNCACHE_UNLOCK(data); if(foundPendingCandidate && data->set.pipewait) { infof(data, @@ -1425,8 +1443,10 @@ void Curl_verboseconnect(struct connectdata *conn) { if(conn->data->set.verbose) infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", +#ifndef CURL_DISABLE_PROXY conn->bits.socksproxy ? conn->socks_proxy.host.dispname : conn->bits.httpproxy ? conn->http_proxy.host.dispname : +#endif conn->bits.conn_to_host ? conn->conn_to_host.dispname : conn->host.dispname, conn->ip_addr_str, conn->port, conn->connection_id); @@ -1573,8 +1593,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->ssl_extra = ssl; conn->ssl[0].backend = (void *)ssl; conn->ssl[1].backend = (void *)(ssl + sslsize); +#ifndef CURL_DISABLE_PROXY conn->proxy_ssl[0].backend = (void *)(ssl + 2 * sslsize); conn->proxy_ssl[1].backend = (void *)(ssl + 3 * sslsize); +#endif } #endif @@ -1613,10 +1635,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->data = data; /* Setup the association between this connection and the Curl_easy */ +#ifndef CURL_DISABLE_PROXY conn->http_proxy.proxytype = data->set.proxytype; conn->socks_proxy.proxytype = CURLPROXY_SOCKS4; -#if !defined(CURL_DISABLE_PROXY) /* note that these two proxy bits are now just on what looks to be requested, they may be altered down the road */ conn->bits.proxy = (data->set.str[STRING_PROXY] && @@ -1647,10 +1669,12 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; +#ifndef CURL_DISABLE_PROXY conn->proxy_ssl_config.verifystatus = data->set.proxy_ssl.primary.verifystatus; conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; +#endif conn->ip_version = data->set.ipver; conn->bits.connect_only = data->set.connect_only; conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */ @@ -1996,7 +2020,7 @@ static CURLcode setup_range(struct Curl_easy *data) */ static CURLcode setup_connection_internals(struct connectdata *conn) { - const struct Curl_handler * p; + const struct Curl_handler *p; CURLcode result; /* Perform setup complement if some. */ @@ -2343,24 +2367,14 @@ static CURLcode parse_proxy(struct Curl_easy *data, static CURLcode parse_proxy_auth(struct Curl_easy *data, struct connectdata *conn) { - char proxyuser[MAX_CURL_USER_LENGTH]=""; - char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; - CURLcode result; - - if(data->set.str[STRING_PROXYUSERNAME] != NULL) { - strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME], - MAX_CURL_USER_LENGTH); - proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/ - } - if(data->set.str[STRING_PROXYPASSWORD] != NULL) { - strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD], - MAX_CURL_PASSWORD_LENGTH); - proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ - } + char *proxyuser = data->set.str[STRING_PROXYUSERNAME]; + char *proxypasswd = data->set.str[STRING_PROXYPASSWORD]; + CURLcode result = CURLE_OK; - result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL, - FALSE); - if(!result) + if(proxyuser) + result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL, + FALSE); + if(!result && proxypasswd) result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd, NULL, FALSE); return result; @@ -2580,6 +2594,12 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len, size_t plen; size_t olen; + /* the input length check is because this is called directcly from setopt + and isn't going through the regular string length check */ + size_t llen = strlen(login); + if(llen > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + /* Attempt to find the password separator */ if(passwdp) { psep = strchr(login, ':'); @@ -2776,12 +2796,14 @@ static CURLcode override_login(struct Curl_easy *data, /* for updated strings, we update them in the URL */ if(user_changed) { - uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0); + uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, + CURLU_URLENCODE); if(uc) return Curl_uc_to_curlcode(uc); } if(passwd_changed) { - uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0); + uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, + CURLU_URLENCODE); if(uc) return Curl_uc_to_curlcode(uc); } @@ -3040,7 +3062,14 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data, #ifdef USE_ALTSVC if(data->asi && !host && (port == -1) && - (conn->handler->protocol == CURLPROTO_HTTPS)) { + ((conn->handler->protocol == CURLPROTO_HTTPS) || +#ifdef CURLDEBUG + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_ALTSVC_HTTP") +#else + 0 +#endif + )) { /* no connect_to match, try alt-svc! */ enum alpnid srcalpnid; bool hit; @@ -3147,7 +3176,7 @@ static CURLcode resolve_server(struct Curl_easy *data, else { bool longpath = FALSE; hostaddr->addr = Curl_unix2addr(path, &longpath, - conn->abstract_unix_socket); + conn->bits.abstract_unix_socket); if(hostaddr->addr) hostaddr->inuse++; else { @@ -3165,6 +3194,7 @@ static CURLcode resolve_server(struct Curl_easy *data, } else #endif + if(!conn->bits.proxy) { struct hostname *connhost; if(conn->bits.conn_to_host) @@ -3193,10 +3223,11 @@ static CURLcode resolve_server(struct Curl_easy *data, else if(!hostaddr) { failf(data, "Couldn't resolve host '%s'", connhost->dispname); - result = CURLE_COULDNT_RESOLVE_HOST; + result = CURLE_COULDNT_RESOLVE_HOST; /* don't return yet, we need to clean up the timeout first */ } } +#ifndef CURL_DISABLE_PROXY else { /* This is a proxy that hasn't been resolved yet. */ @@ -3222,6 +3253,7 @@ static CURLcode resolve_server(struct Curl_easy *data, /* don't return yet, we need to clean up the timeout first */ } } +#endif DEBUGASSERT(conn->dns_entry == NULL); conn->dns_entry = hostaddr; } @@ -3237,16 +3269,17 @@ static CURLcode resolve_server(struct Curl_easy *data, static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { +#ifndef CURL_DISABLE_PROXY Curl_free_idnconverted_hostname(&old_conn->http_proxy.host); Curl_free_idnconverted_hostname(&old_conn->socks_proxy.host); free(old_conn->http_proxy.host.rawalloc); free(old_conn->socks_proxy.host.rawalloc); - + Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config); +#endif /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ Curl_free_primary_ssl_config(&old_conn->ssl_config); - Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config); conn->data = old_conn->data; @@ -3263,6 +3296,7 @@ static void reuse_conn(struct connectdata *old_conn, old_conn->passwd = NULL; } +#ifndef CURL_DISABLE_PROXY conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd; if(conn->bits.proxy_user_passwd) { /* use the new proxy user name and proxy password though */ @@ -3279,6 +3313,11 @@ static void reuse_conn(struct connectdata *old_conn, old_conn->http_proxy.passwd = NULL; old_conn->socks_proxy.passwd = NULL; } + Curl_safefree(old_conn->http_proxy.user); + Curl_safefree(old_conn->socks_proxy.user); + Curl_safefree(old_conn->http_proxy.passwd); + Curl_safefree(old_conn->socks_proxy.passwd); +#endif /* host can change, when doing keepalive with a proxy or if the case is different this time etc */ @@ -3306,10 +3345,6 @@ static void reuse_conn(struct connectdata *old_conn, Curl_safefree(old_conn->user); Curl_safefree(old_conn->passwd); Curl_safefree(old_conn->options); - Curl_safefree(old_conn->http_proxy.user); - Curl_safefree(old_conn->socks_proxy.user); - Curl_safefree(old_conn->http_proxy.passwd); - Curl_safefree(old_conn->socks_proxy.passwd); Curl_safefree(old_conn->localdev); Curl_llist_destroy(&old_conn->easyq, NULL); @@ -3394,7 +3429,7 @@ static CURLcode create_conn(struct Curl_easy *data, result = CURLE_OUT_OF_MEMORY; goto out; } - conn->abstract_unix_socket = data->set.abstract_unix_socket; + conn->bits.abstract_unix_socket = data->set.abstract_unix_socket; } #endif @@ -3404,7 +3439,6 @@ static CURLcode create_conn(struct Curl_easy *data, result = create_conn_helper_init_proxy(conn); if(result) goto out; -#endif /************************************************************* * If the protocol is using SSL and HTTP proxy is used, we set @@ -3412,6 +3446,7 @@ static CURLcode create_conn(struct Curl_easy *data, *************************************************************/ if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) conn->bits.tunnel_proxy = TRUE; +#endif /************************************************************* * Figure out the remote port number and fix it in the URL @@ -3450,6 +3485,7 @@ static CURLcode create_conn(struct Curl_easy *data, if(result) goto out; } +#ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy) { result = Curl_idnconvert_hostname(conn, &conn->http_proxy.host); if(result) @@ -3460,6 +3496,7 @@ static CURLcode create_conn(struct Curl_easy *data, if(result) goto out; } +#endif /************************************************************* * Check whether the host and the "connect to host" are equal. @@ -3478,6 +3515,7 @@ static CURLcode create_conn(struct Curl_easy *data, conn->bits.conn_to_port = FALSE; } +#ifndef CURL_DISABLE_PROXY /************************************************************* * If the "connect to" feature is used with an HTTP proxy, * we set the tunnel_proxy bit. @@ -3485,6 +3523,7 @@ static CURLcode create_conn(struct Curl_easy *data, if((conn->bits.conn_to_host || conn->bits.conn_to_port) && conn->bits.httpproxy) conn->bits.tunnel_proxy = TRUE; +#endif /************************************************************* * Setup internals depending on protocol. Needs to be done after @@ -3517,6 +3556,7 @@ static CURLcode create_conn(struct Curl_easy *data, if(!result) { conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ + Curl_attach_connnection(data, conn); result = Curl_conncache_add_conn(data->state.conn_cache, conn); if(result) goto out; @@ -3531,7 +3571,6 @@ static CURLcode create_conn(struct Curl_easy *data, (void)conn->handler->done(conn, result, FALSE); goto out; } - Curl_attach_connnection(data, conn); Curl_setup_transfer(data, -1, -1, FALSE, -1); } @@ -3552,49 +3591,59 @@ static CURLcode create_conn(struct Curl_easy *data, copies will be separately allocated. */ data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG]; - data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG]; - data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; - data->set.proxy_ssl.primary.random_file = - data->set.str[STRING_SSL_RANDOM_FILE]; data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; - data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; data->set.ssl.primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_ORIG]; - data->set.proxy_ssl.primary.cipher_list = - data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; data->set.ssl.primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_ORIG]; - data->set.proxy_ssl.primary.cipher_list13 = - data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; data->set.ssl.primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; + +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; + data->set.proxy_ssl.primary.random_file = + data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.proxy_ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; + data->set.proxy_ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; data->set.proxy_ssl.primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; - - data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; - data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; - data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; - data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; - data->set.ssl.key = data->set.str[STRING_KEY_ORIG]; data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; - data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG]; data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; - data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG]; data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; - data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG]; data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; + data->set.proxy_ssl.cert_blob = data->set.blobs[BLOB_CERT_PROXY]; + data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY]; +#endif + data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; + data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; + data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; + data->set.ssl.key = data->set.str[STRING_KEY_ORIG]; + data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG]; + data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG]; + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG]; #ifdef USE_TLS_SRP data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; - data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; #endif +#endif + + data->set.ssl.cert_blob = data->set.blobs[BLOB_CERT_ORIG]; + data->set.ssl.key_blob = data->set.blobs[BLOB_KEY_ORIG]; + data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG]; if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, &conn->ssl_config)) { @@ -3602,11 +3651,13 @@ static CURLcode create_conn(struct Curl_easy *data, goto out; } +#ifndef CURL_DISABLE_PROXY if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary, &conn->proxy_ssl_config)) { result = CURLE_OUT_OF_MEMORY; goto out; } +#endif prune_dead_connections(data); @@ -3644,12 +3695,17 @@ static CURLcode create_conn(struct Curl_easy *data, conn = conn_temp; *in_connect = conn; +#ifndef CURL_DISABLE_PROXY infof(data, "Re-using existing connection! (#%ld) with %s %s\n", conn->connection_id, conn->bits.proxy?"proxy":"host", conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : conn->http_proxy.host.name ? conn->http_proxy.host.dispname : - conn->host.dispname); + conn->host.dispname); +#else + infof(data, "Re-using existing connection! (#%ld) with host %s\n", + conn->connection_id, conn->host.dispname); +#endif } else { /* We have decided that we want a new connection. However, we may not @@ -3681,7 +3737,7 @@ static CURLcode create_conn(struct Curl_easy *data, /* The bundle is full. Extract the oldest connection. */ conn_candidate = Curl_conncache_extract_bundle(data, bundle); - Curl_conncache_unlock(data); + CONNCACHE_UNLOCK(data); if(conn_candidate) (void)Curl_disconnect(data, conn_candidate, @@ -3693,7 +3749,7 @@ static CURLcode create_conn(struct Curl_easy *data, } } else - Curl_conncache_unlock(data); + CONNCACHE_UNLOCK(data); } @@ -3727,6 +3783,8 @@ static CURLcode create_conn(struct Curl_easy *data, * This is a brand new connection, so let's store it in the connection * cache of ours! */ + Curl_attach_connnection(data, conn); + result = Curl_conncache_add_conn(data->state.conn_cache, conn); if(result) goto out; @@ -3778,10 +3836,12 @@ static CURLcode create_conn(struct Curl_easy *data, /* Strip trailing dots. resolve_server copied the name. */ strip_trailing_dot(&conn->host); +#ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy) strip_trailing_dot(&conn->http_proxy.host); if(conn->bits.socksproxy) strip_trailing_dot(&conn->socks_proxy.host); +#endif if(conn->bits.conn_to_host) strip_trailing_dot(&conn->conn_to_host); @@ -3812,22 +3872,23 @@ CURLcode Curl_setup_conn(struct connectdata *conn, } *protocol_done = FALSE; /* default to not done */ +#ifndef CURL_DISABLE_PROXY /* set proxy_connect_closed to false unconditionally already here since it is used strictly to provide extra information to a parent function in the case of proxy CONNECT failures and we must make sure we don't have it lingering set from a previous invoke */ conn->bits.proxy_connect_closed = FALSE; - +#endif /* * Set user-agent. Used for HTTP, but since we can attempt to tunnel * basically anything through a http proxy we can't limit this based on * protocol. */ if(data->set.str[STRING_USERAGENT]) { - Curl_safefree(conn->allocptr.uagent); - conn->allocptr.uagent = + Curl_safefree(data->state.aptr.uagent); + data->state.aptr.uagent = aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]); - if(!conn->allocptr.uagent) + if(!data->state.aptr.uagent) return CURLE_OUT_OF_MEMORY; } @@ -3881,7 +3942,7 @@ CURLcode Curl_connect(struct Curl_easy *data, result = create_conn(data, &conn, asyncp); if(!result) { - if(CONN_INUSE(conn)) + if(CONN_INUSE(conn) > 1) /* multiplexed */ *protocol_done = TRUE; else if(!*asyncp) { @@ -3898,11 +3959,10 @@ CURLcode Curl_connect(struct Curl_easy *data, else if(result && conn) { /* We're not allowed to return failure with memory left allocated in the connectdata struct, free those here */ + Curl_detach_connnection(data); + Curl_conncache_remove_conn(data, conn, TRUE); Curl_disconnect(data, conn, TRUE); } - else if(!result && !data->conn) - /* FILE: transfers already have the connection attached */ - Curl_attach_connnection(data, conn); return result; } @@ -3921,6 +3981,11 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) { struct SingleRequest *k = &data->req; + /* if this is a pushed stream, we need this: */ + CURLcode result = Curl_preconnect(data); + if(result) + return result; + if(conn) { conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */ @@ -3933,30 +3998,17 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) data->state.done = FALSE; /* *_done() is not called yet */ data->state.expect100header = FALSE; - if(data->set.opt_no_body) /* in HTTP lingo, no body means using the HEAD request... */ - data->set.httpreq = HTTPREQ_HEAD; - else if(HTTPREQ_HEAD == data->set.httpreq) - /* ... but if unset there really is no perfect method that is the - "opposite" of HEAD but in reality most people probably think GET - then. The important thing is that we can't let it remain HEAD if the - opt_no_body is set FALSE since then we'll behave wrong when getting - HTTP. */ - data->set.httpreq = HTTPREQ_GET; + data->state.httpreq = HTTPREQ_HEAD; k->start = Curl_now(); /* start time */ k->now = k->start; /* current time is now */ k->header = TRUE; /* assume header */ - k->bytecount = 0; - - k->buf = data->state.buffer; - k->hbufp = data->state.headerbuff; k->ignorebody = FALSE; Curl_speedinit(data); - Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h index 5000c51..1941dc6 100644 --- a/Utilities/cmcurl/lib/url.h +++ b/Utilities/cmcurl/lib/url.h @@ -47,7 +47,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn); CURLcode Curl_open(struct Curl_easy **curl); CURLcode Curl_init_userdefined(struct Curl_easy *data); -void Curl_freeset(struct Curl_easy * data); +void Curl_freeset(struct Curl_easy *data); CURLcode Curl_uc_to_curlcode(CURLUcode uc); CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */ CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect); @@ -77,6 +77,10 @@ void Curl_free_idnconverted_hostname(struct hostname *host); void Curl_verboseconnect(struct connectdata *conn); #endif +#ifdef CURL_DISABLE_PROXY +#define CONNECT_PROXY_SSL() FALSE +#else + #define CONNECT_PROXY_SSL()\ (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ !conn->bits.proxy_ssl_connected[sockindex]) @@ -88,5 +92,6 @@ void Curl_verboseconnect(struct connectdata *conn); #define CONNECT_SECONDARYSOCKET_PROXY_SSL()\ (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ !conn->bits.proxy_ssl_connected[SECONDARYSOCKET]) +#endif /* !CURL_DISABLE_PROXY */ #endif /* HEADER_CURL_URL_H */ diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c index 506e244..37937fb 100644 --- a/Utilities/cmcurl/lib/urlapi.c +++ b/Utilities/cmcurl/lib/urlapi.c @@ -606,7 +606,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) char dest[16]; /* fits a binary IPv6 address */ #endif const char *l = "0123456789abcdefABCDEF:."; - if(hlen < 5) /* '[::1]' is the shortest possible valid string */ + if(hlen < 4) /* '[::]' is the shortest possible valid string */ return CURLUE_MALFORMED_INPUT; hostname++; hlen -= 2; diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h index e1348cf..74b43ab 100644 --- a/Utilities/cmcurl/lib/urldata.h +++ b/Utilities/cmcurl/lib/urldata.h @@ -49,6 +49,7 @@ #define PORT_RTMPT PORT_HTTP #define PORT_RTMPS PORT_HTTPS #define PORT_GOPHER 70 +#define PORT_MQTT 1883 #define DICT_MATCH "/MATCH:" #define DICT_MATCH2 "/M:" @@ -80,7 +81,7 @@ */ #define RESP_TIMEOUT (120*1000) -/* Max string intput length is a precaution against abuse and to detect junk +/* Max string input length is a precaution against abuse and to detect junk input easier and better. */ #define CURL_MAX_INPUT_LENGTH 8000000 @@ -103,6 +104,7 @@ #include "hostip.h" #include "hash.h" #include "splay.h" +#include "dynbuf.h" /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -128,6 +130,7 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */ #include "http.h" #include "rtsp.h" #include "smb.h" +#include "mqtt.h" #include "wildcard.h" #include "multihandle.h" #include "quic.h" @@ -150,10 +153,6 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */ #include <libssh2_sftp.h> #endif /* HAVE_LIBSSH2_H */ -/* Initial size of the buffer to store headers in, it'll be enlarged in case - of need. */ -#define HEADERSIZE 256 - #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU #define GOOD_EASY_HANDLE(x) \ ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) @@ -241,11 +240,14 @@ struct ssl_config_data { long certverifyresult; /* result from the certificate verification */ char *CRLfile; /* CRL to check certificate revocation */ char *issuercert;/* optional issuer certificate filename */ + struct curl_blob *issuercert_blob; curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ void *fsslctxp; /* parameter for call back */ char *cert; /* client certificate file name */ + struct curl_blob *cert_blob; char *cert_type; /* format for certificate (default: PEM)*/ char *key; /* private key file name */ + struct curl_blob *key_blob; char *key_type; /* format for private key (default: PEM) */ char *key_passwd; /* plain text private key password */ #ifdef USE_TLS_SRP @@ -258,6 +260,9 @@ struct ssl_config_data { BIT(enable_beast); /* allow this flaw for interoperability's sake*/ BIT(no_revoke); /* disable SSL certificate revocation checks */ BIT(no_partialchain); /* don't accept partial certificate chains */ + BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation + list errors */ + BIT(native_ca_store); /* use the native ca store of operating system */ }; struct ssl_general_config { @@ -415,11 +420,23 @@ struct negotiatedata { * Boolean values that concerns this connection. */ struct ConnectBits { - /* always modify bits.close with the connclose() and connkeep() macros! */ - bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy - is complete */ bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set the first time on the first connect function call */ +#ifndef CURL_DISABLE_PROXY + bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy + is complete */ + BIT(httpproxy); /* if set, this transfer is done through a http proxy */ + BIT(socksproxy); /* if set, this transfer is done through a socks proxy */ + BIT(proxy_user_passwd); /* user+password for the proxy? */ + BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy. + This is implicit when SSL-protocols are used through + proxies, but can also be enabled explicitly by + apps */ + BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection + in a CONNECT request with auth, so that + libcurl should reconnect and continue. */ +#endif + /* always modify bits.close with the connclose() and connkeep() macros! */ BIT(close); /* if set, we close the connection after this request */ BIT(reuse); /* if set, this is a re-used connection */ BIT(altused); /* this is an alt-svc "redirect" */ @@ -428,10 +445,7 @@ struct ConnectBits { BIT(conn_to_port); /* if set, this connection has a "connect to port" that overrides the port in the URL (remote port) */ BIT(proxy); /* if set, this transfer is done through a proxy - any type */ - BIT(httpproxy); /* if set, this transfer is done through a http proxy */ - BIT(socksproxy); /* if set, this transfer is done through a socks proxy */ BIT(user_passwd); /* do we use user+password for this connection? */ - BIT(proxy_user_passwd); /* user+password for the proxy? */ BIT(ipv6_ip); /* we communicate with a remote site specified with pure IPv6 IP address */ BIT(ipv6); /* we communicate with a site using an IPv6 address */ @@ -441,10 +455,6 @@ struct ConnectBits { the TCP layer connect */ BIT(retry); /* this connection is about to get closed and then re-attempted at another connection. */ - BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy. - This is implicit when SSL-protocols are used through - proxies, but can also be enabled explicitly by - apps */ BIT(authneg); /* TRUE when the auth phase has started, which means that we are creating a request with an auth header, but it is not the final request in the auth @@ -463,20 +473,22 @@ struct ConnectBits { BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */ #endif BIT(netrc); /* name+password provided by netrc */ - BIT(userpwd_in_url); /* name+password found in url */ - BIT(stream_was_rewound); /* The stream was rewound after a request read - past the end of its response byte boundary */ - BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection - in a CONNECT request with auth, so that - libcurl should reconnect and continue. */ BIT(bound); /* set true if bind() has already been done on this socket/ connection */ - BIT(type_set); /* type= was used in the URL */ BIT(multiplex); /* connection is multiplexed */ BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(tls_enable_npn); /* TLS NPN extension? */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ BIT(connect_only); + BIT(doh); +#ifdef USE_UNIX_SOCKETS + BIT(abstract_unix_socket); +#endif + BIT(tls_upgraded); + BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with + accept() */ + BIT(parallel_connect); /* set TRUE when a parallel connect attempt has + started (happy eyeballs) */ }; struct hostname { @@ -554,18 +566,13 @@ enum doh_slots { DOH_PROBE_SLOTS }; -struct dohresponse { - unsigned char *memory; - size_t size; -}; - /* one of these for each DoH request */ struct dnsprobe { CURL *easy; int dnstype; unsigned char dohbuffer[512]; size_t dohlen; - struct dohresponse serverdoh; + struct dynbuf serverdoh; }; struct dohdata { @@ -609,12 +616,7 @@ struct SingleRequest { written as body */ int headerline; /* counts header lines to better track the first one */ - char *hbufp; /* points at *end* of header line */ - size_t hbuflen; char *str; /* within buf */ - char *str_start; /* within buf */ - char *end_ptr; /* within buf */ - char *p; /* within headerbuff */ curl_off_t offset; /* possible resume offset read from the Content-Range: header */ int httpcode; /* error code from the 'HTTP/1.? XXX' or @@ -623,11 +625,10 @@ struct SingleRequest { enum expect100 exp100; /* expect 100 continue state */ enum upgrade101 upgr101; /* 101 upgrade state */ - struct contenc_writer_s *writer_stack; /* Content unencoding stack. */ - /* See sec 3.5, RFC2616. */ + /* Content unencoding stack. See sec 3.5, RFC2616. */ + struct contenc_writer *writer_stack; time_t timeofdoc; long bodywrites; - char *buf; int keepon; char *location; /* This points to an allocated version of the Location: header data */ @@ -795,15 +796,10 @@ struct proxy_info { char *passwd; /* proxy password string, allocated */ }; -#define CONNECT_BUFFER_SIZE 16384 - /* struct for HTTP CONNECT state data */ struct http_connect_state { - char connect_buffer[CONNECT_BUFFER_SIZE]; - int perline; /* count bytes per line */ + struct dynbuf rcvbuf; int keepon; - char *line_start; - char *ptr; /* where to store more data */ curl_off_t cl; /* size of content to read and ignore */ enum { TUNNEL_INIT, /* init/default/no tunnel state */ @@ -883,15 +879,15 @@ struct connectdata { /* 'dns_entry' is the particular host we use. This points to an entry in the DNS cache and it will not get pruned while locked. It gets unlocked in - Curl_done(). This entry will be NULL if the connection is re-used as then + multi_done(). This entry will be NULL if the connection is re-used as then there is no name resolve done. */ struct Curl_dns_entry *dns_entry; /* 'ip_addr' is the particular IP we connected to. It points to a struct within the DNS cache, so this pointer is only valid as long as the DNS - cache entry remains locked. It gets unlocked in Curl_done() */ - Curl_addrinfo *ip_addr; - Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */ + cache entry remains locked. It gets unlocked in multi_done() */ + struct Curl_addrinfo *ip_addr; + struct Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */ /* 'ip_addr_str' is the ip_addr data as a human readable string. It remains available as long as the connection does, which is longer than @@ -916,10 +912,10 @@ struct connectdata { char *secondaryhostname; /* secondary socket host name (ftp) */ struct hostname conn_to_host; /* the host to connect to. valid only if bits.conn_to_host is set */ - +#ifndef CURL_DISABLE_PROXY struct proxy_info socks_proxy; struct proxy_info http_proxy; - +#endif long port; /* which port to use locally */ int remote_port; /* the remote port, not the proxy port! */ int conn_to_port; /* the remote port to connect to. valid only if @@ -959,6 +955,7 @@ struct connectdata { curl_socket_t sock[2]; /* two sockets, the second is used for the data transfer when doing FTP */ curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */ + int tempfamily[2]; /* family used for the temp sockets */ Curl_recv *recv[2]; Curl_send *send[2]; @@ -966,12 +963,16 @@ struct connectdata { struct postponed_data postponed[2]; /* two buffers for two sockets */ #endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ +#ifndef CURL_DISABLE_PROXY struct ssl_connect_data proxy_ssl[2]; /* this is for proxy ssl-stuff */ +#endif #ifdef USE_SSL void *ssl_extra; /* separately allocated backend-specific data */ #endif struct ssl_primary_config ssl_config; +#ifndef CURL_DISABLE_PROXY struct ssl_primary_config proxy_ssl_config; +#endif struct ConnectBits bits; /* various state-flags for this connection */ /* connecttime: when connect() is called on the current IP address. Used to @@ -980,8 +981,10 @@ struct connectdata { struct curltime connecttime; /* The two fields below get set in Curl_connecthost */ int num_addr; /* number of addresses to try to connect to */ - timediff_t timeoutms_per_addr; /* how long time in milliseconds to spend on - trying to connect to each IP address */ + + /* how long time in milliseconds to spend on trying to connect to each IP + address, per family */ + timediff_t timeoutms_per_addr[2]; const struct Curl_handler *handler; /* Connection's protocol handler */ const struct Curl_handler *given; /* The protocol first given */ @@ -1002,21 +1005,6 @@ struct connectdata { well be the same we read from. CURL_SOCKET_BAD disables */ - /** Dynamically allocated strings, MUST be freed before this **/ - /** struct is killed. **/ - struct dynamically_allocated_data { - char *proxyuserpwd; - char *uagent; - char *accept_encoding; - char *userpwd; - char *rangeline; - char *ref; - char *host; - char *cookiehost; - char *rtsp_transport; - char *te; /* TE: request header */ - } allocptr; - #ifdef HAVE_GSSAPI BIT(sec_complete); /* if Kerberos is enabled for this connection */ enum protection_level command_prot; @@ -1063,10 +1051,8 @@ struct connectdata { /* data used for the asynch name resolve callback */ struct Curl_async async; - /* These three are used for chunked-encoding trailer support */ - char *trailer; /* allocated buffer to store trailer in */ - int trlMax; /* allocated buffer size */ - int trlPos; /* index of where to store data */ + /* for chunked-encoded trailer */ + struct dynbuf trailer; union { struct ftp_conn ftpc; @@ -1080,6 +1066,7 @@ struct connectdata { struct smb_conn smbc; void *rtmp; struct ldapconninfo *ldapc; + struct mqtt_conn mqtt; } proto; int cselect_bits; /* bitmask of socket events */ @@ -1100,21 +1087,10 @@ struct connectdata { struct http_connect_state *connect_state; /* for HTTP CONNECT */ struct connectbundle *bundle; /* The bundle we are member of */ int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */ - + int retrycount; /* number of retries on a new connection */ #ifdef USE_UNIX_SOCKETS char *unix_domain_socket; - BIT(abstract_unix_socket); #endif - BIT(tls_upgraded); - /* the two following *_inuse fields are only flags, not counters in any way. - If TRUE it means the channel is in use, and if FALSE it means the channel - is up for grabs by one. */ - BIT(readchannel_inuse); /* whether the read channel is in use by an easy - handle */ - BIT(writechannel_inuse); /* whether the write channel is in use by an easy - handle */ - BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with - accept() */ }; /* The end of connectdata. */ @@ -1236,17 +1212,6 @@ typedef enum { RTSPREQ_LAST /* last in list */ } Curl_RtspReq; -/* - * Values that are generated, temporary or calculated internally for a - * "session handle" must be defined within the 'struct UrlState'. This struct - * will be used within the Curl_easy struct. When the 'Curl_easy' - * struct is cloned, this data MUST NOT be copied. - * - * Remember that any "state" information goes globally for the curl handle. - * Session-data MUST be put in the connectdata struct and here. */ -#define MAX_CURL_USER_LENGTH 256 -#define MAX_CURL_PASSWORD_LENGTH 256 - struct auth { unsigned long want; /* Bitmask set to the authentication methods wanted by app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ @@ -1272,9 +1237,7 @@ struct Curl_http2_dep { * BODY). */ struct tempbuf { - char *buf; /* allocated buffer to keep data in when a write callback - returns to make the connection paused */ - size_t len; /* size of the 'tempwrite' allocated buffer */ + struct dynbuf b; int type; /* type of the 'tempwrite' buffer as a bitmask that is used with Curl_client_write() */ }; @@ -1284,7 +1247,8 @@ typedef enum { EXPIRE_100_TIMEOUT, EXPIRE_ASYNC_NAME, EXPIRE_CONNECTTIMEOUT, - EXPIRE_DNS_PER_NAME, + EXPIRE_DNS_PER_NAME, /* family1 */ + EXPIRE_DNS_PER_NAME2, /* family2 */ EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */ EXPIRE_HAPPY_EYEBALLS, EXPIRE_MULTI_PENDING, @@ -1327,7 +1291,6 @@ struct urlpieces { }; struct UrlState { - /* Points to the connection cache */ struct conncache *conn_cache; @@ -1335,9 +1298,7 @@ struct UrlState { struct curltime keeps_speed; /* for the progress meter really */ struct connectdata *lastconnect; /* The last connection, NULL if undefined */ - - char *headerbuff; /* allocated buffer to store headers in */ - size_t headersize; /* size of the allocation */ + struct dynbuf headerb; /* buffer to store headers in */ char *buffer; /* download buffer */ char *ulbuf; /* allocated upload buffer or NULL */ @@ -1415,13 +1376,30 @@ struct UrlState { int stream_weight; CURLU *uh; /* URL handle for the current parsed URL */ struct urlpieces up; + Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ #ifndef CURL_DISABLE_HTTP size_t trailers_bytes_sent; - Curl_send_buffer *trailers_buf; /* a buffer containing the compiled trailing - headers */ + struct dynbuf trailers_buf; /* a buffer containing the compiled trailing + headers */ #endif trailers_state trailers_state; /* whether we are sending trailers and what stage are we at */ + + /* Dynamically allocated strings, MUST be freed before this struct is + killed. */ + struct dynamically_allocated_data { + char *proxyuserpwd; + char *uagent; + char *accept_encoding; + char *userpwd; + char *rangeline; + char *ref; + char *host; + char *cookiehost; + char *rtsp_transport; + char *te; /* TE: request header */ + } aptr; + #ifdef CURLDEBUG BIT(conncache_lock); #endif @@ -1579,6 +1557,11 @@ enum dupstring { STRING_TEMP_URL, /* temp URL storage for proxy use */ + STRING_DNS_SERVERS, + STRING_DNS_INTERFACE, + STRING_DNS_LOCAL_IP4, + STRING_DNS_LOCAL_IP6, + /* -- end of zero-terminated strings -- */ STRING_LASTZEROTERMINATED, @@ -1587,9 +1570,20 @@ enum dupstring { STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ + STRING_LAST /* not used, just an end-of-list marker */ }; +enum dupblob { + BLOB_CERT_ORIG, + BLOB_CERT_PROXY, + BLOB_KEY_ORIG, + BLOB_KEY_PROXY, + BLOB_SSL_ISSUERCERT_ORIG, + BLOB_SSL_ISSUERCERT_PROXY, + BLOB_LAST +}; + /* callback that gets called when this easy handle is completed within a multi handle. Only used for internally created transfers, like for example DoH. */ @@ -1687,11 +1681,13 @@ struct UserDefined { the hostname and port to connect to */ curl_TimeCond timecondition; /* kind of time/date comparison */ time_t timevalue; /* what time to compare with */ - Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ + Curl_HttpReq method; /* what kind of HTTP request (if any) is this */ long httpversion; /* when non-zero, a specific HTTP version requested to be used in the library's request(s) */ struct ssl_config_data ssl; /* user defined SSL stuff */ +#ifndef CURL_DISABLE_PROXY struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ +#endif struct ssl_general_config general_ssl; /* general user defined SSL stuff */ curl_proxytype proxytype; /* what kind of proxy that is in use */ long dns_cache_timeout; /* DNS cache timeout */ @@ -1721,6 +1717,7 @@ struct UserDefined { long new_directory_perms; /* Permissions to use when creating remote dirs */ long ssh_auth_types; /* allowed SSH auth types */ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ + struct curl_blob *blobs[BLOB_LAST]; unsigned int scope_id; /* Scope id for IPv6 */ long allowed_protocols; long redir_protocols; diff --git a/Utilities/cmcurl/lib/vauth/cleartext.c b/Utilities/cmcurl/lib/vauth/cleartext.c index 6f452c1..3a5c943 100644 --- a/Utilities/cmcurl/lib/vauth/cleartext.c +++ b/Utilities/cmcurl/lib/vauth/cleartext.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -81,7 +81,8 @@ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, plen = strlen(passwd); /* Compute binary message length. Check for overflows. */ - if(((zlen + clen) > SIZE_T_MAX/4) || (plen > (SIZE_T_MAX/2 - 2))) + if((zlen > SIZE_T_MAX/4) || (clen > SIZE_T_MAX/4) || + (plen > (SIZE_T_MAX/2 - 2))) return CURLE_OUT_OF_MEMORY; plainlen = zlen + clen + plen + 2; diff --git a/Utilities/cmcurl/lib/vauth/cram.c b/Utilities/cmcurl/lib/vauth/cram.c index 04438fa..717d7f0 100644 --- a/Utilities/cmcurl/lib/vauth/cram.c +++ b/Utilities/cmcurl/lib/vauth/cram.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -96,7 +96,7 @@ CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, { CURLcode result = CURLE_OK; size_t chlglen = 0; - HMAC_context *ctxt; + struct HMAC_context *ctxt; unsigned char digest[MD5_DIGEST_LEN]; char *response; diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c index a883570..b9210a8 100644 --- a/Utilities/cmcurl/lib/vauth/digest.c +++ b/Utilities/cmcurl/lib/vauth/digest.c @@ -358,7 +358,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, char **outptr, size_t *outlen) { size_t i; - MD5_context *ctxt; + struct MD5_context *ctxt; char *response = NULL; unsigned char digest[MD5_DIGEST_LEN]; char HA1_hex[2 * MD5_DIGEST_LEN + 1]; diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c index a109056..4998306 100644 --- a/Utilities/cmcurl/lib/vauth/digest_sspi.c +++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>. - * Copyright (C) 2015 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2015 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -134,7 +134,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, if(status != SEC_E_OK) { free(input_token); - return CURLE_NOT_BUILT_IN; + failf(data, "SSPI: couldn't get auth info\n"); + return CURLE_AUTH_ERROR; } token_max = SecurityPackage->cbMaxToken; @@ -288,13 +289,13 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, if(strcasecompare(value, "realm")) { /* Setup identity's domain and length */ - domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); + domain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *) content); if(!domain.tchar_ptr) return CURLE_OUT_OF_MEMORY; dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); if(!dup_domain.tchar_ptr) { - Curl_unicodefree(domain.tchar_ptr); + curlx_unicodefree(domain.tchar_ptr); return CURLE_OUT_OF_MEMORY; } @@ -303,7 +304,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); dup_domain.tchar_ptr = NULL; - Curl_unicodefree(domain.tchar_ptr); + curlx_unicodefree(domain.tchar_ptr); } else { /* Unknown specifier, ignore it! */ @@ -431,8 +432,10 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, /* Query the security package for DigestSSP */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; + if(status != SEC_E_OK) { + failf(data, "SSPI: couldn't get auth info\n"); + return CURLE_AUTH_ERROR; + } token_max = SecurityPackage->cbMaxToken; @@ -580,7 +583,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, resp_buf.pvBuffer = output_token; resp_buf.cbBuffer = curlx_uztoul(token_max); - spn = Curl_convert_UTF8_to_tchar((char *) uripath); + spn = curlx_convert_UTF8_to_tchar((char *) uripath); if(!spn) { s_pSecFn->FreeCredentialsHandle(&credentials); @@ -602,7 +605,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, &chlg_desc, 0, digest->http_context, &resp_desc, &attrs, &expiry); - Curl_unicodefree(spn); + curlx_unicodefree(spn); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c index 98041d9..1fb6257 100644 --- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c +++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014 - 2019, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2014 - 2020, Steve Holme, <steve_holme@hotmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -125,7 +125,8 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, TEXT(SP_NAME_KERBEROS), &SecurityPackage); if(status != SEC_E_OK) { - return CURLE_NOT_BUILT_IN; + failf(data, "SSPI: couldn't get auth info\n"); + return CURLE_AUTH_ERROR; } krb5->token_max = SecurityPackage->cbMaxToken; @@ -395,7 +396,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; /* Convert the user name to UTF8 when operating with Unicode */ - user_name = Curl_convert_tchar_to_UTF8(names.sUserName); + user_name = curlx_convert_tchar_to_UTF8(names.sUserName); if(!user_name) { free(trailer); @@ -407,7 +408,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, message = malloc(messagelen); if(!message) { free(trailer); - Curl_unicodefree(user_name); + curlx_unicodefree(user_name); return CURLE_OUT_OF_MEMORY; } @@ -420,7 +421,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, outdata = htonl(max_size) | sec_layer; memcpy(message, &outdata, sizeof(outdata)); strcpy((char *) message + sizeof(outdata), user_name); - Curl_unicodefree(user_name); + curlx_unicodefree(user_name); /* Allocate the padding */ padding = malloc(sizes.cbBlockSize); diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c index 8f91038..3b46e1a 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm.c +++ b/Utilities/cmcurl/lib/vauth/ntlm.c @@ -600,11 +600,14 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, #endif #if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION) + +#define CURL_MD5_DIGEST_LENGTH 16 /* fixed size */ + /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) { unsigned char ntbuffer[0x18]; unsigned char tmp[0x18]; - unsigned char md5sum[MD5_DIGEST_LENGTH]; + unsigned char md5sum[CURL_MD5_DIGEST_LENGTH]; unsigned char entropy[8]; /* Need to create 8 bytes random data */ diff --git a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c index cd6cb79..84ea51d 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c +++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -105,8 +105,10 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, /* Query the security package for NTLM */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; + if(status != SEC_E_OK) { + failf(data, "SSPI: couldn't get auth info\n"); + return CURLE_AUTH_ERROR; + } ntlm->token_max = SecurityPackage->cbMaxToken; diff --git a/Utilities/cmcurl/lib/vauth/spnego_sspi.c b/Utilities/cmcurl/lib/vauth/spnego_sspi.c index b9c2cf7..194f250 100644 --- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c +++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -129,8 +129,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NEGOTIATE), &SecurityPackage); - if(nego->status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; + if(nego->status != SEC_E_OK) { + failf(data, "SSPI: couldn't get auth info\n"); + return CURLE_AUTH_ERROR; + } nego->token_max = SecurityPackage->cbMaxToken; diff --git a/Utilities/cmcurl/lib/vauth/vauth.c b/Utilities/cmcurl/lib/vauth/vauth.c index a9c5c9c..d98e66c 100644 --- a/Utilities/cmcurl/lib/vauth/vauth.c +++ b/Utilities/cmcurl/lib/vauth/vauth.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014 - 2019, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2014 - 2020, Steve Holme, <steve_holme@hotmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -89,7 +89,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, } /* Allocate our TCHAR based SPN */ - tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); + tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn); if(!tchar_spn) { free(utf8_spn); @@ -97,7 +97,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, } /* Release the UTF8 variant when operating with Unicode */ - Curl_unicodefree(utf8_spn); + curlx_unicodefree(utf8_spn); /* Return our newly allocated SPN */ return tchar_spn; diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c index 77aca7c..14e5096 100644 --- a/Utilities/cmcurl/lib/version.c +++ b/Utilities/cmcurl/lib/version.c @@ -66,16 +66,6 @@ #include <brotli/decode.h> #endif -void Curl_version_init(void); - -/* For thread safety purposes this function is called by global_init so that - the static data in both version functions is initialized. */ -void Curl_version_init(void) -{ - curl_version(); - curl_version_info(CURLVERSION_NOW); -} - #ifdef HAVE_BROTLI static size_t brotli_version(char *buf, size_t bufsz) { @@ -88,95 +78,118 @@ static size_t brotli_version(char *buf, size_t bufsz) } #endif +/* + * curl_version() returns a pointer to a static buffer. + * + * It is implemented to work multi-threaded by making sure repeated invokes + * generate the exact same string and never write any temporary data like + * zeros in the data. + */ + +#define VERSION_PARTS 14 /* number of substrings we can concatenate */ + char *curl_version(void) { - static bool initialized; - static char version[250]; - char *ptr = version; - size_t len; - size_t left = sizeof(version); - - if(initialized) - return version; - - strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION); - len = strlen(ptr); - left -= len; - ptr += len; - - len = Curl_ssl_version(ptr + 1, left - 1); - - if(len > 0) { - *ptr = ' '; - left -= ++len; - ptr += len; + static char out[300]; + char *outp; + size_t outlen; + const char *src[VERSION_PARTS]; +#ifdef USE_SSL + char ssl_version[200]; +#endif +#ifdef HAVE_LIBZ + char z_version[40]; +#endif +#ifdef HAVE_BROTLI + char br_version[40] = "brotli/"; +#endif +#ifdef USE_ARES + char cares_version[40]; +#endif +#if defined(USE_LIBIDN2) + char idn_version[40]; +#endif +#ifdef USE_LIBPSL + char psl_version[40]; +#endif +#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) + char iconv_version[40]="iconv"; +#endif +#ifdef USE_SSH + char ssh_version[40]; +#endif +#ifdef USE_NGHTTP2 + char h2_version[40]; +#endif +#ifdef ENABLE_QUIC + char h3_version[40]; +#endif +#ifdef USE_LIBRTMP + char rtmp_version[40]; +#endif + int i = 0; + int j; + +#ifdef DEBUGBUILD + /* Override version string when environment variable CURL_VERSION is set */ + const char *debugversion = getenv("CURL_VERSION"); + if(debugversion) { + strncpy(out, debugversion, sizeof(out)-1); + out[sizeof(out)-1] = '\0'; + return out; } +#endif + src[i++] = LIBCURL_NAME "/" LIBCURL_VERSION; +#ifdef USE_SSL + Curl_ssl_version(ssl_version, sizeof(ssl_version)); + src[i++] = ssl_version; +#endif #ifdef HAVE_LIBZ - len = msnprintf(ptr, left, " zlib/%s", zlibVersion()); - left -= len; - ptr += len; + msnprintf(z_version, sizeof(z_version), "zlib/%s", zlibVersion()); + src[i++] = z_version; #endif #ifdef HAVE_BROTLI - len = msnprintf(ptr, left, "%s", " brotli/"); - left -= len; - ptr += len; - len = brotli_version(ptr, left); - left -= len; - ptr += len; + brotli_version(&br_version[7], sizeof(br_version) - 7); + src[i++] = br_version; #endif #ifdef USE_ARES - /* this function is only present in c-ares, not in the original ares */ - len = msnprintf(ptr, left, " c-ares/%s", ares_version(NULL)); - left -= len; - ptr += len; + msnprintf(cares_version, sizeof(cares_version), + "c-ares/%s", ares_version(NULL)); + src[i++] = cares_version; #endif #ifdef USE_LIBIDN2 - if(idn2_check_version(IDN2_VERSION)) { - len = msnprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); - left -= len; - ptr += len; - } + msnprintf(idn_version, sizeof(idn_version), + "libidn2/%s", idn2_check_version(NULL)); + src[i++] = idn_version; +#elif defined(USE_WIN32_IDN) + src[i++] = (char *)"WinIDN"; #endif + #ifdef USE_LIBPSL - len = msnprintf(ptr, left, " libpsl/%s", psl_get_version()); - left -= len; - ptr += len; -#endif -#ifdef USE_WIN32_IDN - len = msnprintf(ptr, left, " WinIDN"); - left -= len; - ptr += len; + msnprintf(psl_version, sizeof(psl_version), "libpsl/%s", psl_get_version()); + src[i++] = psl_version; #endif #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #ifdef _LIBICONV_VERSION - len = msnprintf(ptr, left, " iconv/%d.%d", - _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); + msnprintf(iconv_version, sizeof(iconv_version), "iconv/%d.%d", + _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); #else - /* version unknown */ - len = msnprintf(ptr, left, " iconv"); + /* version unknown, let the default stand */ #endif /* _LIBICONV_VERSION */ - left -= len; - ptr += len; + src[i++] = iconv_version; #endif #ifdef USE_SSH - if(left) { - *ptr++=' '; - left--; - } - len = Curl_ssh_version(ptr, left); - left -= len; - ptr += len; + Curl_ssh_version(ssh_version, sizeof(ssh_version)); + src[i++] = ssh_version; #endif #ifdef USE_NGHTTP2 - len = Curl_http2_ver(ptr, left); - left -= len; - ptr += len; + Curl_http2_ver(h2_version, sizeof(h2_version)); + src[i++] = h2_version; #endif #ifdef ENABLE_QUIC - len = Curl_quic_ver(ptr, left); - left -= len; - ptr += len; + Curl_quic_ver(h3_version, sizeof(h3_version)); + src[i++] = h3_version; #endif #ifdef USE_LIBRTMP { @@ -188,27 +201,34 @@ char *curl_version(void) else suff[0] = '\0'; - msnprintf(ptr, left, " librtmp/%d.%d%s", + msnprintf(rtmp_version, sizeof(rtmp_version), "librtmp/%d.%d%s", RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, suff); -/* - If another lib version is added below this one, this code would - also have to do: - - len = what msnprintf() returned - - left -= len; - ptr += len; -*/ + src[i++] = rtmp_version; } #endif - /* Silent scan-build even if librtmp is not enabled. */ - (void) left; - (void) ptr; + DEBUGASSERT(i <= VERSION_PARTS); - initialized = true; - return version; + outp = &out[0]; + outlen = sizeof(out); + for(j = 0; j < i; j++) { + size_t n = strlen(src[j]); + /* we need room for a space, the string and the final zero */ + if(outlen <= (n + 2)) + break; + if(j) { + /* prepend a space if not the first */ + *outp++ = ' '; + outlen--; + } + memcpy(outp, src[j], n); + outp += n; + outlen -= n; + } + *outp = 0; + + return out; } /* data for curl_version_info @@ -253,6 +273,9 @@ static const char * const protocols[] = { "ldaps", #endif #endif +#ifdef CURL_ENABLE_MQTT + "mqtt", +#endif #ifndef CURL_DISABLE_POP3 "pop3", #endif @@ -369,9 +392,6 @@ static curl_version_info_data version_info = { #if defined(USE_ALTSVC) | CURL_VERSION_ALTSVC #endif -#ifdef USE_ESNI - | CURL_VERSION_ESNI -#endif , NULL, /* ssl_version */ 0, /* ssl_version_num, this is kept at zero */ @@ -386,12 +406,21 @@ static curl_version_info_data version_info = { NULL, /* brotli version */ 0, /* nghttp2 version number */ NULL, /* nghttp2 version string */ - NULL /* quic library string */ + NULL, /* quic library string */ +#ifdef CURL_CA_BUNDLE + CURL_CA_BUNDLE, /* cainfo */ +#else + NULL, +#endif +#ifdef CURL_CA_PATH + CURL_CA_PATH /* capath */ +#else + NULL +#endif }; curl_version_info_data *curl_version_info(CURLversion stamp) { - static bool initialized; #if defined(USE_SSH) static char ssh_buffer[80]; #endif @@ -406,9 +435,6 @@ curl_version_info_data *curl_version_info(CURLversion stamp) static char brotli_buffer[80]; #endif - if(initialized) - return &version_info; - #ifdef USE_SSL Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); version_info.ssl_version = ssl_buffer; @@ -476,7 +502,5 @@ curl_version_info_data *curl_version_info(CURLversion stamp) #endif (void)stamp; /* avoid compiler warnings, we don't use this */ - - initialized = true; return &version_info; } diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.c b/Utilities/cmcurl/lib/vquic/ngtcp2.c index 0788404..e552823 100644 --- a/Utilities/cmcurl/lib/vquic/ngtcp2.c +++ b/Utilities/cmcurl/lib/vquic/ngtcp2.c @@ -26,7 +26,9 @@ #include <ngtcp2/ngtcp2.h> #include <ngtcp2/ngtcp2_crypto.h> #include <nghttp3/nghttp3.h> +#ifdef USE_OPENSSL #include <openssl/err.h> +#endif #include "urldata.h" #include "sendf.h" #include "strdup.h" @@ -36,6 +38,9 @@ #include "strcase.h" #include "connect.h" #include "strerror.h" +#include "dynbuf.h" +#include "vquic.h" +#include "vtls/keylog.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -69,10 +74,18 @@ struct h3out { #define QUIC_MAX_STREAMS (256*1024) #define QUIC_MAX_DATA (1*1024*1024) #define QUIC_IDLE_TIMEOUT 60000 /* milliseconds */ + +#ifdef USE_OPENSSL #define QUIC_CIPHERS \ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" #define QUIC_GROUPS "P-256:X25519:P-384:P-521" +#elif defined(USE_GNUTLS) +#define QUIC_PRIORITY \ + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \ + "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \ + "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1" +#endif static CURLcode ng_process_ingress(struct connectdata *conn, curl_socket_t sockfd, @@ -101,6 +114,7 @@ static void quic_printf(void *user_data, const char *fmt, ...) } #endif +#ifdef USE_OPENSSL static ngtcp2_crypto_level quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level) { @@ -117,22 +131,43 @@ quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level) assert(0); } } - -static int setup_initial_crypto_context(struct quicsocket *qs) +#elif defined(USE_GNUTLS) +static ngtcp2_crypto_level +quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level) { - const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(qs->qconn); + switch(gtls_level) { + case GNUTLS_ENCRYPTION_LEVEL_INITIAL: + return NGTCP2_CRYPTO_LEVEL_INITIAL; + case GNUTLS_ENCRYPTION_LEVEL_EARLY: + return NGTCP2_CRYPTO_LEVEL_EARLY; + case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE: + return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + case GNUTLS_ENCRYPTION_LEVEL_APPLICATION: + return NGTCP2_CRYPTO_LEVEL_APP; + default: + assert(0); + } +} +#endif - if(ngtcp2_crypto_derive_and_install_initial_key( - qs->qconn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dcid, - NGTCP2_CRYPTO_SIDE_CLIENT) != 0) - return -1; +static void qlog_callback(void *user_data, const void *data, size_t datalen) +{ + struct quicsocket *qs = (struct quicsocket *)user_data; + if(qs->qlogfd != -1) { + ssize_t rc = write(qs->qlogfd, data, datalen); + if(rc == -1) { + /* on write error, stop further write attempts */ + close(qs->qlogfd); + qs->qlogfd = -1; + } + } - return 0; } -static void quic_settings(ngtcp2_settings *s, +static void quic_settings(struct quicsocket *qs, uint64_t stream_buffer_size) { + ngtcp2_settings *s = &qs->settings; ngtcp2_settings_default(s); #ifdef DEBUG_NGTCP2 s->log_printf = quic_printf; @@ -147,47 +182,41 @@ static void quic_settings(ngtcp2_settings *s, s->transport_params.initial_max_streams_bidi = 1; s->transport_params.initial_max_streams_uni = 3; s->transport_params.max_idle_timeout = QUIC_IDLE_TIMEOUT; + if(qs->qlogfd != -1) { + s->qlog.write = qlog_callback; + } } -static FILE *keylog_file; /* not thread-safe */ +#ifdef USE_OPENSSL static void keylog_callback(const SSL *ssl, const char *line) { (void)ssl; - fputs(line, keylog_file); - fputc('\n', keylog_file); - fflush(keylog_file); + Curl_tls_keylog_write_line(line); } - -static int init_ngh3_conn(struct quicsocket *qs); - -static int quic_set_encryption_secrets(SSL *ssl, - OSSL_ENCRYPTION_LEVEL ossl_level, - const uint8_t *rx_secret, - const uint8_t *tx_secret, - size_t secretlen) +#elif defined(USE_GNUTLS) +static int keylog_callback(gnutls_session_t session, const char *label, + const gnutls_datum_t *secret) { - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - int level = quic_from_ossl_level(ossl_level); - - if(ngtcp2_crypto_derive_and_install_key( - qs->qconn, ssl, NULL, NULL, NULL, NULL, NULL, NULL, level, rx_secret, - tx_secret, secretlen, NGTCP2_CRYPTO_SIDE_CLIENT) != 0) - return 0; + gnutls_datum_t crandom; + gnutls_datum_t srandom; - if(level == NGTCP2_CRYPTO_LEVEL_APP) { - if(init_ngh3_conn(qs) != CURLE_OK) - return 0; + gnutls_session_get_random(session, &crandom, &srandom); + if(crandom.size != 32) { + return -1; } - return 1; + Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size); + return 0; } +#endif -static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, - const uint8_t *data, size_t len) +static int init_ngh3_conn(struct quicsocket *qs); + +static int write_client_handshake(struct quicsocket *qs, + ngtcp2_crypto_level level, + const uint8_t *data, size_t len) { - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); struct quic_handshake *crypto_data; - ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level); int rv; crypto_data = &qs->crypto_data[level]; @@ -216,6 +245,41 @@ static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, return 1; } +#ifdef USE_OPENSSL +static int quic_set_encryption_secrets(SSL *ssl, + OSSL_ENCRYPTION_LEVEL ossl_level, + const uint8_t *rx_secret, + const uint8_t *tx_secret, + size_t secretlen) +{ + struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); + int level = quic_from_ossl_level(ossl_level); + + if(ngtcp2_crypto_derive_and_install_rx_key( + qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0) + return 0; + + if(ngtcp2_crypto_derive_and_install_tx_key( + qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0) + return 0; + + if(level == NGTCP2_CRYPTO_LEVEL_APP) { + if(init_ngh3_conn(qs) != CURLE_OK) + return 0; + } + + return 1; +} + +static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, + const uint8_t *data, size_t len) +{ + struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); + ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level); + + return write_client_handshake(qs, level, data, len); +} + static int quic_flush_flight(SSL *ssl) { (void)ssl; @@ -239,7 +303,6 @@ static SSL_QUIC_METHOD quic_method = {quic_set_encryption_secrets, static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) { SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); - const char *keylog_filename; SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); @@ -260,12 +323,10 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) SSL_CTX_set_quic_method(ssl_ctx, &quic_method); - keylog_filename = getenv("SSLKEYLOGFILE"); - if(keylog_filename) { - keylog_file = fopen(keylog_filename, "wb"); - if(keylog_file) { - SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); - } + /* Open the file if a TLS or QUIC backend has not done this before. */ + Curl_tls_keylog_open(); + if(Curl_tls_keylog_enabled()) { + SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); } return ssl_ctx; @@ -280,9 +341,7 @@ static int quic_init_ssl(struct quicsocket *qs) /* this will need some attention when HTTPS proxy over QUIC get fixed */ const char * const hostname = qs->conn->host.name; - if(qs->ssl) - SSL_free(qs->ssl); - + DEBUGASSERT(!qs->ssl); qs->ssl = SSL_new(qs->sslctx); SSL_set_app_data(qs->ssl, qs); @@ -291,8 +350,8 @@ static int quic_init_ssl(struct quicsocket *qs) switch(qs->version) { #ifdef NGTCP2_PROTO_VER case NGTCP2_PROTO_VER: - alpn = (const uint8_t *)NGTCP2_ALPN_H3; - alpnlen = sizeof(NGTCP2_ALPN_H3) - 1; + alpn = (const uint8_t *)NGHTTP3_ALPN_H3; + alpnlen = sizeof(NGHTTP3_ALPN_H3) - 1; break; #endif } @@ -303,17 +362,191 @@ static int quic_init_ssl(struct quicsocket *qs) SSL_set_tlsext_host_name(qs->ssl, hostname); return 0; } +#elif defined(USE_GNUTLS) +static int secret_func(gnutls_session_t ssl, + gnutls_record_encryption_level_t gtls_level, + const void *rx_secret, + const void *tx_secret, size_t secretlen) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + int level = quic_from_gtls_level(gtls_level); + + if(level != NGTCP2_CRYPTO_LEVEL_EARLY && + ngtcp2_crypto_derive_and_install_rx_key( + qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0) + return 0; + + if(ngtcp2_crypto_derive_and_install_tx_key( + qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0) + return 0; + + if(level == NGTCP2_CRYPTO_LEVEL_APP) { + if(init_ngh3_conn(qs) != CURLE_OK) + return -1; + } + + return 0; +} -static int cb_initial(ngtcp2_conn *quic, void *user_data) +static int read_func(gnutls_session_t ssl, + gnutls_record_encryption_level_t gtls_level, + gnutls_handshake_description_t htype, const void *data, + size_t len) { - struct quicsocket *qs = (struct quicsocket *)user_data; + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + ngtcp2_crypto_level level = quic_from_gtls_level(gtls_level); + int rv; - if(ngtcp2_crypto_read_write_crypto_data( - quic, qs->ssl, NGTCP2_CRYPTO_LEVEL_INITIAL, NULL, 0) != 0) - return NGTCP2_ERR_CALLBACK_FAILURE; + if(htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC) + return 0; + + rv = write_client_handshake(qs, level, data, len); + if(rv == 0) + return -1; + + return 0; +} + +static int alert_read_func(gnutls_session_t ssl, + gnutls_record_encryption_level_t gtls_level, + gnutls_alert_level_t alert_level, + gnutls_alert_description_t alert_desc) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + (void)gtls_level; + (void)alert_level; + + qs->tls_alert = alert_desc; + return 1; +} + +static int tp_recv_func(gnutls_session_t ssl, const uint8_t *data, + size_t data_size) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + ngtcp2_transport_params params; + + if(ngtcp2_decode_transport_params( + ¶ms, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, + data, data_size) != 0) + return -1; + + if(ngtcp2_conn_set_remote_transport_params(qs->qconn, ¶ms) != 0) + return -1; + + return 0; +} + +static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + uint8_t paramsbuf[64]; + ngtcp2_transport_params params; + ssize_t nwrite; + int rc; + + ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms); + nwrite = ngtcp2_encode_transport_params( + paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, + ¶ms); + if(nwrite < 0) { + H3BUGF(fprintf(stderr, "ngtcp2_encode_transport_params: %s\n", + ngtcp2_strerror((int)nwrite))); + return -1; + } + + rc = gnutls_buffer_append_data(extdata, paramsbuf, nwrite); + if(rc < 0) + return rc; + + return (int)nwrite; +} + +static int quic_init_ssl(struct quicsocket *qs) +{ + gnutls_datum_t alpn = {NULL, 0}; + /* this will need some attention when HTTPS proxy over QUIC get fixed */ + const char * const hostname = qs->conn->host.name; + int rc; + + DEBUGASSERT(!qs->ssl); + + gnutls_init(&qs->ssl, GNUTLS_CLIENT); + gnutls_session_set_ptr(qs->ssl, qs); + + rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL); + if(rc < 0) { + H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n", + gnutls_strerror(rc))); + return 1; + } + + gnutls_handshake_set_secret_function(qs->ssl, secret_func); + gnutls_handshake_set_read_function(qs->ssl, read_func); + gnutls_alert_set_read_function(qs->ssl, alert_read_func); + + rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters", + 0xffa5, GNUTLS_EXT_TLS, + tp_recv_func, tp_send_func, + NULL, NULL, NULL, + GNUTLS_EXT_FLAG_TLS | + GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE); + if(rc < 0) { + H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n", + gnutls_strerror(rc))); + return 1; + } + /* Open the file if a TLS or QUIC backend has not done this before. */ + Curl_tls_keylog_open(); + if(Curl_tls_keylog_enabled()) { + gnutls_session_set_keylog_function(qs->ssl, keylog_callback); + } + + if(qs->cred) + gnutls_certificate_free_credentials(qs->cred); + + rc = gnutls_certificate_allocate_credentials(&qs->cred); + if(rc < 0) { + H3BUGF(fprintf(stderr, + "gnutls_certificate_allocate_credentials failed: %s\n", + gnutls_strerror(rc))); + return 1; + } + + rc = gnutls_certificate_set_x509_system_trust(qs->cred); + if(rc < 0) { + H3BUGF(fprintf(stderr, + "gnutls_certificate_set_x509_system_trust failed: %s\n", + gnutls_strerror(rc))); + return 1; + } + + rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred); + if(rc < 0) { + H3BUGF(fprintf(stderr, "gnutls_credentials_set failed: %s\n", + gnutls_strerror(rc))); + return 1; + } + + switch(qs->version) { +#ifdef NGTCP2_PROTO_VER + case NGTCP2_PROTO_VER: + /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */ + alpn.data = (unsigned char *)NGHTTP3_ALPN_H3 + 1; + alpn.size = sizeof(NGHTTP3_ALPN_H3) - 2; + break; +#endif + } + if(alpn.data) + gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0); + + /* set SNI */ + gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname)); return 0; } +#endif static int cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level, @@ -321,10 +554,10 @@ cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level, const uint8_t *data, size_t datalen, void *user_data) { - struct quicsocket *qs = (struct quicsocket *)user_data; (void)offset; + (void)user_data; - if(ngtcp2_crypto_read_write_crypto_data(tconn, qs->ssl, crypto_level, data, + if(ngtcp2_crypto_read_write_crypto_data(tconn, crypto_level, data, datalen) != 0) return NGTCP2_ERR_CRYPTO; @@ -350,13 +583,14 @@ static void extend_stream_window(ngtcp2_conn *tconn, } -static int cb_recv_stream_data(ngtcp2_conn *tconn, int64_t stream_id, - int fin, uint64_t offset, +static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags, + int64_t stream_id, uint64_t offset, const uint8_t *buf, size_t buflen, void *user_data, void *stream_user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; ssize_t nconsumed; + int fin = flags & NGTCP2_STREAM_DATA_FLAG_FIN ? 1 : 0; (void)offset; (void)stream_user_data; @@ -442,20 +676,6 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id, return 0; } -static int cb_recv_retry(ngtcp2_conn *tconn, const ngtcp2_pkt_hd *hd, - const ngtcp2_pkt_retry *retry, void *user_data) -{ - /* Re-generate handshake secrets here because connection ID might change. */ - struct quicsocket *qs = (struct quicsocket *)user_data; - (void)tconn; - (void)hd; - (void)retry; - - setup_initial_crypto_context(qs); - - return 0; -} - static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn, uint64_t max_streams, void *user_data) @@ -508,7 +728,7 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, } static ngtcp2_conn_callbacks ng_callbacks = { - cb_initial, + ngtcp2_crypto_client_initial_cb, NULL, /* recv_client_initial */ cb_recv_crypto_data, cb_handshake_completed, @@ -522,7 +742,7 @@ static ngtcp2_conn_callbacks ng_callbacks = { NULL, /* stream_open */ cb_stream_close, NULL, /* recv_stateless_reset */ - cb_recv_retry, + ngtcp2_crypto_recv_retry_cb, cb_extend_max_local_streams_bidi, NULL, /* extend_max_local_streams_uni */ NULL, /* rand */ @@ -536,7 +756,8 @@ static ngtcp2_conn_callbacks ng_callbacks = { NULL, /* extend_max_remote_streams_uni */ cb_extend_max_stream_data, NULL, /* dcid_status */ - NULL /* handshake_confirmed */ + NULL, /* handshake_confirmed */ + NULL /* recv_new_token */ }; /* @@ -556,10 +777,10 @@ CURLcode Curl_quic_connect(struct connectdata *conn, struct quicsocket *qs = &conn->hequic[sockindex]; char ipbuf[40]; long port; - uint8_t paramsbuf[64]; - ngtcp2_transport_params params; - ssize_t nwrite; + int qfd; + if(qs->conn) + Curl_quic_disconnect(conn, sockindex); qs->conn = conn; /* extract the used address as a string */ @@ -574,9 +795,11 @@ CURLcode Curl_quic_connect(struct connectdata *conn, sockfd, ipbuf, port); qs->version = NGTCP2_PROTO_VER; +#ifdef USE_OPENSSL qs->sslctx = quic_ssl_ctx(data); if(!qs->sslctx) return CURLE_QUIC_CONNECT_ERROR; +#endif if(quic_init_ssl(qs)) return CURLE_QUIC_CONNECT_ERROR; @@ -591,7 +814,9 @@ CURLcode Curl_quic_connect(struct connectdata *conn, if(result) return result; - quic_settings(&qs->settings, data->set.buffer_size); + (void)Curl_qlogdir(data, qs->scid.data, NGTCP2_MAX_CIDLEN, &qfd); + qs->qlogfd = qfd; /* -1 if failure above */ + quic_settings(qs, data->set.buffer_size); qs->local_addrlen = sizeof(qs->local_addr); rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr, @@ -613,22 +838,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, if(rc) return CURLE_QUIC_CONNECT_ERROR; - ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms); - nwrite = ngtcp2_encode_transport_params( - paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, - ¶ms); - if(nwrite < 0) { - failf(data, "ngtcp2_encode_transport_params: %s\n", - ngtcp2_strerror((int)nwrite)); - return CURLE_QUIC_CONNECT_ERROR; - } - - if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite)) - return CURLE_QUIC_CONNECT_ERROR; - - rc = setup_initial_crypto_context(qs); - if(rc) - return CURLE_QUIC_CONNECT_ERROR; + ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->ssl); return CURLE_OK; } @@ -641,7 +851,7 @@ int Curl_quic_ver(char *p, size_t len) { ngtcp2_info *ng2 = ngtcp2_version(0); nghttp3_info *ht3 = nghttp3_version(0); - return msnprintf(p, len, " ngtcp2/%s nghttp3/%s", + return msnprintf(p, len, "ngtcp2/%s nghttp3/%s", ng2->version_str, ht3->version_str); } @@ -669,19 +879,49 @@ static int ng_perform_getsock(const struct connectdata *conn, return ng_getsock((struct connectdata *)conn, socks); } -static CURLcode ng_disconnect(struct connectdata *conn, - bool dead_connection) +static void qs_disconnect(struct quicsocket *qs) { int i; - struct quicsocket *qs = &conn->hequic[0]; - (void)dead_connection; + if(!qs->conn) /* already closed */ + return; + qs->conn = NULL; + if(qs->qlogfd != -1) { + close(qs->qlogfd); + qs->qlogfd = -1; + } if(qs->ssl) +#ifdef USE_OPENSSL SSL_free(qs->ssl); +#elif defined(USE_GNUTLS) + gnutls_deinit(qs->ssl); +#endif + qs->ssl = NULL; +#ifdef USE_GNUTLS + if(qs->cred) + gnutls_certificate_free_credentials(qs->cred); +#endif for(i = 0; i < 3; i++) - free(qs->crypto_data[i].buf); + Curl_safefree(qs->crypto_data[i].buf); nghttp3_conn_del(qs->h3conn); ngtcp2_conn_del(qs->qconn); +#ifdef USE_OPENSSL SSL_CTX_free(qs->sslctx); +#endif +} + +void Curl_quic_disconnect(struct connectdata *conn, + int tempindex) +{ + if(conn->transport == TRNSPRT_QUIC) + qs_disconnect(&conn->hequic[tempindex]); +} + +static CURLcode ng_disconnect(struct connectdata *conn, + bool dead_connection) +{ + (void)dead_connection; + Curl_quic_disconnect(conn, 0); + Curl_quic_disconnect(conn, 1); return CURLE_OK; } @@ -734,57 +974,12 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, return 0; } -/* Minimum size of the overflow buffer */ -#define OVERFLOWSIZE 1024 - -/* - * allocate_overflow() ensures that there is room for incoming data in the - * overflow buffer, growing it to accommodate the new data if necessary. We - * may need to use the overflow buffer because we can't precisely limit the - * amount of HTTP/3 header data we receive using QUIC flow control mechanisms. - */ -static CURLcode allocate_overflow(struct Curl_easy *data, - struct HTTP *stream, - size_t length) -{ - size_t maxleft; - size_t newsize; - /* length can be arbitrarily large, so take care not to overflow newsize */ - maxleft = CURL_MAX_READ_SIZE - stream->overflow_buflen; - if(length > maxleft) { - /* The reason to have a max limit for this is to avoid the risk of a bad - server feeding libcurl with a highly compressed list of headers that - will cause our overflow buffer to grow too large */ - failf(data, "Rejected %zu bytes of overflow data (max is %d)!", - stream->overflow_buflen + length, CURL_MAX_READ_SIZE); - return CURLE_OUT_OF_MEMORY; - } - newsize = stream->overflow_buflen + length; - if(newsize > stream->overflow_bufsize) { - /* We enlarge the overflow buffer as it is too small */ - char *newbuff; - newsize = CURLMAX(newsize * 3 / 2, stream->overflow_bufsize*2); - newsize = CURLMIN(CURLMAX(OVERFLOWSIZE, newsize), CURL_MAX_READ_SIZE); - newbuff = realloc(stream->overflow_buf, newsize); - if(!newbuff) { - failf(data, "Failed to alloc memory for overflow buffer!"); - return CURLE_OUT_OF_MEMORY; - } - stream->overflow_buf = newbuff; - stream->overflow_bufsize = newsize; - infof(data, "Grew HTTP/3 overflow buffer to %zu bytes\n", newsize); - } - return CURLE_OK; -} - /* * write_data() copies data to the stream's receive buffer. If not enough * space is available in the receive buffer, it copies the rest to the * stream's overflow buffer. */ -static CURLcode write_data(struct Curl_easy *data, - struct HTTP *stream, - const void *mem, size_t memlen) +static CURLcode write_data(struct HTTP *stream, const void *mem, size_t memlen) { CURLcode result = CURLE_OK; const char *buf = mem; @@ -792,10 +987,6 @@ static CURLcode write_data(struct Curl_easy *data, /* copy as much as possible to the receive buffer */ if(stream->len) { size_t len = CURLMIN(ncopy, stream->len); -#if 0 /* extra debugging of incoming h3 data */ - fprintf(stderr, "!! Copies %zd bytes to %p (total %zd)\n", - len, stream->mem, stream->memlen); -#endif memcpy(stream->mem, buf, len); stream->len -= len; stream->memlen += len; @@ -804,26 +995,8 @@ static CURLcode write_data(struct Curl_easy *data, ncopy -= len; } /* copy the rest to the overflow buffer */ - if(ncopy) { - result = allocate_overflow(data, stream, ncopy); - if(result) { - return result; - } -#if 0 /* extra debugging of incoming h3 data */ - fprintf(stderr, "!! Copies %zd overflow bytes to %p (total %zd)\n", - ncopy, stream->overflow_buf, stream->overflow_buflen); -#endif - memcpy(stream->overflow_buf + stream->overflow_buflen, buf, ncopy); - stream->overflow_buflen += ncopy; - } -#if 0 /* extra debugging of incoming h3 data */ - { - size_t i; - for(i = 0; i < memlen; i++) { - fprintf(stderr, "!! data[%d]: %02x '%c'\n", i, buf[i], buf[i]); - } - } -#endif + if(ncopy) + result = Curl_dyn_addn(&stream->overflow, buf, ncopy); return result; } @@ -836,7 +1009,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id, CURLcode result = CURLE_OK; (void)conn; - result = write_data(data, stream, buf, buflen); + result = write_data(stream, buf, buflen); if(result) { return -1; } @@ -899,7 +1072,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, /* add a CRLF only if we've received some headers */ if(stream->firstheader) { - result = write_data(data, stream, "\r\n", 2); + result = write_data(stream, "\r\n", 2); if(result) { return -1; } @@ -930,26 +1103,26 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, int status = decode_status_code(h3val.base, h3val.len); DEBUGASSERT(status != -1); ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status); - result = write_data(data, stream, line, ncopy); + result = write_data(stream, line, ncopy); if(result) { return -1; } } else { /* store as a HTTP1-style header */ - result = write_data(data, stream, h3name.base, h3name.len); + result = write_data(stream, h3name.base, h3name.len); if(result) { return -1; } - result = write_data(data, stream, ": ", 2); + result = write_data(stream, ": ", 2); if(result) { return -1; } - result = write_data(data, stream, h3val.base, h3val.len); + result = write_data(stream, h3val.base, h3val.len); if(result) { return -1; } - result = write_data(data, stream, "\r\n", 2); + result = write_data(stream, "\r\n", 2); if(result) { return -1; } @@ -1057,15 +1230,16 @@ static Curl_send ngh3_stream_send; static size_t drain_overflow_buffer(struct HTTP *stream) { - size_t ncopy = CURLMIN(stream->overflow_buflen, stream->len); + size_t overlen = Curl_dyn_len(&stream->overflow); + size_t ncopy = CURLMIN(overlen, stream->len); if(ncopy > 0) { - memcpy(stream->mem, stream->overflow_buf, ncopy); + memcpy(stream->mem, Curl_dyn_ptr(&stream->overflow), ncopy); stream->len -= ncopy; stream->mem += ncopy; stream->memlen += ncopy; - stream->overflow_buflen -= ncopy; - memmove(stream->overflow_buf, stream->overflow_buf + ncopy, - stream->overflow_buflen); + if(ncopy != overlen) + /* make the buffer only keep the tail */ + (void)Curl_dyn_tail(&stream->overflow, overlen - ncopy); } return ncopy; } @@ -1244,6 +1418,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, stream->stream3_id = stream3_id; stream->h3req = TRUE; /* senf off! */ + Curl_dyn_init(&stream->overflow, CURL_MAX_READ_SIZE); /* Calculate number of headers contained in [mem, mem + len). Assumes a correctly generated HTTP header field block. */ @@ -1400,7 +1575,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, } } - switch(data->set.httpreq) { + switch(data->state.httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: @@ -1522,11 +1697,11 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn, result = ng_process_ingress(conn, sockfd, qs); if(result) - return result; + goto error; result = ng_flush_egress(conn, sockfd, qs); if(result) - return result; + goto error; if(ngtcp2_conn_get_handshake_completed(qs->qconn)) { *done = TRUE; @@ -1534,6 +1709,10 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn, } return result; + error: + (void)qs_disconnect(qs); + return result; + } static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd, @@ -1630,11 +1809,12 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, return CURLE_SEND_ERROR; } else if(veccnt > 0) { + uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE | + (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0); outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, out, pktlen, &ndatalen, - NGTCP2_WRITE_STREAM_FLAG_MORE, - stream_id, fin, + flags, stream_id, (const ngtcp2_vec *)vec, veccnt, ts); if(outlen == 0) { break; @@ -1642,6 +1822,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, if(outlen < 0) { if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED || outlen == NGTCP2_ERR_STREAM_SHUT_WR) { + assert(ndatalen == -1); rv = nghttp3_conn_block_stream(qs->h3conn, stream_id); if(rv != 0) { failf(conn->data, @@ -1664,19 +1845,14 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, continue; } else { + assert(ndatalen == -1); failf(conn->data, "ngtcp2_conn_writev_stream returned error: %s\n", ngtcp2_strerror((int)outlen)); return CURLE_SEND_ERROR; } } - else if(ndatalen >= 0) { - rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen); - if(rv != 0) { - failf(conn->data, - "nghttp3_conn_add_write_offset returned error: %s\n", - nghttp3_strerror(rv)); - return CURLE_SEND_ERROR; - } + else { + assert(ndatalen == -1); } } } @@ -1748,7 +1924,7 @@ void Curl_quic_done(struct Curl_easy *data, bool premature) if(data->conn->handler == &Curl_handler_http3) { /* only for HTTP/3 transfers */ struct HTTP *stream = data->req.protop; - Curl_safefree(stream->overflow_buf); + Curl_dyn_free(&stream->overflow); } } @@ -1763,7 +1939,7 @@ bool Curl_quic_data_pending(const struct Curl_easy *data) there's no more data coming on the socket, we need to keep reading until the overflow buffer is empty. */ const struct HTTP *stream = data->req.protop; - return stream->overflow_buflen > 0; + return Curl_dyn_len(&stream->overflow) > 0; } #endif diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.h b/Utilities/cmcurl/lib/vquic/ngtcp2.h index 30d442f..e2f8b56 100644 --- a/Utilities/cmcurl/lib/vquic/ngtcp2.h +++ b/Utilities/cmcurl/lib/vquic/ngtcp2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,7 +28,11 @@ #include <ngtcp2/ngtcp2.h> #include <nghttp3/nghttp3.h> +#ifdef USE_OPENSSL #include <openssl/ssl.h> +#elif defined(USE_GNUTLS) +#include <gnutls/gnutls.h> +#endif struct quic_handshake { char *buf; /* pointer to the buffer */ @@ -44,8 +48,13 @@ struct quicsocket { ngtcp2_cid scid; uint32_t version; ngtcp2_settings settings; +#ifdef USE_OPENSSL SSL_CTX *sslctx; SSL *ssl; +#elif defined(USE_GNUTLS) + gnutls_certificate_credentials_t cred; + gnutls_session_t ssl; +#endif struct quic_handshake crypto_data[3]; /* the last TLS alert description generated by the local endpoint */ uint8_t tls_alert; @@ -54,6 +63,7 @@ struct quicsocket { nghttp3_conn *h3conn; nghttp3_conn_settings h3settings; + int qlogfd; }; #include "urldata.h" diff --git a/Utilities/cmcurl/lib/vquic/quiche.c b/Utilities/cmcurl/lib/vquic/quiche.c index d09ba70..be6f15c 100644 --- a/Utilities/cmcurl/lib/vquic/quiche.c +++ b/Utilities/cmcurl/lib/vquic/quiche.c @@ -34,6 +34,7 @@ #include "multiif.h" #include "connect.h" #include "strerror.h" +#include "vquic.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -64,7 +65,6 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, static Curl_recv h3_stream_recv; static Curl_send h3_stream_send; - static int quiche_getsock(struct connectdata *conn, curl_socket_t *socks) { struct SingleRequest *k = &conn->data->req; @@ -89,16 +89,30 @@ static int quiche_perform_getsock(const struct connectdata *conn, return quiche_getsock((struct connectdata *)conn, socks); } +static CURLcode qs_disconnect(struct quicsocket *qs) +{ + if(qs->h3config) + quiche_h3_config_free(qs->h3config); + if(qs->h3c) + quiche_h3_conn_free(qs->h3c); + quiche_config_free(qs->cfg); + quiche_conn_free(qs->conn); + return CURLE_OK; +} + static CURLcode quiche_disconnect(struct connectdata *conn, bool dead_connection) { struct quicsocket *qs = conn->quic; (void)dead_connection; - quiche_h3_config_free(qs->h3config); - quiche_h3_conn_free(qs->h3c); - quiche_config_free(qs->cfg); - quiche_conn_free(qs->conn); - return CURLE_OK; + return qs_disconnect(qs); +} + +void Curl_quic_disconnect(struct connectdata *conn, + int tempindex) +{ + if(conn->transport == TRNSPRT_QUIC) + qs_disconnect(&conn->hequic[tempindex]); } static unsigned int quiche_conncheck(struct connectdata *conn, @@ -152,6 +166,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, CURLcode result; struct quicsocket *qs = &conn->hequic[sockindex]; struct Curl_easy *data = conn->data; + char *keylog_file = NULL; #ifdef DEBUG_QUICHE /* initialize debug log callback only once */ @@ -189,7 +204,9 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, if(result) return result; - if(getenv("SSLKEYLOGFILE")) + keylog_file = getenv("SSLKEYLOGFILE"); + + if(keylog_file) quiche_config_log_keys(qs->cfg); qs->conn = quiche_connect(conn->host.name, (const uint8_t *) qs->scid, @@ -199,6 +216,20 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, return CURLE_OUT_OF_MEMORY; } + if(keylog_file) + quiche_conn_set_keylog_path(qs->conn, keylog_file); + + /* Known to not work on Windows */ +#if !defined(WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD) + { + int qfd; + (void)Curl_qlogdir(data, qs->scid, sizeof(qs->scid), &qfd); + if(qfd != -1) + quiche_conn_set_qlog_fd(qs->conn, qfd, + "qlog title", "curl qlog"); + } +#endif + result = flush_egress(conn, sockfd, qs); if(result) return result; @@ -217,8 +248,20 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, /* for connection reuse purposes: */ conn->ssl[FIRSTSOCKET].state = ssl_connection_complete; - infof(data, "Sent QUIC client Initial, ALPN: %s\n", - QUICHE_H3_APPLICATION_PROTOCOL + 1); + { + unsigned char alpn_protocols[] = QUICHE_H3_APPLICATION_PROTOCOL; + unsigned alpn_len, offset = 0; + + /* Replace each ALPN length prefix by a comma. */ + while(offset < sizeof(alpn_protocols) - 1) { + alpn_len = alpn_protocols[offset]; + alpn_protocols[offset] = ','; + offset += 1 + alpn_len; + } + + infof(data, "Sent QUIC client Initial, ALPN: %s\n", + alpn_protocols + 1); + } return CURLE_OK; } @@ -273,11 +316,11 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex, result = process_ingress(conn, sockfd, qs); if(result) - return result; + goto error; result = flush_egress(conn, sockfd, qs); if(result) - return result; + goto error; if(quiche_conn_is_established(qs->conn)) { *done = TRUE; @@ -286,6 +329,9 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex, } return result; + error: + qs_disconnect(qs); + return result; } static CURLcode process_ingress(struct connectdata *conn, int sockfd, @@ -532,7 +578,7 @@ static ssize_t h3_stream_send(struct connectdata *conn, */ int Curl_quic_ver(char *p, size_t len) { - return msnprintf(p, len, " quiche/%s", quiche_version()); + return msnprintf(p, len, "quiche/%s", quiche_version()); } /* Index where :authority header field will appear in request header @@ -714,7 +760,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, } } - switch(data->set.httpreq) { + switch(data->state.httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: diff --git a/Utilities/cmcurl/lib/vquic/vquic.c b/Utilities/cmcurl/lib/vquic/vquic.c new file mode 100644 index 0000000..aae8e09 --- /dev/null +++ b/Utilities/cmcurl/lib/vquic/vquic.c @@ -0,0 +1,85 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef ENABLE_QUIC + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include "urldata.h" +#include "dynbuf.h" +#include "curl_printf.h" +#include "vquic.h" + +#ifdef O_BINARY +#define QLOGMODE O_WRONLY|O_CREAT|O_BINARY +#else +#define QLOGMODE O_WRONLY|O_CREAT +#endif + +/* + * If the QLOGDIR environment variable is set, open and return a file + * descriptor to write the log to. + * + * This function returns error if something failed outside of failing to + * create the file. Open file success is deemed by seeing if the returned fd + * is != -1. + */ +CURLcode Curl_qlogdir(struct Curl_easy *data, + unsigned char *scid, + size_t scidlen, + int *qlogfdp) +{ + const char *qlog_dir = getenv("QLOGDIR"); + *qlogfdp = -1; + if(qlog_dir) { + struct dynbuf fname; + CURLcode result; + unsigned int i; + Curl_dyn_init(&fname, DYN_QLOG_NAME); + result = Curl_dyn_add(&fname, qlog_dir); + if(!result) + result = Curl_dyn_add(&fname, "/"); + for(i = 0; (i < scidlen) && !result; i++) { + char hex[3]; + msnprintf(hex, 3, "%02x", scid[i]); + result = Curl_dyn_add(&fname, hex); + } + if(!result) + result = Curl_dyn_add(&fname, ".qlog"); + + if(!result) { + int qlogfd = open(Curl_dyn_ptr(&fname), QLOGMODE, + data->set.new_file_perms); + if(qlogfd != -1) + *qlogfdp = qlogfd; + } + Curl_dyn_free(&fname); + if(result) + return result; + } + + return CURLE_OK; +} +#endif diff --git a/Utilities/cmcurl/lib/vquic/vquic.h b/Utilities/cmcurl/lib/vquic/vquic.h new file mode 100644 index 0000000..ecff0ed --- /dev/null +++ b/Utilities/cmcurl/lib/vquic/vquic.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_VQUIC_QUIC_H +#define HEADER_CURL_VQUIC_QUIC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef ENABLE_QUIC +CURLcode Curl_qlogdir(struct Curl_easy *data, + unsigned char *scid, + size_t scidlen, + int *qlogfdp); +#endif + +#endif /* HEADER_CURL_VQUIC_QUIC_H */ diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c index 647b4d4..8988e23 100644 --- a/Utilities/cmcurl/lib/vssh/libssh.c +++ b/Utilities/cmcurl/lib/vssh/libssh.c @@ -345,13 +345,27 @@ static int myssh_is_known(struct connectdata *conn) return rc; if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) { + int i; + char md5buffer[33]; + const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; + rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, &hash, &hlen); - if(rc != SSH_OK) + if(rc != SSH_OK || hlen != 16) { + failf(data, + "Denied establishing ssh session: md5 fingerprint not available"); goto cleanup; + } + + for(i = 0; i < 16; i++) + msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]); - if(hlen != strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) || - memcmp(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], hash, hlen)) { + infof(data, "SSH MD5 fingerprint: %s\n", md5buffer); + + if(!strcasecompare(md5buffer, pubkey_md5)) { + failf(data, + "Denied establishing ssh session: mismatch md5 fingerprint. " + "Remote %s is not equal to %s", md5buffer, pubkey_md5); rc = SSH_ERROR; goto cleanup; } @@ -389,6 +403,9 @@ static int myssh_is_known(struct connectdata *conn) knownkey.keytype = CURLKHTYPE_RSA1; break; case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P521: knownkey.keytype = CURLKHTYPE_ECDSA; break; case SSH_KEYTYPE_ED25519: @@ -456,6 +473,11 @@ static int myssh_is_known(struct connectdata *conn) foundkey.keytype = CURLKHTYPE_RSA1; break; case SSH_KEYTYPE_ECDSA: +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P521: +#endif foundkey.keytype = CURLKHTYPE_ECDSA; break; #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0) @@ -2127,6 +2149,7 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done) CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; struct Curl_easy *data = conn->data; + int rc; /* initialize per-handle data if not already */ if(!data->req.protop) @@ -2153,38 +2176,70 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done) return CURLE_FAILED_INIT; } - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name); + if(rc != SSH_OK) { + failf(data, "Could not set remote host"); + return CURLE_FAILED_INIT; + } + + rc = ssh_options_parse_config(ssh->ssh_session, NULL); + if(rc != SSH_OK) { + infof(data, "Could not parse SSH configuration files"); + /* ignore */ + } - if(conn->user) { + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock); + if(rc != SSH_OK) { + failf(data, "Could not set socket"); + return CURLE_FAILED_INIT; + } + + if(conn->user && conn->user[0] != '\0') { infof(data, "User: %s\n", conn->user); - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user); + if(rc != SSH_OK) { + failf(data, "Could not set user"); + return CURLE_FAILED_INIT; + } } if(data->set.str[STRING_SSH_KNOWNHOSTS]) { infof(data, "Known hosts: %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]); - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS, - data->set.str[STRING_SSH_KNOWNHOSTS]); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS, + data->set.str[STRING_SSH_KNOWNHOSTS]); + if(rc != SSH_OK) { + failf(data, "Could not set known hosts file path"); + return CURLE_FAILED_INIT; + } } - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name); - if(conn->remote_port) - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT, - &conn->remote_port); + if(conn->remote_port) { + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT, + &conn->remote_port); + if(rc != SSH_OK) { + failf(data, "Could not set remote port"); + return CURLE_FAILED_INIT; + } + } if(data->set.ssh_compression) { - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION, - "zlib,zlib@openssh.com,none"); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION, + "zlib,zlib@openssh.com,none"); + if(rc != SSH_OK) { + failf(data, "Could not set compression"); + return CURLE_FAILED_INIT; + } } ssh->privkey = NULL; ssh->pubkey = NULL; if(data->set.str[STRING_SSH_PUBLIC_KEY]) { - int rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY], - &ssh->pubkey); + rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY], + &ssh->pubkey); if(rc != SSH_OK) { failf(data, "Could not load public key file"); - /* ignore */ + return CURLE_FAILED_INIT; } } diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c index 8e04374..555afc9 100644 --- a/Utilities/cmcurl/lib/vssh/libssh2.c +++ b/Utilities/cmcurl/lib/vssh/libssh2.c @@ -93,15 +93,12 @@ #define HAS_STATVFS_SUPPORT 1 #endif -#define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s)) - -#define sftp_libssh2_realpath(s,p,t,m) \ - libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \ - (t), (m), LIBSSH2_SFTP_REALPATH) - +#define sftp_libssh2_realpath(s,p,t,m) \ + libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \ + (t), (m), LIBSSH2_SFTP_REALPATH) /* Local functions: */ -static const char *sftp_libssh2_strerror(int err); +static const char *sftp_libssh2_strerror(unsigned long err); static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); static LIBSSH2_FREE_FUNC(my_libssh2_free); @@ -213,7 +210,7 @@ kbd_callback(const char *name, int name_len, const char *instruction, (void)abstract; } /* kbd_callback */ -static CURLcode sftp_libssh2_error_to_CURLE(int err) +static CURLcode sftp_libssh2_error_to_CURLE(unsigned long err) { switch(err) { case LIBSSH2_FX_OK: @@ -694,31 +691,40 @@ static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn) while(!libssh2_knownhost_get(sshc->kh, &store, store)) { /* For non-standard ports, the name will be enclosed in */ /* square brackets, followed by a colon and the port */ - if(store->name[0] == '[') { - kh_name_end = strstr(store->name, "]:"); - if(!kh_name_end) { - infof(data, "Invalid host pattern %s in %s\n", - store->name, data->set.str[STRING_SSH_KNOWNHOSTS]); - continue; - } - port = atoi(kh_name_end + 2); - if(kh_name_end && (port == conn->remote_port)) { - kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end); - if(strncmp(store->name + 1, conn->host.name, kh_name_size) == 0) { + if(store) { + if(store->name) { + if(store->name[0] == '[') { + kh_name_end = strstr(store->name, "]:"); + if(!kh_name_end) { + infof(data, "Invalid host pattern %s in %s\n", + store->name, data->set.str[STRING_SSH_KNOWNHOSTS]); + continue; + } + port = atoi(kh_name_end + 2); + if(kh_name_end && (port == conn->remote_port)) { + kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end); + if(strncmp(store->name + 1, + conn->host.name, kh_name_size) == 0) { + found = true; + break; + } + } + } + else if(strcmp(store->name, conn->host.name) == 0) { found = true; break; } } - } - else if(strcmp(store->name, conn->host.name) == 0) { - found = true; - break; + else { + found = true; + break; + } } } if(found) { infof(data, "Found host %s in %s\n", - store->name, data->set.str[STRING_SSH_KNOWNHOSTS]); + conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { #ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 @@ -786,10 +792,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) struct SSHPROTO *sftp_scp = data->req.protop; struct ssh_conn *sshc = &conn->proto.sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - char *new_readdir_line; int rc = LIBSSH2_ERROR_NONE; - int err; + int ssherr; + unsigned long sftperr; int seekerr = CURL_SEEKFUNC_OK; + size_t readdir_len; *block = 0; /* we're not blocking by default */ do { @@ -865,12 +872,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_AUTH_DONE); break; } - err = libssh2_session_last_errno(sshc->ssh_session); - if(err == LIBSSH2_ERROR_EAGAIN) + ssherr = libssh2_session_last_errno(sshc->ssh_session); + if(ssherr == LIBSSH2_ERROR_EAGAIN) rc = LIBSSH2_ERROR_EAGAIN; else { state(conn, SSH_SESSION_FREE); - sshc->actualcode = libssh2_session_error_to_CURLE(err); + sshc->actualcode = libssh2_session_error_to_CURLE(ssherr); } break; } @@ -1240,16 +1247,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } else { /* Return the error type */ - err = sftp_libssh2_last_error(sshc->sftp_session); - if(err) - result = sftp_libssh2_error_to_CURLE(err); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + if(sftperr) + result = sftp_libssh2_error_to_CURLE(sftperr); else /* in this case, the error wasn't in the SFTP level but for example a time-out or similar */ result = CURLE_SSH; sshc->actualcode = result; DEBUGF(infof(data, "error = %d makes libcurl = %d\n", - err, (int)result)); + ssherr, (int)result)); state(conn, SSH_STOP); break; } @@ -1351,7 +1358,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) */ cp = strchr(cmd, ' '); if(cp == NULL) { - failf(data, "Syntax error in SFTP command. Supply parameter(s)!"); + failf(data, "Syntax error command '%s'. Missing parameter!", + cmd); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1367,7 +1375,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else - failf(data, "Syntax error: Bad first parameter"); + failf(data, "Syntax error: Bad first parameter to '%s'", cmd); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; @@ -1392,8 +1400,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else - failf(data, "Syntax error in chgrp/chmod/chown: " - "Bad second parameter"); + failf(data, "Syntax error in %s: Bad second parameter", cmd); Curl_safefree(sshc->quote_path1); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; @@ -1524,11 +1531,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc != 0 && !sshc->acceptfail) { /* get those attributes */ - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Attempt to get SFTP stats failed: %s", - sftp_libssh2_strerror(err)); + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1595,11 +1602,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Attempt to set SFTP stats failed: %s", - sftp_libssh2_strerror(err)); + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1618,11 +1625,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "symlink command failed: %s", - sftp_libssh2_strerror(err)); + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1639,9 +1646,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err)); + failf(data, "mkdir command failed: %s", + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1663,10 +1671,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); - failf(data, "rename command failed: %s", sftp_libssh2_strerror(err)); + failf(data, "rename command failed: %s", + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1682,9 +1691,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err)); + failf(data, "rmdir command failed: %s", + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1700,9 +1710,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - failf(data, "rm command failed: %s", sftp_libssh2_strerror(err)); + failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1723,9 +1733,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc != 0 && !sshc->acceptfail) { - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err)); + failf(data, "statvfs command failed: %s", + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; @@ -1862,21 +1873,21 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc) /* only when there was an SFTP protocol error can we extract the sftp error! */ - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); else - err = -1; /* not an sftp error at all */ + sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */ if(sshc->secondCreateDirs) { state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = err>= LIBSSH2_FX_OK? - sftp_libssh2_error_to_CURLE(err):CURLE_SSH; + sshc->actualcode = sftperr != LIBSSH2_FX_OK ? + sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH; failf(data, "Creating the dir/file failed: %s", - sftp_libssh2_strerror(err)); + sftp_libssh2_strerror(sftperr)); break; } - if(((err == LIBSSH2_FX_NO_SUCH_FILE) || - (err == LIBSSH2_FX_FAILURE) || - (err == LIBSSH2_FX_NO_SUCH_PATH)) && + if(((sftperr == LIBSSH2_FX_NO_SUCH_FILE) || + (sftperr == LIBSSH2_FX_FAILURE) || + (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) && (data->set.ftp_create_missing_dirs && (strlen(sftp_scp->path) > 1))) { /* try to create the path remotely */ @@ -1886,18 +1897,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = err>= LIBSSH2_FX_OK? - sftp_libssh2_error_to_CURLE(err):CURLE_SSH; + sshc->actualcode = sftperr != LIBSSH2_FX_OK ? + sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH; if(!sshc->actualcode) { - /* Sometimes, for some reason libssh2_sftp_last_error() returns - zero even though libssh2_sftp_open() failed previously! We need - to work around that! */ + /* Sometimes, for some reason libssh2_sftp_last_error() returns zero + even though libssh2_sftp_open() failed previously! We need to + work around that! */ sshc->actualcode = CURLE_SSH; - err = -1; + sftperr = LIBSSH2_FX_OK; } failf(data, "Upload failed: %s (%d/%d)", - err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error", - err, rc); + sftperr != LIBSSH2_FX_OK ? + sftp_libssh2_strerror(sftperr):"ssh error", + sftperr, rc); break; } @@ -2024,11 +2036,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) * permission was denied (creation might succeed further down the * path) - retry on unspecific FAILURE also */ - err = sftp_libssh2_last_error(sshc->sftp_session); - if((err != LIBSSH2_FX_FILE_ALREADY_EXISTS) && - (err != LIBSSH2_FX_FAILURE) && - (err != LIBSSH2_FX_PERMISSION_DENIED)) { - result = sftp_libssh2_error_to_CURLE(err); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + if((sftperr != LIBSSH2_FX_FILE_ALREADY_EXISTS) && + (sftperr != LIBSSH2_FX_FAILURE) && + (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) { + result = sftp_libssh2_error_to_CURLE(sftperr); state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result?result:CURLE_SSH; break; @@ -2060,11 +2072,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) rc = LIBSSH2_ERROR_EAGAIN; break; } - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); failf(data, "Could not open directory for reading: %s", - sftp_libssh2_strerror(err)); + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); - result = sftp_libssh2_error_to_CURLE(err); + result = sftp_libssh2_error_to_CURLE(sftperr); sshc->actualcode = result?result:CURLE_SSH; break; } @@ -2081,6 +2093,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } + Curl_dyn_init(&sshc->readdir, PATH_MAX * 2); state(conn, SSH_SFTP_READDIR); break; @@ -2095,68 +2108,51 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } if(rc > 0) { - sshc->readdir_len = (size_t) rc; - sshc->readdir_filename[sshc->readdir_len] = '\0'; + readdir_len = (size_t) rc; + sshc->readdir_filename[readdir_len] = '\0'; if(data->set.ftp_list_only) { - char *tmpLine; - - tmpLine = aprintf("%s\n", sshc->readdir_filename); - if(tmpLine == NULL) { - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } result = Curl_client_write(conn, CLIENTWRITE_BODY, - tmpLine, sshc->readdir_len + 1); - free(tmpLine); - + sshc->readdir_filename, + readdir_len); + if(!result) + result = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *)"\n", 1); if(result) { state(conn, SSH_STOP); break; } /* since this counts what we send to the client, we include the newline in this counter */ - data->req.bytecount += sshc->readdir_len + 1; + data->req.bytecount += readdir_len + 1; /* output debug output if that is requested */ if(data->set.verbose) { - Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename, - sshc->readdir_len); + Curl_debug(data, CURLINFO_DATA_IN, sshc->readdir_filename, + readdir_len); + Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1); } } else { - sshc->readdir_currLen = strlen(sshc->readdir_longentry); - sshc->readdir_totalLen = 80 + sshc->readdir_currLen; - sshc->readdir_line = calloc(sshc->readdir_totalLen, 1); - if(!sshc->readdir_line) { - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - - memcpy(sshc->readdir_line, sshc->readdir_longentry, - sshc->readdir_currLen); - if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && - ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFLNK)) { - sshc->readdir_linkPath = malloc(PATH_MAX + 1); - if(sshc->readdir_linkPath == NULL) { - Curl_safefree(sshc->readdir_filename); - Curl_safefree(sshc->readdir_longentry); - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; + result = Curl_dyn_add(&sshc->readdir, sshc->readdir_longentry); + + if(!result) { + if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && + ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFLNK)) { + Curl_dyn_init(&sshc->readdir_link, PATH_MAX); + result = Curl_dyn_add(&sshc->readdir_link, sftp_scp->path); + state(conn, SSH_SFTP_READDIR_LINK); + if(!result) + break; + } + else { + state(conn, SSH_SFTP_READDIR_BOTTOM); break; } - - msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path, - sshc->readdir_filename); - state(conn, SSH_SFTP_READDIR_LINK); - break; } - state(conn, SSH_SFTP_READDIR_BOTTOM); + sshc->actualcode = result; + state(conn, SSH_SFTP_CLOSE); break; } } @@ -2167,11 +2163,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } else if(rc < 0) { - err = sftp_libssh2_last_error(sshc->sftp_session); - result = sftp_libssh2_error_to_CURLE(err); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); + result = sftp_libssh2_error_to_CURLE(sftperr); sshc->actualcode = result?result:CURLE_SSH; failf(data, "Could not open remote file for reading: %s :: %d", - sftp_libssh2_strerror(err), + sftp_libssh2_strerror(sftperr), libssh2_session_last_errno(sshc->ssh_session)); Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); @@ -2183,64 +2179,56 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_SFTP_READDIR_LINK: rc = libssh2_sftp_symlink_ex(sshc->sftp_session, - sshc->readdir_linkPath, - curlx_uztoui(strlen(sshc->readdir_linkPath)), + Curl_dyn_ptr(&sshc->readdir_link), + (int)Curl_dyn_len(&sshc->readdir_link), sshc->readdir_filename, PATH_MAX, LIBSSH2_SFTP_READLINK); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - sshc->readdir_len = (size_t) rc; - Curl_safefree(sshc->readdir_linkPath); + readdir_len = (size_t) rc; + Curl_dyn_free(&sshc->readdir_link); + + /* append filename and extra output */ + result = Curl_dyn_addf(&sshc->readdir, " -> %s", sshc->readdir_filename); - /* get room for the filename and extra output */ - sshc->readdir_totalLen += 4 + sshc->readdir_len; - new_readdir_line = Curl_saferealloc(sshc->readdir_line, - sshc->readdir_totalLen); - if(!new_readdir_line) { + if(result) { sshc->readdir_line = NULL; Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; + sshc->actualcode = result; break; } - sshc->readdir_line = new_readdir_line; - - sshc->readdir_currLen += msnprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, - " -> %s", - sshc->readdir_filename); state(conn, SSH_SFTP_READDIR_BOTTOM); break; case SSH_SFTP_READDIR_BOTTOM: - sshc->readdir_currLen += msnprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, "\n"); - result = Curl_client_write(conn, CLIENTWRITE_BODY, - sshc->readdir_line, - sshc->readdir_currLen); + result = Curl_dyn_addn(&sshc->readdir, "\n", 1); + if(!result) + result = Curl_client_write(conn, CLIENTWRITE_BODY, + Curl_dyn_ptr(&sshc->readdir), + Curl_dyn_len(&sshc->readdir)); if(!result) { /* output debug output if that is requested */ if(data->set.verbose) { - Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line, - sshc->readdir_currLen); + Curl_debug(data, CURLINFO_DATA_IN, + Curl_dyn_ptr(&sshc->readdir), + Curl_dyn_len(&sshc->readdir)); } - data->req.bytecount += sshc->readdir_currLen; + data->req.bytecount += Curl_dyn_len(&sshc->readdir); } - Curl_safefree(sshc->readdir_line); if(result) { + Curl_dyn_free(&sshc->readdir); state(conn, SSH_STOP); } - else + else { + Curl_dyn_reset(&sshc->readdir); state(conn, SSH_SFTP_READDIR); + } break; case SSH_SFTP_READDIR_DONE: @@ -2273,11 +2261,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) rc = LIBSSH2_ERROR_EAGAIN; break; } - err = sftp_libssh2_last_error(sshc->sftp_session); + sftperr = libssh2_sftp_last_error(sshc->sftp_session); failf(data, "Could not open remote file for reading: %s", - sftp_libssh2_strerror(err)); + sftp_libssh2_strerror(sftperr)); state(conn, SSH_SFTP_CLOSE); - result = sftp_libssh2_error_to_CURLE(err); + result = sftp_libssh2_error_to_CURLE(sftperr); sshc->actualcode = result?result:CURLE_SSH; break; } @@ -2542,7 +2530,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } /* upload data */ - Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET); + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->sockfd = conn->writesockfd; @@ -2612,7 +2602,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* download data */ bytecount = (curl_off_t)sb.st_size; - data->req.maxdownload = (curl_off_t)sb.st_size; + data->req.maxdownload = (curl_off_t)sb.st_size; Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1); /* not set by Curl_setup_transfer to preserve keepon bits */ @@ -2819,7 +2809,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); Curl_safefree(sshc->readdir_line); - Curl_safefree(sshc->readdir_linkPath); + Curl_dyn_free(&sshc->readdir); /* the code we are about to return */ result = sshc->actualcode; @@ -2943,7 +2933,7 @@ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done) } static CURLcode ssh_block_statemach(struct connectdata *conn, - bool disconnect) + bool duringconnect) { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; @@ -2958,19 +2948,17 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, if(result) break; - if(!disconnect) { - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; - result = Curl_speedcheck(data, now); - if(result) - break; + result = Curl_speedcheck(data, now); + if(result) + break; - left = Curl_timeleft(data, NULL, FALSE); - if(left < 0) { - failf(data, "Operation timed out"); - return CURLE_OPERATION_TIMEDOUT; - } + left = Curl_timeleft(data, NULL, duringconnect); + if(left < 0) { + failf(data, "Operation timed out"); + return CURLE_OPERATION_TIMEDOUT; } #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION @@ -2985,7 +2973,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, fd_write = sock; /* wait for the socket to become ready */ (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, - left>1000?1000:(time_t)left); + left>1000?1000:left); } #endif @@ -3193,7 +3181,7 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection) state(conn, SSH_SESSION_DISCONNECT); - result = ssh_block_statemach(conn, TRUE); + result = ssh_block_statemach(conn, FALSE); } return result; @@ -3342,7 +3330,7 @@ static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection) if(conn->proto.sshc.ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SFTP_SHUTDOWN); - result = ssh_block_statemach(conn, TRUE); + result = ssh_block_statemach(conn, FALSE); } DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n")); @@ -3417,7 +3405,7 @@ static ssize_t sftp_recv(struct connectdata *conn, int sockindex, return nread; } -static const char *sftp_libssh2_strerror(int err) +static const char *sftp_libssh2_strerror(unsigned long err) { switch(err) { case LIBSSH2_FX_NO_SUCH_FILE: diff --git a/Utilities/cmcurl/lib/vssh/ssh.h b/Utilities/cmcurl/lib/vssh/ssh.h index 0d4ee52..9e49993 100644 --- a/Utilities/cmcurl/lib/vssh/ssh.h +++ b/Utilities/cmcurl/lib/vssh/ssh.h @@ -134,9 +134,7 @@ struct ssh_conn { quote command fails) */ char *homedir; /* when doing SFTP we figure out home dir in the connect phase */ - size_t readdir_len, readdir_totalLen, readdir_currLen; char *readdir_line; - char *readdir_linkPath; /* end of READDIR stuff */ int secondCreateDirs; /* counter use by the code to see if the @@ -147,6 +145,8 @@ struct ssh_conn { int orig_waitfor; /* default READ/WRITE bits wait for */ #if defined(USE_LIBSSH) + char *readdir_linkPath; + size_t readdir_len, readdir_totalLen, readdir_currLen; /* our variables */ unsigned kbd_state; /* 0 or 1 */ ssh_key privkey; @@ -168,6 +168,8 @@ struct ssh_conn { const char *readdir_longentry; char *readdir_tmp; #elif defined(USE_LIBSSH2) + struct dynbuf readdir_link; + struct dynbuf readdir; char *readdir_filename; char *readdir_longentry; diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c index 363a52c..dcbbab6 100644 --- a/Utilities/cmcurl/lib/vssh/wolfssh.c +++ b/Utilities/cmcurl/lib/vssh/wolfssh.c @@ -241,8 +241,8 @@ static ssize_t wsftp_send(struct connectdata *conn, int sockindex, int rc; (void)sockindex; - offset[0] = (word32)sshc->offset&0xFFFFFFFF; - offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; + offset[0] = (word32)sshc->offset&0xFFFFFFFF; + offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle, sshc->handleSz, @@ -284,8 +284,8 @@ static ssize_t wsftp_recv(struct connectdata *conn, int sockindex, word32 offset[2]; (void)sockindex; - offset[0] = (word32)sshc->offset&0xFFFFFFFF; - offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; + offset[0] = (word32)sshc->offset&0xFFFFFFFF; + offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle, sshc->handleSz, diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c index 67f9458..628e16a 100644 --- a/Utilities/cmcurl/lib/vtls/bearssl.c +++ b/Utilities/cmcurl/lib/vtls/bearssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019, Michael Forney, <mforney@mforney.org> + * Copyright (C) 2019 - 2020, Michael Forney, <mforney@mforney.org> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,8 +56,6 @@ struct ssl_backend_data { size_t pending_write; }; -#define BACKEND connssl->backend - struct cafile_parser { CURLcode err; bool in_cert; @@ -300,6 +298,7 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; @@ -343,7 +342,7 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) } if(ssl_cafile) { - ret = load_cafile(ssl_cafile, &BACKEND->anchors, &BACKEND->anchors_len); + ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { failf(data, "error setting certificate verify locations:\n" @@ -356,24 +355,24 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) } /* initialize SSL context */ - br_ssl_client_init_full(&BACKEND->ctx, &BACKEND->x509.minimal, - BACKEND->anchors, BACKEND->anchors_len); - br_ssl_engine_set_versions(&BACKEND->ctx.eng, version_min, version_max); - br_ssl_engine_set_buffer(&BACKEND->ctx.eng, BACKEND->buf, - sizeof(BACKEND->buf), 1); + br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal, + backend->anchors, backend->anchors_len); + br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max); + br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf, + sizeof(backend->buf), 1); /* initialize X.509 context */ - BACKEND->x509.vtable = &x509_vtable; - BACKEND->x509.verifypeer = verifypeer; - BACKEND->x509.verifyhost = verifyhost; - br_ssl_engine_set_x509(&BACKEND->ctx.eng, &BACKEND->x509.vtable); + backend->x509.vtable = &x509_vtable; + backend->x509.verifypeer = verifypeer; + backend->x509.verifyhost = verifyhost; + br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable); if(SSL_SET_OPTION(primary.sessionid)) { void *session; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) { - br_ssl_engine_set_session_parameters(&BACKEND->ctx.eng, session); + br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); infof(data, "BearSSL: re-using session ID\n"); } Curl_ssl_sessionid_unlock(conn); @@ -389,16 +388,16 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { - BACKEND->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; + backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif - BACKEND->protocols[cur++] = ALPN_HTTP_1_1; + backend->protocols[cur++] = ALPN_HTTP_1_1; infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - br_ssl_engine_set_protocol_names(&BACKEND->ctx.eng, - BACKEND->protocols, cur); + br_ssl_engine_set_protocol_names(&backend->ctx.eng, + backend->protocols, cur); } if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) @@ -414,9 +413,9 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) hostname = NULL; } - if(!br_ssl_client_reset(&BACKEND->ctx, hostname, 0)) + if(!br_ssl_client_reset(&backend->ctx, hostname, 0)) return CURLE_FAILED_INIT; - BACKEND->active = TRUE; + backend->active = TRUE; connssl->connecting_state = ssl_connect_2; @@ -428,6 +427,7 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; curl_socket_t sockfd = conn->sock[sockindex]; unsigned state; unsigned char *buf; @@ -436,9 +436,9 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, int err; for(;;) { - state = br_ssl_engine_current_state(&BACKEND->ctx.eng); + state = br_ssl_engine_current_state(&backend->ctx.eng); if(state & BR_SSL_CLOSED) { - err = br_ssl_engine_last_error(&BACKEND->ctx.eng); + err = br_ssl_engine_last_error(&backend->ctx.eng); switch(err) { case BR_ERR_OK: /* TLS close notify */ @@ -468,7 +468,7 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, if(state & target) return CURLE_OK; if(state & BR_SSL_SENDREC) { - buf = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &len); + buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len); ret = swrite(sockfd, buf, len); if(ret == -1) { if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { @@ -478,10 +478,10 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, } return CURLE_WRITE_ERROR; } - br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); + br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret); } else if(state & BR_SSL_RECVREC) { - buf = br_ssl_engine_recvrec_buf(&BACKEND->ctx.eng, &len); + buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len); ret = sread(sockfd, buf, len); if(ret == 0) { failf(data, "SSL: EOF without close notify"); @@ -495,7 +495,7 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, } return CURLE_READ_ERROR; } - br_ssl_engine_recvrec_ack(&BACKEND->ctx.eng, ret); + br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret); } } } @@ -504,13 +504,14 @@ static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CURLcode ret; ret = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP | BR_SSL_RECVAPP); if(ret == CURLE_AGAIN) return CURLE_OK; if(ret == CURLE_OK) { - if(br_ssl_engine_current_state(&BACKEND->ctx.eng) == BR_SSL_CLOSED) { + if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) { failf(data, "SSL: connection closed during handshake"); return CURLE_SSL_CONNECT_ERROR; } @@ -523,6 +524,7 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CURLcode ret; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -530,7 +532,7 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) if(conn->bits.tls_enable_alpn) { const char *protocol; - protocol = br_ssl_engine_get_selected_protocol(&BACKEND->ctx.eng); + protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng); if(protocol) { infof(data, "ALPN, server accepted to use %s\n", protocol); @@ -558,7 +560,7 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) session = malloc(sizeof(*session)); if(!session) return CURLE_OUT_OF_MEMORY; - br_ssl_engine_get_session_parameters(&BACKEND->ctx.eng, session); + br_ssl_engine_get_session_parameters(&backend->ctx.eng, session); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex)); if(incache) @@ -581,6 +583,7 @@ static ssize_t bearssl_send(struct connectdata *conn, int sockindex, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; unsigned char *app; size_t applen; @@ -588,23 +591,23 @@ static ssize_t bearssl_send(struct connectdata *conn, int sockindex, *err = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP); if (*err != CURLE_OK) return -1; - app = br_ssl_engine_sendapp_buf(&BACKEND->ctx.eng, &applen); + app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen); if(!app) { failf(data, "SSL: connection closed during write"); *err = CURLE_SEND_ERROR; return -1; } - if(BACKEND->pending_write) { - applen = BACKEND->pending_write; - BACKEND->pending_write = 0; + if(backend->pending_write) { + applen = backend->pending_write; + backend->pending_write = 0; return applen; } if(applen > len) applen = len; memcpy(app, buf, applen); - br_ssl_engine_sendapp_ack(&BACKEND->ctx.eng, applen); - br_ssl_engine_flush(&BACKEND->ctx.eng, 0); - BACKEND->pending_write = applen; + br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen); + br_ssl_engine_flush(&backend->ctx.eng, 0); + backend->pending_write = applen; } } @@ -612,19 +615,20 @@ static ssize_t bearssl_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; unsigned char *app; size_t applen; *err = bearssl_run_until(conn, sockindex, BR_SSL_RECVAPP); if(*err != CURLE_OK) return -1; - app = br_ssl_engine_recvapp_buf(&BACKEND->ctx.eng, &applen); + app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen); if(!app) return 0; if(applen > len) applen = len; memcpy(buf, app, applen); - br_ssl_engine_recvapp_ack(&BACKEND->ctx.eng, applen); + br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen); return applen; } @@ -638,7 +642,7 @@ static CURLcode bearssl_connect_common(struct connectdata *conn, struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; - time_t timeout_ms; + timediff_t timeout_ms; int what; /* check if the connection has already been established */ @@ -739,8 +743,8 @@ static bool Curl_bearssl_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - - return br_ssl_engine_current_state(&BACKEND->ctx.eng) & BR_SSL_RECVAPP; + struct ssl_backend_data *backend = connssl->backend; + return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP; } static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM, @@ -786,21 +790,23 @@ static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn, static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - return &BACKEND->ctx; + struct ssl_backend_data *backend = connssl->backend; + return &backend->ctx; } static void Curl_bearssl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; size_t i; - if(BACKEND->active) { - br_ssl_engine_close(&BACKEND->ctx.eng); + if(backend->active) { + br_ssl_engine_close(&backend->ctx.eng); (void)bearssl_run_until(conn, sockindex, BR_SSL_CLOSED); } - for(i = 0; i < BACKEND->anchors_len; ++i) - free(BACKEND->anchors[i].dn.data); - free(BACKEND->anchors); + for(i = 0; i < backend->anchors_len; ++i) + free(backend->anchors[i].dn.data); + free(backend->anchors); } static void Curl_bearssl_session_free(void *ptr) @@ -836,9 +842,7 @@ static CURLcode Curl_bearssl_sha256sum(const unsigned char *input, const struct Curl_ssl Curl_ssl_bearssl = { { CURLSSLBACKEND_BEARSSL, "bearssl" }, - 0, - sizeof(struct ssl_backend_data), Curl_none_init, diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c index 32153dd..0538e4a 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.c +++ b/Utilities/cmcurl/lib/vtls/gskit.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -108,13 +108,13 @@ struct ssl_backend_data { #define BACKEND connssl->backend /* Supported ciphers. */ -typedef struct { +struct gskit_cipher { const char *name; /* Cipher name. */ const char *gsktoken; /* Corresponding token for GSKit String. */ unsigned int versions; /* SSL version flags. */ -} gskit_cipher; +}; -static const gskit_cipher ciphertable[] = { +static const struct gskit_cipher ciphertable[] = { { "null-md5", "01", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, @@ -307,7 +307,7 @@ static CURLcode set_ciphers(struct connectdata *conn, struct Curl_easy *data = conn->data; const char *cipherlist = SSL_CONN_CONFIG(cipher_list); const char *clp; - const gskit_cipher *ctp; + const struct gskit_cipher *ctp; int i; int l; bool unsupported; @@ -524,7 +524,6 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, int m; int i; int ret = 0; - struct timeval tv = {0, 0}; char buf[CURL_MAX_WRITE_SIZE]; if(!connssl->use || !connproxyssl->use) @@ -544,7 +543,7 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, if(n < conn->sock[sockindex]) n = conn->sock[sockindex]; } - i = select(n + 1, &fds_read, &fds_write, NULL, &tv); + i = Curl_select(n + 1, &fds_read, &fds_write, NULL, 0); if(i < 0) return -1; /* Select error. */ @@ -820,7 +819,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) if(!result) { /* Compute the handshake timeout. Since GSKit granularity is 1 second, we round up the required value. */ - long timeout = Curl_timeleft(data, NULL, TRUE); + timediff_t timeout = Curl_timeleft(data, NULL, TRUE); if(timeout < 0) result = CURLE_OPERATION_TIMEDOUT; else @@ -933,7 +932,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, /* Poll or wait for end of SSL asynchronous handshake. */ for(;;) { - long timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE); + timediff_t timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) timeout_ms = 0; stmv.tv_sec = timeout_ms / 1000; diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c index 5f740ee..9b4c365 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.c +++ b/Utilities/cmcurl/lib/vtls/gtls.c @@ -72,36 +72,11 @@ static void tls_log_func(int level, const char *str) #endif static bool gtls_inited = FALSE; -#if defined(GNUTLS_VERSION_NUMBER) -# if (GNUTLS_VERSION_NUMBER >= 0x020c00) -# undef gnutls_transport_set_lowat -# define gnutls_transport_set_lowat(A,B) Curl_nop_stmt -# define USE_GNUTLS_PRIORITY_SET_DIRECT 1 -# endif -# if (GNUTLS_VERSION_NUMBER >= 0x020c03) -# define GNUTLS_MAPS_WINSOCK_ERRORS 1 -# endif - -# if HAVE_GNUTLS_ALPN_SET_PROTOCOLS -# define HAS_ALPN -# endif - -# if HAVE_GNUTLS_OCSP_REQ_INIT -# define HAS_OCSP -# endif - -# if (GNUTLS_VERSION_NUMBER >= 0x030306) -# define HAS_CAPATH -# endif +#if !defined(GNUTLS_VERSION_NUMBER) || (GNUTLS_VERSION_NUMBER < 0x03010a) +#error "too old GnuTLS version" #endif -#if (GNUTLS_VERSION_NUMBER >= 0x030603) -#define HAS_TLS13 -#endif - -#ifdef HAS_OCSP # include <gnutls/ocsp.h> -#endif struct ssl_backend_data { gnutls_session_t session; @@ -111,58 +86,10 @@ struct ssl_backend_data { #endif }; -#define BACKEND connssl->backend - -/* - * Custom push and pull callback functions used by GNU TLS to read and write - * to the socket. These functions are simple wrappers to send() and recv() - * (although here using the sread/swrite macros as defined by - * curl_setup_once.h). - * We use custom functions rather than the GNU TLS defaults because it allows - * us to get specific about the fourth "flags" argument, and to use arbitrary - * private data with gnutls_transport_set_ptr if we wish. - * - * When these custom push and pull callbacks fail, GNU TLS checks its own - * session-specific error variable, and when not set also its own global - * errno variable, in order to take appropriate action. GNU TLS does not - * require that the transport is actually a socket. This implies that for - * Windows builds these callbacks should ideally set the session-specific - * error variable using function gnutls_transport_set_errno or as a last - * resort global errno variable using gnutls_transport_set_global_errno, - * with a transport agnostic error value. This implies that some winsock - * error translation must take place in these callbacks. - * - * Paragraph above applies to GNU TLS versions older than 2.12.3, since - * this version GNU TLS does its own internal winsock error translation - * using system_errno() function. - */ - -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) -# define gtls_EINTR 4 -# define gtls_EIO 5 -# define gtls_EAGAIN 11 -static int gtls_mapped_sockerrno(void) -{ - switch(SOCKERRNO) { - case WSAEWOULDBLOCK: - return gtls_EAGAIN; - case WSAEINTR: - return gtls_EINTR; - default: - break; - } - return gtls_EIO; -} -#endif - static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { curl_socket_t sock = *(curl_socket_t *)s; ssize_t ret = swrite(sock, buf, len); -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) - if(ret < 0) - gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); -#endif return ret; } @@ -170,10 +97,6 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { curl_socket_t sock = *(curl_socket_t *)s; ssize_t ret = sread(sock, buf, len); -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) - if(ret < 0) - gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); -#endif return ret; } @@ -284,7 +207,8 @@ static CURLcode handshake(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gnutls_session_t session = BACKEND->session; + struct ssl_backend_data *backend = connssl->backend; + gnutls_session_t session = backend->session; curl_socket_t sockfd = conn->sock[sockindex]; for(;;) { @@ -311,7 +235,7 @@ static CURLcode handshake(struct connectdata *conn, what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0: - timeout_ms?(time_t)timeout_ms:1000); + timeout_ms?timeout_ms:1000); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -383,51 +307,6 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type) return -1; } -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT -static CURLcode -set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - long i = ssl_version; - long protocol_priority_idx = 0; - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - case CURL_SSLVERSION_MAX_DEFAULT: -#ifdef HAS_TLS13 - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; -#endif - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - for(; i <= (ssl_version_max >> 16) && - protocol_priority_idx < list_size; ++i) { - switch(i) { - case CURL_SSLVERSION_TLSv1_0: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0; - break; - case CURL_SSLVERSION_TLSv1_1: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1; - break; - case CURL_SSLVERSION_TLSv1_2: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2; - break; - case CURL_SSLVERSION_TLSv1_3: -#ifdef HAS_TLS13 - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_3; - break; -#else - failf(data, "GnuTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; -#endif - } - } - return CURLE_OK; -} -#else #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" /* If GnuTLS was compiled without support for SRP it will error out if SRP is requested in the priority string, so treat it specially @@ -445,77 +324,59 @@ set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn) ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT; } switch(ssl_version | ssl_version_max) { - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: -#ifdef HAS_TLS13 - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.3:" GNUTLS_SRP; - return CURLE_OK; -#else - failf(data, "GnuTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; -#endif - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" -#ifdef HAS_TLS13 - "+VERS-TLS1.3:" -#endif - GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:+VERS-TLS1.2:" -#ifdef HAS_TLS13 - "+VERS-TLS1.3:" -#endif - GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2:" -#ifdef HAS_TLS13 - "+VERS-TLS1.3:" -#endif - GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2:" -#ifdef HAS_TLS13 - "+VERS-TLS1.3:" -#endif - GNUTLS_SRP; - return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1:+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2" + ":+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1:+VERS-TLS1.2" + ":+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2" + ":+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2" + ":+VERS-TLS1.3"; + return CURLE_OK; } failf(data, "GnuTLS: cannot set ssl protocol"); return CURLE_SSL_CONNECT_ERROR; } -#endif static CURLcode gtls_connect_step1(struct connectdata *conn, @@ -523,6 +384,7 @@ gtls_connect_step1(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; unsigned int init_flags; gnutls_session_t session; int rc; @@ -535,28 +397,12 @@ gtls_connect_step1(struct connectdata *conn, #else struct in_addr addr; #endif -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT - static const int cipher_priority[] = { - /* These two ciphers were added to GnuTLS as late as ver. 3.0.1, - but this code path is only ever used for ver. < 2.12.0. - GNUTLS_CIPHER_AES_128_GCM, - GNUTLS_CIPHER_AES_256_GCM, - */ - GNUTLS_CIPHER_AES_128_CBC, - GNUTLS_CIPHER_AES_256_CBC, - GNUTLS_CIPHER_CAMELLIA_128_CBC, - GNUTLS_CIPHER_CAMELLIA_256_CBC, - GNUTLS_CIPHER_3DES_CBC, - }; - static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; - int protocol_priority[] = { 0, 0, 0, 0 }; -#else const char *prioritylist; const char *err = NULL; -#endif - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; if(connssl->state == ssl_connection_complete) /* to make us tolerant against being called more than once for the @@ -566,6 +412,9 @@ gtls_connect_step1(struct connectdata *conn, if(!gtls_inited) Curl_gtls_init(); + /* Initialize certverifyresult to OK */ + *certverifyresult = 0; + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; @@ -574,7 +423,7 @@ gtls_connect_step1(struct connectdata *conn, sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ - rc = gnutls_certificate_allocate_credentials(&BACKEND->cred); + rc = gnutls_certificate_allocate_credentials(&backend->cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; @@ -585,14 +434,14 @@ gtls_connect_step1(struct connectdata *conn, infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); rc = gnutls_srp_allocate_client_credentials( - &BACKEND->srp_client_cred); + &backend->srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_allocate_client_cred() failed: %s", gnutls_strerror(rc)); return CURLE_OUT_OF_MEMORY; } - rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred, + rc = gnutls_srp_set_client_credentials(backend->srp_client_cred, SSL_SET_OPTION(username), SSL_SET_OPTION(password)); if(rc != GNUTLS_E_SUCCESS) { @@ -605,52 +454,54 @@ gtls_connect_step1(struct connectdata *conn, if(SSL_CONN_CONFIG(CAfile)) { /* set the trusted CA cert bundle file */ - gnutls_certificate_set_verify_flags(BACKEND->cred, + gnutls_certificate_set_verify_flags(backend->cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); - rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred, + rc = gnutls_certificate_set_x509_trust_file(backend->cred, SSL_CONN_CONFIG(CAfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc)); - if(SSL_CONN_CONFIG(verifypeer)) + if(SSL_CONN_CONFIG(verifypeer)) { + *certverifyresult = rc; return CURLE_SSL_CACERT_BADFILE; + } } else infof(data, "found %d certificates in %s\n", rc, SSL_CONN_CONFIG(CAfile)); } -#ifdef HAS_CAPATH if(SSL_CONN_CONFIG(CApath)) { /* set the trusted CA cert directory */ - rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred, + rc = gnutls_certificate_set_x509_trust_dir(backend->cred, SSL_CONN_CONFIG(CApath), GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", SSL_CONN_CONFIG(CApath), gnutls_strerror(rc)); - if(SSL_CONN_CONFIG(verifypeer)) + if(SSL_CONN_CONFIG(verifypeer)) { + *certverifyresult = rc; return CURLE_SSL_CACERT_BADFILE; + } } else infof(data, "found %d certificates in %s\n", rc, SSL_CONN_CONFIG(CApath)); } -#endif #ifdef CURL_CA_FALLBACK /* use system ca certificate store as fallback */ if(SSL_CONN_CONFIG(verifypeer) && !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) { - gnutls_certificate_set_x509_system_trust(BACKEND->cred); + gnutls_certificate_set_x509_system_trust(backend->cred); } #endif if(SSL_SET_OPTION(CRLfile)) { /* set the CRL list file */ - rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred, + rc = gnutls_certificate_set_x509_crl_file(backend->cred, SSL_SET_OPTION(CRLfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { @@ -675,14 +526,14 @@ gtls_connect_step1(struct connectdata *conn, init_flags |= GNUTLS_NO_TICKETS; #endif - rc = gnutls_init(&BACKEND->session, init_flags); + rc = gnutls_init(&backend->session, init_flags); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* convenient assign */ - session = BACKEND->session; + session = backend->session; if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 @@ -699,62 +550,6 @@ gtls_connect_step1(struct connectdata *conn, if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT - rc = gnutls_cipher_set_priority(session, cipher_priority); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - - /* Sets the priority on the certificate types supported by gnutls. Priority - is higher for types specified before others. After specifying the types - you want, you must append a 0. */ - rc = gnutls_certificate_type_set_priority(session, cert_type_priority); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - - if(SSL_CONN_CONFIG(cipher_list) != NULL) { - failf(data, "can't pass a custom cipher list to older GnuTLS" - " versions"); - return CURLE_SSL_CONNECT_ERROR; - } - - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_SSLv3: - protocol_priority[0] = GNUTLS_SSL3; - break; - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - protocol_priority[0] = GNUTLS_TLS1_0; - protocol_priority[1] = GNUTLS_TLS1_1; - protocol_priority[2] = GNUTLS_TLS1_2; -#ifdef HAS_TLS13 - protocol_priority[3] = GNUTLS_TLS1_3; -#endif - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(protocol_priority, - sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn); - if(result != CURLE_OK) - return result; - break; - } - case CURL_SSLVERSION_SSLv2: - failf(data, "GnuTLS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - rc = gnutls_protocol_set_priority(session, protocol_priority); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "Did you pass a valid GnuTLS cipher list?"); - return CURLE_SSL_CONNECT_ERROR; - } - -#else /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ @@ -764,11 +559,11 @@ gtls_connect_step1(struct connectdata *conn, break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" + prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0" #ifdef HAS_TLS13 - "+VERS-TLS1.3:" + ":+VERS-TLS1.3" #endif - GNUTLS_SRP; + ; break; case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: @@ -787,32 +582,39 @@ gtls_connect_step1(struct connectdata *conn, failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } - rc = gnutls_priority_set_direct(session, prioritylist, &err); - if((rc == GNUTLS_E_INVALID_REQUEST) && err) { - if(!strcmp(err, GNUTLS_SRP)) { - /* This GnuTLS was probably compiled without support for SRP. - * Note that fact and try again without it. */ - int validprioritylen = curlx_uztosi(err - prioritylist); - char *prioritycopy = strdup(prioritylist); - if(!prioritycopy) - return CURLE_OUT_OF_MEMORY; +#ifdef USE_TLS_SRP + /* Only add SRP to the cipher list if SRP is requested. Otherwise + * GnuTLS will disable TLS 1.3 support. */ + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { + size_t len = strlen(prioritylist); + + char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1); + if(!prioritysrp) + return CURLE_OUT_OF_MEMORY; + strcpy(prioritysrp, prioritylist); + strcpy(prioritysrp + len, ":" GNUTLS_SRP); + + rc = gnutls_priority_set_direct(session, prioritysrp, &err); + free(prioritysrp); + + if((rc == GNUTLS_E_INVALID_REQUEST) && err) { infof(data, "This GnuTLS does not support SRP\n"); - if(validprioritylen) - /* Remove the :+SRP */ - prioritycopy[validprioritylen - 1] = 0; - rc = gnutls_priority_set_direct(session, prioritycopy, &err); - free(prioritycopy); } } + else { +#endif + rc = gnutls_priority_set_direct(session, prioritylist, &err); +#ifdef USE_TLS_SRP + } +#endif + if(rc != GNUTLS_E_SUCCESS) { failf(data, "Error %d setting GnuTLS cipher list starting with %s", rc, err); return CURLE_SSL_CONNECT_ERROR; } -#endif -#ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { int cur = 0; gnutls_datum_t protocols[2]; @@ -834,18 +636,16 @@ gtls_connect_step1(struct connectdata *conn, gnutls_alpn_set_protocols(session, protocols, cur, 0); } -#endif if(SSL_SET_OPTION(cert)) { if(SSL_SET_OPTION(key_passwd)) { -#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 const unsigned int supported_key_encryption_algorithms = GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | GNUTLS_PKCS_USE_PBES2_AES_256; rc = gnutls_certificate_set_x509_key_file2( - BACKEND->cred, + backend->cred, SSL_SET_OPTION(cert), SSL_SET_OPTION(key) ? SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), @@ -858,14 +658,10 @@ gtls_connect_step1(struct connectdata *conn, gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } -#else - failf(data, "gnutls lacks support for encrypted key files"); - return CURLE_SSL_CONNECT_ERROR; -#endif } else { if(gnutls_certificate_set_x509_key_file( - BACKEND->cred, + backend->cred, SSL_SET_OPTION(cert), SSL_SET_OPTION(key) ? SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), @@ -881,7 +677,7 @@ gtls_connect_step1(struct connectdata *conn, /* put the credentials to the current session */ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, - BACKEND->srp_client_cred); + backend->srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; @@ -891,7 +687,7 @@ gtls_connect_step1(struct connectdata *conn, #endif { rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, - BACKEND->cred); + backend->cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; @@ -917,10 +713,6 @@ gtls_connect_step1(struct connectdata *conn, gnutls_transport_set_push_function(session, gnutls_transport_push); gnutls_transport_set_pull_function(session, gnutls_transport_pull); - /* lowat must be set to zero when using custom push and pull functions. */ - gnutls_transport_set_lowat(session, 0); - -#ifdef HAS_OCSP if(SSL_CONN_CONFIG(verifystatus)) { rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); if(rc != GNUTLS_E_SUCCESS) { @@ -928,7 +720,6 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } } -#endif /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ @@ -1020,17 +811,17 @@ gtls_connect_step3(struct connectdata *conn, unsigned int verify_status = 0; gnutls_x509_crt_t x509_cert, x509_issuer; gnutls_datum_t issuerp; - char certbuf[256] = ""; /* big enough? */ + gnutls_datum_t certfields; + char certname[65] = ""; /* limited to 64 chars by ASN.1 */ size_t size; time_t certclock; const char *ptr; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gnutls_session_t session = BACKEND->session; + struct ssl_backend_data *backend = connssl->backend; + gnutls_session_t session = backend->session; int rc; -#ifdef HAS_ALPN gnutls_datum_t proto; -#endif CURLcode result = CURLE_OK; #ifndef CURL_DISABLE_VERBOSE_STRINGS unsigned int algo; @@ -1039,6 +830,8 @@ gtls_connect_step3(struct connectdata *conn, #endif const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), @@ -1070,6 +863,7 @@ gtls_connect_step3(struct connectdata *conn, else { #endif failf(data, "failed to get server cert"); + *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND; return CURLE_PEER_FAILED_VERIFICATION; #ifdef USE_TLS_SRP } @@ -1106,9 +900,12 @@ gtls_connect_step3(struct connectdata *conn, rc = gnutls_certificate_verify_peers2(session, &verify_status); if(rc < 0) { failf(data, "server cert verify failed: %d", rc); + *certverifyresult = rc; return CURLE_SSL_CONNECT_ERROR; } + *certverifyresult = verify_status; + /* verify_status is a bitmask of gnutls_certificate_status bits */ if(verify_status & GNUTLS_CERT_INVALID) { if(SSL_CONN_CONFIG(verifypeer)) { @@ -1127,7 +924,6 @@ gtls_connect_step3(struct connectdata *conn, else infof(data, "\t server certificate verification SKIPPED\n"); -#ifdef HAS_OCSP if(SSL_CONN_CONFIG(verifystatus)) { if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { gnutls_datum_t status_request; @@ -1230,7 +1026,6 @@ gtls_connect_step3(struct connectdata *conn, } else infof(data, "\t server certificate status verification SKIPPED\n"); -#endif /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); @@ -1257,11 +1052,11 @@ gtls_connect_step3(struct connectdata *conn, SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); } - size = sizeof(certbuf); + size = sizeof(certname); rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, 0, /* the first and only one */ FALSE, - certbuf, + certname, &size); if(rc) { infof(data, "error fetching CN from cert:%s\n", @@ -1322,16 +1117,16 @@ gtls_connect_step3(struct connectdata *conn, if(SSL_CONN_CONFIG(verifyhost)) { failf(data, "SSL: certificate subject name (%s) does not match " - "target host name '%s'", certbuf, dispname); + "target host name '%s'", certname, dispname); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t common name: %s (does not match '%s')\n", - certbuf, dispname); + certname, dispname); } else - infof(data, "\t common name: %s (matched)\n", certbuf); + infof(data, "\t common name: %s (matched)\n", certname); /* Check for time-based validity */ certclock = gnutls_x509_crt_get_expiration_time(x509_cert); @@ -1339,6 +1134,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock == (time_t)-1) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert expiration date verify failed"); + *certverifyresult = GNUTLS_CERT_EXPIRED; gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; } @@ -1349,6 +1145,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock < time(NULL)) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate expiration date has passed."); + *certverifyresult = GNUTLS_CERT_EXPIRED; gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } @@ -1364,6 +1161,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock == (time_t)-1) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert activation date verify failed"); + *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; } @@ -1374,6 +1172,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock > time(NULL)) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate not activated yet."); + *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } @@ -1416,9 +1215,10 @@ gtls_connect_step3(struct connectdata *conn, gnutls_x509_crt_get_version(x509_cert)); - size = sizeof(certbuf); - gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); - infof(data, "\t subject: %s\n", certbuf); + rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields); + if(rc != 0) + return CURLE_OUT_OF_MEMORY; + infof(data, "\t subject: %s\n", certfields.data); certclock = gnutls_x509_crt_get_activation_time(x509_cert); showtime(data, "start date", certclock); @@ -1426,14 +1226,14 @@ gtls_connect_step3(struct connectdata *conn, certclock = gnutls_x509_crt_get_expiration_time(x509_cert); showtime(data, "expire date", certclock); - size = sizeof(certbuf); - gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); - infof(data, "\t issuer: %s\n", certbuf); + rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields); + if(rc != 0) + return CURLE_OUT_OF_MEMORY; + infof(data, "\t issuer: %s\n", certfields.data); #endif gnutls_x509_crt_deinit(x509_cert); -#ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { rc = gnutls_alpn_get_selected_protocol(session, &proto); if(rc == 0) { @@ -1459,7 +1259,6 @@ gtls_connect_step3(struct connectdata *conn, Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } -#endif conn->ssl[sockindex].state = ssl_connection_complete; conn->recv[sockindex] = gtls_recv; @@ -1577,13 +1376,14 @@ static bool Curl_gtls_data_pending(const struct connectdata *conn, { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; bool res = FALSE; - if(BACKEND->session && - 0 != gnutls_record_check_pending(BACKEND->session)) + struct ssl_backend_data *backend = connssl->backend; + if(backend->session && + 0 != gnutls_record_check_pending(backend->session)) res = TRUE; connssl = &conn->proxy_ssl[connindex]; - if(BACKEND->session && - 0 != gnutls_record_check_pending(BACKEND->session)) + if(backend->session && + 0 != gnutls_record_check_pending(backend->session)) res = TRUE; return res; @@ -1596,7 +1396,8 @@ static ssize_t gtls_send(struct connectdata *conn, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - ssize_t rc = gnutls_record_send(BACKEND->session, mem, len); + struct ssl_backend_data *backend = connssl->backend; + ssize_t rc = gnutls_record_send(backend->session, mem, len); if(rc < 0) { *curlcode = (rc == GNUTLS_E_AGAIN) @@ -1611,19 +1412,20 @@ static ssize_t gtls_send(struct connectdata *conn, static void close_one(struct ssl_connect_data *connssl) { - if(BACKEND->session) { - gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); - gnutls_deinit(BACKEND->session); - BACKEND->session = NULL; + struct ssl_backend_data *backend = connssl->backend; + if(backend->session) { + gnutls_bye(backend->session, GNUTLS_SHUT_WR); + gnutls_deinit(backend->session); + backend->session = NULL; } - if(BACKEND->cred) { - gnutls_certificate_free_credentials(BACKEND->cred); - BACKEND->cred = NULL; + if(backend->cred) { + gnutls_certificate_free_credentials(backend->cred); + backend->cred = NULL; } #ifdef USE_TLS_SRP - if(BACKEND->srp_client_cred) { - gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); - BACKEND->srp_client_cred = NULL; + if(backend->srp_client_cred) { + gnutls_srp_free_client_credentials(backend->srp_client_cred); + backend->srp_client_cred = NULL; } #endif } @@ -1641,6 +1443,7 @@ static void Curl_gtls_close(struct connectdata *conn, int sockindex) static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; int retval = 0; struct Curl_easy *data = conn->data; @@ -1651,10 +1454,10 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) we do not send one. Let's hope other servers do the same... */ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); + gnutls_bye(backend->session, GNUTLS_SHUT_WR); #endif - if(BACKEND->session) { + if(backend->session) { ssize_t result; bool done = FALSE; char buf[120]; @@ -1665,7 +1468,7 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ - result = gnutls_record_recv(BACKEND->session, + result = gnutls_record_recv(backend->session, buf, sizeof(buf)); switch(result) { case 0: @@ -1695,18 +1498,18 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) done = TRUE; } } - gnutls_deinit(BACKEND->session); + gnutls_deinit(backend->session); } - gnutls_certificate_free_credentials(BACKEND->cred); + gnutls_certificate_free_credentials(backend->cred); #ifdef USE_TLS_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP && SSL_SET_OPTION(username) != NULL) - gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); + gnutls_srp_free_client_credentials(backend->srp_client_cred); #endif - BACKEND->cred = NULL; - BACKEND->session = NULL; + backend->cred = NULL; + backend->session = NULL; return retval; } @@ -1718,9 +1521,10 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; ssize_t ret; - ret = gnutls_record_recv(BACKEND->session, buf, buffersize); + ret = gnutls_record_recv(backend->session, buf, buffersize); if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { *curlcode = CURLE_AGAIN; return -1; @@ -1836,18 +1640,15 @@ static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ static bool Curl_gtls_cert_status_request(void) { -#ifdef HAS_OCSP return TRUE; -#else - return FALSE; -#endif } static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->session; + return backend->session; } const struct Curl_ssl Curl_ssl_gnutls = { diff --git a/Utilities/cmcurl/lib/vtls/keylog.c b/Utilities/cmcurl/lib/vtls/keylog.c new file mode 100644 index 0000000..70d22ec --- /dev/null +++ b/Utilities/cmcurl/lib/vtls/keylog.c @@ -0,0 +1,156 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#include "keylog.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1) + +#define CLIENT_RANDOM_SIZE 32 + +/* + * The master secret in TLS 1.2 and before is always 48 bytes. In TLS 1.3, the + * secret size depends on the cipher suite's hash function which is 32 bytes + * for SHA-256 and 48 bytes for SHA-384. + */ +#define SECRET_MAXLEN 48 + + +/* The fp for the open SSLKEYLOGFILE, or NULL if not open */ +static FILE *keylog_file_fp; + +void +Curl_tls_keylog_open(void) +{ + char *keylog_file_name; + + if(!keylog_file_fp) { + keylog_file_name = curl_getenv("SSLKEYLOGFILE"); + if(keylog_file_name) { + keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); + if(keylog_file_fp) { +#ifdef WIN32 + if(setvbuf(keylog_file_fp, NULL, _IONBF, 0)) +#else + if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) +#endif + { + fclose(keylog_file_fp); + keylog_file_fp = NULL; + } + } + Curl_safefree(keylog_file_name); + } + } +} + +void +Curl_tls_keylog_close(void) +{ + if(keylog_file_fp) { + fclose(keylog_file_fp); + keylog_file_fp = NULL; + } +} + +bool +Curl_tls_keylog_enabled(void) +{ + return keylog_file_fp != NULL; +} + +bool +Curl_tls_keylog_write_line(const char *line) +{ + /* The current maximum valid keylog line length LF and NUL is 195. */ + size_t linelen; + char buf[256]; + + if(!keylog_file_fp || !line) { + return false; + } + + linelen = strlen(line); + if(linelen == 0 || linelen > sizeof(buf) - 2) { + /* Empty line or too big to fit in a LF and NUL. */ + return false; + } + + memcpy(buf, line, linelen); + if(line[linelen - 1] != '\n') { + buf[linelen++] = '\n'; + } + buf[linelen] = '\0'; + + /* Using fputs here instead of fprintf since libcurl's fprintf replacement + may not be thread-safe. */ + fputs(buf, keylog_file_fp); + return true; +} + +bool +Curl_tls_keylog_write(const char *label, + const unsigned char client_random[CLIENT_RANDOM_SIZE], + const unsigned char *secret, size_t secretlen) +{ + const char *hex = "0123456789ABCDEF"; + size_t pos, i; + char line[KEYLOG_LABEL_MAXLEN + 1 + 2 * CLIENT_RANDOM_SIZE + 1 + + 2 * SECRET_MAXLEN + 1 + 1]; + + if(!keylog_file_fp) { + return false; + } + + pos = strlen(label); + if(pos > KEYLOG_LABEL_MAXLEN || !secretlen || secretlen > SECRET_MAXLEN) { + /* Should never happen - sanity check anyway. */ + return false; + } + + memcpy(line, label, pos); + line[pos++] = ' '; + + /* Client Random */ + for(i = 0; i < CLIENT_RANDOM_SIZE; i++) { + line[pos++] = hex[client_random[i] >> 4]; + line[pos++] = hex[client_random[i] & 0xF]; + } + line[pos++] = ' '; + + /* Secret */ + for(i = 0; i < secretlen; i++) { + line[pos++] = hex[secret[i] >> 4]; + line[pos++] = hex[secret[i] & 0xF]; + } + line[pos++] = '\n'; + line[pos] = '\0'; + + /* Using fputs here instead of fprintf since libcurl's fprintf replacement + may not be thread-safe. */ + fputs(line, keylog_file_fp); + return true; +} diff --git a/Utilities/cmcurl/lib/vtls/keylog.h b/Utilities/cmcurl/lib/vtls/keylog.h new file mode 100644 index 0000000..c6b99db --- /dev/null +++ b/Utilities/cmcurl/lib/vtls/keylog.h @@ -0,0 +1,56 @@ +#ifndef HEADER_CURL_KEYLOG_H +#define HEADER_CURL_KEYLOG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +/* + * Opens the TLS key log file if requested by the user. The SSLKEYLOGFILE + * environment variable specifies the output file. + */ +void Curl_tls_keylog_open(void); + +/* + * Closes the TLS key log file if not already. + */ +void Curl_tls_keylog_close(void); + +/* + * Returns true if the user successfully enabled the TLS key log file. + */ +bool Curl_tls_keylog_enabled(void); + +/* + * Appends a key log file entry. + * Returns true iff the key log file is open and a valid entry was provided. + */ +bool Curl_tls_keylog_write(const char *label, + const unsigned char client_random[32], + const unsigned char *secret, size_t secretlen); + +/* + * Appends a line to the key log file, ensure it is terminated by a LF. + * Returns true iff the key log file is open and a valid line was provided. + */ +bool Curl_tls_keylog_write_line(const char *line); + +#endif /* HEADER_CURL_KEYLOG_H */ diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c index f057315..ba31b8e 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls.c @@ -75,8 +75,6 @@ struct ssl_backend_data { const char *protocols[3]; }; -#define BACKEND connssl->backend - /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) #define THREADING_SUPPORT @@ -196,6 +194,7 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; long ssl_version = SSL_CONN_CONFIG(version); @@ -227,9 +226,9 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) return result; } - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, mbedtls_ver_min); - mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, mbedtls_ver_max); return result; @@ -240,7 +239,8 @@ mbed_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); @@ -261,9 +261,9 @@ mbed_connect_step1(struct connectdata *conn, #ifdef THREADING_SUPPORT entropy_init_mutex(&ts_entropy); - mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); + mbedtls_ctr_drbg_init(&backend->ctr_drbg); - ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, entropy_func_mutex, + ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex, &ts_entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C @@ -273,11 +273,11 @@ mbed_connect_step1(struct connectdata *conn, -ret, errorbuf); } #else - mbedtls_entropy_init(&BACKEND->entropy); - mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); + mbedtls_entropy_init(&backend->entropy); + mbedtls_ctr_drbg_init(&backend->ctr_drbg); - ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, mbedtls_entropy_func, - &BACKEND->entropy, NULL, 0); + ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func, + &backend->entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -288,10 +288,10 @@ mbed_connect_step1(struct connectdata *conn, #endif /* THREADING_SUPPORT */ /* Load the trusted CA */ - mbedtls_x509_crt_init(&BACKEND->cacert); + mbedtls_x509_crt_init(&backend->cacert); if(ssl_cafile) { - ret = mbedtls_x509_crt_parse_file(&BACKEND->cacert, ssl_cafile); + ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile); if(ret<0) { #ifdef MBEDTLS_ERROR_C @@ -306,7 +306,7 @@ mbed_connect_step1(struct connectdata *conn, } if(ssl_capath) { - ret = mbedtls_x509_crt_parse_path(&BACKEND->cacert, ssl_capath); + ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath); if(ret<0) { #ifdef MBEDTLS_ERROR_C @@ -321,10 +321,10 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the client certificate */ - mbedtls_x509_crt_init(&BACKEND->clicert); + mbedtls_x509_crt_init(&backend->clicert); if(ssl_cert) { - ret = mbedtls_x509_crt_parse_file(&BACKEND->clicert, ssl_cert); + ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert); if(ret) { #ifdef MBEDTLS_ERROR_C @@ -338,13 +338,13 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the client private key */ - mbedtls_pk_init(&BACKEND->pk); + mbedtls_pk_init(&backend->pk); if(SSL_SET_OPTION(key)) { - ret = mbedtls_pk_parse_keyfile(&BACKEND->pk, SSL_SET_OPTION(key), + ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key), SSL_SET_OPTION(key_passwd)); - if(ret == 0 && !(mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA) || - mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_ECKEY))) + if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || + mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; if(ret) { @@ -359,10 +359,10 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the CRL */ - mbedtls_x509_crl_init(&BACKEND->crl); + mbedtls_x509_crl_init(&backend->crl); if(ssl_crlfile) { - ret = mbedtls_x509_crl_parse_file(&BACKEND->crl, ssl_crlfile); + ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile); if(ret) { #ifdef MBEDTLS_ERROR_C @@ -377,14 +377,14 @@ mbed_connect_step1(struct connectdata *conn, infof(data, "mbedTLS: Connecting to %s:%ld\n", hostname, port); - mbedtls_ssl_config_init(&BACKEND->config); + mbedtls_ssl_config_init(&backend->config); - mbedtls_ssl_init(&BACKEND->ssl); - if(mbedtls_ssl_setup(&BACKEND->ssl, &BACKEND->config)) { + mbedtls_ssl_init(&backend->ssl); + if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) { failf(data, "mbedTLS: ssl_init failed"); return CURLE_SSL_CONNECT_ERROR; } - ret = mbedtls_ssl_config_defaults(&BACKEND->config, + ret = mbedtls_ssl_config_defaults(&backend->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); @@ -394,20 +394,20 @@ mbed_connect_step1(struct connectdata *conn, } /* new profile with RSA min key len = 1024 ... */ - mbedtls_ssl_conf_cert_profile(&BACKEND->config, + mbedtls_ssl_conf_cert_profile(&backend->config, &mbedtls_x509_crt_profile_fr); switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1); infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n"); break; case CURL_SSLVERSION_SSLv3: - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); - mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); infof(data, "mbedTLS: Set SSL version to SSLv3\n"); break; @@ -426,25 +426,25 @@ mbed_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - mbedtls_ssl_conf_authmode(&BACKEND->config, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL); - mbedtls_ssl_conf_rng(&BACKEND->config, mbedtls_ctr_drbg_random, - &BACKEND->ctr_drbg); - mbedtls_ssl_set_bio(&BACKEND->ssl, &conn->sock[sockindex], + mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random, + &backend->ctr_drbg); + mbedtls_ssl_set_bio(&backend->ssl, &conn->sock[sockindex], mbedtls_net_send, mbedtls_net_recv, NULL /* rev_timeout() */); - mbedtls_ssl_conf_ciphersuites(&BACKEND->config, + mbedtls_ssl_conf_ciphersuites(&backend->config, mbedtls_ssl_list_ciphersuites()); #if defined(MBEDTLS_SSL_RENEGOTIATION) - mbedtls_ssl_conf_renegotiation(&BACKEND->config, + mbedtls_ssl_conf_renegotiation(&backend->config, MBEDTLS_SSL_RENEGOTIATION_ENABLED); #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) - mbedtls_ssl_conf_session_tickets(&BACKEND->config, + mbedtls_ssl_conf_session_tickets(&backend->config, MBEDTLS_SSL_SESSION_TICKETS_DISABLED); #endif @@ -454,7 +454,7 @@ mbed_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { - ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session); + ret = mbedtls_ssl_set_session(&backend->ssl, old_session); if(ret) { Curl_ssl_sessionid_unlock(conn); failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); @@ -465,15 +465,15 @@ mbed_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_unlock(conn); } - mbedtls_ssl_conf_ca_chain(&BACKEND->config, - &BACKEND->cacert, - &BACKEND->crl); + mbedtls_ssl_conf_ca_chain(&backend->config, + &backend->cacert, + &backend->crl); if(SSL_SET_OPTION(key)) { - mbedtls_ssl_conf_own_cert(&BACKEND->config, - &BACKEND->clicert, &BACKEND->pk); + mbedtls_ssl_conf_own_cert(&backend->config, + &backend->clicert, &backend->pk); } - if(mbedtls_ssl_set_hostname(&BACKEND->ssl, hostname)) { + if(mbedtls_ssl_set_hostname(&backend->ssl, hostname)) { /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name to set in the SNI extension. So even if curl connects to a host specified as an IP address, this function must be used. */ @@ -483,7 +483,7 @@ mbed_connect_step1(struct connectdata *conn, #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { - const char **p = &BACKEND->protocols[0]; + const char **p = &backend->protocols[0]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) *p++ = NGHTTP2_PROTO_VERSION_ID; @@ -492,19 +492,19 @@ mbed_connect_step1(struct connectdata *conn, *p = NULL; /* this function doesn't clone the protocols array, which is why we need to keep it around */ - if(mbedtls_ssl_conf_alpn_protocols(&BACKEND->config, - &BACKEND->protocols[0])) { + if(mbedtls_ssl_conf_alpn_protocols(&backend->config, + &backend->protocols[0])) { failf(data, "Failed setting ALPN protocols"); return CURLE_SSL_CONNECT_ERROR; } - for(p = &BACKEND->protocols[0]; *p; ++p) + for(p = &backend->protocols[0]; *p; ++p) infof(data, "ALPN, offering %s\n", *p); } #endif #ifdef MBEDTLS_DEBUG /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ - mbedtls_ssl_conf_dbg(&BACKEND->config, mbed_debug, data); + mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data); /* - 0 No debug * - 1 Error * - 2 State change @@ -516,7 +516,7 @@ mbed_connect_step1(struct connectdata *conn, /* give application a chance to interfere with mbedTLS set up. */ if(data->set.ssl.fsslctx) { - ret = (*data->set.ssl.fsslctx)(data, &BACKEND->config, + ret = (*data->set.ssl.fsslctx)(data, &backend->config, data->set.ssl.fsslctxp); if(ret) { failf(data, "error signaled by ssl ctx callback"); @@ -535,16 +535,17 @@ mbed_connect_step2(struct connectdata *conn, { int ret; struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const mbedtls_x509_crt *peercert; const char * const pinnedpubkey = SSL_IS_PROXY() ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; conn->recv[sockindex] = mbed_recv; conn->send[sockindex] = mbed_send; - ret = mbedtls_ssl_handshake(&BACKEND->ssl); + ret = mbedtls_ssl_handshake(&backend->ssl); if(ret == MBEDTLS_ERR_SSL_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; @@ -566,10 +567,10 @@ mbed_connect_step2(struct connectdata *conn, } infof(data, "mbedTLS: Handshake complete, cipher is %s\n", - mbedtls_ssl_get_ciphersuite(&BACKEND->ssl) + mbedtls_ssl_get_ciphersuite(&backend->ssl) ); - ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl); + ret = mbedtls_ssl_get_verify_result(&backend->ssl); if(!SSL_CONN_CONFIG(verifyhost)) /* Ignore hostname errors if verifyhost is disabled */ @@ -594,7 +595,7 @@ mbed_connect_step2(struct connectdata *conn, return CURLE_PEER_FAILED_VERIFICATION; } - peercert = mbedtls_ssl_get_peer_cert(&BACKEND->ssl); + peercert = mbedtls_ssl_get_peer_cert(&backend->ssl); if(peercert && data->set.verbose) { const size_t bufsize = 16384; @@ -664,7 +665,7 @@ mbed_connect_step2(struct connectdata *conn, #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { - const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl); + const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl); if(next_protocol) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); @@ -701,6 +702,7 @@ mbed_connect_step3(struct connectdata *conn, { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; struct Curl_easy *data = conn->data; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -716,7 +718,7 @@ mbed_connect_step3(struct connectdata *conn, mbedtls_ssl_session_init(our_ssl_sessionid); - ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid); + ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid); if(ret) { if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED) mbedtls_ssl_session_free(our_ssl_sessionid); @@ -750,9 +752,10 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; int ret = -1; - ret = mbedtls_ssl_write(&BACKEND->ssl, + ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len); if(ret < 0) { @@ -772,15 +775,16 @@ static void Curl_mbedtls_close_all(struct Curl_easy *data) static void Curl_mbedtls_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - mbedtls_pk_free(&BACKEND->pk); - mbedtls_x509_crt_free(&BACKEND->clicert); - mbedtls_x509_crt_free(&BACKEND->cacert); - mbedtls_x509_crl_free(&BACKEND->crl); - mbedtls_ssl_config_free(&BACKEND->config); - mbedtls_ssl_free(&BACKEND->ssl); - mbedtls_ctr_drbg_free(&BACKEND->ctr_drbg); + struct ssl_backend_data *backend = connssl->backend; + mbedtls_pk_free(&backend->pk); + mbedtls_x509_crt_free(&backend->clicert); + mbedtls_x509_crt_free(&backend->cacert); + mbedtls_x509_crl_free(&backend->crl); + mbedtls_ssl_config_free(&backend->config); + mbedtls_ssl_free(&backend->ssl); + mbedtls_ctr_drbg_free(&backend->ctr_drbg); #ifndef THREADING_SUPPORT - mbedtls_entropy_free(&BACKEND->entropy); + mbedtls_entropy_free(&backend->entropy); #endif /* THREADING_SUPPORT */ } @@ -789,11 +793,12 @@ static ssize_t mbed_recv(struct connectdata *conn, int num, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; int ret = -1; ssize_t len = -1; memset(buf, 0, buffersize); - ret = mbedtls_ssl_read(&BACKEND->ssl, (unsigned char *)buf, + ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, buffersize); if(ret <= 0) { @@ -933,7 +938,7 @@ mbed_connect_common(struct connectdata *conn, connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : (time_t)timeout_ms); + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -1029,7 +1034,8 @@ static bool Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex) { const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0; + struct ssl_backend_data *backend = connssl->backend; + return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0; } static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input, @@ -1051,8 +1057,9 @@ static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input, static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return &BACKEND->ssl; + return &backend->ssl; } const struct Curl_ssl Curl_ssl_mbedtls = { diff --git a/Utilities/cmcurl/lib/vtls/mesalink.c b/Utilities/cmcurl/lib/vtls/mesalink.c index cab1e39..7132bdf 100644 --- a/Utilities/cmcurl/lib/vtls/mesalink.c +++ b/Utilities/cmcurl/lib/vtls/mesalink.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2017 - 2018, Yiming Jing, <jingyiming@baidu.com> - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -542,9 +542,8 @@ mesalink_connect_common(struct connectdata *conn, int sockindex, ? sockfd : CURL_SOCKET_BAD; - what = Curl_socket_check( - readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : (time_t)timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index ef51b0d..fca2926 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -87,8 +87,6 @@ struct ssl_backend_data { PK11GenericObject *obj_clicert; }; -#define BACKEND connssl->backend - static PRLock *nss_initlock = NULL; static PRLock *nss_crllock = NULL; static PRLock *nss_findslot_lock = NULL; @@ -103,10 +101,10 @@ struct ptr_list_wrap { struct curl_llist_element node; }; -typedef struct { +struct cipher_s { const char *name; int num; -} cipher_s; +}; #define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \ CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \ @@ -118,7 +116,7 @@ typedef struct { #define CERT_NewTempCertificate __CERT_NewTempCertificate #define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0]) -static const cipher_s cipherlist[] = { +static const struct cipher_s cipherlist[] = { /* SSL2 cipher suites */ {"rc4", SSL_EN_RC4_128_WITH_MD5}, {"rc4-md5", SSL_EN_RC4_128_WITH_MD5}, @@ -462,6 +460,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl, const int slot_id = (cacert) ? 0 : 1; char *slot_name = aprintf("PEM Token #%d", slot_id); + struct ssl_backend_data *backend = connssl->backend; if(!slot_name) return CURLE_OUT_OF_MEMORY; @@ -495,14 +494,14 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl, if(!obj) return result; - if(insert_wrapped_ptr(&BACKEND->obj_list, obj) != CURLE_OK) { + if(insert_wrapped_ptr(&backend->obj_list, obj) != CURLE_OK) { PK11_DestroyGenericObject(obj); return CURLE_OUT_OF_MEMORY; } if(!cacert && CKO_CERTIFICATE == obj_class) /* store reference to a client certificate */ - BACKEND->obj_clicert = obj; + backend->obj_clicert = obj; return CURLE_OK; } @@ -1084,7 +1083,8 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, const char *pinnedpubkey) { CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - struct Curl_easy *data = BACKEND->data; + struct ssl_backend_data *backend = connssl->backend; + struct Curl_easy *data = backend->data; CERTCertificate *cert; if(!pinnedpubkey) @@ -1092,7 +1092,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, return CURLE_OK; /* get peer certificate */ - cert = SSL_PeerCertificate(BACKEND->handle); + cert = SSL_PeerCertificate(backend->handle); if(cert) { /* extract public key from peer certificate */ SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert); @@ -1136,11 +1136,12 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct SECKEYPrivateKeyStr **pRetKey) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; - struct Curl_easy *data = BACKEND->data; - const char *nickname = BACKEND->client_nickname; + struct ssl_backend_data *backend = connssl->backend; + struct Curl_easy *data = backend->data; + const char *nickname = backend->client_nickname; static const char pem_slotname[] = "PEM Token #1"; - if(BACKEND->obj_clicert) { + if(backend->obj_clicert) { /* use the cert/key provided by PEM reader */ SECItem cert_der = { 0, NULL, 0 }; void *proto_win = SSL_RevealPinArg(sock); @@ -1153,7 +1154,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, return SECFailure; } - if(PK11_ReadRawAttribute(PK11_TypeGeneric, BACKEND->obj_clicert, CKA_VALUE, + if(PK11_ReadRawAttribute(PK11_TypeGeneric, backend->obj_clicert, CKA_VALUE, &cert_der) != SECSuccess) { failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); PK11_FreeSlot(slot); @@ -1503,11 +1504,12 @@ static void Curl_nss_cleanup(void) static int Curl_nss_check_cxn(struct connectdata *conn) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + struct ssl_backend_data *backend = connssl->backend; int rc; char buf; rc = - PR_Recv(BACKEND->handle, (void *)&buf, 1, PR_MSG_PEEK, + PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK, PR_SecondsToInterval(1)); if(rc > 0) return 1; /* connection still in place */ @@ -1521,26 +1523,27 @@ static int Curl_nss_check_cxn(struct connectdata *conn) static void nss_close(struct ssl_connect_data *connssl) { /* before the cleanup, check whether we are using a client certificate */ - const bool client_cert = (BACKEND->client_nickname != NULL) - || (BACKEND->obj_clicert != NULL); + struct ssl_backend_data *backend = connssl->backend; + const bool client_cert = (backend->client_nickname != NULL) + || (backend->obj_clicert != NULL); - free(BACKEND->client_nickname); - BACKEND->client_nickname = NULL; + free(backend->client_nickname); + backend->client_nickname = NULL; /* destroy all NSS objects in order to avoid failure of NSS shutdown */ - Curl_llist_destroy(&BACKEND->obj_list, NULL); - BACKEND->obj_clicert = NULL; + Curl_llist_destroy(&backend->obj_list, NULL); + backend->obj_clicert = NULL; - if(BACKEND->handle) { + if(backend->handle) { if(client_cert) /* A server might require different authentication based on the * particular path being requested by the client. To support this * scenario, we must ensure that a connection will never reuse the * authentication data from a previous connection. */ - SSL_InvalidateSession(BACKEND->handle); + SSL_InvalidateSession(backend->handle); - PR_Close(BACKEND->handle); - BACKEND->handle = NULL; + PR_Close(backend->handle); + backend->handle = NULL; } } @@ -1551,15 +1554,16 @@ static void Curl_nss_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; - if(BACKEND->handle || connssl_proxy->backend->handle) { + if(backend->handle || connssl_proxy->backend->handle) { /* NSS closes the socket we previously handed to it, so we must mark it as closed to avoid double close */ fake_sclose(conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; } - if(BACKEND->handle) + if(backend->handle) /* nss_close(connssl) will transitively close also connssl_proxy->backend->handle if both are used. Clear it to avoid a double close leading to crash. */ @@ -1773,6 +1777,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, CURLcode curlerr) { PRErrorCode err = 0; + struct ssl_backend_data *backend = connssl->backend; if(is_nss_error(curlerr)) { /* read NSPR error code */ @@ -1788,7 +1793,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, } /* cleanup on connection failure */ - Curl_llist_destroy(&BACKEND->obj_list, NULL); + Curl_llist_destroy(&backend->obj_list, NULL); return curlerr; } @@ -1799,10 +1804,11 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl, bool blocking) { static PRSocketOptionData sock_opt; + struct ssl_backend_data *backend = connssl->backend; sock_opt.option = PR_SockOpt_Nonblocking; sock_opt.value.non_blocking = !blocking; - if(PR_SetSocketOption(BACKEND->handle, &sock_opt) != PR_SUCCESS) + if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS) return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); return CURLE_OK; @@ -1818,6 +1824,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CURLcode result; bool second_layer = FALSE; SSLVersionRange sslver_supported; @@ -1835,10 +1842,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) #endif }; - BACKEND->data = data; + backend->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ - Curl_llist_init(&BACKEND->obj_list, nss_destroy_object); + Curl_llist_init(&backend->obj_list, nss_destroy_object); PR_Lock(nss_initlock); result = nss_init(conn->data); @@ -1960,7 +1967,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) char *nickname = dup_nickname(data, SSL_SET_OPTION(cert)); if(nickname) { /* we are not going to use libnsspem.so to read the client cert */ - BACKEND->obj_clicert = NULL; + backend->obj_clicert = NULL; } else { CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert), @@ -1973,10 +1980,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } /* store the nickname for SelectClientCert() called during handshake */ - BACKEND->client_nickname = nickname; + backend->client_nickname = nickname; } else - BACKEND->client_nickname = NULL; + backend->client_nickname = NULL; if(SSL_GetClientAuthDataHook(model, SelectClientCert, (void *)connssl) != SECSuccess) { @@ -2017,8 +2024,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } /* import our model socket onto the current I/O stack */ - BACKEND->handle = SSL_ImportFD(model, nspr_io); - if(!BACKEND->handle) { + backend->handle = SSL_ImportFD(model, nspr_io); + if(!backend->handle) { if(!second_layer) PR_Close(nspr_io); goto error; @@ -2029,36 +2036,36 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* This is the password associated with the cert that we're using */ if(SSL_SET_OPTION(key_passwd)) { - SSL_SetPKCS11PinArg(BACKEND->handle, SSL_SET_OPTION(key_passwd)); + SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd)); } #ifdef SSL_ENABLE_OCSP_STAPLING if(SSL_CONN_CONFIG(verifystatus)) { - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) + if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) != SECSuccess) goto error; } #endif #ifdef SSL_ENABLE_NPN - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn + if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif #ifdef SSL_ENABLE_ALPN - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn + if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif #if NSSVERNUM >= 0x030f04 /* 3.15.4 */ if(data->set.ssl.falsestart) { - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_FALSE_START, PR_TRUE) + if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE) != SECSuccess) goto error; - if(SSL_SetCanFalseStartCallback(BACKEND->handle, CanFalseStartCallback, + if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback, conn) != SECSuccess) goto error; } @@ -2082,24 +2089,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); cur += ALPN_HTTP_1_1_LENGTH; - if(SSL_SetNextProtoNego(BACKEND->handle, protocols, cur) != SECSuccess) + if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess) goto error; } #endif /* Force handshake on next I/O */ - if(SSL_ResetHandshake(BACKEND->handle, /* asServer */ PR_FALSE) + if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE) != SECSuccess) goto error; /* propagate hostname to the TLS layer */ - if(SSL_SetURL(BACKEND->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : + if(SSL_SetURL(backend->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name) != SECSuccess) goto error; /* prevent NSS from re-using the session for a different hostname */ - if(SSL_SetSockPeerID(BACKEND->handle, SSL_IS_PROXY() ? + if(SSL_SetSockPeerID(backend->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name) != SECSuccess) goto error; @@ -2116,6 +2123,7 @@ error: static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; struct Curl_easy *data = conn->data; CURLcode result = CURLE_SSL_CONNECT_ERROR; PRUint32 timeout; @@ -2136,7 +2144,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) /* Force the handshake now */ timeout = PR_MillisecondsToInterval((PRUint32) time_left); - if(SSL_ForceHandshakeWithTimeout(BACKEND->handle, timeout) != SECSuccess) { + if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) { if(PR_GetError() == PR_WOULD_BLOCK_ERROR) /* blocking direction is updated by nss_update_connecting_state() */ return CURLE_AGAIN; @@ -2147,7 +2155,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) goto error; } - result = display_conn_info(conn, BACKEND->handle); + result = display_conn_info(conn, backend->handle); if(result) goto error; @@ -2156,7 +2164,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); if(nickname) { /* we support only nicknames in case of issuercert for now */ - ret = check_issuer_cert(BACKEND->handle, nickname); + ret = check_issuer_cert(backend->handle, nickname); free(nickname); } @@ -2260,13 +2268,14 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; ssize_t rc; /* The SelectClientCert() hook uses this for infof() and failf() but the handle stored in nss_setup_connect() could have already been freed. */ - BACKEND->data = conn->data; + backend->data = conn->data; - rc = PR_Send(BACKEND->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT); + rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT); if(rc < 0) { PRInt32 err = PR_GetError(); if(err == PR_WOULD_BLOCK_ERROR) @@ -2297,13 +2306,14 @@ static ssize_t nss_recv(struct connectdata *conn, /* connection data */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; ssize_t nread; /* The SelectClientCert() hook uses this for infof() and failf() but the handle stored in nss_setup_connect() could have already been freed. */ - BACKEND->data = conn->data; + backend->data = conn->data; - nread = PR_Recv(BACKEND->handle, buf, (int)buffersize, 0, + nread = PR_Recv(backend->handle, buf, (int)buffersize, 0, PR_INTERVAL_NO_WAIT); if(nread < 0) { /* failed SSL read */ @@ -2364,6 +2374,9 @@ static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */ PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); unsigned int MD5out; + if(!MD5pw) + return CURLE_NOT_BUILT_IN; + PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen)); PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len)); PK11_DestroyContext(MD5pw, PR_TRUE); @@ -2379,6 +2392,9 @@ static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */ PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256); unsigned int SHA256out; + if(!SHA256pw) + return CURLE_NOT_BUILT_IN; + PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen)); PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len)); PK11_DestroyContext(SHA256pw, PR_TRUE); @@ -2407,8 +2423,9 @@ static bool Curl_nss_false_start(void) static void *Curl_nss_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->handle; + return backend->handle; } const struct Curl_ssl Curl_ssl_nss = { diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index 1d09cad..790d358 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -41,11 +41,17 @@ #include "slist.h" #include "select.h" #include "vtls.h" +#include "keylog.h" #include "strcase.h" #include "hostcheck.h" #include "multiif.h" #include "strerror.h" #include "curl_printf.h" + +#if defined(USE_WIN32_CRYPTO) +#include <wincrypt.h> +#endif + #include <openssl/ssl.h> #include <openssl/rand.h> #include <openssl/x509v3.h> @@ -207,29 +213,17 @@ "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" #endif -#define ENABLE_SSLKEYLOGFILE - -#ifdef ENABLE_SSLKEYLOGFILE -typedef struct ssl_tap_state { - int master_key_length; - unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; - unsigned char client_random[SSL3_RANDOM_SIZE]; -} ssl_tap_state_t; -#endif /* ENABLE_SSLKEYLOGFILE */ - struct ssl_backend_data { /* these ones requires specific SSL-types */ SSL_CTX* ctx; SSL* handle; X509* server_cert; -#ifdef ENABLE_SSLKEYLOGFILE - /* tap_state holds the last seen master key if we're logging them */ - ssl_tap_state_t tap_state; +#ifndef HAVE_KEYLOG_CALLBACK + /* Set to true once a valid keylog entry has been created to avoid dupes. */ + bool keylog_done; #endif }; -#define BACKEND connssl->backend - /* * Number of bytes to read from the random number seed file. This must be * a finite value (because some entropy "files" like /dev/urandom have @@ -238,57 +232,27 @@ struct ssl_backend_data { */ #define RAND_LOAD_LENGTH 1024 -#ifdef ENABLE_SSLKEYLOGFILE -/* The fp for the open SSLKEYLOGFILE, or NULL if not open */ -static FILE *keylog_file_fp; - #ifdef HAVE_KEYLOG_CALLBACK static void ossl_keylog_callback(const SSL *ssl, const char *line) { (void)ssl; - /* Using fputs here instead of fprintf since libcurl's fprintf replacement - may not be thread-safe. */ - if(keylog_file_fp && line && *line) { - char stackbuf[256]; - char *buf; - size_t linelen = strlen(line); - - if(linelen <= sizeof(stackbuf) - 2) - buf = stackbuf; - else { - buf = malloc(linelen + 2); - if(!buf) - return; - } - memcpy(buf, line, linelen); - buf[linelen] = '\n'; - buf[linelen + 1] = '\0'; - - fputs(buf, keylog_file_fp); - if(buf != stackbuf) - free(buf); - } + Curl_tls_keylog_write_line(line); } #else -#define KEYLOG_PREFIX "CLIENT_RANDOM " -#define KEYLOG_PREFIX_LEN (sizeof(KEYLOG_PREFIX) - 1) /* - * tap_ssl_key is called by libcurl to make the CLIENT_RANDOMs if the OpenSSL - * being used doesn't have native support for doing that. + * ossl_log_tls12_secret is called by libcurl to make the CLIENT_RANDOMs if the + * OpenSSL being used doesn't have native support for doing that. */ -static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state) +static void +ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done) { - const char *hex = "0123456789ABCDEF"; - int pos, i; - char line[KEYLOG_PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 + - 2 * SSL_MAX_MASTER_KEY_LENGTH + 1 + 1]; const SSL_SESSION *session = SSL_get_session(ssl); unsigned char client_random[SSL3_RANDOM_SIZE]; unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; int master_key_length = 0; - if(!session || !keylog_file_fp) + if(!session || *keylog_done) return; #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ @@ -307,44 +271,17 @@ static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state) } #endif + /* The handshake has not progressed sufficiently yet, or this is a TLS 1.3 + * session (when curl was built with older OpenSSL headers and running with + * newer OpenSSL runtime libraries). */ if(master_key_length <= 0) return; - /* Skip writing keys if there is no key or it did not change. */ - if(state->master_key_length == master_key_length && - !memcmp(state->master_key, master_key, master_key_length) && - !memcmp(state->client_random, client_random, SSL3_RANDOM_SIZE)) { - return; - } - - state->master_key_length = master_key_length; - memcpy(state->master_key, master_key, master_key_length); - memcpy(state->client_random, client_random, SSL3_RANDOM_SIZE); - - memcpy(line, KEYLOG_PREFIX, KEYLOG_PREFIX_LEN); - pos = KEYLOG_PREFIX_LEN; - - /* Client Random for SSLv3/TLS */ - for(i = 0; i < SSL3_RANDOM_SIZE; i++) { - line[pos++] = hex[client_random[i] >> 4]; - line[pos++] = hex[client_random[i] & 0xF]; - } - line[pos++] = ' '; - - /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */ - for(i = 0; i < master_key_length; i++) { - line[pos++] = hex[master_key[i] >> 4]; - line[pos++] = hex[master_key[i] & 0xF]; - } - line[pos++] = '\n'; - line[pos] = '\0'; - - /* Using fputs here instead of fprintf since libcurl's fprintf replacement - may not be thread-safe. */ - fputs(line, keylog_file_fp); + *keylog_done = true; + Curl_tls_keylog_write("CLIENT_RANDOM", client_random, + master_key, master_key_length); } #endif /* !HAVE_KEYLOG_CALLBACK */ -#endif /* ENABLE_SSLKEYLOGFILE */ static const char *SSL_ERROR_to_str(int err) { @@ -618,12 +555,136 @@ static bool is_pkcs11_uri(const char *string) static CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine); +static int +SSL_CTX_use_certificate_bio(SSL_CTX *ctx, BIO *in, int type, + const char *key_passwd) +{ + int ret = 0; + X509 *x = NULL; + + if(type == SSL_FILETYPE_ASN1) { + /* j = ERR_R_ASN1_LIB; */ + x = d2i_X509_bio(in, NULL); + } + else if(type == SSL_FILETYPE_PEM) { + /* ERR_R_PEM_LIB; */ + x = PEM_read_bio_X509(in, NULL, + passwd_callback, (void *)key_passwd); + } + else { + ret = 0; + goto end; + } + + if(x == NULL) { + ret = 0; + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); + end: + X509_free(x); + return ret; +} + +static int +SSL_CTX_use_PrivateKey_bio(SSL_CTX *ctx, BIO* in, int type, + const char *key_passwd) +{ + int ret = 0; + EVP_PKEY *pkey = NULL; + + if(type == SSL_FILETYPE_PEM) + pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback, + (void *)key_passwd); + else if(type == SSL_FILETYPE_ASN1) + pkey = d2i_PrivateKey_bio(in, NULL); + else { + ret = 0; + goto end; + } + if(pkey == NULL) { + ret = 0; + goto end; + } + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + EVP_PKEY_free(pkey); + end: + return ret; +} + +static int +SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in, + const char *key_passwd) +{ +/* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */ +#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) /* 1.0.2 or later */ + int ret = 0; + X509 *x = NULL; + void *passwd_callback_userdata = (void *)key_passwd; + + ERR_clear_error(); + + x = PEM_read_bio_X509_AUX(in, NULL, + passwd_callback, (void *)key_passwd); + + if(x == NULL) { + ret = 0; + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); + + if(ERR_peek_error() != 0) + ret = 0; + + if(ret) { + X509 *ca; + unsigned long err; + + if(!SSL_CTX_clear_chain_certs(ctx)) { + ret = 0; + goto end; + } + + while((ca = PEM_read_bio_X509(in, NULL, passwd_callback, + passwd_callback_userdata)) + != NULL) { + + if(!SSL_CTX_add0_chain_cert(ctx, ca)) { + X509_free(ca); + ret = 0; + goto end; + } + } + + err = ERR_peek_last_error(); + if((ERR_GET_LIB(err) == ERR_LIB_PEM) && + (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) + ERR_clear_error(); + else + ret = 0; + } + + end: + X509_free(x); + return ret; +#else + (void)ctx; /* unused */ + (void)in; /* unused */ + (void)key_passwd; /* unused */ + return 0; +#endif +} + static int cert_stuff(struct connectdata *conn, SSL_CTX* ctx, char *cert_file, + BIO *cert_bio, const char *cert_type, char *key_file, + BIO* key_bio, const char *key_type, char *key_passwd) { @@ -633,10 +694,11 @@ int cert_stuff(struct connectdata *conn, int file_type = do_file_type(cert_type); - if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) { + if(cert_file || cert_bio || (file_type == SSL_FILETYPE_ENGINE)) { SSL *ssl; X509 *x509; int cert_done = 0; + int cert_use_result; if(key_passwd) { /* set the password in the callback userdata */ @@ -649,8 +711,10 @@ int cert_stuff(struct connectdata *conn, switch(file_type) { case SSL_FILETYPE_PEM: /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ - if(SSL_CTX_use_certificate_chain_file(ctx, - cert_file) != 1) { + cert_use_result = cert_bio ? + SSL_CTX_use_certificate_chain_bio(ctx, cert_bio, key_passwd) : + SSL_CTX_use_certificate_chain_file(ctx, cert_file); + if(cert_use_result != 1) { failf(data, "could not load PEM client certificate, " OSSL_PACKAGE " error %s, " @@ -665,9 +729,12 @@ int cert_stuff(struct connectdata *conn, /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but we use the case above for PEM so this can only be performed with ASN1 files. */ - if(SSL_CTX_use_certificate_file(ctx, - cert_file, - file_type) != 1) { + + cert_use_result = cert_bio ? + SSL_CTX_use_certificate_bio(ctx, cert_bio, + file_type, key_passwd) : + SSL_CTX_use_certificate_file(ctx, cert_file, file_type); + if(cert_use_result != 1) { failf(data, "could not load ASN1 client certificate, " OSSL_PACKAGE " error %s, " @@ -747,27 +814,31 @@ int cert_stuff(struct connectdata *conn, PKCS12 *p12 = NULL; EVP_PKEY *pri; STACK_OF(X509) *ca = NULL; + if(!cert_bio) { + fp = BIO_new(BIO_s_file()); + if(fp == NULL) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return 0; + } - fp = BIO_new(BIO_s_file()); - if(fp == NULL) { - failf(data, - "BIO_new return NULL, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - return 0; + if(BIO_read_filename(fp, cert_file) <= 0) { + failf(data, "could not open PKCS12 file '%s'", cert_file); + BIO_free(fp); + return 0; + } } - if(BIO_read_filename(fp, cert_file) <= 0) { - failf(data, "could not open PKCS12 file '%s'", cert_file); + p12 = d2i_PKCS12_bio(cert_bio ? cert_bio : fp, NULL); + if(fp) BIO_free(fp); - return 0; - } - p12 = d2i_PKCS12_bio(fp, NULL); - BIO_free(fp); if(!p12) { - failf(data, "error reading PKCS12 file '%s'", cert_file); + failf(data, "error reading PKCS12 file '%s'", + cert_bio ? "(memory blob)" : cert_file); return 0; } @@ -848,8 +919,10 @@ int cert_stuff(struct connectdata *conn, return 0; } - if(!key_file) + if((!key_file) && (!key_bio)) { key_file = cert_file; + key_bio = cert_bio; + } else file_type = do_file_type(key_type); @@ -859,9 +932,12 @@ int cert_stuff(struct connectdata *conn, break; /* FALLTHROUGH */ case SSL_FILETYPE_ASN1: - if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { + cert_use_result = key_bio ? + SSL_CTX_use_PrivateKey_bio(ctx, key_bio, file_type, key_passwd) : + SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type); + if(cert_use_result != 1) { failf(data, "unable to set private key file: '%s' type %s", - key_file, key_type?key_type:"PEM"); + key_file?key_file:"(memory blob)", key_type?key_type:"PEM"); return 0; } break; @@ -1021,10 +1097,6 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) */ static int Curl_ossl_init(void) { -#ifdef ENABLE_SSLKEYLOGFILE - char *keylog_file_name; -#endif - OPENSSL_load_builtin_modules(); #ifdef USE_OPENSSL_ENGINE @@ -1057,26 +1129,7 @@ static int Curl_ossl_init(void) OpenSSL_add_all_algorithms(); #endif -#ifdef ENABLE_SSLKEYLOGFILE - if(!keylog_file_fp) { - keylog_file_name = curl_getenv("SSLKEYLOGFILE"); - if(keylog_file_name) { - keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); - if(keylog_file_fp) { -#ifdef WIN32 - if(setvbuf(keylog_file_fp, NULL, _IONBF, 0)) -#else - if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) -#endif - { - fclose(keylog_file_fp); - keylog_file_fp = NULL; - } - } - Curl_safefree(keylog_file_name); - } - } -#endif + Curl_tls_keylog_open(); /* Initialize the extra data indexes */ if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0) @@ -1119,12 +1172,7 @@ static void Curl_ossl_cleanup(void) #endif #endif -#ifdef ENABLE_SSLKEYLOGFILE - if(keylog_file_fp) { - fclose(keylog_file_fp); - keylog_file_fp = NULL; - } -#endif + Curl_tls_keylog_close(); } /* @@ -1269,19 +1317,19 @@ static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) return list; } - static void ossl_close(struct ssl_connect_data *connssl) { - if(BACKEND->handle) { - (void)SSL_shutdown(BACKEND->handle); - SSL_set_connect_state(BACKEND->handle); + struct ssl_backend_data *backend = connssl->backend; + if(backend->handle) { + (void)SSL_shutdown(backend->handle); + SSL_set_connect_state(backend->handle); - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + 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; } } @@ -1291,7 +1339,9 @@ static void ossl_close(struct ssl_connect_data *connssl) static void Curl_ossl_close(struct connectdata *conn, int sockindex) { ossl_close(&conn->ssl[sockindex]); +#ifndef CURL_DISABLE_PROXY ossl_close(&conn->proxy_ssl[sockindex]); +#endif } /* @@ -1310,6 +1360,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) int buffsize; int err; bool done = FALSE; + struct ssl_backend_data *backend = connssl->backend; #ifndef CURL_DISABLE_FTP /* This has only been tested on the proftpd server, and the mod_tls code @@ -1318,10 +1369,10 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) we do not send one. Let's hope other servers do the same... */ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - (void)SSL_shutdown(BACKEND->handle); + (void)SSL_shutdown(backend->handle); #endif - if(BACKEND->handle) { + if(backend->handle) { buffsize = (int)sizeof(buf); while(!done) { int what = SOCKET_READABLE(conn->sock[sockindex], @@ -1331,8 +1382,8 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) /* Something to read, let's do it and hope that it is the close notify alert from the server */ - nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); - err = SSL_get_error(BACKEND->handle, (int)nread); + nread = (ssize_t)SSL_read(backend->handle, buf, buffsize); + err = SSL_get_error(backend->handle, (int)nread); switch(err) { case SSL_ERROR_NONE: /* this is not an error */ @@ -1377,7 +1428,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) if(data->set.verbose) { #ifdef HAVE_SSL_GET_SHUTDOWN - switch(SSL_get_shutdown(BACKEND->handle)) { + switch(SSL_get_shutdown(backend->handle)) { case SSL_SENT_SHUTDOWN: infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); break; @@ -1392,8 +1443,8 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) #endif } - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + SSL_free(backend->handle); + backend->handle = NULL; } return retval; } @@ -1517,10 +1568,16 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) CURLcode result = CURLE_OK; bool dNSName = FALSE; /* if a dNSName field exists in the cert */ bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; +#ifndef CURL_DISABLE_PROXY + const char * const hostname = SSL_IS_PROXY() ? + conn->http_proxy.host.name : conn->host.name; const char * const dispname = SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname; +#else + /* disabled proxy support */ + const char * const hostname = conn->host.name; + const char * const dispname = conn->host.dispname; +#endif #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1712,13 +1769,13 @@ static CURLcode verifystatus(struct connectdata *conn, const unsigned char *p; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; - OCSP_RESPONSE *rsp = NULL; OCSP_BASICRESP *br = NULL; X509_STORE *st = NULL; STACK_OF(X509) *ch = NULL; + struct ssl_backend_data *backend = connssl->backend; - long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status); + long len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status); if(!status) { failf(data, "No OCSP response received"); @@ -1748,8 +1805,8 @@ static CURLcode verifystatus(struct connectdata *conn, goto end; } - ch = SSL_get_peer_cert_chain(BACKEND->handle); - st = SSL_CTX_get_cert_store(BACKEND->ctx); + ch = SSL_get_peer_cert_chain(backend->handle); + st = SSL_CTX_get_cert_store(backend->ctx); #if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ (defined(LIBRESSL_VERSION_NUMBER) && \ @@ -1825,7 +1882,8 @@ static CURLcode verifystatus(struct connectdata *conn, } end: - if(br) OCSP_BASICRESP_free(br); + if(br) + OCSP_BASICRESP_free(br); OCSP_RESPONSE_free(rsp); return result; @@ -2270,7 +2328,7 @@ set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, #ifdef TLS1_3_VERSION { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION); *ctx_options |= SSL_OP_NO_TLSv1_2; } #else @@ -2398,27 +2456,39 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME bool sni; +#ifndef CURL_DISABLE_PROXY const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; +#else + const char * const hostname = conn->host.name; +#endif + #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif #endif +#ifndef CURL_DISABLE_PROXY long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; +#else + long * const certverifyresult = &data->set.ssl.certverifyresult; +#endif const long int ssl_version = SSL_CONN_CONFIG(version); #ifdef USE_TLS_SRP const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); #endif char * const ssl_cert = SSL_SET_OPTION(cert); + const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(cert_blob); const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); char error_buffer[256]; + struct ssl_backend_data *backend = connssl->backend; + bool imported_native_ca = false; DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); @@ -2477,25 +2547,25 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } - 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: %s", ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); return CURLE_OUT_OF_MEMORY; } #ifdef SSL_MODE_RELEASE_BUFFERS - SSL_CTX_set_mode(BACKEND->ctx, SSL_MODE_RELEASE_BUFFERS); + SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS); #endif #ifdef SSL_CTRL_SET_MSG_CALLBACK if(data->set.fdebug && data->set.verbose) { /* the SSL trace callback is only used for verbose logging */ - SSL_CTX_set_msg_callback(BACKEND->ctx, ssl_tls_trace); - SSL_CTX_set_msg_callback_arg(BACKEND->ctx, conn); + SSL_CTX_set_msg_callback(backend->ctx, ssl_tls_trace); + SSL_CTX_set_msg_callback_arg(backend->ctx, conn); } #endif @@ -2561,8 +2631,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) /* "--sslv2" option means SSLv2 only, disable all others */ case CURL_SSLVERSION_SSLv2: #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ - SSL_CTX_set_min_proto_version(BACKEND->ctx, SSL2_VERSION); - SSL_CTX_set_max_proto_version(BACKEND->ctx, SSL2_VERSION); + SSL_CTX_set_min_proto_version(backend->ctx, SSL2_VERSION); + SSL_CTX_set_max_proto_version(backend->ctx, SSL2_VERSION); #else ctx_options |= SSL_OP_NO_SSLv3; ctx_options |= SSL_OP_NO_TLSv1; @@ -2579,8 +2649,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) /* "--sslv3" option means SSLv3 only, disable all others */ case CURL_SSLVERSION_SSLv3: #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ - SSL_CTX_set_min_proto_version(BACKEND->ctx, SSL3_VERSION); - SSL_CTX_set_max_proto_version(BACKEND->ctx, SSL3_VERSION); + SSL_CTX_set_min_proto_version(backend->ctx, SSL3_VERSION); + SSL_CTX_set_max_proto_version(backend->ctx, SSL3_VERSION); #else ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_TLSv1; @@ -2607,7 +2677,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) ctx_options |= SSL_OP_NO_SSLv3; #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ - result = set_ssl_version_min_max(BACKEND->ctx, conn); + result = set_ssl_version_min_max(backend->ctx, conn); #else result = set_ssl_version_min_max_legacy(&ctx_options, conn, sockindex); #endif @@ -2620,11 +2690,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } - SSL_CTX_set_options(BACKEND->ctx, ctx_options); + SSL_CTX_set_options(backend->ctx, ctx_options); #ifdef HAS_NPN if(conn->bits.tls_enable_npn) - SSL_CTX_set_next_proto_select_cb(BACKEND->ctx, select_next_proto_cb, conn); + SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, conn); #endif #ifdef HAS_ALPN @@ -2633,8 +2703,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) unsigned char protocols[128]; #ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2 && - (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, @@ -2652,14 +2725,37 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) /* expects length prefixed preference ordered list of protocols in wire * format */ - SSL_CTX_set_alpn_protos(BACKEND->ctx, protocols, cur); + SSL_CTX_set_alpn_protos(backend->ctx, protocols, cur); } #endif - if(ssl_cert || ssl_cert_type) { - if(!cert_stuff(conn, BACKEND->ctx, ssl_cert, ssl_cert_type, - SSL_SET_OPTION(key), SSL_SET_OPTION(key_type), - SSL_SET_OPTION(key_passwd))) { + if(ssl_cert || ssl_cert_blob || ssl_cert_type) { + BIO *ssl_cert_bio = NULL; + BIO *ssl_key_bio = NULL; + int result_cert_stuff; + if(ssl_cert_blob) { + /* the typecast of blob->len is fine since it is guaranteed to never be + larger than CURL_MAX_INPUT_LENGTH */ + ssl_cert_bio = BIO_new_mem_buf(ssl_cert_blob->data, + (int)ssl_cert_blob->len); + if(!ssl_cert_bio) + return CURLE_SSL_CERTPROBLEM; + } + if(SSL_SET_OPTION(key_blob)) { + ssl_key_bio = BIO_new_mem_buf(SSL_SET_OPTION(key_blob)->data, + (int)SSL_SET_OPTION(key_blob)->len); + if(!ssl_key_bio) + return CURLE_SSL_CERTPROBLEM; + } + result_cert_stuff = cert_stuff(conn, backend->ctx, + ssl_cert, ssl_cert_bio, ssl_cert_type, + SSL_SET_OPTION(key), ssl_key_bio, + SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd)); + if(ssl_cert_bio) + BIO_free(ssl_cert_bio); + if(ssl_key_bio) + BIO_free(ssl_key_bio); + if(!result_cert_stuff) { /* failf() is already done in cert_stuff() */ return CURLE_SSL_CERTPROBLEM; } @@ -2669,7 +2765,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(!ciphers) ciphers = (char *)DEFAULT_CIPHER_SELECTION; if(ciphers) { - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } @@ -2680,7 +2776,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { char *ciphers13 = SSL_CONN_CONFIG(cipher_list13); if(ciphers13) { - if(!SSL_CTX_set_ciphersuites(BACKEND->ctx, ciphers13)) { + if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) { failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); return CURLE_SSL_CIPHER; } @@ -2691,7 +2787,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH /* OpenSSL 1.1.1 requires clients to opt-in for PHA */ - SSL_CTX_set_post_handshake_auth(BACKEND->ctx, 1); + SSL_CTX_set_post_handshake_auth(backend->ctx, 1); #endif #ifdef USE_TLS_SRP @@ -2700,18 +2796,18 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) infof(data, "Using TLS-SRP username: %s\n", ssl_username); - if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) { + if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) { failf(data, "Unable to set SRP user name"); return CURLE_BAD_FUNCTION_ARGUMENT; } - if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) { + if(!SSL_CTX_set_srp_password(backend->ctx, SSL_SET_OPTION(password))) { failf(data, "failed setting SRP password"); return CURLE_BAD_FUNCTION_ARGUMENT; } if(!SSL_CONN_CONFIG(cipher_list)) { infof(data, "Setting cipher list SRP\n"); - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, "SRP")) { + if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) { failf(data, "failed setting SRP cipher list"); return CURLE_SSL_CIPHER; } @@ -2719,11 +2815,186 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } #endif + +#if defined(USE_WIN32_CRYPTO) + /* Import certificates from the Windows root certificate store if requested. + https://stackoverflow.com/questions/9507184/ + https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 + https://tools.ietf.org/html/rfc5280 */ + if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) && + (SSL_SET_OPTION(native_ca_store))) { + X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx); + HCERTSTORE hStore = CertOpenSystemStoreA((HCRYPTPROV_LEGACY)NULL, "ROOT"); + + if(hStore) { + PCCERT_CONTEXT pContext = NULL; + /* The array of enhanced key usage OIDs will vary per certificate and is + declared outside of the loop so that rather than malloc/free each + iteration we can grow it with realloc, when necessary. */ + CERT_ENHKEY_USAGE *enhkey_usage = NULL; + DWORD enhkey_usage_size = 0; + + /* This loop makes a best effort to import all valid certificates from + the MS root store. If a certificate cannot be imported it is skipped. + 'result' is used to store only hard-fail conditions (such as out of + memory) that cause an early break. */ + result = CURLE_OK; + for(;;) { + X509 *x509; + FILETIME now; + BYTE key_usage[2]; + DWORD req_size; + const unsigned char *encoded_cert; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + char cert_name[256]; +#endif + + pContext = CertEnumCertificatesInStore(hStore, pContext); + if(!pContext) + break; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, + NULL, cert_name, sizeof(cert_name))) { + strcpy(cert_name, "Unknown"); + } + infof(data, "SSL: Checking cert \"%s\"\n", cert_name); +#endif + + encoded_cert = (const unsigned char *)pContext->pbCertEncoded; + if(!encoded_cert) + continue; + + GetSystemTimeAsFileTime(&now); + if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 || + CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0) + continue; + + /* If key usage exists check for signing attribute */ + if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType, + pContext->pCertInfo, + key_usage, sizeof(key_usage))) { + if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) + continue; + } + else if(GetLastError()) + continue; + + /* If enhanced key usage exists check for server auth attribute. + * + * Note "In a Microsoft environment, a certificate might also have EKU + * extended properties that specify valid uses for the certificate." + * The call below checks both, and behavior varies depending on what is + * found. For more details see CertGetEnhancedKeyUsage doc. + */ + if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) { + if(req_size && req_size > enhkey_usage_size) { + void *tmp = realloc(enhkey_usage, req_size); + + if(!tmp) { + failf(data, "SSL: Out of memory allocating for OID list"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + enhkey_usage = (CERT_ENHKEY_USAGE *)tmp; + enhkey_usage_size = req_size; + } + + if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) { + if(!enhkey_usage->cUsageIdentifier) { + /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is + good for all uses. If it returns zero, the certificate has no + valid uses." */ + if(GetLastError() != CRYPT_E_NOT_FOUND) + continue; + } + else { + DWORD i; + bool found = false; + + for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) { + if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */, + enhkey_usage->rgpszUsageIdentifier[i])) { + found = true; + break; + } + } + + if(!found) + continue; + } + } + else + continue; + } + else + continue; + + x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if(!x509) + continue; + + /* Try to import the certificate. This may fail for legitimate reasons + such as duplicate certificate, which is allowed by MS but not + OpenSSL. */ + if(X509_STORE_add_cert(store, x509) == 1) { +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(data, "SSL: Imported cert \"%s\"\n", cert_name); +#endif + imported_native_ca = true; + } + X509_free(x509); + } + + free(enhkey_usage); + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); + + if(result) + return result; + } + if(imported_native_ca) + infof(data, "successfully imported windows ca store\n"); + else + infof(data, "error importing windows ca store, continuing anyway\n"); + } +#endif + +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + { + if(ssl_cafile) { + if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { + if(verifypeer) { + /* 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 a warning if no certificate verif is required. */ + infof(data, "error setting certificate file, continuing anyway\n"); + } + infof(data, " CAfile: %s\n", ssl_cafile); + } + if(ssl_capath) { + if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { + if(verifypeer) { + /* 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 a warning if no certificate verif is required. */ + infof(data, "error setting certificate path, continuing anyway\n"); + } + infof(data, " CApath: %s\n", ssl_capath); + } + } +#else if(ssl_cafile || ssl_capath) { /* tell SSL where to find CA certificates that are used to verify the servers certificate. */ - if(!SSL_CTX_load_verify_locations(BACKEND->ctx, ssl_cafile, ssl_capath)) { - if(verifypeer) { + 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:\n" " CAfile: %s\n CApath: %s", @@ -2731,7 +3002,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) ssl_capath ? ssl_capath : "none"); return CURLE_SSL_CACERT_BADFILE; } - /* Just continue with a warning if no strict certificate verification + /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "error setting certificate verify locations," " continuing anyway:\n"); @@ -2746,18 +3017,20 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) ssl_cafile ? ssl_cafile : "none", ssl_capath ? ssl_capath : "none"); } +#endif + #ifdef CURL_CA_FALLBACK - else if(verifypeer) { + if(verifypeer && !ssl_cafile && !ssl_capath && !imported_native_ca) { /* verifying the peer without any CA certificates won't work so use openssl's built in default as fallback */ - SSL_CTX_set_default_verify_paths(BACKEND->ctx); + SSL_CTX_set_default_verify_paths(backend->ctx); } #endif if(ssl_crlfile) { /* tell SSL where to find CRL file that is used to check certificate * revocation */ - lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(BACKEND->ctx), + lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx), X509_LOOKUP_file()); if(!lookup || (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { @@ -2766,7 +3039,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } /* Everything is fine. */ infof(data, "successfully load CRL file:\n"); - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); infof(data, " CRLfile: %s\n", ssl_crlfile); @@ -2775,22 +3048,25 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(verifypeer) { /* Try building a chain using issuers in the trusted store first to avoid problems with server-sent legacy intermediates. Newer versions of - OpenSSL do alternate chain checking by default which gives us the same - fix without as much of a performance hit (slight), so we prefer that if - available. + OpenSSL do alternate chain checking by default but we do not know how to + determine that in a reliable manner. https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest */ -#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), +#if defined(X509_V_FLAG_TRUSTED_FIRST) + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_TRUSTED_FIRST); #endif #ifdef X509_V_FLAG_PARTIAL_CHAIN - if(!SSL_SET_OPTION(no_partialchain)) { + if(!SSL_SET_OPTION(no_partialchain) && !ssl_crlfile) { /* Have intermediate certificates in the trust store be treated as trust-anchors, in the same way as self-signed root CA certificates are. This allows users to verify servers using the intermediate cert - only, instead of needing the whole chain. */ - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), + only, instead of needing the whole chain. + + Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we + cannot do partial chains with CRL check. + */ + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_PARTIAL_CHAIN); } #endif @@ -2800,13 +3076,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(BACKEND->ctx, + SSL_CTX_set_verify(backend->ctx, verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ -#if defined(ENABLE_SSLKEYLOGFILE) && defined(HAVE_KEYLOG_CALLBACK) - if(keylog_file_fp) { - SSL_CTX_set_keylog_callback(BACKEND->ctx, ossl_keylog_callback); +#ifdef HAVE_KEYLOG_CALLBACK + if(Curl_tls_keylog_enabled()) { + SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback); } #endif @@ -2814,14 +3090,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) * callback. Use the "external storage" mode to avoid that OpenSSL creates * an internal session cache. */ - SSL_CTX_set_session_cache_mode(BACKEND->ctx, + SSL_CTX_set_session_cache_mode(backend->ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); - SSL_CTX_sess_set_new_cb(BACKEND->ctx, ossl_new_session_cb); + SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb); /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { Curl_set_in_callback(data, true); - result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, + result = (*data->set.ssl.fsslctx)(data, backend->ctx, data->set.ssl.fsslctxp); Curl_set_in_callback(data, false); if(result) { @@ -2831,10 +3107,10 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } /* Lets make an SSL structure */ - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } @@ -2842,23 +3118,23 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) if(SSL_CONN_CONFIG(verifystatus)) - SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp); + SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp); #endif #if defined(OPENSSL_IS_BORINGSSL) && defined(ALLOW_RENEG) - SSL_set_renegotiate_mode(BACKEND->handle, ssl_renegotiate_freely); + SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely); #endif - SSL_set_connect_state(BACKEND->handle); + SSL_set_connect_state(backend->handle); - BACKEND->server_cert = 0x0; + backend->server_cert = 0x0; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && #endif sni && - !SSL_set_tlsext_host_name(BACKEND->handle, hostname)) + !SSL_set_tlsext_host_name(backend->handle, hostname)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); #endif @@ -2872,14 +3148,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(connectdata_idx >= 0 && sockindex_idx >= 0) { /* Store the data needed for the "new session" callback. * The sockindex is stored as a pointer to an array element. */ - SSL_set_ex_data(BACKEND->handle, connectdata_idx, conn); - SSL_set_ex_data(BACKEND->handle, sockindex_idx, conn->sock + sockindex); + SSL_set_ex_data(backend->handle, connectdata_idx, conn); + SSL_set_ex_data(backend->handle, sockindex_idx, conn->sock + sockindex); } Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ - if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + if(!SSL_set_session(backend->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSL_set_session failed: %s", ossl_strerror(ERR_get_error(), error_buffer, @@ -2892,6 +3168,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) Curl_ssl_sessionid_unlock(conn); } +#ifndef CURL_DISABLE_PROXY if(conn->proxy_ssl[sockindex].use) { BIO *const bio = BIO_new(BIO_f_ssl()); SSL *handle = conn->proxy_ssl[sockindex].backend->handle; @@ -2899,9 +3176,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) DEBUGASSERT(handle != NULL); DEBUGASSERT(bio != NULL); BIO_set_ssl(bio, handle, FALSE); - SSL_set_bio(BACKEND->handle, bio, bio); + SSL_set_bio(backend->handle, bio, bio); } - else if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { + else +#endif + if(!SSL_set_fd(backend->handle, (int)sockfd)) { /* pass the raw socket into the SSL layers */ failf(data, "SSL: SSL_set_fd failed: %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); @@ -2918,26 +3197,34 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) struct Curl_easy *data = conn->data; int err; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; +#ifndef CURL_DISABLE_PROXY long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; +#else + long * const certverifyresult = &data->set.ssl.certverifyresult; +#endif + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); ERR_clear_error(); - err = SSL_connect(BACKEND->handle); - /* If keylogging is enabled but the keylog callback is not supported then log - secrets here, immediately after SSL_connect by using tap_ssl_key. */ -#if defined(ENABLE_SSLKEYLOGFILE) && !defined(HAVE_KEYLOG_CALLBACK) - tap_ssl_key(BACKEND->handle, &BACKEND->tap_state); + err = SSL_connect(backend->handle); +#ifndef HAVE_KEYLOG_CALLBACK + if(Curl_tls_keylog_enabled()) { + /* If key logging is enabled, wait for the handshake to complete and then + * proceed with logging secrets (for TLS 1.2 or older). + */ + ossl_log_tls12_secret(backend->handle, &backend->keylog_done); + } #endif /* 1 is fine 0 is "not successful but was shut down controlled" <0 is "handshake was not successful, because a fatal error occurred" */ if(1 != err) { - int detail = SSL_get_error(BACKEND->handle, err); + int detail = SSL_get_error(backend->handle, err); if(SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; @@ -2977,7 +3264,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { result = CURLE_PEER_FAILED_VERIFICATION; - lerr = SSL_get_verify_result(BACKEND->handle); + lerr = SSL_get_verify_result(backend->handle); if(lerr != X509_V_OK) { *certverifyresult = lerr; msnprintf(error_buffer, sizeof(error_buffer), @@ -3001,9 +3288,14 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) * the SO_ERROR is also lost. */ if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { +#ifndef CURL_DISABLE_PROXY const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; +#else + const char * const hostname = conn->host.name; + const long int port = conn->remote_port; +#endif char extramsg[80]=""; int sockerr = SOCKERRNO; if(sockerr && detail == SSL_ERROR_SYSCALL) @@ -3026,8 +3318,8 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) /* Informational message */ infof(data, "SSL connection using %s / %s\n", - get_ssl_version_txt(BACKEND->handle), - SSL_get_cipher(BACKEND->handle)); + get_ssl_version_txt(backend->handle), + SSL_get_cipher(backend->handle)); #ifdef HAS_ALPN /* Sets data and len to negotiated protocol, len is 0 if no protocol was @@ -3036,7 +3328,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) if(conn->bits.tls_enable_alpn) { const unsigned char *neg_protocol; unsigned int len; - SSL_get0_alpn_selected(BACKEND->handle, &neg_protocol, &len); + SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len); if(len != 0) { infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); @@ -3171,8 +3463,9 @@ static CURLcode get_cert_chain(struct connectdata *conn, struct Curl_easy *data = conn->data; numcert_t numcerts; BIO *mem; + struct ssl_backend_data *backend = connssl->backend; - sk = SSL_get_peer_cert_chain(BACKEND->handle); + sk = SSL_get_peer_cert_chain(backend->handle); if(!sk) { return CURLE_OUT_OF_MEMORY; } @@ -3455,16 +3748,21 @@ static CURLcode servercert(struct connectdata *conn, char error_buffer[256]=""; char buffer[2048]; const char *ptr; +#ifndef CURL_DISABLE_PROXY long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; +#else + long * const certverifyresult = &data->set.ssl.certverifyresult; +#endif BIO *mem = BIO_new(BIO_s_mem()); + struct ssl_backend_data *backend = connssl->backend; if(data->set.ssl.certinfo) /* we've been asked to gather certificate info! */ (void)get_cert_chain(conn, connssl); - BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle); - if(!BACKEND->server_cert) { + backend->server_cert = SSL_get_peer_certificate(backend->handle); + if(!backend->server_cert) { BIO_free(mem); if(!strict) return CURLE_OK; @@ -3475,19 +3773,19 @@ static CURLcode servercert(struct connectdata *conn, infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); - rc = x509_name_oneline(X509_get_subject_name(BACKEND->server_cert), + rc = x509_name_oneline(X509_get_subject_name(backend->server_cert), buffer, sizeof(buffer)); infof(data, " subject: %s\n", rc?"[NONE]":buffer); #ifndef CURL_DISABLE_VERBOSE_STRINGS { long len; - ASN1_TIME_print(mem, X509_get0_notBefore(BACKEND->server_cert)); + ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " start date: %.*s\n", len, ptr); (void)BIO_reset(mem); - ASN1_TIME_print(mem, X509_get0_notAfter(BACKEND->server_cert)); + ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " expire date: %.*s\n", len, ptr); (void)BIO_reset(mem); @@ -3497,15 +3795,15 @@ static CURLcode servercert(struct connectdata *conn, BIO_free(mem); if(SSL_CONN_CONFIG(verifyhost)) { - result = verifyhost(conn, BACKEND->server_cert); + result = verifyhost(conn, backend->server_cert); if(result) { - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return result; } } - rc = x509_name_oneline(X509_get_issuer_name(BACKEND->server_cert), + rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert), buffer, sizeof(buffer)); if(rc) { if(strict) @@ -3519,27 +3817,32 @@ static CURLcode servercert(struct connectdata *conn, deallocating the certificate. */ /* e.g. match issuer name with provided issuer certificate */ - if(SSL_SET_OPTION(issuercert)) { - fp = BIO_new(BIO_s_file()); - if(fp == NULL) { - failf(data, - "BIO_new return NULL, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - return CURLE_OUT_OF_MEMORY; - } + if(SSL_SET_OPTION(issuercert) || SSL_SET_OPTION(issuercert_blob)) { + if(SSL_SET_OPTION(issuercert_blob)) + fp = BIO_new_mem_buf(SSL_SET_OPTION(issuercert_blob)->data, + (int)SSL_SET_OPTION(issuercert_blob)->len); + else { + fp = BIO_new(BIO_s_file()); + if(fp == NULL) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_OUT_OF_MEMORY; + } - if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { - if(strict) - failf(data, "SSL: Unable to open issuer cert (%s)", - SSL_SET_OPTION(issuercert)); - BIO_free(fp); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - return CURLE_SSL_ISSUER_ERROR; + if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { + if(strict) + failf(data, "SSL: Unable to open issuer cert (%s)", + SSL_SET_OPTION(issuercert)); + BIO_free(fp); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } } issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL); @@ -3549,19 +3852,19 @@ static CURLcode servercert(struct connectdata *conn, SSL_SET_OPTION(issuercert)); BIO_free(fp); X509_free(issuer); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } - if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) { + if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) { if(strict) failf(data, "SSL: Certificate issuer check failed (%s)", SSL_SET_OPTION(issuercert)); BIO_free(fp); X509_free(issuer); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } @@ -3571,7 +3874,7 @@ static CURLcode servercert(struct connectdata *conn, X509_free(issuer); } - lerr = *certverifyresult = SSL_get_verify_result(BACKEND->handle); + lerr = *certverifyresult = SSL_get_verify_result(backend->handle); if(*certverifyresult != X509_V_OK) { if(SSL_CONN_CONFIG(verifypeer)) { @@ -3596,8 +3899,8 @@ static CURLcode servercert(struct connectdata *conn, if(SSL_CONN_CONFIG(verifystatus)) { result = verifystatus(conn, connssl); if(result) { - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return result; } } @@ -3610,13 +3913,13 @@ static CURLcode servercert(struct connectdata *conn, ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; if(!result && ptr) { - result = pkp_pin_peer_pubkey(data, BACKEND->server_cert, ptr); + result = pkp_pin_peer_pubkey(data, backend->server_cert, ptr); if(result) failf(data, "SSL: public key does not match pinned public key!"); } - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; connssl->connecting_state = ssl_connect_done; return result; @@ -3657,7 +3960,6 @@ static CURLcode ossl_connect_common(struct connectdata *conn, struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; - timediff_t timeout_ms; int what; /* check if the connection has already been established */ @@ -3668,7 +3970,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn, if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ @@ -3686,7 +3988,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn, ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ @@ -3704,7 +4006,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn, connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:(time_t)timeout_ms); + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -3783,14 +4085,15 @@ static bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex]; - if(connssl->backend->handle && SSL_pending(connssl->backend->handle)) return TRUE; - - if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle)) - return TRUE; - +#ifndef CURL_DISABLE_PROXY + { + const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex]; + if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle)) + return TRUE; + } +#endif return FALSE; } @@ -3810,14 +4113,15 @@ static ssize_t ossl_send(struct connectdata *conn, int memlen; int rc; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; ERR_clear_error(); memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - rc = SSL_write(BACKEND->handle, mem, memlen); + rc = SSL_write(backend->handle, mem, memlen); if(rc <= 0) { - err = SSL_get_error(BACKEND->handle, rc); + err = SSL_get_error(backend->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: @@ -3850,8 +4154,11 @@ static ssize_t ossl_send(struct connectdata *conn, sslerror = ERR_get_error(); if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL && ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET && - conn->ssl[sockindex].state == ssl_connection_complete && - conn->proxy_ssl[sockindex].state == ssl_connection_complete) { + conn->ssl[sockindex].state == ssl_connection_complete +#ifndef CURL_DISABLE_PROXY + && conn->proxy_ssl[sockindex].state == ssl_connection_complete +#endif + ) { char ver[120]; Curl_ossl_version(ver, 120); failf(conn->data, "Error: %s does not support double SSL tunneling.", @@ -3884,14 +4191,15 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ ssize_t nread; int buffsize; struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; ERR_clear_error(); buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); + nread = (ssize_t)SSL_read(backend->handle, buf, buffsize); if(nread <= 0) { /* failed SSL_read */ - int err = SSL_get_error(BACKEND->handle, (int)nread); + int err = SSL_get_error(backend->handle, (int)nread); switch(err) { case SSL_ERROR_NONE: /* this is not an error */ @@ -4074,7 +4382,7 @@ static CURLcode Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ unsigned int len = 0; (void) unused; - mdctx = EVP_MD_CTX_create(); + mdctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); EVP_DigestUpdate(mdctx, tmp, tmplen); EVP_DigestFinal_ex(mdctx, sha256sum, &len); @@ -4097,8 +4405,9 @@ static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl, CURLINFO info) { /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ + struct ssl_backend_data *backend = connssl->backend; return info == CURLINFO_TLS_SESSION ? - (void *)BACKEND->ctx : (void *)BACKEND->handle; + (void *)backend->ctx : (void *)backend->handle; } const struct Curl_ssl Curl_ssl_openssl = { diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index 0818d94..1996526 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -27,16 +27,6 @@ * but vtls.c should ever call or use these functions. */ -/* - * Based upon the PolarSSL implementation in polarssl.c and polarssl.h: - * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> - * - * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * Thanks for code and inspiration! - */ - #include "curl_setup.h" #ifdef USE_SCHANNEL @@ -49,10 +39,11 @@ #include "schannel.h" #include "vtls.h" +#include "strcase.h" #include "sendf.h" #include "connect.h" /* for the connect timeout */ #include "strerror.h" -#include "select.h" /* for the socket readyness */ +#include "select.h" /* for the socket readiness */ #include "inet_pton.h" /* for IP addr SNI check */ #include "curl_multibyte.h" #include "warnless.h" @@ -61,7 +52,7 @@ #include "multiif.h" #include "system_win32.h" - /* The last #include file should be: */ +/* The last #include file should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -179,25 +170,25 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn) long i = ssl_version; switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; + case CURL_SSLVERSION_MAX_NONE: + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; } for(; i <= (ssl_version_max >> 16); ++i) { switch(i) { - case CURL_SSLVERSION_TLSv1_0: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_1: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_2: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_3: - failf(data, "schannel: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_0: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_1: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_2: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "schannel: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; } } return CURLE_OK; @@ -205,9 +196,9 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn) /*longest is 26, buffer is slightly bigger*/ #define LONGEST_ALG_ID 32 -#define CIPHEROPTION(X) \ -if(strcmp(#X, tmp) == 0) \ - return X +#define CIPHEROPTION(X) \ + if(strcmp(#X, tmp) == 0) \ + return X static int get_alg_id_by_name(char *name) @@ -283,11 +274,11 @@ get_alg_id_by_name(char *name) #ifdef CALG_HMAC CIPHEROPTION(CALG_HMAC); #endif -#if !defined(__W32API_MAJOR_VERSION) || \ - !defined(__W32API_MINOR_VERSION) || \ - defined(__MINGW64_VERSION_MAJOR) || \ - (__W32API_MAJOR_VERSION > 5) || \ - ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0)) +#if !defined(__W32API_MAJOR_VERSION) || \ + !defined(__W32API_MINOR_VERSION) || \ + defined(__MINGW64_VERSION_MAJOR) || \ + (__W32API_MAJOR_VERSION > 5) || \ + ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0)) /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0, see https://osdn.net/projects/mingw/ticket/38391 */ CIPHEROPTION(CALG_TLS1PRF); @@ -349,7 +340,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers) if(startCur) startCur++; } - schannel_cred->palgSupportedAlgs = algIds; + schannel_cred->palgSupportedAlgs = algIds; schannel_cred->cSupportedAlgs = algCount; return CURLE_OK; } @@ -434,8 +425,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) #endif TCHAR *host_name; CURLcode result; +#ifndef CURL_DISABLE_PROXY char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; +#else + char * const hostname = conn->host.name; +#endif DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", @@ -443,20 +438,20 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT, VERSION_LESS_THAN_EQUAL)) { - /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and - algorithms that may not be supported by all servers. */ - infof(data, "schannel: Windows version is old and may not be able to " - "connect to some servers due to lack of SNI, algorithms, etc.\n"); + /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and + algorithms that may not be supported by all servers. */ + infof(data, "schannel: Windows version is old and may not be able to " + "connect to some servers due to lack of SNI, algorithms, etc.\n"); } #ifdef HAS_ALPN /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. Also it doesn't seem to be supported for Wine, see curl bug #983. */ BACKEND->use_alpn = conn->bits.tls_enable_alpn && - !GetProcAddress(GetModuleHandleA("ntdll"), - "wine_get_version") && - Curl_verify_windows_version(6, 3, PLATFORM_WINNT, - VERSION_GREATER_THAN_EQUAL); + !GetProcAddress(GetModuleHandleA("ntdll"), + "wine_get_version") && + Curl_verify_windows_version(6, 3, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL); #else BACKEND->use_alpn = false; #endif @@ -530,8 +525,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) DEBUGF(infof(data, "schannel: disabled server certificate revocation " "checks\n")); } + else if(data->set.ssl.revoke_best_effort) { + schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN; + + DEBUGF(infof(data, "schannel: ignore revocation offline errors")); + } else { schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; + DEBUGF(infof(data, "schannel: checking server certificate revocation\n")); } @@ -558,12 +560,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: - { - result = set_ssl_version_min_max(&schannel_cred, conn); - if(result != CURLE_OK) - return result; - break; - } + { + result = set_ssl_version_min_max(&schannel_cred, conn); + if(result != CURLE_OK) + return result; + break; + } case CURL_SSLVERSION_SSLv3: schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; break; @@ -586,68 +588,186 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) #ifdef HAS_CLIENT_CERT_PATH /* client certificate */ - if(data->set.ssl.cert) { - DWORD cert_store_name; - TCHAR *cert_store_path; - TCHAR *cert_thumbprint_str; + if(data->set.ssl.cert || data->set.ssl.cert_blob) { + DWORD cert_store_name = 0; + TCHAR *cert_store_path = NULL; + TCHAR *cert_thumbprint_str = NULL; CRYPT_HASH_BLOB cert_thumbprint; BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN]; - HCERTSTORE cert_store; + HCERTSTORE cert_store = NULL; + FILE *fInCert = NULL; + void *certdata = NULL; + size_t certsize = 0; + bool blob = data->set.ssl.cert_blob != NULL; + TCHAR *cert_path = NULL; + if(blob) { + certdata = data->set.ssl.cert_blob->data; + certsize = data->set.ssl.cert_blob->len; + } + else { + cert_path = curlx_convert_UTF8_to_tchar(data->set.ssl.cert); + if(!cert_path) + return CURLE_OUT_OF_MEMORY; - TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert); - if(!cert_path) - return CURLE_OUT_OF_MEMORY; + result = get_cert_location(cert_path, &cert_store_name, + &cert_store_path, &cert_thumbprint_str); - result = get_cert_location(cert_path, &cert_store_name, - &cert_store_path, &cert_thumbprint_str); - if(result != CURLE_OK) { - failf(data, "schannel: Failed to get certificate location for %s", - cert_path); - Curl_unicodefree(cert_path); - return result; + if(result && (data->set.ssl.cert[0]!='\0')) + fInCert = fopen(data->set.ssl.cert, "rb"); + + if(result && !fInCert) { + failf(data, "schannel: Failed to get certificate location" + " or file for %s", + data->set.ssl.cert); + curlx_unicodefree(cert_path); + return result; + } } - cert_store = - CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, - (HCRYPTPROV)NULL, - CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, - cert_store_path); - if(!cert_store) { - failf(data, "schannel: Failed to open cert store %x %s, " - "last error is %x", - cert_store_name, cert_store_path, GetLastError()); - free(cert_store_path); - Curl_unicodefree(cert_path); + if((fInCert || blob) && (data->set.ssl.cert_type) && + (!strcasecompare(data->set.ssl.cert_type, "P12"))) { + failf(data, "schannel: certificate format compatibility error " + " for %s", + blob ? "(memory blob)" : data->set.ssl.cert); + curlx_unicodefree(cert_path); return CURLE_SSL_CERTPROBLEM; } - free(cert_store_path); - cert_thumbprint.pbData = cert_thumbprint_data; - cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN; + if(fInCert || blob) { + /* Reading a .P12 or .pfx file, like the example at bottom of + https://social.msdn.microsoft.com/Forums/windowsdesktop/ + en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 + */ + CRYPT_DATA_BLOB datablob; + WCHAR* pszPassword; + size_t pwd_len = 0; + int str_w_len = 0; + const char *cert_showfilename_error = blob ? + "(memory blob)" : data->set.ssl.cert; + curlx_unicodefree(cert_path); + if(fInCert) { + long cert_tell = 0; + bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0; + if(continue_reading) + cert_tell = ftell(fInCert); + if(cert_tell < 0) + continue_reading = FALSE; + else + certsize = (size_t)cert_tell; + if(continue_reading) + continue_reading = fseek(fInCert, 0, SEEK_SET) == 0; + if(continue_reading) + certdata = malloc(certsize + 1); + if((!certdata) || + ((int) fread(certdata, certsize, 1, fInCert) != 1)) + continue_reading = FALSE; + fclose(fInCert); + if(!continue_reading) { + failf(data, "schannel: Failed to read cert file %s", + data->set.ssl.cert); + free(certdata); + return CURLE_SSL_CERTPROBLEM; + } + } - if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN, - CRYPT_STRING_HEX, - cert_thumbprint_data, &cert_thumbprint.cbData, - NULL, NULL)) { - Curl_unicodefree(cert_path); - return CURLE_SSL_CERTPROBLEM; - } + /* Convert key-pair data to the in-memory certificate store */ + datablob.pbData = (BYTE*)certdata; + datablob.cbData = (DWORD)certsize; + + if(data->set.ssl.key_passwd != NULL) + pwd_len = strlen(data->set.ssl.key_passwd); + pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1)); + if(pszPassword) { + if(pwd_len > 0) + str_w_len = MultiByteToWideChar(CP_UTF8, + MB_ERR_INVALID_CHARS, + data->set.ssl.key_passwd, (int)pwd_len, + pszPassword, (int)(pwd_len + 1)); + + if((str_w_len >= 0) && (str_w_len <= (int)pwd_len)) + pszPassword[str_w_len] = 0; + else + pszPassword[0] = 0; + + cert_store = PFXImportCertStore(&datablob, pszPassword, 0); + free(pszPassword); + } + if(!blob) + free(certdata); + if(cert_store == NULL) { + DWORD errorcode = GetLastError(); + if(errorcode == ERROR_INVALID_PASSWORD) + failf(data, "schannel: Failed to import cert file %s, " + "password is bad", + cert_showfilename_error); + else + failf(data, "schannel: Failed to import cert file %s, " + "last error is 0x%x", + cert_showfilename_error, errorcode); + return CURLE_SSL_CERTPROBLEM; + } - client_certs[0] = CertFindCertificateInStore( - cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, - CERT_FIND_HASH, &cert_thumbprint, NULL); + client_certs[0] = CertFindCertificateInStore( + cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, + CERT_FIND_ANY, NULL, NULL); - Curl_unicodefree(cert_path); + if(client_certs[0] == NULL) { + failf(data, "schannel: Failed to get certificate from file %s" + ", last error is 0x%x", + cert_showfilename_error, GetLastError()); + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } - if(client_certs[0]) { schannel_cred.cCreds = 1; schannel_cred.paCred = client_certs; } else { - /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ - return CURLE_SSL_CERTPROBLEM; - } + cert_store = + CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, + (HCRYPTPROV)NULL, + CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, + cert_store_path); + if(!cert_store) { + failf(data, "schannel: Failed to open cert store %x %s, " + "last error is 0x%x", + cert_store_name, cert_store_path, GetLastError()); + free(cert_store_path); + curlx_unicodefree(cert_path); + return CURLE_SSL_CERTPROBLEM; + } + free(cert_store_path); + + cert_thumbprint.pbData = cert_thumbprint_data; + cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN; + + if(!CryptStringToBinary(cert_thumbprint_str, + CERT_THUMBPRINT_STR_LEN, + CRYPT_STRING_HEX, + cert_thumbprint_data, + &cert_thumbprint.cbData, + NULL, NULL)) { + curlx_unicodefree(cert_path); + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + + client_certs[0] = CertFindCertificateInStore( + cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, + CERT_FIND_HASH, &cert_thumbprint, NULL); + + curlx_unicodefree(cert_path); + if(client_certs[0]) { + schannel_cred.cCreds = 1; + schannel_cred.paCred = client_certs; + } + else { + /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + } CertCloseStore(cert_store, 0); } #else @@ -671,7 +791,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) BACKEND->cred->refcount = 1; /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx - */ + */ sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, @@ -688,15 +808,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); Curl_safefree(BACKEND->cred); switch(sspi_status) { - case SEC_E_INSUFFICIENT_MEMORY: - return CURLE_OUT_OF_MEMORY; - case SEC_E_NO_CREDENTIALS: - case SEC_E_SECPKG_NOT_FOUND: - case SEC_E_NOT_OWNER: - case SEC_E_UNKNOWN_CREDENTIALS: - case SEC_E_INTERNAL_ERROR: - default: - return CURLE_SSL_CONNECT_ERROR; + case SEC_E_INSUFFICIENT_MEMORY: + return CURLE_OUT_OF_MEMORY; + case SEC_E_NO_CREDENTIALS: + case SEC_E_SECPKG_NOT_FOUND: + case SEC_E_NOT_OWNER: + case SEC_E_UNKNOWN_CREDENTIALS: + case SEC_E_INTERNAL_ERROR: + default: + return CURLE_SSL_CONNECT_ERROR; } } } @@ -780,7 +900,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) return CURLE_OUT_OF_MEMORY; } - host_name = Curl_convert_UTF8_to_tchar(hostname); + host_name = curlx_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; @@ -797,35 +917,35 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) 0, &BACKEND->ctxt->ctxt_handle, &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); - Curl_unicodefree(host_name); + curlx_unicodefree(host_name); if(sspi_status != SEC_I_CONTINUE_NEEDED) { char buffer[STRERROR_LEN]; Curl_safefree(BACKEND->ctxt); switch(sspi_status) { - case SEC_E_INSUFFICIENT_MEMORY: - failf(data, "schannel: initial InitializeSecurityContext failed: %s", - Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - return CURLE_OUT_OF_MEMORY; - case SEC_E_WRONG_PRINCIPAL: - failf(data, "schannel: SNI or certificate check failed: %s", - Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - return CURLE_PEER_FAILED_VERIFICATION; - /* - case SEC_E_INVALID_HANDLE: - case SEC_E_INVALID_TOKEN: - case SEC_E_LOGON_DENIED: - case SEC_E_TARGET_UNKNOWN: - case SEC_E_NO_AUTHENTICATING_AUTHORITY: - case SEC_E_INTERNAL_ERROR: - case SEC_E_NO_CREDENTIALS: - case SEC_E_UNSUPPORTED_FUNCTION: - case SEC_E_APPLICATION_PROTOCOL_MISMATCH: - */ - default: - failf(data, "schannel: initial InitializeSecurityContext failed: %s", - Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - return CURLE_SSL_CONNECT_ERROR; + case SEC_E_INSUFFICIENT_MEMORY: + failf(data, "schannel: initial InitializeSecurityContext failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_OUT_OF_MEMORY; + case SEC_E_WRONG_PRINCIPAL: + failf(data, "schannel: SNI or certificate check failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_PEER_FAILED_VERIFICATION; + /* + case SEC_E_INVALID_HANDLE: + case SEC_E_INVALID_TOKEN: + case SEC_E_LOGON_DENIED: + case SEC_E_TARGET_UNKNOWN: + case SEC_E_NO_AUTHENTICATING_AUTHORITY: + case SEC_E_INTERNAL_ERROR: + case SEC_E_NO_CREDENTIALS: + case SEC_E_UNSUPPORTED_FUNCTION: + case SEC_E_APPLICATION_PROTOCOL_MISMATCH: + */ + default: + failf(data, "schannel: initial InitializeSecurityContext failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_SSL_CONNECT_ERROR; } } @@ -871,8 +991,12 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; bool doread; +#ifndef CURL_DISABLE_PROXY char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; +#else + char * const hostname = conn->host.name; +#endif const char *pubkey_ptr; doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; @@ -980,18 +1104,18 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer, BACKEND->encdata_offset); - host_name = Curl_convert_UTF8_to_tchar(hostname); + host_name = curlx_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx - */ + */ sspi_status = s_pSecFn->InitializeSecurityContext( &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); - Curl_unicodefree(host_name); + curlx_unicodefree(host_name); /* free buffer for received handshake data */ Curl_safefree(inbuf[0].pvBuffer); @@ -1046,29 +1170,29 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) else { char buffer[STRERROR_LEN]; switch(sspi_status) { - case SEC_E_INSUFFICIENT_MEMORY: - failf(data, "schannel: next InitializeSecurityContext failed: %s", - Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - return CURLE_OUT_OF_MEMORY; - case SEC_E_WRONG_PRINCIPAL: - failf(data, "schannel: SNI or certificate check failed: %s", - Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - return CURLE_PEER_FAILED_VERIFICATION; - /* - case SEC_E_INVALID_HANDLE: - case SEC_E_INVALID_TOKEN: - case SEC_E_LOGON_DENIED: - case SEC_E_TARGET_UNKNOWN: - case SEC_E_NO_AUTHENTICATING_AUTHORITY: - case SEC_E_INTERNAL_ERROR: - case SEC_E_NO_CREDENTIALS: - case SEC_E_UNSUPPORTED_FUNCTION: - case SEC_E_APPLICATION_PROTOCOL_MISMATCH: - */ - default: - failf(data, "schannel: next InitializeSecurityContext failed: %s", - Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - return CURLE_SSL_CONNECT_ERROR; + case SEC_E_INSUFFICIENT_MEMORY: + failf(data, "schannel: next InitializeSecurityContext failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_OUT_OF_MEMORY; + case SEC_E_WRONG_PRINCIPAL: + failf(data, "schannel: SNI or certificate check failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_PEER_FAILED_VERIFICATION; + /* + case SEC_E_INVALID_HANDLE: + case SEC_E_INVALID_TOKEN: + case SEC_E_LOGON_DENIED: + case SEC_E_TARGET_UNKNOWN: + case SEC_E_NO_AUTHENTICATING_AUTHORITY: + case SEC_E_INTERNAL_ERROR: + case SEC_E_NO_CREDENTIALS: + case SEC_E_UNSUPPORTED_FUNCTION: + case SEC_E_APPLICATION_PROTOCOL_MISMATCH: + */ + default: + failf(data, "schannel: next InitializeSecurityContext failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + return CURLE_SSL_CONNECT_ERROR; } } @@ -1237,8 +1361,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) #ifdef HAS_ALPN if(BACKEND->use_alpn) { - sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, - SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); + sspi_status = + s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + SECPKG_ATTR_APPLICATION_PROTOCOL, + &alpn_result); if(sspi_status != SEC_E_OK) { failf(data, "schannel: failed to retrieve ALPN result"); @@ -1249,21 +1375,21 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) SecApplicationProtocolNegotiationStatus_Success) { infof(data, "schannel: ALPN, server accepted to use %.*s\n", - alpn_result.ProtocolIdSize, alpn_result.ProtocolId); + alpn_result.ProtocolIdSize, alpn_result.ProtocolId); #ifdef USE_NGHTTP2 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId, - NGHTTP2_PROTO_VERSION_ID_LEN)) { + NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif - if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, - ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } + if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, + ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } } else infof(data, "ALPN, server did not agree to a protocol\n"); @@ -1310,8 +1436,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) if(data->set.ssl.certinfo) { int certs_count = 0; - sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, - SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); + sspi_status = + s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &ccert_context); if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) { failf(data, "schannel: failed to retrieve remote cert context"); @@ -1394,7 +1522,7 @@ schannel_connect_common(struct connectdata *conn, int sockindex, connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : (time_t)timeout_ms); + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); @@ -1543,14 +1671,10 @@ schannel_send(struct connectdata *conn, int sockindex, /* send entire message or fail */ while(len > (size_t)written) { - ssize_t this_write; - timediff_t timeleft; + ssize_t this_write = 0; int what; - - this_write = 0; - - timeleft = Curl_timeleft(conn->data, NULL, FALSE); - if(timeleft < 0) { + timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, FALSE); + if(timeout_ms < 0) { /* we already got the timeout */ failf(conn->data, "schannel: timed out sending data " "(bytes sent: %zd)", written); @@ -1558,8 +1682,9 @@ schannel_send(struct connectdata *conn, int sockindex, written = -1; break; } - - what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft); + else if(!timeout_ms) + timeout_ms = TIMEDIFF_T_MAX; + what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms); if(what < 0) { /* fatal error */ failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -1653,8 +1778,8 @@ schannel_recv(struct connectdata *conn, int sockindex, } else if(!len) { /* It's debatable what to return when !len. Regardless we can't return - immediately because there may be data to decrypt (in the case we want to - decrypt all encrypted cached data) so handle !len later in cleanup. + immediately because there may be data to decrypt (in the case we want to + decrypt all encrypted cached data) so handle !len later in cleanup. */ ; /* do nothing */ } @@ -1664,7 +1789,7 @@ schannel_recv(struct connectdata *conn, int sockindex, if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || BACKEND->encdata_length < min_encdata_length) { reallocated_length = BACKEND->encdata_offset + - CURL_SCHANNEL_BUFFER_FREE_SIZE; + CURL_SCHANNEL_BUFFER_FREE_SIZE; if(reallocated_length < min_encdata_length) { reallocated_length = min_encdata_length; } @@ -1732,7 +1857,7 @@ schannel_recv(struct connectdata *conn, int sockindex, InitSecBufferDesc(&inbuf_desc, inbuf, 4); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx - */ + */ sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); @@ -1748,7 +1873,7 @@ schannel_recv(struct connectdata *conn, int sockindex, /* increase buffer in order to fit the received amount of data */ size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? - inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; + inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; if(BACKEND->decdata_length - BACKEND->decdata_offset < size || BACKEND->decdata_length < len) { /* increase internal decrypted data buffer */ @@ -1818,7 +1943,7 @@ schannel_recv(struct connectdata *conn, int sockindex, if(BACKEND->encdata_offset) { *err = CURLE_RECV_ERROR; infof(data, "schannel: can't renogotiate, " - "encrypted data available\n"); + "encrypted data available\n"); goto cleanup; } /* begin renegotiation */ @@ -1873,17 +1998,20 @@ schannel_recv(struct connectdata *conn, int sockindex, "schannel: decrypted data buffer: offset %zu length %zu\n", BACKEND->decdata_offset, BACKEND->decdata_length)); -cleanup: + cleanup: /* Warning- there is no guarantee the encdata state is valid at this point */ DEBUGF(infof(data, "schannel: schannel_recv cleanup\n")); /* Error if the connection has closed without a close_notify. - Behavior here is a matter of debate. We don't want to be vulnerable to a - truncation attack however there's some browser precedent for ignoring the - close_notify for compatibility reasons. - Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't - return close_notify. In that case if the connection was closed we assume it - was graceful (close_notify) since there doesn't seem to be a way to tell. + + The behavior here is a matter of debate. We don't want to be vulnerable + to a truncation attack however there's some browser precedent for + ignoring the close_notify for compatibility reasons. + + Additionally, Windows 2000 (v5.0) is a special case since it seems it + doesn't return close_notify. In that case if the connection was closed we + assume it was graceful (close_notify) since there doesn't seem to be a + way to tell. */ if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed && !BACKEND->recv_sspi_close_notify) { @@ -1900,7 +2028,7 @@ cleanup: /* Any error other than CURLE_AGAIN is an unrecoverable error. */ if(*err && *err != CURLE_AGAIN) - BACKEND->recv_unrecoverable_err = *err; + BACKEND->recv_unrecoverable_err = *err; size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset; if(size) { @@ -1917,10 +2045,11 @@ cleanup: } if(!*err && !BACKEND->recv_connection_closed) - *err = CURLE_AGAIN; + *err = CURLE_AGAIN; - /* It's debatable what to return when !len. We could return whatever error we - got from decryption but instead we override here so the return is consistent. + /* It's debatable what to return when !len. We could return whatever error + we got from decryption but instead we override here so the return is + consistent. */ if(!len) *err = CURLE_OK; @@ -1986,8 +2115,12 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) */ struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; +#ifndef CURL_DISABLE_PROXY char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; +#else + char * const hostname = conn->host.name; +#endif DEBUGASSERT(data); @@ -2016,7 +2149,7 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); } - host_name = Curl_convert_UTF8_to_tchar(hostname); + host_name = curlx_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; @@ -2038,7 +2171,7 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); - Curl_unicodefree(host_name); + curlx_unicodefree(host_name); if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { /* send close message which is in output buffer */ @@ -2147,8 +2280,8 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex, SECURITY_STATUS sspi_status; const char *x509_der; DWORD x509_der_len; - curl_X509certificate x509_parsed; - curl_asn1Element *pubkey; + struct Curl_X509certificate x509_parsed; + struct Curl_asn1Element *pubkey; sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, @@ -2164,7 +2297,7 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex, if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) && - (pCertContextServer->cbCertEncoded > 0))) + (pCertContextServer->cbCertEncoded > 0))) break; x509_der = (const char *)pCertContextServer->pbCertEncoded; @@ -2213,7 +2346,7 @@ static void Curl_schannel_checksum(const unsigned char *input, memset(checksum, 0, checksumlen); if(!CryptAcquireContext(&hProv, NULL, NULL, provType, - CRYPT_VERIFYCONTEXT)) + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) return; /* failed */ do { @@ -2255,9 +2388,9 @@ static CURLcode Curl_schannel_md5sum(unsigned char *input, } static CURLcode Curl_schannel_sha256sum(const unsigned char *input, - size_t inputlen, - unsigned char *sha256sum, - size_t sha256len) + size_t inputlen, + unsigned char *sha256sum, + size_t sha256len) { Curl_schannel_checksum(input, inputlen, sha256sum, sha256len, PROV_RSA_AES, CALG_SHA_256); diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c index e75132c..bdd7199 100644 --- a/Utilities/cmcurl/lib/vtls/schannel_verify.c +++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c @@ -57,7 +57,7 @@ #define BEGIN_CERT "-----BEGIN CERTIFICATE-----" #define END_CERT "\n-----END CERTIFICATE-----" -typedef struct { +struct cert_chain_engine_config_win7 { DWORD cbSize; HCERTSTORE hRestrictedRoot; HCERTSTORE hRestrictedTrust; @@ -70,7 +70,7 @@ typedef struct { DWORD CycleDetectionModulus; HCERTSTORE hExclusiveRoot; HCERTSTORE hExclusiveTrustedPeople; -} CERT_CHAIN_ENGINE_CONFIG_WIN7, *PCERT_CHAIN_ENGINE_CONFIG_WIN7; +}; static int is_cr_or_lf(char c) { @@ -94,7 +94,7 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store, int num_certs = 0; size_t END_CERT_LEN; - ca_file_tstr = Curl_convert_UTF8_to_tchar((char *)ca_file); + ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file); if(!ca_file_tstr) { char buffer[STRERROR_LEN]; failf(data, @@ -288,7 +288,7 @@ cleanup: CloseHandle(ca_file_handle); } Curl_safefree(ca_file_buffer); - Curl_unicodefree(ca_file_tstr); + curlx_unicodefree(ca_file_tstr); return result; } @@ -361,7 +361,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data, return actual_length; } - decode_para.cbSize = sizeof(CRYPT_DECODE_PARA); + decode_para.cbSize = sizeof(CRYPT_DECODE_PARA); ret_val = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, @@ -476,7 +476,7 @@ static CURLcode verify_host(struct Curl_easy *data, * is acceptable since both values are assumed to use ASCII * (or some equivalent) encoding */ - cert_hostname = Curl_convert_tchar_to_UTF8( + cert_hostname = curlx_convert_tchar_to_UTF8( &cert_hostname_buff[cert_hostname_buff_index]); if(!cert_hostname) { result = CURLE_OUT_OF_MEMORY; @@ -508,7 +508,7 @@ static CURLcode verify_host(struct Curl_easy *data, result = CURLE_PEER_FAILED_VERIFICATION; } - Curl_unicodefree(cert_hostname); + curlx_unicodefree(cert_hostname); } } @@ -522,7 +522,7 @@ static CURLcode verify_host(struct Curl_easy *data, failf(data, "schannel: server certificate name verification failed"); cleanup: - Curl_unicodefree(cert_hostname_buff); + curlx_unicodefree(cert_hostname_buff); return result; } @@ -537,9 +537,13 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex) const CERT_CHAIN_CONTEXT *pChainContext = NULL; HCERTCHAINENGINE cert_chain_engine = NULL; HCERTSTORE trust_store = NULL; +#ifndef CURL_DISABLE_PROXY const char * const conn_hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; +#else + const char * const conn_hostname = conn->host.name; +#endif sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, @@ -585,7 +589,7 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex) } if(result == CURLE_OK) { - CERT_CHAIN_ENGINE_CONFIG_WIN7 engine_config; + struct cert_chain_engine_config_win7 engine_config; BOOL create_engine_result; memset(&engine_config, 0, sizeof(engine_config)); @@ -636,6 +640,15 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex) CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED); dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; + + if(data->set.ssl.revoke_best_effort) { + /* Ignore errors when root certificates are missing the revocation + * list URL, or when the list could not be downloaded because the + * server is currently unreachable. */ + dwTrustErrorMask &= ~(DWORD)(CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION); + } + if(dwTrustErrorMask) { if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) failf(data, "schannel: CertGetCertificateChain trust error" diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c index 7dd028f..2627aff 100644 --- a/Utilities/cmcurl/lib/vtls/sectransp.c +++ b/Utilities/cmcurl/lib/vtls/sectransp.c @@ -138,8 +138,6 @@ struct ssl_backend_data { size_t ssl_write_buffered_length; }; -#define BACKEND connssl->backend - /* pinned public key support tests */ /* version 1 supports macOS 10.12+ and iOS 10+ */ @@ -201,7 +199,8 @@ static OSStatus SocketRead(SSLConnectionRef connection, UInt8 *currData = (UInt8 *)data; /*int sock = *(int *)connection;*/ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; - int sock = BACKEND->ssl_sockfd; + struct ssl_backend_data *backend = connssl->backend; + int sock = backend->ssl_sockfd; OSStatus rtn = noErr; size_t bytesRead; ssize_t rrtn; @@ -230,7 +229,7 @@ static OSStatus SocketRead(SSLConnectionRef connection, break; case EAGAIN: rtn = errSSLWouldBlock; - BACKEND->ssl_direction = false; + backend->ssl_direction = false; break; default: rtn = ioErr; @@ -261,7 +260,8 @@ static OSStatus SocketWrite(SSLConnectionRef connection, size_t bytesSent = 0; /*int sock = *(int *)connection;*/ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; - int sock = BACKEND->ssl_sockfd; + struct ssl_backend_data *backend = connssl->backend; + int sock = backend->ssl_sockfd; ssize_t length; size_t dataLen = *dataLength; const UInt8 *dataPtr = (UInt8 *)data; @@ -281,7 +281,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection, theErr = errno; if(theErr == EAGAIN) { ortn = errSSLWouldBlock; - BACKEND->ssl_direction = true; + backend->ssl_direction = true; } else { ortn = ioErr; @@ -1126,12 +1126,12 @@ static OSStatus CopyIdentityWithLabel(char *label, } static OSStatus CopyIdentityFromPKCS12File(const char *cPath, + const struct curl_blob *blob, const char *cPassword, SecIdentityRef *out_cert_and_key) { OSStatus status = errSecItemNotFound; - CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL, - (const UInt8 *)cPath, strlen(cPath), false); + CFURLRef pkcs_url = NULL; CFStringRef password = cPassword ? CFStringCreateWithCString(NULL, cPassword, kCFStringEncodingUTF8) : NULL; CFDataRef pkcs_data = NULL; @@ -1140,8 +1140,26 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath, /* These constants are documented as having first appeared in 10.6 but they raise linker errors when used on that cat for some reason. */ #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS - if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data, - NULL, NULL, &status)) { + bool resource_imported; + + if(blob) { + pkcs_data = CFDataCreate(kCFAllocatorDefault, + (const unsigned char *)blob->data, blob->len); + status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate; + resource_imported = (pkcs_data != NULL); + } + else { + pkcs_url = + CFURLCreateFromFileSystemRepresentation(NULL, + (const UInt8 *)cPath, + strlen(cPath), false); + resource_imported = + CFURLCreateDataAndPropertiesFromResource(NULL, + pkcs_url, &pkcs_data, + NULL, NULL, &status); + } + + if(resource_imported) { CFArrayRef items = NULL; /* On iOS SecPKCS12Import will never add the client certificate to the @@ -1219,7 +1237,8 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath, #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ if(password) CFRelease(password); - CFRelease(pkcs_url); + if(pkcs_url) + CFRelease(pkcs_url); return status; } @@ -1276,6 +1295,7 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); long max_supported_version_by_os; @@ -1326,30 +1346,30 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) return result; } - (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, darwin_ver_min); - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, darwin_ver_max); + (void)SSLSetProtocolVersionMin(backend->ssl_ctx, darwin_ver_min); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, darwin_ver_max); return result; } else { #if CURL_SUPPORT_MAC_10_8 long i = ssl_version; - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false); for(; i <= (ssl_version_max >> 16); i++) { switch(i) { case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true); break; case CURL_SSLVERSION_TLSv1_1: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol11, true); break; case CURL_SSLVERSION_TLSv1_2: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol12, true); break; @@ -1373,9 +1393,12 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const struct curl_blob *ssl_cablob = NULL; const bool verifypeer = SSL_CONN_CONFIG(verifypeer); char * const ssl_cert = SSL_SET_OPTION(cert); + const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(cert_blob); const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; @@ -1395,10 +1418,10 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext != NULL) { /* use the newer API if available */ - if(BACKEND->ssl_ctx) - CFRelease(BACKEND->ssl_ctx); - BACKEND->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); - if(!BACKEND->ssl_ctx) { + if(backend->ssl_ctx) + CFRelease(backend->ssl_ctx); + backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); + if(!backend->ssl_ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } @@ -1406,9 +1429,9 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, else { /* The old ST API does not exist under iOS, so don't compile it: */ #if CURL_SUPPORT_MAC_10_8 - if(BACKEND->ssl_ctx) - (void)SSLDisposeContext(BACKEND->ssl_ctx); - err = SSLNewContext(false, &(BACKEND->ssl_ctx)); + if(backend->ssl_ctx) + (void)SSLDisposeContext(backend->ssl_ctx); + err = SSLNewContext(false, &(backend->ssl_ctx)); if(err != noErr) { failf(data, "SSL: couldn't create a context: OSStatus %d", err); return CURLE_OUT_OF_MEMORY; @@ -1416,31 +1439,31 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, #endif /* CURL_SUPPORT_MAC_10_8 */ } #else - if(BACKEND->ssl_ctx) - (void)SSLDisposeContext(BACKEND->ssl_ctx); - err = SSLNewContext(false, &(BACKEND->ssl_ctx)); + if(backend->ssl_ctx) + (void)SSLDisposeContext(backend->ssl_ctx); + err = SSLNewContext(false, &(backend->ssl_ctx)); if(err != noErr) { failf(data, "SSL: couldn't create a context: OSStatus %d", err); return CURLE_OUT_OF_MEMORY; } #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - BACKEND->ssl_write_buffered_length = 0UL; /* reset buffered write length */ + backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */ /* check to see if we've been told to use an explicit SSL/TLS version */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLSetProtocolVersionMax != NULL) { switch(conn->ssl_config.version) { case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kTLSProtocol1); + (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1); #if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 if(__builtin_available(macOS 10.13, iOS 11.0, *)) { - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol13); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol13); } else { - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12); } #else - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12); #endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 */ break; @@ -1456,20 +1479,20 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, break; } case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol3); + err = SSLSetProtocolVersionMin(backend->ssl_ctx, kSSLProtocol3); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv3"); return CURLE_SSL_CONNECT_ERROR; } - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol3); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kSSLProtocol3); break; case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol2); + err = SSLSetProtocolVersionMin(backend->ssl_ctx, kSSLProtocol2); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol2); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kSSLProtocol2); break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); @@ -1478,19 +1501,19 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } else { #if CURL_SUPPORT_MAC_10_8 - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false); switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true); - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol11, true); - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol12, true); break; @@ -1505,7 +1528,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, break; } case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + err = SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocol3, true); if(err != noErr) { @@ -1514,7 +1537,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } break; case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + err = SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocol2, true); if(err != noErr) { @@ -1534,12 +1557,12 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, " SSL/TLS version"); return CURLE_SSL_CONNECT_ERROR; } - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocolAll, false); + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false); switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true); break; @@ -1553,7 +1576,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, failf(data, "Your version of the OS does not support TLSv1.3"); return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + err = SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocol2, true); if(err != noErr) { @@ -1562,7 +1585,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } break; case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + err = SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocol3, true); if(err != noErr) { @@ -1596,7 +1619,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, /* expects length prefixed preference ordered list of protocols in wire * format */ - err = SSLSetALPNProtocols(BACKEND->ssl_ctx, alpnArr); + err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr); if(err != noErr) infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d\n", err); @@ -1610,15 +1633,16 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, "Transport. The private key must be in the Keychain.\n"); } - if(ssl_cert) { + if(ssl_cert || ssl_cert_blob) { + bool is_cert_data = ssl_cert_blob != NULL; + bool is_cert_file = (!is_cert_data) && is_file(ssl_cert); SecIdentityRef cert_and_key = NULL; - bool is_cert_file = is_file(ssl_cert); /* User wants to authenticate with a client cert. Look for it: If we detect that this is a file on disk, then let's load it. Otherwise, assume that the user wants to use an identity loaded from the Keychain. */ - if(is_cert_file) { + if(is_cert_file || is_cert_data) { if(!SSL_SET_OPTION(cert_type)) infof(data, "WARNING: SSL: Certificate type not set, assuming " "PKCS#12 format.\n"); @@ -1627,7 +1651,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, infof(data, "WARNING: SSL: The Security framework only supports " "loading identities that are in PKCS#12 format.\n"); - err = CopyIdentityFromPKCS12File(ssl_cert, + err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob, SSL_SET_OPTION(key_passwd), &cert_and_key); } else @@ -1657,7 +1681,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, certs_c[0] = cert_and_key; certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, &kCFTypeArrayCallBacks); - err = SSLSetCertificate(BACKEND->ssl_ctx, certs); + err = SSLSetCertificate(backend->ssl_ctx, certs); if(certs) CFRelease(certs); if(err != noErr) { @@ -1667,27 +1691,30 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, CFRelease(cert_and_key); } else { + const char *cert_showfilename_error = + is_cert_data ? "(memory blob)" : ssl_cert; + switch(err) { case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ failf(data, "SSL: Incorrect password for the certificate \"%s\" " - "and its private key.", ssl_cert); + "and its private key.", cert_showfilename_error); break; case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ failf(data, "SSL: Couldn't make sense of the data in the " "certificate \"%s\" and its private key.", - ssl_cert); + cert_showfilename_error); break; case -25260: /* errSecPassphraseRequired */ failf(data, "SSL The certificate \"%s\" requires a password.", - ssl_cert); + cert_showfilename_error); break; case errSecItemNotFound: failf(data, "SSL: Can't find the certificate \"%s\" and its private " - "key in the Keychain.", ssl_cert); + "key in the Keychain.", cert_showfilename_error); break; default: failf(data, "SSL: Can't load the certificate \"%s\" and its private " - "key: OSStatus %d", ssl_cert, err); + "key: OSStatus %d", cert_showfilename_error, err); break; } return CURLE_SSL_CERTPROBLEM; @@ -1719,8 +1746,9 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, #else if(SSLSetSessionOption != NULL) { #endif /* CURL_BUILD_MAC */ - bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile; - err = SSLSetSessionOption(BACKEND->ssl_ctx, + bool break_on_auth = !conn->ssl_config.verifypeer || + ssl_cafile || ssl_cablob; + err = SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionBreakOnServerAuth, break_on_auth); if(err != noErr) { @@ -1730,7 +1758,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } else { #if CURL_SUPPORT_MAC_10_8 - err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, + err = SSLSetEnableCertVerify(backend->ssl_ctx, conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); @@ -1739,7 +1767,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, #endif /* CURL_SUPPORT_MAC_10_8 */ } #else - err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, + err = SSLSetEnableCertVerify(backend->ssl_ctx, conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); @@ -1747,10 +1775,11 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ - if(ssl_cafile && verifypeer) { - bool is_cert_file = is_file(ssl_cafile); + if((ssl_cafile || ssl_cablob) && verifypeer) { + bool is_cert_data = ssl_cablob != NULL; + bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile); - if(!is_cert_file) { + if(!(is_cert_file || is_cert_data)) { failf(data, "SSL: can't load CA certificate file %s", ssl_cafile); return CURLE_SSL_CACERT_BADFILE; } @@ -1760,7 +1789,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, * Both hostname check and SNI require SSLSetPeerDomainName(). * Also: the verifyhost setting influences SNI usage */ if(conn->ssl_config.verifyhost) { - err = SSLSetPeerDomainName(BACKEND->ssl_ctx, hostname, + err = SSLSetPeerDomainName(backend->ssl_ctx, hostname, strlen(hostname)); if(err != noErr) { @@ -1786,7 +1815,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, higher priority, but it's probably better that we not connect at all than to give the user a false sense of security if the server only supports insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */ - err = SSLGetNumberSupportedCiphers(BACKEND->ssl_ctx, &all_ciphers_count); + err = SSLGetNumberSupportedCiphers(backend->ssl_ctx, &all_ciphers_count); if(err != noErr) { failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d", err); @@ -1803,7 +1832,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, failf(data, "SSL: Failed to allocate memory for allowed ciphers"); return CURLE_OUT_OF_MEMORY; } - err = SSLGetSupportedCiphers(BACKEND->ssl_ctx, all_ciphers, + err = SSLGetSupportedCiphers(backend->ssl_ctx, all_ciphers, &all_ciphers_count); if(err != noErr) { Curl_safefree(all_ciphers); @@ -1890,7 +1919,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, break; } } - err = SSLSetEnabledCiphers(BACKEND->ssl_ctx, allowed_ciphers, + err = SSLSetEnabledCiphers(backend->ssl_ctx, allowed_ciphers, allowed_ciphers_count); Curl_safefree(all_ciphers); Curl_safefree(allowed_ciphers); @@ -1903,9 +1932,9 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, /* We want to enable 1/n-1 when using a CBC cipher unless the user specifically doesn't want us doing that: */ if(SSLSetSessionOption != NULL) { - SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionSendOneByteRecord, + SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord, !data->set.ssl.enable_beast); - SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionFalseStart, + SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart, data->set.ssl.falsestart); /* false start support */ } #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ @@ -1919,7 +1948,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, &ssl_sessionid_len, sockindex)) { /* we got a session id, use it! */ - err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); Curl_ssl_sessionid_unlock(conn); if(err != noErr) { failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); @@ -1937,7 +1966,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port); ssl_sessionid_len = strlen(ssl_sessionid); - err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); if(err != noErr) { Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); @@ -1954,7 +1983,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } } - err = SSLSetIOFuncs(BACKEND->ssl_ctx, SocketRead, SocketWrite); + err = SSLSetIOFuncs(backend->ssl_ctx, SocketRead, SocketWrite); if(err != noErr) { failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; @@ -1964,8 +1993,8 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, /* We need to store the FD in a constant memory address, because * SSLSetConnection() will not copy that address. I've found that * conn->sock[sockindex] may change on its own. */ - BACKEND->ssl_sockfd = sockfd; - err = SSLSetConnection(BACKEND->ssl_ctx, connssl); + backend->ssl_sockfd = sockfd; + err = SSLSetConnection(backend->ssl_ctx, connssl); if(err != noErr) { failf(data, "SSL: SSLSetConnection() failed: %d", err); return CURLE_SSL_CONNECT_ERROR; @@ -2346,6 +2375,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; OSStatus err; SSLCipherSuite cipher; SSLProtocol protocol = 0; @@ -2357,12 +2387,12 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ - err = SSLHandshake(BACKEND->ssl_ctx); + err = SSLHandshake(backend->ssl_ctx); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* they're not done with us yet */ - connssl->connecting_state = BACKEND->ssl_direction ? + connssl->connecting_state = backend->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; @@ -2371,7 +2401,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) case -9841: if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), data, - BACKEND->ssl_ctx); + backend->ssl_ctx); if(result) return result; } @@ -2580,7 +2610,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) #ifdef SECTRANSP_PINNEDPUBKEY if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) { - CURLcode result = pkp_pin_peer_pubkey(data, BACKEND->ssl_ctx, + CURLcode result = pkp_pin_peer_pubkey(data, backend->ssl_ctx, data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]); if(result) { failf(data, "SSL: public key does not match pinned public key!"); @@ -2590,8 +2620,8 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) #endif /* SECTRANSP_PINNEDPUBKEY */ /* Informational message */ - (void)SSLGetNegotiatedCipher(BACKEND->ssl_ctx, &cipher); - (void)SSLGetNegotiatedProtocolVersion(BACKEND->ssl_ctx, &protocol); + (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher); + (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol); switch(protocol) { case kSSLProtocol2: infof(data, "SSL 2.0 connection using %s\n", @@ -2631,7 +2661,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { CFArrayRef alpnArr = NULL; CFStringRef chosenProtocol = NULL; - err = SSLCopyALPNProtocols(BACKEND->ssl_ctx, &alpnArr); + err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr); if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1) chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0); @@ -2674,19 +2704,20 @@ show_verbose_server_cert(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CFArrayRef server_certs = NULL; SecCertificateRef server_cert; OSStatus err; CFIndex i, count; SecTrustRef trust = NULL; - if(!BACKEND->ssl_ctx) + if(!backend->ssl_ctx) return; #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS #if CURL_BUILD_IOS #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 a null trust, so be on guard for that: */ if(err == noErr && trust) { @@ -2712,7 +2743,7 @@ show_verbose_server_cert(struct connectdata *conn, Lion or later. */ if(SecTrustEvaluateAsync != NULL) { #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 a null trust, so be on guard for that: */ if(err == noErr && trust) { @@ -2732,7 +2763,7 @@ show_verbose_server_cert(struct connectdata *conn, } else { #if CURL_SUPPORT_MAC_10_8 - err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); + err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); /* Just in case SSLCopyPeerCertificates() returns null too... */ if(err == noErr && server_certs) { count = CFArrayGetCount(server_certs); @@ -2754,7 +2785,7 @@ show_verbose_server_cert(struct connectdata *conn, #endif /* CURL_BUILD_IOS */ #else #pragma unused(trust) - err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); + err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); if(err == noErr) { count = CFArrayGetCount(server_certs); for(i = 0L ; i < count ; i++) { @@ -2805,7 +2836,6 @@ sectransp_connect_common(struct connectdata *conn, struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; - timediff_t timeout_ms; int what; /* check if the connection has already been established */ @@ -2816,7 +2846,7 @@ sectransp_connect_common(struct connectdata *conn, if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ @@ -2834,7 +2864,7 @@ sectransp_connect_common(struct connectdata *conn, ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ @@ -2852,7 +2882,7 @@ sectransp_connect_common(struct connectdata *conn, connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:(time_t)timeout_ms); + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -2933,34 +2963,36 @@ static CURLcode Curl_sectransp_connect(struct connectdata *conn, int sockindex) static void Curl_sectransp_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; - if(BACKEND->ssl_ctx) { - (void)SSLClose(BACKEND->ssl_ctx); + if(backend->ssl_ctx) { + (void)SSLClose(backend->ssl_ctx); #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext != NULL) - CFRelease(BACKEND->ssl_ctx); + CFRelease(backend->ssl_ctx); #if CURL_SUPPORT_MAC_10_8 else - (void)SSLDisposeContext(BACKEND->ssl_ctx); + (void)SSLDisposeContext(backend->ssl_ctx); #endif /* CURL_SUPPORT_MAC_10_8 */ #else - (void)SSLDisposeContext(BACKEND->ssl_ctx); + (void)SSLDisposeContext(backend->ssl_ctx); #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - BACKEND->ssl_ctx = NULL; + backend->ssl_ctx = NULL; } - BACKEND->ssl_sockfd = 0; + backend->ssl_sockfd = 0; } static int Curl_sectransp_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; struct Curl_easy *data = conn->data; ssize_t nread; int what; int rc; char buf[120]; - if(!BACKEND->ssl_ctx) + if(!backend->ssl_ctx) return 0; #ifndef CURL_DISABLE_FTP @@ -3033,11 +3065,12 @@ static size_t Curl_sectransp_version(char *buffer, size_t size) static int Curl_sectransp_check_cxn(struct connectdata *conn) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + struct ssl_backend_data *backend = connssl->backend; OSStatus err; SSLSessionState state; - if(BACKEND->ssl_ctx) { - err = SSLGetSessionState(BACKEND->ssl_ctx, &state); + if(backend->ssl_ctx) { + err = SSLGetSessionState(backend->ssl_ctx, &state); if(err == noErr) return state == kSSLConnected || state == kSSLHandshake; return -1; @@ -3049,11 +3082,12 @@ static bool Curl_sectransp_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; + struct ssl_backend_data *backend = connssl->backend; OSStatus err; size_t buffer; - if(BACKEND->ssl_ctx) { /* SSL is in use */ - err = SSLGetBufferedReadSize(BACKEND->ssl_ctx, &buffer); + if(backend->ssl_ctx) { /* SSL is in use */ + err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer); if(err == noErr) return buffer > 0UL; return false; @@ -3119,6 +3153,7 @@ static ssize_t sectransp_send(struct connectdata *conn, { /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; size_t processed = 0UL; OSStatus err; @@ -3137,15 +3172,15 @@ static ssize_t sectransp_send(struct connectdata *conn, over again with no new data until it quits returning errSSLWouldBlock. */ /* Do we have buffered data to write from the last time we were called? */ - if(BACKEND->ssl_write_buffered_length) { + if(backend->ssl_write_buffered_length) { /* Write the buffered data: */ - err = SSLWrite(BACKEND->ssl_ctx, NULL, 0UL, &processed); + err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed); switch(err) { case noErr: /* processed is always going to be 0 because we didn't write to the buffer, so return how much was written to the socket */ - processed = BACKEND->ssl_write_buffered_length; - BACKEND->ssl_write_buffered_length = 0UL; + processed = backend->ssl_write_buffered_length; + backend->ssl_write_buffered_length = 0UL; break; case errSSLWouldBlock: /* argh, try again */ *curlcode = CURLE_AGAIN; @@ -3158,13 +3193,13 @@ static ssize_t sectransp_send(struct connectdata *conn, } else { /* We've got new data to write: */ - err = SSLWrite(BACKEND->ssl_ctx, mem, len, &processed); + err = SSLWrite(backend->ssl_ctx, mem, len, &processed); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* Data was buffered but not sent, we have to tell the caller to try sending again, and remember how much was buffered */ - BACKEND->ssl_write_buffered_length = len; + backend->ssl_write_buffered_length = len; *curlcode = CURLE_AGAIN; return -1L; default: @@ -3185,11 +3220,12 @@ static ssize_t sectransp_recv(struct connectdata *conn, { /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; size_t processed = 0UL; OSStatus err; again: - err = SSLRead(BACKEND->ssl_ctx, buf, buffersize, &processed); + err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed); if(err != noErr) { switch(err) { @@ -3215,7 +3251,7 @@ static ssize_t sectransp_recv(struct connectdata *conn, case -9841: if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), conn->data, - BACKEND->ssl_ctx); + backend->ssl_ctx); if(result) return result; } @@ -3233,8 +3269,9 @@ static ssize_t sectransp_recv(struct connectdata *conn, static void *Curl_sectransp_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->ssl_ctx; + return backend->ssl_ctx; } const struct Curl_ssl Curl_ssl_sectransp = { diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index dfefa1b..dfe2601 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -83,8 +83,8 @@ dest->var = NULL; bool -Curl_ssl_config_matches(struct ssl_primary_config* data, - struct ssl_primary_config* needle) +Curl_ssl_config_matches(struct ssl_primary_config *data, + struct ssl_primary_config *needle) { if((data->version == needle->version) && (data->version_max == needle->version_max) && @@ -127,7 +127,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, return TRUE; } -void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc) +void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) { Curl_safefree(sslc->CApath); Curl_safefree(sslc->CAfile); @@ -174,6 +174,9 @@ int Curl_ssl_init(void) return Curl_ssl->init(); } +#if defined(CURL_WITH_MULTI_SSL) +static const struct Curl_ssl Curl_ssl_multi; +#endif /* Global cleanup */ void Curl_ssl_cleanup(void) @@ -181,6 +184,9 @@ void Curl_ssl_cleanup(void) if(init_ssl) { /* only cleanup if we did a previous init */ Curl_ssl->cleanup(); +#if defined(CURL_WITH_MULTI_SSL) + Curl_ssl = &Curl_ssl_multi; +#endif init_ssl = FALSE; } } @@ -209,6 +215,7 @@ static bool ssl_prefs_check(struct Curl_easy *data) return TRUE; } +#ifndef CURL_DISABLE_PROXY static CURLcode ssl_connect_init_proxy(struct connectdata *conn, int sockindex) { @@ -232,17 +239,20 @@ ssl_connect_init_proxy(struct connectdata *conn, int sockindex) } return CURLE_OK; } +#endif CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex) { CURLcode result; +#ifndef CURL_DISABLE_PROXY if(conn->bits.proxy_ssl_connected[sockindex]) { result = ssl_connect_init_proxy(conn, sockindex); if(result) return result; } +#endif if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; @@ -264,12 +274,13 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; +#ifndef CURL_DISABLE_PROXY if(conn->bits.proxy_ssl_connected[sockindex]) { result = ssl_connect_init_proxy(conn, sockindex); if(result) return result; } - +#endif if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; @@ -315,13 +326,21 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, long *general_age; bool no_match = TRUE; +#ifndef CURL_DISABLE_PROXY const bool isProxy = CONNECT_PROXY_SSL(); struct ssl_primary_config * const ssl_config = isProxy ? &conn->proxy_ssl_config : &conn->ssl_config; - const char * const name = isProxy ? conn->http_proxy.host.name : - conn->host.name; + const char * const name = isProxy ? + conn->http_proxy.host.name : conn->host.name; int port = isProxy ? (int)conn->port : conn->remote_port; +#else + /* no proxy support */ + struct ssl_primary_config * const ssl_config = &conn->ssl_config; + const char * const name = conn->host.name; + int port = conn->remote_port; + (void)sockindex; +#endif *ssl_sessionid = NULL; DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); @@ -423,14 +442,23 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, char *clone_conn_to_host; int conn_to_port; long *general_age; +#ifndef CURL_DISABLE_PROXY const bool isProxy = CONNECT_PROXY_SSL(); struct ssl_primary_config * const ssl_config = isProxy ? &conn->proxy_ssl_config : &conn->ssl_config; - + const char *hostname = isProxy ? conn->http_proxy.host.name : + conn->host.name; +#else + /* proxy support disabled */ + const bool isProxy = FALSE; + struct ssl_primary_config * const ssl_config = &conn->ssl_config; + const char *hostname = conn->host.name; + (void)sockindex; +#endif DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); - clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name); + clone_host = strdup(hostname); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ @@ -489,6 +517,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->scheme = conn->handler->scheme; if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) { + Curl_free_primary_ssl_config(&store->ssl_config); store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); free(clone_conn_to_host); @@ -1077,7 +1106,7 @@ bool Curl_none_false_start(void) CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, unsigned char *md5sum, size_t md5len UNUSED_PARAM) { - MD5_context *MD5pw; + struct MD5_context *MD5pw; (void)md5len; diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h index f58adee..bcc8444 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.h +++ b/Utilities/cmcurl/lib/vtls/vtls.h @@ -113,12 +113,6 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, #define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ #endif -#ifndef MD5_DIGEST_LENGTH -#ifndef LIBWOLFSSL_VERSION_HEX /* because WolfSSL borks this */ -#define MD5_DIGEST_LENGTH 16 /* fixed size */ -#endif -#endif - #ifndef CURL_SHA256_DIGEST_LENGTH #define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */ #endif @@ -129,20 +123,27 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, /* set of helper macros for the backends to access the correct fields. For the proxy or for the remote host - to properly support HTTPS proxy */ +#ifndef CURL_DISABLE_PROXY +#define SSL_IS_PROXY() \ + (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \ + ssl_connection_complete != \ + conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \ + CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state) +#define SSL_SET_OPTION(var) \ + (SSL_IS_PROXY() ? data->set.proxy_ssl.var : data->set.ssl.var) +#define SSL_CONN_CONFIG(var) \ + (SSL_IS_PROXY() ? conn->proxy_ssl_config.var : conn->ssl_config.var) +#else +#define SSL_IS_PROXY() FALSE +#define SSL_SET_OPTION(var) data->set.ssl.var +#define SSL_CONN_CONFIG(var) conn->ssl_config.var +#endif -#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \ - ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \ - CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state) -#define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \ - data->set.ssl.var) -#define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \ - conn->proxy_ssl_config.var : conn->ssl_config.var) - -bool Curl_ssl_config_matches(struct ssl_primary_config* data, - struct ssl_primary_config* needle); +bool Curl_ssl_config_matches(struct ssl_primary_config *data, + struct ssl_primary_config *needle); bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source, struct ssl_primary_config *dest); -void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc); +void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc); int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks); int Curl_ssl_backend(void); @@ -262,7 +263,6 @@ bool Curl_ssl_false_start(void); #define Curl_ssl_send(a,b,c,d,e) -1 #define Curl_ssl_recv(a,b,c,d,e) -1 #define Curl_ssl_initsessions(x,y) CURLE_OK -#define Curl_ssl_version(x,y) 0 #define Curl_ssl_data_pending(x,y) 0 #define Curl_ssl_check_cxn(x) 0 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c index 8c2d3f4..7b2a124 100644 --- a/Utilities/cmcurl/lib/vtls/wolfssl.c +++ b/Utilities/cmcurl/lib/vtls/wolfssl.c @@ -63,6 +63,7 @@ #include "sendf.h" #include "inet_pton.h" #include "vtls.h" +#include "keylog.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" @@ -96,11 +97,109 @@ struct ssl_backend_data { SSL* handle; }; -#define BACKEND connssl->backend - static Curl_recv wolfssl_recv; static Curl_send wolfssl_send; +#ifdef OPENSSL_EXTRA +/* + * Availability note: + * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in + * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that + * option is not set, then TLS 1.3 will not be logged. + * For TLS 1.2 and before, we use wolfSSL_get_keys(). + * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA + * (--enable-opensslextra or --enable-all). + */ +#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) +static int +wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret, + int secretSz, void *ctx) +{ + const char *label; + unsigned char client_random[SSL3_RANDOM_SIZE]; + (void)ctx; + + if(!ssl || !Curl_tls_keylog_enabled()) { + return 0; + } + + switch(id) { + case CLIENT_EARLY_TRAFFIC_SECRET: + label = "CLIENT_EARLY_TRAFFIC_SECRET"; + break; + case CLIENT_HANDSHAKE_TRAFFIC_SECRET: + label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"; + break; + case SERVER_HANDSHAKE_TRAFFIC_SECRET: + label = "SERVER_HANDSHAKE_TRAFFIC_SECRET"; + break; + case CLIENT_TRAFFIC_SECRET: + label = "CLIENT_TRAFFIC_SECRET_0"; + break; + case SERVER_TRAFFIC_SECRET: + label = "SERVER_TRAFFIC_SECRET_0"; + break; + case EARLY_EXPORTER_SECRET: + label = "EARLY_EXPORTER_SECRET"; + break; + case EXPORTER_SECRET: + label = "EXPORTER_SECRET"; + break; + default: + return 0; + } + + if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) { + /* Should never happen as wolfSSL_KeepArrays() was called before. */ + return 0; + } + + Curl_tls_keylog_write(label, client_random, secret, secretSz); + return 0; +} +#endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */ + +static void +wolfssl_log_tls12_secret(SSL *ssl) +{ + unsigned char *ms, *sr, *cr; + unsigned int msLen, srLen, crLen, i, x = 0; + +#if LIBWOLFSSL_VERSION_HEX >= 0x0300d000 /* >= 3.13.0 */ + /* wolfSSL_GetVersion is available since 3.13, we use it instead of + * SSL_version since the latter relies on OPENSSL_ALL (--enable-opensslall or + * --enable-all). Failing to perform this check could result in an unusable + * key log line when TLS 1.3 is actually negotiated. */ + switch(wolfSSL_GetVersion(ssl)) { + case WOLFSSL_SSLV3: + case WOLFSSL_TLSV1: + case WOLFSSL_TLSV1_1: + case WOLFSSL_TLSV1_2: + break; + default: + /* TLS 1.3 does not use this mechanism, the "master secret" returned below + * is not directly usable. */ + return; + } +#endif + + if(SSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != SSL_SUCCESS) { + return; + } + + /* Check for a missing master secret and skip logging. That can happen if + * curl rejects the server certificate and aborts the handshake. + */ + for(i = 0; i < msLen; i++) { + x |= ms[i]; + } + if(x == 0) { + return; + } + + Curl_tls_keylog_write("CLIENT_RANDOM", cr, ms, msLen); +} +#endif /* OPENSSL_EXTRA */ static int do_file_type(const char *type) { @@ -123,7 +222,8 @@ wolfssl_connect_step1(struct connectdata *conn, { char *ciphers; struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; SSL_METHOD* req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI @@ -203,11 +303,11 @@ wolfssl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - if(BACKEND->ctx) - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = SSL_CTX_new(req_method); + if(backend->ctx) + SSL_CTX_free(backend->ctx); + backend->ctx = SSL_CTX_new(req_method); - if(!BACKEND->ctx) { + if(!backend->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } @@ -222,11 +322,11 @@ wolfssl_connect_step1(struct connectdata *conn, * defaults to TLS 1.1) so we have this short circuit evaluation to find * the minimum supported TLS version. */ - if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) && - (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) && - (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1) + if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) && + (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) && + (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1) #ifdef WOLFSSL_TLS13 - && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_3) != 1) + && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1) #endif ) { failf(data, "SSL: couldn't set the minimum protocol version"); @@ -238,7 +338,7 @@ wolfssl_connect_step1(struct connectdata *conn, ciphers = SSL_CONN_CONFIG(cipher_list); if(ciphers) { - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } @@ -248,7 +348,7 @@ wolfssl_connect_step1(struct connectdata *conn, #ifndef NO_FILESYSTEM /* load trusted cacert */ if(SSL_CONN_CONFIG(CAfile)) { - if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx, + if(1 != SSL_CTX_load_verify_locations(backend->ctx, SSL_CONN_CONFIG(CAfile), SSL_CONN_CONFIG(CApath))) { if(SSL_CONN_CONFIG(verifypeer)) { @@ -285,7 +385,7 @@ wolfssl_connect_step1(struct connectdata *conn, if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) { int file_type = do_file_type(SSL_SET_OPTION(cert_type)); - if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert), + if(SSL_CTX_use_certificate_file(backend->ctx, SSL_SET_OPTION(cert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); @@ -293,7 +393,7 @@ wolfssl_connect_step1(struct connectdata *conn, } file_type = do_file_type(SSL_SET_OPTION(key_type)); - if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key), + if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key), file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; @@ -305,7 +405,7 @@ wolfssl_connect_step1(struct connectdata *conn, * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(BACKEND->ctx, + SSL_CTX_set_verify(backend->ctx, SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: SSL_VERIFY_NONE, NULL); @@ -316,15 +416,19 @@ wolfssl_connect_step1(struct connectdata *conn, #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif +#ifndef CURL_DISABLE_PROXY const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; +#else + const char * const hostname = conn->host.name; +#endif size_t hostname_len = strlen(hostname); if((hostname_len < USHRT_MAX) && (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) && #endif - (wolfSSL_CTX_UseSNI(BACKEND->ctx, WOLFSSL_SNI_HOST_NAME, hostname, + (wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, hostname, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -334,7 +438,7 @@ wolfssl_connect_step1(struct connectdata *conn, /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { - CURLcode result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, + CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx, data->set.ssl.fsslctxp); if(result) { failf(data, "error signaled by ssl ctx callback"); @@ -352,10 +456,10 @@ wolfssl_connect_step1(struct connectdata *conn, #endif /* Let's make an SSL structure */ - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } @@ -378,7 +482,7 @@ wolfssl_connect_step1(struct connectdata *conn, strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - if(wolfSSL_UseALPN(BACKEND->handle, protocols, + if(wolfSSL_UseALPN(backend->handle, protocols, (unsigned)strlen(protocols), WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { failf(data, "SSL: failed setting ALPN protocols"); @@ -387,6 +491,17 @@ wolfssl_connect_step1(struct connectdata *conn, } #endif /* HAVE_ALPN */ +#ifdef OPENSSL_EXTRA + if(Curl_tls_keylog_enabled()) { + /* Ensure the Client Random is preserved. */ + wolfSSL_KeepArrays(backend->handle); +#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) + wolfSSL_set_tls13_secret_cb(backend->handle, + wolfssl_tls13_secret_callback, NULL); +#endif + } +#endif /* OPENSSL_EXTRA */ + /* Check if there's a cached ID we can/should use here! */ if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid = NULL; @@ -394,11 +509,11 @@ wolfssl_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ - if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + if(!SSL_set_session(backend->handle, ssl_sessionid)) { char error_buffer[WOLFSSL_MAX_ERROR_SZ]; Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(BACKEND->handle, 0), + ERR_error_string(SSL_get_error(backend->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } @@ -409,7 +524,7 @@ wolfssl_connect_step1(struct connectdata *conn, } /* pass the raw socket into the SSL layer */ - if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { + if(!SSL_set_fd(backend->handle, (int)sockfd)) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } @@ -425,29 +540,62 @@ wolfssl_connect_step2(struct connectdata *conn, { int ret = -1; struct Curl_easy *data = conn->data; - struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; +#ifndef CURL_DISABLE_PROXY const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const char * const dispname = SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname; const char * const pinnedpubkey = SSL_IS_PROXY() ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; +#else + const char * const hostname = conn->host.name; + const char * const dispname = conn->host.dispname; + const char * const pinnedpubkey = + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; +#endif conn->recv[sockindex] = wolfssl_recv; conn->send[sockindex] = wolfssl_send; /* Enable RFC2818 checks */ if(SSL_CONN_CONFIG(verifyhost)) { - ret = wolfSSL_check_domain_name(BACKEND->handle, hostname); + ret = wolfSSL_check_domain_name(backend->handle, hostname); if(ret == SSL_FAILURE) return CURLE_OUT_OF_MEMORY; } - ret = SSL_connect(BACKEND->handle); + ret = SSL_connect(backend->handle); + +#ifdef OPENSSL_EXTRA + if(Curl_tls_keylog_enabled()) { + /* If key logging is enabled, wait for the handshake to complete and then + * proceed with logging secrets (for TLS 1.2 or older). + * + * During the handshake (ret==-1), wolfSSL_want_read() is true as it waits + * for the server response. At that point the master secret is not yet + * available, so we must not try to read it. + * To log the secret on completion with a handshake failure, detect + * completion via the observation that there is nothing to read or write. + * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever + * changes, the worst case is that no key is logged on error. + */ + if(ret == SSL_SUCCESS || + (!wolfSSL_want_read(backend->handle) && + !wolfSSL_want_write(backend->handle))) { + wolfssl_log_tls12_secret(backend->handle); + /* Client Random and master secrets are no longer needed, erase these. + * Ignored while the handshake is still in progress. */ + wolfSSL_FreeArrays(backend->handle); + } + } +#endif /* OPENSSL_EXTRA */ + if(ret != 1) { char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int detail = SSL_get_error(BACKEND->handle, ret); + int detail = SSL_get_error(backend->handle, ret); if(SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; @@ -512,11 +660,11 @@ wolfssl_connect_step2(struct connectdata *conn, X509 *x509; const char *x509_der; int x509_der_len; - curl_X509certificate x509_parsed; - curl_asn1Element *pubkey; + struct Curl_X509certificate x509_parsed; + struct Curl_asn1Element *pubkey; CURLcode result; - x509 = SSL_get_peer_certificate(BACKEND->handle); + x509 = SSL_get_peer_certificate(backend->handle); if(!x509) { failf(data, "SSL: failed retrieving server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; @@ -558,7 +706,7 @@ wolfssl_connect_step2(struct connectdata *conn, char *protocol = NULL; unsigned short protocol_len = 0; - rc = wolfSSL_ALPN_GetProtocol(BACKEND->handle, &protocol, &protocol_len); + rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len); if(rc == SSL_SUCCESS) { infof(data, "ALPN, server accepted to use %.*s\n", protocol_len, @@ -592,8 +740,8 @@ wolfssl_connect_step2(struct connectdata *conn, connssl->connecting_state = ssl_connect_3; #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010) infof(data, "SSL connection using %s / %s\n", - wolfSSL_get_version(BACKEND->handle), - wolfSSL_get_cipher_name(BACKEND->handle)); + wolfSSL_get_version(backend->handle), + wolfSSL_get_cipher_name(backend->handle)); #else infof(data, "SSL connected\n"); #endif @@ -609,6 +757,7 @@ wolfssl_connect_step3(struct connectdata *conn, CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -617,7 +766,7 @@ wolfssl_connect_step3(struct connectdata *conn, SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; - our_ssl_sessionid = SSL_get_session(BACKEND->handle); + our_ssl_sessionid = SSL_get_session(backend->handle); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, @@ -655,12 +804,13 @@ static ssize_t wolfssl_send(struct connectdata *conn, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - int rc = SSL_write(BACKEND->handle, mem, memlen); + int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; + int rc = SSL_write(backend->handle, mem, memlen); if(rc < 0) { - int err = SSL_get_error(BACKEND->handle, rc); + int err = SSL_get_error(backend->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: @@ -682,31 +832,33 @@ static ssize_t wolfssl_send(struct connectdata *conn, static void Curl_wolfssl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; - 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; } } static ssize_t wolfssl_recv(struct connectdata *conn, - int num, - char *buf, - size_t buffersize, - CURLcode *curlcode) + int num, + char *buf, + size_t buffersize, + CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - int nread = SSL_read(BACKEND->handle, buf, buffsize); + int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; + int nread = SSL_read(backend->handle, buf, buffsize); if(nread < 0) { - int err = SSL_get_error(BACKEND->handle, nread); + int err = SSL_get_error(backend->handle, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ @@ -747,6 +899,9 @@ static size_t Curl_wolfssl_version(char *buffer, size_t size) static int Curl_wolfssl_init(void) { +#ifdef OPENSSL_EXTRA + Curl_tls_keylog_open(); +#endif return (wolfSSL_Init() == SSL_SUCCESS); } @@ -754,15 +909,19 @@ static int Curl_wolfssl_init(void) static void Curl_wolfssl_cleanup(void) { wolfSSL_Cleanup(); +#ifdef OPENSSL_EXTRA + Curl_tls_keylog_close(); +#endif } -static bool Curl_wolfssl_data_pending(const struct connectdata* conn, - int connindex) +static bool Curl_wolfssl_data_pending(const struct connectdata *conn, + int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - if(BACKEND->handle) /* SSL is in use */ - return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE; + struct ssl_backend_data *backend = connssl->backend; + if(backend->handle) /* SSL is in use */ + return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE; else return FALSE; } @@ -776,10 +935,11 @@ static int Curl_wolfssl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; - if(BACKEND->handle) { - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + if(backend->handle) { + SSL_free(backend->handle); + backend->handle = NULL; } return retval; } @@ -795,7 +955,6 @@ wolfssl_connect_common(struct connectdata *conn, struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; - time_t timeout_ms; int what; /* check if the connection has already been established */ @@ -806,7 +965,7 @@ wolfssl_connect_common(struct connectdata *conn, if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ @@ -824,7 +983,7 @@ wolfssl_connect_common(struct connectdata *conn, ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ @@ -950,10 +1109,11 @@ static CURLcode Curl_wolfssl_sha256sum(const unsigned char *tmp, /* input */ } static void *Curl_wolfssl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->handle; + return backend->handle; } const struct Curl_ssl Curl_ssl_wolfssl = { diff --git a/Utilities/cmcurl/lib/warnless.h b/Utilities/cmcurl/lib/warnless.h index ea4c439..ab78f94 100644 --- a/Utilities/cmcurl/lib/warnless.h +++ b/Utilities/cmcurl/lib/warnless.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -94,19 +94,6 @@ unsigned short curlx_htons(unsigned short usnum); unsigned short curlx_ntohs(unsigned short usnum); -#ifndef BUILDING_WARNLESS_C -# undef FD_ISSET -# define FD_ISSET(a,b) curlx_FD_ISSET((a),(b)) -# undef FD_SET -# define FD_SET(a,b) curlx_FD_SET((a),(b)) -# undef FD_ZERO -# define FD_ZERO(a) curlx_FD_ZERO((a)) -# undef htons -# define htons(a) curlx_htons((a)) -# undef ntohs -# define ntohs(a) curlx_ntohs((a)) -#endif - #endif /* __INTEL_COMPILER && __unix__ */ #endif /* HEADER_CURL_WARNLESS_H */ diff --git a/Utilities/cmcurl/lib/x509asn1.c b/Utilities/cmcurl/lib/x509asn1.c index ece5364..52747d5 100644 --- a/Utilities/cmcurl/lib/x509asn1.c +++ b/Utilities/cmcurl/lib/x509asn1.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,7 +44,7 @@ static const char cnOID[] = "2.5.4.3"; /* Common name. */ static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */ -static const curl_OID OIDtable[] = { +static const struct Curl_OID OIDtable[] = { { "1.2.840.10040.4.1", "dsa" }, { "1.2.840.10040.4.3", "dsa-with-sha1" }, { "1.2.840.10045.2.1", "ecPublicKey" }, @@ -103,16 +103,16 @@ static const curl_OID OIDtable[] = { * Please note there is no pretention here to rewrite a full SSL library. */ -static const char *getASN1Element(curl_asn1Element *elem, +static const char *getASN1Element(struct Curl_asn1Element *elem, const char *beg, const char *end) WARN_UNUSED_RESULT; -static const char *getASN1Element(curl_asn1Element *elem, +static const char *getASN1Element(struct Curl_asn1Element *elem, const char *beg, const char *end) { unsigned char b; unsigned long len; - curl_asn1Element lelem; + struct Curl_asn1Element lelem; /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg' ending at `end'. @@ -176,9 +176,9 @@ static const char *getASN1Element(curl_asn1Element *elem, * Search the null terminated OID or OID identifier in local table. * Return the table entry pointer or NULL if not found. */ -static const curl_OID * searchOID(const char *oid) +static const struct Curl_OID *searchOID(const char *oid) { - const curl_OID *op; + const struct Curl_OID *op; for(op = OIDtable; op->numoid; op++) if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid)) return op; @@ -445,7 +445,7 @@ static const char *OID2str(const char *beg, const char *end, bool symbolic) buf[buflen] = '\0'; if(symbolic) { - const curl_OID *op = searchOID(buf); + const struct Curl_OID *op = searchOID(buf); if(op) { free(buf); buf = strdup(op->textoid); @@ -565,7 +565,7 @@ static const char *UTime2str(const char *beg, const char *end) * Convert an ASN.1 element to a printable string. * Return the dynamically allocated string, or NULL if an error occurs. */ -static const char *ASN1tostr(curl_asn1Element *elem, int type) +static const char *ASN1tostr(struct Curl_asn1Element *elem, int type) { if(elem->constructed) return NULL; /* No conversion of structured elements. */ @@ -609,12 +609,12 @@ static const char *ASN1tostr(curl_asn1Element *elem, int type) * ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at * `buf'. Return the total string length, even if larger than `buflen'. */ -static ssize_t encodeDN(char *buf, size_t buflen, curl_asn1Element *dn) +static ssize_t encodeDN(char *buf, size_t buflen, struct Curl_asn1Element *dn) { - curl_asn1Element rdn; - curl_asn1Element atv; - curl_asn1Element oid; - curl_asn1Element value; + struct Curl_asn1Element rdn; + struct Curl_asn1Element atv; + struct Curl_asn1Element oid; + struct Curl_asn1Element value; size_t l = 0; const char *p1; const char *p2; @@ -683,7 +683,7 @@ static ssize_t encodeDN(char *buf, size_t buflen, curl_asn1Element *dn) * Convert an ASN.1 distinguished name into a printable string. * Return the dynamically allocated string, or NULL if an error occurs. */ -static const char *DNtostr(curl_asn1Element *dn) +static const char *DNtostr(struct Curl_asn1Element *dn) { char *buf = NULL; ssize_t buflen = encodeDN(NULL, 0, dn); @@ -703,11 +703,11 @@ static const char *DNtostr(curl_asn1Element *dn) * Syntax is assumed to have already been checked by the SSL backend. * See RFC 5280. */ -int Curl_parseX509(curl_X509certificate *cert, +int Curl_parseX509(struct Curl_X509certificate *cert, const char *beg, const char *end) { - curl_asn1Element elem; - curl_asn1Element tbsCertificate; + struct Curl_asn1Element elem; + struct Curl_asn1Element tbsCertificate; const char *ccp; static const char defaultVersion = 0; /* v1. */ @@ -835,10 +835,10 @@ static size_t copySubstring(char *to, const char *from) return i; } -static const char *dumpAlgo(curl_asn1Element *param, +static const char *dumpAlgo(struct Curl_asn1Element *param, const char *beg, const char *end) { - curl_asn1Element oid; + struct Curl_asn1Element oid; /* Get algorithm parameters and return algorithm name. */ @@ -855,7 +855,7 @@ static const char *dumpAlgo(curl_asn1Element *param, } static void do_pubkey_field(struct Curl_easy *data, int certnum, - const char *label, curl_asn1Element *elem) + const char *label, struct Curl_asn1Element *elem) { const char *output; @@ -872,11 +872,11 @@ static void do_pubkey_field(struct Curl_easy *data, int certnum, } static void do_pubkey(struct Curl_easy *data, int certnum, - const char *algo, curl_asn1Element *param, - curl_asn1Element *pubkey) + const char *algo, struct Curl_asn1Element *param, + struct Curl_asn1Element *pubkey) { - curl_asn1Element elem; - curl_asn1Element pk; + struct Curl_asn1Element elem; + struct Curl_asn1Element pk; const char *p; /* Generate all information records for the public key. */ @@ -950,9 +950,9 @@ CURLcode Curl_extract_certinfo(struct connectdata *conn, const char *beg, const char *end) { - curl_X509certificate cert; + struct Curl_X509certificate cert; struct Curl_easy *data = conn->data; - curl_asn1Element param; + struct Curl_asn1Element param; const char *ccp; char *cp1; size_t cl1; @@ -1111,7 +1111,7 @@ CURLcode Curl_extract_certinfo(struct connectdata *conn, static const char *checkOID(const char *beg, const char *end, const char *oid) { - curl_asn1Element e; + struct Curl_asn1Element e; const char *ccp; const char *p; bool matched; @@ -1136,22 +1136,21 @@ CURLcode Curl_verifyhost(struct connectdata *conn, const char *beg, const char *end) { struct Curl_easy *data = conn->data; - curl_X509certificate cert; - curl_asn1Element dn; - curl_asn1Element elem; - curl_asn1Element ext; - curl_asn1Element name; + struct Curl_X509certificate cert; + struct Curl_asn1Element dn; + struct Curl_asn1Element elem; + struct Curl_asn1Element ext; + struct Curl_asn1Element name; const char *p; const char *q; char *dnsname; int matched = -1; size_t addrlen = (size_t) -1; ssize_t len; - const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: - conn->host.name; - const char * const dispname = SSL_IS_PROXY()? - conn->http_proxy.host.dispname: - conn->host.dispname; + const char *const hostname = SSL_IS_PROXY()? + conn->http_proxy.host.name : conn->host.name; + const char *const dispname = SSL_IS_PROXY()? + conn->http_proxy.host.dispname : conn->host.dispname; #ifdef ENABLE_IPV6 struct in6_addr addr; #else diff --git a/Utilities/cmcurl/lib/x509asn1.h b/Utilities/cmcurl/lib/x509asn1.h index 205fdc0..0b7fb88 100644 --- a/Utilities/cmcurl/lib/x509asn1.h +++ b/Utilities/cmcurl/lib/x509asn1.h @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -79,52 +79,51 @@ */ /* ASN.1 parsed element. */ -typedef struct { - const char * header; /* Pointer to header byte. */ - const char * beg; /* Pointer to element data. */ - const char * end; /* Pointer to 1st byte after element. */ - unsigned char class; /* ASN.1 element class. */ - unsigned char tag; /* ASN.1 element tag. */ - bool constructed; /* Element is constructed. */ -} curl_asn1Element; +struct Curl_asn1Element { + const char *header; /* Pointer to header byte. */ + const char *beg; /* Pointer to element data. */ + const char *end; /* Pointer to 1st byte after element. */ + unsigned char class; /* ASN.1 element class. */ + unsigned char tag; /* ASN.1 element tag. */ + bool constructed; /* Element is constructed. */ +}; /* ASN.1 OID table entry. */ -typedef struct { - const char * numoid; /* Dotted-numeric OID. */ - const char * textoid; /* OID name. */ -} curl_OID; +struct Curl_OID { + const char *numoid; /* Dotted-numeric OID. */ + const char *textoid; /* OID name. */ +}; /* X509 certificate: RFC 5280. */ -typedef struct { - curl_asn1Element certificate; - curl_asn1Element version; - curl_asn1Element serialNumber; - curl_asn1Element signatureAlgorithm; - curl_asn1Element signature; - curl_asn1Element issuer; - curl_asn1Element notBefore; - curl_asn1Element notAfter; - curl_asn1Element subject; - curl_asn1Element subjectPublicKeyInfo; - curl_asn1Element subjectPublicKeyAlgorithm; - curl_asn1Element subjectPublicKey; - curl_asn1Element issuerUniqueID; - curl_asn1Element subjectUniqueID; - curl_asn1Element extensions; -} curl_X509certificate; - +struct Curl_X509certificate { + struct Curl_asn1Element certificate; + struct Curl_asn1Element version; + struct Curl_asn1Element serialNumber; + struct Curl_asn1Element signatureAlgorithm; + struct Curl_asn1Element signature; + struct Curl_asn1Element issuer; + struct Curl_asn1Element notBefore; + struct Curl_asn1Element notAfter; + struct Curl_asn1Element subject; + struct Curl_asn1Element subjectPublicKeyInfo; + struct Curl_asn1Element subjectPublicKeyAlgorithm; + struct Curl_asn1Element subjectPublicKey; + struct Curl_asn1Element issuerUniqueID; + struct Curl_asn1Element subjectUniqueID; + struct Curl_asn1Element extensions; +}; /* * Prototypes. */ -const char *Curl_getASN1Element(curl_asn1Element *elem, - const char *beg, const char *end); -const char *Curl_ASN1tostr(curl_asn1Element *elem, int type); -const char *Curl_DNtostr(curl_asn1Element *dn); -int Curl_parseX509(curl_X509certificate *cert, +const char *Curl_getASN1Element(struct Curl_asn1Element *elem, + const char *beg, const char *end); +const char *Curl_ASN1tostr(struct Curl_asn1Element *elem, int type); +const char *Curl_DNtostr(struct Curl_asn1Element *dn); +int Curl_parseX509(struct Curl_X509certificate *cert, const char *beg, const char *end); CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum, const char *beg, const char *end); |