From de7c21d677db1ddaeece03c19e13e448f4031511 Mon Sep 17 00:00:00 2001 From: Curl Upstream Date: Wed, 4 Oct 2017 07:52:15 +0200 Subject: curl 2017-10-04 (3ea76790) Code extracted from: https://github.com/curl/curl.git at commit 3ea76790571c1f7cf1bed34fabffd3cc20ad3dd3 (curl-7_56_0). --- CMake/Macros.cmake | 29 + CMake/OtherTests.cmake | 12 +- CMake/cmake_uninstall.cmake.in | 26 + CMakeLists.txt | 220 +++-- include/curl/curl.h | 247 +++++- include/curl/curlbuild.h.cmake | 197 ----- include/curl/curlrules.h | 239 ------ include/curl/curlver.h | 8 +- include/curl/multi.h | 2 +- include/curl/system.h | 615 +++++++------ include/curl/typecheck-gcc.h | 21 +- lib/CMakeLists.txt | 11 +- lib/Makefile.inc | 5 +- lib/asyn-ares.c | 8 +- lib/asyn-thread.c | 55 +- lib/conncache.h | 2 +- lib/connect.c | 82 +- lib/connect.h | 4 +- lib/content_encoding.c | 6 +- lib/cookie.c | 146 ++-- lib/cookie.h | 11 +- lib/curl_addrinfo.c | 6 +- lib/curl_config.h.cmake | 12 +- lib/curl_fnmatch.c | 12 +- lib/curl_ntlm_core.c | 92 +- lib/curl_ntlm_core.h | 14 +- lib/curl_ntlm_wb.c | 26 +- lib/curl_rtmp.c | 8 +- lib/curl_sasl.c | 6 +- lib/curl_setup.h | 42 +- lib/curl_setup_once.h | 14 - lib/curl_threads.c | 15 +- lib/dict.c | 15 +- lib/dotdot.c | 30 +- lib/easy.c | 26 +- lib/escape.c | 26 +- lib/file.c | 42 +- lib/formdata.c | 887 ++++--------------- lib/formdata.h | 54 +- lib/ftp.c | 278 +++--- lib/ftp.h | 4 +- lib/ftplistparser.c | 38 +- lib/getinfo.c | 87 +- lib/gopher.c | 11 +- lib/hash.c | 4 +- lib/hostcheck.c | 14 +- lib/hostip.c | 12 +- lib/hostip4.c | 4 +- lib/hostip6.c | 4 +- lib/http.c | 444 +++++----- lib/http.h | 17 +- lib/http2.c | 65 +- lib/http2.h | 7 +- lib/http_chunks.c | 26 +- lib/http_ntlm.c | 13 +- lib/http_proxy.c | 278 +++--- lib/http_proxy.h | 10 + lib/if2ip.c | 16 +- lib/if2ip.h | 5 +- lib/imap.c | 195 ++--- lib/imap.h | 3 +- lib/inet_ntop.c | 14 +- lib/inet_pton.c | 6 +- lib/inet_pton.h | 5 +- lib/krb5.c | 2 +- lib/ldap.c | 9 +- lib/memdebug.c | 23 +- lib/mime.c | 1860 ++++++++++++++++++++++++++++++++++++++++ lib/mime.h | 135 +++ lib/mprintf.c | 38 +- lib/multi.c | 139 +-- lib/multihandle.h | 2 +- lib/netrc.c | 44 +- lib/non-ascii.c | 104 +-- lib/non-ascii.h | 4 +- lib/openldap.c | 14 +- lib/parsedate.c | 74 +- lib/pingpong.c | 28 +- lib/pingpong.h | 2 +- lib/pipeline.c | 37 +- lib/pop3.c | 79 +- lib/progress.c | 132 +-- lib/progress.h | 8 +- lib/rand.c | 2 +- lib/rtsp.c | 43 +- lib/rtsp.h | 2 - lib/security.c | 4 +- lib/select.c | 10 +- lib/select.h | 5 +- lib/sendf.c | 20 +- lib/smb.c | 31 +- lib/smtp.c | 118 +-- lib/socks.c | 88 +- lib/socks_gssapi.c | 59 +- lib/socks_sspi.c | 24 +- lib/speedcheck.c | 4 +- lib/speedcheck.h | 4 +- lib/splay.c | 26 +- lib/splay.h | 17 +- lib/ssh.c | 58 +- lib/strcase.c | 11 +- lib/strdup.c | 6 +- lib/strerror.c | 57 +- lib/strtoofft.c | 67 +- lib/strtoofft.h | 37 +- lib/telnet.c | 48 +- lib/tftp.c | 69 +- lib/timeval.c | 71 +- lib/timeval.h | 19 +- lib/transfer.c | 215 +++-- lib/transfer.h | 5 +- lib/url.c | 339 +++++--- lib/urldata.h | 293 +++---- lib/vauth/digest_sspi.c | 45 +- lib/vauth/ntlm.c | 16 +- lib/vauth/ntlm_sspi.c | 9 +- lib/vauth/spnego_gssapi.c | 4 + lib/vauth/vauth.h | 5 +- lib/version.c | 8 +- lib/vtls/axtls.c | 190 ++-- lib/vtls/axtls.h | 39 +- lib/vtls/cyassl.c | 223 +++-- lib/vtls/cyassl.h | 63 +- lib/vtls/darwinssl.c | 469 ++++++---- lib/vtls/darwinssl.h | 70 +- lib/vtls/gskit.c | 191 +++-- lib/vtls/gskit.h | 38 +- lib/vtls/gtls.c | 233 +++-- lib/vtls/gtls.h | 64 +- lib/vtls/mbedtls.c | 237 +++-- lib/vtls/mbedtls.h | 52 +- lib/vtls/nss.c | 237 +++-- lib/vtls/nssg.h | 71 +- lib/vtls/openssl.c | 627 ++++++++++---- lib/vtls/openssl.h | 91 +- lib/vtls/polarssl.c | 198 +++-- lib/vtls/polarssl.h | 52 +- lib/vtls/polarssl_threadlock.c | 4 +- lib/vtls/schannel.c | 532 +++++++----- lib/vtls/schannel.h | 89 +- lib/vtls/vtls.c | 501 +++++++++-- lib/vtls/vtls.h | 82 +- lib/warnless.c | 32 +- 143 files changed, 7983 insertions(+), 5808 deletions(-) create mode 100644 CMake/cmake_uninstall.cmake.in delete mode 100644 include/curl/curlbuild.h.cmake delete mode 100644 include/curl/curlrules.h create mode 100644 lib/mime.c create mode 100644 lib/mime.h diff --git a/CMake/Macros.cmake b/CMake/Macros.cmake index dab005f..82aadca 100644 --- a/CMake/Macros.cmake +++ b/CMake/Macros.cmake @@ -93,3 +93,32 @@ macro(CURL_INTERNAL_TEST_RUN CURL_TEST) endif(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST}) endif() endmacro(CURL_INTERNAL_TEST_RUN) + +macro(CURL_NROFF_CHECK) + find_program(NROFF NAMES gnroff nroff) + if(NROFF) + # Need a way to write to stdin, this will do + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test") + # Tests for a valid nroff option to generate a manpage + foreach(_MANOPT "-man" "-mandoc") + execute_process(COMMAND "${NROFF}" ${_MANOPT} + OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT + INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" + ERROR_QUIET) + # Save the option if it was valid + if(NROFF_MANOPT_OUTPUT) + message("Found *nroff option: -- ${_MANOPT}") + set(NROFF_MANOPT ${_MANOPT}) + set(NROFF_USEFUL ON) + break() + endif() + endforeach() + # No need for the temporary file + file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt") + if(NOT NROFF_USEFUL) + message(WARNING "Found no *nroff option to get plaintext from man pages") + endif() + else() + message(WARNING "Found no *nroff program") + endif() +endmacro(CURL_NROFF_CHECK) diff --git a/CMake/OtherTests.cmake b/CMake/OtherTests.cmake index 3b203c5..989f04e 100644 --- a/CMake/OtherTests.cmake +++ b/CMake/OtherTests.cmake @@ -32,9 +32,9 @@ int main(void) { if(curl_cv_recv) if(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown") foreach(recv_retv "int" "ssize_t" ) - foreach(recv_arg1 "int" "ssize_t" "SOCKET") - foreach(recv_arg2 "void *" "char *") - foreach(recv_arg3 "size_t" "int" "socklen_t" "unsigned int") + foreach(recv_arg1 "SOCKET" "int" ) + foreach(recv_arg2 "char *" "void *" ) + foreach(recv_arg3 "int" "size_t" "socklen_t" "unsigned int") foreach(recv_arg4 "int" "unsigned int") if(NOT curl_cv_func_recv_done) unset(curl_cv_func_recv_test CACHE) @@ -96,9 +96,9 @@ int main(void) { if(curl_cv_send) if(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown") foreach(send_retv "int" "ssize_t" ) - foreach(send_arg1 "int" "ssize_t" "SOCKET") - foreach(send_arg2 "const void *" "void *" "char *" "const char *") - foreach(send_arg3 "size_t" "int" "socklen_t" "unsigned int") + foreach(send_arg1 "SOCKET" "int" "ssize_t" ) + foreach(send_arg2 "const char *" "const void *" "void *" "char *") + foreach(send_arg3 "int" "size_t" "socklen_t" "unsigned int") foreach(send_arg4 "int" "unsigned int") if(NOT curl_cv_func_send_done) unset(curl_cv_func_send_test CACHE) diff --git a/CMake/cmake_uninstall.cmake.in b/CMake/cmake_uninstall.cmake.in new file mode 100644 index 0000000..d00a516 --- /dev/null +++ b/CMake/cmake_uninstall.cmake.in @@ -0,0 +1,26 @@ +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(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +if (NOT DEFINED CMAKE_INSTALL_PREFIX) + set (CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") +endif () + message(${CMAKE_INSTALL_PREFIX}) + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif(NOT "${rm_retval}" STREQUAL 0) + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2e1c2b..261baba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -43,6 +43,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") include(Utilities) include(Macros) include(CMakeDependentOption) +include(CheckCCompilerFlag) project( CURL C ) @@ -72,20 +73,36 @@ set(OS "\"${CMAKE_SYSTEM_NAME}\"") include_directories(${PROJECT_BINARY_DIR}/include/curl) include_directories( ${CURL_SOURCE_DIR}/include ) +option(CURL_WERROR "Turn compiler warnings into errors" OFF) +option(PICKY_COMPILER "Enable picky compiler options" ON) option(BUILD_CURL_EXE "Set to ON to build curl executable." ON) option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF) option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) if(WIN32) - CMAKE_DEPENDENT_OPTION(ENABLE_THREADED_RESOLVER - "Set to ON to enable threaded DNS lookup" - ON "NOT ENABLE_ARES" - OFF) -else() - option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF) + option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF) + option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON) endif() + +CMAKE_DEPENDENT_OPTION(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup" + ON "NOT ENABLE_ARES" + OFF) + option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF) option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF) +if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG) + if (PICKY_COMPILER) + foreach (_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers) + # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new + # test result in. + CHECK_C_COMPILER_FLAG(${_CCOPT} OPT${_CCOPT}) + if(OPT${_CCOPT}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT}") + endif() + endforeach() + endif(PICKY_COMPILER) +endif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG) + if (ENABLE_DEBUG) # DEBUGBUILD will be defined only for Debug builds if(NOT CMAKE_VERSION VERSION_LESS 3.0) @@ -100,13 +117,12 @@ if (ENABLE_CURLDEBUG) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG) endif() +# For debug libs and exes, add "-d" postfix +set(CMAKE_DEBUG_POSTFIX "-d" CACHE STRING "Set debug library postfix") + # initialize CURL_LIBS set(CURL_LIBS "") -if(ENABLE_THREADED_RESOLVER AND ENABLE_ARES) - message(FATAL_ERROR "Options ENABLE_THREADED_RESOLVER and ENABLE_ARES are mutually exclusive") -endif() - if(ENABLE_ARES) set(USE_ARES 1) find_package(CARES REQUIRED) @@ -114,11 +130,6 @@ if(ENABLE_ARES) set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY}) endif() -if(MSVC) - option(BUILD_RELEASE_DEBUG_DIRS "Set OFF to build each configuration to a separate directory" OFF) - mark_as_advanced(BUILD_RELEASE_DEBUG_DIRS) -endif() - include(CurlSymbolHiding) option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF) @@ -176,8 +187,6 @@ option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF) mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH) option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF) mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS) -option(DISABLED_THREADSAFE "Set to explicitly specify we don't want to use thread-safe functions" OFF) -mark_as_advanced(DISABLED_THREADSAFE) option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON) mark_as_advanced(ENABLE_IPV6) if(ENABLE_IPV6 AND NOT WIN32) @@ -194,48 +203,45 @@ if(ENABLE_IPV6 AND NOT WIN32) endif() endif() -option(ENABLE_MANUAL "to provide the built-in manual" ON) -unset(USE_MANUAL CACHE) # TODO: cache NROFF/NROFF_MANOPT/USE_MANUAL vars? +CURL_NROFF_CHECK() +find_package(Perl) + +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) - find_program(NROFF NAMES gnroff nroff) - if(NROFF) - # Need a way to write to stdin, this will do - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test") - # Tests for a valid nroff option to generate a manpage - foreach(_MANOPT "-man" "-mandoc") - execute_process(COMMAND "${NROFF}" ${_MANOPT} - OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT - INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" - ERROR_QUIET) - # Save the option if it was valid - if(NROFF_MANOPT_OUTPUT) - message("Found *nroff option: -- ${_MANOPT}") - set(NROFF_MANOPT ${_MANOPT}) - set(USE_MANUAL 1) - break() - endif() - endforeach() - # No need for the temporary file - file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt") - if(NOT USE_MANUAL) - message(WARNING "Found no *nroff option to get plaintext from man pages") - endif() - else() - message(WARNING "Found no *nroff program") - endif() + set(USE_MANUAL ON) endif() -# Required for building manual, docs, tests -find_package(Perl REQUIRED) # We need ansi c-flags, especially on HP set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}") set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS}) +if(CURL_STATIC_CRT) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") +endif() + # Disable warnings on Borland to avoid changing 3rd party code. if(BORLAND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-") endif(BORLAND) +if(CURL_WERROR) + if(MSVC_VERSION) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /WX") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /WX") + else() + # this assumes clang or gcc style options + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + endif() +endif(CURL_WERROR) + # If we are on AIX, do the _ALL_SOURCE magic if(${CMAKE_SYSTEM_NAME} MATCHES AIX) set(_ALL_SOURCE 1) @@ -258,19 +264,14 @@ if(WIN32) endif(WIN32) if(ENABLE_THREADED_RESOLVER) + find_package(Threads REQUIRED) if(WIN32) set(USE_THREADS_WIN32 ON) else() - check_include_file_concat("pthread.h" HAVE_PTHREAD_H) - if(HAVE_PTHREAD_H) - set(CMAKE_THREAD_PREFER_PTHREAD 1) - find_package(Threads) - if(CMAKE_USE_PTHREADS_INIT) - set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) - set(USE_THREADS_POSIX 1) - endif() - endif() + set(USE_THREADS_POSIX ${CMAKE_USE_PTHREADS_INIT}) + set(HAVE_PTHREAD_H ${CMAKE_USE_PTHREADS_INIT}) endif() + set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) endif() # Check for all needed libraries @@ -795,50 +796,6 @@ if(NOT HAVE_SIZEOF_SSIZE_T) endif(NOT HAVE_SIZEOF_SSIZE_T) # off_t is sized later, after the HAVE_FILE_OFFSET_BITS test -# Different sizeofs, etc. - -# define CURL_SIZEOF_LONG 4 -# define CURL_TYPEOF_CURL_OFF_T long long -# define CURL_FORMAT_CURL_OFF_T "lld" -# define CURL_FORMAT_CURL_OFF_TU "llu" -# define CURL_FORMAT_OFF_T "%lld" -# define CURL_SIZEOF_CURL_OFF_T 8 -# define CURL_SUFFIX_CURL_OFF_T LL -# define CURL_SUFFIX_CURL_OFF_TU ULL - -set(CURL_SIZEOF_LONG ${SIZEOF_LONG}) - -if(SIZEOF_LONG EQUAL 8) - set(CURL_TYPEOF_CURL_OFF_T long) - set(CURL_SIZEOF_CURL_OFF_T 8) - set(CURL_FORMAT_CURL_OFF_T "ld") - set(CURL_FORMAT_CURL_OFF_TU "lu") - set(CURL_FORMAT_OFF_T "%ld") - set(CURL_SUFFIX_CURL_OFF_T L) - set(CURL_SUFFIX_CURL_OFF_TU UL) -endif(SIZEOF_LONG EQUAL 8) - -if(SIZEOF_LONG_LONG EQUAL 8) - set(CURL_TYPEOF_CURL_OFF_T "long long") - set(CURL_SIZEOF_CURL_OFF_T 8) - set(CURL_FORMAT_CURL_OFF_T "lld") - set(CURL_FORMAT_CURL_OFF_TU "llu") - set(CURL_FORMAT_OFF_T "%lld") - set(CURL_SUFFIX_CURL_OFF_T LL) - set(CURL_SUFFIX_CURL_OFF_TU ULL) -endif(SIZEOF_LONG_LONG EQUAL 8) - -if(NOT CURL_TYPEOF_CURL_OFF_T) - set(CURL_TYPEOF_CURL_OFF_T ${ssize_t}) - set(CURL_SIZEOF_CURL_OFF_T ${SIZEOF_SSIZE_T}) - # TODO: need adjustment here. - set(CURL_FORMAT_CURL_OFF_T "ld") - set(CURL_FORMAT_CURL_OFF_TU "lu") - set(CURL_FORMAT_OFF_T "%ld") - set(CURL_SUFFIX_CURL_OFF_T L) - set(CURL_SUFFIX_CURL_OFF_TU LU) -endif(NOT CURL_TYPEOF_CURL_OFF_T) - if(HAVE_SIZEOF_LONG_LONG) set(HAVE_LONGLONG 1) set(HAVE_LL 1) @@ -924,7 +881,18 @@ check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL) check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT) # symbol exists in win32, but function does not. -check_function_exists(inet_pton HAVE_INET_PTON) +if(WIN32) + if(ENABLE_INET_PTON) + check_function_exists(inet_pton HAVE_INET_PTON) + # _WIN32_WINNT_VISTA (0x0600) + add_definitions(-D_WIN32_WINNT=0x0600) + else() + # _WIN32_WINNT_WINXP (0x0501) + add_definitions(-D_WIN32_WINNT=0x0501) + endif() +else() + check_function_exists(inet_pton HAVE_INET_PTON) +endif() check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR) if(HAVE_FSETXATTR) @@ -996,6 +964,13 @@ if(HAVE_FILE_OFFSET_BITS) set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") endif(HAVE_FILE_OFFSET_BITS) check_type_size("off_t" SIZEOF_OFF_T) + +# include this header to get the type +set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCE_DIR}/include") +set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h") +check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) +set(CMAKE_EXTRA_INCLUDE_FILES "") + set(CMAKE_REQUIRED_FLAGS) foreach(CURL_TEST @@ -1111,7 +1086,7 @@ else() set(CURL_SIZEOF_CURL_SOCKLEN_T ${SIZEOF_INT}) endif() -# TODO test which of these headers are required for the typedefs used in curlbuild.h +# TODO test which of these headers are required if(WIN32) set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H}) else() @@ -1126,11 +1101,6 @@ include(CMake/OtherTests.cmake) add_definitions(-DHAVE_CONFIG_H) -# For windows, do not allow the compiler to use default target (Vista). -if(WIN32) - add_definitions(-D_WIN32_WINNT=0x0501) -endif(WIN32) - # For windows, all compilers used by cmake should support large files if(WIN32) set(USE_WIN32_LARGE_FILES ON) @@ -1138,6 +1108,11 @@ endif(WIN32) if(MSVC) add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) + if(CMAKE_C_FLAGS MATCHES "/W[0-4]") + string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + else(CMAKE_C_FLAGS MATCHES "/W[0-4]") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") + endif(CMAKE_C_FLAGS MATCHES "/W[0-4]") endif(MSVC) # Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it). @@ -1156,8 +1131,12 @@ function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE) endfunction() -add_subdirectory(docs) +if(USE_MANUAL) + add_subdirectory(docs) +endif() + add_subdirectory(lib) + if(BUILD_CURL_EXE) add_subdirectory(src) endif() @@ -1261,7 +1240,7 @@ 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(_lib MATCHES ".*/.*") + if(_lib MATCHES ".*/.*" OR _lib MATCHES "^-") set(LIBCURL_LIBS "${LIBCURL_LIBS} ${_lib}") else() set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") @@ -1297,16 +1276,10 @@ if(NOT CURL_CONFIG_HAS_BEEN_RUN_BEFORE) set(CURL_CONFIG_HAS_BEEN_RUN_BEFORE 1 CACHE INTERNAL "Flag to track whether this is the first time running CMake or if CMake has been configured before") endif() -# Installation. -# First, install generated curlbuild.h -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/curl/curlbuild.h" - DESTINATION include/curl ) -# Next, install other headers excluding curlbuild.h +# install headers install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl" DESTINATION include - FILES_MATCHING PATTERN "*.h" - PATTERN "curlbuild.h" EXCLUDE) - + FILES_MATCHING PATTERN "*.h") # Workaround for MSVS10 to avoid the Dialog Hell # FIXME: This could be removed with future version of CMake. @@ -1316,3 +1289,14 @@ if(MSVC_VERSION EQUAL 1600) file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n") endif() endif() + +if(NOT TARGET uninstall) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake + IMMEDIATE @ONLY) + + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake) +endif() diff --git a/include/curl/curl.h b/include/curl/curl.h index ddba98c..7139a33 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -36,8 +36,6 @@ #include "curlver.h" /* libcurl version defines */ #include "system.h" /* determine things run-time */ -#include "curlbuild.h" /* libcurl build definitions */ -#include "curlrules.h" /* libcurl rules enforcement */ /* * Define WIN32 when build target is Win32 API @@ -76,6 +74,7 @@ #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + defined(__CYGWIN__) || \ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) #include #endif @@ -134,6 +133,27 @@ typedef int curl_socket_t; #define curl_socket_typedef #endif /* curl_socket_typedef */ +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_WOLFSSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL + struct curl_httppost { struct curl_httppost *next; /* next entry in the list */ char *name; /* pointer to allocated name */ @@ -337,7 +357,7 @@ typedef size_t (*curl_read_callback)(char *buffer, size_t nitems, void *instream); -typedef enum { +typedef enum { CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ CURLSOCKTYPE_LAST /* never use */ @@ -379,7 +399,7 @@ typedef enum { CURLIOE_LAST /* never use */ } curlioerr; -typedef enum { +typedef enum { CURLIOCMD_NOP, /* no operation */ CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ CURLIOCMD_LAST /* never use */ @@ -679,6 +699,8 @@ typedef enum { #define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) /* Deprecated since the advent of CURLAUTH_NEGOTIATE */ #define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ +#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE #define CURLAUTH_NTLM (((unsigned long)1)<<3) #define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) #define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) @@ -1782,6 +1804,18 @@ typedef enum { /* Suppress proxy CONNECT response headers from user callbacks */ CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), + /* The request target, instead of extracted from the URL */ + CINIT(REQUEST_TARGET, STRINGPOINT, 266), + + /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ + CINIT(SOCKS5_AUTH, LONG, 267), + + /* Enable/disable SSH compression */ + CINIT(SSH_COMPRESSION, LONG, 268), + + /* Post MIME data. */ + CINIT(MIMEPOST, OBJECTPOINT, 269), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -1928,15 +1962,140 @@ typedef enum { CURL_TIMECOND_LAST } curl_TimeCond; +/* Special size_t value signaling a zero-terminated string. */ +#define CURL_ZERO_TERMINATED ((size_t) -1) /* curl_strequal() and curl_strnequal() are subject for removal in a future - libcurl, see lib/README.curlx for details + release */ +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. */ + +/* + * NAME curl_mime_init() + * + * DESCRIPTION + * + * Create a mime context and return its handle. The easy parameter is the + * target handle. + */ +CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); + +/* + * NAME curl_mime_free() + * + * DESCRIPTION + * + * release a mime handle and its substructures. + */ +CURL_EXTERN void curl_mime_free(curl_mime *mime); + +/* + * NAME curl_mime_addpart() + * + * DESCRIPTION + * + * Append a new empty part to the given mime context and return a handle to + * the created part. + */ +CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); + +/* + * NAME curl_mime_name() + * + * DESCRIPTION + * + * Set mime/form part name. + */ +CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); + +/* + * NAME curl_mime_filename() + * + * DESCRIPTION + * + * Set mime part remote file name. + */ +CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_type() + * + * DESCRIPTION + * + * Set mime part type. + */ +CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); + +/* + * NAME curl_mime_encoder() + * + * DESCRIPTION + * + * Set mime data transfer encoder. + */ +CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, + const char *encoding); + +/* + * NAME curl_mime_data() + * + * DESCRIPTION + * + * Set mime part data source from memory data, + */ +CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize); + +/* + * NAME curl_mime_filedata() + * + * DESCRIPTION + * + * Set mime part data source from named file. + */ +CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_data_cb() + * + * DESCRIPTION + * + * Set mime part data source from callback function. + */ +CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, + curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, + void *arg); - !checksrc! disable SPACEBEFOREPAREN 2 -*/ -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); +/* + * NAME curl_mime_subparts() + * + * DESCRIPTION + * + * Set mime part data source from subparts. + */ +CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, + curl_mime *subparts); +/* + * NAME curl_mime_headers() + * + * DESCRIPTION + * + * Set mime part headers. + */ +CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, + int take_ownership); +/* Old form API. */ /* name is uppercase CURLFORM_ */ #ifdef CFINIT #undef CFINIT @@ -2179,6 +2338,47 @@ struct curl_slist { }; /* + * NAME curl_global_sslset() + * + * DESCRIPTION + * + * When built with multiple SSL backends, curl_global_sslset() allows to + * choose one. This function can only be called once, and it must be called + * *before* curl_global_init(). + * + * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The + * backend can also be specified via the name parameter (passing -1 as id). + * If both id and name are specified, the name will be ignored. If neither id + * nor name are specified, the function will fail with + * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the + * NULL-terminated list of available backends. + * + * Upon success, the function returns CURLSSLSET_OK. + * + * If the specified SSL backend is not available, the function returns + * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated + * list of available SSL backends. + * + * The SSL backend can be set only once. If it has already been set, a + * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. + */ + +typedef struct { + curl_sslbackend id; + const char *name; +} curl_ssl_backend; + +typedef enum { + CURLSSLSET_OK = 0, + CURLSSLSET_UNKNOWN_BACKEND, + CURLSSLSET_TOO_LATE, + CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ +} CURLsslset; + +CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + +/* * NAME curl_slist_append() * * DESCRIPTION @@ -2218,27 +2418,6 @@ struct curl_certinfo { format "name: value" */ }; -/* enum for the different supported SSL backends */ -typedef enum { - CURLSSLBACKEND_NONE = 0, - CURLSSLBACKEND_OPENSSL = 1, - CURLSSLBACKEND_GNUTLS = 2, - CURLSSLBACKEND_NSS = 3, - CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ - CURLSSLBACKEND_GSKIT = 5, - CURLSSLBACKEND_POLARSSL = 6, - CURLSSLBACKEND_CYASSL = 7, - CURLSSLBACKEND_SCHANNEL = 8, - CURLSSLBACKEND_DARWINSSL = 9, - CURLSSLBACKEND_AXTLS = 10, - CURLSSLBACKEND_MBEDTLS = 11 -} curl_sslbackend; - -/* aliases for library clones and renames */ -#define CURLSSLBACKEND_LIBRESSL 1 -#define CURLSSLBACKEND_BORINGSSL 1 -#define CURLSSLBACKEND_WOLFSSL 6 - /* Information about the SSL library used and the respective internal SSL handle, which can be used to obtain further information regarding the connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ @@ -2253,6 +2432,7 @@ struct curl_tlssessioninfo { #define CURLINFO_SLIST 0x400000 #define CURLINFO_PTR 0x400000 /* same as SLIST */ #define CURLINFO_SOCKET 0x500000 +#define CURLINFO_OFF_T 0x600000 #define CURLINFO_MASK 0x0fffff #define CURLINFO_TYPEMASK 0xf00000 @@ -2265,15 +2445,21 @@ typedef enum { CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, CURLINFO_FILETIME = CURLINFO_LONG + 14, CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, @@ -2471,6 +2657,7 @@ typedef struct { #define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used for cookie domain verification */ #define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ +#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ /* * NAME curl_version_info() diff --git a/include/curl/curlbuild.h.cmake b/include/curl/curlbuild.h.cmake deleted file mode 100644 index bbb31a9..0000000 --- a/include/curl/curlbuild.h.cmake +++ /dev/null @@ -1,197 +0,0 @@ -#ifndef __CURL_CURLBUILD_H -#define __CURL_CURLBUILD_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.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. - * - ***************************************************************************/ - -/* ================================================================ */ -/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ -/* ================================================================ */ - -/* - * NOTE 1: - * ------- - * - * Nothing in this file is intended to be modified or adjusted by the - * curl library user nor by the curl library builder. - * - * If you think that something actually needs to be changed, adjusted - * or fixed in this file, then, report it on the libcurl development - * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ - * - * This header file shall only export symbols which are 'curl' or 'CURL' - * prefixed, otherwise public name space would be polluted. - * - * NOTE 2: - * ------- - * - * Right now you might be staring at file include/curl/curlbuild.h.in or - * at file include/curl/curlbuild.h, this is due to the following reason: - * - * On systems capable of running the configure script, the configure process - * will overwrite the distributed include/curl/curlbuild.h file with one that - * is suitable and specific to the library being configured and built, which - * is generated from the include/curl/curlbuild.h.in template file. - * - */ - -/* ================================================================ */ -/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ -/* ================================================================ */ - -#ifdef CURL_SIZEOF_LONG -#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined -#endif - -#ifdef CURL_TYPEOF_CURL_SOCKLEN_T -#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined -#endif - -#ifdef CURL_SIZEOF_CURL_SOCKLEN_T -#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined -#endif - -#ifdef CURL_TYPEOF_CURL_OFF_T -#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined -#endif - -#ifdef CURL_FORMAT_CURL_OFF_T -#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined -#endif - -#ifdef CURL_FORMAT_CURL_OFF_TU -#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined -#endif - -#ifdef CURL_FORMAT_OFF_T -#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined -#endif - -#ifdef CURL_SIZEOF_CURL_OFF_T -#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined -#endif - -#ifdef CURL_SUFFIX_CURL_OFF_T -#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined -#endif - -#ifdef CURL_SUFFIX_CURL_OFF_TU -#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" - Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined -#endif - -/* ================================================================ */ -/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ -/* ================================================================ */ - -/* Configure process defines this to 1 when it finds out that system */ -/* header file ws2tcpip.h must be included by the external interface. */ -#cmakedefine CURL_PULL_WS2TCPIP_H -#ifdef CURL_PULL_WS2TCPIP_H -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# include -# include -#endif - -/* Configure process defines this to 1 when it finds out that system */ -/* header file sys/types.h must be included by the external interface. */ -#cmakedefine CURL_PULL_SYS_TYPES_H -#ifdef CURL_PULL_SYS_TYPES_H -# include -#endif - -/* Configure process defines this to 1 when it finds out that system */ -/* header file stdint.h must be included by the external interface. */ -#cmakedefine CURL_PULL_STDINT_H -#ifdef CURL_PULL_STDINT_H -# include -#endif - -/* Configure process defines this to 1 when it finds out that system */ -/* header file inttypes.h must be included by the external interface. */ -#cmakedefine CURL_PULL_INTTYPES_H -#ifdef CURL_PULL_INTTYPES_H -# include -#endif - -/* Configure process defines this to 1 when it finds out that system */ -/* header file sys/socket.h must be included by the external interface. */ -#cmakedefine CURL_PULL_SYS_SOCKET_H -#ifdef CURL_PULL_SYS_SOCKET_H -# include -#endif - -/* Configure process defines this to 1 when it finds out that system */ -/* header file sys/poll.h must be included by the external interface. */ -#cmakedefine CURL_PULL_SYS_POLL_H -#ifdef CURL_PULL_SYS_POLL_H -# include -#endif - -/* The size of `long', as computed by sizeof. */ -#define CURL_SIZEOF_LONG ${CURL_SIZEOF_LONG} - -/* Integral data type used for curl_socklen_t. */ -#define CURL_TYPEOF_CURL_SOCKLEN_T ${CURL_TYPEOF_CURL_SOCKLEN_T} - -/* The size of `curl_socklen_t', as computed by sizeof. */ -#define CURL_SIZEOF_CURL_SOCKLEN_T ${CURL_SIZEOF_CURL_SOCKLEN_T} - -/* Data type definition of curl_socklen_t. */ -typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; - -/* Signed integral data type used for curl_off_t. */ -#define CURL_TYPEOF_CURL_OFF_T ${CURL_TYPEOF_CURL_OFF_T} - -/* Data type definition of curl_off_t. */ -typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; - -/* curl_off_t formatting string directive without "%" conversion specifier. */ -#define CURL_FORMAT_CURL_OFF_T "${CURL_FORMAT_CURL_OFF_T}" - -/* unsigned curl_off_t formatting string without "%" conversion specifier. */ -#define CURL_FORMAT_CURL_OFF_TU "${CURL_FORMAT_CURL_OFF_TU}" - -/* curl_off_t formatting string directive with "%" conversion specifier. */ -#define CURL_FORMAT_OFF_T "${CURL_FORMAT_OFF_T}" - -/* The size of `curl_off_t', as computed by sizeof. */ -#define CURL_SIZEOF_CURL_OFF_T ${CURL_SIZEOF_CURL_OFF_T} - -/* curl_off_t constant suffix. */ -#define CURL_SUFFIX_CURL_OFF_T ${CURL_SUFFIX_CURL_OFF_T} - -/* unsigned curl_off_t constant suffix. */ -#define CURL_SUFFIX_CURL_OFF_TU ${CURL_SUFFIX_CURL_OFF_TU} - -#endif /* __CURL_CURLBUILD_H */ diff --git a/include/curl/curlrules.h b/include/curl/curlrules.h deleted file mode 100644 index 0abd9f7..0000000 --- a/include/curl/curlrules.h +++ /dev/null @@ -1,239 +0,0 @@ -#ifndef __CURL_CURLRULES_H -#define __CURL_CURLRULES_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.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. - * - ***************************************************************************/ - -/* ================================================================ */ -/* COMPILE TIME SANITY CHECKS */ -/* ================================================================ */ - -/* - * NOTE 1: - * ------- - * - * All checks done in this file are intentionally placed in a public - * header file which is pulled by curl/curl.h when an application is - * being built using an already built libcurl library. Additionally - * this file is also included and used when building the library. - * - * If compilation fails on this file it is certainly sure that the - * problem is elsewhere. It could be a problem in the curlbuild.h - * header file, or simply that you are using different compilation - * settings than those used to build the library. - * - * Nothing in this file is intended to be modified or adjusted by the - * curl library user nor by the curl library builder. - * - * Do not deactivate any check, these are done to make sure that the - * library is properly built and used. - * - * You can find further help on the libcurl development mailing list: - * https://cool.haxx.se/mailman/listinfo/curl-library/ - * - * NOTE 2 - * ------ - * - * Some of the following compile time checks are based on the fact - * that the dimension of a constant array can not be a negative one. - * In this way if the compile time verification fails, the compilation - * will fail issuing an error. The error description wording is compiler - * dependent but it will be quite similar to one of the following: - * - * "negative subscript or subscript is too large" - * "array must have at least one element" - * "-1 is an illegal array size" - * "size of array is negative" - * - * If you are building an application which tries to use an already - * built libcurl library and you are getting this kind of errors on - * this file, it is a clear indication that there is a mismatch between - * how the library was built and how you are trying to use it for your - * application. Your already compiled or binary library provider is the - * only one who can give you the details you need to properly use it. - */ - -/* - * Verify that some macros are actually defined. - */ - -#ifndef CURL_SIZEOF_LONG -# error "CURL_SIZEOF_LONG definition is missing!" - Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing -#endif - -#ifndef CURL_TYPEOF_CURL_SOCKLEN_T -# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" - Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing -#endif - -#ifndef CURL_SIZEOF_CURL_SOCKLEN_T -# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" - Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing -#endif - -#ifndef CURL_TYPEOF_CURL_OFF_T -# error "CURL_TYPEOF_CURL_OFF_T definition is missing!" - Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing -#endif - -#ifndef CURL_FORMAT_CURL_OFF_T -# error "CURL_FORMAT_CURL_OFF_T definition is missing!" - Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing -#endif - -#ifndef CURL_FORMAT_CURL_OFF_TU -# error "CURL_FORMAT_CURL_OFF_TU definition is missing!" - Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing -#endif - -#ifndef CURL_SIZEOF_CURL_OFF_T -# error "CURL_SIZEOF_CURL_OFF_T definition is missing!" - Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing -#endif - -#ifndef CURL_SUFFIX_CURL_OFF_T -# error "CURL_SUFFIX_CURL_OFF_T definition is missing!" - Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing -#endif - -#ifndef CURL_SUFFIX_CURL_OFF_TU -# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" - Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing -#endif - -/* - * Macros private to this header file. - */ - -#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 - -#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 - -/* - * Verify that the size previously defined and expected for long - * is the same as the one reported by sizeof() at compile time. - */ - -typedef char - __curl_rule_01__ - [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; - -/* - * Verify that the size previously defined and expected for - * curl_off_t is actually the the same as the one reported - * by sizeof() at compile time. - */ - -typedef char - __curl_rule_02__ - [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; - -/* - * Verify at compile time that the size of curl_off_t as reported - * by sizeof() is greater or equal than the one reported for long - * for the current compilation. - */ - -typedef char - __curl_rule_03__ - [CurlchkszGE(curl_off_t, long)]; - -/* - * Verify that the size previously defined and expected for - * curl_socklen_t is actually the the same as the one reported - * by sizeof() at compile time. - */ - -typedef char - __curl_rule_04__ - [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; - -/* - * Verify at compile time that the size of curl_socklen_t as reported - * by sizeof() is greater or equal than the one reported for int for - * the current compilation. - */ - -typedef char - __curl_rule_05__ - [CurlchkszGE(curl_socklen_t, int)]; - -/* ================================================================ */ -/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ -/* ================================================================ */ - -/* - * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow - * these to be visible and exported by the external libcurl interface API, - * while also making them visible to the library internals, simply including - * curl_setup.h, without actually needing to include curl.h internally. - * If some day this section would grow big enough, all this should be moved - * to its own header file. - */ - -/* - * Figure out if we can use the ## preprocessor operator, which is supported - * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ - * or __cplusplus so we need to carefully check for them too. - */ - -#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ - defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ - defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ - defined(__ILEC400__) - /* This compiler is believed to have an ISO compatible preprocessor */ -#define CURL_ISOCPP -#else - /* This compiler is believed NOT to have an ISO compatible preprocessor */ -#undef CURL_ISOCPP -#endif - -/* - * Macros for minimum-width signed and unsigned curl_off_t integer constants. - */ - -#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) -# define __CURL_OFF_T_C_HLPR2(x) x -# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) -# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ - __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) -# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ - __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) -#else -# ifdef CURL_ISOCPP -# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix -# else -# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix -# endif -# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) -# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) -# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) -#endif - -/* - * Get rid of macros private to this header file. - */ - -#undef CurlchkszEQ -#undef CurlchkszGE - -#endif /* __CURL_CURLRULES_H */ diff --git a/include/curl/curlver.h b/include/curl/curlver.h index 227571c..8c9fb5e 100644 --- a/include/curl/curlver.h +++ b/include/curl/curlver.h @@ -30,13 +30,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.54.1-DEV" +#define LIBCURL_VERSION "7.56.0-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 54 -#define LIBCURL_VERSION_PATCH 1 +#define LIBCURL_VERSION_MINOR 56 +#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 @@ -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 0x073601 +#define LIBCURL_VERSION_NUM 0x073800 /* * This is the date and time when the full source package was created. The diff --git a/include/curl/multi.h b/include/curl/multi.h index f93e511..911c91d 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms diff --git a/include/curl/system.h b/include/curl/system.h index ed3a55c..39dae75 100644 --- a/include/curl/system.h +++ b/include/curl/system.h @@ -23,14 +23,6 @@ ***************************************************************************/ /* - * This header is supposed to eventually replace curlbuild.h. This little one - * is still learning. During the experimental phase, this header files - * defines symbols using the prefixes CURLSYS_ or curlsys_. When we feel - * confident enough, we replace curlbuild.h with this file and rename all - * prefixes to CURL_ and curl_. - */ - -/* * Try to keep one section per platform, compiler and architecture, otherwise, * if an existing section is reused for a different one and later on the * original is adjusted, probably the piggybacking one can be adversely @@ -60,323 +52,271 @@ #if defined(__DJGPP__) || defined(__GO32__) # if defined(__DJGPP__) && (__DJGPP__ > 1) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # else -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__SALFORDC__) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__BORLANDC__) # if (__BORLANDC__ < 0x520) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # else -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T __int64 -# define CURLSYS_FORMAT_CURL_OFF_T "I64d" -# define CURLSYS_FORMAT_CURL_OFF_TU "I64u" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T i64 -# define CURLSYS_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__TURBOC__) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__WATCOMC__) # if defined(__386__) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T __int64 -# define CURLSYS_FORMAT_CURL_OFF_T "I64d" -# define CURLSYS_FORMAT_CURL_OFF_TU "I64u" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T i64 -# define CURLSYS_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 # else -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__POCC__) # if (__POCC__ < 280) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # elif defined(_MSC_VER) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T __int64 -# define CURLSYS_FORMAT_CURL_OFF_T "I64d" -# define CURLSYS_FORMAT_CURL_OFF_TU "I64u" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T i64 -# define CURLSYS_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 # else -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__LCC__) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__SYMBIAN32__) # if defined(__EABI__) /* Treat all ARM compilers equally */ -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__CW32__) # pragma longlong on -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__VC32__) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T __int64 -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T unsigned int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int #elif defined(__MWERKS__) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(_WIN32_WCE) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T __int64 -# define CURLSYS_FORMAT_CURL_OFF_T "I64d" -# define CURLSYS_FORMAT_CURL_OFF_TU "I64u" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T i64 -# define CURLSYS_SUFFIX_CURL_OFF_TU ui64 -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__MINGW32__) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "I64d" -# define CURLSYS_FORMAT_CURL_OFF_TU "I64u" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 -# define CURLSYS_PULL_SYS_TYPES_H 1 -# define CURLSYS_PULL_WS2TCPIP_H 1 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_WS2TCPIP_H 1 #elif defined(__VMS) # if defined(__VAX) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # else -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T unsigned int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int #elif defined(__OS400__) # if defined(__ILEC400__) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 -# define CURLSYS_PULL_SYS_TYPES_H 1 -# define CURLSYS_PULL_SYS_SOCKET_H 1 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 # endif #elif defined(__MVS__) # if defined(__IBMC__) || defined(__IBMCPP__) # if defined(_ILP32) -# define CURLSYS_SIZEOF_LONG 4 # elif defined(_LP64) -# define CURLSYS_SIZEOF_LONG 8 # endif # if defined(_LONG_LONG) -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(_LP64) -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # else -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 -# define CURLSYS_PULL_SYS_TYPES_H 1 -# define CURLSYS_PULL_SYS_SOCKET_H 1 +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 # endif #elif defined(__370__) # if defined(__IBMC__) || defined(__IBMCPP__) # if defined(_ILP32) -# define CURLSYS_SIZEOF_LONG 4 # elif defined(_LP64) -# define CURLSYS_SIZEOF_LONG 8 # endif # if defined(_LONG_LONG) -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(_LP64) -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # else -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 -# define CURLSYS_PULL_SYS_TYPES_H 1 -# define CURLSYS_PULL_SYS_SOCKET_H 1 +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 # endif #elif defined(TPF) -# define CURLSYS_SIZEOF_LONG 8 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__TINYC__) /* also known as tcc */ -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURLSYS_PULL_SYS_TYPES_H 1 -# define CURLSYS_PULL_SYS_SOCKET_H 1 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__SUNPRO_C) /* Oracle Solaris Studio */ +# if !defined(__LP64) && (defined(__ILP32) || \ + defined(__i386) || defined(__sparcv8)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64) || \ + defined(__amd64) || defined(__sparcv9) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 /* ===================================== */ /* KEEP MSVC THE PENULTIMATE ENTRY */ @@ -384,101 +324,148 @@ #elif defined(_MSC_VER) # if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T __int64 -# define CURLSYS_FORMAT_CURL_OFF_T "I64d" -# define CURLSYS_FORMAT_CURL_OFF_TU "I64u" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T i64 -# define CURLSYS_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 # else -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_TYPEOF_CURL_SOCKLEN_T int /* ===================================== */ /* KEEP GENERIC GCC THE LAST ENTRY */ /* ===================================== */ #elif defined(__GNUC__) -# if !defined(__LP64__) && (defined(__ILP32__) || \ - defined(__i386__) || defined(__ppc__) || defined(__arm__) || \ - defined(__sparc__) || defined(__mips__) || defined(__sh__)) -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long long -# define CURLSYS_FORMAT_CURL_OFF_T "lld" -# define CURLSYS_FORMAT_CURL_OFF_TU "llu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T LL -# define CURLSYS_SUFFIX_CURL_OFF_TU ULL +# if !defined(__LP64__) && \ + (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ + defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ + defined(__XTENSA__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__LP64__) || \ - defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) -# define CURLSYS_SIZEOF_LONG 8 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SIZEOF_CURL_OFF_T 8 -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL # endif -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 -# define CURLSYS_PULL_SYS_TYPES_H 1 -# define CURLSYS_PULL_SYS_SOCKET_H 1 +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 #else /* generic "safe guess" on old 32 bit style */ -# define CURLSYS_SIZEOF_LONG 4 -# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4 -# define CURLSYS_SIZEOF_CURL_OFF_T 4 -# define CURLSYS_TYPEOF_CURL_OFF_T long -# define CURLSYS_FORMAT_CURL_OFF_T "ld" -# define CURLSYS_FORMAT_CURL_OFF_TU "lu" -# define CURLSYS_SUFFIX_CURL_OFF_T L -# define CURLSYS_SUFFIX_CURL_OFF_TU UL -# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int #endif -/* CURLSYS_PULL_WS2TCPIP_H is defined above when inclusion of header file */ +#ifdef _AIX +/* AIX needs */ +#define CURL_PULL_SYS_POLL_H +#endif + + +/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ /* ws2tcpip.h is required here to properly make type definitions below. */ -#ifdef CURLSYS_PULL_WS2TCPIP_H -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include +#ifdef CURL_PULL_WS2TCPIP_H # include +# include # include #endif -/* CURLSYS_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ /* sys/types.h is required here to properly make type definitions below. */ -#ifdef CURLSYS_PULL_SYS_TYPES_H +#ifdef CURL_PULL_SYS_TYPES_H # include #endif -/* CURLSYS_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ /* sys/socket.h is required here to properly make type definitions below. */ -#ifdef CURLSYS_PULL_SYS_SOCKET_H +#ifdef CURL_PULL_SYS_SOCKET_H # include #endif +/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ +/* sys/poll.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + /* Data type definition of curl_socklen_t. */ -#ifdef CURLSYS_TYPEOF_CURL_SOCKLEN_T - typedef CURLSYS_TYPEOF_CURL_SOCKLEN_T curlsys_socklen_t; +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; #endif /* Data type definition of curl_off_t. */ -#ifdef CURLSYS_TYPEOF_CURL_OFF_T - typedef CURLSYS_TYPEOF_CURL_OFF_T curlsys_off_t; +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; #endif -#endif /* __CURL_SYSTEM_H */ +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +#endif /* __CURL_SYSTEM_H */ diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index 10b5de2..10c74c7 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -96,6 +96,9 @@ __extension__ ({ \ if((_curl_opt) == CURLOPT_HTTPPOST) \ if(!_curl_is_arr((value), struct curl_httppost)) \ _curl_easy_setopt_err_curl_httpost(); \ + if((_curl_opt) == CURLOPT_MIMEPOST) \ + if(!_curl_is_ptr((value), curl_mime)) \ + _curl_easy_setopt_err_curl_mimepost(); \ if(_curl_is_slist_option(_curl_opt)) \ if(!_curl_is_arr((value), struct curl_slist)) \ _curl_easy_setopt_err_curl_slist(); \ @@ -110,7 +113,7 @@ __extension__ ({ \ /* FIXME: don't allow const pointers */ #define curl_easy_getinfo(handle, info, arg) \ __extension__ ({ \ - __typeof__(info) _curl_info = info; \ + __typeof__(info) _curl_info = info; \ if(__builtin_constant_p(_curl_info)) { \ if(_curl_is_string_info(_curl_info)) \ if(!_curl_is_arr((arg), char *)) \ @@ -130,9 +133,12 @@ __extension__ ({ \ if(_curl_is_certinfo_info(_curl_info)) \ if(!_curl_is_arr((arg), struct curl_certinfo *)) \ _curl_easy_getinfo_err_curl_certinfo(); \ - if(_curl_is_socket_info(_curl_info)) \ + if(_curl_is_socket_info(_curl_info)) \ if(!_curl_is_arr((arg), curl_socket_t)) \ _curl_easy_getinfo_err_curl_socket(); \ + if(_curl_is_off_t_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_off_t)) \ + _curl_easy_getinfo_err_curl_off_t(); \ } \ curl_easy_getinfo(handle, _curl_info, arg); \ }) @@ -197,6 +203,9 @@ _CURL_WARNING(_curl_easy_setopt_err_postfields, _CURL_WARNING(_curl_easy_setopt_err_curl_httpost, "curl_easy_setopt expects a 'struct curl_httppost *' " "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost, + "curl_easy_setopt expects a 'curl_mime *' " + "argument for this option") _CURL_WARNING(_curl_easy_setopt_err_curl_slist, "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") _CURL_WARNING(_curl_easy_setopt_err_CURLSH, @@ -218,6 +227,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo, "'struct curl_certinfo *' for this info") _CURL_WARNING(_curl_easy_getinfo_err_curl_socket, "curl_easy_getinfo expects a pointer to curl_socket_t for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t, + "curl_easy_getinfo expects a pointer to curl_off_t for this info") /* groups of curl_easy_setops options that take the same type of argument */ @@ -391,7 +402,11 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_socket, /* true if info expects a pointer to struct curl_socket_t argument */ #define _curl_is_socket_info(info) \ - (CURLINFO_SOCKET < (info)) + (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) + +/* true if info expects a pointer to curl_off_t argument */ +#define _curl_is_off_t_info(info) \ + (CURLINFO_OFF_T < (info)) /* typecheck helpers -- check whether given expression has requested type*/ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index eb2de6d..d6c9961 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,7 +1,5 @@ set(LIB_NAME libcurl) -configure_file(${CURL_SOURCE_DIR}/include/curl/curlbuild.h.cmake - ${CURL_BINARY_DIR}/include/curl/curlbuild.h) configure_file(curl_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h) @@ -10,11 +8,11 @@ include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) list(APPEND HHEADERS ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h - ${CURL_BINARY_DIR}/include/curl/curlbuild.h ) if(MSVC) list(APPEND CSOURCES libcurl.rc) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4127") endif() # SET(CSOURCES @@ -100,6 +98,13 @@ if(WIN32) if(NOT CURL_STATICLIB) # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib" set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib") + + set_target_properties (${LIB_NAME} PROPERTIES + DEBUG_POSTFIX "-d" + # Note: no postfix for release variants, let user choose what style of release he wants + # MINSIZEREL_POSTFIX "-z" + # RELWITHDEBINFO_POSTFIX "-g" + ) endif() endif() diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 19f5800..5c0b930 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -53,7 +53,8 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.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 pipeline.c dotdot.c \ - x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c + x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ + mime.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 \ @@ -72,7 +73,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ curl_setup_once.h multihandle.h setup-vms.h pipeline.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 + curl_printf.h system_win32.h rand.h mime.h LIB_RCFILES = libcurl.rc diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 11a914f..87e70b4 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -260,7 +260,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms) bitmask = ares_getsock((ares_channel)data->state.resolver, socks, ARES_GETSOCK_MAXNUM); - for(i=0; i < ARES_GETSOCK_MAXNUM; i++) { + for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { pfd[i].events = 0; pfd[i].revents = 0; if(ARES_GETSOCK_READABLE(bitmask, i)) { @@ -289,7 +289,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms) ARES_SOCKET_BAD); else { /* move through the descriptors and ask for processing on them */ - for(i=0; i < num; i++) + for(i = 0; i < num; i++) ares_process_fd((ares_channel)data->state.resolver, pfd[i].revents & (POLLRDNORM|POLLIN)? pfd[i].fd:ARES_SOCKET_BAD, @@ -355,7 +355,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; long timeout; - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); struct Curl_dns_entry *temp_entry; if(entry) @@ -400,7 +400,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; else { - struct timeval now2 = Curl_tvnow(); + struct curltime now2 = Curl_tvnow(); time_t timediff = Curl_tvdiff(now2, now); /* spent time */ if(timediff <= 0) timeout -= 1; /* always deduct at least 1 */ diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index 65fa6c5..a867729 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -210,6 +210,10 @@ int init_thread_sync_data(struct thread_data * td, tsd->td = td; tsd->port = port; + /* Treat the request as done until the thread actually starts so any early + * cleanup gets done properly. + */ + tsd->done = 1; #ifdef HAVE_GETADDRINFO DEBUGASSERT(hints); tsd->hints = *hints; @@ -380,11 +384,11 @@ static bool init_resolve_thread(struct connectdata *conn, const struct addrinfo *hints) { struct thread_data *td = calloc(1, sizeof(struct thread_data)); - int err = RESOLVER_ENOMEM; + int err = ENOMEM; conn->async.os_specific = (void *)td; if(!td) - goto err_exit; + goto errno_exit; conn->async.port = port; conn->async.done = FALSE; @@ -392,14 +396,20 @@ static bool init_resolve_thread(struct connectdata *conn, conn->async.dns = NULL; td->thread_hnd = curl_thread_t_null; - if(!init_thread_sync_data(td, hostname, port, hints)) - goto err_exit; + if(!init_thread_sync_data(td, hostname, port, hints)) { + conn->async.os_specific = NULL; + free(td); + goto errno_exit; + } free(conn->async.hostname); conn->async.hostname = strdup(hostname); if(!conn->async.hostname) goto err_exit; + /* The thread will set this to 1 when complete. */ + td->tsd.done = 0; + #ifdef HAVE_GETADDRINFO td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); #else @@ -407,9 +417,9 @@ static bool init_resolve_thread(struct connectdata *conn, #endif if(!td->thread_hnd) { -#ifndef _WIN32_WCE + /* The thread never started, so mark it as done here for proper cleanup. */ + td->tsd.done = 1; err = errno; -#endif goto err_exit; } @@ -418,8 +428,8 @@ static bool init_resolve_thread(struct connectdata *conn, err_exit: destroy_async_data(&conn->async); - SET_ERRNO(err); - + errno_exit: + errno = err; return FALSE; } @@ -594,28 +604,29 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, int *waitp) { struct addrinfo hints; - struct in_addr in; Curl_addrinfo *res; int error; char sbuf[12]; int pf = PF_INET; -#ifdef CURLRES_IPV6 - struct in6_addr in6; -#endif /* CURLRES_IPV6 */ *waitp = 0; /* default to synchronous response */ #ifndef 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 */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - + { + struct in_addr in; + /* 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 */ + return Curl_ip2addr(AF_INET, &in, hostname, port); + } #ifdef CURLRES_IPV6 - /* check if this is an IPv6 address string */ - if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) - /* This is an IPv6 address literal */ - return Curl_ip2addr(AF_INET6, &in6, hostname, port); + { + 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 */ + return Curl_ip2addr(AF_INET6, &in6, hostname, port); + } #endif /* CURLRES_IPV6 */ #endif /* !USE_RESOLVE_ON_IPS */ @@ -654,7 +665,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, /* fall-back to blocking version */ infof(conn->data, "init_resolve_thread() failed for %s; %s\n", - hostname, Curl_strerror(conn, ERRNO)); + hostname, Curl_strerror(conn, errno)); error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res); if(error) { diff --git a/lib/conncache.h b/lib/conncache.h index f976cfd..14be4e8 100644 --- a/lib/conncache.h +++ b/lib/conncache.h @@ -27,7 +27,7 @@ struct conncache { struct curl_hash hash; size_t num_connections; long next_connection_id; - struct timeval last_cleanup; + struct curltime last_cleanup; }; #define BUNDLE_NO_MULTIUSE -1 diff --git a/lib/connect.c b/lib/connect.c index d4fd52b..b7d10af 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -180,12 +180,12 @@ singleipconnect(struct connectdata *conn, * @unittest: 1303 */ time_t Curl_timeleft(struct Curl_easy *data, - struct timeval *nowp, + struct curltime *nowp, bool duringconnect) { int timeout_set = 0; time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0; - struct timeval now; + struct curltime now; /* if a timeout is set, use the most restrictive one */ @@ -249,7 +249,7 @@ static CURLcode bindlocal(struct connectdata *conn, struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa; #endif - struct Curl_dns_entry *h=NULL; + struct Curl_dns_entry *h = NULL; unsigned short port = data->set.localport; /* use this port number, 0 for "random" */ /* how many port numbers to try to bind to, increasing one at a time */ @@ -319,7 +319,7 @@ static CURLcode bindlocal(struct connectdata *conn, * as a hostname or ip address. */ if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, - dev, (curl_socklen_t)strlen(dev)+1) != 0) { + dev, (curl_socklen_t)strlen(dev) + 1) != 0) { error = SOCKERRNO; infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;" " will do regular bind\n", @@ -607,7 +607,8 @@ void Curl_persistconninfo(struct connectdata *conn) conn->data->info.conn_local_port = conn->local_port; } -/* retrieves ip address and port from a sockaddr structure */ +/* retrieves ip address and port from a sockaddr structure. + note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */ static bool getaddressinfo(struct sockaddr *sa, char *addr, long *port) { @@ -654,7 +655,7 @@ static bool getaddressinfo(struct sockaddr *sa, char *addr, addr[0] = '\0'; *port = 0; - + errno = EAFNOSUPPORT; return FALSE; } @@ -672,11 +673,9 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) return; if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { - int error; - len = sizeof(struct Curl_sockaddr_storage); if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) { - error = SOCKERRNO; + int error = SOCKERRNO; failf(data, "getpeername() failed with errno %d: %s", error, Curl_strerror(conn, error)); return; @@ -685,7 +684,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) len = sizeof(struct Curl_sockaddr_storage); memset(&ssloc, 0, sizeof(ssloc)); if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) { - error = SOCKERRNO; + int error = SOCKERRNO; failf(data, "getsockname() failed with errno %d: %s", error, Curl_strerror(conn, error)); return; @@ -693,18 +692,16 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) if(!getaddressinfo((struct sockaddr*)&ssrem, conn->primary_ip, &conn->primary_port)) { - error = ERRNO; failf(data, "ssrem inet_ntop() failed with errno %d: %s", - error, Curl_strerror(conn, error)); + errno, Curl_strerror(conn, errno)); return; } memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); if(!getaddressinfo((struct sockaddr*)&ssloc, conn->local_ip, &conn->local_port)) { - error = ERRNO; failf(data, "ssloc inet_ntop() failed with errno %d: %s", - error, Curl_strerror(conn, error)); + errno, Curl_strerror(conn, errno)); return; } @@ -726,7 +723,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, CURLcode result = CURLE_OK; time_t allow; int error = 0; - struct timeval now; + struct curltime now; int rc; int i; @@ -751,7 +748,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, return CURLE_OPERATION_TIMEDOUT; } - for(i=0; i<2; i++) { + for(i = 0; i<2; i++) { const int other = i ^ 1; if(conn->tempsock[i] == CURL_SOCKET_BAD) continue; @@ -879,19 +876,6 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) curl_socklen_t onoff = (curl_socklen_t) 1; int level = IPPROTO_TCP; -#if 0 - /* The use of getprotobyname() is disabled since it isn't thread-safe on - numerous systems. On these getprotobyname_r() should be used instead, but - that exists in at least one 4 arg version and one 5 arg version, and - since the proto number rarely changes anyway we now just use the hard - coded number. The "proper" fix would need a configure check for the - correct function much in the same style the gethostbyname_r versions are - detected. */ - struct protoent *pe = getprotobyname("tcp"); - if(pe) - level = pe->p_proto; -#endif - #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) conn; #endif @@ -916,7 +900,7 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) static void nosigpipe(struct connectdata *conn, curl_socket_t sockfd) { - struct Curl_easy *data= conn->data; + struct Curl_easy *data = conn->data; int onoff = 1; if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, sizeof(onoff)) < 0) @@ -1008,9 +992,8 @@ static CURLcode singleipconnect(struct connectdata *conn, if(!getaddressinfo((struct sockaddr*)&addr.sa_addr, ipaddress, &port)) { /* malformed address or bug in inet_ntop, try next address */ - error = ERRNO; failf(data, "sa_addr inet_ntop() failed with errno %d: %s", - error, Curl_strerror(conn, error)); + errno, Curl_strerror(conn, errno)); Curl_closesocket(conn, sockfd); return CURLE_OK; } @@ -1076,16 +1059,25 @@ static CURLcode singleipconnect(struct connectdata *conn, if(!isconnected && (conn->socktype == SOCK_STREAM)) { if(conn->bits.tcp_fastopen) { #if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */ - sa_endpoints_t endpoints; - endpoints.sae_srcif = 0; - endpoints.sae_srcaddr = NULL; - endpoints.sae_srcaddrlen = 0; - endpoints.sae_dstaddr = &addr.sa_addr; - endpoints.sae_dstaddrlen = addr.addrlen; - - rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, - CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, - NULL, 0, NULL, NULL); +#ifdef HAVE_BUILTIN_AVAILABLE + if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) { +#endif /* HAVE_BUILTIN_AVAILABLE */ + sa_endpoints_t endpoints; + endpoints.sae_srcif = 0; + endpoints.sae_srcaddr = NULL; + endpoints.sae_srcaddrlen = 0; + endpoints.sae_dstaddr = &addr.sa_addr; + endpoints.sae_dstaddrlen = addr.addrlen; + + rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, + CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, + NULL, 0, NULL, NULL); +#ifdef HAVE_BUILTIN_AVAILABLE + } + else { + rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + } +#endif /* HAVE_BUILTIN_AVAILABLE */ #elif defined(MSG_FASTOPEN) /* Linux */ if(conn->given->flags & PROTOPT_SSL) rc = connect(sockfd, &addr.sa_addr, addr.addrlen); @@ -1153,7 +1145,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ const struct Curl_dns_entry *remotehost) { struct Curl_easy *data = conn->data; - struct timeval before = Curl_tvnow(); + struct curltime before = Curl_tvnow(); CURLcode result = CURLE_COULDNT_CONNECT; time_t timeout_ms = Curl_timeleft(data, &before, TRUE); @@ -1169,7 +1161,6 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ conn->tempaddr[1] = NULL; conn->tempsock[0] = CURL_SOCKET_BAD; conn->tempsock[1] = CURL_SOCKET_BAD; - Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS); /* Max time for the next connection attempt */ conn->timeoutms_per_addr = @@ -1190,6 +1181,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ } data->info.numconnects++; /* to track the number of connections made */ + Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS); return CURLE_OK; } @@ -1341,7 +1333,7 @@ CURLcode Curl_socket(struct connectdata *conn, addr->family = ai->ai_family; addr->socktype = conn->socktype; - addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol; + addr->protocol = conn->socktype == SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol; addr->addrlen = ai->ai_addrlen; if(addr->addrlen > sizeof(struct Curl_sockaddr_storage)) diff --git a/lib/connect.h b/lib/connect.h index 44bdb10..3f05c39 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,7 +36,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* generic function that returns how much time there's left to run, according to the timeouts set */ time_t Curl_timeleft(struct Curl_easy *data, - struct timeval *nowp, + struct curltime *nowp, bool duringconnect); #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ diff --git a/lib/content_encoding.c b/lib/content_encoding.c index 652ed97..1102260 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -227,7 +227,7 @@ static enum { extra_len = (data[1] << 8) | data[0]; - if(len < (extra_len+2)) + if(len < (extra_len + 2)) return GZIP_UNDERFLOW; len -= (extra_len + 2); @@ -288,7 +288,7 @@ Curl_unencode_gzip_write(struct connectdata *conn, if(strcmp(zlibVersion(), "1.2.0.4") >= 0) { /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */ - if(inflateInit2(z, MAX_WBITS+32) != Z_OK) { + if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) { return process_zlib_error(conn, z); } k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */ diff --git a/lib/cookie.c b/lib/cookie.c index 6b678ae..7fb596a 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -125,7 +125,7 @@ static bool tailmatch(const char *cooke_domain, const char *hostname) if(hostname_len < cookie_domain_len) return FALSE; - if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len)) + if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len)) return FALSE; /* A lead char of cookie_domain is not '.'. @@ -375,9 +375,8 @@ Curl_cookie_add(struct Curl_easy *data, unless set */ { struct Cookie *clist; - char name[MAX_NAME]; struct Cookie *co; - struct Cookie *lastc=NULL; + struct Cookie *lastc = NULL; time_t now = time(NULL); bool replace_old = FALSE; bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ @@ -397,17 +396,19 @@ Curl_cookie_add(struct Curl_easy *data, if(httpheader) { /* This line was read off a HTTP-header */ + char name[MAX_NAME]; + char what[MAX_NAME]; const char *ptr; const char *semiptr; - char *what; - what = malloc(MAX_COOKIE_LINE); - if(!what) { + size_t linelength = strlen(lineptr); + if(linelength > MAX_COOKIE_LINE) { + /* discard overly long lines at once */ free(co); return NULL; } - semiptr=strchr(lineptr, ';'); /* first, find a semicolon */ + semiptr = strchr(lineptr, ';'); /* first, find a semicolon */ while(*lineptr && ISBLANK(*lineptr)) lineptr++; @@ -415,9 +416,9 @@ Curl_cookie_add(struct Curl_easy *data, ptr = lineptr; do { /* we have a = pair or a stand-alone word here */ - name[0]=what[0]=0; /* init the buffers */ + name[0] = what[0] = 0; /* init the buffers */ if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%" - MAX_COOKIE_LINE_TXT "[^;\r\n]", + MAX_NAME_TXT "[^;\r\n]", name, what)) { /* Use strstore() below to properly deal with received cookie headers that have the same string property set more than once, @@ -425,10 +426,24 @@ Curl_cookie_add(struct Curl_easy *data, const char *whatptr; bool done = FALSE; bool sep; - size_t len=strlen(what); + size_t len = strlen(what); size_t nlen = strlen(name); const char *endofn = &ptr[ nlen ]; + infof(data, "cookie size: name/val %d + %d bytes\n", + nlen, len); + + if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) || + ((nlen + len) > MAX_NAME)) { + /* too long individual name or contents, or too long combination of + name + contents. Chrome and Firefox support 4095 or 4096 bytes + combo. */ + freecookie(co); + infof(data, "oversized cookie dropped, name/val %d + %d bytes\n", + nlen, len); + return NULL; + } + /* name ends with a '=' ? */ sep = (*endofn == '=')?TRUE:FALSE; @@ -440,18 +455,18 @@ Curl_cookie_add(struct Curl_easy *data, endofn--; nlen--; } - name[nlen]=0; /* new end of name */ + name[nlen] = 0; /* new end of name */ } } /* Strip off trailing whitespace from the 'what' */ while(len && ISBLANK(what[len-1])) { - what[len-1]=0; + what[len-1] = 0; len--; } /* Skip leading whitespace from the 'what' */ - whatptr=what; + whatptr = what; while(*whatptr && ISBLANK(*whatptr)) whatptr++; @@ -484,6 +499,7 @@ Curl_cookie_add(struct Curl_easy *data, badcookie = TRUE; /* out of memory bad */ break; } + free(co->spath); /* if this is set again */ co->spath = sanitize_cookie_path(co->path); if(!co->spath) { badcookie = TRUE; /* out of memory bad */ @@ -510,7 +526,7 @@ Curl_cookie_add(struct Curl_easy *data, /* check for more dots */ dotp = strchr(whatptr, '.'); if(!dotp && !strcasecompare("localhost", whatptr)) - domain=":"; + domain = ":"; } #endif @@ -525,14 +541,14 @@ Curl_cookie_add(struct Curl_easy *data, break; } if(!is_ip) - co->tailmatch=TRUE; /* we always do that if the domain name was - given */ + co->tailmatch = TRUE; /* we always do that if the domain name was + given */ } else { /* we did not get a tailmatch and then the attempted set domain is not a domain to which the current host belongs. Mark as bad. */ - badcookie=TRUE; + badcookie = TRUE; infof(data, "skipped cookie with bad tailmatch domain: %s\n", whatptr); } @@ -581,26 +597,32 @@ Curl_cookie_add(struct Curl_easy *data, continue; } - ptr=semiptr+1; + ptr = semiptr + 1; while(*ptr && ISBLANK(*ptr)) ptr++; - semiptr=strchr(ptr, ';'); /* now, find the next semicolon */ + semiptr = strchr(ptr, ';'); /* now, find the next semicolon */ if(!semiptr && *ptr) /* There are no more semicolons, but there's a final name=value pair coming up */ - semiptr=strchr(ptr, '\0'); + semiptr = strchr(ptr, '\0'); } while(semiptr); if(co->maxage) { - co->expires = - curlx_strtoofft((*co->maxage=='\"')? - &co->maxage[1]:&co->maxage[0], NULL, 10); - if(CURL_OFF_T_MAX - now < co->expires) - /* avoid overflow */ + CURLofft offt; + offt = curlx_strtoofft((*co->maxage == '\"')? + &co->maxage[1]:&co->maxage[0], NULL, 10, + &co->expires); + if(offt == CURL_OFFT_FLOW) + /* overflow, used max value */ co->expires = CURL_OFF_T_MAX; - else - co->expires += now; + else if(!offt) { + if(CURL_OFF_T_MAX - now < co->expires) + /* would overflow */ + co->expires = CURL_OFF_T_MAX; + else + co->expires += now; + } } else if(co->expirestr) { /* Note that if the date couldn't get parsed for whatever reason, @@ -619,7 +641,7 @@ Curl_cookie_add(struct Curl_easy *data, if(!badcookie && !co->domain) { if(domain) { /* no domain was given in the header line, set the default */ - co->domain=strdup(domain); + co->domain = strdup(domain); if(!co->domain) badcookie = TRUE; } @@ -639,11 +661,11 @@ Curl_cookie_add(struct Curl_easy *data, else endslash = memrchr(path, '/', (size_t)(queryp - path)); if(endslash) { - size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */ - co->path=malloc(pathlen+1); /* one extra for the zero byte */ + size_t pathlen = (size_t)(endslash-path + 1); /* include end slash */ + co->path = malloc(pathlen + 1); /* one extra for the zero byte */ if(co->path) { memcpy(co->path, path, pathlen); - co->path[pathlen]=0; /* zero terminate */ + co->path[pathlen] = 0; /* zero terminate */ co->spath = sanitize_cookie_path(co->path); if(!co->spath) badcookie = TRUE; /* out of memory bad */ @@ -653,8 +675,6 @@ Curl_cookie_add(struct Curl_easy *data, } } - free(what); - if(badcookie || !co->name) { /* we didn't get a cookie name or a bad one, this is an illegal line, bail out */ @@ -668,7 +688,7 @@ Curl_cookie_add(struct Curl_easy *data, reading the odd netscape cookies-file format here */ char *ptr; char *firstptr; - char *tok_buf=NULL; + char *tok_buf = NULL; int fields; /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies @@ -689,19 +709,19 @@ Curl_cookie_add(struct Curl_easy *data, return NULL; } /* strip off the possible end-of-line characters */ - ptr=strchr(lineptr, '\r'); + ptr = strchr(lineptr, '\r'); if(ptr) - *ptr=0; /* clear it */ - ptr=strchr(lineptr, '\n'); + *ptr = 0; /* clear it */ + ptr = strchr(lineptr, '\n'); if(ptr) - *ptr=0; /* clear it */ + *ptr = 0; /* clear it */ - firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ + firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ /* Now loop through the fields and init the struct we already have allocated */ - for(ptr=firstptr, fields=0; ptr && !badcookie; - ptr=strtok_r(NULL, "\t", &tok_buf), fields++) { + for(ptr = firstptr, fields = 0; ptr && !badcookie; + ptr = strtok_r(NULL, "\t", &tok_buf), fields++) { switch(fields) { case 0: if(ptr[0]=='.') /* skip preceding dots */ @@ -712,7 +732,7 @@ Curl_cookie_add(struct Curl_easy *data, break; case 1: /* This field got its explanation on the 23rd of May 2001 by - Andrés García: + Andrés García: flag: A TRUE/FALSE value indicating if all machines within a given domain can access the variable. This value is set automatically by @@ -726,7 +746,7 @@ Curl_cookie_add(struct Curl_easy *data, case 2: /* It turns out, that sometimes the file format allows the path field to remain not filled in, we try to detect this and work - around it! Andrés García made us aware of this... */ + around it! Andrés García made us aware of this... */ if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) { /* only if the path doesn't look like a boolean option! */ co->path = strdup(ptr); @@ -753,7 +773,8 @@ Curl_cookie_add(struct Curl_easy *data, co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE; break; case 4: - co->expires = curlx_strtoofft(ptr, NULL, 10); + if(curlx_strtoofft(ptr, NULL, 10, &co->expires)) + badcookie = TRUE; break; case 5: co->name = strdup(ptr); @@ -828,7 +849,7 @@ Curl_cookie_add(struct Curl_easy *data, if(strcasecompare(clist->domain, co->domain) && (clist->tailmatch == co->tailmatch)) /* The domains are identical */ - replace_old=TRUE; + replace_old = TRUE; } else if(!clist->domain && !co->domain) replace_old = TRUE; @@ -957,7 +978,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, { struct CookieInfo *c; FILE *fp = NULL; - bool fromfile=TRUE; + bool fromfile = TRUE; char *line = NULL; if(NULL == inc) { @@ -977,7 +998,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, if(file && !strcmp(file, "-")) { fp = stdin; - fromfile=FALSE; + fromfile = FALSE; } else if(file && !*file) { /* points to a "" string */ @@ -998,12 +1019,12 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, while(get_line(line, MAX_COOKIE_LINE, fp)) { if(checkprefix("Set-Cookie:", line)) { /* This is a cookie line, get it! */ - lineptr=&line[11]; - headerline=TRUE; + lineptr = &line[11]; + headerline = TRUE; } else { - lineptr=line; - headerline=FALSE; + lineptr = line; + headerline = FALSE; } while(*lineptr && ISBLANK(*lineptr)) lineptr++; @@ -1113,7 +1134,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, struct Cookie *newco; struct Cookie *co; time_t now = time(NULL); - struct Cookie *mainco=NULL; + struct Cookie *mainco = NULL; size_t matches = 0; bool is_ip; @@ -1185,7 +1206,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, co = mainco; - for(i=0; co; co = co->next) + for(i = 0; co; co = co->next) array[i++] = co; /* now sort the cookie pointers in path length order */ @@ -1194,8 +1215,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* remake the linked list order according to the new order */ mainco = array[0]; /* start here */ - for(i=0; inext = array[i+1]; + for(i = 0; inext = array[i + 1]; array[matches-1]->next = NULL; /* terminate the list */ free(array); /* remove the temporary data again */ @@ -1335,7 +1356,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) { struct Cookie *co; FILE *out; - bool use_stdout=FALSE; + bool use_stdout = FALSE; char *format_ptr; if((NULL == c) || (0 == c->numcookies)) @@ -1349,7 +1370,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) if(!strcmp("-", dumphere)) { /* use stdout */ out = stdout; - use_stdout=TRUE; + use_stdout = TRUE; } else { out = fopen(dumphere, FOPEN_WRITETEXT); @@ -1382,7 +1403,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) return 0; } -struct curl_slist *Curl_cookie_list(struct Curl_easy *data) +static struct curl_slist *cookie_list(struct Curl_easy *data) { struct curl_slist *list = NULL; struct curl_slist *beg; @@ -1413,6 +1434,15 @@ struct curl_slist *Curl_cookie_list(struct Curl_easy *data) return list; } +struct curl_slist *Curl_cookie_list(struct Curl_easy *data) +{ + struct curl_slist *list; + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + list = cookie_list(data); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + return list; +} + void Curl_flush_cookies(struct Curl_easy *data, int cleanup) { if(data->set.str[STRING_COOKIEJAR]) { diff --git a/lib/cookie.h b/lib/cookie.h index a9a4578..cb50b71 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -62,13 +62,16 @@ struct CookieInfo { that comprise the cookie non-terminal in the syntax description of the Set-Cookie header)" + We allow max 5000 bytes cookie header. Max 4095 bytes length per cookie + name and value. Name + value may not exceed 4096 bytes. + */ #define MAX_COOKIE_LINE 5000 #define MAX_COOKIE_LINE_TXT "4999" -/* This is the maximum length of a cookie name we deal with: */ -#define MAX_NAME 1024 -#define MAX_NAME_TXT "1023" +/* This is the maximum length of a cookie name or content we deal with: */ +#define MAX_NAME 4096 +#define MAX_NAME_TXT "4095" struct Curl_easy; /* diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 1adf319..6eb28bb 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -286,7 +286,7 @@ 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++) { + for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { size_t ss_size; #ifdef ENABLE_IPV6 @@ -570,9 +570,9 @@ curl_dogetaddrinfo(const char *hostname, int line, const char *source) { #ifdef USE_LWIPSOCK - int res=lwip_getaddrinfo(hostname, service, hints, result); + int res = lwip_getaddrinfo(hostname, service, hints, result); #else - int res=(getaddrinfo)(hostname, service, hints, result); + int res = (getaddrinfo)(hostname, service, hints, result); #endif if(0 == res) /* success */ diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 812d969..c80484f 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -51,9 +51,6 @@ /* to disable RTSP */ #cmakedefine CURL_DISABLE_RTSP 1 -/* to disable RTMP */ -#cmakedefine CURL_DISABLE_RTMP 1 - /* to disable SMB */ #cmakedefine CURL_DISABLE_SMB 1 @@ -82,9 +79,6 @@ /* when not building a shared library */ #cmakedefine CURL_STATICLIB 1 -/* Set to explicitly specify we don't want to use thread-safe functions */ -#cmakedefine DISABLED_THREADSAFE 1 - /* your Entropy Gathering Daemon socket pathname */ #cmakedefine EGD_SOCKET ${EGD_SOCKET} @@ -894,6 +888,9 @@ /* The size of `off_t', as computed by sizeof. */ #cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T} +/* The size of `curl_off_t', as computed by sizeof. */ +#cmakedefine SIZEOF_CURL_OFF_T ${SIZEOF_CURL_OFF_T} + /* The size of `size_t', as computed by sizeof. */ #cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T} @@ -972,9 +969,6 @@ /* Version number of package */ #cmakedefine VERSION ${VERSION} -/* Define to avoid automatic inclusion of winsock.h */ -#cmakedefine WIN32_LEAN_AND_MEAN 1 - /* Define to 1 if OS is AIX. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE diff --git a/lib/curl_fnmatch.c b/lib/curl_fnmatch.c index 46d3ada..631268b 100644 --- a/lib/curl_fnmatch.c +++ b/lib/curl_fnmatch.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -151,7 +151,7 @@ static int setcharset(unsigned char **p, unsigned char *charset) (*p)++; } else if(c == '[') { - char c2 = *((*p)+1); + char c2 = *((*p) + 1); if(c2 == ':') { /* there has to be a keyword */ (*p) += 2; if(parsekeyword(p, charset)) { @@ -319,9 +319,9 @@ static int loop(const unsigned char *pattern, const unsigned char *string) switch(state) { case CURLFNM_LOOP_DEFAULT: if(*p == '*') { - while(*(p+1) == '*') /* eliminate multiple stars */ + while(*(p + 1) == '*') /* eliminate multiple stars */ p++; - if(*s == '\0' && *(p+1) == '\0') + if(*s == '\0' && *(p + 1) == '\0') return CURL_FNMATCH_MATCH; rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */ if(rc == CURL_FNMATCH_MATCH) @@ -351,7 +351,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string) p++; } else if(*p == '[') { - unsigned char *pp = p+1; /* cannot handle with pointer to register */ + unsigned char *pp = p + 1; /* cannot handle with pointer to register */ if(setcharset(&pp, charset)) { int found = FALSE; if(charset[(unsigned int)*s]) @@ -381,7 +381,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string) found = !found; if(found) { - p = pp+1; + p = pp + 1; s++; memset(charset, 0, CURLFNM_CHSET_SIZE); } diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c index aea5452..5154949 100644 --- a/lib/curl_ntlm_core.c +++ b/lib/curl_ntlm_core.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,6 +31,25 @@ * https://www.innovation.ch/java/ntlm.html */ +/* Please keep the SSL backend-specific #if branches in this order: + + 1. USE_OPENSSL + 2. USE_GNUTLS_NETTLE + 3. USE_GNUTLS + 4. USE_NSS + 5. USE_MBEDTLS + 6. USE_DARWINSSL + 7. USE_OS400CRYPTO + 8. USE_WIN32_CRYPTO + + This ensures that: + - the same SSL branch gets activated throughout this source + file even if multiple backends are enabled at the same time. + - OpenSSL and NSS have higher priority than Windows Crypt, due + to issues with the latter supporting NTLM2Session responses + in NTLM type-3 messages. + */ + #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) #ifdef USE_OPENSSL @@ -76,14 +95,6 @@ # define MD5_DIGEST_LENGTH 16 # define MD4_DIGEST_LENGTH 16 -#elif defined(USE_MBEDTLS) - -# include -# include -# if !defined(MBEDTLS_MD4_C) -# include "curl_md4.h" -# endif - #elif defined(USE_NSS) # include @@ -92,6 +103,14 @@ # include "curl_md4.h" # define MD5_DIGEST_LENGTH MD5_LENGTH +#elif defined(USE_MBEDTLS) + +# include +# include +# if !defined(MBEDTLS_MD4_C) +# include "curl_md4.h" +# endif + #elif defined(USE_DARWINSSL) # include @@ -196,26 +215,6 @@ static void setup_des_key(const unsigned char *key_56, gcry_cipher_setkey(*des, key, sizeof(key)); } -#elif defined(USE_MBEDTLS) - -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - mbedtls_des_context ctx; - char key[8]; - - /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, key); - - /* Set the key parity to odd */ - mbedtls_des_key_set_parity((unsigned char *) key); - - /* Perform the encryption */ - mbedtls_des_init(&ctx); - mbedtls_des_setkey_enc(&ctx, (unsigned char *) key); - return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; -} - #elif defined(USE_NSS) /* @@ -281,6 +280,26 @@ fail: return rv; } +#elif defined(USE_MBEDTLS) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + mbedtls_des_context ctx; + char key[8]; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + mbedtls_des_key_set_parity((unsigned char *) key); + + /* Perform the encryption */ + mbedtls_des_init(&ctx); + mbedtls_des_setkey_enc(&ctx, (unsigned char *) key); + return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; +} + #elif defined(USE_DARWINSSL) static bool encrypt_des(const unsigned char *in, unsigned char *out, @@ -428,7 +447,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, setup_des_key(keys + 14, &des); gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); gcry_cipher_close(des); -#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \ +#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \ || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(plaintext, results, keys); encrypt_des(plaintext, results + 8, keys + 7); @@ -492,7 +511,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, setup_des_key(pw + 7, &des); gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); gcry_cipher_close(des); -#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \ +#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \ || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(magic, lmbuffer, pw); encrypt_des(magic, lmbuffer + 8, pw + 7); @@ -571,13 +590,18 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, gcry_md_write(MD4pw, pw, 2 * len); memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH); gcry_md_close(MD4pw); -#elif defined(USE_NSS) || defined(USE_OS400CRYPTO) || \ - (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) +#elif defined(USE_NSS) Curl_md4it(ntbuffer, pw, 2 * len); #elif defined(USE_MBEDTLS) +#if defined(MBEDTLS_MD4_C) mbedtls_md4(pw, 2 * len, ntbuffer); +#else + Curl_md4it(ntbuffer, pw, 2 * len); +#endif #elif defined(USE_DARWINSSL) (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer); +#elif defined(USE_OS400CRYPTO) + Curl_md4it(ntbuffer, pw, 2 * len); #elif defined(USE_WIN32_CRYPTO) HCRYPTPROV hprov; if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, @@ -780,7 +804,7 @@ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, /* Concatenate the HMAC MD5 output with the client nonce */ memcpy(lmresp, hmac_output, 16); - memcpy(lmresp+16, challenge_client, 8); + memcpy(lmresp + 16, challenge_client, 8); return result; } diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h index 4a83d40..07ef5de 100644 --- a/lib/curl_ntlm_core.h +++ b/lib/curl_ntlm_core.h @@ -26,13 +26,19 @@ #if defined(USE_NTLM) +/* 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_GNUTLS_NETTLE) && \ + !defined(USE_GNUTLS) && \ + defined(USE_NSS) +#define NTLM_NEEDS_NSS_INIT +#endif + #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) #ifdef USE_OPENSSL -# if !defined(OPENSSL_VERSION_NUMBER) && \ - !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H) -# error "curl_ntlm_core.h shall not be included before OpenSSL headers." -# endif +# include #endif /* Define USE_NTRESPONSES in order to make the type-3 message include diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c index 9f5b87b..03f47a3 100644 --- a/lib/curl_ntlm_wb.c +++ b/lib/curl_ntlm_wb.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -48,6 +48,7 @@ #include "sendf.h" #include "select.h" #include "vauth/ntlm.h" +#include "curl_ntlm_core.h" #include "curl_ntlm_wb.h" #include "url.h" #include "strerror.h" @@ -123,7 +124,6 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) struct passwd pw, *pw_res; char pwbuf[1024]; #endif - int error; /* Return if communication with ntlm_auth already set up */ if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || @@ -178,26 +178,23 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) ntlm_auth = NTLM_WB_FILE; if(access(ntlm_auth, X_OK) != 0) { - error = ERRNO; failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s", - ntlm_auth, error, Curl_strerror(conn, error)); + ntlm_auth, errno, Curl_strerror(conn, errno)); goto done; } if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) { - error = ERRNO; failf(conn->data, "Could not open socket pair. errno %d: %s", - error, Curl_strerror(conn, error)); + errno, Curl_strerror(conn, errno)); goto done; } child_pid = fork(); if(child_pid == -1) { - error = ERRNO; sclose(sockfds[0]); sclose(sockfds[1]); failf(conn->data, "Could not fork. errno %d: %s", - error, Curl_strerror(conn, error)); + errno, Curl_strerror(conn, errno)); goto done; } else if(!child_pid) { @@ -208,16 +205,14 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) /* Don't use sclose in the child since it fools the socket leak detector */ sclose_nolog(sockfds[0]); if(dup2(sockfds[1], STDIN_FILENO) == -1) { - error = ERRNO; failf(conn->data, "Could not redirect child stdin. errno %d: %s", - error, Curl_strerror(conn, error)); + errno, Curl_strerror(conn, errno)); exit(1); } if(dup2(sockfds[1], STDOUT_FILENO) == -1) { - error = ERRNO; failf(conn->data, "Could not redirect child stdout. errno %d: %s", - error, Curl_strerror(conn, error)); + errno, Curl_strerror(conn, errno)); exit(1); } @@ -235,10 +230,9 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) "--username", username, NULL); - error = ERRNO; sclose_nolog(sockfds[1]); failf(conn->data, "Could not execl(). errno %d: %s", - error, Curl_strerror(conn, error)); + errno, Curl_strerror(conn, errno)); exit(1); } @@ -364,7 +358,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, /* not set means empty */ if(!userp) - userp=""; + userp = ""; switch(ntlm->state) { case NTLMSTATE_TYPE1: @@ -420,7 +414,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, /* connection is already authenticated, * don't send a header in future requests */ free(*allocuserpwd); - *allocuserpwd=NULL; + *allocuserpwd = NULL; authp->done = TRUE; break; } diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c index 87a6caf..9743064 100644 --- a/lib/curl_rtmp.c +++ b/lib/curl_rtmp.c @@ -74,6 +74,7 @@ const struct Curl_handler Curl_handler_rtmp = { ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_RTMP, /* defport */ CURLPROTO_RTMP, /* protocol */ PROTOPT_NONE /* flags*/ @@ -94,6 +95,7 @@ const struct Curl_handler Curl_handler_rtmpt = { ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_RTMPT, /* defport */ CURLPROTO_RTMPT, /* protocol */ PROTOPT_NONE /* flags*/ @@ -114,6 +116,7 @@ const struct Curl_handler Curl_handler_rtmpe = { ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_RTMP, /* defport */ CURLPROTO_RTMPE, /* protocol */ PROTOPT_NONE /* flags*/ @@ -134,6 +137,7 @@ const struct Curl_handler Curl_handler_rtmpte = { ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_RTMPT, /* defport */ CURLPROTO_RTMPTE, /* protocol */ PROTOPT_NONE /* flags*/ @@ -154,6 +158,7 @@ const struct Curl_handler Curl_handler_rtmps = { ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_RTMPS, /* defport */ CURLPROTO_RTMPS, /* protocol */ PROTOPT_NONE /* flags*/ @@ -174,6 +179,7 @@ const struct Curl_handler Curl_handler_rtmpts = { ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_RTMPS, /* defport */ CURLPROTO_RTMPTS, /* protocol */ PROTOPT_NONE /* flags*/ @@ -200,7 +206,7 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done) RTMP *r = conn->proto.generic; SET_RCVTIMEO(tv, 10); - r->m_sb.sb_socket = conn->sock[FIRSTSOCKET]; + r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET]; /* We have to know if it's a write before we send the * connect request packet diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index bd574b5..550433d 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -331,7 +331,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_NTLM; if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd, + result = Curl_auth_create_ntlm_type1_message(data, + conn->user, conn->passwd, &conn->ntlm, &resp, &len); } else @@ -493,7 +494,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, #ifdef USE_NTLM case SASL_NTLM: /* Create the type-1 message */ - result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd, + result = Curl_auth_create_ntlm_type1_message(data, + conn->user, conn->passwd, &conn->ntlm, &resp, &len); newstate = SASL_NTLM_TYPE2MSG; break; diff --git a/lib/curl_setup.h b/lib/curl_setup.h index d22997c..402ebc0 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,6 +22,10 @@ * ***************************************************************************/ +#if defined(BUILDING_LIBCURL) && !defined(CURL_NO_OLDIES) +#define CURL_NO_OLDIES +#endif + /* * Define WIN32 when build target is Win32 API */ @@ -31,6 +35,17 @@ #define WIN32 #endif +#ifdef WIN32 +/* + * Don't include unneeded stuff in Windows headers to avoid compiler + * warnings and macro clashes. + * Make sure to define this macro before including any Windows headers. + */ +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +#endif + /* * Include configuration script results or hand-crafted * configuration file for platforms which lack config tool. @@ -126,14 +141,7 @@ #include -/* - * Ensure that no one is using the old SIZEOF_CURL_OFF_T macro - */ - -#ifdef SIZEOF_CURL_OFF_T -# error "SIZEOF_CURL_OFF_T shall not be defined!" - Error Compilation_aborted_SIZEOF_CURL_OFF_T_shall_not_be_defined -#endif +#define CURL_SIZEOF_CURL_OFF_T SIZEOF_CURL_OFF_T /* * Disable other protocols when http is the only one desired. @@ -170,9 +178,6 @@ # ifndef CURL_DISABLE_SMTP # define CURL_DISABLE_SMTP # endif -# ifndef CURL_DISABLE_RTMP -# define CURL_DISABLE_RTMP -# endif # ifndef CURL_DISABLE_GOPHER # define CURL_DISABLE_GOPHER # endif @@ -191,7 +196,7 @@ /* ================================================================ */ /* No system header file shall be included in this file before this */ -/* point. The only allowed ones are those included from curlbuild.h */ +/* point. The only allowed ones are those included from curl/system.h */ /* ================================================================ */ /* @@ -237,9 +242,6 @@ # if defined(_UNICODE) && !defined(UNICODE) # define UNICODE # endif -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif # include # ifdef HAVE_WINSOCK2_H # include @@ -640,9 +642,8 @@ int netware_init(void); #endif #endif -/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */ -#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE) -#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") +#ifdef CURL_WANTS_CA_BUNDLE_ENV +#error "No longer supported. Set CURLOPT_CAINFO at runtime instead." #endif /* @@ -716,6 +717,7 @@ Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 #if defined(WIN32) || defined(MSDOS) #define FOPEN_READTEXT "rt" #define FOPEN_WRITETEXT "wt" +#define FOPEN_APPENDTEXT "at" #elif defined(__CYGWIN__) /* Cygwin has specific behavior we need to address when WIN32 is not defined. https://cygwin.com/cygwin-ug-net/using-textbinary.html @@ -725,9 +727,11 @@ endings either CRLF or LF so 't' is appropriate. */ #define FOPEN_READTEXT "rt" #define FOPEN_WRITETEXT "w" +#define FOPEN_APPENDTEXT "a" #else #define FOPEN_READTEXT "r" #define FOPEN_WRITETEXT "w" +#define FOPEN_APPENDTEXT "a" #endif /* WinSock destroys recv() buffer when send() failed. diff --git a/lib/curl_setup_once.h b/lib/curl_setup_once.h index 684187c..a5b542c 100644 --- a/lib/curl_setup_once.h +++ b/lib/curl_setup_once.h @@ -436,20 +436,6 @@ typedef int sig_atomic_t; /* - * Macro ERRNO / SET_ERRNO() returns / sets the NOT *socket-related* errno - * (or equivalent) on this platform to hide platform details to code using it. - */ - -#if defined(WIN32) && !defined(USE_LWIPSOCK) -#define ERRNO ((int)GetLastError()) -#define SET_ERRNO(x) (SetLastError((DWORD)(x))) -#else -#define ERRNO (errno) -#define SET_ERRNO(x) (errno = (x)) -#endif - - -/* * Portable error number symbolic names defined to Winsock error codes. */ diff --git a/lib/curl_threads.c b/lib/curl_threads.c index a78eff5..c1624a9 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -104,15 +104,22 @@ int Curl_thread_join(curl_thread_t *hnd) curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), void *arg) { + curl_thread_t t; #ifdef _WIN32_WCE - return CreateThread(NULL, 0, func, arg, 0, NULL); + t = CreateThread(NULL, 0, func, arg, 0, NULL); #else - curl_thread_t t; t = (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL); - if((t == 0) || (t == (curl_thread_t)-1L)) +#endif + if((t == 0) || (t == LongToHandle(-1L))) { +#ifdef _WIN32_WCE + DWORD gle = GetLastError(); + errno = ((gle == ERROR_ACCESS_DENIED || + gle == ERROR_NOT_ENOUGH_MEMORY) ? + EACCES : EINVAL); +#endif return curl_thread_t_null; + } return t; -#endif } void Curl_thread_destroy(curl_thread_t hnd) diff --git a/lib/dict.c b/lib/dict.c index 451ec38..4fc8552 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -85,6 +85,7 @@ const struct Curl_handler Curl_handler_dict = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_DICT, /* defport */ CURLPROTO_DICT, /* protocol */ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ @@ -97,7 +98,7 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff) char *ptr; size_t len; char ch; - int olen=0; + int olen = 0; CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE); if(!newp || result) @@ -116,7 +117,7 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff) } dictp[olen++] = ch; } - dictp[olen]=0; + dictp[olen] = 0; } free(newp); return dictp; @@ -131,8 +132,8 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) char *strategy = NULL; char *nthdef = NULL; /* This is not part of the protocol, but required by RFC 2229 */ - CURLcode result=CURLE_OK; - struct Curl_easy *data=conn->data; + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; char *path = data->state.path; @@ -167,7 +168,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) if((word == NULL) || (*word == (char)0)) { infof(data, "lookup word is missing\n"); - word=(char *)"default"; + word = (char *)"default"; } if((database == NULL) || (*database == (char)0)) { database = (char *)"!"; @@ -221,7 +222,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) if((word == NULL) || (*word == (char)0)) { infof(data, "lookup word is missing\n"); - word=(char *)"default"; + word = (char *)"default"; } if((database == NULL) || (*database == (char)0)) { database = (char *)"!"; diff --git a/lib/dotdot.c b/lib/dotdot.c index 20603bc..cbb308d 100644 --- a/lib/dotdot.c +++ b/lib/dotdot.c @@ -55,7 +55,7 @@ char *Curl_dedotdotify(const char *input) size_t inlen = strlen(input); char *clone; size_t clen = inlen; /* the length of the cloned input */ - char *out = malloc(inlen+1); + char *out = malloc(inlen + 1); char *outptr; char *orgclone; char *queryp; @@ -92,25 +92,25 @@ char *Curl_dedotdotify(const char *input) remove that prefix from the input buffer; otherwise, */ if(!strncmp("./", clone, 2)) { - clone+=2; - clen-=2; + clone += 2; + clen -= 2; } else if(!strncmp("../", clone, 3)) { - clone+=3; - clen-=3; + clone += 3; + clen -= 3; } /* B. if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, */ else if(!strncmp("/./", clone, 3)) { - clone+=2; - clen-=2; + clone += 2; + clen -= 2; } else if(!strcmp("/.", clone)) { clone[1]='/'; clone++; - clen-=1; + clen -= 1; } /* C. if the input buffer begins with a prefix of "/../" or "/..", where @@ -119,8 +119,8 @@ char *Curl_dedotdotify(const char *input) any) from the output buffer; otherwise, */ else if(!strncmp("/../", clone, 4)) { - clone+=3; - clen-=3; + clone += 3; + clen -= 3; /* remove the last segment from the output buffer */ while(outptr > out) { outptr--; @@ -131,8 +131,8 @@ char *Curl_dedotdotify(const char *input) } else if(!strcmp("/..", clone)) { clone[2]='/'; - clone+=2; - clen-=2; + clone += 2; + clen -= 2; /* remove the last segment from the output buffer */ while(outptr > out) { outptr--; @@ -146,8 +146,8 @@ char *Curl_dedotdotify(const char *input) that from the input buffer; otherwise, */ else if(!strcmp(".", clone) || !strcmp("..", clone)) { - *clone=0; - *out=0; + *clone = 0; + *out = 0; } else { @@ -172,7 +172,7 @@ char *Curl_dedotdotify(const char *input) from the correct index. */ size_t oindex = queryp - orgclone; qlen = strlen(&input[oindex]); - memcpy(outptr, &input[oindex], qlen+1); /* include the ending zero byte */ + memcpy(outptr, &input[oindex], qlen + 1); /* include the end zero byte */ } free(orgclone); diff --git a/lib/easy.c b/lib/easy.c index 2b1ce9e..5328f9c 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -433,7 +433,7 @@ static int events_timer(struct Curl_multi *multi, /* multi handle */ */ static int poll2cselect(int pollmask) { - int omask=0; + int omask = 0; if(pollmask & POLLIN) omask |= CURL_CSELECT_IN; if(pollmask & POLLOUT) @@ -450,7 +450,7 @@ static int poll2cselect(int pollmask) */ static short socketcb2poll(int pollmask) { - short omask=0; + short omask = 0; if(pollmask & CURL_POLL_IN) omask |= POLLIN; if(pollmask & CURL_POLL_OUT) @@ -473,7 +473,7 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */ { struct events *ev = userp; struct socketmonitor *m; - struct socketmonitor *prev=NULL; + struct socketmonitor *prev = NULL; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) easy; @@ -569,14 +569,14 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) struct socketmonitor *m; struct pollfd *f; struct pollfd fds[4]; - int numfds=0; + int numfds = 0; int pollrc; int i; - struct timeval before; - struct timeval after; + struct curltime before; + struct curltime after; /* populate the fds[] array */ - for(m = ev->list, f=&fds[0]; m; m = m->next) { + for(m = ev->list, f = &fds[0]; m; m = m->next) { f->fd = m->socket.fd; f->events = m->socket.events; f->revents = 0; @@ -653,7 +653,9 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) */ static CURLcode easy_events(struct Curl_multi *multi) { - struct events evs= {2, FALSE, 0, NULL, 0}; + /* this struct is made static to allow it to be used after this function + returns and curl_multi_remove_handle() is called */ + static struct events evs = {2, FALSE, 0, NULL, 0}; /* if running event-based, do some further multi inits */ events_setup(multi, &evs); @@ -670,7 +672,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi) bool done = FALSE; CURLMcode mcode = CURLM_OK; CURLcode result = CURLE_OK; - struct timeval before; + struct curltime before; int without_fds = 0; /* count number of consecutive returns from curl_multi_wait() without any filedescriptors */ @@ -683,7 +685,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi) if(!mcode) { if(!rc) { - struct timeval after = curlx_tvnow(); + struct curltime after = curlx_tvnow(); /* If it returns without any filedescriptor instantly, we need to avoid busy-looping during periods where it has nothing particular @@ -1025,13 +1027,13 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) struct tempbuf writebuf[3]; /* there can only be three */ /* copy the structs to allow for immediate re-pausing */ - for(i=0; i < data->state.tempcount; i++) { + for(i = 0; i < data->state.tempcount; i++) { writebuf[i] = data->state.tempwrite[i]; data->state.tempwrite[i].buf = NULL; } data->state.tempcount = 0; - for(i=0; i < count; i++) { + for(i = 0; i < count; i++) { /* even if one function returns error, this loops through and frees all buffers */ if(!result) diff --git a/lib/escape.c b/lib/escape.c index 973aeb6..b7e2d32 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -84,14 +84,14 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, char *testing_ptr = NULL; unsigned char in; /* we need to treat the characters unsigned */ size_t newlen; - size_t strindex=0; + size_t strindex = 0; size_t length; CURLcode result; if(inlength < 0) return NULL; - alloc = (inlength?(size_t)inlength:strlen(string))+1; + alloc = (inlength?(size_t)inlength:strlen(string)) + 1; newlen = alloc; ns = malloc(alloc); @@ -104,7 +104,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, if(Curl_isunreserved(in)) /* just copy this */ - ns[strindex++]=in; + ns[strindex++] = in; else { /* encode it */ newlen += 2; /* the size grows with two, since this'll become a %XX */ @@ -116,7 +116,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, ns = testing_ptr; } - result = Curl_convert_to_network(data, &in, 1); + result = Curl_convert_to_network(data, (char *)&in, 1); if(result) { /* Curl_convert_to_network calls failf if unsuccessful */ free(ns); @@ -125,11 +125,11 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, snprintf(&ns[strindex], 4, "%%%02X", in); - strindex+=3; + strindex += 3; } string++; } - ns[strindex]=0; /* terminate it */ + ns[strindex] = 0; /* terminate it */ return ns; } @@ -148,10 +148,10 @@ CURLcode Curl_urldecode(struct Curl_easy *data, char **ostring, size_t *olen, bool reject_ctrl) { - size_t alloc = (length?length:strlen(string))+1; + size_t alloc = (length?length:strlen(string)) + 1; char *ns = malloc(alloc); unsigned char in; - size_t strindex=0; + size_t strindex = 0; unsigned long hex; CURLcode result; @@ -173,15 +173,15 @@ CURLcode Curl_urldecode(struct Curl_easy *data, in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */ - result = Curl_convert_from_network(data, &in, 1); + result = Curl_convert_from_network(data, (char *)&in, 1); if(result) { /* Curl_convert_from_network calls failf if unsuccessful */ free(ns); return result; } - string+=2; - alloc-=2; + string += 2; + alloc -= 2; } if(reject_ctrl && (in < 0x20)) { @@ -192,7 +192,7 @@ CURLcode Curl_urldecode(struct Curl_easy *data, ns[strindex++] = in; string++; } - ns[strindex]=0; /* terminate it */ + ns[strindex] = 0; /* terminate it */ if(olen) /* store output size */ diff --git a/lib/file.c b/lib/file.c index c804d75..7cfdab1 100644 --- a/lib/file.c +++ b/lib/file.c @@ -108,6 +108,7 @@ const struct Curl_handler Curl_handler_file = { ZERO_NULL, /* perform_getsock */ file_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ 0, /* defport */ CURLPROTO_FILE, /* protocol */ PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */ @@ -132,37 +133,42 @@ static CURLcode file_setup_connection(struct connectdata *conn) static CURLcode file_range(struct connectdata *conn) { curl_off_t from, to; - curl_off_t totalsize=-1; + curl_off_t totalsize = -1; char *ptr; char *ptr2; struct Curl_easy *data = conn->data; if(data->state.use_range && data->state.range) { - from=curlx_strtoofft(data->state.range, &ptr, 0); - while(*ptr && (ISSPACE(*ptr) || (*ptr=='-'))) + CURLofft from_t; + CURLofft to_t; + from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); + if(from_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) ptr++; - to=curlx_strtoofft(ptr, &ptr2, 0); - if(ptr == ptr2) { - /* we didn't get any digit */ - to=-1; - } - if((-1 == to) && (from>=0)) { + to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); + if(to_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + if((to_t == CURL_OFFT_INVAL) && !from_t) { /* X - */ data->state.resume_from = from; DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n", from)); } - else if(from < 0) { + else if((from_t == CURL_OFFT_INVAL) && !to_t) { /* -Y */ - data->req.maxdownload = -from; - data->state.resume_from = from; + data->req.maxdownload = to; + data->state.resume_from = -to; DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n", - -from)); + to)); } else { /* X-Y */ totalsize = to-from; - data->req.maxdownload = totalsize+1; /* include last byte */ + if(totalsize == CURL_OFF_T_MAX) + /* this is too big to increase, so bail out */ + return CURLE_RANGE_ERROR; + data->req.maxdownload = totalsize + 1; /* include last byte */ data->state.resume_from = from; DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", @@ -225,7 +231,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) } /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ - for(i=0; i < real_path_len; ++i) + for(i = 0; i < real_path_len; ++i) if(actual_path[i] == '/') actual_path[i] = '\\'; else if(!actual_path[i]) { /* binary zero */ @@ -427,9 +433,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done) struct_stat statbuf; /* struct_stat instead of struct stat just to allow the Windows version to have a different struct without having to redefine the simple word 'stat' */ - curl_off_t expected_size=0; + curl_off_t expected_size = 0; bool size_known; - bool fstated=FALSE; + bool fstated = FALSE; ssize_t nread; struct Curl_easy *data = conn->data; char *buf = data->state.buffer; @@ -500,7 +506,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) tm->tm_hour, tm->tm_min, tm->tm_sec); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0); if(!result) /* set the file size to make it available post transfer */ Curl_pgrsSetDownloadSize(data, expected_size); diff --git a/lib/formdata.c b/lib/formdata.c index e48a627..3568ac5 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -32,6 +32,8 @@ #include "urldata.h" /* for struct Curl_easy */ #include "formdata.h" +#include "mime.h" +#include "non-ascii.h" #include "vtls/vtls.h" #include "strcase.h" #include "sendf.h" @@ -42,13 +44,6 @@ #include "curl_memory.h" #include "memdebug.h" -#ifndef HAVE_BASENAME -static char *Curl_basename(char *path); -#define basename(x) Curl_basename((x)) -#endif - -static size_t readfromfile(struct Form *form, char *buffer, size_t size); -static CURLcode formboundary(struct Curl_easy *data, char *buffer, size_t len); /* What kind of Content-Type to use on un-specified files with unrecognized extensions. */ @@ -197,7 +192,7 @@ static const char *ContentTypeForFilename(const char *filename, contenttype = HTTPPOST_CONTENTTYPE_DEFAULT; if(filename) { /* in case a NULL was passed in */ - for(i=0; i= strlen(ctts[i].extension)) { if(strcasecompare(filename + strlen(filename) - strlen(ctts[i].extension), @@ -272,7 +267,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, struct curl_httppost *post = NULL; CURLformoption option; struct curl_forms *forms = NULL; - char *array_value=NULL; /* value read from an array */ + char *array_value = NULL; /* value read from an array */ /* This is a state variable, that if TRUE means that we're parsing an array that we got passed to us. If FALSE we're parsing the input @@ -641,15 +636,26 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } form->contenttype_alloc = TRUE; } + if(form->name && form->namelength) { + /* Name should not contain nul bytes. */ + size_t i; + for(i = 0; i < form->namelength; i++) + if(!form->name[i]) { + return_value = CURL_FORMADD_NULL; + break; + } + if(return_value != CURL_FORMADD_OK) + break; + } if(!(form->flags & HTTPPOST_PTRNAME) && (form == first_form) ) { /* Note that there's small risk that form->name is NULL here if the app passed in a bad combo, so we better check for that first. */ if(form->name) { - /* copy name (without strdup; possibly contains null characters) */ + /* copy name (without strdup; possibly not nul-terminated) */ form->name = Curl_memdup(form->name, form->namelength? form->namelength: - strlen(form->name)+1); + strlen(form->name) + 1); } if(!form->name) { return_value = CURL_FORMADD_MEMORY; @@ -663,7 +669,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, /* copy value (without strdup; possibly contains null characters) */ size_t clen = (size_t) form->contentslength; if(!clen) - clen = strlen(form->value)+1; + clen = strlen(form->value) + 1; form->value = Curl_memdup(form->value, clen); @@ -746,211 +752,6 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost, return result; } -#ifdef __VMS -#include -/* - * get_vms_file_size does what it takes to get the real size of the file - * - * For fixed files, find out the size of the EOF block and adjust. - * - * For all others, have to read the entire file in, discarding the contents. - * Most posted text files will be small, and binary files like zlib archives - * and CD/DVD images should be either a STREAM_LF format or a fixed format. - * - */ -curl_off_t VmsRealFileSize(const char *name, - const struct_stat *stat_buf) -{ - char buffer[8192]; - curl_off_t count; - int ret_stat; - FILE * file; - - file = fopen(name, FOPEN_READTEXT); /* VMS */ - if(file == NULL) - return 0; - - count = 0; - ret_stat = 1; - while(ret_stat > 0) { - ret_stat = fread(buffer, 1, sizeof(buffer), file); - if(ret_stat != 0) - count += ret_stat; - } - fclose(file); - - return count; -} - -/* - * - * VmsSpecialSize checks to see if the stat st_size can be trusted and - * if not to call a routine to get the correct size. - * - */ -static curl_off_t VmsSpecialSize(const char *name, - const struct_stat *stat_buf) -{ - switch(stat_buf->st_fab_rfm) { - case FAB$C_VAR: - case FAB$C_VFC: - return VmsRealFileSize(name, stat_buf); - break; - default: - return stat_buf->st_size; - } -} - -#endif - -#ifndef __VMS -#define filesize(name, stat_data) (stat_data.st_size) -#else - /* Getting the expected file size needs help on VMS */ -#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) -#endif - -/* - * AddFormData() adds a chunk of data to the FormData linked list. - * - * size is incremented by the chunk length, unless it is NULL - */ -static CURLcode AddFormData(struct FormData **formp, - enum formtype type, - const void *line, - curl_off_t length, - curl_off_t *size) -{ - struct FormData *newform; - char *alloc2 = NULL; - CURLcode result = CURLE_OK; - if(length < 0 || (size && *size < 0)) - return CURLE_BAD_FUNCTION_ARGUMENT; - - newform = malloc(sizeof(struct FormData)); - if(!newform) - return CURLE_OUT_OF_MEMORY; - newform->next = NULL; - - if(type <= FORM_CONTENT) { - /* we make it easier for plain strings: */ - if(!length) - length = strlen((char *)line); -#if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T) - else if(length >= (curl_off_t)(size_t)-1) { - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto error; - } -#endif - if(type != FORM_DATAMEM) { - newform->line = malloc((size_t)length+1); - if(!newform->line) { - result = CURLE_OUT_OF_MEMORY; - goto error; - } - alloc2 = newform->line; - memcpy(newform->line, line, (size_t)length); - - /* zero terminate for easier debugging */ - newform->line[(size_t)length]=0; - } - else { - newform->line = (char *)line; - type = FORM_DATA; /* in all other aspects this is just FORM_DATA */ - } - newform->length = (size_t)length; - } - else - /* For callbacks and files we don't have any actual data so we just keep a - pointer to whatever this points to */ - newform->line = (char *)line; - - newform->type = type; - - if(size) { - if(type != FORM_FILE) - /* for static content as well as callback data we add the size given - as input argument */ - *size += length; - else { - /* Since this is a file to be uploaded here, add the size of the actual - file */ - if(strcmp("-", newform->line)) { - struct_stat file; - if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) - *size += filesize(newform->line, file); - else { - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto error; - } - } - } - } - - if(*formp) { - (*formp)->next = newform; - *formp = newform; - } - else - *formp = newform; - - return CURLE_OK; - error: - if(newform) - free(newform); - if(alloc2) - free(alloc2); - return result; -} - -/* - * AddFormDataf() adds printf()-style formatted data to the formdata chain. - */ - -static CURLcode AddFormDataf(struct FormData **formp, - curl_off_t *size, - const char *fmt, ...) -{ - char *s; - CURLcode result; - va_list ap; - va_start(ap, fmt); - s = curl_mvaprintf(fmt, ap); - va_end(ap); - - if(!s) - return CURLE_OUT_OF_MEMORY; - - result = AddFormData(formp, FORM_DATAMEM, s, 0, size); - if(result) - free(s); - - return result; -} - -/* - * Curl_formclean() is used from http.c, this cleans a built FormData linked - * list - */ -void Curl_formclean(struct FormData **form_ptr) -{ - struct FormData *next, *form; - - form = *form_ptr; - if(!form) - return; - - do { - next=form->next; /* the following form line */ - if(form->type <= FORM_CONTENT) - free(form->line); /* free the line */ - free(form); /* free the struct */ - form = next; - } while(form); /* continue */ - - *form_ptr = NULL; -} - /* * curl_formget() * Serialize a curl_httppost struct. @@ -962,42 +763,34 @@ int curl_formget(struct curl_httppost *form, void *arg, curl_formget_callback append) { CURLcode result; - curl_off_t size; - struct FormData *data, *ptr; + curl_mimepart toppart; - result = Curl_getformdata(NULL, &data, form, NULL, &size); - if(result) - return (int)result; - - for(ptr = data; ptr; ptr = ptr->next) { - if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) { - char buffer[8192]; - size_t nread; - struct Form temp; - - Curl_FormInit(&temp, ptr); - - do { - nread = readfromfile(&temp, buffer, sizeof(buffer)); - if((nread == (size_t) -1) || - (nread > sizeof(buffer)) || - (nread != append(arg, buffer, nread))) { - if(temp.fp) - fclose(temp.fp); - Curl_formclean(&data); - return -1; - } - } while(nread); - } - else { - if(ptr->length != append(arg, ptr->line, ptr->length)) { - Curl_formclean(&data); - return -1; - } + Curl_mime_initpart(&toppart, NULL); /* default form is empty */ + result = Curl_getformdata(NULL, &toppart, form, NULL); + if(!result) + result = Curl_mime_prepare_headers(&toppart, "multipart/form-data", + NULL, MIMESTRATEGY_FORM); + + while(!result) { + char buffer[8192]; + size_t nread = Curl_mime_read(buffer, 1, sizeof buffer, &toppart); + + 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; } } - Curl_formclean(&data); - return 0; + + Curl_mime_cleanpart(&toppart); + return (int) result; } /* @@ -1013,7 +806,7 @@ void curl_formfree(struct curl_httppost *form) return; do { - next=form->next; /* the following form line */ + next = form->next; /* the following form line */ /* recurse to sub-contents */ curl_formfree(form->more); @@ -1031,118 +824,29 @@ void curl_formfree(struct curl_httppost *form) } while(form); /* continue */ } -#ifndef HAVE_BASENAME -/* - (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 - Edition) - - The basename() function shall take the pathname pointed to by path and - return a pointer to the final component of the pathname, deleting any - trailing '/' characters. - - If the string pointed to by path consists entirely of the '/' character, - basename() shall return a pointer to the string "/". If the string pointed - to by path is exactly "//", it is implementation-defined whether '/' or "//" - is returned. - If path is a null pointer or points to an empty string, basename() shall - return a pointer to the string ".". - - The basename() function may modify the string pointed to by path, and may - return a pointer to static storage that may then be overwritten by a - subsequent call to basename(). - - The basename() function need not be reentrant. A function that is not - required to be reentrant is not required to be thread-safe. - -*/ -static char *Curl_basename(char *path) +/* Set mime part name, taking care of non nul-terminated name string. */ +static CURLcode setname(curl_mimepart *part, const char *name, size_t len) { - /* Ignore all the details above for now and make a quick and simple - implementaion here */ - char *s1; - char *s2; - - s1=strrchr(path, '/'); - s2=strrchr(path, '\\'); + char *zname; + CURLcode res; - if(s1 && s2) { - path = (s1 > s2? s1 : s2)+1; - } - else if(s1) - path = s1 + 1; - else if(s2) - path = s2 + 1; - - return path; -} -#endif - -static char *strippath(const char *fullfile) -{ - char *filename; - char *base; - filename = strdup(fullfile); /* duplicate since basename() may ruin the - buffer it works on */ - if(!filename) - return NULL; - base = strdup(basename(filename)); - - free(filename); /* free temporary buffer */ - - return base; /* returns an allocated string or NULL ! */ -} - -static CURLcode formdata_add_filename(const struct curl_httppost *file, - struct FormData **form, - curl_off_t *size) -{ - CURLcode result = CURLE_OK; - char *filename = file->showfilename; - char *filebasename = NULL; - char *filename_escaped = NULL; - - if(!filename) { - filebasename = strippath(file->contents); - if(!filebasename) - return CURLE_OUT_OF_MEMORY; - filename = filebasename; - } - - if(strchr(filename, '\\') || strchr(filename, '"')) { - char *p0, *p1; - - /* filename need be escaped */ - filename_escaped = malloc(strlen(filename)*2+1); - if(!filename_escaped) { - free(filebasename); - return CURLE_OUT_OF_MEMORY; - } - p0 = filename_escaped; - p1 = filename; - while(*p1) { - if(*p1 == '\\' || *p1 == '"') - *p0++ = '\\'; - *p0++ = *p1++; - } - *p0 = '\0'; - filename = filename_escaped; - } - result = AddFormDataf(form, size, - "; filename=\"%s\"", - filename); - free(filename_escaped); - free(filebasename); - return result; + if(!name || !len) + return curl_mime_name(part, name); + zname = malloc(len + 1); + if(!zname) + return CURLE_OUT_OF_MEMORY; + memcpy(zname, name, len); + zname[len] = '\0'; + res = curl_mime_name(part, zname); + free(zname); + return res; } /* - * Curl_getformdata() converts a linked list of "meta data" into a complete - * (possibly huge) multipart formdata. The input list is in 'post', while the - * output resulting linked lists gets stored in '*finalform'. *sizep will get - * the total size of the whole POST. - * A multipart/form_data content-type is built, unless a custom content-type - * is passed in 'custom_content_type'. + * Curl_getformdata() converts a linked list of "meta data" into a mime + * structure. The input list is in 'post', while the output is stored in + * mime part at '*finalform'. * * This function will not do a failf() for the potential memory failures but * should for all other errors it spots. Just note that this function MAY get @@ -1150,422 +854,123 @@ static CURLcode formdata_add_filename(const struct curl_httppost *file, */ CURLcode Curl_getformdata(struct Curl_easy *data, - struct FormData **finalform, + curl_mimepart *finalform, struct curl_httppost *post, - const char *custom_content_type, - curl_off_t *sizep) + curl_read_callback fread_func) { - struct FormData *form = NULL; - struct FormData *firstform; - struct curl_httppost *file; CURLcode result = CURLE_OK; - curl_off_t size = 0; /* support potentially ENORMOUS formposts */ - char fileboundary[42]; - struct curl_slist *curList; - char boundary[42]; + curl_mime *form = NULL; + curl_mime *multipart; + curl_mimepart *part; + struct curl_httppost *file; - *finalform = NULL; /* default form is empty */ + Curl_mime_cleanpart(finalform); /* default form is empty */ if(!post) return result; /* no input => no output! */ - result = formboundary(data, boundary, sizeof(boundary)); - if(result) - return result; - - /* Make the first line of the output */ - result = AddFormDataf(&form, NULL, - "%s; boundary=%s\r\n", - custom_content_type?custom_content_type: - "Content-Type: multipart/form-data", - boundary); - - if(result) { - return result; - } - /* we DO NOT include that line in the total size of the POST, since it'll be - part of the header! */ - - firstform = form; - - do { - - if(size) { - result = AddFormDataf(&form, &size, "\r\n"); - if(result) - break; - } - - /* boundary */ - result = AddFormDataf(&form, &size, "--%s\r\n", boundary); - if(result) - break; - - /* Maybe later this should be disabled when a custom_content_type is - passed, since Content-Disposition is not meaningful for all multipart - types. - */ - result = AddFormDataf(&form, &size, - "Content-Disposition: form-data; name=\""); - if(result) - break; - - result = AddFormData(&form, FORM_DATA, post->name, post->namelength, - &size); - if(result) - break; + form = curl_mime_init(data); + if(!form) + result = CURLE_OUT_OF_MEMORY; - result = AddFormDataf(&form, &size, "\""); - if(result) - break; + if(!result) + result = curl_mime_subparts(finalform, form); + /* Process each top part. */ + for(; !result && post; post = post->next) { + /* If we have more than a file here, create a mime subpart and fill it. */ + multipart = form; if(post->more) { - /* If used, this is a link to more file names, we must then do - the magic to include several files with the same field name */ - - result = formboundary(data, fileboundary, sizeof(fileboundary)); - if(result) { - break; + part = curl_mime_addpart(form); + if(!part) + result = CURLE_OUT_OF_MEMORY; + if(!result) + result = setname(part, post->name, post->namelength); + if(!result) { + multipart = curl_mime_init(data); + if(!multipart) + result = CURLE_OUT_OF_MEMORY; } - - result = AddFormDataf(&form, &size, - "\r\nContent-Type: multipart/mixed;" - " boundary=%s\r\n", - fileboundary); - if(result) - break; + if(!result) + result = curl_mime_subparts(part, multipart); } - file = post; - - do { - - /* If 'showfilename' is set, that is a faked name passed on to us - to use to in the formpost. If that is not set, the actually used - local file name should be added. */ - - if(post->more) { - /* if multiple-file */ - result = AddFormDataf(&form, &size, - "\r\n--%s\r\nContent-Disposition: " - "attachment", - fileboundary); - if(result) - break; - result = formdata_add_filename(file, &form, &size); - if(result) - break; - } - else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER| - HTTPPOST_CALLBACK)) { - /* it should be noted that for the HTTPPOST_FILENAME and - HTTPPOST_CALLBACK cases the ->showfilename struct member is always - assigned at this point */ - if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) { - result = formdata_add_filename(post, &form, &size); - } + /* Generate all the part contents. */ + for(file = post; !result && file; file = file->more) { + /* Create the part. */ + part = curl_mime_addpart(multipart); + if(!part) + result = CURLE_OUT_OF_MEMORY; - if(result) - break; - } + /* Set the headers. */ + if(!result) + result = curl_mime_headers(part, file->contentheader, 0); - if(file->contenttype) { - /* we have a specified type */ - result = AddFormDataf(&form, &size, - "\r\nContent-Type: %s", - file->contenttype); - if(result) - break; - } + /* Set the content type. */ + if(!result &&file->contenttype) + result = curl_mime_type(part, file->contenttype); - curList = file->contentheader; - while(curList) { - /* Process the additional headers specified for this form */ - result = AddFormDataf(&form, &size, "\r\n%s", curList->data); - if(result) - break; - curList = curList->next; - } - if(result) - break; + /* Set field name. */ + if(!result && !post->more) + result = setname(part, post->name, post->namelength); - result = AddFormDataf(&form, &size, "\r\n\r\n"); - if(result) - break; + /* Process contents. */ + if(!result) { + curl_off_t clen = post->contentslength; - if((post->flags & HTTPPOST_FILENAME) || - (post->flags & HTTPPOST_READFILE)) { - /* we should include the contents from the specified file */ - FILE *fileread; - - fileread = !strcmp("-", file->contents)? - stdin:fopen(file->contents, "rb"); /* binary read for win32 */ - - /* - * VMS: This only allows for stream files on VMS. Stream files are - * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC, - * every record needs to have a \n appended & 1 added to SIZE - */ - - if(fileread) { - if(fileread != stdin) { - /* close the file */ - fclose(fileread); - /* add the file name only - for later reading from this */ - result = AddFormData(&form, FORM_FILE, file->contents, 0, &size); - } - else { - /* When uploading from stdin, we can't know the size of the file, - * thus must read the full file as before. We *could* use chunked - * transfer-encoding, but that only works for HTTP 1.1 and we - * can't be sure we work with such a server. - */ - size_t nread; - char buffer[512]; - while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) { - result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size); - if(result || feof(fileread) || ferror(fileread)) - break; - } + if(post->flags & CURL_HTTPPOST_LARGE) + clen = post->contentlen; + if(!clen) + clen = -1; + + if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) { + if(!strcmp(file->contents, "-")) { + /* There are a few cases where the code below won't work; in + particular, freopen(stdin) by the caller is not guaranteed + to result as expected. This feature has been kept for backward + compatibility: use of "-" pseudo file name should be avoided. */ + result = curl_mime_data_cb(part, (curl_off_t) -1, + (curl_read_callback) fread, + (curl_seek_callback) fseek, + NULL, (void *) stdin); } + else + result = curl_mime_filedata(part, file->contents); + if(!result && (post->flags & HTTPPOST_READFILE)) + result = curl_mime_filename(part, NULL); } + else if(post->flags & HTTPPOST_BUFFER) + result = curl_mime_data(part, post->buffer, + post->bufferlength? post->bufferlength: -1); + else if(post->flags & HTTPPOST_CALLBACK) + /* the contents should be read with the callback and the size is set + with the contentslength */ + result = curl_mime_data_cb(part, clen, + fread_func, NULL, NULL, post->userp); else { - if(data) - failf(data, "couldn't open file \"%s\"", file->contents); - *finalform = NULL; - result = CURLE_READ_ERROR; + result = curl_mime_data(part, post->contents, (ssize_t) clen); +#ifdef CURL_DOES_CONVERSIONS + /* Convert textual contents now. */ + if(!result && data && part->datasize) + result = Curl_convert_to_network(data, part->data, part->datasize); +#endif } } - else if(post->flags & HTTPPOST_BUFFER) - /* include contents of buffer */ - result = AddFormData(&form, FORM_CONTENT, post->buffer, - post->bufferlength, &size); - else if(post->flags & HTTPPOST_CALLBACK) - /* the contents should be read with the callback and the size is set - with the contentslength */ - result = AddFormData(&form, FORM_CALLBACK, post->userp, - post->flags&CURL_HTTPPOST_LARGE? - post->contentlen:post->contentslength, &size); - else - /* include the contents we got */ - result = AddFormData(&form, FORM_CONTENT, post->contents, - post->flags&CURL_HTTPPOST_LARGE? - post->contentlen:post->contentslength, &size); - file = file->more; - } while(file && !result); /* for each specified file for this field */ - - if(result) - break; - if(post->more) { - /* this was a multiple-file inclusion, make a termination file - boundary: */ - result = AddFormDataf(&form, &size, - "\r\n--%s--", - fileboundary); - if(result) - break; + /* Set fake file name. */ + if(!result && post->showfilename) + if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER | + HTTPPOST_CALLBACK))) + result = curl_mime_filename(part, post->showfilename); } - post = post->next; - } while(post); /* for each field */ - - /* end-boundary for everything */ - if(!result) - result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary); - - if(result) { - Curl_formclean(&firstform); - return result; } - *sizep = size; - *finalform = firstform; + if(result) + Curl_mime_cleanpart(finalform); return result; } -/* - * Curl_FormInit() inits the struct 'form' points to with the 'formdata' - * and resets the 'sent' counter. - */ -int Curl_FormInit(struct Form *form, struct FormData *formdata) -{ - if(!formdata) - return 1; /* error */ - - form->data = formdata; - form->sent = 0; - form->fp = NULL; - form->fread_func = ZERO_NULL; - - return 0; -} - -#ifndef __VMS -# define fopen_read fopen -#else - /* - * vmsfopenread - * - * For upload to work as expected on VMS, different optional - * parameters must be added to the fopen command based on - * record format of the file. - * - */ -# define fopen_read vmsfopenread -static FILE * vmsfopenread(const char *file, const char *mode) -{ - struct_stat statbuf; - int result; - - result = stat(file, &statbuf); - - switch(statbuf.st_fab_rfm) { - case FAB$C_VAR: - case FAB$C_VFC: - case FAB$C_STMCR: - return fopen(file, FOPEN_READTEXT); /* VMS */ - break; - default: - return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); - } -} -#endif - -/* - * readfromfile() - * - * The read callback that this function may use can return a value larger than - * 'size' (which then this function returns) that indicates a problem and it - * must be properly dealt with - */ -static size_t readfromfile(struct Form *form, char *buffer, - size_t size) -{ - size_t nread; - bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE; - - if(callback) { - if(form->fread_func == ZERO_NULL) - return 0; - nread = form->fread_func(buffer, 1, size, form->data->line); - } - else { - if(!form->fp) { - /* this file hasn't yet been opened */ - form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */ - if(!form->fp) - return (size_t)-1; /* failure */ - } - nread = fread(buffer, 1, size, form->fp); - } - if(!nread) { - /* this is the last chunk from the file, move on */ - if(form->fp) { - fclose(form->fp); - form->fp = NULL; - } - form->data = form->data->next; - } - - return nread; -} - -/* - * Curl_FormReader() is the fread() emulation function that will be used to - * deliver the formdata to the transfer loop and then sent away to the peer. - */ -size_t Curl_FormReader(char *buffer, - size_t size, - size_t nitems, - FILE *mydata) -{ - struct Form *form; - size_t wantedsize; - size_t gotsize = 0; - - form=(struct Form *)mydata; - - wantedsize = size * nitems; - - if(!form->data) - return 0; /* nothing, error, empty */ - - if((form->data->type == FORM_FILE) || - (form->data->type == FORM_CALLBACK)) { - gotsize = readfromfile(form, buffer, wantedsize); - - if(gotsize) - /* If positive or -1, return. If zero, continue! */ - return gotsize; - } - do { - - if((form->data->length - form->sent) > wantedsize - gotsize) { - - memcpy(buffer + gotsize, form->data->line + form->sent, - wantedsize - gotsize); - - form->sent += wantedsize-gotsize; - - return wantedsize; - } - - memcpy(buffer+gotsize, - form->data->line + form->sent, - (form->data->length - form->sent) ); - gotsize += form->data->length - form->sent; - - form->sent = 0; - - form->data = form->data->next; /* advance */ - - } while(form->data && (form->data->type < FORM_CALLBACK)); - /* If we got an empty line and we have more data, we proceed to the next - line immediately to avoid returning zero before we've reached the end. */ - - return gotsize; -} - -/* - * Curl_formpostheader() returns the first line of the formpost, the - * request-header part (which is not part of the request-body like the rest of - * the post). - */ -char *Curl_formpostheader(void *formp, size_t *len) -{ - char *header; - struct Form *form=(struct Form *)formp; - - if(!form->data) - return NULL; /* nothing, ERROR! */ - - header = form->data->line; - *len = form->data->length; - - form->data = form->data->next; /* advance */ - - return header; -} - -/* - * formboundary() creates a suitable boundary string and returns an allocated - * one. - */ -static CURLcode formboundary(struct Curl_easy *data, - char *buffer, size_t buflen) -{ - /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615) - combinations */ - if(buflen < 41) - return CURLE_BAD_FUNCTION_ARGUMENT; - - memset(buffer, '-', 24); - Curl_rand_hex(data, (unsigned char *)&buffer[24], 17); - - return CURLE_OK; -} - #else /* CURL_DISABLE_HTTP */ CURLFORMcode curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, diff --git a/lib/formdata.h b/lib/formdata.h index 69629f6..1246c2b 100644 --- a/lib/formdata.h +++ b/lib/formdata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,32 +22,6 @@ * ***************************************************************************/ -enum formtype { - FORM_DATAMEM, /* already allocated FORM_DATA memory */ - FORM_DATA, /* form metadata (convert to network encoding if necessary) */ - FORM_CONTENT, /* form content (never convert) */ - FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback - */ - FORM_FILE /* 'line' points to a file name we should read from - to create the form data (never convert) */ -}; - -/* plain and simple linked list with lines to send */ -struct FormData { - struct FormData *next; - enum formtype type; - char *line; - size_t length; -}; - -struct Form { - struct FormData *data; /* current form line to send */ - size_t sent; /* number of bytes of the current line that has - already been sent in a previous invoke */ - FILE *fp; /* file to read from */ - curl_read_callback fread_func; /* fread callback pointer */ -}; - /* used by FormAdd for temporary storage */ typedef struct FormInfo { char *name; @@ -69,31 +43,9 @@ typedef struct FormInfo { struct FormInfo *more; } FormInfo; -int Curl_FormInit(struct Form *form, struct FormData *formdata); - CURLcode Curl_getformdata(struct Curl_easy *data, - struct FormData **, + curl_mimepart *, struct curl_httppost *post, - const char *custom_contenttype, - curl_off_t *size); - -/* fread() emulation */ -size_t Curl_FormReader(char *buffer, - size_t size, - size_t nitems, - FILE *mydata); - -/* - * Curl_formpostheader() returns the first line of the formpost, the - * request-header part (which is not part of the request-body like the rest of - * the post). - */ -char *Curl_formpostheader(void *formp, size_t *len); - -char *Curl_FormBoundary(void); - -void Curl_formclean(struct FormData **); - -CURLcode Curl_formconvert(struct Curl_easy *, struct FormData *); + curl_read_callback fread_func); #endif /* HEADER_CURL_FORMDATA_H */ diff --git a/lib/ftp.c b/lib/ftp.c index 5edec37..54ba405 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -178,10 +178,11 @@ const struct Curl_handler Curl_handler_ftp = { ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_FTP, /* defport */ CURLPROTO_FTP, /* protocol */ - PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD - | PROTOPT_NOURLQUERY /* flags */ + PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD | + PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP /* flags */ }; @@ -205,6 +206,7 @@ const struct Curl_handler Curl_handler_ftps = { ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_FTPS, /* defport */ CURLPROTO_FTPS, /* protocol */ PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION | @@ -212,59 +214,6 @@ const struct Curl_handler Curl_handler_ftps = { }; #endif -#ifndef CURL_DISABLE_HTTP -/* - * HTTP-proxyed FTP protocol handler. - */ - -static const struct Curl_handler Curl_handler_ftp_proxy = { - "FTP", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_FTP, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; - - -#ifdef USE_SSL -/* - * HTTP-proxyed FTPS protocol handler. - */ - -static const struct Curl_handler Curl_handler_ftps_proxy = { - "FTPS", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_FTPS, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; -#endif -#endif - static void close_secondarysocket(struct connectdata *conn) { if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { @@ -272,7 +221,6 @@ static void close_secondarysocket(struct connectdata *conn) conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; } conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; - conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT; } /* @@ -291,9 +239,9 @@ static void freedirs(struct ftp_conn *ftpc) { int i; if(ftpc->dirs) { - for(i=0; i < ftpc->dirdepth; i++) { + for(i = 0; i < ftpc->dirdepth; i++) { free(ftpc->dirs[i]); - ftpc->dirs[i]=NULL; + ftpc->dirs[i] = NULL; } free(ftpc->dirs); ftpc->dirs = NULL; @@ -340,7 +288,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn) if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { size = sizeof(add); - s=accept(sock, (struct sockaddr *) &add, &size); + s = accept(sock, (struct sockaddr *) &add, &size); } Curl_closesocket(conn, sock); /* close the first socket */ @@ -388,7 +336,7 @@ static time_t ftp_timeleft_accept(struct Curl_easy *data) { time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT; time_t other; - struct timeval now; + struct curltime now; if(data->set.accepttimeout > 0) timeout_ms = data->set.accepttimeout; @@ -509,7 +457,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn) } if(conn->proto.ftpc.state_saved == FTP_STOR) { - *(ftp->bytecountp)=0; + *(ftp->bytecountp) = 0; /* When we know we're uploading a specified file, we can get the file size prior to the actual upload. */ @@ -644,7 +592,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd, #endif /* store the latest code for later retrieval */ - data->info.httpcode=code; + data->info.httpcode = code; if(ftpcode) *ftpcode = code; @@ -692,8 +640,8 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; size_t nread; - int cache_skip=0; - int value_to_be_ignored=0; + int cache_skip = 0; + int value_to_be_ignored = 0; if(ftpcode) *ftpcode = 0; /* 0 for errors */ @@ -701,13 +649,13 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ /* make the pointer point to something for the rest of this function */ ftpcode = &value_to_be_ignored; - *nreadp=0; + *nreadp = 0; while(!*ftpcode && !result) { /* check and reset timeout value every lap */ timeout = Curl_pp_state_timeout(pp); - if(timeout <=0) { + if(timeout <= 0) { failf(data, "FTP response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } @@ -765,7 +713,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ else /* when we got data or there is no cache left, we reset the cache skip counter */ - cache_skip=0; + cache_skip = 0; *nreadp += nread; @@ -900,7 +848,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, int i; /* PORT is used to tell the server to connect to us, and during that we don't do happy eyeballs, but we do if we connect to the server */ - for(s=1, i=0; i<2; i++) { + for(s = 1, i = 0; i<2; i++) { if(conn->tempsock[i] != CURL_SOCKET_BAD) { socks[s] = conn->tempsock[i]; bits |= GETSOCK_WRITESOCK(s++); @@ -937,23 +885,26 @@ static CURLcode ftp_state_cwd(struct connectdata *conn) /* count3 is set to allow a MKD to fail once. In the case when first CWD fails and then MKD fails (due to another session raced it to create the dir) this then allows for a second try to CWD to it */ - ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0; + ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0; - if(conn->bits.reuse && ftpc->entrypath) { + if((conn->data->set.ftp_filemethod == FTPFILE_NOCWD) && !ftpc->cwdcount) + /* No CWD necessary */ + result = ftp_state_mdtm(conn); + else if(conn->bits.reuse && ftpc->entrypath) { /* This is a re-used connection. Since we change directory to where the transfer is taking place, we must first get back to the original dir where we ended up after login: */ - ftpc->count1 = 0; /* we count this as the first path, then we add one - for all upcoming ones in the ftp->dirs[] array */ + ftpc->cwdcount = 0; /* we count this as the first path, then we add one + for all upcoming ones in the ftp->dirs[] array */ PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath); state(conn, FTP_CWD); } else { if(ftpc->dirdepth) { - ftpc->count1 = 1; + ftpc->cwdcount = 1; /* issue the first CWD, the rest is sent when the CWD responses are received... */ - PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]); + PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]); state(conn, FTP_CWD); } else { @@ -977,15 +928,15 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, { CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; - struct Curl_easy *data=conn->data; - curl_socket_t portsock= CURL_SOCKET_BAD; + struct Curl_easy *data = conn->data; + curl_socket_t portsock = CURL_SOCKET_BAD; char myhost[256] = ""; struct Curl_sockaddr_storage ss; Curl_addrinfo *res, *ai; curl_socklen_t sslen; char hbuf[NI_MAXHOST]; - struct sockaddr *sa=(struct sockaddr *)&ss; + struct sockaddr *sa = (struct sockaddr *)&ss; struct sockaddr_in * const sa4 = (void *)sa; #ifdef ENABLE_IPV6 struct sockaddr_in6 * const sa6 = (void *)sa; @@ -996,7 +947,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, int error; char *host = NULL; char *string_ftpport = data->set.str[STRING_FTPPORT]; - struct Curl_dns_entry *h=NULL; + struct Curl_dns_entry *h = NULL; unsigned short port_min = 0; unsigned short port_max = 0; unsigned short port; @@ -1024,7 +975,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, char *port_start = NULL; char *port_sep = NULL; - addr = calloc(addrlen+1, 1); + addr = calloc(addrlen + 1, 1); if(!addr) return CURLE_OUT_OF_MEMORY; @@ -1067,7 +1018,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(ip_end != NULL) { port_start = strchr(ip_end, ':'); if(port_start) { - port_min = curlx_ultous(strtoul(port_start+1, NULL, 10)); + port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10)); port_sep = strchr(port_start, '-'); if(port_sep) { port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10)); @@ -1311,7 +1262,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* translate x.x.x.x to x,x,x,x */ while(source && *source) { if(*source == '.') - *dest=','; + *dest = ','; else *dest = *source; dest++; @@ -1518,12 +1469,12 @@ static CURLcode ftp_state_list(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; /* Check if path does not end with /, as then we cut off the file part */ - if(lstArg[strlen(lstArg) - 1] != '/') { + if(lstArg[strlen(lstArg) - 1] != '/') { /* chop off the file part if format is dir/dir/file */ slashPos = strrchr(lstArg, '/'); if(slashPos) - *(slashPos+1) = '\0'; + *(slashPos + 1) = '\0'; } } @@ -1671,7 +1622,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, } if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed=0; + curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_FTP_COULDNT_USE_REST; @@ -1733,7 +1684,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn, struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; - bool quote=FALSE; + bool quote = FALSE; struct curl_slist *item; switch(instate) { @@ -1870,11 +1821,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, { struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result; - struct Curl_easy *data=conn->data; - struct Curl_dns_entry *addr=NULL; + struct Curl_easy *data = conn->data; + struct Curl_dns_entry *addr = NULL; int rc; unsigned short connectport; /* the local port connect() should use! */ - char *str=&data->state.buffer[4]; /* start on the first letter */ + char *str = &data->state.buffer[4]; /* start on the first letter */ /* if we come here again, make sure the former name is cleared */ Curl_safefree(ftpc->newhost); @@ -1898,9 +1849,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, /* The four separators should be identical, or else this is an oddly formatted reply and we bail out immediately. */ - for(i=1; i<4; i++) { + for(i = 1; i<4; i++) { if(separator[i] != sep1) { - ptr=NULL; /* set to NULL to signal error */ + ptr = NULL; /* set to NULL to signal error */ break; } } @@ -1916,7 +1867,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, } } else - ptr=NULL; + ptr = NULL; } if(!ptr) { failf(data, "Weirdly formatted EPSV reply"); @@ -2090,7 +2041,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, int ftpcode) { CURLcode result = CURLE_OK; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -2104,7 +2055,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, &year, &month, &day, &hour, &minute, &second)) { /* we have a time, reformat it */ char timebuf[24]; - time_t secs=time(NULL); + time_t secs = time(NULL); snprintf(timebuf, sizeof(timebuf), "%04d%02d%02d %02d:%02d:%02d GMT", @@ -2120,7 +2071,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, if(data->set.opt_no_body && ftpc->file && data->set.get_filetime && - (data->info.filetime>=0) ) { + (data->info.filetime >= 0) ) { char headerbuf[128]; time_t filetime = (time_t)data->info.filetime; struct tm buffer; @@ -2196,7 +2147,7 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; if(ftpcode/100 != 2) { /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a @@ -2225,7 +2176,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize) { CURLcode result = CURLE_OK; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -2308,12 +2259,14 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct Curl_easy *data=conn->data; - curl_off_t filesize; + struct Curl_easy *data = conn->data; + curl_off_t filesize = -1; char *buf = data->state.buffer; /* get the size from the ascii string: */ - filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1; + if(ftpcode == 213) + /* ignores parsing errors, which will make the size remain unknown */ + (void)curlx_strtoofft(buf + 4, NULL, 0, &filesize); if(instate == FTP_SIZE) { #ifdef CURL_FTP_HTTPSTYLE_HEAD @@ -2383,7 +2336,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn, CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; - if(ftpcode>=400) { + if(ftpcode >= 400) { failf(data, "Failed FTP upload: %0d", ftpcode); state(conn, FTP_STOP); /* oops, we never close the sockets! */ @@ -2441,7 +2394,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, E: 125 Data connection already open; Transfer starting. */ - curl_off_t size=-1; /* default unknown size */ + curl_off_t size = -1; /* default unknown size */ /* @@ -2465,9 +2418,9 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, * Example D above makes this parsing a little tricky */ char *bytes; char *buf = data->state.buffer; - bytes=strstr(buf, " bytes"); + bytes = strstr(buf, " bytes"); if(bytes--) { - long in=(long)(bytes-buf); + long in = (long)(bytes-buf); /* this is a hint there is size information in there! ;-) */ while(--in) { /* scan for the left parenthesis and break there */ @@ -2475,7 +2428,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, break; /* skip only digits */ if(!ISDIGIT(*bytes)) { - bytes=NULL; + bytes = NULL; break; } /* one more estep backwards */ @@ -2484,7 +2437,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, /* if we have nothing but digits: */ if(bytes++) { /* get the number! */ - size = curlx_strtoofft(bytes, NULL, 0); + (void)curlx_strtoofft(bytes, NULL, 0, &size); } } } @@ -2647,7 +2600,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) { CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; int ftpcode; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; @@ -2699,7 +2652,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* We don't have a SSL/TLS connection yet, but FTPS is requested. Try a FTPS connection now */ - ftpc->count3=0; + ftpc->count3 = 0; switch(data->set.ftpsslauth) { case CURLFTPAUTH_DEFAULT: case CURLFTPAUTH_SSL: @@ -2822,10 +2775,11 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_PWD: if(ftpcode == 257) { - char *ptr=&data->state.buffer[4]; /* start on the first letter */ + char *ptr = &data->state.buffer[4]; /* start on the first letter */ const size_t buf_size = data->set.buffer_size; char *dir; char *store; + bool entry_extracted = FALSE; dir = malloc(nread + 1); if(!dir) @@ -2857,7 +2811,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) } else { /* end of path */ - *store = '\0'; /* zero terminate */ + entry_extracted = TRUE; break; /* get out of this loop */ } } @@ -2866,7 +2820,9 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) store++; ptr++; } - + *store = '\0'; /* zero terminate */ + } + if(entry_extracted) { /* If the path name does not look like an absolute path (i.e.: it does not start with a '/'), we probably need some server-dependent adjustments. For example, this is the case when connecting to @@ -2913,7 +2869,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_SYST: if(ftpcode == 215) { - char *ptr=&data->state.buffer[4]; /* start on the first letter */ + char *ptr = &data->state.buffer[4]; /* start on the first letter */ char *os; char *store; @@ -2988,10 +2944,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(ftpcode/100 != 2) { /* failure to CWD there */ if(conn->data->set.ftp_create_missing_dirs && - ftpc->count1 && !ftpc->count2) { + ftpc->cwdcount && !ftpc->count2) { /* try making it */ ftpc->count2++; /* counter to prevent CWD-MKD loops */ - PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]); + PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]); state(conn, FTP_MKD); } else { @@ -3004,10 +2960,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) } else { /* success */ - ftpc->count2=0; - if(++ftpc->count1 <= ftpc->dirdepth) { + ftpc->count2 = 0; + if(++ftpc->cwdcount <= ftpc->dirdepth) { /* send next CWD */ - PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); + PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]); } else { result = ftp_state_mdtm(conn); @@ -3025,7 +2981,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) } state(conn, FTP_CWD); /* send CWD */ - PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); + PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]); break; case FTP_MDTM: @@ -3244,15 +3200,16 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */ size_t dlen = strlen(path)-flen; if(!ftpc->cwdfail) { + ftpc->prevmethod = data->set.ftp_filemethod; if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) { ftpc->prevpath = path; if(flen) /* if 'path' is not the whole string */ - ftpc->prevpath[dlen]=0; /* terminate */ + ftpc->prevpath[dlen] = 0; /* terminate */ } else { /* we never changed dir */ - ftpc->prevpath=strdup(""); + ftpc->prevpath = strdup(""); free(path); } if(ftpc->prevpath) @@ -3515,35 +3472,36 @@ static CURLcode ftp_range(struct connectdata *conn) { curl_off_t from, to; char *ptr; - char *ptr2; struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; if(data->state.use_range && data->state.range) { - from=curlx_strtoofft(data->state.range, &ptr, 0); - while(*ptr && (ISSPACE(*ptr) || (*ptr=='-'))) + CURLofft from_t; + CURLofft to_t; + from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); + if(from_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) ptr++; - to=curlx_strtoofft(ptr, &ptr2, 0); - if(ptr == ptr2) { - /* we didn't get any digit */ - to=-1; - } - if((-1 == to) && (from>=0)) { + to_t = curlx_strtoofft(ptr, NULL, 0, &to); + if(to_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + if((to_t == CURL_OFFT_INVAL) && !from_t) { /* X - */ data->state.resume_from = from; DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n", from)); } - else if(from < 0) { + else if(!to_t && (from_t == CURL_OFFT_INVAL)) { /* -Y */ - data->req.maxdownload = -from; - data->state.resume_from = from; + data->req.maxdownload = to; + data->state.resume_from = -to; DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T - " bytes\n", -from)); + " bytes\n", to)); } else { /* X-Y */ - data->req.maxdownload = (to-from)+1; /* include last byte */ + data->req.maxdownload = (to - from) + 1; /* include last byte */ data->state.resume_from = from; DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", @@ -3574,7 +3532,7 @@ static CURLcode ftp_range(struct connectdata *conn) static CURLcode ftp_do_more(struct connectdata *conn, int *completep) { - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = CURLE_OK; bool connected = FALSE; @@ -3585,7 +3543,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) /* if the second connection isn't done yet, wait for it */ if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { - if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) { + if(Curl_connect_ongoing(conn)) { /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port aren't used so we blank their arguments. TODO: make this nicer */ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0); @@ -3617,7 +3575,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) return result; if(conn->bits.tunnel_proxy && conn->bits.httpproxy && - conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) + Curl_connect_ongoing(conn)) return result; @@ -3741,7 +3699,7 @@ CURLcode ftp_perform(struct connectdata *conn, bool *dophase_done) { /* this is FTP and no proxy */ - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -4034,7 +3992,7 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd) #define SBUF_SIZE 1024 char s[SBUF_SIZE]; size_t write_len; - char *sptr=s; + char *sptr = s; CURLcode result = CURLE_OK; #ifdef HAVE_GSSAPI enum protection_level data_sec = conn->data_prot; @@ -4045,9 +4003,8 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd) return CURLE_BAD_FUNCTION_ARGUMENT; strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ - write_len +=2; - - bytes_written=0; + write_len += 2; + bytes_written = 0; result = Curl_convert_to_network(conn->data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ @@ -4125,7 +4082,7 @@ static CURLcode ftp_quit(struct connectdata *conn) */ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) { - struct ftp_conn *ftpc= &conn->proto.ftpc; + struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; /* We cannot send quit unconditionally. If this connection is stale or @@ -4221,7 +4178,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) ftpc->dirdepth = 0; break; } - slash_pos=strrchr(cur_pos, '/'); + slash_pos = strrchr(cur_pos, '/'); if(slash_pos || !*cur_pos) { size_t dirlen = slash_pos-cur_pos; CURLcode result; @@ -4242,7 +4199,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) return result; } ftpc->dirdepth = 1; /* we consider it to be a single dir */ - filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */ + filename = slash_pos ? slash_pos + 1 : cur_pos; /* rest is file name */ } else filename = cur_pos; /* this is a file name only */ @@ -4326,8 +4283,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) } } else - ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL - pointer */ + ftpc->file = NULL; /* instead of point to a zero byte, we make it a NULL + pointer */ if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { /* We need a file name when uploading. Return error! */ @@ -4351,7 +4308,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) dlen -= ftpc->file?strlen(ftpc->file):0; if((dlen == strlen(ftpc->prevpath)) && - !strncmp(path, ftpc->prevpath, dlen)) { + !strncmp(path, ftpc->prevpath, dlen) && + (ftpc->prevmethod == data->set.ftp_filemethod)) { infof(data, "Request has same path as previous transfer\n"); ftpc->cwddone = TRUE; } @@ -4422,8 +4380,8 @@ static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *dophase_done) { - CURLcode result=CURLE_OK; - bool connected=FALSE; + CURLcode result = CURLE_OK; + bool connected = FALSE; struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; data->req.size = -1; /* make sure this is unknown at this point */ @@ -4463,28 +4421,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn) char command; struct FTP *ftp; - if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel ftp operations through the proxy, we - switch and use HTTP operations only */ -#ifndef CURL_DISABLE_HTTP - if(conn->handler == &Curl_handler_ftp) - conn->handler = &Curl_handler_ftp_proxy; - else { -#ifdef USE_SSL - conn->handler = &Curl_handler_ftps_proxy; -#else - failf(data, "FTPS not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - /* set it up as a HTTP connection instead */ - return conn->handler->setup_connection(conn); -#else - failf(data, "FTP over http proxy requires HTTP support built-in!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - conn->data->req.protop = ftp = malloc(sizeof(struct FTP)); if(NULL == ftp) return CURLE_OUT_OF_MEMORY; diff --git a/lib/ftp.h b/lib/ftp.h index 3bbf262..e4aa63f 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -130,10 +130,12 @@ struct ftp_conn { should be FALSE when it gets to Curl_ftp_quit() */ bool cwddone; /* if it has been determined that the proper CWD combo already has been done */ + int cwdcount; /* number of CWD commands issued */ bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent caching the current directory */ bool wait_data_conn; /* this is set TRUE if data connection is waited */ char *prevpath; /* conn->path from the previous transfer */ + curl_ftpfile prevmethod; /* ftp method in previous transfer */ char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a and others (A/I or zero) */ int count1; /* general purpose counter for the state machine */ diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index 2acce31..b2a8c0f 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -421,7 +421,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, else if(c == '\n') { finfo->b_data[parser->item_length - 1] = 0; if(strncmp("total ", finfo->b_data, 6) == 0) { - char *endptr = finfo->b_data+6; + char *endptr = finfo->b_data + 6; /* here we can deal with directory size, pass the leading white spaces and then the digits */ while(ISSPACE(*endptr)) @@ -609,16 +609,18 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, char *p; curl_off_t fsize; finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; - fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10); - if(p[0] == '\0' && fsize != CURL_OFF_T_MAX && - fsize != CURL_OFF_T_MIN) { - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; - parser->file_data->info.size = fsize; + if(!curlx_strtoofft(finfo->b_data + parser->item_offset, + &p, 10, &fsize)) { + if(p[0] == '\0' && fsize != CURL_OFF_T_MAX && + fsize != CURL_OFF_T_MIN) { + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; + parser->file_data->info.size = fsize; + } + parser->item_length = 0; + parser->item_offset = 0; + parser->state.UNIX.main = PL_UNIX_TIME; + parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; } - parser->item_length = 0; - parser->item_offset = 0; - parser->state.UNIX.main = PL_UNIX_TIME; - parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; } else if(!ISDIGIT(c)) { PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); @@ -935,19 +937,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } else { char *endptr; - finfo->size = curlx_strtoofft(finfo->b_data + - parser->item_offset, - &endptr, 10); - if(!*endptr) { - if(finfo->size == CURL_OFF_T_MAX || - finfo->size == CURL_OFF_T_MIN) { - if(errno == ERANGE) { - PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); - return bufflen; - } - } - } - else { + if(curlx_strtoofft(finfo->b_data + + parser->item_offset, + &endptr, 10, &finfo->size)) { PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); return bufflen; } diff --git a/lib/getinfo.c b/lib/getinfo.c index a1ce505..862ced0 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -54,6 +54,7 @@ CURLcode Curl_initinfo(struct Curl_easy *data) pro->t_starttransfer = 0; pro->timespent = 0; pro->t_redirect = 0; + pro->is_t_startransfer_set = false; info->httpcode = 0; info->httpproxycode = 0; @@ -246,27 +247,60 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, return CURLE_OK; } +#define DOUBLE_SECS(x) (double)(x)/1000000 + +static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, + curl_off_t *param_offt) +{ + switch(info) { + case CURLINFO_SIZE_UPLOAD_T: + *param_offt = data->progress.uploaded; + break; + case CURLINFO_SIZE_DOWNLOAD_T: + *param_offt = data->progress.downloaded; + break; + case CURLINFO_SPEED_DOWNLOAD_T: + *param_offt = data->progress.dlspeed; + break; + case CURLINFO_SPEED_UPLOAD_T: + *param_offt = data->progress.ulspeed; + break; + case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T: + *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)? + data->progress.size_dl:-1; + break; + case CURLINFO_CONTENT_LENGTH_UPLOAD_T: + *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? + data->progress.size_ul:-1; + break; + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, double *param_doublep) { switch(info) { case CURLINFO_TOTAL_TIME: - *param_doublep = data->progress.timespent; + *param_doublep = DOUBLE_SECS(data->progress.timespent); break; case CURLINFO_NAMELOOKUP_TIME: - *param_doublep = data->progress.t_nslookup; + *param_doublep = DOUBLE_SECS(data->progress.t_nslookup); break; case CURLINFO_CONNECT_TIME: - *param_doublep = data->progress.t_connect; + *param_doublep = DOUBLE_SECS(data->progress.t_connect); break; case CURLINFO_APPCONNECT_TIME: - *param_doublep = data->progress.t_appconnect; + *param_doublep = DOUBLE_SECS(data->progress.t_appconnect); break; case CURLINFO_PRETRANSFER_TIME: - *param_doublep = data->progress.t_pretransfer; + *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer); break; case CURLINFO_STARTTRANSFER_TIME: - *param_doublep = data->progress.t_starttransfer; + *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer); break; case CURLINFO_SIZE_UPLOAD: *param_doublep = (double)data->progress.uploaded; @@ -289,7 +323,7 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, (double)data->progress.size_ul:-1; break; case CURLINFO_REDIRECT_TIME: - *param_doublep = data->progress.t_redirect; + *param_doublep = DOUBLE_SECS(data->progress.t_redirect); break; default: @@ -326,46 +360,25 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info, struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **) param_slistp; struct curl_tlssessioninfo *tsi = &data->tsi; +#ifdef USE_SSL struct connectdata *conn = data->easy_conn; +#endif *tsip = tsi; tsi->backend = Curl_ssl_backend(); tsi->internals = NULL; +#ifdef USE_SSL if(conn && tsi->backend != CURLSSLBACKEND_NONE) { unsigned int i; for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) { if(conn->ssl[i].use) { -#if defined(USE_AXTLS) - tsi->internals = (void *)conn->ssl[i].ssl; -#elif defined(USE_CYASSL) - tsi->internals = (void *)conn->ssl[i].handle; -#elif defined(USE_DARWINSSL) - tsi->internals = (void *)conn->ssl[i].ssl_ctx; -#elif defined(USE_GNUTLS) - tsi->internals = (void *)conn->ssl[i].session; -#elif defined(USE_GSKIT) - tsi->internals = (void *)conn->ssl[i].handle; -#elif defined(USE_MBEDTLS) - tsi->internals = (void *)&conn->ssl[i].ssl; -#elif defined(USE_NSS) - tsi->internals = (void *)conn->ssl[i].handle; -#elif defined(USE_OPENSSL) - /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ - tsi->internals = ((info == CURLINFO_TLS_SESSION) ? - (void *)conn->ssl[i].ctx : - (void *)conn->ssl[i].handle); -#elif defined(USE_POLARSSL) - tsi->internals = (void *)&conn->ssl[i].ssl; -#elif defined(USE_SCHANNEL) - tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle; -#elif defined(USE_SSL) -#error "SSL backend specific information missing for CURLINFO_TLS_SSL_PTR" -#endif + tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info); break; } } } +#endif } break; default: @@ -394,6 +407,7 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) va_list arg; long *param_longp = NULL; double *param_doublep = NULL; + curl_off_t *param_offt = NULL; const char **param_charp = NULL; struct curl_slist **param_slistp = NULL; curl_socket_t *param_socketp = NULL; @@ -422,6 +436,11 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) if(param_doublep) result = getinfo_double(data, info, param_doublep); break; + case CURLINFO_OFF_T: + param_offt = va_arg(arg, curl_off_t *); + if(param_offt) + result = getinfo_offt(data, info, param_offt); + break; case CURLINFO_SLIST: param_slistp = va_arg(arg, struct curl_slist **); if(param_slistp) diff --git a/lib/gopher.c b/lib/gopher.c index e6d2746..b7c31b6 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -65,6 +65,7 @@ const struct Curl_handler Curl_handler_gopher = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_GOPHER, /* defport */ CURLPROTO_GOPHER, /* protocol */ PROTOPT_NONE /* flags */ @@ -72,8 +73,8 @@ const struct Curl_handler Curl_handler_gopher = { static CURLcode gopher_do(struct connectdata *conn, bool *done) { - CURLcode result=CURLE_OK; - struct Curl_easy *data=conn->data; + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; curl_off_t *bytecount = &data->req.bytecount; @@ -96,11 +97,11 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) /* Otherwise, drop / and the first character (i.e., item type) ... */ newp = path; - newp+=2; + newp += 2; /* ... then turn ? into TAB for search servers, Veronica, etc. ... */ j = strlen(newp); - for(i=0; icurrent_element) { - for(i = iter->slot_index;i < h->slots;i++) { + for(i = iter->slot_index; i < h->slots; i++) { if(h->table[i].head) { iter->current_element = h->table[i].head; - iter->slot_index = i+1; + iter->slot_index = i + 1; break; } } diff --git a/lib/hostcheck.c b/lib/hostcheck.c index 156091c..23dc3d2 100644 --- a/lib/hostcheck.c +++ b/lib/hostcheck.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -73,10 +73,10 @@ static int hostmatch(char *hostname, char *pattern) /* normalize pattern and hostname by stripping off trailing dots */ size_t len = strlen(hostname); if(hostname[len-1]=='.') - hostname[len-1]=0; + hostname[len-1] = 0; len = strlen(pattern); if(pattern[len-1]=='.') - pattern[len-1]=0; + pattern[len-1] = 0; pattern_wildcard = strchr(pattern, '*'); if(pattern_wildcard == NULL) @@ -95,7 +95,7 @@ static int hostmatch(char *hostname, char *pattern) match. */ wildcard_enabled = 1; pattern_label_end = strchr(pattern, '.'); - if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || + if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL || pattern_wildcard > pattern_label_end || strncasecompare(pattern, "xn--", 4)) { wildcard_enabled = 0; @@ -116,9 +116,9 @@ static int hostmatch(char *hostname, char *pattern) return CURL_HOST_NOMATCH; prefixlen = pattern_wildcard - pattern; - suffixlen = pattern_label_end - (pattern_wildcard+1); + suffixlen = pattern_label_end - (pattern_wildcard + 1); return strncasecompare(pattern, hostname, prefixlen) && - strncasecompare(pattern_wildcard+1, hostname_label_end - suffixlen, + strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen, suffixlen) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; } @@ -137,7 +137,7 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) hostp = strdup(hostname); if(hostp) { if(hostmatch(hostp, matchp) == CURL_HOST_MATCH) - res= 1; + res = 1; free(hostp); } free(matchp); diff --git a/lib/hostip.c b/lib/hostip.c index 619ec84..1a18a3e 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -304,9 +304,9 @@ fetch_addr(struct connectdata *conn, entry_len = strlen(entry_id); /* See if its already in our dns cache */ - dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); - if(dns && (data->set.dns_cache_timeout != -1)) { + if(dns && (data->set.dns_cache_timeout != -1)) { /* See whether the returned entry is stale. Done before we release lock */ struct hostcache_prune_data user; @@ -316,7 +316,7 @@ fetch_addr(struct connectdata *conn, if(hostcache_timestamp_remove(&user, dns)) { infof(data, "Hostname in DNS cache was stale, zapped\n"); dns = NULL; /* the memory deallocation is being handled by the hash */ - Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1); + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); } } @@ -403,7 +403,7 @@ Curl_cache_addr(struct Curl_easy *data, dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */ /* Store the resolved data in our DNS cache. */ - dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1, + dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1, (void *)dns); if(!dns2) { free(dns); @@ -807,7 +807,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* delete entry, ignore if it didn't exist */ - Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1); + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -848,7 +848,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* See if its already in our dns cache */ - dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); /* free the allocated entry_id again */ free(entry_id); diff --git a/lib/hostip4.c b/lib/hostip4.c index e459328..6a7c6e5 100644 --- a/lib/hostip4.c +++ b/lib/hostip4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -249,7 +249,7 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, */ if(CURL_HOSTENT_SIZE >= - (sizeof(struct hostent)+sizeof(struct hostent_data))) { + (sizeof(struct hostent) + sizeof(struct hostent_data))) { /* August 22nd, 2000: Albert Chin-A-Young brought an updated version * that should work! September 20: Richard Prescott worked on the buffer diff --git a/lib/hostip6.c b/lib/hostip6.c index 4ebfc2d..edeebec 100644 --- a/lib/hostip6.c +++ b/lib/hostip6.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -212,7 +212,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, if(port) { snprintf(sbuf, sizeof(sbuf), "%d", port); - sbufptr=sbuf; + sbufptr = sbuf; } error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res); diff --git a/lib/http.c b/lib/http.c index 21574e2..38227eb 100644 --- a/lib/http.c +++ b/lib/http.c @@ -50,6 +50,7 @@ #include "transfer.h" #include "sendf.h" #include "formdata.h" +#include "mime.h" #include "progress.h" #include "curl_base64.h" #include "cookie.h" @@ -119,6 +120,7 @@ const struct Curl_handler Curl_handler_http = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ PROTOPT_CREDSPERREQUEST /* flags */ @@ -143,6 +145,7 @@ const struct Curl_handler Curl_handler_https = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_HTTPS, /* defport */ CURLPROTO_HTTPS, /* protocol */ PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */ @@ -160,6 +163,7 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn) if(!http) return CURLE_OUT_OF_MEMORY; + Curl_mime_initpart(&http->form, conn->data); conn->data->req.protop = http; Curl_http2_setup_conn(conn); @@ -168,26 +172,6 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn) return CURLE_OK; } -/* - * checkheaders() checks the linked list of custom HTTP headers for a - * particular header (prefix). - * - * Returns a pointer to the first matching header or NULL if none matched. - */ -char *Curl_checkheaders(const struct connectdata *conn, - const char *thisheader) -{ - struct curl_slist *head; - size_t thislen = strlen(thisheader); - struct Curl_easy *data = conn->data; - - for(head = data->set.headers;head; head=head->next) { - if(strncasecompare(head->data, thisheader, thislen)) - return head->data; - } - - return NULL; -} /* * checkProxyHeaders() checks the linked list of custom proxy headers @@ -207,7 +191,7 @@ char *Curl_checkProxyheaders(const struct connectdata *conn, for(head = (conn->bits.proxy && data->set.sep_headers) ? data->set.proxyheaders : data->set.headers; - head; head=head->next) { + head; head = head->next) { if(strncasecompare(head->data, thisheader, thislen)) return head->data; } @@ -425,6 +409,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) expectsend = data->state.infilesize; break; case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: expectsend = http->postsize; break; default: @@ -608,7 +593,7 @@ output_auth_headers(struct connectdata *conn, #endif #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) if(authstatus->picked == CURLAUTH_NTLM_WB) { - auth="NTLM_WB"; + auth = "NTLM_WB"; result = Curl_output_ntlm_wb(conn, proxy); if(result) return result; @@ -1020,7 +1005,7 @@ static size_t readmoredata(char *buffer, http->sending++; /* move one step up */ - http->backup.postsize=0; + http->backup.postsize = 0; } else http->postsize = 0; @@ -1148,7 +1133,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, /* there was body data sent beyond the initial header part, pass that on to the debug callback too */ Curl_debug(conn->data, CURLINFO_DATA_OUT, - ptr+headlen, bodylen, conn); + ptr + headlen, bodylen, conn); } } @@ -1260,7 +1245,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size) (~(size * 2) < (in->size_used * 2))) new_size = (size_t)-1; else - new_size = (in->size_used+size) * 2; + new_size = (in->size_used + size) * 2; if(in->buffer) /* we have a buffer, enlarge the existing one */ @@ -1337,7 +1322,7 @@ Curl_compareheader(const char *headerline, /* line to check */ clen = strlen(content); /* length of the word to find */ /* find the content string in the rest of the line */ - for(;len>=clen;len--, start++) { + for(; len >= clen; len--, start++) { if(strncasecompare(start, content, clen)) return TRUE; /* match! */ } @@ -1369,7 +1354,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) if(CONNECT_FIRSTSOCKET_PROXY_SSL()) return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */ - if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) + if(Curl_connect_ongoing(conn)) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; @@ -1468,18 +1453,17 @@ CURLcode Curl_http_done(struct connectdata *conn, Curl_http2_done(conn, premature); - if(HTTPREQ_POST_FORM == data->set.httpreq) { - data->req.bytecount = http->readbytecount + http->writebytecount; + Curl_mime_cleanpart(&http->form); - Curl_formclean(&http->sendit); /* Now free that whole lot */ - if(http->form.fp) { - /* a file being uploaded was left opened, close it! */ - fclose(http->form.fp); - http->form.fp = NULL; - } - } - else if(HTTPREQ_PUT == data->set.httpreq) + switch(data->set.httpreq) { + case HTTPREQ_PUT: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: data->req.bytecount = http->readbytecount + http->writebytecount; + break; + default: + break; + } if(status) return status; @@ -1579,7 +1563,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, char *ptr; struct curl_slist *h[2]; struct curl_slist *headers; - int numlists=1; /* by default */ + int numlists = 1; /* by default */ struct Curl_easy *data = conn->data; int i; @@ -1611,7 +1595,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, } /* loop through one or two lists */ - for(i=0; i < numlists; i++) { + for(i = 0; i < numlists; i++) { headers = h[i]; while(headers) { @@ -1635,15 +1619,19 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, /* this header (extended by formdata.c) is sent later */ checkprefix("Content-Type:", headers->data)) ; + else if(data->set.httpreq == HTTPREQ_POST_MIME && + /* this header is sent later */ + checkprefix("Content-Type:", headers->data)) + ; else if(conn->bits.authneg && /* while doing auth neg, don't allow the custom length since we will force length zero then */ - checkprefix("Content-Length", headers->data)) + checkprefix("Content-Length:", headers->data)) ; else if(conn->allocptr.te && /* when asking for Transfer-Encoding, don't pass on a custom Connection: */ - checkprefix("Connection", headers->data)) + checkprefix("Connection:", headers->data)) ; else if((conn->httpversion == 20) && checkprefix("Transfer-Encoding:", headers->data)) @@ -1676,6 +1664,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, *ptr = ':'; result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data); + + /* restore the previous value */ + *ptr = ';'; + if(result) return result; } @@ -1773,7 +1765,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) const char *httpstring; Curl_send_buffer *req_buffer; curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ - int seekerr = CURL_SEEKFUNC_OK; + int seekerr = CURL_SEEKFUNC_CANTSEEK; /* Always consider the DO phase done after this function call, even if there may be parts of the request that is not yet sent, since we can deal with @@ -1846,11 +1838,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) switch(httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: request = "POST"; break; case HTTPREQ_PUT: request = "PUT"; break; + case HTTPREQ_OPTIONS: + request = "OPTIONS"; + break; default: /* this should never happen */ case HTTPREQ_GET: request = "GET"; @@ -1868,7 +1864,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) here. */ if(Curl_checkheaders(conn, "User-Agent:")) { free(conn->allocptr.uagent); - conn->allocptr.uagent=NULL; + conn->allocptr.uagent = NULL; } /* setup the authentication headers */ @@ -1937,6 +1933,48 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif + switch(httpreq) { + case HTTPREQ_POST_MIME: + http->sendit = &data->set.mimepost; + break; + case HTTPREQ_POST_FORM: + /* Convert the form structure into a mime structure. */ + Curl_mime_cleanpart(&http->form); + result = Curl_getformdata(data, &http->form, data->set.httppost, + data->state.fread_func); + if(result) + return result; + http->sendit = &http->form; + break; + default: + http->sendit = NULL; + } + + if(http->sendit) { + const char *cthdr = Curl_checkheaders(conn, "Content-Type:"); + + /* Read and seek body only. */ + http->sendit->flags |= MIME_BODY_ONLY; + + /* Prepare the mime structure headers & set content type. */ + + if(cthdr) + for(cthdr += 13; *cthdr == ' '; cthdr++) + ; + else if(http->sendit->kind == MIMEKIND_MULTIPART) + cthdr = "multipart/form-data"; + + curl_mime_headers(http->sendit, data->set.headers, 0); + result = Curl_mime_prepare_headers(http->sendit, cthdr, + NULL, MIMESTRATEGY_FORM); + curl_mime_headers(http->sendit, NULL, 0); + if(!result) + result = Curl_mime_rewind(http->sendit); + if(result) + return result; + http->postsize = Curl_mime_size(http->sendit); + } + ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); if(ptr) { /* Some kind of TE is requested, check if 'chunked' is chosen */ @@ -1944,9 +1982,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); } else { - if((conn->handler->protocol&PROTO_FAMILY_HTTP) && - data->set.upload && - (data->state.infilesize == -1)) { + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && + http->postsize < 0) || + (data->set.upload && data->state.infilesize == -1))) { if(conn->bits.authneg) /* don't enable chunked during auth neg */ ; @@ -2044,7 +2083,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #ifndef CURL_DISABLE_PROXY - if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* Using a proxy but does not tunnel through it */ /* The path sent to the proxy is in fact the entire URL. But if the remote @@ -2118,21 +2157,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif /* CURL_DISABLE_PROXY */ - if(HTTPREQ_POST_FORM == httpreq) { - /* we must build the whole post sequence first, so that we have a size of - the whole transfer before we start to send it */ - result = Curl_getformdata(data, &http->sendit, data->set.httppost, - Curl_checkheaders(conn, "Content-Type:"), - &http->postsize); - if(result) - return result; - } - http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n"; - if(( (HTTPREQ_POST == httpreq) || - (HTTPREQ_POST_FORM == httpreq) || - (HTTPREQ_PUT == httpreq) ) && + if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) && data->state.resume_from) { /********************************************************************** * Resuming upload in HTTP means that we PUT or POST and that we have @@ -2140,6 +2167,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * a Range: header that will be passed along. We need to "fast forward" * the file the given number of bytes and decrease the assume upload * file size before we continue this venture in the dark lands of HTTP. + * Resuming mime/form posting at an offset > 0 has no sense and is ignored. *********************************************************************/ if(data->state.resume_from < 0) { @@ -2161,7 +2189,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed=0; + curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); @@ -2214,7 +2242,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->state.range); } - else if((httpreq != HTTPREQ_GET) && + 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 */ @@ -2232,7 +2260,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } else if(data->state.resume_from) { /* This is because "resume" was selected */ - curl_off_t total_expected_size= + curl_off_t total_expected_size = data->state.resume_from + data->state.infilesize; conn->allocptr.rangeline = aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T @@ -2266,6 +2294,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(result) return result; + if(data->set.str[STRING_TARGET]) + ppath = data->set.str[STRING_TARGET]; + /* url */ if(paste_ftp_userpwd) result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s", @@ -2339,8 +2370,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) #if !defined(CURL_DISABLE_COOKIES) if(data->cookies || addcookies) { - struct Cookie *co=NULL; /* no cookies from start */ - int count=0; + struct Cookie *co = NULL; /* no cookies from start */ + int count = 0; if(data->cookies) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); @@ -2353,7 +2384,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } if(co) { - struct Cookie *store=co; + struct Cookie *store = co; /* now loop through all cookies that matched */ while(co) { if(co->value) { @@ -2407,117 +2438,79 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) switch(httpreq) { - case HTTPREQ_POST_FORM: - if(!http->sendit || conn->bits.authneg) { - /* nothing to post! */ - result = Curl_add_bufferf(req_buffer, "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); - if(result) - failf(data, "Failed sending POST request"); - else - /* setup variables for the upcoming transfer */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - -1, NULL); - break; - } - - if(Curl_FormInit(&http->form, http->sendit)) { - failf(data, "Internal HTTP POST error!"); - return CURLE_HTTP_POST_ERROR; - } - - /* Get the currently set callback function pointer and store that in the - form struct since we might want the actual user-provided callback later - on. The data->set.fread_func pointer itself will be changed for the - multipart case to the function that returns a multipart formatted - stream. */ - http->form.fread_func = data->state.fread_func; - - /* Set the read function to read from the generated form data */ - data->state.fread_func = (curl_read_callback)Curl_FormReader; - data->state.in = &http->form; + case HTTPREQ_PUT: /* Let's PUT the data to the server! */ - http->sending = HTTPSEND_BODY; + if(conn->bits.authneg) + postsize = 0; + else + postsize = data->state.infilesize; - if(!data->req.upload_chunky && - !Curl_checkheaders(conn, "Content-Length:")) { + 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", http->postsize); + "\r\n", postsize); if(result) return result; } - result = expect100(data, conn, req_buffer); - if(result) - return result; - - { - - /* Get Content-Type: line from Curl_formpostheader. - */ - char *contentType; - size_t linelength=0; - contentType = Curl_formpostheader((void *)&http->form, - &linelength); - if(!contentType) { - failf(data, "Could not get Content-Type header line!"); - return CURLE_HTTP_POST_ERROR; - } - - result = Curl_add_buffer(req_buffer, contentType, linelength); + if(postsize != 0) { + result = expect100(data, conn, req_buffer); if(result) return result; } - /* make the request end in a true CRLF */ - result = Curl_add_buffer(req_buffer, "\r\n", 2); + result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */ if(result) return result; - /* set upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, http->postsize); + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, postsize); - /* fire away the whole request to the server */ + /* this sends the buffer and frees all the buffer resources */ result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size, 0, FIRSTSOCKET); if(result) - failf(data, "Failed sending POST request"); + failf(data, "Failed sending PUT request"); else - /* setup variables for the upcoming transfer */ + /* prepare for transfer */ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, FIRSTSOCKET, - &http->writebytecount); - - if(result) { - Curl_formclean(&http->sendit); /* free that whole lot */ - return result; - } - - /* convert the form data */ - result = Curl_convert_form(data, http->sendit); - if(result) { - Curl_formclean(&http->sendit); /* free that whole lot */ + &http->readbytecount, postsize?FIRSTSOCKET:-1, + postsize?&http->writebytecount:NULL); + if(result) return result; - } - break; - case HTTPREQ_PUT: /* Let's PUT the data to the server! */ + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + /* 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"); + if(result) + return result; - if(conn->bits.authneg) - postsize = 0; - else - postsize = data->state.infilesize; + result = Curl_add_buffer_send(req_buffer, conn, + &data->info.request_size, 0, FIRSTSOCKET); + if(result) + failf(data, "Failed sending POST request"); + else + /* setup variables for the upcoming transfer */ + Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, + -1, NULL); + break; + } - if((postsize != -1) && !data->req.upload_chunky && + postsize = http->postsize; + + /* We only set Content-Length and allow a custom Content-Length if + we don't upload data chunked, as RFC2616 forbids us to set both + kinds of headers (Transfer-Encoding: chunked and Content-Length) */ + if(postsize != -1 && !data->req.upload_chunky && (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { - /* only add Content-Length if not uploading chunked */ + /* 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); @@ -2525,24 +2518,52 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - if(postsize != 0) { + /* Output mime-generated headers. */ + { + struct curl_slist *hdr; + + for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) { + result = Curl_add_bufferf(req_buffer, "%s\r\n", hdr->data); + if(result) + return result; + } + } + + /* For really small posts we don't use Expect: headers at all, and for + the somewhat bigger ones we allow the app to disable it. Just make + sure that the expect100header is always set to the preferred value + here. */ + ptr = Curl_checkheaders(conn, "Expect:"); + if(ptr) { + data->state.expect100header = + Curl_compareheader(ptr, "Expect:", "100-continue"); + } + else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { result = expect100(data, conn, req_buffer); if(result) return result; } + else + data->state.expect100header = FALSE; - result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */ + /* make the request end in a true CRLF */ + result = Curl_add_buffer(req_buffer, "\r\n", 2); if(result) return result; /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, postsize); + /* Read from mime structure. */ + data->state.fread_func = (curl_read_callback) Curl_mime_read; + data->state.in = (void *) http->sendit; + 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); if(result) - failf(data, "Failed sending PUT request"); + failf(data, "Failed sending POST request"); else /* prepare for transfer */ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, @@ -2550,6 +2571,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize?&http->writebytecount:NULL); if(result) return result; + break; case HTTPREQ_POST: @@ -2592,7 +2614,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); } - else if(postsize > TINY_INITIAL_POST_SIZE || postsize < 0) { + else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { result = expect100(data, conn, req_buffer); if(result) return result; @@ -2606,7 +2628,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) its size. */ if(conn->httpversion != 20 && !data->state.expect100header && - (postsize < MAX_INITIAL_POST_SIZE)) { + (postsize < MAX_INITIAL_POST_SIZE)) { /* if we don't use expect: 100 AND postsize is less than MAX_INITIAL_POST_SIZE @@ -2771,7 +2793,7 @@ checkhttpprefix(struct Curl_easy *data, failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } - if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { + if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { /* Curl_convert_from_network calls failf if unsuccessful */ free(scratch); return FALSE; /* can't return CURLE_foobar so return FALSE */ @@ -2801,6 +2823,7 @@ static bool checkrtspprefix(struct Curl_easy *data, const char *s) { + bool result = FALSE; #ifdef CURL_DOES_CONVERSIONS /* convert from the network encoding using a scratch area */ @@ -2809,18 +2832,19 @@ checkrtspprefix(struct Curl_easy *data, failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } - if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { + if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { /* Curl_convert_from_network calls failf if unsuccessful */ - free(scratch); - return FALSE; /* can't return CURLE_foobar so return FALSE */ + result = FALSE; /* can't return CURLE_foobar so return FALSE */ } - s = scratch; + else + result = checkprefix("RTSP/", scratch)? TRUE: FALSE; + free(scratch); #else (void)data; /* unused */ + result = checkprefix("RTSP/", s)? TRUE: FALSE; #endif /* CURL_DOES_CONVERSIONS */ - if(checkprefix("RTSP/", s)) - return TRUE; - return FALSE; + + return result; } #endif /* CURL_DISABLE_RTSP */ @@ -2862,14 +2886,14 @@ static CURLcode header_append(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - newsize=CURLMAX((k->hbuflen+ length)*3/2, data->state.headersize*2); + 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.headersize = newsize; data->state.headerbuff = newbuff; k->hbufp = data->state.headerbuff + hbufp_index; } @@ -2962,7 +2986,7 @@ 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 = (k->end_ptr - k->str) + 1; *nread -= (ssize_t)rest_length; k->str = k->end_ptr + 1; /* move past new line */ @@ -3161,6 +3185,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, case HTTPREQ_PUT: case HTTPREQ_POST: case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: /* We got an error response. If this happened before the whole * request body has been sent we stop sending and mark the * connection for closure after we've read the entire response. @@ -3288,7 +3313,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #define HEADER1 scratch #define SCRATCHSIZE 21 CURLcode res; - char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */ + 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, @@ -3314,19 +3339,22 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * says. We try to allow any number here, but we cannot make * guarantees on future behaviors since it isn't within the protocol. */ + char separator; nc = sscanf(HEADER1, - " HTTP/%d.%d %d", + " HTTP/%1d.%1d%c%3d", &httpversion_major, &conn->httpversion, + &separator, &k->httpcode); if(nc == 1 && httpversion_major == 2 && 1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) { conn->httpversion = 0; - nc = 3; + nc = 4; + separator = ' '; } - if(nc==3) { + if((nc == 4) && (' ' == separator)) { conn->httpversion += 10 * httpversion_major; if(k->upgr101 == UPGR101_RECEIVED) { @@ -3335,11 +3363,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, infof(data, "Lying server, not serving HTTP/2\n"); } } - else { + else if(!nc) { /* this is the real world, not a Nirvana NCSA 1.5.x returns this crap when asked for HTTP/1.1 */ - nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); + nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode); conn->httpversion = 10; /* If user has set option HTTP200ALIASES, @@ -3353,6 +3381,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } } + else { + failf(data, "Unsupported HTTP version in response\n"); + return CURLE_UNSUPPORTED_PROTOCOL; + } } else if(conn->handler->protocol & CURLPROTO_RTSP) { nc = sscanf(HEADER1, @@ -3360,7 +3392,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, &rtspversion_major, &conn->rtspversion, &k->httpcode); - if(nc==3) { + if(nc == 3) { conn->rtspversion += 10 * rtspversion_major; conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */ } @@ -3392,7 +3424,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) { if(data->state.resume_from && - (data->set.httpreq==HTTPREQ_GET) && + (data->set.httpreq == HTTPREQ_GET) && (k->httpcode == 416)) { /* "Requested Range Not Satisfiable", just proceed and pretend this is no error */ @@ -3448,8 +3480,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * fields. */ if(data->set.timecondition) data->info.timecond = TRUE; - k->size=0; - k->maxdownload=0; + k->size = 0; + k->maxdownload = 0; k->ignorecl = TRUE; /* ignore Content-Length headers */ break; default: @@ -3471,28 +3503,32 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* Check for Content-Length: header lines to get size */ if(!k->ignorecl && !data->set.ignorecl && checkprefix("Content-Length:", k->p)) { - curl_off_t contentlength = curlx_strtoofft(k->p+15, NULL, 10); - if(data->set.max_filesize && - contentlength > data->set.max_filesize) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } - if(contentlength >= 0) { - k->size = contentlength; - k->maxdownload = k->size; - /* we set the progress download size already at this point - just to make it easier for apps/callbacks to extract this - info as soon as possible */ - Curl_pgrsSetDownloadSize(data, k->size); - } - else { - /* Negative Content-Length is really odd, and we know it - happens for example when older Apache servers send large - files */ - streamclose(conn, "negative content-length"); - infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T - ", closing after transfer\n", contentlength); + curl_off_t contentlength; + if(!curlx_strtoofft(k->p + 15, NULL, 10, &contentlength)) { + if(data->set.max_filesize && + contentlength > data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + if(contentlength >= 0) { + k->size = contentlength; + k->maxdownload = k->size; + /* we set the progress download size already at this point + just to make it easier for apps/callbacks to extract this + info as soon as possible */ + Curl_pgrsSetDownloadSize(data, k->size); + } + else { + /* Negative Content-Length is really odd, and we know it + happens for example when older Apache servers send large + files */ + streamclose(conn, "negative content-length"); + infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T + ", closing after transfer\n", contentlength); + } } + else + infof(data, "Illegal Content-Length: header\n"); } /* check for Content-Type: header lines to get the MIME-type */ else if(checkprefix("Content-Type:", k->p)) { @@ -3667,11 +3703,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* if it truly stopped on a digit */ if(ISDIGIT(*ptr)) { - k->offset = curlx_strtoofft(ptr, NULL, 10); - - if(data->state.resume_from == k->offset) - /* we asked for a resume and we got it */ - k->content_range = TRUE; + if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) { + if(data->state.resume_from == k->offset) + /* we asked for a resume and we got it */ + k->content_range = TRUE; + } } else data->state.resume_from = 0; /* get everything */ @@ -3682,7 +3718,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_add(data, - data->cookies, TRUE, k->p+11, + data->cookies, TRUE, k->p + 11, /* If there is a custom-set Host: name, use it here, or else use real peer host name. */ conn->allocptr.cookiehost? @@ -3693,8 +3729,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #endif else if(checkprefix("Last-Modified:", k->p) && (data->set.timecondition || data->set.get_filetime) ) { - time_t secs=time(NULL); - k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"), + time_t secs = time(NULL); + k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"), &secs); if(data->set.get_filetime) data->info.filetime = (long)k->timeofdoc; diff --git a/lib/http.h b/lib/http.h index 7ce4bd9..d2781bc 100644 --- a/lib/http.h +++ b/lib/http.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,8 +40,6 @@ bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ const char *content); /* content string to find */ -char *Curl_checkheaders(const struct connectdata *conn, - const char *thisheader); char *Curl_copy_header_value(const char *header); char *Curl_checkProxyheaders(const struct connectdata *conn, @@ -115,8 +113,13 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn); #define MAX_INITIAL_POST_SIZE (64*1024) #endif -#ifndef TINY_INITIAL_POST_SIZE -#define TINY_INITIAL_POST_SIZE 1024 +/* EXPECT_100_THRESHOLD is the request body size limit for when libcurl will + * automatically add an "Expect: 100-continue" header in HTTP requests. When + * the size is unknown, it will always add it. + * + */ +#ifndef EXPECT_100_THRESHOLD +#define EXPECT_100_THRESHOLD 1024 #endif #endif /* CURL_DISABLE_HTTP */ @@ -125,7 +128,7 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn); * HTTP unique setup ***************************************************************************/ struct HTTP { - struct FormData *sendit; + curl_mimepart *sendit; curl_off_t postsize; /* off_t to handle large file sizes */ const char *postdata; @@ -135,7 +138,7 @@ struct HTTP { curl_off_t writebytecount; /* For FORM posting */ - struct Form form; + curl_mimepart form; struct back { curl_read_callback fread_func; /* backup storage for fread pointer */ diff --git a/lib/http2.c b/lib/http2.c index f8e23c5..9a2a1dd 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -28,6 +28,7 @@ #include "http2.h" #include "http.h" #include "sendf.h" +#include "select.h" #include "curl_base64.h" #include "strcase.h" #include "multiif.h" @@ -151,6 +152,49 @@ static CURLcode http2_disconnect(struct connectdata *conn, return CURLE_OK; } +/* + * The server may send us data at any point (e.g. PING frames). Therefore, + * we cannot assume that an HTTP/2 socket is dead just because it is readable. + * + * Instead, if it is readable, run Curl_connalive() to peek at the socket + * and distinguish between closed and data. + */ +static bool http2_connisdead(struct connectdata *check) +{ + int sval; + bool ret_val = TRUE; + + sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0); + if(sval == 0) { + /* timeout */ + ret_val = FALSE; + } + else if(sval & CURL_CSELECT_ERR) { + /* socket is in an error state */ + ret_val = TRUE; + } + else if(sval & CURL_CSELECT_IN) { + /* readable with no error. could still be closed */ + ret_val = !Curl_connalive(check); + } + + return ret_val; +} + + +static unsigned int http2_conncheck(struct connectdata *check, + unsigned int checks_to_perform) +{ + unsigned int ret_val = CONNRESULT_NONE; + + if(checks_to_perform & CONNCHECK_ISDEAD) { + if(http2_connisdead(check)) + ret_val |= CONNRESULT_DEAD; + } + + return ret_val; +} + /* called from Curl_http_setup_conn */ void Curl_http2_setup_req(struct Curl_easy *data) { @@ -196,6 +240,7 @@ static const struct Curl_handler Curl_handler_http2 = { http2_perform_getsock, /* perform_getsock */ http2_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + http2_conncheck, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ PROTOPT_STREAM /* flags */ @@ -216,6 +261,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = { http2_perform_getsock, /* perform_getsock */ http2_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + http2_conncheck, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTPS, /* protocol */ PROTOPT_SSL | PROTOPT_STREAM /* flags */ @@ -338,12 +384,12 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) struct HTTP *stream = h->data->req.protop; size_t len = strlen(header); size_t i; - for(i=0; ipush_headers_used; i++) { + for(i = 0; ipush_headers_used; i++) { if(!strncmp(header, stream->push_headers[i], len)) { /* sub-match, make sure that it is followed by a colon */ if(stream->push_headers[i][len] != ':') continue; - return &stream->push_headers[i][len+1]; + return &stream->push_headers[i][len + 1]; } } } @@ -418,7 +464,7 @@ static int push_promise(struct Curl_easy *data, data->multi->push_userp); /* free the headers again */ - for(i=0; ipush_headers_used; i++) + for(i = 0; ipush_headers_used; i++) free(stream->push_headers[i]); free(stream->push_headers); stream->push_headers = NULL; @@ -1536,7 +1582,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, failf(data, "nghttp2_session_mem_recv() returned %d:%s\n", rv, nghttp2_strerror((int)rv)); *err = CURLE_RECV_ERROR; - return 0; + return -1; } DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv)); if(nread == rv) { @@ -1554,7 +1600,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, rv = h2_session_send(data, httpc->h2); if(rv != 0) { *err = CURLE_SEND_ERROR; - return 0; + return -1; } if(should_close_session(httpc)) { @@ -1909,6 +1955,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, switch(conn->data->set.httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: case HTTPREQ_PUT: if(conn->data->state.infilesize != -1) stream->upload_left = conn->data->state.infilesize; @@ -2134,12 +2181,15 @@ CURLcode Curl_http2_switched(struct connectdata *conn, return CURLE_OK; } -void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child, - bool exclusive) +CURLcode Curl_http2_add_child(struct Curl_easy *parent, + struct Curl_easy *child, + bool exclusive) { if(parent) { struct Curl_http2_dep **tail; struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep)); + if(!dep) + return CURLE_OUT_OF_MEMORY; dep->data = child; if(parent->set.stream_dependents && exclusive) { @@ -2170,6 +2220,7 @@ void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child, child->set.stream_depends_on = parent; child->set.stream_depends_e = exclusive; + return CURLE_OK; } void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child) diff --git a/lib/http2.h b/lib/http2.h index f405b3a..f597c80 100644 --- a/lib/http2.h +++ b/lib/http2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -53,8 +53,9 @@ void Curl_http2_setup_conn(struct connectdata *conn); void Curl_http2_setup_req(struct Curl_easy *data); void Curl_http2_done(struct connectdata *conn, bool premature); CURLcode Curl_http2_done_sending(struct connectdata *conn); -void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child, - bool exclusive); +CURLcode Curl_http2_add_child(struct Curl_easy *parent, + struct Curl_easy *child, + bool exclusive); void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child); void Curl_http2_cleanup_dependencies(struct Curl_easy *data); diff --git a/lib/http_chunks.c b/lib/http_chunks.c index 1bdf697..92d7731 100644 --- a/lib/http_chunks.c +++ b/lib/http_chunks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -86,8 +86,8 @@ static bool Curl_isxdigit(char digit) void Curl_httpchunk_init(struct connectdata *conn) { struct Curl_chunker *chunk = &conn->chunk; - chunk->hexindex=0; /* start at 0 */ - chunk->dataleft=0; /* no data left yet! */ + chunk->hexindex = 0; /* start at 0 */ + chunk->dataleft = 0; /* no data left yet! */ chunk->state = CHUNK_HEX; /* we get hex first! */ } @@ -107,7 +107,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, ssize_t datalen, ssize_t *wrotep) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct Curl_chunker *ch = &conn->chunk; struct SingleRequest *k = &data->req; @@ -147,7 +147,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, return CHUNKE_ILLEGAL_HEX; /* length and datap are unmodified */ - ch->hexbuffer[ch->hexindex]=0; + ch->hexbuffer[ch->hexindex] = 0; /* convert to host encoding before calling strtoul */ result = Curl_convert_from_network(conn->data, ch->hexbuffer, @@ -158,9 +158,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, return CHUNKE_ILLEGAL_HEX; } - ch->datasize=curlx_strtoofft(ch->hexbuffer, &endptr, 16); - if((ch->datasize == CURL_OFF_T_MAX) && (errno == ERANGE)) - /* overflow is an error */ + if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize)) return CHUNKE_ILLEGAL_HEX; ch->state = CHUNK_LF; /* now wait for the CRLF */ } @@ -172,7 +170,7 @@ 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; + conn->trlPos = 0; } else ch->state = CHUNK_DATA; @@ -259,9 +257,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, 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; + conn->trailer[conn->trlPos++] = 0x0d; + conn->trailer[conn->trlPos++] = 0x0a; + conn->trailer[conn->trlPos] = 0; /* Convert to host encoding before calling Curl_client_write */ result = Curl_convert_from_network(conn->data, conn->trailer, @@ -277,7 +275,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, if(result) return CHUNKE_WRITE_ERROR; } - conn->trlPos=0; + conn->trlPos = 0; ch->state = CHUNK_TRAILER_CR; if(*datap == 0x0a) /* already on the LF */ @@ -301,7 +299,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, ptr = realloc(conn->trailer, conn->trlMax + 3); } else { - conn->trlMax=128; + conn->trlMax = 128; ptr = malloc(conn->trlMax + 3); } if(!ptr) diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index 8a78bd2..0f1edcf 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,11 +37,14 @@ #include "sendf.h" #include "strcase.h" #include "http_ntlm.h" +#include "curl_ntlm_core.h" #include "curl_ntlm_wb.h" #include "vauth/vauth.h" #include "url.h" -#if defined(USE_NSS) +/* SSL backend-specific #if branches in this file must be kept in the order + documented in curl_ntlm_core. */ +#if defined(NTLM_NEEDS_NSS_INIT) #include "vtls/nssg.h" #elif defined(USE_WINDOWS_SSPI) #include "curl_sspi.h" @@ -129,7 +132,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) DEBUGASSERT(conn); DEBUGASSERT(conn->data); -#ifdef USE_NSS +#if defined(NTLM_NEEDS_NSS_INIT) if(CURLE_OK != Curl_nss_force_init(conn->data)) return CURLE_OUT_OF_MEMORY; #endif @@ -170,8 +173,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ - result = Curl_auth_create_ntlm_type1_message(userp, passwdp, ntlm, &base64, - &len); + result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp, + ntlm, &base64, &len); if(result) return result; diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 9894e2e..dff9d23 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -22,11 +22,11 @@ #include "curl_setup.h" +#include "http_proxy.h" + #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) -#include "urldata.h" #include -#include "http_proxy.h" #include "sendf.h" #include "http.h" #include "url.h" @@ -135,35 +135,73 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) return CURLE_OK; } -#define CONNECT_BUFFER_SIZE 16384 +bool Curl_connect_complete(struct connectdata *conn) +{ + return !conn->connect_state || + (conn->connect_state->tunnel_state == TUNNEL_COMPLETE); +} + +bool Curl_connect_ongoing(struct connectdata *conn) +{ + return conn->connect_state && + (conn->connect_state->tunnel_state != TUNNEL_COMPLETE); +} + +static CURLcode connect_init(struct connectdata *conn, bool reinit) +{ + struct http_connect_state *s; + if(!reinit) { + DEBUGASSERT(!conn->connect_state); + s = calloc(1, sizeof(struct http_connect_state)); + if(!s) + return CURLE_OUT_OF_MEMORY; + infof(conn->data, "allocate connect buffer!\n"); + conn->connect_state = s; + } + else { + DEBUGASSERT(conn->connect_state); + s = conn->connect_state; + } + s->tunnel_state = TUNNEL_INIT; + s->keepon = TRUE; + s->line_start = s->connect_buffer; + s->ptr = s->line_start; + s->cl = 0; + return CURLE_OK; +} + +static void connect_done(struct connectdata *conn) +{ + struct http_connect_state *s = conn->connect_state; + s->tunnel_state = TUNNEL_COMPLETE; + infof(conn->data, "CONNECT phase completed!\n"); +} static CURLcode CONNECT(struct connectdata *conn, int sockindex, const char *hostname, int remote_port) { - int subversion=0; - struct Curl_easy *data=conn->data; + int subversion = 0; + struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; CURLcode result; curl_socket_t tunnelsocket = conn->sock[sockindex]; - curl_off_t cl=0; bool closeConnection = FALSE; - bool chunked_encoding = FALSE; time_t check; + struct http_connect_state *s = conn->connect_state; #define SELECT_OK 0 #define SELECT_ERROR 1 #define SELECT_TIMEOUT 2 - int error = SELECT_OK; - if(conn->tunnel_state[sockindex] == TUNNEL_COMPLETE) + if(Curl_connect_complete(conn)) return CURLE_OK; /* CONNECT is already completed */ conn->bits.proxy_connect_closed = FALSE; do { - if(TUNNEL_INIT == conn->tunnel_state[sockindex]) { + if(TUNNEL_INIT == s->tunnel_state) { /* BEGIN CONNECT PHASE */ char *host_port; Curl_send_buffer *req_buffer; @@ -196,8 +234,8 @@ static CURLcode CONNECT(struct connectdata *conn, if(!result) { char *host = NULL; - const char *proxyconn=""; - const char *useragent=""; + const char *proxyconn = ""; + const char *useragent = ""; const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; bool ipv6_ip = conn->bits.ipv6_ip; @@ -206,7 +244,7 @@ static CURLcode CONNECT(struct connectdata *conn, /* the hostname may be different */ if(hostname != conn->host.name) ipv6_ip = (strchr(hostname, ':') != NULL); - hostheader= /* host:port with IPv6 support */ + hostheader = /* host:port with IPv6 support */ aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", remote_port); if(!hostheader) { @@ -271,65 +309,46 @@ static CURLcode CONNECT(struct connectdata *conn, if(result) return result; - conn->tunnel_state[sockindex] = TUNNEL_CONNECT; + s->tunnel_state = TUNNEL_CONNECT; + s->perline = 0; } /* END CONNECT PHASE */ check = Curl_timeleft(data, NULL, TRUE); if(check <= 0) { failf(data, "Proxy CONNECT aborted due to timeout"); - return CURLE_RECV_ERROR; + return CURLE_OPERATION_TIMEDOUT; } if(!Curl_conn_data_pending(conn, sockindex)) /* return so we'll be called again polling-style */ return CURLE_OK; - DEBUGF(infof(data, "Read response immediately from proxy CONNECT\n")); /* at this point, the tunnel_connecting phase is over. */ { /* READING RESPONSE PHASE */ - size_t nread; /* total size read */ - int perline; /* count bytes per line */ - int keepon=TRUE; - ssize_t gotbytes; - char *ptr; - char *line_start; + int error = SELECT_OK; - ptr = conn->connect_buffer; - line_start = ptr; + while(s->keepon && !error) { + ssize_t gotbytes; - nread = 0; - perline = 0; - - while(nread < (size_t)CONNECT_BUFFER_SIZE && keepon && !error) { - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - - if(ptr >= &conn->connect_buffer[CONNECT_BUFFER_SIZE]) { + /* 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; } - check = Curl_timeleft(data, NULL, TRUE); - if(check <= 0) { - failf(data, "Proxy CONNECT aborted due to timeout"); - error = SELECT_TIMEOUT; /* already too little time */ - break; - } - /* 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, ptr, 1, &gotbytes); - if(result == CURLE_AGAIN) { - if(SOCKET_READABLE(tunnelsocket, check<1000L?check:1000) == -1) { - error = SELECT_ERROR; - failf(data, "Proxy CONNECT aborted due to select/poll error"); - break; - } - continue; - } + result = Curl_read(conn, tunnelsocket, s->ptr, 1, &gotbytes); + if(result == CURLE_AGAIN) + /* socket buffer drained, return */ + return CURLE_OK; + + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + if(result) { - keepon = FALSE; + s->keepon = FALSE; break; } else if(gotbytes <= 0) { @@ -343,24 +362,22 @@ static CURLcode CONNECT(struct connectdata *conn, error = SELECT_ERROR; failf(data, "Proxy CONNECT aborted"); } - keepon = FALSE; + s->keepon = FALSE; break; } - /* We got a byte of data */ - nread++; - if(keepon > TRUE) { + if(s->keepon > TRUE) { /* This means we are currently ignoring a response-body */ - nread = 0; /* make next read start over in the read buffer */ - ptr = conn->connect_buffer; - if(cl) { + 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! */ - cl--; - if(cl <= 0) { - keepon = FALSE; + s->cl--; + if(s->cl <= 0) { + s->keepon = FALSE; + s->tunnel_state = TUNNEL_COMPLETE; break; } } @@ -372,28 +389,29 @@ 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, ptr, 1, &tookcareof); + r = Curl_httpchunk_read(conn, s->ptr, 1, &tookcareof); if(r == CHUNKE_STOP) { /* we're done reading chunks! */ infof(data, "chunk reading DONE\n"); - keepon = FALSE; + s->keepon = FALSE; /* we did the full CONNECT treatment, go COMPLETE */ - conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + s->tunnel_state = TUNNEL_COMPLETE; } } continue; } - perline++; /* amount of bytes in this line so far */ + s->perline++; /* amount of bytes in this line so far */ /* if this is not the end of a header line then continue */ - if(*ptr != 0x0a) { - ptr++; + if(*s->ptr != 0x0a) { + s->ptr++; continue; } /* convert from the network encoding */ - result = Curl_convert_from_network(data, line_start, perline); + result = Curl_convert_from_network(data, s->line_start, + (size_t)s->perline); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) return result; @@ -401,7 +419,7 @@ static CURLcode CONNECT(struct connectdata *conn, /* output debug if that is requested */ if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, - line_start, (size_t)perline, conn); + s->line_start, (size_t)s->perline, conn); if(!data->set.suppress_connect_headers) { /* send the header to the callback */ @@ -409,35 +427,34 @@ static CURLcode CONNECT(struct connectdata *conn, if(data->set.include_header) writetype |= CLIENTWRITE_BODY; - result = Curl_client_write(conn, writetype, line_start, perline); + result = Curl_client_write(conn, writetype, + s->line_start, s->perline); if(result) return result; } - data->info.header_size += (long)perline; - data->req.headerbytecount += (long)perline; + data->info.header_size += (long)s->perline; + data->req.headerbytecount += (long)s->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' == line_start[0]) || - ('\n' == line_start[0])) { + if(('\r' == s->line_start[0]) || + ('\n' == s->line_start[0])) { /* end of response-headers from the proxy */ - nread = 0; /* make next read start over in the read - buffer */ - ptr = conn->connect_buffer; + 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 whole response-body */ - keepon = 2; + s->keepon = 2; - if(cl) { + if(s->cl) { infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T - " bytes of response-body\n", cl); + " bytes of response-body\n", s->cl); } - else if(chunked_encoding) { + else if(s->chunked_encoding) { CHUNKcode r; infof(data, "Ignore chunked response-body\n"); @@ -448,46 +465,46 @@ static CURLcode CONNECT(struct connectdata *conn, function returns! */ k->ignorebody = TRUE; - if(line_start[1] == '\n') { + if(s->line_start[1] == '\n') { /* this can only be a LF if the letter at index 0 was a CR */ - line_start++; + s->line_start++; } /* now parse the chunked piece of data so that we can properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, line_start + 1, 1, &gotbytes); + r = Curl_httpchunk_read(conn, s->line_start + 1, 1, &gotbytes); if(r == CHUNKE_STOP) { /* we're done reading chunks! */ infof(data, "chunk reading DONE\n"); - keepon = FALSE; - /* we did the full CONNECT treatment, go to - COMPLETE */ - conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + s->keepon = FALSE; + /* we did the full CONNECT treatment, go to COMPLETE */ + s->tunnel_state = TUNNEL_COMPLETE; } } else { /* without content-length or chunked encoding, we can't keep the connection alive since the close is the end signal so we bail out at once instead */ - keepon = FALSE; + s->keepon = FALSE; } } else - keepon = FALSE; - /* we did the full CONNECT treatment, go to COMPLETE */ - conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + s->keepon = FALSE; + if(!s->cl) + /* we did the full CONNECT treatment, go to COMPLETE */ + s->tunnel_state = TUNNEL_COMPLETE; continue; } - line_start[perline] = 0; /* zero terminate the buffer */ - if((checkprefix("WWW-Authenticate:", line_start) && + s->line_start[s->perline] = 0; /* zero terminate the buffer */ + if((checkprefix("WWW-Authenticate:", s->line_start) && (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", line_start) && + (checkprefix("Proxy-authenticate:", s->line_start) && (407 == k->httpcode))) { bool proxy = (k->httpcode == 407) ? TRUE : FALSE; - char *auth = Curl_copy_header_value(line_start); + char *auth = Curl_copy_header_value(s->line_start); if(!auth) return CURLE_OUT_OF_MEMORY; @@ -498,7 +515,7 @@ static CURLcode CONNECT(struct connectdata *conn, if(result) return result; } - else if(checkprefix("Content-Length:", line_start)) { + else if(checkprefix("Content-Length:", s->line_start)) { if(k->httpcode/100 == 2) { /* A client MUST ignore any Content-Length or Transfer-Encoding header fields received in a successful response to CONNECT. @@ -507,13 +524,13 @@ static CURLcode CONNECT(struct connectdata *conn, k->httpcode); } else { - cl = curlx_strtoofft(line_start + - strlen("Content-Length:"), NULL, 10); + (void)curlx_strtoofft(s->line_start + + strlen("Content-Length:"), NULL, 10, &s->cl); } } - else if(Curl_compareheader(line_start, "Connection:", "close")) + else if(Curl_compareheader(s->line_start, "Connection:", "close")) closeConnection = TRUE; - else if(checkprefix("Transfer-Encoding:", line_start)) { + else if(checkprefix("Transfer-Encoding:", s->line_start)) { if(k->httpcode/100 == 2) { /* A client MUST ignore any Content-Length or Transfer-Encoding header fields received in a successful response to CONNECT. @@ -521,26 +538,27 @@ static CURLcode CONNECT(struct connectdata *conn, infof(data, "Ignoring Transfer-Encoding in " "CONNECT %03d response\n", k->httpcode); } - else if(Curl_compareheader(line_start, + else if(Curl_compareheader(s->line_start, "Transfer-Encoding:", "chunked")) { infof(data, "CONNECT responded chunked\n"); - chunked_encoding = TRUE; + s->chunked_encoding = TRUE; /* init our chunky engine */ Curl_httpchunk_init(conn); } } - else if(Curl_compareheader(line_start, "Proxy-Connection:", "close")) + else if(Curl_compareheader(s->line_start, + "Proxy-Connection:", "close")) closeConnection = TRUE; - else if(2 == sscanf(line_start, "HTTP/1.%d %d", + else if(2 == sscanf(s->line_start, "HTTP/1.%d %d", &subversion, &k->httpcode)) { /* store the HTTP code from the proxy */ data->info.httpproxycode = k->httpcode; } - perline = 0; /* line starts over here */ - ptr = conn->connect_buffer; - line_start = ptr; + s->perline = 0; /* line starts over here */ + s->ptr = s->connect_buffer; + s->line_start = s->ptr; } /* while there's buffer left and loop is requested */ if(Curl_pgrsUpdate(conn)) @@ -549,7 +567,7 @@ static CURLcode CONNECT(struct connectdata *conn, if(error) return CURLE_RECV_ERROR; - if(data->info.httpproxycode != 200) { + if(data->info.httpproxycode/100 != 2) { /* Deal with the possibly already received authenticate headers. 'newurl' is set to a new URL if we must loop. */ result = Curl_http_auth_act(conn); @@ -574,19 +592,17 @@ static CURLcode CONNECT(struct connectdata *conn, /* If we are supposed to continue and request a new URL, which basically * means the HTTP authentication is still going on so if the tunnel * is complete we start over in INIT state */ - if(data->req.newurl && - (TUNNEL_COMPLETE == conn->tunnel_state[sockindex])) { - conn->tunnel_state[sockindex] = TUNNEL_INIT; - infof(data, "TUNNEL_STATE switched to: %d\n", - conn->tunnel_state[sockindex]); + if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) { + connect_init(conn, TRUE); /* reinit */ } } while(data->req.newurl); - if(200 != data->req.httpcode) { + if(data->info.httpproxycode/100 != 2) { if(closeConnection && data->req.newurl) { conn->bits.proxy_connect_closed = TRUE; infof(data, "Connect me again please\n"); + connect_done(conn); } else { free(data->req.newurl); @@ -598,7 +614,7 @@ static CURLcode CONNECT(struct connectdata *conn, } /* to back to init state */ - conn->tunnel_state[sockindex] = TUNNEL_INIT; + s->tunnel_state = TUNNEL_INIT; if(conn->bits.proxy_connect_closed) /* this is not an error, just part of the connection negotiation */ @@ -608,7 +624,7 @@ static CURLcode CONNECT(struct connectdata *conn, return CURLE_RECV_ERROR; } - conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + s->tunnel_state = TUNNEL_COMPLETE; /* 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 @@ -618,13 +634,24 @@ static CURLcode CONNECT(struct connectdata *conn, data->state.authproxy.done = TRUE; - infof(data, "Proxy replied OK to CONNECT request\n"); + infof(data, "Proxy replied %d to CONNECT request\n", + data->info.httpproxycode); 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 */ return CURLE_OK; } +void Curl_connect_free(struct Curl_easy *data) +{ + struct connectdata *conn = data->easy_conn; + struct http_connect_state *s = conn->connect_state; + if(s) { + free(s); + conn->connect_state = NULL; + } +} + /* * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This * function will issue the necessary commands to get a seamless tunnel through @@ -637,20 +664,23 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, int remote_port) { CURLcode result; - if(TUNNEL_INIT == conn->tunnel_state[sockindex]) { - if(!conn->connect_buffer) { - conn->connect_buffer = malloc(CONNECT_BUFFER_SIZE); - if(!conn->connect_buffer) - return CURLE_OUT_OF_MEMORY; - } + if(!conn->connect_state) { + result = connect_init(conn, FALSE); + if(result) + return result; } result = CONNECT(conn, sockindex, hostname, remote_port); - if(result || (TUNNEL_COMPLETE == conn->tunnel_state[sockindex])) - Curl_safefree(conn->connect_buffer); + if(result || Curl_connect_complete(conn)) + connect_done(conn); return result; } +#else +void Curl_connect_free(struct Curl_easy *data) +{ + (void)data; +} #endif /* CURL_DISABLE_PROXY */ diff --git a/lib/http_proxy.h b/lib/http_proxy.h index cbb1ab4..e19fa85 100644 --- a/lib/http_proxy.h +++ b/lib/http_proxy.h @@ -22,6 +22,9 @@ * ***************************************************************************/ +#include "curl_setup.h" +#include "urldata.h" + #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) /* ftp can use this as well */ CURLcode Curl_proxyCONNECT(struct connectdata *conn, @@ -33,9 +36,16 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex); +bool Curl_connect_complete(struct connectdata *conn); +bool Curl_connect_ongoing(struct connectdata *conn); + #else #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN #define Curl_proxy_connect(x,y) CURLE_OK +#define Curl_connect_complete(x) CURLE_OK +#define Curl_connect_ongoing(x) FALSE #endif +void Curl_connect_free(struct Curl_easy *data); + #endif /* HEADER_CURL_HTTP_PROXY_H */ diff --git a/lib/if2ip.c b/lib/if2ip.c index 4de81be..ce38ea1 100644 --- a/lib/if2ip.c +++ b/lib/if2ip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -71,6 +71,8 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa) const unsigned char *b = sa6->sin6_addr.s6_addr; unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); + if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */ + return IPV6_SCOPE_UNIQUELOCAL; switch(w & 0xFFC0) { case 0xFE80: return IPV6_SCOPE_LINKLOCAL; @@ -101,7 +103,7 @@ bool Curl_if_is_interface_name(const char *interf) struct ifaddrs *iface, *head; if(getifaddrs(&head) >= 0) { - for(iface=head; iface != NULL; iface=iface->ifa_next) { + for(iface = head; iface != NULL; iface = iface->ifa_next) { if(strcasecompare(iface->ifa_name, interf)) { result = TRUE; break; @@ -121,15 +123,15 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, #ifndef ENABLE_IPV6 (void) remote_scope; - -#ifndef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID - (void) remote_scope_id; #endif +#if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \ + !defined(ENABLE_IPV6) + (void) remote_scope_id; #endif if(getifaddrs(&head) >= 0) { - for(iface = head; iface != NULL; iface=iface->ifa_next) { + for(iface = head; iface != NULL; iface = iface->ifa_next) { if(iface->ifa_addr != NULL) { if(iface->ifa_addr->sa_family == af) { if(strcasecompare(iface->ifa_name, interf)) { @@ -228,7 +230,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, return IF2IP_NOT_FOUND; memset(&req, 0, sizeof(req)); - memcpy(req.ifr_name, interf, len+1); + memcpy(req.ifr_name, interf, len + 1); req.ifr_addr.sa_family = AF_INET; if(ioctl(dummy, SIOCGIFADDR, &req) < 0) { diff --git a/lib/if2ip.h b/lib/if2ip.h index f3a7ff0..a90e662 100644 --- a/lib/if2ip.h +++ b/lib/if2ip.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,7 +27,8 @@ #define IPV6_SCOPE_GLOBAL 0 /* Global scope. */ #define IPV6_SCOPE_LINKLOCAL 1 /* Link-local scope. */ #define IPV6_SCOPE_SITELOCAL 2 /* Site-local scope (deprecated). */ -#define IPV6_SCOPE_NODELOCAL 3 /* Loopback. */ +#define IPV6_SCOPE_UNIQUELOCAL 3 /* Unique local */ +#define IPV6_SCOPE_NODELOCAL 4 /* Loopback. */ unsigned int Curl_ipv6_scope(const struct sockaddr *sa); diff --git a/lib/imap.c b/lib/imap.c index b528f77..954d18f 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -68,6 +68,7 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "imap.h" +#include "mime.h" #include "strtoofft.h" #include "strcase.h" #include "vtls/vtls.h" @@ -128,6 +129,7 @@ const struct Curl_handler Curl_handler_imap = { ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_IMAP, /* defport */ CURLPROTO_IMAP, /* protocol */ PROTOPT_CLOSEACTION| /* flags */ @@ -154,69 +156,22 @@ const struct Curl_handler Curl_handler_imaps = { ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_IMAPS, /* defport */ CURLPROTO_IMAPS, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */ }; #endif -#ifndef CURL_DISABLE_HTTP -/* - * HTTP-proxyed IMAP protocol handler. - */ - -static const struct Curl_handler Curl_handler_imap_proxy = { - "IMAP", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_IMAP, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; - -#ifdef USE_SSL -/* - * HTTP-proxyed IMAPS protocol handler. - */ - -static const struct Curl_handler Curl_handler_imaps_proxy = { - "IMAPS", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_IMAPS, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; -#endif -#endif +#define IMAP_RESP_OK 1 +#define IMAP_RESP_NOT_OK 2 +#define IMAP_RESP_PREAUTH 3 /* SASL parameters for the imap protocol */ static const struct SASLproto saslimap = { "imap", /* The service name */ '+', /* Code received when continuation is expected */ - 'O', /* Code to receive upon authentication success */ + IMAP_RESP_OK, /* Code to receive upon authentication success */ 0, /* Maximum initial response length (no max) */ imap_perform_authenticate, /* Send authentication command */ imap_continue_authenticate, /* Send authentication continuation */ @@ -299,15 +254,11 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, len -= id_len + 1; if(len >= 2 && !memcmp(line, "OK", 2)) - *resp = 'O'; - else if(len >= 2 && !memcmp(line, "NO", 2)) - *resp = 'N'; - else if(len >= 3 && !memcmp(line, "BAD", 3)) - *resp = 'B'; - else { - failf(conn->data, "Bad tagged response"); - *resp = -1; - } + *resp = IMAP_RESP_OK; + else if(len >= 7 && !memcmp(line, "PREAUTH", 7)) + *resp = IMAP_RESP_PREAUTH; + else + *resp = IMAP_RESP_NOT_OK; return TRUE; } @@ -613,9 +564,10 @@ static CURLcode imap_perform_authentication(struct connectdata *conn) struct imap_conn *imapc = &conn->proto.imapc; saslprogress progress; - /* Check we have enough data to authenticate with and end the - connect phase if we don't */ - if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) { + /* Check if already authenticated OR if there is enough data to authenticate + with and end the connect phase if we don't */ + if(imapc->preauth || + !Curl_sasl_can_authenticate(&imapc->sasl, conn)) { state(conn, IMAP_STOP); return result; } @@ -757,18 +709,48 @@ static CURLcode imap_perform_fetch(struct connectdata *conn) static CURLcode imap_perform_append(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct IMAP *imap = conn->data->req.protop; + struct Curl_easy *data = conn->data; + struct IMAP *imap = data->req.protop; char *mailbox; /* Check we have a mailbox */ if(!imap->mailbox) { - failf(conn->data, "Cannot APPEND without a mailbox."); + failf(data, "Cannot APPEND without a mailbox."); return CURLE_URL_MALFORMAT; } + /* Prepare the mime data if some. */ + if(data->set.mimepost.kind != MIMEKIND_NONE) { + /* Use the whole structure as data. */ + data->set.mimepost.flags &= ~MIME_BODY_ONLY; + + /* Add external headers and mime version. */ + curl_mime_headers(&data->set.mimepost, data->set.headers, 0); + result = Curl_mime_prepare_headers(&data->set.mimepost, NULL, + NULL, MIMESTRATEGY_MAIL); + + if(!result) + if(!Curl_checkheaders(conn, "Mime-Version")) + result = Curl_mime_add_header(&data->set.mimepost.curlheaders, + "Mime-Version: 1.0"); + + /* Make sure we will read the entire mime structure. */ + if(!result) + result = Curl_mime_rewind(&data->set.mimepost); + + if(result) + return result; + + data->state.infilesize = Curl_mime_size(&data->set.mimepost); + + /* Read from mime structure. */ + data->state.fread_func = (curl_read_callback) Curl_mime_read; + data->state.in = (void *) &data->set.mimepost; + } + /* Check we know the size of the upload */ - if(conn->data->state.infilesize < 0) { - failf(conn->data, "Cannot APPEND with unknown input file size\n"); + if(data->state.infilesize < 0) { + failf(data, "Cannot APPEND with unknown input file size\n"); return CURLE_UPLOAD_FAILED; } @@ -779,7 +761,7 @@ static CURLcode imap_perform_append(struct connectdata *conn) /* Send the APPEND command */ result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", - mailbox, conn->data->state.infilesize); + mailbox, data->state.infilesize); free(mailbox); @@ -839,19 +821,21 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn, int imapcode, imapstate instate) { - CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; - (void)instate; /* no use for this yet */ - if(imapcode != 'O') { + if(imapcode == IMAP_RESP_PREAUTH) { + /* PREAUTH */ + struct imap_conn *imapc = &conn->proto.imapc; + imapc->preauth = TRUE; + infof(data, "PREAUTH connection, already authenticated!\n"); + } + else if(imapcode != IMAP_RESP_OK) { failf(data, "Got unexpected imap-server response"); - result = CURLE_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } - else - result = imap_perform_capability(conn); - return result; + return imap_perform_capability(conn); } /* For CAPABILITY responses */ @@ -918,7 +902,7 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn, line += wordlen; } } - else if(imapcode == 'O') { + else if(imapcode == IMAP_RESP_OK) { if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { /* We don't have a SSL/TLS connection yet, but SSL is requested */ if(imapc->tls_supported) @@ -951,7 +935,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ - if(imapcode != 'O') { + if(imapcode != IMAP_RESP_OK) { if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied"); result = CURLE_USE_SSL_FAILED; @@ -1009,7 +993,7 @@ static CURLcode imap_state_login_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ - if(imapcode != 'O') { + if(imapcode != IMAP_RESP_OK) { failf(data, "Access denied. %c", imapcode); result = CURLE_LOGIN_DENIED; } @@ -1037,7 +1021,7 @@ static CURLcode imap_state_listsearch_resp(struct connectdata *conn, result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); line[len] = '\0'; } - else if(imapcode != 'O') + else if(imapcode != IMAP_RESP_OK) result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */ else /* End of DO phase */ @@ -1066,7 +1050,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode, imapc->mailbox_uidvalidity = strdup(tmp); } } - else if(imapcode == 'O') { + else if(imapcode == IMAP_RESP_OK) { /* Check if the UIDVALIDITY has been specified and matches */ if(imap->uidvalidity && imapc->mailbox_uidvalidity && strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) { @@ -1120,10 +1104,11 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, if(*ptr == '{') { char *endptr; - size = curlx_strtoofft(ptr + 1, &endptr, 10); - if(endptr - ptr > 1 && endptr[0] == '}' && - endptr[1] == '\r' && endptr[2] == '\0') - parsed = TRUE; + if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) { + if(endptr - ptr > 1 && endptr[0] == '}' && + endptr[1] == '\r' && endptr[2] == '\0') + parsed = TRUE; + } } if(parsed) { @@ -1197,7 +1182,7 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, (void)instate; /* No use for this yet */ - if(imapcode != 'O') + if(imapcode != IMAP_RESP_OK) result = CURLE_WEIRD_SERVER_REPLY; else /* End of DONE phase */ @@ -1241,7 +1226,7 @@ static CURLcode imap_state_append_final_resp(struct connectdata *conn, (void)instate; /* No use for this yet */ - if(imapcode != 'O') + if(imapcode != IMAP_RESP_OK) result = CURLE_UPLOAD_FAILED; else /* End of DONE phase */ @@ -1469,9 +1454,10 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, result = status; /* use the already set error code */ } else if(!data->set.connect_only && !imap->custom && - (imap->uid || data->set.upload)) { + (imap->uid || data->set.upload || + data->set.mimepost.kind != MIMEKIND_NONE)) { /* Handle responses after FETCH or APPEND transfer has finished */ - if(!data->set.upload) + if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE) state(conn, IMAP_FETCH_FINAL); else { /* End the APPEND command first by sending an empty line */ @@ -1541,7 +1527,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected, selected = TRUE; /* Start the first command in the DO phase */ - if(conn->data->set.upload) + if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE) /* APPEND can be executed directly */ result = imap_perform_append(conn); else if(imap->custom && (selected || !imap->mailbox)) @@ -1715,31 +1701,6 @@ static CURLcode imap_setup_connection(struct connectdata *conn) /* Clear the TLS upgraded flag */ conn->tls_upgraded = FALSE; - - /* Set up the proxy if necessary */ - if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel IMAP operations through the proxy, we - switch and use HTTP operations only */ -#ifndef CURL_DISABLE_HTTP - if(conn->handler == &Curl_handler_imap) - conn->handler = &Curl_handler_imap_proxy; - else { -#ifdef USE_SSL - conn->handler = &Curl_handler_imaps_proxy; -#else - failf(data, "IMAPS not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - - /* set it up as an HTTP connection instead */ - return conn->handler->setup_connection(conn); -#else - failf(data, "IMAP over http proxy requires HTTP support built-in!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - data->state.path++; /* don't include the initial slash */ return CURLE_OK; @@ -1836,7 +1797,7 @@ static char *imap_atom(const char *str, bool escape_only) return strdup(str); /* Calculate the new string length */ - newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0); + newlen = strlen(str) + backsp_count + quote_count + (escape_only ? 0 : 2); /* Allocate the new string */ newstr = (char *) malloc((newlen + 1) * sizeof(char)); @@ -1845,7 +1806,7 @@ static char *imap_atom(const char *str, bool escape_only) /* Surround the string in quotes if necessary */ p2 = newstr; - if(others_exists) { + if(!escape_only) { newstr[0] = '"'; newstr[newlen - 1] = '"'; p2++; diff --git a/lib/imap.h b/lib/imap.h index 5e0e228..9fc4ff5 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2009 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -71,6 +71,7 @@ struct imap_conn { struct pingpong pp; imapstate state; /* Always use imap.c:state() to change state! */ bool ssldone; /* Is connect() over SSL done? */ + bool preauth; /* Is this connection PREAUTH? */ struct SASL sasl; /* SASL-related parameters */ unsigned int preftype; /* Preferred authentication type */ int cmdid; /* Last used command ID */ diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c index 9afbdbb..fb91a50 100644 --- a/lib/inet_ntop.c +++ b/lib/inet_ntop.c @@ -63,7 +63,7 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) len = strlen(tmp); if(len == 0 || len >= size) { - SET_ERRNO(ENOSPC); + errno = ENOSPC; return (NULL); } strcpy(dst, tmp); @@ -141,8 +141,8 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) */ if(i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { - if(!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) { - SET_ERRNO(ENOSPC); + if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) { + errno = ENOSPC; return (NULL); } tp += strlen(tp); @@ -160,7 +160,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) /* Check for overflow, copy, and we're done. */ if((size_t)(tp - tmp) > size) { - SET_ERRNO(ENOSPC); + errno = ENOSPC; return (NULL); } strcpy(dst, tmp); @@ -177,8 +177,8 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) * * On Windows we store the error in the thread errno, not * in the winsock error code. This is to avoid losing the - * actual last winsock error. So use macro ERRNO to fetch the - * errno this function sets when returning NULL, not SOCKERRNO. + * actual last winsock error. So when this function returns + * NULL, check errno not SOCKERRNO. */ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) { @@ -190,7 +190,7 @@ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) return inet_ntop6((const unsigned char *)src, buf, size); #endif default: - SET_ERRNO(EAFNOSUPPORT); + errno = EAFNOSUPPORT; return NULL; } } diff --git a/lib/inet_pton.c b/lib/inet_pton.c index 475f44a..fef9610 100644 --- a/lib/inet_pton.c +++ b/lib/inet_pton.c @@ -57,8 +57,8 @@ static int inet_pton6(const char *src, unsigned char *dst); * notice: * On Windows we store the error in the thread errno, not * in the winsock error code. This is to avoid losing the - * actual last winsock error. So use macro ERRNO to fetch the - * errno this function sets when returning (-1), not SOCKERRNO. + * actual last winsock error. So when this function returns + * -1, check errno not SOCKERRNO. * author: * Paul Vixie, 1996. */ @@ -73,7 +73,7 @@ Curl_inet_pton(int af, const char *src, void *dst) return (inet_pton6(src, (unsigned char *)dst)); #endif default: - SET_ERRNO(EAFNOSUPPORT); + errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ diff --git a/lib/inet_pton.h b/lib/inet_pton.h index 9188d95..e216f4e 100644 --- a/lib/inet_pton.h +++ b/lib/inet_pton.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,6 +29,9 @@ int Curl_inet_pton(int, const char *, void *); #ifdef HAVE_INET_PTON #ifdef HAVE_ARPA_INET_H #include +#elif defined(HAVE_WS2TCPIP_H) +/* inet_pton() exists in Vista or later */ +#include #endif #define Curl_inet_pton(x,y,z) inet_pton(x,y,z) #endif diff --git a/lib/krb5.c b/lib/krb5.c index 69a3597..af25e92 100644 --- a/lib/krb5.c +++ b/lib/krb5.c @@ -1,6 +1,6 @@ /* GSSAPI/krb5 support for FTP - loosely based on old krb4.c * - * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan + * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * Copyright (c) 2004 - 2016 Daniel Stenberg * All rights reserved. diff --git a/lib/ldap.c b/lib/ldap.c index 79e84d9..040641c 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -150,6 +150,7 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_LDAP, /* defport */ CURLPROTO_LDAP, /* protocol */ PROTOPT_NONE /* flags */ @@ -175,6 +176,7 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_LDAPS, /* defport */ CURLPROTO_LDAPS, /* protocol */ PROTOPT_SSL /* flags */ @@ -233,7 +235,6 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server, const char *user, const char *passwd) { int rc = LDAP_INVALID_CREDENTIALS; - ULONG method = LDAP_AUTH_SIMPLE; PTCHAR inuser = NULL; PTCHAR inpass = NULL; @@ -242,7 +243,7 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server, inuser = Curl_convert_UTF8_to_tchar((char *) user); inpass = Curl_convert_UTF8_to_tchar((char *) passwd); - rc = ldap_bind_s(server, inuser, inpass, method); + rc = ldap_simple_bind_s(server, inuser, inpass); Curl_unicodefree(inuser); Curl_unicodefree(inpass); @@ -266,7 +267,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) LDAPMessage *ldapmsg = NULL; LDAPMessage *entryIterator; int num = 0; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; int ldap_proto = LDAP_VERSION3; int ldap_ssl = 0; char *val_b64 = NULL; diff --git a/lib/memdebug.c b/lib/memdebug.c index 2b8808a..0eb249c 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -115,7 +115,8 @@ void curl_memdebug(const char *logname) logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC /* Flush the log file after every line so the log isn't lost in a crash */ - setbuf(logfile, (char *)NULL); + if(logfile) + setbuf(logfile, (char *)NULL); #endif } } @@ -146,7 +147,7 @@ static bool countcheck(const char *func, int line, const char *source) source, line, func); fflush(logfile); /* because it might crash now */ } - SET_ERRNO(ENOMEM); + errno = ENOMEM; return TRUE; /* RETURN ERROR! */ } else @@ -169,7 +170,7 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source) return NULL; /* alloc at least 64 bytes */ - size = sizeof(struct memdebug)+wantedsize; + size = sizeof(struct memdebug) + wantedsize; mem = (Curl_cmalloc)(size); if(mem) { @@ -224,9 +225,9 @@ char *curl_dostrdup(const char *str, int line, const char *source) if(countcheck("strdup", line, source)) return NULL; - len=strlen(str)+1; + len = strlen(str) + 1; - mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */ + mem = curl_domalloc(len, 0, NULL); /* NULL prevents logging */ if(mem) memcpy(mem, str, len); @@ -268,9 +269,9 @@ wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source) void *curl_dorealloc(void *ptr, size_t wantedsize, int line, const char *source) { - struct memdebug *mem=NULL; + struct memdebug *mem = NULL; - size_t size = sizeof(struct memdebug)+wantedsize; + size_t size = sizeof(struct memdebug) + wantedsize; DEBUGASSERT(wantedsize != 0); @@ -406,7 +407,7 @@ void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source) /* this is our own defined way to close sockets on *ALL* platforms */ int curl_sclose(curl_socket_t sockfd, int line, const char *source) { - int res=sclose(sockfd); + int res = sclose(sockfd); curl_mark_sclose(sockfd, line, source); return res; } @@ -414,7 +415,7 @@ int curl_sclose(curl_socket_t sockfd, int line, const char *source) FILE *curl_fopen(const char *file, const char *mode, int line, const char *source) { - FILE *res=fopen(file, mode); + FILE *res = fopen(file, mode); if(source) curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", @@ -427,7 +428,7 @@ FILE *curl_fopen(const char *file, const char *mode, FILE *curl_fdopen(int filedes, const char *mode, int line, const char *source) { - FILE *res=fdopen(filedes, mode); + FILE *res = fdopen(filedes, mode); if(source) curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", @@ -443,7 +444,7 @@ int curl_fclose(FILE *file, int line, const char *source) DEBUGASSERT(file != NULL); - res=fclose(file); + res = fclose(file); if(source) curl_memlog("FILE %s:%d fclose(%p)\n", diff --git a/lib/mime.c b/lib/mime.c new file mode 100644 index 0000000..496f5e6 --- /dev/null +++ b/lib/mime.c @@ -0,0 +1,1860 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.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 + +#include "mime.h" +#include "non-ascii.h" + +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP) + +#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) +#include +#endif + +#include "rand.h" +#include "slist.h" +#include "strcase.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifdef WIN32 +# ifndef R_OK +# define R_OK 4 +# endif +#endif + + +#define FILE_CONTENTTYPE_DEFAULT "application/octet-stream" +#define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed" +#define DISPOSITION_DEFAULT "attachment" + +#define READ_ERROR ((size_t) -1) + +/* Encoders. */ +static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part); +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); +static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part); +static curl_off_t encoder_base64_size(curl_mimepart *part); +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[] = { + {"binary", encoder_nop_read, encoder_nop_size}, + {"8bit", encoder_nop_read, encoder_nop_size}, + {"7bit", encoder_7bit_read, encoder_nop_size}, + {"base64", encoder_base64_read, encoder_base64_size}, + {"quoted-printable", encoder_qp_read, encoder_qp_size}, + {ZERO_NULL, ZERO_NULL, ZERO_NULL} +}; + +/* Base64 encoding table */ +static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* Quoted-printable character class table. + * + * We cannot rely on ctype functions since quoted-printable input data + * is assumed to be ascii-compatible, even on non-ascii platforms. */ +#define QP_OK 1 /* Can be represented by itself. */ +#define QP_SP 2 /* Space or tab. */ +#define QP_CR 3 /* Carriage return. */ +#define QP_LF 4 /* Line-feed. */ +static const unsigned char qp_class[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */ + 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */ + QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ +}; + + +/* Binary --> hexadecimal ASCII table. */ +static const char aschex[] = + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46"; + + + +#ifndef __VMS +#define filesize(name, stat_data) (stat_data.st_size) +#define fopen_read fopen + +#else + +#include +/* + * get_vms_file_size does what it takes to get the real size of the file + * + * For fixed files, find out the size of the EOF block and adjust. + * + * For all others, have to read the entire file in, discarding the contents. + * Most posted text files will be small, and binary files like zlib archives + * and CD/DVD images should be either a STREAM_LF format or a fixed format. + * + */ +curl_off_t VmsRealFileSize(const char *name, + const struct_stat *stat_buf) +{ + char buffer[8192]; + curl_off_t count; + int ret_stat; + FILE * file; + + file = fopen(name, FOPEN_READTEXT); /* VMS */ + if(file == NULL) + return 0; + + count = 0; + ret_stat = 1; + while(ret_stat > 0) { + ret_stat = fread(buffer, 1, sizeof(buffer), file); + if(ret_stat != 0) + count += ret_stat; + } + fclose(file); + + return count; +} + +/* + * + * VmsSpecialSize checks to see if the stat st_size can be trusted and + * if not to call a routine to get the correct size. + * + */ +static curl_off_t VmsSpecialSize(const char *name, + const struct_stat *stat_buf) +{ + switch(stat_buf->st_fab_rfm) { + case FAB$C_VAR: + case FAB$C_VFC: + return VmsRealFileSize(name, stat_buf); + break; + default: + return stat_buf->st_size; + } +} + +#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) + +/* + * vmsfopenread + * + * For upload to work as expected on VMS, different optional + * parameters must be added to the fopen command based on + * record format of the file. + * + */ +static FILE * vmsfopenread(const char *file, const char *mode) +{ + struct_stat statbuf; + int result; + + result = stat(file, &statbuf); + + switch(statbuf.st_fab_rfm) { + case FAB$C_VAR: + case FAB$C_VFC: + case FAB$C_STMCR: + return fopen(file, FOPEN_READTEXT); /* VMS */ + break; + default: + return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); + } +} + +#define fopen_read vmsfopenread +#endif + + +#ifndef HAVE_BASENAME +/* + (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 + Edition) + + The basename() function shall take the pathname pointed to by path and + return a pointer to the final component of the pathname, deleting any + trailing '/' characters. + + If the string pointed to by path consists entirely of the '/' character, + basename() shall return a pointer to the string "/". If the string pointed + to by path is exactly "//", it is implementation-defined whether '/' or "//" + is returned. + + If path is a null pointer or points to an empty string, basename() shall + return a pointer to the string ".". + + The basename() function may modify the string pointed to by path, and may + return a pointer to static storage that may then be overwritten by a + subsequent call to basename(). + + The basename() function need not be reentrant. A function that is not + required to be reentrant is not required to be thread-safe. + +*/ +static char *Curl_basename(char *path) +{ + /* Ignore all the details above for now and make a quick and simple + implementaion here */ + char *s1; + char *s2; + + s1 = strrchr(path, '/'); + s2 = strrchr(path, '\\'); + + if(s1 && s2) { + path = (s1 > s2? s1 : s2) + 1; + } + else if(s1) + path = s1 + 1; + else if(s2) + path = s2 + 1; + + return path; +} + +#define basename(x) Curl_basename((x)) +#endif + + +/* Set readback state. */ +static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr) +{ + state->state = tok; + state->ptr = ptr; + state->offset = 0; +} + + +/* Escape header string into allocated memory. */ +static char *escape_string(const char *src) +{ + size_t bytecount = 0; + size_t i; + char *dst; + + for(i = 0; src[i]; i++) + if(src[i] == '"' || src[i] == '\\') + bytecount++; + + bytecount += i; + dst = malloc(bytecount + 1); + if(!dst) + return NULL; + + for(i = 0; *src; src++) { + if(*src == '"' || *src == '\\') + dst[i++] = '\\'; + dst[i++] = *src; + } + + dst[i] = '\0'; + return dst; +} + +/* Check if header matches. */ +static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len) +{ + char *value = NULL; + + if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':') + for(value = hdr->data + len + 1; *value == ' '; value++) + ; + return value; +} + +/* Get a header from an slist. */ +static char *search_header(struct curl_slist *hdrlist, const char *hdr) +{ + size_t len = strlen(hdr); + char *value = NULL; + + for(; !value && hdrlist; hdrlist = hdrlist->next) + value = match_header(hdrlist, hdr, len); + + return value; +} + +static char *strippath(const char *fullfile) +{ + char *filename; + char *base; + filename = strdup(fullfile); /* duplicate since basename() may ruin the + buffer it works on */ + if(!filename) + return NULL; + base = strdup(basename(filename)); + + free(filename); /* free temporary buffer */ + + return base; /* returns an allocated string or NULL ! */ +} + +/* Initialize data encoder state. */ +static void cleanup_encoder_state(mime_encoder_state *p) +{ + p->pos = 0; + p->bufbeg = 0; + p->bufend = 0; +} + + +/* 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) +{ + mime_encoder_state *st = &part->encstate; + size_t insize = st->bufend - st->bufbeg; + + (void) ateof; + + if(size > insize) + size = insize; + if(size) + memcpy(buffer, st->buf, size); + st->bufbeg += size; + return size; +} + +static curl_off_t encoder_nop_size(curl_mimepart *part) +{ + return part->datasize; +} + + +/* 7bit encoder: the encoder is just a data validity check. */ +static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part) +{ + mime_encoder_state *st = &part->encstate; + size_t cursize = st->bufend - st->bufbeg; + + (void) ateof; + + if(size > cursize) + size = cursize; + + for(cursize = 0; cursize < size; cursize++) { + *buffer = st->buf[st->bufbeg]; + if(*buffer++ & 0x80) + return cursize? cursize: READ_ERROR; + st->bufbeg++; + } + + return cursize; +} + + +/* Base64 content encoder. */ +static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part) +{ + mime_encoder_state *st = &part->encstate; + size_t cursize = 0; + int i; + char *ptr = buffer; + + while(st->bufbeg < st->bufend) { + /* Line full ? */ + if(st->pos >= MAX_ENCODED_LINE_LENGTH - 4) { + /* Yes, we need 2 characters for CRLF. */ + if(size < 2) + break; + *ptr++ = '\r'; + *ptr++ = '\n'; + st->pos = 0; + cursize += 2; + size -= 2; + } + + /* Be sure there is enough space and input data for a base64 group. */ + if(size < 4 || st->bufend - st->bufbeg < 3) + break; + + /* Encode three bytes a four characters. */ + i = st->buf[st->bufbeg++] & 0xFF; + i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); + i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); + *ptr++ = base64[(i >> 18) & 0x3F]; + *ptr++ = base64[(i >> 12) & 0x3F]; + *ptr++ = base64[(i >> 6) & 0x3F]; + *ptr++ = base64[i & 0x3F]; + cursize += 4; + st->pos += 4; + size -= 4; + } + + /* 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++; + } + cursize += 4; + st->pos += 4; + break; + } + } + +#ifdef CURL_DOES_CONVERSIONS + /* This is now textual data, Convert character codes. */ + if(part->easy && cursize) { + CURLcode result = Curl_convert_to_network(part->easy, buffer, cursize); + if(result) + return READ_ERROR; + } +#endif + + return cursize; +} + +static curl_off_t encoder_base64_size(curl_mimepart *part) +{ + curl_off_t size = part->datasize; + + if(size <= 0) + return size; /* Unknown size or no data. */ + + /* Compute base64 character count. */ + size = 4 * (1 + (size - 1) / 3); + + /* Effective character count must include CRLFs. */ + return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH); +} + + +/* Quoted-printable lookahead. + * + * 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) +{ + n += st->bufbeg; + if(n >= st->bufend && ateof) + return 1; + if(n + 2 > st->bufend) + return ateof? 0: -1; + if(qp_class[st->buf[n] & 0xFF] == QP_CR && + qp_class[st->buf[n + 1] & 0xFF] == QP_LF) + return 1; + return 0; +} + +/* Quoted-printable encoder. */ +static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, + curl_mimepart *part) +{ + mime_encoder_state *st = &part->encstate; + char *ptr = buffer; + size_t cursize = 0; + int i; + size_t len; + size_t consumed; + int softlinebreak; + char buf[4]; + + /* On all platforms, input is supposed to be ASCII compatible: for this + reason, we use hexadecimal ASCII codes in this function rather than + character constants that can be interpreted as non-ascii on some + platforms. Preserve ASCII encoding on output too. */ + while(st->bufbeg < st->bufend) { + len = 1; + consumed = 1; + i = st->buf[st->bufbeg]; + buf[0] = (char) i; + buf[1] = aschex[(i >> 4) & 0xF]; + buf[2] = aschex[i & 0xF]; + + switch(qp_class[st->buf[st->bufbeg] & 0xFF]) { + case QP_OK: /* Not a special character. */ + break; + case QP_SP: /* Space or tab. */ + /* Spacing must be escaped if followed by CRLF. */ + switch(qp_lookahead_eol(st, ateof, 1)) { + case -1: /* More input data needed. */ + return cursize; + case 0: /* No encoding needed. */ + break; + default: /* CRLF after space or tab. */ + buf[0] = '\x3D'; /* '=' */ + len = 3; + break; + } + break; + case QP_CR: /* Carriage return. */ + /* If followed by a line-feed, output the CRLF pair. + Else escape it. */ + switch(qp_lookahead_eol(st, ateof, 0)) { + case -1: /* Need more data. */ + return cursize; + case 1: /* CRLF found. */ + buf[len++] = '\x0A'; /* Append '\n'. */ + consumed = 2; + break; + default: /* Not followed by LF: escape. */ + buf[0] = '\x3D'; /* '=' */ + len = 3; + break; + } + break; + default: /* Character must be escaped. */ + buf[0] = '\x3D'; /* '=' */ + len = 3; + break; + } + + /* Be sure the encoded character fits within maximum line length. */ + if(buf[len - 1] != '\x0A') { /* '\n' */ + softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH; + if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) { + /* We may use the current line only if end of data or followed by + a CRLF. */ + 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; + } + } + if(softlinebreak) { + strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */ + len = 3; + consumed = 0; + } + } + + /* If the output buffer would overflow, do not store. */ + if(len > size) + break; + + /* Append to output buffer. */ + memcpy(ptr, buf, len); + cursize += len; + ptr += len; + size -= len; + st->pos += len; + if(buf[len - 1] == '\x0A') /* '\n' */ + st->pos = 0; + st->bufbeg += consumed; + } + + return cursize; +} + +static curl_off_t encoder_qp_size(curl_mimepart *part) +{ + /* Determining the size can only be done by reading the data: unless the + data size is 0, we return it as unknown (-1). */ + return part->datasize? -1: 0; +} + + +/* In-memory data callbacks. */ +/* Argument is a pointer to the mime part. */ +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; + + (void) size; /* Always 1.*/ + + if(sz > nitems) + sz = nitems; + + if(sz) + memcpy(buffer, (char *) part->data, sz); + + part->state.offset += sz; + return sz; +} + +static int mime_mem_seek(void *instream, curl_off_t offset, int whence) +{ + curl_mimepart *part = (curl_mimepart *) instream; + + switch(whence) { + case SEEK_CUR: + offset += part->state.offset; + break; + case SEEK_END: + offset += part->datasize; + break; + } + + if(offset < 0 || offset > part->datasize) + return CURL_SEEKFUNC_FAIL; + + part->state.offset = (size_t) offset; + return CURL_SEEKFUNC_OK; +} + +static void mime_mem_free(void *ptr) +{ + Curl_safefree(((curl_mimepart *) ptr)->data); +} + + +/* Named file callbacks. */ +/* Argument is a pointer to the mime part. */ +static int mime_open_file(curl_mimepart * part) +{ + /* Open a MIMEKIND_FILE part. */ + + if(part->fp) + return 0; + part->fp = fopen_read(part->data, "rb"); + return part->fp? 0: -1; +} + +static size_t mime_file_read(char *buffer, size_t size, size_t nitems, + void *instream) +{ + curl_mimepart *part = (curl_mimepart *) instream; + + if(mime_open_file(part)) + return READ_ERROR; + + return fread(buffer, size, nitems, part->fp); +} + +static int mime_file_seek(void *instream, curl_off_t offset, int whence) +{ + curl_mimepart *part = (curl_mimepart *) instream; + + if(whence == SEEK_SET && !offset && !part->fp) + return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */ + + if(mime_open_file(part)) + return CURL_SEEKFUNC_FAIL; + + return fseek(part->fp, (long) offset, whence)? + CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK; +} + +static void mime_file_free(void *ptr) +{ + curl_mimepart *part = (curl_mimepart *) ptr; + + if(part->fp) { + fclose(part->fp); + part->fp = NULL; + } + Curl_safefree(part->data); + part->data = NULL; +} + + +/* Subparts callbacks. */ +/* Argument is a pointer to the mime structure. */ + +/* Readback a byte string segment. */ +static size_t readback_bytes(mime_state *state, + char *buffer, size_t bufsize, + const char *bytes, size_t numbytes, + const char *trail) +{ + size_t sz; + + sz = numbytes - state->offset; + + if(numbytes > state->offset) { + sz = numbytes - state->offset; + bytes += state->offset; + } + else { + size_t tsz = strlen(trail); + + sz = state->offset - numbytes; + if(sz >= tsz) + return 0; + bytes = trail + sz; + sz = tsz - sz; + } + + if(sz > bufsize) + sz = bufsize; + + memcpy(buffer, bytes, sz); + state->offset += sz; + return sz; +} + +/* Read a non-encoded part content. */ +static size_t read_part_content(curl_mimepart *part, + char *buffer, size_t bufsize) +{ + size_t sz = 0; + + if(part->readfunc) + sz = part->readfunc(buffer, 1, bufsize, part->arg); + return sz; +} + +/* Read and encode part content. */ +static size_t read_encoded_part_content(curl_mimepart *part, + char *buffer, size_t bufsize) +{ + mime_encoder_state *st = &part->encstate; + size_t cursize = 0; + size_t sz; + bool ateof = FALSE; + + while(bufsize) { + if(st->bufbeg < st->bufend || ateof) { + /* Encode buffered data. */ + sz = part->encoder->encodefunc(buffer, bufsize, ateof, part); + switch(sz) { + case 0: + if(ateof) + return cursize; + break; + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + return cursize? cursize: sz; + default: + cursize += sz; + buffer += sz; + bufsize -= sz; + continue; + } + } + + /* We need more data in input buffer. */ + if(st->bufbeg) { + size_t len = st->bufend - st->bufbeg; + + if(len) + memmove(st->buf, st->buf + st->bufbeg, len); + st->bufbeg = 0; + st->bufend = len; + } + 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); + switch(sz) { + case 0: + ateof = TRUE; + break; + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + return cursize? cursize: sz; + default: + st->bufend += sz; + break; + } + } + + return cursize; +} + +/* Readback a mime part. */ +static size_t readback_part(curl_mimepart *part, + char *buffer, size_t bufsize) +{ + size_t cursize = 0; + size_t sz; + struct curl_slist *hdr; +#ifdef CURL_DOES_CONVERSIONS + char *convbuf = buffer; +#endif + + /* Readback from part. */ + + while(bufsize) { + sz = 0; + hdr = (struct curl_slist *) part->state.ptr; + switch(part->state.state) { + case MIMESTATE_BEGIN: + mimesetstate(&part->state, part->flags & MIME_BODY_ONLY? MIMESTATE_BODY: + MIMESTATE_CURLHEADERS, part->curlheaders); + break; + case MIMESTATE_USERHEADERS: + if(!hdr) { + mimesetstate(&part->state, MIMESTATE_EOH, NULL); + break; + } + if(match_header(hdr, "Content-Type", 12)) { + mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next); + break; + } + /* FALLTHROUGH */ + case MIMESTATE_CURLHEADERS: + if(!hdr) + mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders); + else { + sz = readback_bytes(&part->state, buffer, bufsize, + hdr->data, strlen(hdr->data), "\r\n"); + if(!sz) + mimesetstate(&part->state, part->state.state, hdr->next); + } + break; + case MIMESTATE_EOH: + sz = readback_bytes(&part->state, buffer, bufsize, "\r\n", 2, ""); + if(!sz) + mimesetstate(&part->state, MIMESTATE_BODY, NULL); + break; + case MIMESTATE_BODY: +#ifdef CURL_DOES_CONVERSIONS + if(part->easy && convbuf < buffer) { + CURLcode result = Curl_convert_to_network(part->easy, convbuf, + buffer - convbuf); + if(result) + return READ_ERROR; + convbuf = buffer; + } +#endif + cleanup_encoder_state(&part->encstate); + mimesetstate(&part->state, MIMESTATE_CONTENT, NULL); + break; + case MIMESTATE_CONTENT: + if(part->encoder) + sz = read_encoded_part_content(part, buffer, bufsize); + else + sz = read_part_content(part, buffer, bufsize); + switch(sz) { + case 0: + mimesetstate(&part->state, MIMESTATE_END, NULL); + /* Try sparing open file descriptors. */ + if(part->kind == MIMEKIND_FILE && part->fp) { + fclose(part->fp); + part->fp = NULL; + } + /* FALLTHROUGH */ + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + return cursize? cursize: sz; + } + break; + case MIMESTATE_END: + return cursize; + default: + break; /* Other values not in part state. */ + } + + /* Bump buffer and counters according to read size. */ + cursize += sz; + buffer += sz; + bufsize -= sz; + } + +#ifdef CURL_DOES_CONVERSIONS + if(part->easy && convbuf < buffer && + part->state.state < MIMESTATE_BODY) { + CURLcode result = Curl_convert_to_network(part->easy, convbuf, + buffer - convbuf); + if(result) + return READ_ERROR; + } +#endif + + return cursize; +} + +/* Readback from mime. */ +static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, + void *instream) +{ + curl_mime *mime = (curl_mime *) instream; + size_t cursize = 0; + size_t sz; + curl_mimepart *part; +#ifdef CURL_DOES_CONVERSIONS + char *convbuf = buffer; +#endif + + (void) size; /* Always 1. */ + + while(nitems) { + sz = 0; + part = mime->state.ptr; + switch(mime->state.state) { + case MIMESTATE_BEGIN: + case MIMESTATE_BODY: +#ifdef CURL_DOES_CONVERSIONS + convbuf = buffer; +#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 + by skipping the leading CRLF in boundary. */ + mime->state.offset += 2; + break; + case MIMESTATE_BOUNDARY1: + sz = readback_bytes(&mime->state, buffer, nitems, "\r\n--", 4, ""); + if(!sz) + mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part); + break; + case MIMESTATE_BOUNDARY2: + sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary, + strlen(mime->boundary), part? "\r\n": "--\r\n"); + if(!sz) { +#ifdef CURL_DOES_CONVERSIONS + if(mime->easy && convbuf < buffer) { + CURLcode result = Curl_convert_to_network(mime->easy, convbuf, + buffer - convbuf); + if(result) + return READ_ERROR; + convbuf = buffer; + } +#endif + mimesetstate(&mime->state, MIMESTATE_CONTENT, part); + } + break; + case MIMESTATE_CONTENT: + if(!part) { + mimesetstate(&mime->state, MIMESTATE_END, NULL); + break; + } + sz = readback_part(part, buffer, nitems); + switch(sz) { + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + return cursize? cursize: sz; + case 0: +#ifdef CURL_DOES_CONVERSIONS + convbuf = buffer; +#endif + mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart); + break; + } + break; + case MIMESTATE_END: + return cursize; + default: + break; /* other values not used in mime state. */ + } + + /* Bump buffer and counters according to read size. */ + cursize += sz; + buffer += sz; + nitems -= sz; + } + +#ifdef CURL_DOES_CONVERSIONS + if(mime->easy && convbuf < buffer && + mime->state.state <= MIMESTATE_CONTENT) { + CURLcode result = Curl_convert_to_network(mime->easy, convbuf, + buffer - convbuf); + if(result) + return READ_ERROR; + } +#endif + + return cursize; +} + +static int mime_part_rewind(curl_mimepart *part) +{ + int res = CURL_SEEKFUNC_OK; + enum mimestate targetstate = MIMESTATE_BEGIN; + + if(part->flags & MIME_BODY_ONLY) + targetstate = MIMESTATE_BODY; + cleanup_encoder_state(&part->encstate); + if(part->state.state > targetstate) { + res = CURL_SEEKFUNC_CANTSEEK; + if(part->seekfunc) { + res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET); + switch(res) { + case CURL_SEEKFUNC_OK: + case CURL_SEEKFUNC_FAIL: + case CURL_SEEKFUNC_CANTSEEK: + break; + case -1: /* For fseek() error. */ + res = CURL_SEEKFUNC_CANTSEEK; + break; + default: + res = CURL_SEEKFUNC_FAIL; + break; + } + } + } + + if(res == CURL_SEEKFUNC_OK) + mimesetstate(&part->state, targetstate, NULL); + + return res; +} + +static int mime_subparts_seek(void *instream, curl_off_t offset, int whence) +{ + curl_mime *mime = (curl_mime *) instream; + curl_mimepart *part; + int result = CURL_SEEKFUNC_OK; + int res; + + if(whence != SEEK_SET || offset) + return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */ + + if(mime->state.state == MIMESTATE_BEGIN) + return CURL_SEEKFUNC_OK; /* Already rewound. */ + + for(part = mime->firstpart; part; part = part->nextpart) { + res = mime_part_rewind(part); + if(res != CURL_SEEKFUNC_OK) + result = res; + } + + if(result == CURL_SEEKFUNC_OK) + mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL); + + return result; +} + +static void mime_subparts_free(void *ptr) +{ + curl_mime *mime = (curl_mime *) ptr; + curl_mime_free(mime); +} + + +/* Release part content. */ +static void cleanup_part_content(curl_mimepart *part) +{ + if(part->freefunc) + part->freefunc(part->arg); + + part->readfunc = NULL; + part->seekfunc = NULL; + part->freefunc = NULL; + part->arg = (void *) part; /* Defaults to part itself. */ + part->data = NULL; + part->fp = NULL; + part->datasize = (curl_off_t) 0; /* No size yet. */ + part->encoder = NULL; + cleanup_encoder_state(&part->encstate); + part->kind = MIMEKIND_NONE; +} + +void Curl_mime_cleanpart(curl_mimepart *part) +{ + cleanup_part_content(part); + curl_slist_free_all(part->curlheaders); + if(part->flags & MIME_USERHEADERS_OWNER) + curl_slist_free_all(part->userheaders); + Curl_safefree(part->mimetype); + Curl_safefree(part->name); + Curl_safefree(part->filename); + Curl_mime_initpart(part, part->easy); +} + +/* Recursively delete a mime handle and its parts. */ +void curl_mime_free(curl_mime *mime) +{ + curl_mimepart *part; + + if(mime) { + while(mime->firstpart) { + part = mime->firstpart; + mime->firstpart = part->nextpart; + Curl_mime_cleanpart(part); + free(part); + } + + free(mime->boundary); + free(mime); + } +} + +/* + * Mime build functions. + */ + +/* Create a mime handle. */ +curl_mime *curl_mime_init(struct Curl_easy *easy) +{ + curl_mime *mime; + + mime = (curl_mime *) malloc(sizeof *mime); + + if(mime) { + mime->easy = easy; + mime->parent = NULL; + mime->firstpart = NULL; + mime->lastpart = NULL; + + /* Get a part boundary. */ + mime->boundary = malloc(24 + MIME_RAND_BOUNDARY_CHARS + 1); + if(!mime->boundary) { + free(mime); + return NULL; + } + + memset(mime->boundary, '-', 24); + Curl_rand_hex(easy, (unsigned char *) mime->boundary + 24, + MIME_RAND_BOUNDARY_CHARS + 1); + mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL); + } + + return mime; +} + +/* Initialize a mime part. */ +void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy) +{ + memset((char *) part, 0, sizeof *part); + part->easy = easy; + mimesetstate(&part->state, MIMESTATE_BEGIN, NULL); +} + +/* Create a mime part and append it to a mime handle's part list. */ +curl_mimepart *curl_mime_addpart(curl_mime *mime) +{ + curl_mimepart *part; + + if(!mime) + return NULL; + + part = (curl_mimepart *) malloc(sizeof *part); + + if(part) { + Curl_mime_initpart(part, mime->easy); + part->parent = mime; + + if(mime->lastpart) + mime->lastpart->nextpart = part; + else + mime->firstpart = part; + + mime->lastpart = part; + } + + return part; +} + +/* Set mime part name. */ +CURLcode curl_mime_name(curl_mimepart *part, const char *name) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + Curl_safefree(part->name); + part->name = NULL; + + if(name) { + part->name = strdup(name); + if(!part->name) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +/* Set mime part remote file name. */ +CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + Curl_safefree(part->filename); + part->filename = NULL; + + if(filename) { + part->filename = strdup(filename); + if(!part->filename) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +/* Set mime part content from memory data. */ +CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + cleanup_part_content(part); + + if(data) { + if(datasize == CURL_ZERO_TERMINATED) + datasize = strlen(data); + + part->data = malloc(datasize + 1); + if(!part->data) + return CURLE_OUT_OF_MEMORY; + + part->datasize = datasize; + + if(datasize) + memcpy(part->data, data, datasize); + part->data[datasize] = '\0'; /* Set a nul terminator as sentinel. */ + + part->readfunc = mime_mem_read; + part->seekfunc = mime_mem_seek; + part->freefunc = mime_mem_free; + part->kind = MIMEKIND_DATA; + } + + return CURLE_OK; +} + +/* Set mime part content from named local file. */ +CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) +{ + CURLcode result = CURLE_OK; + char *base; + + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + cleanup_part_content(part); + + if(filename) { + struct_stat sbuf; + + if(stat(filename, &sbuf) || access(filename, R_OK)) + result = CURLE_READ_ERROR; + + part->data = strdup(filename); + if(!part->data) + result = CURLE_OUT_OF_MEMORY; + + part->datasize = -1; + if(!result && S_ISREG(sbuf.st_mode)) { + part->datasize = filesize(filename, sbuf); + part->seekfunc = mime_file_seek; + } + + part->readfunc = mime_file_read; + part->freefunc = mime_file_free; + part->kind = MIMEKIND_FILE; + + /* As a side effect, set the filename to the current file's base name. + It is possible to withdraw this by explicitly calling + curl_mime_filename() with a NULL filename argument after the current + call. */ + base = strippath(filename); + if(!base) + result = CURLE_OUT_OF_MEMORY; + else { + CURLcode res = curl_mime_filename(part, base); + + if(res) + result = res; + free(base); + } + } + return result; +} + +/* Set mime part type. */ +CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + Curl_safefree(part->mimetype); + part->mimetype = NULL; + + if(mimetype) { + part->mimetype = strdup(mimetype); + if(!part->mimetype) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +/* Set mime data transfer encoder. */ +CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) +{ + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; + const mime_encoder *mep; + + if(!part) + return result; + + part->encoder = NULL; + + if(!encoding) + return CURLE_OK; /* Removing current encoder. */ + + for(mep = encoders; mep->name; mep++) + if(strcasecompare(encoding, mep->name)) { + part->encoder = mep; + result = CURLE_OK; + } + + return result; +} + +/* Set mime part headers. */ +CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, int take_ownership) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(part->flags & MIME_USERHEADERS_OWNER) { + curl_slist_free_all(part->userheaders); + part->flags &= ~MIME_USERHEADERS_OWNER; + } + part->userheaders = headers; + if(headers && take_ownership) + part->flags |= MIME_USERHEADERS_OWNER; + return CURLE_OK; +} + +/* Set mime part content from callback. */ +CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, void *arg) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + cleanup_part_content(part); + + if(readfunc) { + part->readfunc = readfunc; + part->seekfunc = seekfunc; + part->freefunc = freefunc; + part->arg = arg; + part->datasize = datasize; + part->kind = MIMEKIND_CALLBACK; + } + + return CURLE_OK; +} + +/* Set mime part content from subparts. */ +CURLcode curl_mime_subparts(curl_mimepart *part, + curl_mime *subparts) +{ + if(!part) + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* Accept setting twice the same subparts. */ + if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts) + return CURLE_OK; + + cleanup_part_content(part); + + if(subparts) { + /* Must belong to the same data handle. */ + if(part->easy && subparts->easy && part->easy != subparts->easy) + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* Should not have been attached already. */ + if(subparts->parent) + return CURLE_BAD_FUNCTION_ARGUMENT; + + subparts->parent = part; + part->readfunc = mime_subparts_read; + part->seekfunc = mime_subparts_seek; + part->freefunc = mime_subparts_free; + part->arg = subparts; + part->datasize = -1; + part->kind = MIMEKIND_MULTIPART; + } + + return CURLE_OK; +} + + +/* Readback from top mime. */ +/* Argument is the dummy top part. */ +size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) +{ + curl_mimepart *part = (curl_mimepart *) instream; + + (void) size; /* Always 1. */ + return readback_part(part, buffer, nitems); +} + +/* Rewind mime stream. */ +CURLcode Curl_mime_rewind(curl_mimepart *part) +{ + return mime_part_rewind(part) == CURL_SEEKFUNC_OK? + CURLE_OK: CURLE_SEND_FAIL_REWIND; +} + +/* Compute header list size. */ +static size_t slist_size(struct curl_slist *s, + size_t overhead, const char *skip) +{ + size_t size = 0; + size_t skiplen = skip? strlen(skip): 0; + + for(; s; s = s->next) + if(!skip || !match_header(s, skip, skiplen)) + size += strlen(s->data) + overhead; + return size; +} + +/* Get/compute multipart size. */ +static curl_off_t multipart_size(curl_mime *mime) +{ + curl_off_t size; + curl_off_t sz; + size_t boundarysize; + curl_mimepart *part; + + if(!mime) + return 0; /* Not present -> empty. */ + + boundarysize = 4 + strlen(mime->boundary) + 2; + size = boundarysize; /* Final boundary - CRLF after headers. */ + + for(part = mime->firstpart; part; part = part->nextpart) { + sz = Curl_mime_size(part); + + if(sz < 0) + size = sz; + + if(size >= 0) + size += boundarysize + sz; + } + + return size; +} + +/* Get/compute mime size. */ +curl_off_t Curl_mime_size(curl_mimepart *part) +{ + curl_off_t size; + + if(part->datasize < 0 && part->kind == MIMEKIND_MULTIPART) + part->datasize = multipart_size(part->arg); + + size = part->datasize; + + if(part->encoder) + size = part->encoder->sizefunc(part); + + if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) { + /* Compute total part size. */ + size += slist_size(part->curlheaders, 2, NULL); + size += slist_size(part->userheaders, 2, "Content-Type"); + size += 2; /* CRLF after headers. */ + } + return size; +} + +/* Add a header. */ +/* VARARGS2 */ +CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) +{ + struct curl_slist *hdr = NULL; + char *s = NULL; + va_list ap; + + va_start(ap, fmt); + s = curl_mvaprintf(fmt, ap); + va_end(ap); + + if(s) { + hdr = Curl_slist_append_nodup(*slp, s); + if(hdr) + *slp = hdr; + else + free(s); + } + + return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY; +} + +/* Add a content type header. */ +static CURLcode add_content_type(struct curl_slist **slp, + const char *type, const char *boundary) +{ + return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type, + boundary? "; boundary=": "", + boundary? boundary: ""); +} + + +static const char *ContentTypeForFilename(const char *filename) +{ + unsigned int i; + + /* + * If no content type was specified, we scan through a few well-known + * extensions and pick the first we match! + */ + struct ContentType { + const char *extension; + const char *type; + }; + static const struct ContentType ctts[] = { + {".gif", "image/gif"}, + {".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".png", "image/png"}, + {".svg", "image/svg+xml"}, + {".txt", "text/plain"}, + {".htm", "text/html"}, + {".html", "text/html"}, + {".pdf", "application/pdf"}, + {".xml", "application/xml"} + }; + + if(filename) { + size_t len1 = strlen(filename); + const char *nameend = filename + len1; + + for(i = 0; i < sizeof ctts / sizeof ctts[0]; i++) { + size_t len2 = strlen(ctts[i].extension); + + if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension)) + return ctts[i].type; + } + } + return NULL; +} + +CURLcode Curl_mime_prepare_headers(curl_mimepart *part, + const char *contenttype, + const char *disposition, + enum mimestrategy strategy) +{ + curl_mime *mime = NULL; + const char *boundary = NULL; + char *s; + const char *cte = NULL; + CURLcode ret = CURLE_OK; + + /* Get rid of previously prepared headers. */ + curl_slist_free_all(part->curlheaders); + part->curlheaders = NULL; + + /* Be sure we won't access old headers later. */ + if(part->state.state == MIMESTATE_CURLHEADERS) + mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL); + + /* Build the content-type header. */ + s = search_header(part->userheaders, "Content-Type"); + if(s) + contenttype = s; + if(part->mimetype) + contenttype = part->mimetype; + if(!contenttype) { + switch(part->kind) { + case MIMEKIND_MULTIPART: + contenttype = MULTIPART_CONTENTTYPE_DEFAULT; + break; + case MIMEKIND_FILE: + contenttype = ContentTypeForFilename(part->filename); + if(!contenttype) + contenttype = ContentTypeForFilename(part->data); + if(!contenttype && part->filename) + contenttype = FILE_CONTENTTYPE_DEFAULT; + break; + default: + contenttype = ContentTypeForFilename(part->filename); + break; + } + } + + if(part->kind == MIMEKIND_MULTIPART) { + mime = (curl_mime *) part->arg; + if(mime) + boundary = mime->boundary; + } + else if(contenttype && strcasecompare(contenttype, "text/plain")) + if(strategy == MIMESTRATEGY_MAIL || !part->filename) + contenttype = NULL; + + /* Issue content-disposition header only if not already set by caller. */ + if(!search_header(part->userheaders, "Content-Disposition")) { + if(!disposition) + if(part->filename || part->name || + (contenttype && !strncasecompare(contenttype, "multipart/", 10))) + disposition = DISPOSITION_DEFAULT; + if(disposition && curl_strequal(disposition, "attachment") && + !part->name && !part->filename) + disposition = NULL; + if(disposition) { + char *name = NULL; + char *filename = NULL; + + if(part->name) { + name = escape_string(part->name); + if(!name) + ret = CURLE_OUT_OF_MEMORY; + } + if(!ret && part->filename) { + filename = escape_string(part->filename); + if(!filename) + ret = CURLE_OUT_OF_MEMORY; + } + if(!ret) + ret = Curl_mime_add_header(&part->curlheaders, + "Content-Disposition: %s%s%s%s%s%s%s", + disposition, + name? "; name=\"": "", + name? name: "", + name? "\"": "", + filename? "; filename=\"": "", + filename? filename: "", + filename? "\"": ""); + Curl_safefree(name); + Curl_safefree(filename); + if(ret) + return ret; + } + } + + /* Issue Content-Type header. */ + if(contenttype) { + ret = add_content_type(&part->curlheaders, contenttype, boundary); + if(ret) + return ret; + } + + /* Content-Transfer-Encoding header. */ + if(!search_header(part->userheaders, "Content-Transfer-Encoding")) { + if(part->encoder) + cte = part->encoder->name; + else if(contenttype && strategy == MIMESTRATEGY_MAIL && + part->kind != MIMEKIND_MULTIPART) + cte = "8bit"; + if(cte) { + ret = Curl_mime_add_header(&part->curlheaders, + "Content-Transfer-Encoding: %s", cte); + if(ret) + return ret; + } + } + + /* If we were reading curl-generated headers, restart with new ones (this + should not occur). */ + if(part->state.state == MIMESTATE_CURLHEADERS) + mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders); + + /* Process subparts. */ + if(part->kind == MIMEKIND_MULTIPART && mime) { + curl_mimepart *subpart; + + disposition = NULL; + if(strcasecompare(contenttype, "multipart/form-data")) + disposition = "form-data"; + for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) { + ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy); + if(ret) + return ret; + } + } + return ret; +} + +#else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ + +/* Mime not compiled in: define stubs for externally-referenced functions. */ +curl_mime *curl_mime_init(CURL *easy) +{ + (void) easy; + return NULL; +} + +void curl_mime_free(curl_mime *mime) +{ + (void) mime; +} + +curl_mimepart *curl_mime_addpart(curl_mime *mime) +{ + (void) mime; + return NULL; +} + +CURLcode curl_mime_name(curl_mimepart *part, const char *name) +{ + (void) part; + (void) name; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) +{ + (void) part; + (void) filename; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) +{ + (void) part; + (void) mimetype; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) +{ + (void) part; + (void) encoding; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize) +{ + (void) part; + (void) data; + (void) datasize; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) +{ + (void) part; + (void) filename; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_data_cb(curl_mimepart *part, + curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, + void *arg) +{ + (void) part; + (void) datasize; + (void) readfunc; + (void) seekfunc; + (void) freefunc; + (void) arg; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) +{ + (void) part; + (void) subparts; + return CURLE_NOT_BUILT_IN; +} + +CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, int take_ownership) +{ + (void) part; + (void) headers; + (void) take_ownership; + return CURLE_NOT_BUILT_IN; +} + +void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy) +{ + (void) part; + (void) easy; +} + +void Curl_mime_cleanpart(curl_mimepart *part) +{ + (void) part; +} + +CURLcode Curl_mime_prepare_headers(curl_mimepart *part, + const char *contenttype, + const char *disposition, + enum mimestrategy strategy) +{ + (void) part; + (void) contenttype; + (void) disposition; + (void) strategy; + return CURLE_NOT_BUILT_IN; +} + +curl_off_t Curl_mime_size(curl_mimepart *part) +{ + (void) part; + return (curl_off_t) -1; +} + +size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) +{ + (void) buffer; + (void) size; + (void) nitems; + (void) instream; + return 0; +} + +CURLcode Curl_mime_rewind(curl_mimepart *part) +{ + (void) part; + return CURLE_NOT_BUILT_IN; +} + +/* VARARGS2 */ +CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) +{ + (void) slp; + (void) fmt; + return CURLE_NOT_BUILT_IN; +} + +#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ diff --git a/lib/mime.h b/lib/mime.h new file mode 100644 index 0000000..a144857 --- /dev/null +++ b/lib/mime.h @@ -0,0 +1,135 @@ +#ifndef HEADER_CURL_MIME_H +#define HEADER_CURL_MIME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.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. + * + ***************************************************************************/ + +#define MIME_RAND_BOUNDARY_CHARS 16 /* Nb. of random boundary chars. */ +#define MAX_ENCODED_LINE_LENGTH 76 /* Maximum encoded line length. */ +#define ENCODING_BUFFER_SIZE 256 /* Encoding temp buffers size. */ + +/* Part flags. */ +#define MIME_USERHEADERS_OWNER (1 << 0) +#define MIME_BODY_ONLY (1 << 1) + +/* Part source kinds. */ +enum mimekind { + MIMEKIND_NONE = 0, /* Part not set. */ + MIMEKIND_DATA, /* Allocated mime data. */ + MIMEKIND_FILE, /* Data from file. */ + MIMEKIND_CALLBACK, /* Data from `read' callback. */ + MIMEKIND_MULTIPART, /* Data is a mime subpart. */ + MIMEKIND_LAST +}; + +/* Readback state tokens. */ +enum mimestate { + MIMESTATE_BEGIN, /* Readback has not yet started. */ + MIMESTATE_CURLHEADERS, /* In curl-generated headers. */ + MIMESTATE_USERHEADERS, /* In caller's supplied headers. */ + MIMESTATE_EOH, /* End of headers. */ + MIMESTATE_BODY, /* Placeholder. */ + MIMESTATE_BOUNDARY1, /* In boundary prefix. */ + MIMESTATE_BOUNDARY2, /* In boundary. */ + MIMESTATE_CONTENT, /* In content. */ + MIMESTATE_END, /* End of part reached. */ + MIMESTATE_LAST +}; + +/* Mime headers strategies. */ +enum mimestrategy { + MIMESTRATEGY_MAIL, /* Mime mail. */ + MIMESTRATEGY_FORM, /* HTTP post form. */ + MIMESTRATEGY_LAST +}; + +/* Content transfer encoder. */ +typedef struct { + 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 { + 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 { + enum mimestate state; /* Current state token. */ + void *ptr; /* State-dependent pointer. */ + size_t offset; /* State-dependent offset. */ +} mime_state; + +/* A mime multipart. */ +struct curl_mime_s { + 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; /* The part boundary. */ + mime_state state; /* Current readback state. */ +}; + +/* A mime part. */ +struct curl_mimepart_s { + struct Curl_easy *easy; /* The associated easy handle. */ + curl_mime *parent; /* Parent mime structure. */ + curl_mimepart *nextpart; /* Forward linked list. */ + enum mimekind kind; /* The part kind. */ + char *data; /* Memory data or file name. */ + curl_read_callback readfunc; /* Read function. */ + curl_seek_callback seekfunc; /* Seek function. */ + curl_free_callback freefunc; /* Argument free function. */ + void *arg; /* Argument to callback functions. */ + FILE *fp; /* File pointer. */ + struct curl_slist *curlheaders; /* Part headers. */ + struct curl_slist *userheaders; /* Part headers. */ + char *mimetype; /* Part mime type. */ + char *filename; /* Remote file name. */ + 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. */ +}; + + +/* Prototypes. */ +void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy); +void Curl_mime_cleanpart(curl_mimepart *part); +CURLcode Curl_mime_prepare_headers(curl_mimepart *part, + const char *contenttype, + const char *disposition, + enum mimestrategy strategy); +curl_off_t Curl_mime_size(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_add_header(struct curl_slist **slp, const char *fmt, ...); + +#endif /* HEADER_CURL_MIME_H */ diff --git a/lib/mprintf.c b/lib/mprintf.c index eb7ee0c..d2d91d7 100644 --- a/lib/mprintf.c +++ b/lib/mprintf.c @@ -46,10 +46,6 @@ * If SIZEOF_SIZE_T has not been defined, default to the size of long. */ -#ifndef SIZEOF_SIZE_T -# define SIZEOF_SIZE_T CURL_SIZEOF_LONG -#endif - #ifdef HAVE_LONGLONG # define LONG_LONG_TYPE long long # define HAVE_LONG_LONG_TYPE @@ -111,7 +107,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } WHILE_FALSE /* Data type to read from the arglist */ -typedef enum { +typedef enum { FORMAT_UNKNOWN = 0, FORMAT_STRING, FORMAT_PTR, @@ -181,7 +177,7 @@ struct asprintf { static long dprintf_DollarString(char *input, char **end) { - int number=0; + int number = 0; while(ISDIGIT(*input)) { number *= 10; number += *input-'0'; @@ -237,7 +233,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, long width; long precision; int flags; - long max_param=0; + long max_param = 0; long i; while(*fmt) { @@ -326,7 +322,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, break; #if defined(MP_HAVE_INT_EXTENSIONS) case 'I': -#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) +#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) flags |= FLAGS_LONGLONG; #else flags |= FLAGS_LONG; @@ -348,14 +344,14 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, case 'z': /* the code below generates a warning if -Wunreachable-code is used */ -#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG) +#if (SIZEOF_SIZE_T > SIZEOF_LONG) flags |= FLAGS_LONGLONG; #else flags |= FLAGS_LONG; #endif break; case 'O': -#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) +#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) flags |= FLAGS_LONGLONG; #else flags |= FLAGS_LONG; @@ -380,7 +376,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, else width = param_num; if(width > max_param) - max_param=width; + max_param = width; break; default: break; @@ -486,7 +482,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, } /* Read the arg list parameters into our data list */ - for(i=0; i$ sequence */ - param=dprintf_DollarString(f, &f); + param = dprintf_DollarString(f, &f); if(!param) param = param_num; @@ -952,7 +948,7 @@ static int dprintf_formatf( output characters */ (sprintf)(work, formatbuf, p->data.dnum); DEBUGASSERT(strlen(work) <= sizeof(work)); - for(fptr=work; *fptr; fptr++) + for(fptr = work; *fptr; fptr++) OUTCHAR(*fptr); } break; @@ -984,7 +980,7 @@ static int dprintf_formatf( /* fputc() look-alike */ static int addbyter(int output, FILE *data) { - struct nsprintf *infop=(struct nsprintf *)data; + struct nsprintf *infop = (struct nsprintf *)data; unsigned char outc = (unsigned char)output; if(infop->length < infop->max) { @@ -1032,7 +1028,7 @@ int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) /* fputc() look-alike */ static int alloc_addbyter(int output, FILE *data) { - struct asprintf *infop=(struct asprintf *)data; + struct asprintf *infop = (struct asprintf *)data; unsigned char outc = (unsigned char)output; if(!infop->buffer) { @@ -1042,9 +1038,9 @@ static int alloc_addbyter(int output, FILE *data) return -1; /* fail */ } infop->alloc = 32; - infop->len =0; + infop->len = 0; } - else if(infop->len+1 >= infop->alloc) { + else if(infop->len + 1 >= infop->alloc) { char *newptr = NULL; size_t newsize = infop->alloc*2; @@ -1133,7 +1129,7 @@ int curl_msprintf(char *buffer, const char *format, ...) va_start(ap_save, format); retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); va_end(ap_save); - *buffer=0; /* we terminate this with a zero byte */ + *buffer = 0; /* we terminate this with a zero byte */ return retcode; } @@ -1162,7 +1158,7 @@ int curl_mvsprintf(char *buffer, const char *format, va_list ap_save) { int retcode; retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); - *buffer=0; /* we terminate this with a zero byte */ + *buffer = 0; /* we terminate this with a zero byte */ return retcode; } diff --git a/lib/multi.c b/lib/multi.c index c3a0d12..70aa6bc 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -44,6 +44,7 @@ #include "sigpipe.h" #include "vtls/vtls.h" #include "connect.h" +#include "http_proxy.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -69,7 +70,7 @@ static void singlesocket(struct Curl_multi *multi, struct Curl_easy *data); static int update_timer(struct Curl_multi *multi); -static CURLMcode add_next_timeout(struct timeval now, +static CURLMcode add_next_timeout(struct curltime now, struct Curl_multi *multi, struct Curl_easy *d); static CURLMcode multi_timeout(struct Curl_multi *multi, @@ -114,6 +115,13 @@ static void mstate(struct Curl_easy *data, CURLMstate state NULL, NULL, Curl_init_CONNECT, /* CONNECT */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + Curl_connect_free /* DO */ /* the rest is NULL too */ }; @@ -584,7 +592,7 @@ static CURLcode multi_done(struct connectdata **connp, /* 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++) { + for(i = 0; i < data->state.tempcount; i++) { free(data->state.tempwrite[i].buf); } data->state.tempcount = 0; @@ -794,8 +802,8 @@ static int waitconnect_getsock(struct connectdata *conn, int numsocks) { int i; - int s=0; - int rc=0; + int s = 0; + int rc = 0; if(!numsocks) return GETSOCK_BLANK; @@ -805,7 +813,7 @@ static int waitconnect_getsock(struct connectdata *conn, return Curl_ssl_getsock(conn, sock, numsocks); #endif - for(i=0; i<2; i++) { + for(i = 0; i<2; i++) { if(conn->tempsock[i] != CURL_SOCKET_BAD) { sock[s] = conn->tempsock[i]; rc |= GETSOCK_WRITESOCK(s++); @@ -826,7 +834,7 @@ static int waitproxyconnect_getsock(struct connectdata *conn, /* when we've sent a CONNECT to a proxy, we should rather wait for the socket to become readable to be able to get the response headers */ - if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) + if(conn->connect_state) return GETSOCK_READSOCK(0); return GETSOCK_WRITESOCK(0); @@ -916,7 +924,7 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi, Some easy handles may not have connected to the remote host yet, and then we must make sure that is done. */ struct Curl_easy *data; - int this_max_fd=-1; + int this_max_fd = -1; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; int bitmap; int i; @@ -925,11 +933,11 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi, if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; - data=multi->easyp; + data = multi->easyp; while(data) { bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); - for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { + for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) { @@ -986,11 +994,11 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, timeout_ms = (int)timeout_internal; /* Count up how many fds we have from the multi handle */ - data=multi->easyp; + data = multi->easyp; while(data) { bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); - for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { + for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; if(bitmap & GETSOCK_READSOCK(i)) { @@ -1014,6 +1022,10 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, if(nfds) { 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 + the capability to actually handle over 500 million sockets this + calculation needs a integer overflow check. */ ufds = malloc(nfds * sizeof(struct pollfd)); if(!ufds) return CURLM_OUT_OF_MEMORY; @@ -1029,11 +1041,11 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, if(curlfds) { /* Add the curl handles to our pollfds first */ - data=multi->easyp; + data = multi->easyp; while(data) { bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); - for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { + for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; if(bitmap & GETSOCK_READSOCK(i)) { @@ -1217,15 +1229,15 @@ static CURLcode multi_reconnect_request(struct connectdata **connp) */ static void do_complete(struct connectdata *conn) { - conn->data->req.chunk=FALSE; + conn->data->req.chunk = FALSE; conn->data->req.maxfd = (conn->sockfd>conn->writesockfd? - conn->sockfd:conn->writesockfd)+1; + conn->sockfd:conn->writesockfd) + 1; Curl_pgrsTime(conn->data, TIMER_PRETRANSFER); } static CURLcode multi_do(struct connectdata **connp, bool *done) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; struct connectdata *conn = *connp; struct Curl_easy *data = conn->data; @@ -1274,7 +1286,7 @@ static CURLcode multi_do(struct connectdata **connp, bool *done) static CURLcode multi_do_more(struct connectdata *conn, int *complete) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; *complete = 0; @@ -1289,7 +1301,7 @@ static CURLcode multi_do_more(struct connectdata *conn, int *complete) } static CURLMcode multi_runsingle(struct Curl_multi *multi, - struct timeval now, + struct curltime now, struct Curl_easy *data) { struct Curl_message *msg = NULL; @@ -1403,7 +1415,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, switch(data->mstate) { case CURLM_STATE_INIT: /* init this transfer. */ - result=Curl_pretransfer(data); + result = Curl_pretransfer(data); if(!result) { /* after init, go CONNECT */ @@ -1455,7 +1467,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, CURLM_STATE_WAITDO:CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP - if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) + if(Curl_connect_ongoing(data->easy_conn)) multistate(data, CURLM_STATE_WAITPROXYCONNECT); else #endif @@ -1520,7 +1532,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, CURLM_STATE_WAITDO:CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP - if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) + if(Curl_connect_ongoing(data->easy_conn)) multistate(data, CURLM_STATE_WAITPROXYCONNECT); else #endif @@ -1552,7 +1564,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(!result) { if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS || data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) && - (data->easy_conn->tunnel_state[FIRSTSOCKET] != TUNNEL_CONNECT)) { + Curl_connect_complete(data->easy_conn)) { rc = CURLM_CALL_MULTI_PERFORM; /* initiate protocol connect phase */ multistate(data, CURLM_STATE_SENDPROTOCONNECT); @@ -1568,7 +1580,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, #ifndef CURL_DISABLE_HTTP if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS && !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) || - (data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)) { + Curl_connect_ongoing(data->easy_conn)) { multistate(data, CURLM_STATE_WAITPROXYCONNECT); break; } @@ -1685,7 +1697,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, * back to the CONNECT phase so we can try again. */ char *newurl = NULL; - followtype follow=FOLLOW_NONE; + followtype follow = FOLLOW_NONE; CURLcode drc; bool retry = FALSE; @@ -1771,7 +1783,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(control) { /* if positive, advance to DO_DONE if negative, go back to DOING */ - multistate(data, control==1? + multistate(data, control == 1? CURLM_STATE_DO_DONE: CURLM_STATE_DOING); rc = CURLM_CALL_MULTI_PERFORM; @@ -1926,7 +1938,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multi_done(&data->easy_conn, result, TRUE); } else if(done) { - followtype follow=FOLLOW_NONE; + followtype follow = FOLLOW_NONE; /* call this even if the readwrite function returned error */ Curl_posttransfer(data); @@ -2132,14 +2144,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) { struct Curl_easy *data; - CURLMcode returncode=CURLM_OK; + CURLMcode returncode = CURLM_OK; struct Curl_tree *t; - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; - data=multi->easyp; + data = multi->easyp; while(data) { CURLMcode result; SIGPIPE_VARIABLE(pipe_st); @@ -2234,7 +2246,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) /* remove all easy handles */ data = multi->easyp; while(data) { - nextdata=data->next; + nextdata = data->next; if(data->dns.hostcachetype == HCACHE_MULTI) { /* clear out the usage of the shared DNS cache */ Curl_hostcache_clean(data, data->dns.hostcache); @@ -2314,7 +2326,7 @@ static void singlesocket(struct Curl_multi *multi, int num; unsigned int curraction; - for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) + for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) socks[i] = CURL_SOCKET_BAD; /* Fill in the 'current' struct with the state as it is now: what sockets to @@ -2326,7 +2338,7 @@ static void singlesocket(struct Curl_multi *multi, longer supervised ones and add new ones */ /* walk over the sockets we got right now */ - for(i=0; (i< MAX_SOCKSPEREASYHANDLE) && + for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) && (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))); i++) { int action = CURL_POLL_NONE; @@ -2370,10 +2382,10 @@ static void singlesocket(struct Curl_multi *multi, /* when we've walked over all the sockets we should have right now, we must make sure to detect sockets that are removed */ - for(i=0; i< data->numsocks; i++) { + for(i = 0; i< data->numsocks; i++) { int j; s = data->sockets[i]; - for(j=0; jstate.expiretime; + struct curltime *tv = &d->state.expiretime; struct curl_llist *list = &d->state.timeoutlist; struct curl_llist_element *e; struct time_node *node = NULL; @@ -2520,10 +2532,8 @@ static CURLMcode add_next_timeout(struct timeval now, /* copy the first entry to 'tv' */ memcpy(tv, &node->time, sizeof(*tv)); - /* remove first entry from list */ - Curl_llist_remove(list, e, NULL); - - /* insert this node again into the splay */ + /* Insert this node again into the splay. Keep the timer in the list in + case we need to recompute future timers. */ multi->timetree = Curl_splayinsert(*tv, multi->timetree, &d->state.timenode); } @@ -2539,7 +2549,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, CURLMcode result = CURLM_OK; struct Curl_easy *data = NULL; struct Curl_tree *t; - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); if(checkall) { /* *perform() deals with running_handles on its own */ @@ -2548,7 +2558,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, /* walk through each easy handle and do the socket state change magic and callbacks */ if(result != CURLM_BAD_HANDLE) { - data=multi->easyp; + data = multi->easyp; while(data) { singlesocket(multi, data); data = data->next; @@ -2765,11 +2775,11 @@ CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles) static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms) { - static struct timeval tv_zero = {0, 0}; + static struct curltime tv_zero = {0, 0}; if(multi->timetree) { /* we have a tree of expire times */ - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); /* splay the lowest to the bottom */ multi->timetree = Curl_splay(tv_zero, multi->timetree); @@ -2785,7 +2795,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, * processors while the diff is still present but less than one * millisecond! instead we return 1 until the time is ripe. */ - *timeout_ms=1; + *timeout_ms = 1; } else /* 0 means immediately */ @@ -2821,7 +2831,7 @@ static int update_timer(struct Curl_multi *multi) return -1; } if(timeout_ms < 0) { - static const struct timeval none={0, 0}; + static const struct curltime none = {0, 0}; if(Curl_splaycomparekeys(none, multi->timer_lastcall)) { multi->timer_lastcall = none; /* there's no timeout now but there was one previously, tell the app to @@ -2872,7 +2882,7 @@ multi_deltimeout(struct Curl_easy *data, expire_id eid) */ static CURLMcode multi_addtimeout(struct Curl_easy *data, - struct timeval *stamp, + struct curltime *stamp, expire_id eid) { struct curl_llist_element *e; @@ -2920,9 +2930,9 @@ multi_addtimeout(struct Curl_easy *data, void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id) { struct Curl_multi *multi = data->multi; - struct timeval *nowp = &data->state.expiretime; + struct curltime *nowp = &data->state.expiretime; int rc; - struct timeval set; + struct curltime set; /* this is only interesting while there is still an associated multi struct remaining! */ @@ -2932,34 +2942,33 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id) DEBUGASSERT(id < EXPIRE_LAST); set = Curl_tvnow(); - set.tv_sec += (long)(milli/1000); - set.tv_usec += (long)(milli%1000)*1000; + set.tv_sec += milli/1000; + set.tv_usec += (unsigned int)(milli%1000)*1000; if(set.tv_usec >= 1000000) { set.tv_sec++; set.tv_usec -= 1000000; } + /* Remove any timer with the same id just in case. */ + multi_deltimeout(data, id); + + /* Add it to the timer list. It must stay in the list until it has expired + in case we need to recompute the minimum timer later. */ + multi_addtimeout(data, &set, id); + if(nowp->tv_sec || nowp->tv_usec) { /* This means that the struct is added as a node in the splay tree. Compare if the new time is earlier, and only remove-old/add-new if it is. */ time_t diff = curlx_tvdiff(set, *nowp); - /* remove the previous timer first, if there */ - multi_deltimeout(data, id); - if(diff > 0) { - /* the new expire time was later so just add it to the queue - and get out */ - multi_addtimeout(data, &set, id); + /* The current splay tree entry is sooner than this new expiry time. + We don't need to update our splay tree entry. */ return; } - /* the new time is newer than the presently set one, so add the current - to the queue and update the head */ - multi_addtimeout(data, nowp, id); - /* Since this is an updated time, we must remove the previous entry from the splay tree first and then re-add the new value */ rc = Curl_splayremovebyaddr(multi->timetree, @@ -2969,6 +2978,8 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id) infof(data, "Internal error removing splay node = %d\n", rc); } + /* Indicate that we are in the splay tree and insert the new timer expiry + value since it is our local minimum. */ *nowp = set; data->state.timenode.payload = data; multi->timetree = Curl_splayinsert(*nowp, multi->timetree, @@ -2995,7 +3006,7 @@ void Curl_expire_done(struct Curl_easy *data, expire_id id) void Curl_expire_clear(struct Curl_easy *data) { struct Curl_multi *multi = data->multi; - struct timeval *nowp = &data->state.expiretime; + struct curltime *nowp = &data->state.expiretime; int rc; /* this is only interesting while there is still an associated multi struct @@ -3104,13 +3115,13 @@ void Curl_multi_dump(struct Curl_multi *multi) int i; fprintf(stderr, "* Multi status: %d handles, %d alive\n", multi->num_easy, multi->num_alive); - for(data=multi->easyp; data; data = data->next) { + for(data = multi->easyp; data; data = data->next) { if(data->mstate < CURLM_STATE_COMPLETED) { /* only display handles that are not completed */ fprintf(stderr, "handle %p, state %s, %d sockets\n", (void *)data, statename[data->mstate], data->numsocks); - for(i=0; i < data->numsocks; i++) { + for(i = 0; i < data->numsocks; i++) { curl_socket_t s = data->sockets[i]; struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); diff --git a/lib/multihandle.h b/lib/multihandle.h index e6ffbf5..4057539 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -148,7 +148,7 @@ struct Curl_multi { /* timer callback and user data pointer for the *socket() API */ curl_multi_timer_callback timer_cb; void *timer_userp; - struct timeval timer_lastcall; /* the fixed time for the timeout for the + struct curltime timer_lastcall; /* the fixed time for the timeout for the previous callback */ }; diff --git a/lib/netrc.c b/lib/netrc.c index 996711d..dbcc59a 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,14 +56,15 @@ int Curl_parsenetrc(const char *host, char *netrcfile) { FILE *file; - int retcode=1; + int retcode = 1; int specific_login = (*loginp && **loginp != 0); bool netrc_alloc = FALSE; - enum host_lookup_state state=NOTHING; + enum host_lookup_state state = NOTHING; - char state_login=0; /* Found a login keyword */ - char state_password=0; /* Found a password keyword */ - int state_our_login=FALSE; /* With specific_login, found *our* login name */ + char state_login = 0; /* Found a login keyword */ + char state_password = 0; /* Found a password keyword */ + int state_our_login = FALSE; /* With specific_login, found *our* login + name */ #define NETRC DOT_CHAR "netrc" @@ -88,7 +89,7 @@ int Curl_parsenetrc(const char *host, } else { struct passwd *pw; - pw= getpwuid(geteuid()); + pw = getpwuid(geteuid()); if(pw) { home = pw->pw_dir; } @@ -113,16 +114,19 @@ int Curl_parsenetrc(const char *host, if(file) { char *tok; char *tok_buf; - bool done=FALSE; + bool done = FALSE; char netrcbuffer[256]; int netrcbuffsize = (int)sizeof(netrcbuffer); while(!done && fgets(netrcbuffer, netrcbuffsize, file)) { - tok=strtok_r(netrcbuffer, " \t\n", &tok_buf); + tok = strtok_r(netrcbuffer, " \t\n", &tok_buf); + if(tok && *tok == '#') + /* treat an initial hash as a comment line */ + continue; while(!done && tok) { if((*loginp && **loginp) && (*passwordp && **passwordp)) { - done=TRUE; + done = TRUE; break; } @@ -133,22 +137,22 @@ int Curl_parsenetrc(const char *host, delimiter that starts the stuff entered for this machine, after this we need to search for 'login' and 'password'. */ - state=HOSTFOUND; + state = HOSTFOUND; } else if(strcasecompare("default", tok)) { - state=HOSTVALID; - retcode=0; /* we did find our host */ + state = HOSTVALID; + retcode = 0; /* we did find our host */ } break; case HOSTFOUND: if(strcasecompare(host, tok)) { /* and yes, this is our host! */ - state=HOSTVALID; - retcode=0; /* we did find our host */ + state = HOSTVALID; + retcode = 0; /* we did find our host */ } else /* not our host */ - state=NOTHING; + state = NOTHING; break; case HOSTVALID: /* we are now parsing sub-keywords concerning "our" host */ @@ -164,7 +168,7 @@ int Curl_parsenetrc(const char *host, goto out; } } - state_login=0; + state_login = 0; } else if(state_password) { if(state_our_login || !specific_login) { @@ -175,12 +179,12 @@ int Curl_parsenetrc(const char *host, goto out; } } - state_password=0; + state_password = 0; } else if(strcasecompare("login", tok)) - state_login=1; + state_login = 1; else if(strcasecompare("password", tok)) - state_password=1; + state_password = 1; else if(strcasecompare("machine", tok)) { /* ok, there's machine here go => */ state = HOSTFOUND; diff --git a/lib/non-ascii.c b/lib/non-ascii.c index 2f5de4c..92b2f8d 100644 --- a/lib/non-ascii.c +++ b/lib/non-ascii.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -82,7 +82,7 @@ CURLcode Curl_convert_clone(struct Curl_easy *data, CURLcode Curl_convert_to_network(struct Curl_easy *data, char *buffer, size_t length) { - if(data->set.convtonetwork) { + if(data && data->set.convtonetwork) { /* use translation callback */ CURLcode result = data->set.convtonetwork(buffer, length); if(result) { @@ -96,34 +96,37 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data, else { #ifdef HAVE_ICONV /* do the translation ourselves */ + iconv_t tmpcd = (iconv_t) -1; + iconv_t *cd = &tmpcd; char *input_ptr, *output_ptr; size_t in_bytes, out_bytes, rc; - int error; /* open an iconv conversion descriptor if necessary */ - if(data->outbound_cd == (iconv_t)-1) { - data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - if(data->outbound_cd == (iconv_t)-1) { - error = ERRNO; + if(data) + cd = &data->outbound_cd; + if(*cd == (iconv_t)-1) { + *cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, + CURL_ICONV_CODESET_OF_HOST); + if(*cd == (iconv_t)-1) { failf(data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_NETWORK, CURL_ICONV_CODESET_OF_HOST, - error, strerror(error)); + errno, strerror(errno)); return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; - rc = iconv(data->outbound_cd, (const char **)&input_ptr, &in_bytes, + rc = iconv(*cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); + if(!data) + iconv_close(tmpcd); if((rc == ICONV_ERROR) || (in_bytes != 0)) { - error = ERRNO; failf(data, "The Curl_convert_to_network iconv call failed with errno %i: %s", - error, strerror(error)); + errno, strerror(errno)); return CURLE_CONV_FAILED; } #else @@ -142,7 +145,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data, CURLcode Curl_convert_from_network(struct Curl_easy *data, char *buffer, size_t length) { - if(data->set.convfromnetwork) { + if(data && data->set.convfromnetwork) { /* use translation callback */ CURLcode result = data->set.convfromnetwork(buffer, length); if(result) { @@ -156,34 +159,37 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data, else { #ifdef HAVE_ICONV /* do the translation ourselves */ + iconv_t tmpcd = (iconv_t) -1; + iconv_t *cd = &tmpcd; char *input_ptr, *output_ptr; size_t in_bytes, out_bytes, rc; - int error; /* open an iconv conversion descriptor if necessary */ - if(data->inbound_cd == (iconv_t)-1) { - data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - if(data->inbound_cd == (iconv_t)-1) { - error = ERRNO; + if(data) + cd = &data->inbound_cd; + if(*cd == (iconv_t)-1) { + *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_OF_NETWORK); + if(*cd == (iconv_t)-1) { failf(data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK, - error, strerror(error)); + errno, strerror(errno)); return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; - rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes, + rc = iconv(*cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); + if(!data) + iconv_close(tmpcd); if((rc == ICONV_ERROR) || (in_bytes != 0)) { - error = ERRNO; failf(data, "Curl_convert_from_network iconv call failed with errno %i: %s", - error, strerror(error)); + errno, strerror(errno)); return CURLE_CONV_FAILED; } #else @@ -202,7 +208,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data, CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *buffer, size_t length) { - if(data->set.convfromutf8) { + if(data && data->set.convfromutf8) { /* use translation callback */ CURLcode result = data->set.convfromutf8(buffer, length); if(result) { @@ -216,35 +222,38 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data, else { #ifdef HAVE_ICONV /* do the translation ourselves */ - const char *input_ptr; + iconv_t tmpcd = (iconv_t) -1; + iconv_t *cd = &tmpcd; + char *input_ptr; char *output_ptr; size_t in_bytes, out_bytes, rc; - int error; /* open an iconv conversion descriptor if necessary */ - if(data->utf8_cd == (iconv_t)-1) { - data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8); - if(data->utf8_cd == (iconv_t)-1) { - error = ERRNO; + if(data) + cd = &data->utf8_cd; + if(*cd == (iconv_t)-1) { + *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_FOR_UTF8); + if(*cd == (iconv_t)-1) { failf(data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_FOR_UTF8, - error, strerror(error)); + errno, strerror(errno)); return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; - rc = iconv(data->utf8_cd, &input_ptr, &in_bytes, + rc = iconv(*cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); + if(!data) + iconv_close(tmpcd); if((rc == ICONV_ERROR) || (in_bytes != 0)) { - error = ERRNO; failf(data, "The Curl_convert_from_utf8 iconv call failed with errno %i: %s", - error, strerror(error)); + errno, strerror(errno)); return CURLE_CONV_FAILED; } if(output_ptr < input_ptr) { @@ -310,29 +319,4 @@ void Curl_convert_close(struct Curl_easy *data) #endif /* HAVE_ICONV */ } -/* - * Curl_convert_form() is used from http.c, this converts any form items that - need to be sent in the network encoding. Returns CURLE_OK on success. - */ -CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form) -{ - CURLcode result; - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - while(form) { - if(form->type == FORM_DATA) { - result = Curl_convert_to_network(data, form->line, form->length); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(result) - return result; - } - - form = form->next; - } - - return CURLE_OK; -} - #endif /* CURL_DOES_CONVERSIONS */ diff --git a/lib/non-ascii.h b/lib/non-ascii.h index e27f1f4..5fb5771 100644 --- a/lib/non-ascii.h +++ b/lib/non-ascii.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -48,7 +48,6 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data, char *buffer, size_t length); CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *buffer, size_t length); -CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form); #else #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK) #define Curl_convert_init(x) Curl_nop_stmt @@ -57,7 +56,6 @@ CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form); #define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK) #define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK) #define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK) -#define Curl_convert_form(a,b) CURLE_OK #endif #endif /* HEADER_CURL_NON_ASCII_H */ diff --git a/lib/openldap.c b/lib/openldap.c index 4b8cfb9..f294403 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010, Howard Chu, + * Copyright (C) 2010, 2017, Howard Chu, * Copyright (C) 2011 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which @@ -85,6 +85,7 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_LDAP, /* defport */ CURLPROTO_LDAP, /* protocol */ PROTOPT_NONE /* flags */ @@ -110,6 +111,7 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_LDAPS, /* defport */ CURLPROTO_LDAP, /* protocol */ PROTOPT_SSL /* flags */ @@ -150,7 +152,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn) { ldapconninfo *li; LDAPURLDesc *lud; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; int rc, proto; CURLcode status; @@ -196,7 +198,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done) (void)done; strcpy(hosturl, "ldap"); - ptr = hosturl+4; + ptr = hosturl + 4; if(conn->handler->flags & PROTOPT_SSL) *ptr++ = 's'; snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d", @@ -352,7 +354,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) int rc = 0; LDAPURLDesc *ludp = NULL; int msgid; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; connkeep(conn, "OpenLDAP do"); @@ -517,7 +519,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, else binary = 0; - for(i=0; bvals[i].bv_val != NULL; i++) { + for(i = 0; bvals[i].bv_val != NULL; i++) { int binval = 0; writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); if(writeerr) { @@ -547,7 +549,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, else { /* check for unprintable characters */ unsigned int j; - for(j=0; j, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -167,20 +167,20 @@ static const struct tzinfo tz[]= { RFC 1123) had their signs wrong. Here we use the correct signs to match actual military usage. */ - {"A", +1 * 60}, /* Alpha */ - {"B", +2 * 60}, /* Bravo */ - {"C", +3 * 60}, /* Charlie */ - {"D", +4 * 60}, /* Delta */ - {"E", +5 * 60}, /* Echo */ - {"F", +6 * 60}, /* Foxtrot */ - {"G", +7 * 60}, /* Golf */ - {"H", +8 * 60}, /* Hotel */ - {"I", +9 * 60}, /* India */ + {"A", 1 * 60}, /* Alpha */ + {"B", 2 * 60}, /* Bravo */ + {"C", 3 * 60}, /* Charlie */ + {"D", 4 * 60}, /* Delta */ + {"E", 5 * 60}, /* Echo */ + {"F", 6 * 60}, /* Foxtrot */ + {"G", 7 * 60}, /* Golf */ + {"H", 8 * 60}, /* Hotel */ + {"I", 9 * 60}, /* India */ /* "J", Juliet is not used as a timezone, to indicate the observer's local time */ - {"K", +10 * 60}, /* Kilo */ - {"L", +11 * 60}, /* Lima */ - {"M", +12 * 60}, /* Mike */ + {"K", 10 * 60}, /* Kilo */ + {"L", 11 * 60}, /* Lima */ + {"M", 12 * 60}, /* Mike */ {"N", -1 * 60}, /* November */ {"O", -2 * 60}, /* Oscar */ {"P", -3 * 60}, /* Papa */ @@ -205,14 +205,14 @@ static int checkday(const char *check, size_t len) { int i; const char * const *what; - bool found= FALSE; + bool found = FALSE; if(len > 3) what = &weekday[0]; else what = &Curl_wkday[0]; - for(i=0; i<7; i++) { + for(i = 0; i<7; i++) { if(strcasecompare(check, what[0])) { - found=TRUE; + found = TRUE; break; } what++; @@ -224,12 +224,12 @@ static int checkmonth(const char *check) { int i; const char * const *what; - bool found= FALSE; + bool found = FALSE; what = &Curl_month[0]; - for(i=0; i<12; i++) { + for(i = 0; i<12; i++) { if(strcasecompare(check, what[0])) { - found=TRUE; + found = TRUE; break; } what++; @@ -244,12 +244,12 @@ static int checktz(const char *check) { unsigned int i; const struct tzinfo *what; - bool found= FALSE; + bool found = FALSE; what = tz; - for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) { + for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) { if(strcasecompare(check, what->name)) { - found=TRUE; + found = TRUE; break; } what++; @@ -331,21 +331,21 @@ static time_t my_timegm(struct my_tm *tm) static int parsedate(const char *date, time_t *output) { time_t t = 0; - int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */ - int monnum=-1; /* month of the year number, 0-11 */ - int mdaynum=-1; /* day of month, 1 - 31 */ - int hournum=-1; - int minnum=-1; - int secnum=-1; - int yearnum=-1; - int tzoff=-1; + int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */ + int monnum = -1; /* month of the year number, 0-11 */ + int mdaynum = -1; /* day of month, 1 - 31 */ + int hournum = -1; + int minnum = -1; + int secnum = -1; + int yearnum = -1; + int tzoff = -1; struct my_tm tm; enum assume dignext = DATE_MDAY; const char *indate = date; /* save the original pointer */ int part = 0; /* max 6 parts */ while(*date && (part < 6)) { - bool found=FALSE; + bool found = FALSE; skip(&date); @@ -386,7 +386,7 @@ static int parsedate(const char *date, time_t *output) /* a digit */ int val; char *end; - int len=0; + int len = 0; if((secnum == -1) && (3 == sscanf(date, "%02d:%02d:%02d%n", &hournum, &minnum, &secnum, &len))) { @@ -404,12 +404,12 @@ static int parsedate(const char *date, time_t *output) int error; int old_errno; - old_errno = ERRNO; - SET_ERRNO(0); + old_errno = errno; + errno = 0; lval = strtol(date, &end, 10); - error = ERRNO; - if(error != old_errno) - SET_ERRNO(old_errno); + error = errno; + if(errno != old_errno) + errno = old_errno; if(error) return PARSEDATE_FAIL; diff --git a/lib/pingpong.c b/lib/pingpong.c index 5ed79b7..b8f2140 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -47,10 +47,10 @@ time_t Curl_pp_state_timeout(struct pingpong *pp) { struct connectdata *conn = pp->conn; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; time_t timeout_ms; /* in milliseconds */ time_t timeout2_ms; /* in milliseconds */ - long response_time= (data->set.server_response_timeout)? + long 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 @@ -85,10 +85,10 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) int rc; time_t interval_ms; time_t timeout_ms = Curl_pp_state_timeout(pp); - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; - if(timeout_ms <=0) { + if(timeout_ms <= 0) { failf(data, "server response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } @@ -270,7 +270,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, size_t *size) /* size of the response */ { ssize_t perline; /* count bytes per line */ - bool keepon=TRUE; + bool keepon = TRUE; ssize_t gotbytes; char *ptr; struct connectdata *conn = pp->conn; @@ -281,7 +281,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, *code = 0; /* 0 for errors or not done */ *size = 0; - ptr=buf + pp->nread_resp; + ptr = buf + pp->nread_resp; /* number of bytes in the current line, so far */ perline = (ssize_t)(ptr-pp->linestart_resp); @@ -297,7 +297,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, * it would have been populated with something of size int to begin * with, even though its datatype may be larger than an int. */ - DEBUGASSERT((ptr+pp->cache_size) <= (buf+data->set.buffer_size+1)); + DEBUGASSERT((ptr + pp->cache_size) <= (buf + data->set.buffer_size + 1)); memcpy(ptr, pp->cache, pp->cache_size); gotbytes = (ssize_t)pp->cache_size; free(pp->cache); /* free the cache */ @@ -351,7 +351,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, pp->nread_resp += gotbytes; for(i = 0; i < gotbytes; ptr++, i++) { perline++; - if(*ptr=='\n') { + if(*ptr == '\n') { /* a newline is CRLF in pp-talk, so the CR is ignored as the line isn't really terminated until the LF comes */ @@ -378,17 +378,17 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, start of the buffer and zero terminate, for old times sake */ size_t n = ptr - pp->linestart_resp; memmove(buf, pp->linestart_resp, n); - buf[n]=0; /* zero terminate */ - keepon=FALSE; - pp->linestart_resp = ptr+1; /* advance pointer */ + buf[n] = 0; /* zero terminate */ + keepon = FALSE; + pp->linestart_resp = ptr + 1; /* advance pointer */ i++; /* skip this before getting out */ *size = pp->nread_resp; /* size of the response */ pp->nread_resp = 0; /* restart */ break; } - perline=0; /* line starts over here */ - pp->linestart_resp = ptr+1; + perline = 0; /* line starts over here */ + pp->linestart_resp = ptr + 1; } } @@ -490,7 +490,7 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp) } else { free(pp->sendthis); - pp->sendthis=NULL; + pp->sendthis = NULL; pp->sendleft = pp->sendsize = 0; pp->response = Curl_tvnow(); } diff --git a/lib/pingpong.h b/lib/pingpong.h index ee1a59b..a2c8ff5 100644 --- a/lib/pingpong.h +++ b/lib/pingpong.h @@ -58,7 +58,7 @@ struct pingpong { server */ size_t sendleft; /* number of bytes left to send from the sendthis buffer */ size_t sendsize; /* total size of the sendthis buffer */ - struct timeval response; /* set to Curl_tvnow() when a command has been sent + struct curltime response; /* set to Curl_tvnow() 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. */ diff --git a/lib/pipeline.c b/lib/pipeline.c index b8d2037..4d41b04 100644 --- a/lib/pipeline.c +++ b/lib/pipeline.c @@ -230,28 +230,27 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites, return CURLM_OK; } +struct blacklist_node { + struct curl_llist_element list; + char server_name[1]; +}; + bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *server_name) { if(handle->multi && server_name) { - struct curl_llist *blacklist = + struct curl_llist *list = Curl_multi_pipelining_server_bl(handle->multi); - if(blacklist) { - struct curl_llist_element *curr; - - curr = blacklist->head; - while(curr) { - char *bl_server_name; - - bl_server_name = curr->ptr; - if(strncasecompare(bl_server_name, server_name, - strlen(bl_server_name))) { - infof(handle, "Server %s is blacklisted\n", server_name); - return TRUE; - } - curr = curr->next; + struct curl_llist_element *e = list->head; + while(e) { + struct blacklist_node *bl = (struct blacklist_node *)e; + if(strncasecompare(bl->server_name, server_name, + strlen(bl->server_name))) { + infof(handle, "Server %s is blacklisted\n", server_name); + return TRUE; } + e = e->next; } DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name)); @@ -259,11 +258,6 @@ bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, return FALSE; } -struct blacklist_node { - struct curl_llist_element list; - char server_name[1]; -}; - CURLMcode Curl_pipeline_set_server_blacklist(char **servers, struct curl_llist *list) { @@ -286,8 +280,7 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers, } strcpy(n->server_name, *servers); - Curl_llist_insert_next(list, list->tail, n->server_name, - &n->list); + Curl_llist_insert_next(list, list->tail, n, &n->list); servers++; } } diff --git a/lib/pop3.c b/lib/pop3.c index 3feb3be..5792a4a 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -125,6 +125,7 @@ const struct Curl_handler Curl_handler_pop3 = { ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_POP3, /* defport */ CURLPROTO_POP3, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ @@ -151,6 +152,7 @@ const struct Curl_handler Curl_handler_pop3s = { ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_POP3S, /* defport */ CURLPROTO_POP3S, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL @@ -158,58 +160,6 @@ const struct Curl_handler Curl_handler_pop3s = { }; #endif -#ifndef CURL_DISABLE_HTTP -/* - * HTTP-proxyed POP3 protocol handler. - */ - -static const struct Curl_handler Curl_handler_pop3_proxy = { - "POP3", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_POP3, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; - -#ifdef USE_SSL -/* - * HTTP-proxyed POP3S protocol handler. - */ - -static const struct Curl_handler Curl_handler_pop3s_proxy = { - "POP3S", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_POP3S, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; -#endif -#endif - /* SASL parameters for the pop3 protocol */ static const struct SASLproto saslpop3 = { "pop", /* The service name */ @@ -1355,31 +1305,6 @@ static CURLcode pop3_setup_connection(struct connectdata *conn) /* Clear the TLS upgraded flag */ conn->tls_upgraded = FALSE; - - /* Set up the proxy if necessary */ - if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel POP3 operations through the proxy, we - switch and use HTTP operations only */ -#ifndef CURL_DISABLE_HTTP - if(conn->handler == &Curl_handler_pop3) - conn->handler = &Curl_handler_pop3_proxy; - else { -#ifdef USE_SSL - conn->handler = &Curl_handler_pop3s_proxy; -#else - failf(data, "POP3S not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - - /* set it up as an HTTP connection instead */ - return conn->handler->setup_connection(conn); -#else - failf(data, "POP3 over http proxy requires HTTP support built-in!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - data->state.path++; /* don't include the initial slash */ return CURLE_OK; diff --git a/lib/progress.c b/lib/progress.c index cfaf404..00609d9 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -134,7 +134,7 @@ int Curl_pgrsDone(struct connectdata *conn) { int rc; struct Curl_easy *data = conn->data; - data->progress.lastshow=0; + data->progress.lastshow = 0; rc = Curl_pgrsUpdate(conn); /* the final (forced) update */ if(rc) return rc; @@ -149,21 +149,20 @@ int Curl_pgrsDone(struct connectdata *conn) return 0; } -/* reset all times except redirect, and reset the known transfer sizes */ -void Curl_pgrsResetTimesSizes(struct Curl_easy *data) +/* reset the known transfer sizes */ +void Curl_pgrsResetTransferSizes(struct Curl_easy *data) { - data->progress.t_nslookup = 0.0; - data->progress.t_connect = 0.0; - data->progress.t_pretransfer = 0.0; - data->progress.t_starttransfer = 0.0; - Curl_pgrsSetDownloadSize(data, -1); Curl_pgrsSetUploadSize(data, -1); } +/* + * @unittest: 1399 + */ void Curl_pgrsTime(struct Curl_easy *data, timerid timer) { - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); + time_t *delta = NULL; switch(timer) { default: @@ -177,45 +176,58 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer) case TIMER_STARTSINGLE: /* This is set at the start of each single fetch */ data->progress.t_startsingle = now; + data->progress.is_t_startransfer_set = false; break; - case TIMER_STARTACCEPT: - data->progress.t_acceptdata = Curl_tvnow(); + data->progress.t_acceptdata = now; break; - case TIMER_NAMELOOKUP: - data->progress.t_nslookup = - Curl_tvdiff_secs(now, data->progress.t_startsingle); + delta = &data->progress.t_nslookup; break; case TIMER_CONNECT: - data->progress.t_connect = - Curl_tvdiff_secs(now, data->progress.t_startsingle); + delta = &data->progress.t_connect; break; case TIMER_APPCONNECT: - data->progress.t_appconnect = - Curl_tvdiff_secs(now, data->progress.t_startsingle); + delta = &data->progress.t_appconnect; break; case TIMER_PRETRANSFER: - data->progress.t_pretransfer = - Curl_tvdiff_secs(now, data->progress.t_startsingle); + delta = &data->progress.t_pretransfer; break; case TIMER_STARTTRANSFER: - data->progress.t_starttransfer = - Curl_tvdiff_secs(now, data->progress.t_startsingle); - break; + delta = &data->progress.t_starttransfer; + /* prevent updating t_starttransfer unless: + * 1) this is the first time we're setting t_starttransfer + * 2) a redirect has occurred since the last time t_starttransfer was set + * This prevents repeated invocations of the function from incorrectly + * changing the t_starttransfer time. + */ + if(data->progress.is_t_startransfer_set) { + return; + } + else { + data->progress.is_t_startransfer_set = true; + break; + } case TIMER_POSTRANSFER: /* this is the normal end-of-transfer thing */ break; case TIMER_REDIRECT: - data->progress.t_redirect = Curl_tvdiff_secs(now, data->progress.start); + data->progress.t_redirect = Curl_tvdiff_us(now, data->progress.start); break; } + if(delta) { + time_t us = Curl_tvdiff_us(now, data->progress.t_startsingle); + if(!us) + us++; /* make sure at least one microsecond passed */ + *delta += us; + } } void Curl_pgrsStartNow(struct Curl_easy *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_tvnow(); + data->progress.is_t_startransfer_set = false; data->progress.ul_limit_start.tv_sec = 0; data->progress.ul_limit_start.tv_usec = 0; data->progress.dl_limit_start.tv_sec = 0; @@ -246,8 +258,8 @@ void Curl_pgrsStartNow(struct Curl_easy *data) long Curl_pgrsLimitWaitTime(curl_off_t cursize, curl_off_t startsize, curl_off_t limit, - struct timeval start, - struct timeval now) + struct curltime start, + struct curltime now) { curl_off_t size = cursize - startsize; time_t minimum; @@ -273,7 +285,7 @@ long Curl_pgrsLimitWaitTime(curl_off_t cursize, void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) { - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); data->progress.downloaded = size; @@ -291,7 +303,7 @@ void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size) { - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); data->progress.uploaded = size; @@ -337,12 +349,12 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size) */ int Curl_pgrsUpdate(struct connectdata *conn) { - struct timeval now; + struct curltime now; int result; char max5[6][10]; - curl_off_t dlpercen=0; - curl_off_t ulpercen=0; - curl_off_t total_percen=0; + curl_off_t dlpercen = 0; + curl_off_t ulpercen = 0; + curl_off_t total_percen = 0; curl_off_t total_transfer; curl_off_t total_expected_transfer; curl_off_t timespent; @@ -353,26 +365,26 @@ int Curl_pgrsUpdate(struct connectdata *conn) char time_left[10]; char time_total[10]; char time_spent[10]; - curl_off_t ulestimate=0; - curl_off_t dlestimate=0; + curl_off_t ulestimate = 0; + curl_off_t dlestimate = 0; curl_off_t total_estimate; - bool shownow=FALSE; + bool shownow = FALSE; now = Curl_tvnow(); /* what time is it */ /* The time spent so far (from the start) */ - data->progress.timespent = curlx_tvdiff_secs(now, data->progress.start); - timespent = (curl_off_t)data->progress.timespent; + data->progress.timespent = Curl_tvdiff_us(now, data->progress.start); + timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */ /* The average download speed this far */ data->progress.dlspeed = (curl_off_t) - ((double)data->progress.downloaded/ - (data->progress.timespent>0?data->progress.timespent:1)); + (data->progress.downloaded/ + (timespent>0?timespent:1)); /* The average upload speed this far */ data->progress.ulspeed = (curl_off_t) - ((double)data->progress.uploaded/ - (data->progress.timespent>0?data->progress.timespent:1)); + (data->progress.uploaded/ + (timespent>0?timespent:1)); /* Calculations done at most once a second, unless end is reached */ if(data->progress.lastshow != now.tv_sec) { @@ -380,11 +392,10 @@ int Curl_pgrsUpdate(struct connectdata *conn) data->progress.lastshow = now.tv_sec; - /* Let's do the "current speed" thing, which should use the fastest - of the dl/ul speeds. Store the faster speed at entry 'nowindex'. */ + /* Let's do the "current speed" thing, with the dl + ul speeds + combined. Store the speed at entry 'nowindex'. */ data->progress.speeder[ nowindex ] = - data->progress.downloaded>data->progress.uploaded? - data->progress.downloaded:data->progress.uploaded; + data->progress.downloaded + data->progress.uploaded; /* remember the exact time for this moment */ data->progress.speeder_time [ nowindex ] = now; @@ -397,7 +408,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of transfer. Imagine, after one second we have filled in two entries, after two seconds we've filled in three entries etc. */ - countindex = ((data->progress.speeder_c>=CURR_TIME)? + countindex = ((data->progress.speeder_c >= CURR_TIME)? CURR_TIME:data->progress.speeder_c) - 1; /* first of all, we don't do this if there's no counted seconds yet */ @@ -407,14 +418,14 @@ int Curl_pgrsUpdate(struct connectdata *conn) /* Get the index position to compare with the 'nowindex' position. Get the oldest entry possible. While we have less than CURR_TIME entries, the first entry will remain the oldest. */ - checkindex = (data->progress.speeder_c>=CURR_TIME)? + checkindex = (data->progress.speeder_c >= CURR_TIME)? data->progress.speeder_c%CURR_TIME:0; /* Figure out the exact time for the time span */ span_ms = Curl_tvdiff(now, data->progress.speeder_time[checkindex]); if(0 == span_ms) - span_ms=1; /* at least one millisecond MUST have passed */ + span_ms = 1; /* at least one millisecond MUST have passed */ /* Calculate the average speed the last 'span_ms' milliseconds */ { @@ -433,10 +444,9 @@ int Curl_pgrsUpdate(struct connectdata *conn) } } else - /* the first second we use the main average */ + /* the first second we use the average */ data->progress.current_speed = - (data->progress.ulspeed>data->progress.dlspeed)? - data->progress.ulspeed:data->progress.dlspeed; + data->progress.ulspeed + data->progress.dlspeed; } /* Calculations end */ @@ -445,22 +455,22 @@ int Curl_pgrsUpdate(struct connectdata *conn) if(data->set.fxferinfo) { /* There's a callback set, call that */ - result= data->set.fxferinfo(data->set.progress_client, - data->progress.size_dl, - data->progress.downloaded, - data->progress.size_ul, - data->progress.uploaded); + result = data->set.fxferinfo(data->set.progress_client, + data->progress.size_dl, + data->progress.downloaded, + data->progress.size_ul, + data->progress.uploaded); if(result) failf(data, "Callback aborted"); return result; } if(data->set.fprogress) { /* The older deprecated callback is set, call that */ - result= data->set.fprogress(data->set.progress_client, - (double)data->progress.size_dl, - (double)data->progress.downloaded, - (double)data->progress.size_ul, - (double)data->progress.uploaded); + result = data->set.fprogress(data->set.progress_client, + (double)data->progress.size_dl, + (double)data->progress.downloaded, + (double)data->progress.size_ul, + (double)data->progress.uploaded); if(result) failf(data, "Callback aborted"); return result; diff --git a/lib/progress.h b/lib/progress.h index 155ff04..9333ab2 100644 --- a/lib/progress.h +++ b/lib/progress.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,13 +47,13 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size); void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); int Curl_pgrsUpdate(struct connectdata *); -void Curl_pgrsResetTimesSizes(struct Curl_easy *data); +void Curl_pgrsResetTransferSizes(struct Curl_easy *data); void Curl_pgrsTime(struct Curl_easy *data, timerid timer); long Curl_pgrsLimitWaitTime(curl_off_t cursize, curl_off_t startsize, curl_off_t limit, - struct timeval start, - struct timeval now); + struct curltime start, + struct curltime now); /* Don't show progress for sizes smaller than: */ #define LEAST_SIZE_PROGRESS BUFSIZE diff --git a/lib/rand.c b/lib/rand.c index b6f40ac..2713a0a 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -86,7 +86,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) #endif if(!seeded) { - struct timeval now = curlx_tvnow(); + struct curltime now = curlx_tvnow(); infof(data, "WARNING: Using weak random seed\n"); randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; randseed = randseed * 1103515245 + 12345; diff --git a/lib/rtsp.c b/lib/rtsp.c index 1810cda..925da2c 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -81,6 +81,9 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, static CURLcode rtsp_setup_connection(struct connectdata *conn); +bool rtsp_connisdead(struct connectdata *check); +static unsigned int rtsp_conncheck(struct connectdata *check, + unsigned int checks_to_perform); /* this returns the socket to wait for in the DO and DOING state for the multi interface and then we're always _sending_ a request and thus we wait for @@ -117,6 +120,7 @@ const struct Curl_handler Curl_handler_rtsp = { ZERO_NULL, /* perform_getsock */ rtsp_disconnect, /* disconnect */ rtsp_rtp_readwrite, /* readwrite */ + rtsp_conncheck, /* connection_check */ PORT_RTSP, /* defport */ CURLPROTO_RTSP, /* protocol */ PROTOPT_NONE /* flags */ @@ -143,7 +147,7 @@ static CURLcode rtsp_setup_connection(struct connectdata *conn) * Instead, if it is readable, run Curl_connalive() to peek at the socket * and distinguish between closed and data. */ -bool Curl_rtsp_connisdead(struct connectdata *check) +bool rtsp_connisdead(struct connectdata *check) { int sval; bool ret_val = TRUE; @@ -165,6 +169,23 @@ bool Curl_rtsp_connisdead(struct connectdata *check) return ret_val; } +/* + * Function to check on various aspects of a connection. + */ +static unsigned int rtsp_conncheck(struct connectdata *check, + unsigned int checks_to_perform) +{ + unsigned int ret_val = CONNRESULT_NONE; + + if(checks_to_perform & CONNCHECK_ISDEAD) { + if(rtsp_connisdead(check)) + ret_val |= CONNRESULT_DEAD; + } + + return ret_val; +} + + static CURLcode rtsp_connect(struct connectdata *conn, bool *done) { CURLcode httpStatus; @@ -229,7 +250,7 @@ static CURLcode rtsp_done(struct connectdata *conn, static CURLcode rtsp_do(struct connectdata *conn, bool *done) { struct Curl_easy *data = conn->data; - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; Curl_RtspReq rtspreq = data->set.rtspreq; struct RTSP *rtsp = data->req.protop; struct HTTP *http; @@ -728,14 +749,28 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len) struct Curl_easy *data = conn->data; size_t wrote; curl_write_callback writeit; + void *user_ptr; if(len == 0) { failf(data, "Cannot write a 0 size RTP packet."); return CURLE_WRITE_ERROR; } - writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func; - wrote = writeit(ptr, 1, len, data->set.rtp_out); + /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that + function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP + data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA + pointer to write out the RTP data. */ + if(data->set.fwrite_rtp) { + writeit = data->set.fwrite_rtp; + user_ptr = data->set.rtp_out; + } + else + { + writeit = data->set.fwrite_func; + user_ptr = data->set.out; + } + + wrote = writeit(ptr, 1, len, user_ptr); if(CURL_WRITEFUNC_PAUSE == wrote) { failf(data, "Cannot pause RTP"); diff --git a/lib/rtsp.h b/lib/rtsp.h index 5a8d555..8375a53 100644 --- a/lib/rtsp.h +++ b/lib/rtsp.h @@ -25,13 +25,11 @@ extern const struct Curl_handler Curl_handler_rtsp; -bool Curl_rtsp_connisdead(struct connectdata *check); CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header); #else /* disabled */ #define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN -#define Curl_rtsp_connisdead(x) TRUE #endif /* CURL_DISABLE_RTSP */ diff --git a/lib/security.c b/lib/security.c index f4a8763..a2e4a35 100644 --- a/lib/security.c +++ b/lib/security.c @@ -7,7 +7,7 @@ * rewrite to work around the paragraph 2 in the BSD licenses as explained * below. * - * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan + * Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * * Copyright (C) 2001 - 2015, Daniel Stenberg, , et al. @@ -115,7 +115,7 @@ static char level_to_char(int level) static int ftp_send_command(struct connectdata *conn, const char *message, ...) { int ftp_code; - ssize_t nread=0; + ssize_t nread = 0; va_list args; char print_buffer[50]; diff --git a/lib/select.c b/lib/select.c index f49314b..f6fecaf 100644 --- a/lib/select.c +++ b/lib/select.c @@ -78,7 +78,7 @@ int Curl_wait_ms(int timeout_ms) #ifndef HAVE_POLL_FINE struct timeval pending_tv; #endif - struct timeval initial_tv; + struct curltime initial_tv; int pending_ms; int error; #endif @@ -158,7 +158,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ fd_set fds_err; curl_socket_t maxfd; #endif - struct timeval initial_tv = {0, 0}; + struct curltime initial_tv = {0, 0}; int pending_ms = 0; int error; int r; @@ -398,7 +398,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) fd_set fds_err; curl_socket_t maxfd; #endif - struct timeval initial_tv = {0, 0}; + struct curltime initial_tv = {0, 0}; bool fds_none = TRUE; unsigned int i; int pending_ms = 0; @@ -571,8 +571,8 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) * * Return values are the same as select's. */ -int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, - fd_set* excepts, struct timeval* tv) +int tpf_select_libcurl(int maxfds, fd_set *reads, fd_set *writes, + fd_set *excepts, struct timeval *tv) { int rc; diff --git a/lib/select.h b/lib/select.h index 4ed5dd2..4351786 100644 --- a/lib/select.h +++ b/lib/select.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,7 +36,8 @@ #if !defined(HAVE_STRUCT_POLLFD) && \ !defined(HAVE_SYS_POLL_H) && \ - !defined(HAVE_POLL_H) + !defined(HAVE_POLL_H) && \ + !defined(POLLIN) #define POLLIN 0x01 #define POLLPRI 0x02 diff --git a/lib/sendf.c b/lib/sendf.c index 595c361..7564cb3 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -63,7 +63,7 @@ static size_t convert_lineends(struct Curl_easy *data, if(*startPtr == '\n') { /* This block of incoming data starts with the previous block's LF so get rid of it */ - memmove(startPtr, startPtr+1, size-1); + memmove(startPtr, startPtr + 1, size-1); size--; /* and it wasn't a bare CR but a CRLF conversion instead */ data->state.crlf_conversions++; @@ -75,7 +75,7 @@ static size_t convert_lineends(struct Curl_easy *data, inPtr = outPtr = memchr(startPtr, '\r', size); if(inPtr) { /* at least one CR, now look for CRLF */ - while(inPtr < (startPtr+size-1)) { + while(inPtr < (startPtr + size-1)) { /* note that it's size-1, so we'll never look past the last byte */ if(memcmp(inPtr, "\r\n", 2) == 0) { /* CRLF found, bump past the CR and copy the NL */ @@ -98,7 +98,7 @@ static size_t convert_lineends(struct Curl_easy *data, inPtr++; } /* end of while loop */ - if(inPtr < startPtr+size) { + if(inPtr < startPtr + size) { /* handle last byte */ if(*inPtr == '\r') { /* deal with a CR at the end of the buffer */ @@ -112,7 +112,7 @@ static size_t convert_lineends(struct Curl_easy *data, } outPtr++; } - if(outPtr < startPtr+size) + if(outPtr < startPtr + size) /* tidy up by null terminating the now shorter data */ *outPtr = '\0'; @@ -279,7 +279,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, if(!s) return CURLE_OUT_OF_MEMORY; /* failure */ - bytes_written=0; + bytes_written = 0; write_len = strlen(s); sptr = s; @@ -387,7 +387,7 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num, #endif ) { /* this is just a case of EWOULDBLOCK */ - bytes_written=0; + bytes_written = 0; *code = CURLE_AGAIN; } else { @@ -480,7 +480,7 @@ static CURLcode pausewrite(struct Curl_easy *data, bool newtype = TRUE; if(s->tempcount) { - for(i=0; i< s->tempcount; i++) { + for(i = 0; i< s->tempcount; i++) { if(s->tempwrite[i].type == type) { /* data for this type exists */ newtype = FALSE; @@ -704,7 +704,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ us use the correct ssl handle. */ int num = (sockfd == conn->sock[SECONDARYSOCKET]); - *n=0; /* reset amount to zero */ + *n = 0; /* reset amount to zero */ /* If session can pipeline, check connection buffer */ if(pipelining) { @@ -823,8 +823,8 @@ int Curl_debug(struct Curl_easy *data, curl_infotype type, int rc; if(data->set.printhost && conn && conn->host.dispname) { char buffer[160]; - const char *t=NULL; - const char *w="Data"; + const char *t = NULL; + const char *w = "Data"; switch(type) { case CURLINFO_HEADER_IN: w = "Header"; diff --git a/lib/smb.c b/lib/smb.c index 5b1ffa9..13dfd51 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -34,7 +34,7 @@ #include #ifdef CURL_WINDOWS_APP #define getpid GetCurrentProcessId -#else +#elif !defined(MSDOS) #define getpid _getpid #endif #endif @@ -85,6 +85,7 @@ const struct Curl_handler Curl_handler_smb = { ZERO_NULL, /* perform_getsock */ smb_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_SMB, /* defport */ CURLPROTO_SMB, /* protocol */ PROTOPT_NONE /* flags */ @@ -109,6 +110,7 @@ const struct Curl_handler Curl_handler_smbs = { ZERO_NULL, /* perform_getsock */ smb_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_SMBS, /* defport */ CURLPROTO_SMBS, /* protocol */ PROTOPT_SSL /* flags */ @@ -713,6 +715,23 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done) return CURLE_OK; } +/* + * Convert a timestamp from the Windows world (100 nsec units from + * 1 Jan 1601) to Posix time. + */ +static void get_posix_time(long *_out, const void *_in) +{ +#ifdef HAVE_LONGLONG + long long timestamp = *(long long *) _in; +#else + unsigned __int64 timestamp = *(unsigned __int64 *) _in; +#endif + + timestamp -= 116444736000000000ULL; + timestamp /= 10000000; + *_out = (long) timestamp; +} + static CURLcode smb_request_state(struct connectdata *conn, bool *done) { struct smb_request *req = conn->data->req.protop; @@ -723,6 +742,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) unsigned short off; CURLcode result; void *msg = NULL; + const struct smb_nt_create_response *smb_m; /* Start the request */ if(req->state == SMB_REQUESTING) { @@ -765,7 +785,8 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) next_state = SMB_TREE_DISCONNECT; break; } - req->fid = smb_swap16(((struct smb_nt_create_response *)msg)->fid); + smb_m = (const struct smb_nt_create_response*) msg; + req->fid = smb_swap16(smb_m->fid); conn->data->req.offset = 0; if(conn->data->set.upload) { conn->data->req.size = conn->data->state.infilesize; @@ -773,9 +794,11 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) next_state = SMB_UPLOAD; } else { - conn->data->req.size = - smb_swap64(((struct smb_nt_create_response *)msg)->end_of_file); + smb_m = (const struct smb_nt_create_response*) msg; + conn->data->req.size = smb_swap64(smb_m->end_of_file); Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size); + if(conn->data->set.get_filetime) + get_posix_time(&conn->data->info.filetime, &smb_m->last_change_time); next_state = SMB_DOWNLOAD; } break; diff --git a/lib/smtp.c b/lib/smtp.c index fe064cb..de2dd33 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -67,6 +67,7 @@ #include "transfer.h" #include "escape.h" #include "http.h" /* for HTTP proxy tunnel stuff */ +#include "mime.h" #include "socks.h" #include "smtp.h" #include "strtoofft.h" @@ -124,6 +125,7 @@ const struct Curl_handler Curl_handler_smtp = { ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_SMTP, /* defport */ CURLPROTO_SMTP, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ @@ -150,6 +152,7 @@ const struct Curl_handler Curl_handler_smtps = { ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_SMTPS, /* defport */ CURLPROTO_SMTPS, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL @@ -157,58 +160,6 @@ const struct Curl_handler Curl_handler_smtps = { }; #endif -#ifndef CURL_DISABLE_HTTP -/* - * HTTP-proxyed SMTP protocol handler. - */ - -static const struct Curl_handler Curl_handler_smtp_proxy = { - "SMTP", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_SMTP, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; - -#ifdef USE_SSL -/* - * HTTP-proxyed SMTPS protocol handler. - */ - -static const struct Curl_handler Curl_handler_smtps_proxy = { - "SMTPS", /* scheme */ - Curl_http_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - PORT_SMTPS, /* defport */ - CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ -}; -#endif -#endif - /* SASL parameters for the smtp protocol */ static const struct SASLproto saslsmtp = { "smtp", /* The service name */ @@ -580,8 +531,40 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) } } + /* Prepare the mime data if some. */ + if(data->set.mimepost.kind != MIMEKIND_NONE) { + /* Use the whole structure as data. */ + data->set.mimepost.flags &= ~MIME_BODY_ONLY; + + /* Add external headers and mime version. */ + curl_mime_headers(&data->set.mimepost, data->set.headers, 0); + result = Curl_mime_prepare_headers(&data->set.mimepost, NULL, + NULL, MIMESTRATEGY_MAIL); + + if(!result) + if(!Curl_checkheaders(conn, "Mime-Version")) + result = Curl_mime_add_header(&data->set.mimepost.curlheaders, + "Mime-Version: 1.0"); + + /* Make sure we will read the entire mime structure. */ + if(!result) + result = Curl_mime_rewind(&data->set.mimepost); + + if(result) { + free(from); + free(auth); + return result; + } + + data->state.infilesize = Curl_mime_size(&data->set.mimepost); + + /* Read from mime structure. */ + data->state.fread_func = (curl_read_callback) Curl_mime_read; + data->state.in = (void *) &data->set.mimepost; + } + /* Calculate the optional SIZE parameter */ - if(conn->proto.smtpc.size_supported && conn->data->state.infilesize > 0) { + if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) { size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize); if(!size) { @@ -1209,7 +1192,8 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, connclose(conn, "SMTP done with bad status"); /* marked for closure */ result = status; /* use the already set error code */ } - else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) { + else if(!data->set.connect_only && data->set.mail_rcpt && + (data->set.upload || data->set.mimepost.kind)) { /* Calculate the EOB taking into account any terminating CRLF from the previous line of the email or the CRLF of the DATA command when there is "no mail data". RFC-5321, sect. 4.1.1.4. @@ -1299,7 +1283,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected, smtp->rcpt = data->set.mail_rcpt; /* Start the first command in the DO phase */ - if(data->set.upload && data->set.mail_rcpt) + if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt) /* MAIL transfer */ result = smtp_perform_mail(conn); else @@ -1451,30 +1435,6 @@ static CURLcode smtp_setup_connection(struct connectdata *conn) /* Clear the TLS upgraded flag */ conn->tls_upgraded = FALSE; - /* Set up the proxy if necessary */ - if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel SMTP operations through the proxy, we - switch and use HTTP operations only */ -#ifndef CURL_DISABLE_HTTP - if(conn->handler == &Curl_handler_smtp) - conn->handler = &Curl_handler_smtp_proxy; - else { -#ifdef USE_SSL - conn->handler = &Curl_handler_smtps_proxy; -#else - failf(data, "SMTPS not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - /* set it up as a HTTP connection instead */ - return conn->handler->setup_connection(conn); - -#else - failf(data, "SMTP over http proxy requires HTTP support built-in!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - /* Initialise the SMTP layer */ result = smtp_init(conn); if(result) diff --git a/lib/socks.c b/lib/socks.c index 97a44b2..e64cb98 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -105,7 +105,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ * Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" * Nonsupport "Identification Protocol (RFC1413)" */ -CURLcode Curl_SOCKS4(const char *proxy_name, +CURLcode Curl_SOCKS4(const char *proxy_user, const char *hostname, int remote_port, int sockindex, @@ -154,7 +154,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, /* DNS resolve only for SOCKS4, not SOCKS4a */ if(!protocol4a) { struct Curl_dns_entry *dns; - Curl_addrinfo *hp=NULL; + Curl_addrinfo *hp = NULL; int rc; rc = Curl_resolv(conn, hostname, remote_port, &dns); @@ -171,7 +171,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, * returns a Curl_addrinfo pointer that may not always look the same. */ if(dns) - hp=dns->addr; + hp = dns->addr; if(hp) { char buf[64]; Curl_printable_address(hp, buf, sizeof(buf)); @@ -206,14 +206,14 @@ CURLcode Curl_SOCKS4(const char *proxy_name, * This is currently not supporting "Identification Protocol (RFC1413)". */ socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ - if(proxy_name) { - size_t plen = strlen(proxy_name); + if(proxy_user) { + size_t plen = strlen(proxy_user); if(plen >= sizeof(socksreq) - 8) { failf(data, "Too long SOCKS proxy name, can't use!\n"); return CURLE_COULDNT_CONNECT; } /* copy the proxy name WITH trailing zero */ - memcpy(socksreq + 8, proxy_name, plen+1); + memcpy(socksreq + 8, proxy_user, plen + 1); } /* @@ -306,7 +306,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, ", request rejected or failed.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; case 92: @@ -316,7 +316,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, "identd on the client.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; case 93: @@ -326,7 +326,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, "report different user-ids.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; default: @@ -335,7 +335,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, ", Unknown.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; } @@ -350,7 +350,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, * This function logs in to a SOCKS5 proxy and sends the specifics to the final * destination server. */ -CURLcode Curl_SOCKS5(const char *proxy_name, +CURLcode Curl_SOCKS5(const char *proxy_user, const char *proxy_password, const char *hostname, int remote_port, @@ -375,6 +375,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, */ unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ + int idx; ssize_t actualread; ssize_t written; int result; @@ -386,6 +387,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; const size_t hostname_len = strlen(hostname); ssize_t len = 0; + const unsigned long auth = data->set.socks5auth; + bool allow_gssapi = FALSE; if(conn->bits.httpproxy) infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n", @@ -426,18 +429,29 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_COULDNT_CONNECT; } - socksreq[0] = 5; /* version */ + if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + infof(conn->data, + "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n", + auth); + if(!(auth & CURLAUTH_BASIC)) + /* disable username/password auth */ + proxy_user = NULL; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - socksreq[1] = (char)(proxy_name ? 3 : 2); /* number of methods (below) */ - socksreq[2] = 0; /* no authentication */ - socksreq[3] = 1; /* GSS-API */ - socksreq[4] = 2; /* username/password */ -#else - socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */ - socksreq[2] = 0; /* no authentication */ - socksreq[3] = 2; /* username/password */ + if(auth & CURLAUTH_GSSAPI) + allow_gssapi = TRUE; #endif + idx = 0; + socksreq[idx++] = 5; /* version */ + idx++; /* reserve for the number of authentication methods */ + socksreq[idx++] = 0; /* no authentication */ + if(allow_gssapi) + socksreq[idx++] = 1; /* GSS-API */ + if(proxy_user) + socksreq[idx++] = 2; /* username/password */ + /* write the number of authentication methods */ + socksreq[1] = (unsigned char) (idx - 2); + (void)curlx_nonblock(sock, FALSE); infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port); @@ -469,7 +483,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, FALSE); - result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); + result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); if(result || (actualread != 2)) { failf(data, "Unable to receive initial SOCKS5 response."); return CURLE_COULDNT_CONNECT; @@ -484,7 +498,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, ; } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - else if(socksreq[1] == 1) { + else if(allow_gssapi && (socksreq[1] == 1)) { code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn); if(code) { failf(data, "Unable to negotiate SOCKS5 GSS-API context."); @@ -494,13 +508,13 @@ CURLcode Curl_SOCKS5(const char *proxy_name, #endif else if(socksreq[1] == 2) { /* Needs user name and password */ - size_t proxy_name_len, proxy_password_len; - if(proxy_name && proxy_password) { - proxy_name_len = strlen(proxy_name); + size_t proxy_user_len, proxy_password_len; + if(proxy_user && proxy_password) { + proxy_user_len = strlen(proxy_user); proxy_password_len = strlen(proxy_password); } else { - proxy_name_len = 0; + proxy_user_len = 0; proxy_password_len = 0; } @@ -513,10 +527,10 @@ CURLcode Curl_SOCKS5(const char *proxy_name, */ len = 0; socksreq[len++] = 1; /* username/pw subnegotiation version */ - socksreq[len++] = (unsigned char) proxy_name_len; - if(proxy_name && proxy_name_len) - memcpy(socksreq + len, proxy_name, proxy_name_len); - len += proxy_name_len; + socksreq[len++] = (unsigned char) proxy_user_len; + if(proxy_user && proxy_user_len) + memcpy(socksreq + len, proxy_user, proxy_user_len); + len += proxy_user_len; socksreq[len++] = (unsigned char) proxy_password_len; if(proxy_password && proxy_password_len) memcpy(socksreq + len, proxy_password, proxy_password_len); @@ -528,7 +542,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_COULDNT_CONNECT; } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); + result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); if(result || (actualread != 2)) { failf(data, "Unable to receive SOCKS5 sub-negotiation response."); return CURLE_COULDNT_CONNECT; @@ -545,17 +559,13 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } else { /* error */ -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(socksreq[1] == 255) { -#else - if(socksreq[1] == 1) { + if(!allow_gssapi && (socksreq[1] == 1)) { failf(data, "SOCKS5 GSSAPI per-message authentication is not supported."); return CURLE_COULDNT_CONNECT; } if(socksreq[1] == 255) { -#endif - if(!proxy_name || !*proxy_name) { + if(!proxy_user || !*proxy_user) { failf(data, "No authentication method was acceptable. (It is quite likely" " that the SOCKS5 server wanted a username/password, since none" @@ -605,7 +615,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, * returns a Curl_addrinfo pointer that may not always look the same. */ if(dns) - hp=dns->addr; + hp = dns->addr; if(hp) { int i; char buf[64]; diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 54d0635..96948ac 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009, 2011, Markus Moeller, - * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2009, Markus Moeller, + * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -65,7 +65,7 @@ static int check_gss_err(struct Curl_easy *data, &msg_ctx, &status_string); if(maj_stat == GSS_S_COMPLETE) { if(sizeof(buf) > len + status_string.length + 1) { - strcpy(buf+len, (char *) status_string.value); + strcpy(buf + len, (char *) status_string.value); len += status_string.length; } gss_release_buffer(&min_stat, &status_string); @@ -74,7 +74,7 @@ static int check_gss_err(struct Curl_easy *data, gss_release_buffer(&min_stat, &status_string); } if(sizeof(buf) > len + 3) { - strcpy(buf+len, ".\n"); + strcpy(buf + len, ".\n"); len += 2; } msg_ctx = 0; @@ -86,7 +86,7 @@ static int check_gss_err(struct Curl_easy *data, &msg_ctx, &status_string); if(maj_stat == GSS_S_COMPLETE) { if(sizeof(buf) > len + status_string.length) - strcpy(buf+len, (char *) status_string.value); + strcpy(buf + len, (char *) status_string.value); gss_release_buffer(&min_stat, &status_string); break; } @@ -119,7 +119,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_name_t server = GSS_C_NO_NAME; gss_name_t gss_client_name = GSS_C_NO_NAME; unsigned short us_length; - char *user=NULL; + char *user = NULL; unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; @@ -146,11 +146,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } else { service.value = malloc(serviceptr_length + - strlen(conn->socks_proxy.host.name)+2); + strlen(conn->socks_proxy.host.name) + 2); if(!service.value) return CURLE_OUT_OF_MEMORY; - service.length = serviceptr_length + strlen(conn->socks_proxy.host.name)+1; - snprintf(service.value, service.length+1, "%s@%s", + service.length = serviceptr_length + + strlen(conn->socks_proxy.host.name) + 1; + snprintf(service.value, service.length + 1, "%s@%s", serviceptr, conn->socks_proxy.host.name); gss_major_status = gss_import_name(&gss_minor_status, &service, @@ -196,7 +197,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 1; /* authentication message type */ us_length = htons((short)gss_send_token.length); - memcpy(socksreq+2, &us_length, sizeof(short)); + memcpy(socksreq + 2, &us_length, sizeof(short)); code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); if(code || (4 != written)) { @@ -236,7 +237,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, * +----+------+-----+----------------+ */ - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); + result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive GSS-API authentication response."); gss_release_name(&gss_status, &server); @@ -261,11 +262,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - memcpy(&us_length, socksreq+2, sizeof(short)); + memcpy(&us_length, socksreq + 2, sizeof(short)); us_length = ntohs(us_length); - gss_recv_token.length=us_length; - gss_recv_token.value=malloc(us_length); + gss_recv_token.length = us_length; + gss_recv_token.value = malloc(us_length); if(!gss_recv_token.value) { failf(data, "Could not allocate memory for GSS-API authentication " @@ -275,8 +276,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } - result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, &actualread); + result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, + gss_recv_token.length, &actualread); if(result || (actualread != us_length)) { failf(data, "Failed to receive GSS-API authentication token."); @@ -312,7 +313,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, failf(data, "Failed to determine user name."); return CURLE_COULDNT_CONNECT; } - user=malloc(gss_send_token.length+1); + user = malloc(gss_send_token.length + 1); if(!user) { gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); @@ -326,7 +327,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_send_token); infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user); free(user); - user=NULL; + user = NULL; /* Do encryption */ socksreq[0] = 1; /* GSS-API subnegotiation version */ @@ -341,7 +342,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_enc = 1; infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", - (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality")); + (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality")); /* force for the moment to no data protection */ gss_enc = 0; /* @@ -376,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, */ if(data->set.socks5_gssapi_nec) { us_length = htons((short)1); - memcpy(socksreq+2, &us_length, sizeof(short)); + memcpy(socksreq + 2, &us_length, sizeof(short)); } else { gss_send_token.length = 1; @@ -401,7 +402,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_send_token); us_length = htons((short)gss_w_token.length); - memcpy(socksreq+2, &us_length, sizeof(short)); + memcpy(socksreq + 2, &us_length, sizeof(short)); } code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); @@ -433,7 +434,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_w_token); } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); + result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive GSS-API encryption response."); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -455,17 +456,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - memcpy(&us_length, socksreq+2, sizeof(short)); + memcpy(&us_length, socksreq + 2, sizeof(short)); us_length = ntohs(us_length); - gss_recv_token.length= us_length; - gss_recv_token.value=malloc(gss_recv_token.length); + gss_recv_token.length = us_length; + gss_recv_token.value = malloc(gss_recv_token.length); if(!gss_recv_token.value) { gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OUT_OF_MEMORY; } - result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, &actualread); + result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, + gss_recv_token.length, &actualread); if(result || (actualread != us_length)) { failf(data, "Failed to receive GSS-API encryptrion type."); @@ -513,8 +514,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } infof(data, "SOCKS5 access with%s protection granted.\n", - (socksreq[0]==0)?"out GSS-API data": - ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality")); + (socksreq[0] == 0)?"out GSS-API data": + ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); conn->socks5_gssapi_enctype = socksreq[0]; if(socksreq[0] == 0) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index edc73ad..34699d3 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. * Copyright (C) 2009, 2011, Markus Moeller, * * This software is licensed as described in the file COPYING, which @@ -108,7 +108,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, if(!service_name) return CURLE_OUT_OF_MEMORY; snprintf(service_name, service_length + - strlen(conn->socks_proxy.host.name)+2, "%s/%s", + strlen(conn->socks_proxy.host.name) + 2, "%s/%s", service, conn->socks_proxy.host.name); } @@ -199,7 +199,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 1; /* authentication message type */ us_length = htons((short)sspi_send_token.cbBuffer); - memcpy(socksreq+2, &us_length, sizeof(short)); + memcpy(socksreq + 2, &us_length, sizeof(short)); code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); if(code || (4 != written)) { @@ -283,7 +283,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - memcpy(&us_length, socksreq+2, sizeof(short)); + memcpy(&us_length, socksreq + 2, sizeof(short)); us_length = ntohs(us_length); sspi_recv_token.cbBuffer = us_length; @@ -341,7 +341,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_enc = 1; infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", - (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") ); + (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") ); /* force to no data protection, avoid encryption/decryption for now */ gss_enc = 0; /* @@ -377,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, if(data->set.socks5_gssapi_nec) { us_length = htons((short)1); - memcpy(socksreq+2, &us_length, sizeof(short)); + memcpy(socksreq + 2, &us_length, sizeof(short)); } else { status = s_pSecFn->QueryContextAttributes(&sspi_context, @@ -445,8 +445,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); memcpy((PUCHAR) sspi_send_token.pvBuffer - +sspi_w_token[0].cbBuffer - +sspi_w_token[1].cbBuffer, + + sspi_w_token[0].cbBuffer + + sspi_w_token[1].cbBuffer, sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); @@ -460,7 +460,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, sspi_w_token[2].cbBuffer = 0; us_length = htons((short)sspi_send_token.cbBuffer); - memcpy(socksreq+2, &us_length, sizeof(short)); + memcpy(socksreq + 2, &us_length, sizeof(short)); } code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); @@ -517,7 +517,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - memcpy(&us_length, socksreq+2, sizeof(short)); + memcpy(&us_length, socksreq + 2, sizeof(short)); us_length = ntohs(us_length); sspi_w_token[0].cbBuffer = us_length; @@ -588,8 +588,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } infof(data, "SOCKS5 access with%s protection granted.\n", - (socksreq[0]==0)?"out GSS-API data": - ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality")); + (socksreq[0] == 0)?"out GSS-API data": + ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); /* For later use if encryption is required conn->socks5_gssapi_enctype = socksreq[0]; diff --git a/lib/speedcheck.c b/lib/speedcheck.c index 8addedd..fe669f1 100644 --- a/lib/speedcheck.c +++ b/lib/speedcheck.c @@ -30,14 +30,14 @@ void Curl_speedinit(struct Curl_easy *data) { - memset(&data->state.keeps_speed, 0, sizeof(struct timeval)); + memset(&data->state.keeps_speed, 0, sizeof(struct curltime)); } /* * @unittest: 1606 */ CURLcode Curl_speedcheck(struct Curl_easy *data, - struct timeval now) + struct curltime now) { if((data->progress.current_speed >= 0) && data->set.low_speed_time) { if(data->progress.current_speed < data->set.low_speed_limit) { diff --git a/lib/speedcheck.h b/lib/speedcheck.h index 7dbe3d6..5c2dc9a 100644 --- a/lib/speedcheck.h +++ b/lib/speedcheck.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,6 +28,6 @@ void Curl_speedinit(struct Curl_easy *data); CURLcode Curl_speedcheck(struct Curl_easy *data, - struct timeval now); + struct curltime now); #endif /* HEADER_CURL_SPEEDCHECK_H */ diff --git a/lib/splay.c b/lib/splay.c index 1b301f9..69af446 100644 --- a/lib/splay.c +++ b/lib/splay.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1997 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,7 +37,7 @@ * Splay using the key i (which may or may not be in the tree.) The starting * root is t. */ -struct Curl_tree *Curl_splay(struct timeval i, +struct Curl_tree *Curl_splay(struct curltime i, struct Curl_tree *t) { struct Curl_tree N, *l, *r, *y; @@ -97,24 +97,26 @@ struct Curl_tree *Curl_splay(struct timeval i, * * @unittest: 1309 */ -struct Curl_tree *Curl_splayinsert(struct timeval i, +struct Curl_tree *Curl_splayinsert(struct curltime i, struct Curl_tree *t, struct Curl_tree *node) { - static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */ + static const struct curltime KEY_NOTUSED = { + (time_t)-1, (unsigned int)-1 + }; /* will *NEVER* appear */ if(node == NULL) return t; if(t != NULL) { t = Curl_splay(i, t); - if(compare(i, t->key)==0) { + if(compare(i, t->key) == 0) { /* There already exists a node in the tree with the very same key. Build a doubly-linked circular list of nodes. We add the new 'node' struct to the end of this list. */ node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED - to quickly identify this node as a subnode */ + to quickly identify this node as a subnode */ node->samen = t; node->samep = t->samep; t->samep->samen = node; @@ -149,11 +151,11 @@ struct Curl_tree *Curl_splayinsert(struct timeval i, /* Finds and deletes the best-fit node from the tree. Return a pointer to the resulting tree. best-fit means the smallest node if it is not larger than the key */ -struct Curl_tree *Curl_splaygetbest(struct timeval i, - struct Curl_tree *t, - struct Curl_tree **removed) +struct Curl_tree *Curl_splaygetbest(struct curltime i, + struct Curl_tree *t, + struct Curl_tree **removed) { - static struct timeval tv_zero = {0, 0}; + static struct curltime tv_zero = {0, 0}; struct Curl_tree *x; if(!t) { @@ -209,7 +211,9 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, struct Curl_tree *removenode, struct Curl_tree **newroot) { - static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */ + static const struct curltime KEY_NOTUSED = { + (time_t)-1, (unsigned int)-1 + }; /* will *NEVER* appear */ struct Curl_tree *x; if(!t || !removenode) diff --git a/lib/splay.h b/lib/splay.h index da81894..4612ec2 100644 --- a/lib/splay.h +++ b/lib/splay.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1997 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,30 +22,31 @@ * ***************************************************************************/ #include "curl_setup.h" +#include "timeval.h" struct Curl_tree { struct Curl_tree *smaller; /* smaller node */ struct Curl_tree *larger; /* larger node */ struct Curl_tree *samen; /* points to the next node with identical key */ struct Curl_tree *samep; /* points to the prev node with identical key */ - struct timeval key; /* this node's "sort" key */ + struct curltime key; /* this node's "sort" key */ void *payload; /* data the splay code doesn't care about */ }; -struct Curl_tree *Curl_splay(struct timeval i, +struct Curl_tree *Curl_splay(struct curltime i, struct Curl_tree *t); -struct Curl_tree *Curl_splayinsert(struct timeval key, +struct Curl_tree *Curl_splayinsert(struct curltime key, struct Curl_tree *t, struct Curl_tree *newnode); #if 0 -struct Curl_tree *Curl_splayremove(struct timeval key, +struct Curl_tree *Curl_splayremove(struct curltime key, struct Curl_tree *t, struct Curl_tree **removed); #endif -struct Curl_tree *Curl_splaygetbest(struct timeval key, +struct Curl_tree *Curl_splaygetbest(struct curltime key, struct Curl_tree *t, struct Curl_tree **removed); @@ -53,8 +54,8 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, struct Curl_tree *removenode, struct Curl_tree **newroot); -#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \ - ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \ +#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \ + ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \ ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \ ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0)))) diff --git a/lib/ssh.c b/lib/ssh.c index 00aeca9..5406bf0 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -177,6 +177,7 @@ const struct Curl_handler Curl_handler_scp = { ssh_perform_getsock, /* perform_getsock */ scp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_SSH, /* defport */ CURLPROTO_SCP, /* protocol */ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION @@ -203,6 +204,7 @@ const struct Curl_handler Curl_handler_sftp = { ssh_perform_getsock, /* perform_getsock */ sftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_SSH, /* defport */ CURLPROTO_SFTP, /* protocol */ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION @@ -426,14 +428,14 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, /* Check for /~/, indicating relative to the user's home directory */ if(conn->handler->protocol & CURLPROTO_SCP) { - real_path = malloc(working_path_len+1); + real_path = malloc(working_path_len + 1); if(real_path == NULL) { free(working_path); return CURLE_OUT_OF_MEMORY; } if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) /* It is referenced to the home directory, so strip the leading '/~/' */ - memcpy(real_path, working_path+3, 4 + working_path_len-3); + memcpy(real_path, working_path + 3, 4 + working_path_len-3); else memcpy(real_path, working_path, 1 + working_path_len); } @@ -449,19 +451,19 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, leading '/' */ memcpy(real_path, homedir, homelen); real_path[homelen] = '/'; - real_path[homelen+1] = '\0'; + real_path[homelen + 1] = '\0'; if(working_path_len > 3) { - memcpy(real_path+homelen+1, working_path + 3, + memcpy(real_path + homelen + 1, working_path + 3, 1 + working_path_len -3); } } else { - real_path = malloc(working_path_len+1); + real_path = malloc(working_path_len + 1); if(real_path == NULL) { free(working_path); return CURLE_OUT_OF_MEMORY; } - memcpy(real_path, working_path, 1+working_path_len); + memcpy(real_path, working_path, 1 + working_path_len); } } @@ -1811,7 +1813,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) zero even though libssh2_sftp_open() failed previously! We need to work around that! */ sshc->actualcode = CURLE_SSH; - err=-1; + err = -1; } failf(data, "Upload failed: %s (%d/%d)", err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error", @@ -1829,7 +1831,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed=0; + curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); @@ -1981,13 +1983,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = result?result:CURLE_SSH; break; } - sshc->readdir_filename = malloc(PATH_MAX+1); + sshc->readdir_filename = malloc(PATH_MAX + 1); if(!sshc->readdir_filename) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } - sshc->readdir_longentry = malloc(PATH_MAX+1); + sshc->readdir_longentry = malloc(PATH_MAX + 1); if(!sshc->readdir_longentry) { Curl_safefree(sshc->readdir_filename); state(conn, SSH_SFTP_CLOSE); @@ -2021,7 +2023,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } result = Curl_client_write(conn, CLIENTWRITE_BODY, - tmpLine, sshc->readdir_len+1); + tmpLine, sshc->readdir_len + 1); free(tmpLine); if(result) { @@ -2030,7 +2032,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } /* 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 += sshc->readdir_len + 1; /* output debug output if that is requested */ if(data->set.verbose) { @@ -2231,18 +2233,25 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) curl_off_t from, to; char *ptr; char *ptr2; + CURLofft to_t; + CURLofft from_t; - from=curlx_strtoofft(conn->data->state.range, &ptr, 0); - while(*ptr && (ISSPACE(*ptr) || (*ptr=='-'))) + from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from); + if(from_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) ptr++; - to=curlx_strtoofft(ptr, &ptr2, 0); - if((ptr == ptr2) /* no "to" value given */ + to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); + if(to_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + if((to_t == CURL_OFFT_INVAL) /* no "to" value given */ || (to >= size)) { to = size - 1; } - if(from < 0) { + if(from_t) { /* from is relative to end of file */ - from += size; + from = size - to; + to = size - 1; } if(from > size) { failf(data, "Offset (%" @@ -2825,7 +2834,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, while((sshc->state != SSH_STOP) && !result) { bool block; time_t left = 1000; - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); result = ssh_statemach_act(conn, &block); if(result) @@ -2933,6 +2942,13 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done) return CURLE_FAILED_INIT; } + if(data->set.ssh_compression) { +#if LIBSSH2_VERSION_NUM >= 0x010208 + if(libssh2_session_flag(ssh->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0) +#endif + infof(data, "Failed to enable compression for ssh session\n"); + } + #ifdef HAVE_LIBSSH2_KNOWNHOST_API if(data->set.str[STRING_SSH_KNOWNHOSTS]) { int rc; @@ -3029,8 +3045,8 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done) data->req.size = -1; /* make sure this is unknown at this point */ sshc->actualcode = CURLE_OK; /* reset error code */ - sshc->secondCreateDirs =0; /* reset the create dir attempt state - variable */ + sshc->secondCreateDirs = 0; /* reset the create dir attempt state + variable */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); diff --git a/lib/strcase.c b/lib/strcase.c index a74a4be..24bcca9 100644 --- a/lib/strcase.c +++ b/lib/strcase.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -94,10 +94,11 @@ char Curl_raw_toupper(char in) } /* - * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant - * to be locale independent and only compare strings we know are safe for - * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for - * some further explanation to why this function is necessary. + * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is + * meant to be locale independent and only compare strings we know are safe + * for this. See + * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some + * further explanation to why this function is necessary. * * The function is capable of comparing a-z case insensitively even for * non-ascii. diff --git a/lib/strdup.c b/lib/strdup.c index 136b693..19cb044 100644 --- a/lib/strdup.c +++ b/lib/strdup.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,11 +44,11 @@ char *curlx_strdup(const char *str) if(len >= ((size_t)-1) / sizeof(char)) return (char *)NULL; - newstr = malloc((len+1)*sizeof(char)); + newstr = malloc((len + 1)*sizeof(char)); if(!newstr) return (char *)NULL; - memcpy(newstr, str, (len+1)*sizeof(char)); + memcpy(newstr, str, (len + 1)*sizeof(char)); return newstr; diff --git a/lib/strerror.c b/lib/strerror.c index 7e5cde4..83a96dd 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2004 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2004 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -49,6 +49,10 @@ #include "curl_memory.h" #include "memdebug.h" +#if defined(WIN32) || defined(_WIN32_WCE) +#define PRESERVE_WINDOWS_ERROR_CODE +#endif + const char * curl_easy_strerror(CURLcode error) { @@ -432,6 +436,10 @@ curl_share_strerror(CURLSHcode error) static const char * get_winsock_error (int err, char *buf, size_t len) { +#ifdef PRESERVE_WINDOWS_ERROR_CODE + DWORD old_win_err = GetLastError(); +#endif + int old_errno = errno; const char *p; #ifndef CURL_DISABLE_VERBOSE_STRINGS @@ -611,6 +619,15 @@ get_winsock_error (int err, char *buf, size_t len) #endif strncpy(buf, p, len); buf [len-1] = '\0'; + + if(errno != old_errno) + errno = old_errno; + +#ifdef PRESERVE_WINDOWS_ERROR_CODE + if(old_win_err != GetLastError()) + SetLastError(old_win_err); +#endif + return buf; } #endif /* USE_WINSOCK */ @@ -628,9 +645,12 @@ get_winsock_error (int err, char *buf, size_t len) */ const char *Curl_strerror(struct connectdata *conn, int err) { +#ifdef PRESERVE_WINDOWS_ERROR_CODE + DWORD old_win_err = GetLastError(); +#endif + int old_errno = errno; char *buf, *p; size_t max; - int old_errno = ERRNO; DEBUGASSERT(conn); DEBUGASSERT(err >= 0); @@ -722,8 +742,13 @@ const char *Curl_strerror(struct connectdata *conn, int err) if(p && (p - buf) >= 1) *p = '\0'; - if(old_errno != ERRNO) - SET_ERRNO(old_errno); + if(errno != old_errno) + errno = old_errno; + +#ifdef PRESERVE_WINDOWS_ERROR_CODE + if(old_win_err != GetLastError()) + SetLastError(old_win_err); +#endif return buf; } @@ -731,16 +756,19 @@ const char *Curl_strerror(struct connectdata *conn, int err) #ifdef USE_WINDOWS_SSPI const char *Curl_sspi_strerror (struct connectdata *conn, int err) { +#ifdef PRESERVE_WINDOWS_ERROR_CODE + DWORD old_win_err = GetLastError(); +#endif + int old_errno = errno; + const char *txt; + char *outbuf; + size_t outmax; #ifndef CURL_DISABLE_VERBOSE_STRINGS char txtbuf[80]; char msgbuf[sizeof(conn->syserr_buf)]; char *p, *str, *msg = NULL; bool msg_formatted = FALSE; - int old_errno; #endif - const char *txt; - char *outbuf; - size_t outmax; DEBUGASSERT(conn); @@ -750,8 +778,6 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) #ifndef CURL_DISABLE_VERBOSE_STRINGS - old_errno = ERRNO; - switch(err) { case SEC_E_OK: txt = "No error"; @@ -1051,9 +1077,6 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) strncpy(outbuf, str, outmax); } - if(old_errno != ERRNO) - SET_ERRNO(old_errno); - #else if(err == SEC_E_OK) @@ -1067,6 +1090,14 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) outbuf[outmax] = '\0'; + if(errno != old_errno) + errno = old_errno; + +#ifdef PRESERVE_WINDOWS_ERROR_CODE + if(old_win_err != GetLastError()) + SetLastError(old_win_err); +#endif + return outbuf; } #endif /* USE_WINDOWS_SSPI */ diff --git a/lib/strtoofft.c b/lib/strtoofft.c index b854bf4..807fc54 100644 --- a/lib/strtoofft.c +++ b/lib/strtoofft.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -20,6 +20,7 @@ * ***************************************************************************/ +#include #include "curl_setup.h" #include "strtoofft.h" @@ -29,10 +30,32 @@ * * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we * could use in case strtoll() doesn't exist... See - * http://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html + * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html */ -#ifdef NEED_CURL_STRTOLL +#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) +# ifdef HAVE_STRTOLL +# define strtooff strtoll +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64) +# if defined(_SAL_VERSION) + _Check_return_ _CRTIMP __int64 __cdecl _strtoi64( + _In_z_ const char *_String, + _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix); +# else + _CRTIMP __int64 __cdecl _strtoi64(const char *_String, + char **_EndPtr, int _Radix); +# endif +# define strtooff _strtoi64 +# else +# define PRIVATE_STRTOOFF 1 +# endif +# endif +#else +# define strtooff strtol +#endif + +#ifdef PRIVATE_STRTOOFF /* Range tests can be used for alphanum decoding if characters are consecutive, like in ASCII. Else an array is scanned. Determine this condition now. */ @@ -48,11 +71,10 @@ static const char valchars[] = static int get_char(char c, int base); /** - * Emulated version of the strtoll function. This extracts a long long + * Custom version of the strtooff function. This extracts a curl_off_t * value from the given input string and returns it. */ -curl_off_t -curlx_strtoll(const char *nptr, char **endptr, int base) +static curl_off_t strtooff(const char *nptr, char **endptr, int base) { char *end; int is_negative = 0; @@ -132,7 +154,7 @@ curlx_strtoll(const char *nptr, char **endptr, int base) else value = CURL_OFF_T_MAX; - SET_ERRNO(ERANGE); + errno = ERANGE; } if(endptr) @@ -186,3 +208,34 @@ static int get_char(char c, int base) return value; } #endif /* Only present if we need strtoll, but don't have it. */ + +/* + * Parse a *positive* up to 64 bit number written in ascii. + */ +CURLofft curlx_strtoofft(const char *str, char **endp, int base, + curl_off_t *num) +{ + char *end; + curl_off_t number; + errno = 0; + *num = 0; /* clear by default */ + while(str && *str && ISSPACE(*str)) + str++; + if('-' == *str) { + if(endp) + *endp = (char *)str; /* didn't actually move */ + return CURL_OFFT_INVAL; /* nothing parsed */ + } + number = strtooff(str, &end, base); + if(endp) + *endp = end; + if(errno == ERANGE) + /* overflow/underflow */ + return CURL_OFFT_FLOW; + else if(str == end) + /* nothing parsed */ + return CURL_OFFT_INVAL; + + *num = number; + return CURL_OFFT_OK; +} diff --git a/lib/strtoofft.h b/lib/strtoofft.h index f4039f3..244411a 100644 --- a/lib/strtoofft.h +++ b/lib/strtoofft.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,31 +40,7 @@ * of 'long' the conversion function to use is strtol(). */ -#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) -# ifdef HAVE_STRTOLL -# define curlx_strtoofft strtoll -# else -# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64) -# if defined(_SAL_VERSION) - _Check_return_ _CRTIMP __int64 __cdecl _strtoi64( - _In_z_ const char *_String, - _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix); -# else - _CRTIMP __int64 __cdecl _strtoi64(const char *_String, - char **_EndPtr, int _Radix); -# endif -# define curlx_strtoofft _strtoi64 -# else - curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base); -# define curlx_strtoofft curlx_strtoll -# define NEED_CURL_STRTOLL 1 -# endif -# endif -#else -# define curlx_strtoofft strtol -#endif - -#if (CURL_SIZEOF_CURL_OFF_T == 4) +#if (SIZEOF_CURL_OFF_T == 4) # define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF) #else /* assume CURL_SIZEOF_CURL_OFF_T == 8 */ @@ -72,4 +48,13 @@ #endif #define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1)) +typedef enum { + CURL_OFFT_OK, /* parsed fine */ + CURL_OFFT_FLOW, /* over or underflow */ + CURL_OFFT_INVAL /* nothing was parsed */ +} CURLofft; + +CURLofft curlx_strtoofft(const char *str, char **endp, int base, + curl_off_t *num); + #endif /* HEADER_CURL_STRTOOFFT_H */ diff --git a/lib/telnet.c b/lib/telnet.c index 155d4b2..a7bed3d 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -76,7 +76,7 @@ } WHILE_FALSE #define CURL_SB_ACCUM(x,c) \ do { \ - if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \ + if(x->subpointer < (x->subbuffer + sizeof x->subbuffer)) \ *x->subpointer++ = (c); \ } WHILE_FALSE @@ -192,6 +192,7 @@ const struct Curl_handler Curl_handler_telnet = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_TELNET, /* defport */ CURLPROTO_TELNET, /* protocol */ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ @@ -294,8 +295,8 @@ static void negotiate(struct connectdata *conn) int i; struct TELNET *tn = (struct TELNET *) conn->data->req.protop; - for(i = 0;i < CURL_NTELOPTS;i++) { - if(i==CURL_TELOPT_ECHO) + for(i = 0; i < CURL_NTELOPTS; i++) { + if(i == CURL_TELOPT_ECHO) continue; if(tn->us_preferred[i] == CURL_YES) @@ -791,7 +792,7 @@ static void printsub(struct Curl_easy *data, case CURL_TELOPT_NEW_ENVIRON: if(pointer[1] == CURL_TELQUAL_IS) { infof(data, " "); - for(i = 3;i < length;i++) { + for(i = 3; i < length; i++) { switch(pointer[i]) { case CURL_NEW_ENV_VAR: infof(data, ", "); @@ -842,7 +843,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; } - for(head = data->set.telnet_options; head; head=head->next) { + for(head = data->set.telnet_options; head; head = head->next) { if(sscanf(head->data, "%127[^= ]%*[ =]%255s", option_keyword, option_arg) == 2) { @@ -889,8 +890,8 @@ static CURLcode check_telnet_options(struct connectdata *conn) /* To take care or not of the 8th bit in data exchange */ if(strcasecompare(option_keyword, "BINARY")) { - binary_option=atoi(option_arg); - if(binary_option!=1) { + binary_option = atoi(option_arg); + if(binary_option != 1) { tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; } @@ -898,7 +899,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } failf(data, "Unknown telnet option %s", head->data); - result = CURLE_UNKNOWN_TELNET_OPTION; + result = CURLE_UNKNOWN_OPTION; break; } failf(data, "Syntax error in telnet option: %s", head->data); @@ -934,7 +935,7 @@ static void suboption(struct connectdata *conn) struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; - printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2); + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: len = strlen(tn->subopt_ttype) + 4 + 2; @@ -966,7 +967,7 @@ static void suboption(struct connectdata *conn) CURL_TELQUAL_IS); len = 4; - for(v = tn->telnet_vars;v;v = v->next) { + for(v = tn->telnet_vars; v; v = v->next) { tmplen = (strlen(v->data) + 1); /* Add the variable only if it fits */ if(len + tmplen < (int)sizeof(temp)-6) { @@ -1018,8 +1019,8 @@ static void sendsuboption(struct connectdata *conn, int option) CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS); /* We must deal either with litte or big endian processors */ /* Window size must be sent according to the 'network order' */ - x=htons(tn->subopt_wsx); - y=htons(tn->subopt_wsy); + x = htons(tn->subopt_wsx); + y = htons(tn->subopt_wsy); uc1 = (unsigned char *)&x; uc2 = (unsigned char *)&y; CURL_SB_ACCUM(tn, uc1[0]); @@ -1032,7 +1033,7 @@ static void sendsuboption(struct connectdata *conn, int option) CURL_SB_TERM(tn); /* data suboption is now ready */ - printsub(data, '>', (unsigned char *)tn->subbuffer+2, + printsub(data, '>', (unsigned char *)tn->subbuffer + 2, CURL_SB_LEN(tn)-2); /* we send the header of the suboption... */ @@ -1043,9 +1044,9 @@ static void sendsuboption(struct connectdata *conn, int option) } /* ... then the window size with the send_telnet_data() function to deal with 0xFF cases ... */ - send_telnet_data(conn, (char *)tn->subbuffer+3, 4); + send_telnet_data(conn, (char *)tn->subbuffer + 3, 4); /* ... and the footer */ - bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2); + bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2); if(bytes_written < 0) { err = SOCKERRNO; failf(data, "Sending data failed (%d)", err); @@ -1063,7 +1064,7 @@ CURLcode telrcv(struct connectdata *conn, unsigned char c; CURLcode result; int in = 0; - int startwrite=-1; + int startwrite = -1; struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; @@ -1326,7 +1327,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) curl_off_t total_ul = 0; #endif ssize_t nread; - struct timeval now; + struct curltime now; bool keepon = TRUE; char *buf = data->state.buffer; struct TELNET *tn; @@ -1356,14 +1357,14 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* load ws2_32.dll and get the function pointers we need. */ wsock2 = Curl_load_library(TEXT("WS2_32.DLL")); if(wsock2 == NULL) { - failf(data, "failed to load WS2_32.DLL (%d)", ERRNO); + failf(data, "failed to load WS2_32.DLL (%u)", GetLastError()); return CURLE_FAILED_INIT; } /* Grab a pointer to WSACreateEvent */ create_event_func = GetProcAddress(wsock2, "WSACreateEvent"); if(create_event_func == NULL) { - failf(data, "failed to find WSACreateEvent function (%d)", ERRNO); + failf(data, "failed to find WSACreateEvent function (%u)", GetLastError()); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } @@ -1371,7 +1372,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* And WSACloseEvent */ close_event_func = GetProcAddress(wsock2, "WSACloseEvent"); if(close_event_func == NULL) { - failf(data, "failed to find WSACloseEvent function (%d)", ERRNO); + failf(data, "failed to find WSACloseEvent function (%u)", GetLastError()); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } @@ -1379,7 +1380,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* And WSAEventSelect */ event_select_func = GetProcAddress(wsock2, "WSAEventSelect"); if(event_select_func == NULL) { - failf(data, "failed to find WSAEventSelect function (%d)", ERRNO); + failf(data, "failed to find WSAEventSelect function (%u)", GetLastError()); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } @@ -1387,7 +1388,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* And WSAEnumNetworkEvents */ enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents"); if(enum_netevents_func == NULL) { - failf(data, "failed to find WSAEnumNetworkEvents function (%d)", ERRNO); + failf(data, "failed to find WSAEnumNetworkEvents function (%u)", + GetLastError()); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } @@ -1580,7 +1582,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* We called LoadLibrary, so call FreeLibrary */ if(!FreeLibrary(wsock2)) - infof(data, "FreeLibrary(wsock2) failed (%d)", ERRNO); + infof(data, "FreeLibrary(wsock2) failed (%u)", GetLastError()); #else pfd[0].fd = sockfd; pfd[0].events = POLLIN; diff --git a/lib/tftp.c b/lib/tftp.c index b2b3efe..4e599fd 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -76,12 +76,12 @@ #define TFTP_OPTION_INTERVAL "timeout" typedef enum { - TFTP_MODE_NETASCII=0, + TFTP_MODE_NETASCII = 0, TFTP_MODE_OCTET } tftp_mode_t; typedef enum { - TFTP_STATE_START=0, + TFTP_STATE_START = 0, TFTP_STATE_RX, TFTP_STATE_TX, TFTP_STATE_FIN @@ -100,7 +100,7 @@ typedef enum { } tftp_event_t; typedef enum { - TFTP_ERR_UNDEF=0, + TFTP_ERR_UNDEF = 0, TFTP_ERR_NOTFOUND, TFTP_ERR_PERM, TFTP_ERR_DISKFULL, @@ -181,6 +181,7 @@ const struct Curl_handler Curl_handler_tftp = { ZERO_NULL, /* perform_getsock */ tftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_TFTP, /* defport */ CURLPROTO_TFTP, /* protocol */ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ @@ -216,7 +217,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) if(start) { maxtime = (time_t)(timeout_ms + 500) / 1000; - state->max_time = state->start_time+maxtime; + state->max_time = state->start_time + maxtime; /* Set per-block timeout to total */ timeout = maxtime; @@ -231,7 +232,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) /* Compute the re-start interval to suit the timeout */ state->retry_time = (int)timeout/state->retry_max; if(state->retry_time<1) - state->retry_time=1; + state->retry_time = 1; } else { @@ -240,7 +241,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) else maxtime = 3600; - state->max_time = state->start_time+maxtime; + state->max_time = state->start_time + maxtime; /* Set per-block timeout to total */ timeout = maxtime; @@ -250,15 +251,15 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) } /* But bound the total number */ if(state->retry_max<3) - state->retry_max=3; + state->retry_max = 3; if(state->retry_max>50) - state->retry_max=50; + state->retry_max = 50; /* Compute the re-ACK interval to suit the timeout */ state->retry_time = (int)(timeout/state->retry_max); if(state->retry_time<1) - state->retry_time=1; + state->retry_time = 1; infof(state->conn->data, "set timeouts for state %d; Total %ld, retry %d maxtry %d\n", @@ -320,7 +321,7 @@ static const char *tftp_option_get(const char *buf, size_t len, return NULL; *option = buf; - loc += Curl_strnlen(buf+loc, len-loc); + loc += Curl_strnlen(buf + loc, len-loc); loc++; /* NULL term */ if(loc > len) @@ -474,7 +475,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) /* If we are uploading, send an WRQ */ setpacketevent(&state->spacket, TFTP_EVENT_WRQ); state->conn->data->req.upload_fromhere = - (char *)state->spacket.data+4; + (char *)state->spacket.data + 4; if(data->state.infilesize != -1) Curl_pgrsSetUploadSize(data, data->state.infilesize); } @@ -490,7 +491,13 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(result) return result; - snprintf((char *)state->spacket.data+2, + if(strlen(filename) > (state->blksize - strlen(mode) - 4)) { + failf(data, "TFTP file name too long\n"); + free(filename); + return CURLE_TFTP_ILLEGAL; /* too long file name field */ + } + + snprintf((char *)state->spacket.data + 2, state->blksize, "%s%c%s%c", filename, '\0', mode, '\0'); sbytes = 4 + strlen(filename) + strlen(mode); @@ -505,25 +512,25 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) strcpy(buf, "0"); /* the destination is large enough */ sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, + (char *)state->spacket.data + sbytes, TFTP_OPTION_TSIZE); sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf); + (char *)state->spacket.data + sbytes, buf); /* add blksize option */ snprintf(buf, sizeof(buf), "%d", state->requested_blksize); sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, + (char *)state->spacket.data + sbytes, TFTP_OPTION_BLKSIZE); sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf); + (char *)state->spacket.data + sbytes, buf); /* add timeout option */ snprintf(buf, sizeof(buf), "%d", state->retry_time); sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, + (char *)state->spacket.data + sbytes, TFTP_OPTION_INTERVAL); sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf); + (char *)state->spacket.data + sbytes, buf); } /* the typecase for the 3rd argument is mostly for systems that do @@ -569,7 +576,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit boundary */ -#define NEXT_BLOCKNUM(x) (((x)+1)&0xffff) +#define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff) /********************************************************** * @@ -620,7 +627,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) } /* Check if completed (That is, a less than full packet is received) */ - if(state->rbytes < (ssize_t)state->blksize+4) { + if(state->rbytes < (ssize_t)state->blksize + 4) { state->state = TFTP_STATE_FIN; } else { @@ -736,7 +743,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) else { /* Re-send the data packet */ sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4+state->sbytes, SEND_4TH_ARG, + 4 + state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ @@ -769,7 +776,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) * data block. * */ state->sbytes = 0; - state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4; + state->conn->data->req.upload_fromhere = (char *)state->spacket.data + 4; do { result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes, &cb); @@ -806,7 +813,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) else { /* Re-send the data packet */ sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4+state->sbytes, SEND_4TH_ARG, + 4 + state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ @@ -1102,11 +1109,11 @@ static CURLcode tftp_receive_packet(struct connectdata *conn) fromlen = sizeof(fromaddr); state->rbytes = (int)recvfrom(state->sockfd, (void *)state->rpacket.data, - state->blksize+4, + state->blksize + 4, 0, (struct sockaddr *)&fromaddr, &fromlen); - if(state->remote_addrlen==0) { + if(state->remote_addrlen == 0) { memcpy(&state->remote_addr, &fromaddr, fromlen); state->remote_addrlen = fromlen; } @@ -1128,7 +1135,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn) if(state->rbytes > 4 && (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) { result = Curl_client_write(conn, CLIENTWRITE_BODY, - (char *)state->rpacket.data+4, + (char *)state->rpacket.data + 4, state->rbytes-4); if(result) { tftp_state_machine(state, TFTP_EVENT_ERROR); @@ -1142,14 +1149,14 @@ static CURLcode tftp_receive_packet(struct connectdata *conn) { unsigned short error = getrpacketblock(&state->rpacket); state->error = (tftp_error_t)error; - infof(data, "%s\n", (const char *)state->rpacket.data+4); + infof(data, "%s\n", (const char *)state->rpacket.data + 4); break; } case TFTP_EVENT_ACK: break; case TFTP_EVENT_OACK: result = tftp_parse_option_ack(state, - (const char *)state->rpacket.data+2, + (const char *)state->rpacket.data + 2, state->rbytes-2); if(result) return result; @@ -1193,7 +1200,7 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) state->state = TFTP_STATE_FIN; return 0; } - if(current > state->rx_time+state->retry_time) { + if(current > state->rx_time + state->retry_time) { if(event) *event = TFTP_EVENT_TIMEOUT; time(&state->rx_time); /* update even though we received nothing */ @@ -1344,7 +1351,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done) state = (tftp_state_data_t *)conn->proto.tftpc; if(!state) - return CURLE_BAD_CALLING_ORDER; + return CURLE_TFTP_ILLEGAL; result = tftp_perform(conn, done); diff --git a/lib/timeval.c b/lib/timeval.c index bed44c5..d7207b3 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,14 +24,14 @@ #if defined(WIN32) && !defined(MSDOS) -struct timeval curlx_tvnow(void) +struct curltime curlx_tvnow(void) { /* ** GetTickCount() is available on _all_ Windows versions from W95 up ** to nowadays. Returns milliseconds elapsed since last system boot, ** increases monotonically and wraps once 49.7 days have elapsed. */ - struct timeval now; + struct curltime now; #if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ (_WIN32_WINNT < _WIN32_WINNT_VISTA) DWORD milliseconds = GetTickCount(); @@ -39,8 +39,8 @@ struct timeval curlx_tvnow(void) now.tv_usec = (milliseconds % 1000) * 1000; #else ULONGLONG milliseconds = GetTickCount64(); - now.tv_sec = (long) (milliseconds / 1000); - now.tv_usec = (long) (milliseconds % 1000) * 1000; + now.tv_sec = (time_t) (milliseconds / 1000); + now.tv_usec = (unsigned int) (milliseconds % 1000) * 1000; #endif return now; @@ -48,7 +48,7 @@ struct timeval curlx_tvnow(void) #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) -struct timeval curlx_tvnow(void) +struct curltime curlx_tvnow(void) { /* ** clock_gettime() is granted to be increased monotonically when the @@ -58,10 +58,11 @@ struct timeval curlx_tvnow(void) ** system has started up. */ struct timeval now; + struct curltime cnow; struct timespec tsnow; if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) { - now.tv_sec = tsnow.tv_sec; - now.tv_usec = tsnow.tv_nsec / 1000; + cnow.tv_sec = tsnow.tv_sec; + cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000); } /* ** Even when the configure process has truly detected monotonic clock @@ -69,20 +70,23 @@ struct timeval curlx_tvnow(void) ** run-time. When this occurs simply fallback to other time source. */ #ifdef HAVE_GETTIMEOFDAY - else + else { (void)gettimeofday(&now, NULL); + cnow.tv_sec = now.tv_sec; + cnow.tv_usec = (unsigned int)now.tv_usec; + } #else else { - now.tv_sec = (long)time(NULL); - now.tv_usec = 0; + cnow.tv_sec = time(NULL); + cnow.tv_usec = 0; } #endif - return now; + return cnow; } #elif defined(HAVE_GETTIMEOFDAY) -struct timeval curlx_tvnow(void) +struct curltime curlx_tvnow(void) { /* ** gettimeofday() is not granted to be increased monotonically, due to @@ -90,19 +94,22 @@ struct timeval curlx_tvnow(void) ** forward or backward in time. */ struct timeval now; + struct curltime ret; (void)gettimeofday(&now, NULL); - return now; + ret.tv_sec = now.tv_sec; + ret.tv_usec = now.tv_usec; + return ret; } #else -struct timeval curlx_tvnow(void) +struct curltime curlx_tvnow(void) { /* ** time() returns the value of time in seconds since the Epoch. */ - struct timeval now; - now.tv_sec = (long)time(NULL); + struct curltime now; + now.tv_sec = time(NULL); now.tv_usec = 0; return now; } @@ -115,8 +122,10 @@ struct timeval curlx_tvnow(void) * * Returns: the time difference in number of milliseconds. For large diffs it * returns 0x7fffffff on 32bit time_t systems. + * + * @unittest: 1323 */ -time_t curlx_tvdiff(struct timeval newer, struct timeval older) +time_t curlx_tvdiff(struct curltime newer, struct curltime older) { #if SIZEOF_TIME_T < 8 /* for 32bit time_t systems, add a precaution to avoid overflow for really @@ -126,18 +135,28 @@ time_t curlx_tvdiff(struct timeval newer, struct timeval older) return 0x7fffffff; #endif return (newer.tv_sec-older.tv_sec)*1000+ - (time_t)(newer.tv_usec-older.tv_usec)/1000; + (int)(newer.tv_usec-older.tv_usec)/1000; } /* - * Same as curlx_tvdiff but with full usec resolution. + * Make sure that the first argument is the more recent time, as otherwise + * we'll get a weird negative time-diff back... * - * Returns: the time difference in seconds with subsecond resolution. + * Returns: the time difference in number of microseconds. For too large diffs + * it returns max value. */ -double curlx_tvdiff_secs(struct timeval newer, struct timeval older) +time_t Curl_tvdiff_us(struct curltime newer, struct curltime older) { - if(newer.tv_sec != older.tv_sec) - return (double)(newer.tv_sec-older.tv_sec)+ - (double)(newer.tv_usec-older.tv_usec)/1000000.0; - return (double)(newer.tv_usec-older.tv_usec)/1000000.0; + time_t diff = newer.tv_sec-older.tv_sec; +#if SIZEOF_TIME_T < 8 + /* for 32bit time_t systems */ + if(diff >= (0x7fffffff/1000000)) + return 0x7fffffff; +#else + /* for 64bit time_t systems */ + if(diff >= (0x7fffffffffffffffLL/1000000)) + return 0x7fffffffffffffffLL; +#endif + return (newer.tv_sec-older.tv_sec)*1000000+ + (int)(newer.tv_usec-older.tv_usec); } diff --git a/lib/timeval.h b/lib/timeval.h index 3396935..1ee4b30 100644 --- a/lib/timeval.h +++ b/lib/timeval.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,7 +29,12 @@ #include "curl_setup.h" -struct timeval curlx_tvnow(void); +struct curltime { + time_t tv_sec; /* seconds */ + unsigned int tv_usec; /* microseconds */ +}; + +struct curltime curlx_tvnow(void); /* * Make sure that the first argument (t1) is the more recent time and t2 is @@ -37,20 +42,20 @@ struct timeval curlx_tvnow(void); * * Returns: the time difference in number of milliseconds. */ -time_t curlx_tvdiff(struct timeval t1, struct timeval t2); +time_t curlx_tvdiff(struct curltime t1, struct curltime t2); /* - * Same as curlx_tvdiff but with full usec resolution. + * Make sure that the first argument (t1) is the more recent time and t2 is + * the older time, as otherwise you get a weird negative time-diff back... * - * Returns: the time difference in seconds with subsecond resolution. + * Returns: the time difference in number of microseconds. */ -double curlx_tvdiff_secs(struct timeval t1, struct timeval t2); +time_t Curl_tvdiff_us(struct curltime newer, struct curltime older); /* These two defines below exist to provide the older API for library internals only. */ #define Curl_tvnow() curlx_tvnow() #define Curl_tvdiff(x,y) curlx_tvdiff(x,y) -#define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y) #endif /* HEADER_CURL_TIMEVAL_H */ diff --git a/lib/transfer.c b/lib/transfer.c index 43e8f64..8e66d0d 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -73,12 +73,38 @@ #include "connect.h" #include "non-ascii.h" #include "http2.h" +#include "mime.h" +#include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP) +/* + * checkheaders() checks the linked list of custom headers for a + * particular header (prefix). + * + * Returns a pointer to the first matching header or NULL if none matched. + */ +char *Curl_checkheaders(const struct connectdata *conn, + const char *thisheader) +{ + struct curl_slist *head; + size_t thislen = strlen(thisheader); + struct Curl_easy *data = conn->data; + + for(head = data->set.headers; head; head = head->next) { + if(strncasecompare(head->data, thisheader, thislen)) + return head->data; + } + + return NULL; +} +#endif + /* * This function will call the read callback to fill our buffer with data * to upload. @@ -195,27 +221,28 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) strlen(endofline_network)); #ifdef CURL_DOES_CONVERSIONS - CURLcode result; - int length; - if(data->set.prefer_ascii) { - /* translate the protocol and data */ - length = nread; - } - else { - /* just translate the protocol portion */ - length = strlen(hexbuffer); + { + CURLcode result; + int length; + if(data->set.prefer_ascii) + /* translate the protocol and data */ + length = nread; + else + /* just translate the protocol portion */ + length = (int)strlen(hexbuffer); + result = Curl_convert_to_network(data, data->req.upload_fromhere, + length); + /* Curl_convert_to_network calls failf if unsuccessful */ + if(result) + return result; } - result = Curl_convert_to_network(data, data->req.upload_fromhere, length); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(result) - return result; #endif /* CURL_DOES_CONVERSIONS */ if((nread - hexlen) == 0) /* mark this as done once this chunk is transferred */ data->req.upload_done = TRUE; - nread+=(int)strlen(endofline_native); /* for the added end of line */ + nread += (int)strlen(endofline_native); /* for the added end of line */ } #ifdef CURL_DOES_CONVERSIONS else if((data->set.prefer_ascii) && (!sending_http_headers)) { @@ -241,6 +268,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) CURLcode Curl_readrewind(struct connectdata *conn) { struct Curl_easy *data = conn->data; + curl_mimepart *mimepart = &data->set.mimepost; conn->bits.rewindaftersend = FALSE; /* we rewind now */ @@ -253,9 +281,21 @@ CURLcode Curl_readrewind(struct connectdata *conn) /* We have sent away data. If not using CURLOPT_POSTFIELDS or CURLOPT_HTTPPOST, call app to rewind */ - if(data->set.postfields || - (data->set.httpreq == HTTPREQ_POST_FORM)) + if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + struct HTTP *http = data->req.protop; + + if(http->sendit) + mimepart = http->sendit; + } + if(data->set.postfields) ; /* do nothing */ + else if(data->set.httpreq == HTTPREQ_POST_MIME || + data->set.httpreq == HTTPREQ_POST_FORM) { + if(Curl_mime_rewind(mimepart)) { + failf(data, "Cannot rewind mime/post data"); + return CURLE_SEND_FAIL_REWIND; + } + } else { if(data->set.seek_func) { int err; @@ -560,7 +600,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->set.httpreq == HTTPREQ_GET) && !k->ignorebody) { if(k->size == data->state.resume_from) { @@ -915,7 +955,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data, /* this is a paused transfer */ break; } - if(nread<=0) { + if(nread <= 0) { result = done_sending(conn, k); if(result) return result; @@ -1055,7 +1095,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, { struct SingleRequest *k = &data->req; CURLcode result; - int didwhat=0; + int didwhat = 0; curl_socket_t fd_read; curl_socket_t fd_write; @@ -1288,6 +1328,13 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) failf(data, "No URL set!"); return CURLE_URL_MALFORMAT; } + /* since the URL may have been redirected in a previous use of this handle */ + if(data->change.url_alloc) { + /* the already set URL is allocated, free it first! */ + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } + 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 after the *_setopt() calls (that could specify the size of the cache) but @@ -1296,7 +1343,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) if(result) return result; - data->set.followlocation=0; /* reset the location-follow counter */ + data->set.followlocation = 0; /* reset the location-follow counter */ data->state.this_is_a_follow = FALSE; /* reset this */ data->state.errorbuf = FALSE; /* no error has occurred */ data->state.httpversion = 0; /* don't assume any particular server version */ @@ -1338,7 +1385,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) #endif Curl_initinfo(data); /* reset session-specific information "variables" */ - Curl_pgrsResetTimesSizes(data); + Curl_pgrsResetTransferSizes(data); Curl_pgrsStartNow(data); if(data->set.timeout) @@ -1384,19 +1431,59 @@ CURLcode Curl_posttransfer(struct Curl_easy *data) #ifndef CURL_DISABLE_HTTP /* + * Find the separator at the end of the host name, or the '?' in cases like + * http://www.url.com?id=2380 + */ +static const char *find_host_sep(const char *url) +{ + const char *sep; + const char *query; + + /* Find the start of the hostname */ + sep = strstr(url, "//"); + if(!sep) + sep = url; + else + sep += 2; + + query = strchr(sep, '?'); + sep = strchr(sep, '/'); + + if(!sep) + sep = url + strlen(url); + + if(!query) + query = url + strlen(url); + + return sep < query ? sep : query; +} + +/* * strlen_url() returns the length of the given URL if the spaces within the * URL were properly URL encoded. + * URL encoding should be skipped for host names, otherwise IDN resolution + * will fail. */ -static size_t strlen_url(const char *url) +static size_t strlen_url(const char *url, bool relative) { const unsigned char *ptr; - size_t newlen=0; - bool left=TRUE; /* left side of the ? */ + size_t newlen = 0; + bool left = TRUE; /* left side of the ? */ + const unsigned char *host_sep = (const unsigned char *) url; + + if(!relative) + host_sep = (const unsigned char *) find_host_sep(url); + + for(ptr = (unsigned char *)url; *ptr; ptr++) { + + if(ptr < host_sep) { + ++newlen; + continue; + } - for(ptr=(unsigned char *)url; *ptr; ptr++) { switch(*ptr) { case '?': - left=FALSE; + left = FALSE; /* fall through */ default: if(*ptr >= 0x80) @@ -1405,7 +1492,7 @@ static size_t strlen_url(const char *url) break; case ' ': if(left) - newlen+=3; + newlen += 3; else newlen++; break; @@ -1416,19 +1503,32 @@ static size_t strlen_url(const char *url) /* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in * the source URL accordingly. + * URL encoding should be skipped for host names, otherwise IDN resolution + * will fail. */ -static void strcpy_url(char *output, const char *url) +static void strcpy_url(char *output, const char *url, bool relative) { /* we must add this with whitespace-replacing */ - bool left=TRUE; + bool left = TRUE; const unsigned char *iptr; char *optr = output; + const unsigned char *host_sep = (const unsigned char *) url; + + if(!relative) + host_sep = (const unsigned char *) find_host_sep(url); + for(iptr = (unsigned char *)url; /* read from here */ *iptr; /* until zero byte */ iptr++) { + + if(iptr < host_sep) { + *optr++ = *iptr; + continue; + } + switch(*iptr) { case '?': - left=FALSE; + left = FALSE; /* fall through */ default: if(*iptr >= 0x80) { @@ -1449,7 +1549,7 @@ static void strcpy_url(char *output, const char *url) break; } } - *optr=0; /* zero terminate output buffer */ + *optr = 0; /* zero terminate output buffer */ } @@ -1481,32 +1581,33 @@ static char *concat_url(const char *base, const char *relurl) char *protsep; char *pathsep; size_t newlen; + bool host_changed = FALSE; const char *useurl = relurl; size_t urllen; /* we must make our own copy of the URL to play with, as it may point to read-only data */ - char *url_clone=strdup(base); + char *url_clone = strdup(base); if(!url_clone) return NULL; /* skip out of this NOW */ /* protsep points to the start of the host name */ - protsep=strstr(url_clone, "//"); + protsep = strstr(url_clone, "//"); if(!protsep) - protsep=url_clone; + protsep = url_clone; else - protsep+=2; /* pass the slashes */ + protsep += 2; /* pass the slashes */ if('/' != relurl[0]) { - int level=0; + int level = 0; /* First we need to find out if there's a ?-letter in the URL, and cut it and the right-side of that off */ pathsep = strchr(protsep, '?'); if(pathsep) - *pathsep=0; + *pathsep = 0; /* we have a relative path to append to the last slash if there's one available, or if the new URL is just a query string (starts with a @@ -1515,14 +1616,14 @@ static char *concat_url(const char *base, const char *relurl) if(useurl[0] != '?') { pathsep = strrchr(protsep, '/'); if(pathsep) - *pathsep=0; + *pathsep = 0; } /* Check if there's any slash after the host name, and if so, remember that position instead */ pathsep = strchr(protsep, '/'); if(pathsep) - protsep = pathsep+1; + protsep = pathsep + 1; else protsep = NULL; @@ -1530,13 +1631,13 @@ static char *concat_url(const char *base, const char *relurl) and act accordingly */ if((useurl[0] == '.') && (useurl[1] == '/')) - useurl+=2; /* just skip the "./" */ + useurl += 2; /* just skip the "./" */ while((useurl[0] == '.') && (useurl[1] == '.') && (useurl[2] == '/')) { level++; - useurl+=3; /* pass the "../" */ + useurl += 3; /* pass the "../" */ } if(protsep) { @@ -1544,9 +1645,9 @@ static char *concat_url(const char *base, const char *relurl) /* cut off one more level from the right of the original URL */ pathsep = strrchr(protsep, '/'); if(pathsep) - *pathsep=0; + *pathsep = 0; else { - *protsep=0; + *protsep = 0; break; } } @@ -1558,9 +1659,10 @@ static char *concat_url(const char *base, const char *relurl) if((relurl[0] == '/') && (relurl[1] == '/')) { /* the new URL starts with //, just keep the protocol part from the original one */ - *protsep=0; + *protsep = 0; useurl = &relurl[2]; /* we keep the slashes from the original, so we skip the new ones */ + host_changed = TRUE; } else { /* cut off the original URL from the first slash, or deal with URLs @@ -1573,7 +1675,7 @@ static char *concat_url(const char *base, const char *relurl) char *sep = strchr(protsep, '?'); if(sep && (sep < pathsep)) pathsep = sep; - *pathsep=0; + *pathsep = 0; } else { /* There was no slash. Now, since we might be operating on a badly @@ -1582,7 +1684,7 @@ static char *concat_url(const char *base, const char *relurl) ?-letter as well! */ pathsep = strchr(protsep, '?'); if(pathsep) - *pathsep=0; + *pathsep = 0; } } } @@ -1592,7 +1694,7 @@ static char *concat_url(const char *base, const char *relurl) letter we replace each space with %20 while it is replaced with '+' on the right side of the '?' letter. */ - newlen = strlen_url(useurl); + newlen = strlen_url(useurl, !host_changed); urllen = strlen(url_clone); @@ -1614,7 +1716,7 @@ static char *concat_url(const char *base, const char *relurl) newest[urllen++]='/'; /* then append the new piece on the right side */ - strcpy_url(&newest[urllen], useurl); + strcpy_url(&newest[urllen], useurl, !host_changed); free(url_clone); @@ -1673,7 +1775,7 @@ CURLcode Curl_follow(struct Curl_easy *data, } } - if(!is_absolute_url(newurl)) { + if(!is_absolute_url(newurl)) { /*** *DANG* this is an RFC 2068 violation. The URL is supposed to be absolute and this doesn't seem to be that! @@ -1687,15 +1789,16 @@ CURLcode Curl_follow(struct Curl_easy *data, /* The new URL MAY contain space or high byte values, that means a mighty stupid redirect URL but we still make an effort to do "right". */ char *newest; - size_t newlen = strlen_url(newurl); + size_t newlen = strlen_url(newurl, FALSE); /* This is an absolute URL, don't allow the custom port number */ disallowport = TRUE; - newest = malloc(newlen+1); /* get memory for this */ + newest = malloc(newlen + 1); /* get memory for this */ if(!newest) return CURLE_OUT_OF_MEMORY; - strcpy_url(newest, newurl); /* create a space-free URL */ + + strcpy_url(newest, newurl, FALSE); /* create a space-free URL */ newurl = newest; /* use this instead now */ } @@ -1763,7 +1866,8 @@ CURLcode Curl_follow(struct Curl_easy *data, * can be overridden with CURLOPT_POSTREDIR. */ if((data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM) + || data->set.httpreq == HTTPREQ_POST_FORM + || data->set.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; @@ -1787,7 +1891,8 @@ CURLcode Curl_follow(struct Curl_easy *data, * can be overridden with CURLOPT_POSTREDIR. */ if((data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM) + || data->set.httpreq == HTTPREQ_POST_FORM + || data->set.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; @@ -1820,7 +1925,7 @@ CURLcode Curl_follow(struct Curl_easy *data, break; } Curl_pgrsTime(data, TIMER_REDIRECT); - Curl_pgrsResetTimesSizes(data); + Curl_pgrsResetTransferSizes(data); return CURLE_OK; #endif /* CURL_DISABLE_HTTP */ diff --git a/lib/transfer.h b/lib/transfer.h index 5189672..72526a8 100644 --- a/lib/transfer.h +++ b/lib/transfer.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,6 +22,9 @@ * ***************************************************************************/ +char *Curl_checkheaders(const struct connectdata *conn, + const char *thisheader); + void Curl_init_CONNECT(struct Curl_easy *data); CURLcode Curl_pretransfer(struct Curl_easy *data); diff --git a/lib/url.c b/lib/url.c index 87446db..584635b 100644 --- a/lib/url.c +++ b/lib/url.c @@ -71,6 +71,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "netrc.h" #include "formdata.h" +#include "mime.h" #include "vtls/vtls.h" #include "hostip.h" #include "transfer.h" @@ -274,6 +275,7 @@ static const struct Curl_handler Curl_handler_dummy = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ 0, /* defport */ 0, /* protocol */ PROTOPT_NONE /* flags */ @@ -283,7 +285,7 @@ void Curl_freeset(struct Curl_easy *data) { /* Free all dynamic strings stored in the data->set substructure. */ enum dupstring i; - for(i=(enum dupstring)0; i < STRING_LAST; i++) { + for(i = (enum dupstring)0; i < STRING_LAST; i++) { Curl_safefree(data->set.str[i]); } @@ -370,7 +372,7 @@ CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src) memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); /* duplicate all strings */ - for(i=(enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { + for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { result = setstropt(&dst->set.str[i], src->set.str[i]); if(result) return result; @@ -478,6 +480,8 @@ CURLcode Curl_close(struct Curl_easy *data) Curl_http2_cleanup_dependencies(data); Curl_convert_close(data); + Curl_mime_cleanpart(&data->set.mimepost); + /* No longer a dirty share, if it exists */ if(data->share) { Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); @@ -545,6 +549,9 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ + /* SOCKS5 proxy auth defaults to username/password + GSS-API */ + set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; + /* make libcurl quiet by default: */ set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ @@ -664,6 +671,8 @@ CURLcode Curl_open(struct Curl_easy **curl) result = CURLE_OUT_OF_MEMORY; } + Curl_mime_initpart(&data->set.mimepost, data); + data->state.headerbuff = malloc(HEADERSIZE); if(!data->state.headerbuff) { DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); @@ -672,7 +681,7 @@ CURLcode Curl_open(struct Curl_easy **curl) else { result = Curl_init_userdefined(&data->set); - data->state.headersize=HEADERSIZE; + data->state.headersize = HEADERSIZE; Curl_convert_init(data); @@ -829,6 +838,10 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, then this can be changed to HEAD later on) */ data->set.httpreq = HTTPREQ_GET; break; + case CURLOPT_REQUEST_TARGET: + result = setstropt(&data->set.str[STRING_TARGET], + va_arg(param, char *)); + break; case CURLOPT_FILETIME: /* * Try to get the file time of the remote document. The time will @@ -1139,6 +1152,20 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, data->set.httpreq = HTTPREQ_POST_FORM; data->set.opt_no_body = FALSE; /* this is implied */ break; +#endif /* CURL_DISABLE_HTTP */ + + case CURLOPT_MIMEPOST: + /* + * Set to make us do MIME/form POST + */ + result = curl_mime_subparts(&data->set.mimepost, + va_arg(param, curl_mime *)); + if(!result) { + data->set.mimepost.freefunc = NULL; /* Avoid free upon easy cleanup. */ + data->set.httpreq = HTTPREQ_POST_MIME; + data->set.opt_no_body = FALSE; /* this is implied */ + } + break; case CURLOPT_REFERER: /* @@ -1168,6 +1195,7 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, data->set.headers = va_arg(param, struct curl_slist *); break; +#ifndef CURL_DISABLE_HTTP case CURLOPT_PROXYHEADER: /* * Set a list with proxy headers to use (or replace internals with) @@ -1319,7 +1347,7 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, } break; -#endif /* CURL_DISABLE_COOKIES */ +#endif /* !CURL_DISABLE_COOKIES */ case CURLOPT_HTTPGET: /* @@ -1345,6 +1373,16 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, data->set.httpversion = arg; break; + case CURLOPT_EXPECT_100_TIMEOUT_MS: + /* + * Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. + */ + data->set.expect_100_timeout = va_arg(param, long); + break; + +#endif /* CURL_DISABLE_HTTP */ + case CURLOPT_HTTPAUTH: /* * Set HTTP Authentication type BITMASK. @@ -1396,16 +1434,6 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, } break; - case CURLOPT_EXPECT_100_TIMEOUT_MS: - /* - * Time to wait for a response to a HTTP request containing an - * Expect: 100-continue header before sending the data anyway. - */ - data->set.expect_100_timeout = va_arg(param, long); - break; - -#endif /* CURL_DISABLE_HTTP */ - case CURLOPT_CUSTOMREQUEST: /* * Set a custom string to use as request @@ -1537,6 +1565,11 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, break; #endif /* CURL_DISABLE_PROXY */ + case CURLOPT_SOCKS5_AUTH: + data->set.socks5auth = va_arg(param, unsigned long); + if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + result = CURLE_NOT_BUILT_IN; + break; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) case CURLOPT_SOCKS5_GSSAPI_NEC: /* @@ -1646,28 +1679,28 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, * The low speed limit that if transfers are below this for * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. */ - data->set.low_speed_limit=va_arg(param, long); + data->set.low_speed_limit = va_arg(param, long); break; case CURLOPT_MAX_SEND_SPEED_LARGE: /* * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE * bytes per second the transfer is throttled.. */ - data->set.max_send_speed=va_arg(param, curl_off_t); + data->set.max_send_speed = va_arg(param, curl_off_t); break; case CURLOPT_MAX_RECV_SPEED_LARGE: /* * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per * second the transfer is throttled.. */ - data->set.max_recv_speed=va_arg(param, curl_off_t); + data->set.max_recv_speed = va_arg(param, curl_off_t); break; case CURLOPT_LOW_SPEED_TIME: /* * The low speed time that if transfers are below the set * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. */ - data->set.low_speed_time=va_arg(param, long); + data->set.low_speed_time = va_arg(param, long); break; case CURLOPT_URL: /* @@ -1862,13 +1895,13 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, break; case CURLOPT_RESUME_FROM: /* - * Resume transfer at the give file position + * Resume transfer at the given file position */ data->set.set_resume_from = va_arg(param, long); break; case CURLOPT_RESUME_FROM_LARGE: /* - * Resume transfer at the give file position + * Resume transfer at the given file position */ data->set.set_resume_from = va_arg(param, curl_off_t); break; @@ -2166,24 +2199,26 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, TRUE : FALSE; break; case CURLOPT_SSL_CTX_FUNCTION: -#ifdef have_curlssl_ssl_ctx /* * Set a SSL_CTX callback */ - data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); -#else - result = CURLE_NOT_BUILT_IN; +#ifdef USE_SSL + if(Curl_ssl->have_ssl_ctx) + data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); + else #endif + result = CURLE_NOT_BUILT_IN; break; case CURLOPT_SSL_CTX_DATA: -#ifdef have_curlssl_ssl_ctx /* * Set a SSL_CTX callback parameter pointer */ - data->set.ssl.fsslctxp = va_arg(param, void *); -#else - result = CURLE_NOT_BUILT_IN; +#ifdef USE_SSL + if(Curl_ssl->have_ssl_ctx) + data->set.ssl.fsslctxp = va_arg(param, void *); + else #endif + result = CURLE_NOT_BUILT_IN; break; case CURLOPT_SSL_FALSESTART: /* @@ -2197,35 +2232,38 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CERTINFO: -#ifdef have_curlssl_certinfo - data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE; -#else - result = CURLE_NOT_BUILT_IN; +#ifdef USE_SSL + if(Curl_ssl->have_certinfo) + data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE; + else #endif + result = CURLE_NOT_BUILT_IN; break; case CURLOPT_PINNEDPUBLICKEY: -#ifdef have_curlssl_pinnedpubkey /* only by supported backends */ /* * Set pinned public key for SSL connection. * Specify file name of the public key in DER format. */ - result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG], - va_arg(param, char *)); -#else - result = CURLE_NOT_BUILT_IN; +#ifdef USE_SSL + if(Curl_ssl->have_pinnedpubkey) + result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG], + va_arg(param, char *)); + else #endif + result = CURLE_NOT_BUILT_IN; break; case CURLOPT_PROXY_PINNEDPUBLICKEY: -#ifdef have_curlssl_pinnedpubkey /* only by supported backends */ /* * Set pinned public key for SSL connection. * Specify file name of the public key in DER format. */ - result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], - va_arg(param, char *)); -#else - result = CURLE_NOT_BUILT_IN; +#ifdef USE_SSL + if(Curl_ssl->have_pinnedpubkey) + result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], + va_arg(param, char *)); + else #endif + result = CURLE_NOT_BUILT_IN; break; case CURLOPT_CAINFO: /* @@ -2243,30 +2281,32 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, va_arg(param, char *)); break; case CURLOPT_CAPATH: -#ifdef have_curlssl_ca_path /* not supported by all backends */ /* * Set CA path info for SSL connection. Specify directory name of the CA * certificates which have been prepared using openssl c_rehash utility. */ - /* This does not work on windows. */ - result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG], - va_arg(param, char *)); -#else - result = CURLE_NOT_BUILT_IN; +#ifdef USE_SSL + if(Curl_ssl->have_ca_path) + /* This does not work on windows. */ + result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG], + va_arg(param, char *)); + else #endif + result = CURLE_NOT_BUILT_IN; break; case CURLOPT_PROXY_CAPATH: -#ifdef have_curlssl_ca_path /* not supported by all backends */ /* * Set CA path info for SSL connection proxy. Specify directory name of the * CA certificates which have been prepared using openssl c_rehash utility. */ - /* This does not work on windows. */ - result = setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], - va_arg(param, char *)); -#else - result = CURLE_NOT_BUILT_IN; +#ifdef USE_SSL + if(Curl_ssl->have_ca_path) + /* This does not work on windows. */ + result = setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], + va_arg(param, char *)); + else #endif + result = CURLE_NOT_BUILT_IN; break; case CURLOPT_CRLFILE: /* @@ -2897,7 +2937,7 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, return CURLE_NOT_BUILT_IN; #else arg = va_arg(param, long); - if((arg>=1) && (arg <= 256)) + if((arg >= 1) && (arg <= 256)) data->set.stream_weight = (int)arg; break; #endif @@ -2923,6 +2963,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, case CURLOPT_SUPPRESS_CONNECT_HEADERS: data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE; break; + case CURLOPT_SSH_COMPRESSION: + data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE; + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; @@ -3023,7 +3066,7 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ Curl_safefree(conn->master_buffer); - Curl_safefree(conn->connect_buffer); + Curl_safefree(conn->connect_state); conn_reset_all_postponed_data(conn); @@ -3260,9 +3303,9 @@ Curl_oldest_idle_connection(struct Curl_easy *data) struct curl_hash_iterator iter; struct curl_llist_element *curr; struct curl_hash_element *he; - time_t highscore=-1; + time_t highscore =- 1; time_t score; - struct timeval now; + struct curltime now; struct connectdata *conn_candidate = NULL; struct connectbundle *bundle; @@ -3323,9 +3366,9 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy *data, struct connectbundle *bundle) { struct curl_llist_element *curr; - time_t highscore=-1; + time_t highscore = -1; time_t score; - struct timeval now; + struct curltime now; struct connectdata *conn_candidate = NULL; struct connectdata *conn; @@ -3367,11 +3410,19 @@ static bool disconnect_if_dead(struct connectdata *conn, handles in pipeline and the connection isn't already marked in use */ bool dead; - if(conn->handler->protocol & CURLPROTO_RTSP) - /* RTSP is a special case due to RTP interleaving */ - dead = Curl_rtsp_connisdead(conn); - else + + if(conn->handler->connection_check) { + /* The protocol has a special method for checking the state of the + connection. Use it to check if the connection is dead. */ + unsigned int state; + + state = conn->handler->connection_check(conn, CONNCHECK_ISDEAD); + dead = (state & CONNRESULT_DEAD); + } + else { + /* Use the general method for determining the death of a connection */ dead = SocketIsDead(conn->sock[FIRSTSOCKET]); + } if(dead) { conn->data = data; @@ -3405,7 +3456,7 @@ static int call_disconnect_if_dead(struct connectdata *conn, */ static void prune_dead_connections(struct Curl_easy *data) { - struct timeval now = Curl_tvnow(); + struct curltime now = Curl_tvnow(); time_t elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup); if(elapsed >= 1000L) { @@ -3946,7 +3997,7 @@ int Curl_doing_getsock(struct connectdata *conn, CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; if(conn && conn->handler->connecting) { *done = FALSE; @@ -3965,7 +4016,7 @@ CURLcode Curl_protocol_connecting(struct connectdata *conn, CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; if(conn && conn->handler->doing) { *done = FALSE; @@ -3985,7 +4036,7 @@ CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done) CURLcode Curl_protocol_connect(struct connectdata *conn, bool *protocol_done) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; *protocol_done = FALSE; @@ -4013,7 +4064,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, return CURLE_OK; if(conn->bits.tunnel_proxy && conn->bits.httpproxy && - (conn->tunnel_state[FIRSTSOCKET] != TUNNEL_COMPLETE)) + Curl_connect_ongoing(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; @@ -4072,7 +4123,7 @@ static void fix_hostname(struct connectdata *conn, struct hostname *host) if(len && (host->name[len-1] == '.')) /* strip off a single trailing dot if present, primarily for SNI but there's no use for it */ - host->name[len-1]=0; + host->name[len-1] = 0; /* Check name for non-ASCII and convert hostname to ACE form if we can */ if(!is_ASCII_name(host->name)) { @@ -4125,7 +4176,7 @@ static void free_fixed_hostname(struct hostname *host) host->encalloc = NULL; } #elif defined(USE_WIN32_IDN) - free(host->encalloc); /* must be freed withidn_free() since this was + free(host->encalloc); /* must be freed with free() since this was allocated by curl_win32_idn_to_ascii */ host->encalloc = NULL; #else @@ -4145,7 +4196,12 @@ static void llist_dtor(void *user, void *element) */ static struct connectdata *allocate_conn(struct Curl_easy *data) { - struct connectdata *conn = calloc(1, sizeof(struct connectdata)); +#ifdef USE_SSL +#define SSL_EXTRA + 4 * Curl_ssl->sizeof_ssl_backend_data - sizeof(long long) +#else +#define SSL_EXTRA 0 +#endif + struct connectdata *conn = calloc(1, sizeof(struct connectdata) + SSL_EXTRA); if(!conn) return NULL; @@ -4228,6 +4284,23 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->ip_version = data->set.ipver; +#ifdef USE_SSL + /* + * To save on malloc()s, the SSL backend-specific data has been allocated + * at the end of the connectdata struct. + */ + { + char *p = (char *)&conn->align_data__do_not_use; + conn->ssl[0].backend = (struct ssl_backend_data *)p; + conn->ssl[1].backend = + (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data); + conn->proxy_ssl[0].backend = + (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data * 2); + conn->proxy_ssl[1].backend = + (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data * 3); + } +#endif + #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ defined(NTLM_WB_ENABLED) conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; @@ -4363,11 +4436,16 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, return CURLE_URL_MALFORMAT; } - /* Make sure we don't mistake a drive letter for a scheme, for example: + /* MSDOS/Windows style drive prefix, eg c: in c:foo */ +#define STARTS_WITH_DRIVE_PREFIX(str) \ + ((('a' <= str[0] && str[0] <= 'z') || \ + ('A' <= str[0] && str[0] <= 'Z')) && \ + (str[1] == ':')) + + /* Don't mistake a drive letter for a scheme if the default protocol is file. curld --proto-default file c:/foo/bar.txt */ - if((('a' <= data->change.url[0] && data->change.url[0] <= 'z') || - ('A' <= data->change.url[0] && data->change.url[0] <= 'Z')) && - data->change.url[1] == ':' && data->set.str[STRING_DEFAULT_PROTOCOL] && + if(STARTS_WITH_DRIVE_PREFIX(data->change.url) && + data->set.str[STRING_DEFAULT_PROTOCOL] && strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file")) { ; /* do nothing */ } @@ -4386,8 +4464,6 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, if((url_has_scheme && strncasecompare(data->change.url, "file:", 5)) || (!url_has_scheme && data->set.str[STRING_DEFAULT_PROTOCOL] && strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file"))) { - bool path_has_drive = FALSE; - if(url_has_scheme) rc = sscanf(data->change.url, "%*15[^\n/:]:%[^\n]", path); else @@ -4406,20 +4482,15 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, /* This cannot be done with strcpy() in a portable manner, since the memory areas overlap! */ - memmove(path, path + 2, strlen(path + 2)+1); + memmove(path, path + 2, strlen(path + 2) + 1); } - /* the path may start with a drive letter. for backwards compatibility - we skip some processing on those paths. */ - path_has_drive = (('a' <= path[0] && path[0] <= 'z') || - ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':'; - /* * we deal with file:/// differently since it supports no * hostname other than "localhost" and "127.0.0.1", which is unique among * the URL protocols specified in RFC 1738 */ - if(path[0] != '/' && !path_has_drive) { + if(path[0] != '/' && !STARTS_WITH_DRIVE_PREFIX(path)) { /* the URL includes a host name, it must match "localhost" or "127.0.0.1" to be valid */ char *ptr; @@ -4452,14 +4523,11 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, ptr++; /* This cannot be made with strcpy, as the memory chunks overlap! */ - memmove(path, ptr, strlen(ptr)+1); - - path_has_drive = (('a' <= path[0] && path[0] <= 'z') || - ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':'; + memmove(path, ptr, strlen(ptr) + 1); } #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) - if(path_has_drive) { + if(STARTS_WITH_DRIVE_PREFIX(path)) { failf(data, "File drive letters are only accepted in MSDOS/Windows."); return CURLE_URL_MALFORMAT; } @@ -4471,7 +4539,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, else { /* clear path */ char slashbuf[4]; - path[0]=0; + path[0] = 0; rc = sscanf(data->change.url, "%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]", @@ -4556,7 +4624,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, */ at = strchr(conn->host.name, '@'); if(at) - query = strchr(at+1, '?'); + query = strchr(at + 1, '?'); else query = strchr(conn->host.name, '?'); @@ -4574,15 +4642,15 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, /* move the existing path plus the zero byte forward, to make room for the host-name part */ - memmove(path+hostlen+1, path, pathlen+1); + memmove(path + hostlen + 1, path, pathlen + 1); /* now copy the trailing host part in front of the existing path */ - memcpy(path+1, query, hostlen); + memcpy(path + 1, query, hostlen); path[0]='/'; /* prepend the missing slash */ rebuild_url = TRUE; - *query=0; /* now cut off the hostname at the ? */ + *query = 0; /* now cut off the hostname at the ? */ } else if(!path[0]) { /* if there's no path set, use a single slash */ @@ -4598,7 +4666,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, /* We need this function to deal with overlapping memory areas. We know that the memory area 'path' points to is 'urllen' bytes big and that is bigger than the path. Use +1 to move the zero byte too. */ - memmove(&path[1], path, strlen(path)+1); + memmove(&path[1], path, strlen(path) + 1); path[0] = '/'; rebuild_url = TRUE; } @@ -4704,7 +4772,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, if(*endp == ']') { /* The address scope was well formed. Knock it out of the hostname. */ - memmove(percent, endp, strlen(endp)+1); + memmove(percent, endp, strlen(endp) + 1); conn->scope_id = (unsigned int)scope; } else { @@ -4974,7 +5042,7 @@ static char *detect_proxy(struct connectdata *conn) strcpy(envp, "_proxy"); /* read the protocol proxy: */ - prox=curl_getenv(proxy_env); + prox = curl_getenv(proxy_env); /* * We don't try the uppercase version of HTTP_PROXY because of @@ -4991,7 +5059,7 @@ static char *detect_proxy(struct connectdata *conn) if(!prox && !strcasecompare("http_proxy", proxy_env)) { /* There was no lowercase variable, try the uppercase version: */ Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); - prox=curl_getenv(proxy_env); + prox = curl_getenv(proxy_env); } if(prox) @@ -4999,7 +5067,7 @@ static char *detect_proxy(struct connectdata *conn) else { proxy = curl_getenv("all_proxy"); /* default proxy to use */ if(!proxy) - proxy=curl_getenv("ALL_PROXY"); + proxy = curl_getenv("ALL_PROXY"); } return proxy; @@ -5034,7 +5102,7 @@ static CURLcode parse_proxy(struct Curl_easy *data, /* Parse the protocol part if present */ endofprot = strstr(proxy, "://"); if(endofprot) { - proxyptr = endofprot+3; + proxyptr = endofprot + 3; if(checkprefix("https", proxy)) proxytype = CURLPROXY_HTTPS; else if(checkprefix("socks5h", proxy)) @@ -5056,13 +5124,14 @@ static CURLcode parse_proxy(struct Curl_easy *data, else proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */ -#ifndef HTTPS_PROXY_SUPPORT - if(proxytype == CURLPROXY_HTTPS) { - failf(data, "Unsupported proxy \'%s\'" - ", libcurl is built without the HTTPS-proxy support.", proxy); - return CURLE_NOT_BUILT_IN; - } +#ifdef USE_SSL + if(!Curl_ssl->support_https_proxy) #endif + if(proxytype == CURLPROXY_HTTPS) { + failf(data, "Unsupported proxy \'%s\', libcurl is built without the " + "HTTPS-proxy support.", proxy); + return CURLE_NOT_BUILT_IN; + } sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME || proxytype == CURLPROXY_SOCKS5 || @@ -5133,11 +5202,14 @@ static CURLcode parse_proxy(struct Curl_easy *data, conn->port = port; } else { - if(proxyptr[0]=='/') + if(proxyptr[0]=='/') { /* If the first character in the proxy string is a slash, fail immediately. The following code will otherwise clear the string which will lead to code running as if no proxy was set! */ + Curl_safefree(proxyuser); + Curl_safefree(proxypasswd); return CURLE_COULDNT_RESOLVE_PROXY; + } /* without a port number after the host name, some people seem to use a slash so we strip everything from the first slash */ @@ -5280,22 +5352,21 @@ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn) } } - no_proxy = curl_getenv("no_proxy"); - if(!no_proxy) - no_proxy = curl_getenv("NO_PROXY"); + if(!data->set.str[STRING_NOPROXY]) { + no_proxy = curl_getenv("no_proxy"); + if(!no_proxy) + no_proxy = curl_getenv("NO_PROXY"); + } - if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY]) || - (!data->set.str[STRING_NOPROXY] && - check_noproxy(conn->host.name, no_proxy))) { + if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ? + data->set.str[STRING_NOPROXY] : no_proxy)) { Curl_safefree(proxy); Curl_safefree(socksproxy); } - else if(!proxy && !socksproxy) #ifndef CURL_DISABLE_HTTP + else if(!proxy && !socksproxy) /* if the host is not in the noproxy list, detect proxy. */ proxy = detect_proxy(conn); -#else /* !CURL_DISABLE_HTTP */ - proxy = NULL; #endif /* CURL_DISABLE_HTTP */ Curl_safefree(no_proxy); @@ -5348,12 +5419,15 @@ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn) result = CURLE_UNSUPPORTED_PROTOCOL; goto out; #else - /* force this connection's protocol to become HTTP if not already - compatible - if it isn't tunneling through */ - if(!(conn->handler->protocol & PROTO_FAMILY_HTTP) && - !conn->bits.tunnel_proxy) - conn->handler = &Curl_handler_http; - + /* force this connection's protocol to become HTTP if compatible */ + if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) { + if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) && + !conn->bits.tunnel_proxy) + conn->handler = &Curl_handler_http; + else + /* if not converting to HTTP over the proxy, enforce tunneling */ + conn->bits.tunnel_proxy = TRUE; + } conn->bits.httpproxy = TRUE; #endif } @@ -5740,7 +5814,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data, char *rest; long port; - port=strtol(portptr+1, &rest, 10); /* Port number must be decimal */ + port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */ if((port < 0) || (port > 0xffff)) { /* Single unix standard says port numbers are 16 bits long */ @@ -6096,7 +6170,7 @@ static CURLcode resolve_server(struct Curl_easy *data, struct connectdata *conn, bool *async) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; time_t timeout_ms = Curl_timeleft(data, NULL, TRUE); /************************************************************* @@ -6259,11 +6333,10 @@ static void reuse_conn(struct connectdata *old_conn, free_fixed_hostname(&conn->conn_to_host); Curl_safefree(conn->host.rawalloc); Curl_safefree(conn->conn_to_host.rawalloc); - conn->host=old_conn->host; - conn->bits.conn_to_host = old_conn->bits.conn_to_host; + conn->host = old_conn->host; conn->conn_to_host = old_conn->conn_to_host; - conn->bits.conn_to_port = old_conn->bits.conn_to_port; conn->conn_to_port = old_conn->conn_to_port; + conn->remote_port = old_conn->remote_port; /* persist connection info in session handle */ Curl_persistconninfo(conn); @@ -6362,9 +6435,9 @@ static CURLcode create_conn(struct Curl_easy *data, * other parts of the code will rely on this fact ***********************************************************/ #define LEAST_PATH_ALLOC 256 - urllen=strlen(data->change.url); + urllen = strlen(data->change.url); if(urllen < LEAST_PATH_ALLOC) - urllen=LEAST_PATH_ALLOC; + urllen = LEAST_PATH_ALLOC; /* * We malloc() the buffers below urllen+2 to make room for 2 possibilities: @@ -6375,14 +6448,14 @@ static CURLcode create_conn(struct Curl_easy *data, Curl_safefree(data->state.pathbuffer); data->state.path = NULL; - data->state.pathbuffer = malloc(urllen+2); + data->state.pathbuffer = malloc(urllen + 2); if(NULL == data->state.pathbuffer) { result = CURLE_OUT_OF_MEMORY; /* really bad error */ goto out; } data->state.path = data->state.pathbuffer; - conn->host.rawalloc = malloc(urllen+2); + conn->host.rawalloc = malloc(urllen + 2); if(NULL == conn->host.rawalloc) { Curl_safefree(data->state.pathbuffer); data->state.path = NULL; @@ -7015,7 +7088,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) k->buf = data->state.buffer; k->hbufp = data->state.headerbuff; - k->ignorebody=FALSE; + k->ignorebody = FALSE; Curl_speedinit(data); diff --git a/lib/urldata.h b/lib/urldata.h index d4a4a98..66e4596 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -82,75 +82,6 @@ #include "cookie.h" #include "formdata.h" -#ifdef USE_OPENSSL -#include -#ifdef HAVE_OPENSSL_ENGINE_H -#include -#endif -#endif /* USE_OPENSSL */ - -#ifdef USE_GNUTLS -#include -#endif - -#ifdef USE_MBEDTLS - -#include -#include -#include -#include - -#elif defined USE_POLARSSL - -#include -#include -#if POLARSSL_VERSION_NUMBER<0x01010000 -#include -#else -#include -#include -#endif /* POLARSSL_VERSION_NUMBER<0x01010000 */ - -#endif /* USE_POLARSSL */ - -#ifdef USE_CYASSL -#undef OCSP_REQUEST /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */ -#undef OCSP_RESPONSE /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */ -#include -#endif - -#ifdef USE_NSS -#include -#include -#endif - -#ifdef USE_GSKIT -#include -#endif - -#ifdef USE_AXTLS -#include -#include -#undef malloc -#undef calloc -#undef realloc -#endif /* USE_AXTLS */ - -#if defined(USE_SCHANNEL) || defined(USE_WINDOWS_SSPI) -#include "curl_sspi.h" -#endif -#ifdef USE_SCHANNEL -#include -#include -#endif - -#ifdef USE_DARWINSSL -#include -/* For some reason, when building for iOS, the omnibus header above does - * not include SecureTransport.h as of iOS SDK 5.1. */ -#include -#endif - #ifdef HAVE_NETINET_IN_H #include #endif @@ -172,6 +103,7 @@ #include "hash.h" #include "splay.h" +#include "mime.h" #include "imap.h" #include "pop3.h" #include "smtp.h" @@ -240,20 +172,6 @@ enum protection_level { }; #endif -#ifdef USE_SCHANNEL -/* Structs to store Schannel handles */ -struct curl_schannel_cred { - CredHandle cred_handle; - TimeStamp time_stamp; - int refcount; -}; - -struct curl_schannel_ctxt { - CtxtHandle ctxt_handle; - TimeStamp time_stamp; -}; -#endif - /* enum for the nonblocking SSL connection state machine */ typedef enum { ssl_connect_1, @@ -270,6 +188,9 @@ typedef enum { ssl_connection_complete } ssl_connection_state; +/* SSL backend-specific data; declared differently by each SSL backend */ +struct ssl_backend_data; + /* struct for data related to each SSL connection */ struct ssl_connect_data { /* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm @@ -278,78 +199,8 @@ struct ssl_connect_data { bool use; ssl_connection_state state; ssl_connect_state connecting_state; -#if defined(USE_OPENSSL) - /* these ones requires specific SSL-types */ - SSL_CTX* ctx; - SSL* handle; - X509* server_cert; -#elif defined(USE_GNUTLS) - gnutls_session_t session; - gnutls_certificate_credentials_t cred; -#ifdef USE_TLS_SRP - gnutls_srp_client_credentials_t srp_client_cred; -#endif -#elif defined(USE_MBEDTLS) - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_entropy_context entropy; - mbedtls_ssl_context ssl; - int server_fd; - mbedtls_x509_crt cacert; - mbedtls_x509_crt clicert; - mbedtls_x509_crl crl; - mbedtls_pk_context pk; - mbedtls_ssl_config config; - const char *protocols[3]; -#elif defined(USE_POLARSSL) - ctr_drbg_context ctr_drbg; - entropy_context entropy; - ssl_context ssl; - int server_fd; - x509_crt cacert; - x509_crt clicert; - x509_crl crl; - rsa_context rsa; -#elif defined(USE_CYASSL) - SSL_CTX* ctx; - SSL* handle; -#elif defined(USE_NSS) - PRFileDesc *handle; - char *client_nickname; - struct Curl_easy *data; - struct curl_llist obj_list; - PK11GenericObject *obj_clicert; -#elif defined(USE_GSKIT) - gsk_handle handle; - int iocport; - int localfd; - int remotefd; -#elif defined(USE_AXTLS) - SSL_CTX* ssl_ctx; - SSL* ssl; -#elif defined(USE_SCHANNEL) - struct curl_schannel_cred *cred; - struct curl_schannel_ctxt *ctxt; - SecPkgContext_StreamSizes stream_sizes; - size_t encdata_length, decdata_length; - size_t encdata_offset, decdata_offset; - unsigned char *encdata_buffer, *decdata_buffer; - /* encdata_is_incomplete: if encdata contains only a partial record that - can't be decrypted without another Curl_read_plain (that is, status is - SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes - more bytes into encdata then set this back to false. */ - bool encdata_is_incomplete; - unsigned long req_flags, ret_flags; - CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ - bool recv_sspi_close_notify; /* true if connection closed by close_notify */ - bool recv_connection_closed; /* true if connection closed, regardless how */ - bool use_alpn; /* true if ALPN is used for this connection */ -#elif defined(USE_DARWINSSL) - SSLContextRef ssl_ctx; - curl_socket_t ssl_sockfd; - bool ssl_direction; /* true if writing, false if reading */ - size_t ssl_write_buffered_length; -#elif defined(USE_SSL) -#error "SSL backend specific information missing from ssl_connect_data" +#if defined(USE_SSL) + struct ssl_backend_data *backend; #endif }; @@ -359,13 +210,13 @@ struct ssl_primary_config { bool verifypeer; /* set TRUE if this is desired */ bool verifyhost; /* set TRUE if CN/SAN must match hostname */ bool verifystatus; /* set TRUE if certificate status must be checked */ + bool sessionid; /* cache session IDs or not */ char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* certificate to verify peer against */ char *clientcert; char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ char *cipher_list; /* list of ciphers to use */ - bool sessionid; /* cache session IDs or not */ }; struct ssl_config_data { @@ -411,12 +262,20 @@ struct curl_ssl_session { struct ssl_primary_config ssl_config; /* setup for this session */ }; +#ifdef USE_WINDOWS_SSPI +#include "curl_sspi.h" +#endif + /* Struct used for Digest challenge-response authentication */ struct digestdata { #if defined(USE_WINDOWS_SSPI) BYTE *input_token; size_t input_token_len; CtxtHandle *http_context; + /* copy of user/passwd used to make the identity for http_context. + either may be NULL. */ + char *user; + char *passwd; #else char *nonce; char *cnonce; @@ -438,10 +297,6 @@ typedef enum { NTLMSTATE_LAST } curlntlm; -#ifdef USE_WINDOWS_SSPI -#include "curl_sspi.h" -#endif - #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) #include #endif @@ -678,8 +533,8 @@ struct SingleRequest { 100 reply (without a following second response code) result in a CURLE_GOT_NOTHING error code */ - struct timeval start; /* transfer started at this time */ - struct timeval now; /* current time */ + struct curltime start; /* transfer started at this time */ + struct curltime now; /* current time */ bool header; /* incoming data has HTTP header */ enum { HEADER_NORMAL, /* no bad header at all */ @@ -701,7 +556,7 @@ struct SingleRequest { Content-Range: header */ int httpcode; /* error code from the 'HTTP/1.? XXX' or 'RTSP/1.? XXX' line */ - struct timeval start100; /* time stamp to wait for the 100 code from */ + struct curltime start100; /* time stamp to wait for the 100 code from */ enum expect100 exp100; /* expect 100 continue state */ enum upgrade101 upgr101; /* 101 upgrade state */ @@ -829,6 +684,12 @@ struct Curl_handler { CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore); + /* This function can perform various checks on the connection. See + CONNCHECK_* for more information about the checks that can be performed, + and CONNRESULT_* for the results that can be returned. */ + unsigned int (*connection_check)(struct connectdata *conn, + unsigned int checks_to_perform); + long defport; /* Default port. */ unsigned int protocol; /* See CURLPROTO_* - this needs to be the single specific protocol bit */ @@ -855,6 +716,15 @@ struct Curl_handler { #define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ #define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field of the URL */ +#define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a + HTTP proxy as HTTP proxies may know + this protocol and act as a gateway */ + +#define CONNCHECK_NONE 0 /* No checks */ +#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */ + +#define CONNRESULT_NONE 0 /* No extra information. */ +#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */ /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -892,6 +762,24 @@ 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 */ + int keepon; + char *line_start; + char *ptr; /* where to store more data */ + curl_off_t cl; /* size of content to read and ignore */ + bool chunked_encoding; + enum { + TUNNEL_INIT, /* init/default/no tunnel state */ + TUNNEL_CONNECT, /* CONNECT has been sent off */ + TUNNEL_COMPLETE /* CONNECT response received completely */ + } tunnel_state; +}; + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. @@ -983,8 +871,8 @@ struct connectdata { int httpversion; /* the HTTP version*10 reported by the server */ int rtspversion; /* the RTSP version*10 reported by the server */ - struct timeval now; /* "current" time */ - struct timeval created; /* creation time */ + struct curltime now; /* "current" time */ + struct curltime created; /* creation time */ 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 */ @@ -1007,7 +895,7 @@ struct connectdata { /* connecttime: when connect() is called on the current IP address. Used to be able to track when to move on to try next IP - but only when the multi interface is used. */ - struct timeval connecttime; + struct curltime connecttime; /* The two fields below get set in Curl_connecthost */ int num_addr; /* number of addresses to try to connect to */ time_t timeoutms_per_addr; /* how long time in milliseconds to spend on @@ -1134,22 +1022,24 @@ struct connectdata { char *localdev; unsigned short localport; int localportrange; - - /* tunnel as in tunnel through a HTTP proxy with CONNECT */ - enum { - TUNNEL_INIT, /* init/default/no tunnel state */ - TUNNEL_CONNECT, /* CONNECT has been sent off */ - TUNNEL_COMPLETE /* CONNECT response received completely */ - } tunnel_state[2]; /* two separate ones to allow FTP */ + 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* */ - char *connect_buffer; /* for CONNECT business */ #ifdef USE_UNIX_SOCKETS char *unix_domain_socket; bool abstract_unix_socket; #endif + +#ifdef USE_SSL + /* + * To avoid multiple malloc() calls, the ssl_connect_data structures + * associated with a connectdata struct are allocated in the same block + * as the latter. This field forces alignment to an 8-byte boundary so + * that this all works. + */ + long long *align_data__do_not_use; +#endif }; /* The end of connectdata. */ @@ -1213,34 +1103,36 @@ struct Progress { int width; /* screen width at download start */ int flags; /* see progress.h */ - double timespent; + time_t timespent; curl_off_t dlspeed; curl_off_t ulspeed; - double t_nslookup; - double t_connect; - double t_appconnect; - double t_pretransfer; - double t_starttransfer; - double t_redirect; + time_t t_nslookup; + time_t t_connect; + time_t t_appconnect; + time_t t_pretransfer; + time_t t_starttransfer; + time_t t_redirect; - struct timeval start; - struct timeval t_startsingle; - struct timeval t_startop; - struct timeval t_acceptdata; + struct curltime start; + struct curltime t_startsingle; + struct curltime t_startop; + struct curltime t_acceptdata; + + bool is_t_startransfer_set; /* upload speed limit */ - struct timeval ul_limit_start; + struct curltime ul_limit_start; curl_off_t ul_limit_size; /* download speed limit */ - struct timeval dl_limit_start; + struct curltime dl_limit_start; curl_off_t dl_limit_size; -#define CURR_TIME (5+1) /* 6 entries for 5 seconds */ +#define CURR_TIME (5 + 1) /* 6 entries for 5 seconds */ curl_off_t speeder[ CURR_TIME ]; - struct timeval speeder_time[ CURR_TIME ]; + struct curltime speeder_time[ CURR_TIME ]; int speeder_c; }; @@ -1249,8 +1141,10 @@ typedef enum { HTTPREQ_GET, HTTPREQ_POST, HTTPREQ_POST_FORM, /* we make a difference internally */ + HTTPREQ_POST_MIME, /* we make a difference internally */ HTTPREQ_PUT, HTTPREQ_HEAD, + HTTPREQ_OPTIONS, HTTPREQ_CUSTOM, HTTPREQ_LAST /* last in list */ } Curl_HttpReq; @@ -1334,7 +1228,7 @@ typedef enum { */ struct time_node { struct curl_llist_element list; - struct timeval time; + struct curltime time; expire_id eid; }; @@ -1349,7 +1243,7 @@ struct UrlState { bool multi_owned_by_easy; /* buffers to store authentication data in, as parsed from input options */ - struct timeval keeps_speed; /* for the progress meter really */ + struct curltime keeps_speed; /* for the progress meter really */ struct connectdata *lastconnect; /* The last connection, NULL if undefined */ @@ -1357,7 +1251,7 @@ struct UrlState { size_t headersize; /* size of the allocation */ char *buffer; /* download buffer */ - char uploadbuffer[UPLOAD_BUFSIZE+1]; /* upload buffer */ + char uploadbuffer[UPLOAD_BUFSIZE + 1]; /* upload buffer */ curl_off_t current_speed; /* the ProgressShow() function sets this, bytes / second */ bool this_is_a_follow; /* this is a followed Location: request */ @@ -1401,9 +1295,10 @@ struct UrlState { ares_channel f.e. */ #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) - ENGINE *engine; + /* void instead of ENGINE to avoid bleeding OpenSSL into this header */ + void *engine; #endif /* USE_OPENSSL */ - struct timeval expiretime; /* set this with Curl_expire() only */ + struct curltime expiretime; /* set this with Curl_expire() only */ struct Curl_tree timenode; /* for the splay stuff */ struct curl_llist timeoutlist; /* list of pending timeouts */ struct time_node expires[EXPIRE_LAST]; /* nodes for each expire type */ @@ -1574,7 +1469,7 @@ enum dupstring { #ifdef USE_UNIX_SOCKETS STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */ #endif - + STRING_TARGET, /* CURLOPT_REQUEST_TARGET */ /* -- end of zero-terminated strings -- */ STRING_LASTZEROTERMINATED, @@ -1601,6 +1496,7 @@ struct UserDefined { long use_port; /* which port to use (when not using default) */ unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */ unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */ + unsigned long socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */ long followlocation; /* as in HTTP Location: */ long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 for infinity */ @@ -1663,7 +1559,8 @@ struct UserDefined { curl_off_t set_resume_from; /* continue [ftp] transfer from here */ struct curl_slist *headers; /* linked list of extra headers */ struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */ - struct curl_httppost *httppost; /* linked list of POST data */ + struct curl_httppost *httppost; /* linked list of old POST data */ + curl_mimepart mimepost; /* MIME/POST data. */ bool sep_headers; /* handle host and proxy headers separately */ bool cookiesession; /* new cookie session? */ bool crlf; /* convert crlf on ftp upload(?) */ @@ -1685,6 +1582,7 @@ struct UserDefined { Curl_HttpReq httpreq; /* 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) */ + bool strip_path_slash; /* strip off initial slash from path */ struct ssl_config_data ssl; /* user defined SSL stuff */ struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ struct ssl_general_config general_ssl; /* general user defined SSL stuff */ @@ -1708,6 +1606,7 @@ struct UserDefined { curl_sshkeycallback ssh_keyfunc; /* key matching callback */ void *ssh_keyfunc_userp; /* custom pointer to callback */ + bool ssh_compression; /* enable SSH compression */ /* Here follows boolean settings that define how to behave during this session. They are STATIC, set by libcurl users or at least initially diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index 0bd9444..a3f96ed 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -352,8 +352,8 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, if(!Curl_auth_digest_get_pair(p, value, content, &p)) break; - if(Curl_strcasecompare(value, "stale") - && Curl_strcasecompare(content, "true")) { + if(strcasecompare(value, "stale") && + strcasecompare(content, "true")) { stale = true; break; } @@ -438,6 +438,20 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } + /* If the user/passwd that was used to make the identity for http_context + has changed then delete that context. */ + if((userp && !digest->user) || (!userp && digest->user) || + (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || + (userp && digest->user && strcmp(userp, digest->user)) || + (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) { + if(digest->http_context) { + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); + } + Curl_safefree(digest->user); + Curl_safefree(digest->passwd); + } + if(digest->http_context) { chlg_desc.ulVersion = SECBUFFER_VERSION; chlg_desc.cBuffers = 5; @@ -479,6 +493,10 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ TCHAR *spn; + /* free the copy of user/passwd used to make the previous identity */ + Curl_safefree(digest->user); + Curl_safefree(digest->passwd); + if(userp && *userp) { /* Populate our identity structure */ if(Curl_create_sspi_identity(userp, passwdp, &identity)) { @@ -500,6 +518,25 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, /* Use the current Windows user */ p_identity = NULL; + if(userp) { + digest->user = strdup(userp); + + if(!digest->user) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } + } + + if(passwdp) { + digest->passwd = strdup(passwdp); + + if(!digest->passwd) { + free(output_token); + Curl_safefree(digest->user); + return CURLE_OUT_OF_MEMORY; + } + } + /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT(SP_NAME_DIGEST), @@ -623,6 +660,10 @@ void Curl_auth_digest_cleanup(struct digestdata *digest) s_pSecFn->DeleteSecurityContext(digest->http_context); Curl_safefree(digest->http_context); } + + /* Free the copy of user/passwd used to make the identity for http_context */ + Curl_safefree(digest->user); + Curl_safefree(digest->passwd); } #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c index 4219645..50d9222 100644 --- a/lib/vauth/ntlm.c +++ b/lib/vauth/ntlm.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,7 +44,9 @@ #include "rand.h" #include "vtls/vtls.h" -#ifdef USE_NSS +/* SSL backend-specific #if branches in this file must be kept in the order + documented in curl_ntlm_core. */ +#if defined(NTLM_NEEDS_NSS_INIT) #include "vtls/nssg.h" /* for Curl_nss_force_init() */ #endif @@ -272,7 +274,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, unsigned char *type2 = NULL; size_t type2_len = 0; -#if defined(USE_NSS) +#if defined(NTLM_NEEDS_NSS_INIT) /* Make sure the crypto backend is initialized */ result = Curl_nss_force_init(data); if(result) @@ -350,6 +352,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) * * Parameters: * + * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. * ntlm [in/out] - The NTLM data struct being used and modified. @@ -359,7 +362,8 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, +CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, + const char *userp, const char *passwdp, struct ntlmdata *ntlm, char **outptr, size_t *outlen) @@ -458,7 +462,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, }); /* Return with binary blob encoded into base64 */ - return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); + return Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen); } /* @@ -827,7 +831,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, return CURLE_CONV_FAILED; /* Return with binary blob encoded into base64 */ - result = Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); + result = Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen); Curl_auth_ntlm_cleanup(ntlm); diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index c330517..e748ce3 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,6 +29,7 @@ #include "vauth/vauth.h" #include "urldata.h" #include "curl_base64.h" +#include "curl_ntlm_core.h" #include "warnless.h" #include "curl_multibyte.h" #include "sendf.h" @@ -66,6 +67,7 @@ bool Curl_auth_is_ntlm_supported(void) * * Parameters: * + * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. * ntlm [in/out] - The NTLM data struct being used and modified. @@ -75,7 +77,8 @@ bool Curl_auth_is_ntlm_supported(void) * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, +CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, + const char *userp, const char *passwdp, struct ntlmdata *ntlm, char **outptr, size_t *outlen) @@ -166,7 +169,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, return CURLE_RECV_ERROR; /* Base64 encode the response */ - return Curl_base64_encode(NULL, (char *) ntlm->output_token, + return Curl_base64_encode(data, (char *) ntlm->output_token, type_1_buf.cbBuffer, outptr, outlen); } diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c index 8840db8..5196c27 100644 --- a/lib/vauth/spnego_gssapi.c +++ b/lib/vauth/spnego_gssapi.c @@ -180,6 +180,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } + /* Free previous token */ + if(nego->output_token.length && nego->output_token.value) + gss_release_buffer(&unused_status, &nego->output_token); + nego->output_token = output_token; return CURLE_OK; diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index 9d61228..dfaf985 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014 - 2016, Steve Holme, . + * Copyright (C) 2014 - 2017, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -119,7 +119,8 @@ void Curl_auth_digest_cleanup(struct digestdata *digest); bool Curl_auth_is_ntlm_supported(void); /* This is used to generate a base64 encoded NTLM type-1 message */ -CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, +CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, + const char *userp, const char *passwdp, struct ntlmdata *ntlm, char **outptr, diff --git a/lib/version.c b/lib/version.c index 3d17768..ebd6006 100644 --- a/lib/version.c +++ b/lib/version.c @@ -324,8 +324,8 @@ static curl_version_info_data version_info = { #if defined(USE_LIBPSL) | CURL_VERSION_PSL #endif -#if defined(HTTPS_PROXY_SUPPORT) - | CURL_VERSION_HTTPS_PROXY +#if defined(CURL_WITH_MULTI_SSL) + | CURL_VERSION_MULTI_SSL #endif , NULL, /* ssl_version */ @@ -355,6 +355,10 @@ curl_version_info_data *curl_version_info(CURLversion stamp) #ifdef USE_SSL Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); version_info.ssl_version = ssl_buffer; + if(Curl_ssl->support_https_proxy) + version_info.features |= CURL_VERSION_HTTPS_PROXY; + else + version_info.features &= ~CURL_VERSION_HTTPS_PROXY; #endif #ifdef HAVE_LIBZ diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c index f0e3766..6b42708 100644 --- a/lib/vtls/axtls.c +++ b/lib/vtls/axtls.c @@ -47,21 +47,12 @@ #include "curl_memory.h" #include "memdebug.h" +struct ssl_backend_data { + SSL_CTX* ssl_ctx; + SSL* ssl; +}; -/* Global axTLS init, called from Curl_ssl_init() */ -int Curl_axtls_init(void) -{ -/* axTLS has no global init. Everything is done through SSL and SSL_CTX - * structs stored in connectdata structure. Perhaps can move to axtls.h. - */ - return 1; -} - -int Curl_axtls_cleanup(void) -{ - /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */ - return 1; -} +#define BACKEND connssl->backend static CURLcode map_error_to_curl(int axtls_err) { @@ -120,13 +111,13 @@ static Curl_send axtls_send; static void free_ssl_structs(struct ssl_connect_data *connssl) { - if(connssl->ssl) { - ssl_free(connssl->ssl); - connssl->ssl = NULL; + if(BACKEND->ssl) { + ssl_free(BACKEND->ssl); + BACKEND->ssl = NULL; } - if(connssl->ssl_ctx) { - ssl_ctx_free(connssl->ssl_ctx); - connssl->ssl_ctx = NULL; + if(BACKEND->ssl_ctx) { + ssl_ctx_free(BACKEND->ssl_ctx); + BACKEND->ssl_ctx = NULL; } } @@ -137,6 +128,7 @@ static void free_ssl_structs(struct ssl_connect_data *connssl) */ static CURLcode connect_prep(struct connectdata *conn, int sockindex) { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; SSL_CTX *ssl_ctx; SSL *ssl = NULL; @@ -151,7 +143,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) SSL_SERVER_VERIFY_LATER | SSL_CONNECT_IN_PARTS; - if(conn->ssl[sockindex].state == ssl_connection_complete) + if(connssl->state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ return CURLE_OK; @@ -185,8 +177,8 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } - conn->ssl[sockindex].ssl_ctx = ssl_ctx; - conn->ssl[sockindex].ssl = NULL; + BACKEND->ssl_ctx = ssl_ctx; + BACKEND->ssl = NULL; /* Load the trusted CA cert bundle file */ if(SSL_CONN_CONFIG(CAfile)) { @@ -212,7 +204,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* Load client certificate */ if(SSL_SET_OPTION(cert)) { - i=0; + i = 0; /* Instead of trying to analyze cert type here, let axTLS try them all. */ while(cert_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], @@ -236,7 +228,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) If a pkcs12 file successfully loaded a cert, then there's nothing to do because the key has already been loaded. */ if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) { - i=0; + i = 0; /* Instead of trying to analyze key type here, let axTLS try them all. */ while(key_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], @@ -281,10 +273,26 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) if(!ssl) ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL); - conn->ssl[sockindex].ssl = ssl; + BACKEND->ssl = ssl; return CURLE_OK; } +static void Curl_axtls_close(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + infof(conn->data, " Curl_axtls_close\n"); + + /* line from openssl.c: (void)SSL_shutdown(BACKEND->ssl); + axTLS compat layer does nothing for SSL_shutdown */ + + /* The following line is from openssl.c. There seems to be no axTLS + equivalent. ssl_free and ssl_ctx_free close things. + SSL_set_connect_state(connssl->handle); */ + + free_ssl_structs(connssl); +} + /* * For both blocking and non-blocking connects, this function finalizes the * SSL connection. @@ -292,7 +300,8 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) static CURLcode connect_finish(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; - SSL *ssl = conn->ssl[sockindex].ssl; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + SSL *ssl = BACKEND->ssl; const char *peer_CN; uint32_t dns_altname_index; const char *dns_altname; @@ -387,7 +396,7 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) } /* General housekeeping */ - conn->ssl[sockindex].state = ssl_connection_complete; + connssl->state = ssl_connection_complete; conn->recv[sockindex] = axtls_recv; conn->send[sockindex] = axtls_send; @@ -409,11 +418,10 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) * Use axTLS's non-blocking connection feature to open an SSL connection. * This is called after a TCP connection is already established. */ -CURLcode Curl_axtls_connect_nonblocking( - struct connectdata *conn, - int sockindex, - bool *done) +static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode conn_step; int ssl_fcn_return; int i; @@ -421,23 +429,23 @@ CURLcode Curl_axtls_connect_nonblocking( *done = FALSE; /* connectdata is calloc'd and connecting_state is only changed in this function, so this is safe, as the state is effectively initialized. */ - if(conn->ssl[sockindex].connecting_state == ssl_connect_1) { + if(connssl->connecting_state == ssl_connect_1) { conn_step = connect_prep(conn, sockindex); if(conn_step != CURLE_OK) { Curl_axtls_close(conn, sockindex); return conn_step; } - conn->ssl[sockindex].connecting_state = ssl_connect_2; + connssl->connecting_state = ssl_connect_2; } - if(conn->ssl[sockindex].connecting_state == ssl_connect_2) { + if(connssl->connecting_state == ssl_connect_2) { /* Check to make sure handshake was ok. */ - if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) { + if(ssl_handshake_status(BACKEND->ssl) != SSL_OK) { /* Loop to perform more work in between sleeps. This is work around the fact that axtls does not expose any knowledge about when work needs to be performed. This can save ~25% of time on SSL handshakes. */ - for(i=0; i<5; i++) { - ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL); + for(i = 0; i<5; i++) { + ssl_fcn_return = ssl_read(BACKEND->ssl, NULL); if(ssl_fcn_return < 0) { Curl_axtls_close(conn, sockindex); ssl_display_error(ssl_fcn_return); /* goes to stdout. */ @@ -447,10 +455,10 @@ CURLcode Curl_axtls_connect_nonblocking( } } infof(conn->data, "handshake completed successfully\n"); - conn->ssl[sockindex].connecting_state = ssl_connect_3; + connssl->connecting_state = ssl_connect_3; } - if(conn->ssl[sockindex].connecting_state == ssl_connect_3) { + if(connssl->connecting_state == ssl_connect_3) { conn_step = connect_finish(conn, sockindex); if(conn_step != CURLE_OK) { Curl_axtls_close(conn, sockindex); @@ -458,15 +466,15 @@ CURLcode Curl_axtls_connect_nonblocking( } /* Reset connect state */ - conn->ssl[sockindex].connecting_state = ssl_connect_1; + connssl->connecting_state = ssl_connect_1; *done = TRUE; return CURLE_OK; } /* Unrecognized state. Things are very bad. */ - conn->ssl[sockindex].state = ssl_connection_none; - conn->ssl[sockindex].connecting_state = ssl_connect_1; + connssl->state = ssl_connection_none; + connssl->connecting_state = ssl_connect_1; /* Return value perhaps not strictly correct, but distinguishes the issue.*/ return CURLE_BAD_FUNCTION_ARGUMENT; } @@ -476,15 +484,13 @@ CURLcode Curl_axtls_connect_nonblocking( * This function is called after the TCP connect has completed. Setup the TLS * layer and do all necessary magic for a blocking connect. */ -CURLcode -Curl_axtls_connect(struct connectdata *conn, - int sockindex) - +static CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; CURLcode conn_step = connect_prep(conn, sockindex); int ssl_fcn_return; - SSL *ssl = conn->ssl[sockindex].ssl; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + SSL *ssl = BACKEND->ssl; long timeout_ms; if(conn_step != CURLE_OK) { @@ -530,8 +536,9 @@ static ssize_t axtls_send(struct connectdata *conn, size_t len, CURLcode *err) { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; /* ssl_write() returns 'int' while write() and send() returns 'size_t' */ - int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len); + int rc = ssl_write(BACKEND->ssl, mem, (int)len); infof(conn->data, " axtls_send\n"); @@ -544,27 +551,11 @@ static ssize_t axtls_send(struct connectdata *conn, return rc; } -void Curl_axtls_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - infof(conn->data, " Curl_axtls_close\n"); - - /* line from openssl.c: (void)SSL_shutdown(connssl->ssl); - axTLS compat layer does nothing for SSL_shutdown */ - - /* The following line is from openssl.c. There seems to be no axTLS - equivalent. ssl_free and ssl_ctx_free close things. - SSL_set_connect_state(connssl->handle); */ - - free_ssl_structs(connssl); -} - /* * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ -int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) +static int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) { /* Outline taken from openssl.c since functions are in axTLS compat layer. axTLS's error set is much smaller, so a lot of error-handling was removed. @@ -584,17 +575,17 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - (void)SSL_shutdown(connssl->ssl); + (void)SSL_shutdown(BACKEND->ssl); */ - if(connssl->ssl) { + if(BACKEND->ssl) { int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server. buf is managed internally by axTLS and will be released upon calling ssl_free via free_ssl_structs. */ - nread = (ssize_t)ssl_read(connssl->ssl, &buf); + nread = (ssize_t)ssl_read(BACKEND->ssl, &buf); if(nread < SSL_OK) { failf(data, "close notify alert not received during shutdown"); @@ -630,7 +621,7 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ *err = CURLE_OK; if(connssl) { - ret = ssl_read(connssl->ssl, &read_buf); + ret = ssl_read(BACKEND->ssl, &read_buf); if(ret > SSL_OK) { /* ssl_read returns SSL_OK if there is more data to read, so if it is larger, then all data has been read already. */ @@ -663,9 +654,10 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ * 0 means the connection has been closed * -1 means the connection status is unknown */ -int Curl_axtls_check_cxn(struct connectdata *conn) +static int Curl_axtls_check_cxn(struct connectdata *conn) { - /* openssl.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1); + /* openssl.c line: + rc = SSL_peek(conn->ssl[FIRSTSOCKET].backend->ssl, (void*)&buf, 1); axTLS compat layer always returns the last argument, so connection is always alive? */ @@ -673,7 +665,7 @@ int Curl_axtls_check_cxn(struct connectdata *conn) return 1; /* connection still in place */ } -void Curl_axtls_session_free(void *ptr) +static void Curl_axtls_session_free(void *ptr) { (void)ptr; /* free the ID */ @@ -681,14 +673,13 @@ void Curl_axtls_session_free(void *ptr) compatibility layer does nothing, so we do nothing too. */ } -size_t Curl_axtls_version(char *buffer, size_t size) +static size_t Curl_axtls_version(char *buffer, size_t size) { return snprintf(buffer, size, "axTLS/%s", ssl_version()); } -CURLcode Curl_axtls_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +static CURLcode Curl_axtls_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) { static bool ssl_seeded = FALSE; (void)data; @@ -703,4 +694,49 @@ CURLcode Curl_axtls_random(struct Curl_easy *data, return CURLE_OK; } +static void *Curl_axtls_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + (void)info; + return BACKEND->ssl; +} + +const struct Curl_ssl Curl_ssl_axtls = { + { CURLSSLBACKEND_AXTLS, "axtls" }, /* info */ + + 0, /* have_ca_path */ + 0, /* have_certinfo */ + 0, /* have_pinnedpubkey */ + 0, /* have_ssl_ctx */ + 0, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + /* + * axTLS has no global init. Everything is done through SSL and SSL_CTX + * structs stored in connectdata structure. + */ + Curl_none_init, /* init */ + /* axTLS has no global cleanup. */ + Curl_none_cleanup, /* cleanup */ + Curl_axtls_version, /* version */ + Curl_axtls_check_cxn, /* check_cxn */ + Curl_axtls_shutdown, /* shutdown */ + Curl_none_data_pending, /* data_pending */ + Curl_axtls_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + Curl_axtls_connect, /* connect */ + Curl_axtls_connect_nonblocking, /* connect_nonblocking */ + Curl_axtls_get_internals, /* get_internals */ + Curl_axtls_close, /* close */ + Curl_none_close_all, /* close_all */ + Curl_axtls_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_none_md5sum, /* md5sum */ + NULL /* sha256sum */ +}; + #endif /* USE_AXTLS */ diff --git a/lib/vtls/axtls.h b/lib/vtls/axtls.h index 53797ea..3f1e129 100644 --- a/lib/vtls/axtls.h +++ b/lib/vtls/axtls.h @@ -27,44 +27,7 @@ #include "curl/curl.h" #include "urldata.h" -int Curl_axtls_init(void); -int Curl_axtls_cleanup(void); -CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_axtls_connect_nonblocking( - struct connectdata *conn, - int sockindex, - bool *done); - - /* close a SSL connection */ -void Curl_axtls_close(struct connectdata *conn, int sockindex); - -void Curl_axtls_session_free(void *ptr); -size_t Curl_axtls_version(char *buffer, size_t size); -int Curl_axtls_shutdown(struct connectdata *conn, int sockindex); -int Curl_axtls_check_cxn(struct connectdata *conn); -CURLcode Curl_axtls_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length); - -/* Set the API backend definition to axTLS */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_AXTLS - -/* API setup for axTLS */ -#define curlssl_init Curl_axtls_init -#define curlssl_cleanup Curl_axtls_cleanup -#define curlssl_connect Curl_axtls_connect -#define curlssl_connect_nonblocking Curl_axtls_connect_nonblocking -#define curlssl_session_free(x) Curl_axtls_session_free(x) -#define curlssl_close_all(x) ((void)x) -#define curlssl_close Curl_axtls_close -#define curlssl_shutdown(x,y) Curl_axtls_shutdown(x,y) -#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) -#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) -#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) -#define curlssl_version Curl_axtls_version -#define curlssl_check_cxn(x) Curl_axtls_check_cxn(x) -#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) -#define curlssl_random(x,y,z) Curl_axtls_random(x,y,z) +extern const struct Curl_ssl Curl_ssl_axtls; #endif /* USE_AXTLS */ #endif /* HEADER_CURL_AXTLS_H */ diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c index 01bfdab..ba5ee15 100644 --- a/lib/vtls/cyassl.c +++ b/lib/vtls/cyassl.c @@ -91,6 +91,7 @@ and that's a problem since options.h hasn't been included yet. */ #include "x509asn1.h" #include "curl_printf.h" +#include #include #ifdef HAVE_CYASSL_ERROR_SSL_H #include @@ -110,6 +111,25 @@ and that's a problem since options.h hasn't been included yet. */ #define CYASSL_MAX_ERROR_SZ 80 #endif +/* KEEP_PEER_CERT is a product of the presence of build time symbol + OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is + in wolfSSL's settings.h, and the latter two are build time symbols in + options.h. */ +#ifndef KEEP_PEER_CERT +#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \ + defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ + (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) +#define KEEP_PEER_CERT +#endif +#endif + +struct ssl_backend_data { + SSL_CTX* ctx; + SSL* handle; +}; + +#define BACKEND connssl->backend + static Curl_recv cyassl_recv; static Curl_send cyassl_send; @@ -136,7 +156,7 @@ cyassl_connect_step1(struct connectdata *conn, char error_buffer[CYASSL_MAX_ERROR_SZ]; char *ciphers; struct Curl_easy *data = conn->data; - struct ssl_connect_data* conssl = &conn->ssl[sockindex]; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI @@ -146,7 +166,7 @@ cyassl_connect_step1(struct connectdata *conn, #define use_sni(x) Curl_nop_stmt #endif - if(conssl->state == ssl_connection_complete) + if(connssl->state == ssl_connection_complete) return CURLE_OK; if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { @@ -205,11 +225,11 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - if(conssl->ctx) - SSL_CTX_free(conssl->ctx); - conssl->ctx = SSL_CTX_new(req_method); + if(BACKEND->ctx) + SSL_CTX_free(BACKEND->ctx); + BACKEND->ctx = SSL_CTX_new(req_method); - if(!conssl->ctx) { + if(!BACKEND->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } @@ -225,9 +245,9 @@ cyassl_connect_step1(struct connectdata *conn, version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion because only the former will work before the user's CTX callback is called. */ - if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) && - (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) && - (wolfSSL_CTX_SetMinVersion(conssl->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)) { failf(data, "SSL: couldn't set the minimum protocol version"); return CURLE_SSL_CONNECT_ERROR; } @@ -237,7 +257,7 @@ cyassl_connect_step1(struct connectdata *conn, ciphers = SSL_CONN_CONFIG(cipher_list); if(ciphers) { - if(!SSL_CTX_set_cipher_list(conssl->ctx, ciphers)) { + if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } @@ -247,7 +267,7 @@ cyassl_connect_step1(struct connectdata *conn, #ifndef NO_FILESYSTEM /* load trusted cacert */ if(SSL_CONN_CONFIG(CAfile)) { - if(1 != SSL_CTX_load_verify_locations(conssl->ctx, + if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx, SSL_CONN_CONFIG(CAfile), SSL_CONN_CONFIG(CApath))) { if(SSL_CONN_CONFIG(verifypeer)) { @@ -284,7 +304,7 @@ cyassl_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(conssl->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?)"); @@ -292,7 +312,7 @@ cyassl_connect_step1(struct connectdata *conn, } file_type = do_file_type(SSL_SET_OPTION(key_type)); - if(SSL_CTX_use_PrivateKey_file(conssl->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; @@ -304,7 +324,7 @@ cyassl_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(conssl->ctx, + SSL_CTX_set_verify(BACKEND->ctx, SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: SSL_VERIFY_NONE, NULL); @@ -323,7 +343,7 @@ cyassl_connect_step1(struct connectdata *conn, #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) && #endif - (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, hostname, + (CyaSSL_CTX_UseSNI(BACKEND->ctx, CYASSL_SNI_HOST_NAME, hostname, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -336,15 +356,15 @@ cyassl_connect_step1(struct connectdata *conn, https://github.com/wolfSSL/wolfssl/issues/366 The supported curves below are those also supported by OpenSSL 1.0.2 and in the same order. */ - CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */ - CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */ - CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */ + CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x17); /* secp256r1 */ + CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x19); /* secp521r1 */ + CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x18); /* secp384r1 */ #endif /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { CURLcode result = CURLE_OK; - result = (*data->set.ssl.fsslctx)(data, conssl->ctx, + result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, data->set.ssl.fsslctxp); if(result) { failf(data, "error signaled by ssl ctx callback"); @@ -362,10 +382,10 @@ cyassl_connect_step1(struct connectdata *conn, #endif /* Let's make an SSL structure */ - if(conssl->handle) - SSL_free(conssl->handle); - conssl->handle = SSL_new(conssl->ctx); - if(!conssl->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; } @@ -388,7 +408,7 @@ cyassl_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(conssl->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"); @@ -404,10 +424,10 @@ cyassl_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(conssl->handle, ssl_sessionid)) { + if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(conssl->handle, 0), + ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } @@ -418,12 +438,12 @@ cyassl_connect_step1(struct connectdata *conn, } /* pass the raw socket into the SSL layer */ - if(!SSL_set_fd(conssl->handle, (int)sockfd)) { + if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } - conssl->connecting_state = ssl_connect_2; + connssl->connecting_state = ssl_connect_2; return CURLE_OK; } @@ -434,7 +454,7 @@ cyassl_connect_step2(struct connectdata *conn, { int ret = -1; struct Curl_easy *data = conn->data; - struct ssl_connect_data* conssl = &conn->ssl[sockindex]; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const char * const dispname = SSL_IS_PROXY() ? @@ -448,22 +468,22 @@ cyassl_connect_step2(struct connectdata *conn, /* Enable RFC2818 checks */ if(SSL_CONN_CONFIG(verifyhost)) { - ret = CyaSSL_check_domain_name(conssl->handle, hostname); + ret = CyaSSL_check_domain_name(BACKEND->handle, hostname); if(ret == SSL_FAILURE) return CURLE_OUT_OF_MEMORY; } - ret = SSL_connect(conssl->handle); + ret = SSL_connect(BACKEND->handle); if(ret != 1) { char error_buffer[CYASSL_MAX_ERROR_SZ]; - int detail = SSL_get_error(conssl->handle, ret); + int detail = SSL_get_error(BACKEND->handle, ret); if(SSL_ERROR_WANT_READ == detail) { - conssl->connecting_state = ssl_connect_2_reading; + connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } else if(SSL_ERROR_WANT_WRITE == detail) { - conssl->connecting_state = ssl_connect_2_writing; + connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } /* There is no easy way to override only the CN matching. @@ -524,7 +544,7 @@ cyassl_connect_step2(struct connectdata *conn, curl_asn1Element *pubkey; CURLcode result; - x509 = SSL_get_peer_certificate(conssl->handle); + x509 = SSL_get_peer_certificate(BACKEND->handle); if(!x509) { failf(data, "SSL: failed retrieving server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; @@ -566,7 +586,7 @@ cyassl_connect_step2(struct connectdata *conn, char *protocol = NULL; unsigned short protocol_len = 0; - rc = wolfSSL_ALPN_GetProtocol(conssl->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, @@ -595,11 +615,11 @@ cyassl_connect_step2(struct connectdata *conn, } #endif /* HAVE_ALPN */ - conssl->connecting_state = ssl_connect_3; + connssl->connecting_state = ssl_connect_3; #if (LIBCYASSL_VERSION_HEX >= 0x03009010) infof(data, "SSL connection using %s / %s\n", - wolfSSL_get_version(conssl->handle), - wolfSSL_get_cipher_name(conssl->handle)); + wolfSSL_get_version(BACKEND->handle), + wolfSSL_get_cipher_name(BACKEND->handle)); #else infof(data, "SSL connected\n"); #endif @@ -623,7 +643,7 @@ cyassl_connect_step3(struct connectdata *conn, SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; - our_ssl_sessionid = SSL_get_session(connssl->handle); + our_ssl_sessionid = SSL_get_session(BACKEND->handle); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, @@ -660,12 +680,13 @@ static ssize_t cyassl_send(struct connectdata *conn, size_t len, CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; char error_buffer[CYASSL_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - int rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen); + int rc = SSL_write(BACKEND->handle, mem, memlen); if(rc < 0) { - int err = SSL_get_error(conn->ssl[sockindex].handle, rc); + int err = SSL_get_error(BACKEND->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: @@ -684,18 +705,18 @@ static ssize_t cyassl_send(struct connectdata *conn, return rc; } -void Curl_cyassl_close(struct connectdata *conn, int sockindex) +static void Curl_cyassl_close(struct connectdata *conn, int sockindex) { - struct ssl_connect_data *conssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - if(conssl->handle) { - (void)SSL_shutdown(conssl->handle); - SSL_free(conssl->handle); - conssl->handle = NULL; + if(BACKEND->handle) { + (void)SSL_shutdown(BACKEND->handle); + SSL_free(BACKEND->handle); + BACKEND->handle = NULL; } - if(conssl->ctx) { - SSL_CTX_free(conssl->ctx); - conssl->ctx = NULL; + if(BACKEND->ctx) { + SSL_CTX_free(BACKEND->ctx); + BACKEND->ctx = NULL; } } @@ -705,12 +726,13 @@ static ssize_t cyassl_recv(struct connectdata *conn, size_t buffersize, CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[num]; char error_buffer[CYASSL_MAX_ERROR_SZ]; int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - int nread = SSL_read(conn->ssl[num].handle, buf, buffsize); + int nread = SSL_read(BACKEND->handle, buf, buffsize); if(nread < 0) { - int err = SSL_get_error(conn->ssl[num].handle, nread); + int err = SSL_get_error(BACKEND->handle, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ @@ -732,14 +754,14 @@ static ssize_t cyassl_recv(struct connectdata *conn, } -void Curl_cyassl_session_free(void *ptr) +static void Curl_cyassl_session_free(void *ptr) { (void)ptr; /* CyaSSL reuses sessions on own, no free */ } -size_t Curl_cyassl_version(char *buffer, size_t size) +static size_t Curl_cyassl_version(char *buffer, size_t size) { #if LIBCYASSL_VERSION_HEX >= 0x03006000 return snprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); @@ -753,16 +775,18 @@ size_t Curl_cyassl_version(char *buffer, size_t size) } -int Curl_cyassl_init(void) +static int Curl_cyassl_init(void) { return (CyaSSL_Init() == SSL_SUCCESS); } -bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex) +static bool Curl_cyassl_data_pending(const struct connectdata* conn, + int connindex) { - if(conn->ssl[connindex].handle) /* SSL is in use */ - return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; + const struct ssl_connect_data *connssl = &conn->ssl[connindex]; + if(BACKEND->handle) /* SSL is in use */ + return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE; else return FALSE; } @@ -772,14 +796,14 @@ bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex) * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ -int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex) +static int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - if(connssl->handle) { - SSL_free(connssl->handle); - connssl->handle = NULL; + if(BACKEND->handle) { + SSL_free(BACKEND->handle); + BACKEND->handle = NULL; } return retval; } @@ -804,7 +828,7 @@ cyassl_connect_common(struct connectdata *conn, return CURLE_OK; } - if(ssl_connect_1==connssl->connecting_state) { + if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -836,9 +860,9 @@ cyassl_connect_common(struct connectdata *conn, if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { - curl_socket_t writefd = ssl_connect_2_writing== + curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading== + curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, @@ -899,18 +923,14 @@ cyassl_connect_common(struct connectdata *conn, } -CURLcode -Curl_cyassl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +static CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { return cyassl_connect_common(conn, sockindex, TRUE, done); } -CURLcode -Curl_cyassl_connect(struct connectdata *conn, - int sockindex) +static CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; @@ -924,9 +944,8 @@ Curl_cyassl_connect(struct connectdata *conn, return CURLE_OK; } -CURLcode Curl_cyassl_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +static CURLcode Curl_cyassl_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) { RNG rng; (void)data; @@ -939,10 +958,10 @@ CURLcode Curl_cyassl_random(struct Curl_easy *data, return CURLE_OK; } -void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum /* output */, - size_t unused) +static void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) { Sha256 SHA256pw; (void)unused; @@ -951,4 +970,48 @@ void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ Sha256Final(&SHA256pw, sha256sum); } +static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + (void)info; + return BACKEND->handle; +} + +const struct Curl_ssl Curl_ssl_cyassl = { + { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */ + + 0, /* have_ca_path */ + 0, /* have_certinfo */ +#ifdef KEEP_PEER_CERT + 1, /* have_pinnedpubkey */ +#else + 0, /* have_pinnedpubkey */ +#endif + 1, /* have_ssl_ctx */ + 0, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_cyassl_init, /* init */ + Curl_none_cleanup, /* cleanup */ + Curl_cyassl_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_cyassl_shutdown, /* shutdown */ + Curl_cyassl_data_pending, /* data_pending */ + Curl_cyassl_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + Curl_cyassl_connect, /* connect */ + Curl_cyassl_connect_nonblocking, /* connect_nonblocking */ + Curl_cyassl_get_internals, /* get_internals */ + Curl_cyassl_close, /* close */ + Curl_none_close_all, /* close_all */ + Curl_cyassl_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_none_md5sum, /* md5sum */ + Curl_cyassl_sha256sum /* sha256sum */ +}; + #endif diff --git a/lib/vtls/cyassl.h b/lib/vtls/cyassl.h index f47719e..01e11cc 100644 --- a/lib/vtls/cyassl.h +++ b/lib/vtls/cyassl.h @@ -25,68 +25,7 @@ #ifdef USE_CYASSL -/* KEEP_PEER_CERT is a product of the presence of build time symbol - OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is - in wolfSSL's settings.h, and the latter two are build time symbols in - options.h. */ -#ifndef KEEP_PEER_CERT -#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \ - defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ - (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) -#define KEEP_PEER_CERT -#endif -#endif - -CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex); -bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex); -int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex); - - /* close a SSL connection */ -void Curl_cyassl_close(struct connectdata *conn, int sockindex); - -void Curl_cyassl_session_free(void *ptr); -size_t Curl_cyassl_version(char *buffer, size_t size); -int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex); -int Curl_cyassl_init(void); -CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); -CURLcode Curl_cyassl_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length); -void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t unused); - -/* Set the API backend definition to CyaSSL */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL - -/* this backend supports CURLOPT_SSL_CTX_* */ -#define have_curlssl_ssl_ctx 1 - -#ifdef KEEP_PEER_CERT -/* this backend supports CURLOPT_PINNEDPUBLICKEY */ -#define have_curlssl_pinnedpubkey 1 -#endif - -/* API setup for CyaSSL */ -#define curlssl_init Curl_cyassl_init -#define curlssl_cleanup() Curl_nop_stmt -#define curlssl_connect Curl_cyassl_connect -#define curlssl_connect_nonblocking Curl_cyassl_connect_nonblocking -#define curlssl_session_free(x) Curl_cyassl_session_free(x) -#define curlssl_close_all(x) ((void)x) -#define curlssl_close Curl_cyassl_close -#define curlssl_shutdown(x,y) Curl_cyassl_shutdown(x,y) -#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) -#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) -#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) -#define curlssl_version Curl_cyassl_version -#define curlssl_check_cxn(x) ((void)x, -1) -#define curlssl_data_pending(x,y) Curl_cyassl_data_pending(x,y) -#define curlssl_random(x,y,z) Curl_cyassl_random(x,y,z) -#define curlssl_sha256sum(a,b,c,d) Curl_cyassl_sha256sum(a,b,c,d) +extern const struct Curl_ssl Curl_ssl_cyassl; #endif /* USE_CYASSL */ #endif /* HEADER_CURL_CYASSL_H */ diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c index 0417665..a98f433 100644 --- a/lib/vtls/darwinssl.c +++ b/lib/vtls/darwinssl.c @@ -34,11 +34,18 @@ #ifdef USE_DARWINSSL +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wtautological-pointer-compare" +#endif /* __clang__ */ + #ifdef HAVE_LIMITS_H #include #endif #include +/* For some reason, when building for iOS, the omnibus header above does + * not include SecureTransport.h as of iOS SDK 5.1. */ #include #include #include @@ -113,6 +120,33 @@ #define ioErr -36 #define paramErr -50 +struct ssl_backend_data { + SSLContextRef ssl_ctx; + curl_socket_t ssl_sockfd; + bool ssl_direction; /* true if writing, false if reading */ + size_t ssl_write_buffered_length; +}; + +#define BACKEND connssl->backend + +/* pinned public key support tests */ + +/* version 1 supports macOS 10.12+ and iOS 10+ */ +#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \ + (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)) +#define DARWIN_SSL_PINNEDPUBKEY_V1 1 +#endif + +/* version 2 supports MacOSX 10.7+ */ +#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) +#define DARWIN_SSL_PINNEDPUBKEY_V2 1 +#endif + +#if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2) +/* this backend supports CURLOPT_PINNEDPUBLICKEY */ +#define DARWIN_SSL_PINNEDPUBKEY 1 +#endif /* DARWIN_SSL_PINNEDPUBKEY */ + #ifdef DARWIN_SSL_PINNEDPUBKEY /* both new and old APIs return rsa keys missing the spki header (not DER) */ static const unsigned char rsa4096SpkiHeader[] = { @@ -156,7 +190,7 @@ 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 = connssl->ssl_sockfd; + int sock = BACKEND->ssl_sockfd; OSStatus rtn = noErr; size_t bytesRead; ssize_t rrtn; @@ -185,7 +219,7 @@ static OSStatus SocketRead(SSLConnectionRef connection, break; case EAGAIN: rtn = errSSLWouldBlock; - connssl->ssl_direction = false; + BACKEND->ssl_direction = false; break; default: rtn = ioErr; @@ -216,7 +250,7 @@ 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 = connssl->ssl_sockfd; + int sock = BACKEND->ssl_sockfd; ssize_t length; size_t dataLen = *dataLength; const UInt8 *dataPtr = (UInt8 *)data; @@ -236,7 +270,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection, theErr = errno; if(theErr == EAGAIN) { ortn = errSSLWouldBlock; - connssl->ssl_direction = true; + BACKEND->ssl_direction = true; } else { ortn = ioErr; @@ -844,7 +878,7 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) into a string. Some aren't available under iOS or newer cats. So here's a unified function for getting a string describing the certificate that ought to work in all cats starting with Leopard. */ -CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert) +CF_INLINE CFStringRef getsubject(SecCertificateRef cert) { CFStringRef server_cert_summary = CFSTR("(null)"); @@ -871,6 +905,54 @@ CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert) return server_cert_summary; } +static CURLcode CopyCertSubject(struct Curl_easy *data, + SecCertificateRef cert, char **certp) +{ + CFStringRef c = getsubject(cert); + CURLcode result = CURLE_OK; + const char *direct; + char *cbuf = NULL; + *certp = NULL; + + if(!c) { + failf(data, "SSL: invalid CA certificate subject"); + return CURLE_OUT_OF_MEMORY; + } + + /* If the subject is already available as UTF-8 encoded (ie 'direct') then + use that, else convert it. */ + direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8); + if(direct) { + *certp = strdup(direct); + if(!*certp) { + failf(data, "SSL: out of memory"); + result = CURLE_OUT_OF_MEMORY; + } + } + else { + size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1; + cbuf = calloc(cbuf_size, 1); + if(cbuf) { + if(!CFStringGetCString(c, cbuf, cbuf_size, + kCFStringEncodingUTF8)) { + failf(data, "SSL: invalid CA certificate subject"); + result = CURLE_SSL_CACERT; + } + else + /* pass back the buffer */ + *certp = cbuf; + } + else { + failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size); + result = CURLE_OUT_OF_MEMORY; + } + } + if(result) + free(cbuf); + CFRelease(c); + return result; +} + #if CURL_SUPPORT_MAC_10_6 /* The SecKeychainSearch API was deprecated in Lion, and using it will raise deprecation warnings, so let's not compile this unless it's necessary: */ @@ -963,7 +1045,7 @@ static OSStatus CopyIdentityWithLabel(char *label, keys_list_count = CFArrayGetCount(keys_list); *out_cert_and_key = NULL; status = 1; - for(i=0; issl_ctx, darwin_ver_min); - (void)SSLSetProtocolVersionMax(connssl->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(connssl->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(connssl->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol1, true); break; case CURL_SSLVERSION_TLSv1_1: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol11, true); break; case CURL_SSLVERSION_TLSv1_2: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol12, true); break; @@ -1205,10 +1288,10 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext != NULL) { /* use the newer API if avaialble */ - if(connssl->ssl_ctx) - CFRelease(connssl->ssl_ctx); - connssl->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); - if(!connssl->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; } @@ -1216,9 +1299,9 @@ static CURLcode darwinssl_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(connssl->ssl_ctx) - (void)SSLDisposeContext(connssl->ssl_ctx); - err = SSLNewContext(false, &(connssl->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; @@ -1226,15 +1309,15 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #endif /* CURL_SUPPORT_MAC_10_8 */ } #else - if(connssl->ssl_ctx) - (void)SSLDisposeContext(connssl->ssl_ctx); - err = SSLNewContext(false, &(connssl->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 */ - connssl->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 @@ -1242,8 +1325,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); + (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kTLSProtocol1); + (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12); break; case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: @@ -1256,20 +1339,20 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, break; } case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionMin(connssl->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(connssl->ssl_ctx, kSSLProtocol3); + (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol3); break; case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionMin(connssl->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(connssl->ssl_ctx, kSSLProtocol2); + (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol2); break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); @@ -1278,19 +1361,19 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } else { #if CURL_SUPPORT_MAC_10_8 - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocolAll, false); switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol1, true); - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol11, true); - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol12, true); break; @@ -1305,7 +1388,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, break; } case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocol3, true); if(err != noErr) { @@ -1314,7 +1397,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } break; case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocol2, true); if(err != noErr) { @@ -1334,12 +1417,12 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, " SSL/TLS version"); return CURLE_SSL_CONNECT_ERROR; } - (void)SSLSetProtocolVersionEnabled(connssl->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(connssl->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol1, true); break; @@ -1353,7 +1436,7 @@ static CURLcode darwinssl_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(connssl->ssl_ctx, + err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocol2, true); if(err != noErr) { @@ -1362,7 +1445,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } break; case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocol3, true); if(err != noErr) { @@ -1412,25 +1495,21 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* If we found one, print it out: */ err = SecIdentityCopyCertificate(cert_and_key, &cert); if(err == noErr) { - CFStringRef cert_summary = CopyCertSubject(cert); - char cert_summary_c[128]; - - if(cert_summary) { - memset(cert_summary_c, 0, 128); - if(CFStringGetCString(cert_summary, - cert_summary_c, - 128, - kCFStringEncodingUTF8)) { - infof(data, "Client certificate: %s\n", cert_summary_c); - } - CFRelease(cert_summary); - CFRelease(cert); + char *certp; + CURLcode result = CopyCertSubject(data, cert, &certp); + if(!result) { + infof(data, "Client certificate: %s\n", certp); + free(certp); } + + CFRelease(cert); + if(result) + return result; } certs_c[0] = cert_and_key; certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, &kCFTypeArrayCallBacks); - err = SSLSetCertificate(connssl->ssl_ctx, certs); + err = SSLSetCertificate(BACKEND->ssl_ctx, certs); if(certs) CFRelease(certs); if(err != noErr) { @@ -1493,7 +1572,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, if(SSLSetSessionOption != NULL) { #endif /* CURL_BUILD_MAC */ bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile; - err = SSLSetSessionOption(connssl->ssl_ctx, + err = SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionBreakOnServerAuth, break_on_auth); if(err != noErr) { @@ -1503,7 +1582,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } else { #if CURL_SUPPORT_MAC_10_8 - err = SSLSetEnableCertVerify(connssl->ssl_ctx, + err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); @@ -1512,7 +1591,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #endif /* CURL_SUPPORT_MAC_10_8 */ } #else - err = SSLSetEnableCertVerify(connssl->ssl_ctx, + err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); @@ -1533,7 +1612,7 @@ static CURLcode darwinssl_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(connssl->ssl_ctx, hostname, + err = SSLSetPeerDomainName(BACKEND->ssl_ctx, hostname, strlen(hostname)); if(err != noErr) { @@ -1559,11 +1638,11 @@ static CURLcode darwinssl_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.) */ - (void)SSLGetNumberSupportedCiphers(connssl->ssl_ctx, &all_ciphers_count); + (void)SSLGetNumberSupportedCiphers(BACKEND->ssl_ctx, &all_ciphers_count); all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); if(all_ciphers && allowed_ciphers && - SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers, + SSLGetSupportedCiphers(BACKEND->ssl_ctx, all_ciphers, &all_ciphers_count) == noErr) { for(i = 0UL ; i < all_ciphers_count ; i++) { #if CURL_BUILD_MAC @@ -1645,7 +1724,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, break; } } - err = SSLSetEnabledCiphers(connssl->ssl_ctx, allowed_ciphers, + err = SSLSetEnabledCiphers(BACKEND->ssl_ctx, allowed_ciphers, allowed_ciphers_count); if(err != noErr) { failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err); @@ -1666,9 +1745,9 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, specifically doesn't want us doing that: */ if(SSLSetSessionOption != NULL) { /* TODO s/data->set.ssl.enable_beast/SSL_SET_OPTION(enable_beast)/g */ - SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord, + SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionSendOneByteRecord, !data->set.ssl.enable_beast); - SSLSetSessionOption(connssl->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 */ @@ -1682,7 +1761,7 @@ static CURLcode darwinssl_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(connssl->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); @@ -1700,7 +1779,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port); ssl_sessionid_len = strlen(ssl_sessionid); - err = SSLSetPeerID(connssl->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); @@ -1717,7 +1796,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } - err = SSLSetIOFuncs(connssl->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; @@ -1727,8 +1806,8 @@ static CURLcode darwinssl_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. */ - connssl->ssl_sockfd = sockfd; - err = SSLSetConnection(connssl->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; @@ -1791,7 +1870,7 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen) { int fd; ssize_t n, len = 0, cap = 512; - unsigned char buf[cap], *data; + unsigned char buf[512], *data; fd = open(file, 0); if(fd < 0) @@ -1869,6 +1948,8 @@ static int append_cert_to_array(struct Curl_easy *data, CFMutableArrayRef array) { CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen); + char *certp; + CURLcode result; if(!certdata) { failf(data, "SSL: failed to allocate array for CA certificate"); return CURLE_OUT_OF_MEMORY; @@ -1883,25 +1964,10 @@ static int append_cert_to_array(struct Curl_easy *data, } /* Check if cacert is valid. */ - CFStringRef subject = CopyCertSubject(cacert); - if(subject) { - char subject_cbuf[128]; - memset(subject_cbuf, 0, 128); - if(!CFStringGetCString(subject, - subject_cbuf, - 128, - kCFStringEncodingUTF8)) { - CFRelease(cacert); - failf(data, "SSL: invalid CA certificate subject"); - return CURLE_SSL_CACERT; - } - CFRelease(subject); - } - else { - CFRelease(cacert); - failf(data, "SSL: invalid CA certificate"); - return CURLE_SSL_CACERT; - } + result = CopyCertSubject(data, cacert, &certp); + if(result) + return result; + free(certp); CFArrayAppendValue(array, cacert); CFRelease(cacert); @@ -2027,12 +2093,13 @@ static int verify_cert(const char *cafile, struct Curl_easy *data, } #ifdef DARWIN_SSL_PINNEDPUBKEY -static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, +static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, SSLContextRef ctx, const char *pinnedpubkey) { /* Scratch */ size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24; - unsigned char *pubkey = NULL, *realpubkey = NULL, *spkiHeader = NULL; + unsigned char *pubkey = NULL, *realpubkey = NULL; + const unsigned char *spkiHeader = NULL; CFDataRef publicKeyBits = NULL; /* Result is returned to caller */ @@ -2075,7 +2142,7 @@ static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, #endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */ pubkeylen = CFDataGetLength(publicKeyBits); - pubkey = CFDataGetBytePtr(publicKeyBits); + pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits); switch(pubkeylen) { case 526: @@ -2148,12 +2215,12 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ - err = SSLHandshake(connssl->ssl_ctx); + err = SSLHandshake(BACKEND->ssl_ctx); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* they're not done with us yet */ - connssl->connecting_state = connssl->ssl_direction ? + connssl->connecting_state = BACKEND->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; @@ -2162,7 +2229,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) case -9841: if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { int res = verify_cert(SSL_CONN_CONFIG(CAfile), data, - connssl->ssl_ctx); + BACKEND->ssl_ctx); if(res != CURLE_OK) return res; } @@ -2240,7 +2307,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) #ifdef DARWIN_SSL_PINNEDPUBKEY if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) { - CURLcode result = pkp_pin_peer_pubkey(data, connssl->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!"); @@ -2250,8 +2317,8 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) #endif /* DARWIN_SSL_PINNEDPUBKEY */ /* Informational message */ - (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); - (void)SSLGetNegotiatedProtocolVersion(connssl->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", @@ -2292,36 +2359,32 @@ show_verbose_server_cert(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - CFStringRef server_cert_summary; - char server_cert_summary_c[128]; CFArrayRef server_certs = NULL; SecCertificateRef server_cert; OSStatus err; CFIndex i, count; SecTrustRef trust = NULL; - if(!connssl->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(connssl->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) { count = SecTrustGetCertificateCount(trust); for(i = 0L ; i < count ; i++) { + CURLcode result; + char *certp; server_cert = SecTrustGetCertificateAtIndex(trust, i); - server_cert_summary = CopyCertSubject(server_cert); - memset(server_cert_summary_c, 0, 128); - if(CFStringGetCString(server_cert_summary, - server_cert_summary_c, - 128, - kCFStringEncodingUTF8)) { - infof(data, "Server certificate: %s\n", server_cert_summary_c); + result = CopyCertSubject(data, server_cert, &certp); + if(!result) { + infof(data, "Server certificate: %s\n", certp); + free(certp); } - CFRelease(server_cert_summary); } CFRelease(trust); } @@ -2334,45 +2397,40 @@ show_verbose_server_cert(struct connectdata *conn, Lion or later. */ if(SecTrustEvaluateAsync != NULL) { #pragma unused(server_certs) - err = SSLCopyPeerTrust(connssl->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) { count = SecTrustGetCertificateCount(trust); for(i = 0L ; i < count ; i++) { + char *certp; + CURLcode result; server_cert = SecTrustGetCertificateAtIndex(trust, i); - server_cert_summary = CopyCertSubject(server_cert); - memset(server_cert_summary_c, 0, 128); - if(CFStringGetCString(server_cert_summary, - server_cert_summary_c, - 128, - kCFStringEncodingUTF8)) { - infof(data, "Server certificate: %s\n", server_cert_summary_c); + result = CopyCertSubject(data, server_cert, &certp); + if(!result) { + infof(data, "Server certificate: %s\n", certp); + free(certp); } - CFRelease(server_cert_summary); } CFRelease(trust); } } else { #if CURL_SUPPORT_MAC_10_8 - err = SSLCopyPeerCertificates(connssl->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); for(i = 0L ; i < count ; i++) { + char *certp; + CURLcode result; server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); - - server_cert_summary = CopyCertSubject(server_cert); - memset(server_cert_summary_c, 0, 128); - if(CFStringGetCString(server_cert_summary, - server_cert_summary_c, - 128, - kCFStringEncodingUTF8)) { - infof(data, "Server certificate: %s\n", server_cert_summary_c); + result = CopyCertSubject(data, server_cert, &certp); + if(!result) { + infof(data, "Server certificate: %s\n", certp); + free(certp); } - CFRelease(server_cert_summary); } CFRelease(server_certs); } @@ -2381,20 +2439,18 @@ show_verbose_server_cert(struct connectdata *conn, #endif /* CURL_BUILD_IOS */ #else #pragma unused(trust) - err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); + err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); if(err == noErr) { count = CFArrayGetCount(server_certs); for(i = 0L ; i < count ; i++) { + CURLcode result; + char *certp; server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); - server_cert_summary = CopyCertSubject(server_cert); - memset(server_cert_summary_c, 0, 128); - if(CFStringGetCString(server_cert_summary, - server_cert_summary_c, - 128, - kCFStringEncodingUTF8)) { - infof(data, "Server certificate: %s\n", server_cert_summary_c); + result = CopyCertSubject(data, server_cert, &certp); + if(!result) { + infof(data, "Server certificate: %s\n", certp); + free(certp); } - CFRelease(server_cert_summary); } CFRelease(server_certs); } @@ -2443,7 +2499,7 @@ darwinssl_connect_common(struct connectdata *conn, return CURLE_OK; } - if(ssl_connect_1==connssl->connecting_state) { + if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -2538,17 +2594,13 @@ darwinssl_connect_common(struct connectdata *conn, return CURLE_OK; } -CURLcode -Curl_darwinssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +static CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { return darwinssl_connect_common(conn, sockindex, TRUE, done); } -CURLcode -Curl_darwinssl_connect(struct connectdata *conn, - int sockindex) +static CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; @@ -2563,28 +2615,28 @@ Curl_darwinssl_connect(struct connectdata *conn, return CURLE_OK; } -void Curl_darwinssl_close(struct connectdata *conn, int sockindex) +static void Curl_darwinssl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - if(connssl->ssl_ctx) { - (void)SSLClose(connssl->ssl_ctx); + if(BACKEND->ssl_ctx) { + (void)SSLClose(BACKEND->ssl_ctx); #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext != NULL) - CFRelease(connssl->ssl_ctx); + CFRelease(BACKEND->ssl_ctx); #if CURL_SUPPORT_MAC_10_8 else - (void)SSLDisposeContext(connssl->ssl_ctx); + (void)SSLDisposeContext(BACKEND->ssl_ctx); #endif /* CURL_SUPPORT_MAC_10_8 */ #else - (void)SSLDisposeContext(connssl->ssl_ctx); + (void)SSLDisposeContext(BACKEND->ssl_ctx); #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - connssl->ssl_ctx = NULL; + BACKEND->ssl_ctx = NULL; } - connssl->ssl_sockfd = 0; + BACKEND->ssl_sockfd = 0; } -int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) +static int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; @@ -2593,7 +2645,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) int rc; char buf[120]; - if(!connssl->ssl_ctx) + if(!BACKEND->ssl_ctx) return 0; if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) @@ -2637,7 +2689,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) return rc; } -void Curl_darwinssl_session_free(void *ptr) +static void Curl_darwinssl_session_free(void *ptr) { /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a cached session ID inside the Security framework. There is a private @@ -2648,7 +2700,7 @@ void Curl_darwinssl_session_free(void *ptr) Curl_safefree(ptr); } -size_t Curl_darwinssl_version(char *buffer, size_t size) +static size_t Curl_darwinssl_version(char *buffer, size_t size) { return snprintf(buffer, size, "SecureTransport"); } @@ -2661,14 +2713,14 @@ size_t Curl_darwinssl_version(char *buffer, size_t size) * 0 means the connection has been closed * -1 means the connection status is unknown */ -int Curl_darwinssl_check_cxn(struct connectdata *conn) +static int Curl_darwinssl_check_cxn(struct connectdata *conn) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; OSStatus err; SSLSessionState state; - if(connssl->ssl_ctx) { - err = SSLGetSessionState(connssl->ssl_ctx, &state); + if(BACKEND->ssl_ctx) { + err = SSLGetSessionState(BACKEND->ssl_ctx, &state); if(err == noErr) return state == kSSLConnected || state == kSSLHandshake; return -1; @@ -2676,15 +2728,15 @@ int Curl_darwinssl_check_cxn(struct connectdata *conn) return 0; } -bool Curl_darwinssl_data_pending(const struct connectdata *conn, - int connindex) +static bool Curl_darwinssl_data_pending(const struct connectdata *conn, + int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; OSStatus err; size_t buffer; - if(connssl->ssl_ctx) { /* SSL is in use */ - err = SSLGetBufferedReadSize(connssl->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; @@ -2693,14 +2745,16 @@ bool Curl_darwinssl_data_pending(const struct connectdata *conn, return false; } -CURLcode Curl_darwinssl_random(unsigned char *entropy, - size_t length) +static CURLcode Curl_darwinssl_random(struct Curl_easy *data UNUSED_PARAM, + unsigned char *entropy, size_t length) { /* arc4random_buf() isn't available on cats older than Lion, so let's do this manually for the benefit of the older cats. */ size_t i; u_int32_t random_number = 0; + (void)data; + for(i = 0 ; i < length ; i++) { if(i % sizeof(u_int32_t) == 0) random_number = arc4random(); @@ -2711,25 +2765,26 @@ CURLcode Curl_darwinssl_random(unsigned char *entropy, return CURLE_OK; } -void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len) +static CURLcode Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) { (void)md5len; (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum); + return CURLE_OK; } -void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len) +static void Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len) { - assert(sha256len >= SHA256_DIGEST_LENGTH); + assert(sha256len >= CURL_SHA256_DIGEST_LENGTH); (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum); } -bool Curl_darwinssl_false_start(void) +static bool Curl_darwinssl_false_start(void) { #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 if(SSLSetSessionOption != NULL) @@ -2764,15 +2819,15 @@ static ssize_t darwinssl_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(connssl->ssl_write_buffered_length) { + if(BACKEND->ssl_write_buffered_length) { /* Write the buffered data: */ - err = SSLWrite(connssl->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 = connssl->ssl_write_buffered_length; - connssl->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; @@ -2785,13 +2840,13 @@ static ssize_t darwinssl_send(struct connectdata *conn, } else { /* We've got new data to write: */ - err = SSLWrite(connssl->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 */ - connssl->ssl_write_buffered_length = len; + BACKEND->ssl_write_buffered_length = len; *curlcode = CURLE_AGAIN; return -1L; default: @@ -2813,7 +2868,7 @@ static ssize_t darwinssl_recv(struct connectdata *conn, /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[num]; size_t processed = 0UL; - OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed); + OSStatus err = SSLRead(BACKEND->ssl_ctx, buf, buffersize, &processed); if(err != noErr) { switch(err) { @@ -2844,4 +2899,52 @@ static ssize_t darwinssl_recv(struct connectdata *conn, return (ssize_t)processed; } +static void *Curl_darwinssl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + (void)info; + return BACKEND->ssl_ctx; +} + +const struct Curl_ssl Curl_ssl_darwinssl = { + { CURLSSLBACKEND_DARWINSSL, "darwinssl" }, /* info */ + + 0, /* have_ca_path */ + 0, /* have_certinfo */ +#ifdef DARWIN_SSL_PINNEDPUBKEY + 1, /* have_pinnedpubkey */ +#else + 0, /* have_pinnedpubkey */ +#endif /* DARWIN_SSL_PINNEDPUBKEY */ + 0, /* have_ssl_ctx */ + 0, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_none_init, /* init */ + Curl_none_cleanup, /* cleanup */ + Curl_darwinssl_version, /* version */ + Curl_darwinssl_check_cxn, /* check_cxn */ + Curl_darwinssl_shutdown, /* shutdown */ + Curl_darwinssl_data_pending, /* data_pending */ + Curl_darwinssl_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + Curl_darwinssl_connect, /* connect */ + Curl_darwinssl_connect_nonblocking, /* connect_nonblocking */ + Curl_darwinssl_get_internals, /* get_internals */ + Curl_darwinssl_close, /* close */ + Curl_none_close_all, /* close_all */ + Curl_darwinssl_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_darwinssl_false_start, /* false_start */ + Curl_darwinssl_md5sum, /* md5sum */ + Curl_darwinssl_sha256sum /* sha256sum */ +}; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + #endif /* USE_DARWINSSL */ diff --git a/lib/vtls/darwinssl.h b/lib/vtls/darwinssl.h index fd372ff..23c7f70 100644 --- a/lib/vtls/darwinssl.h +++ b/lib/vtls/darwinssl.h @@ -26,75 +26,7 @@ #ifdef USE_DARWINSSL -CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex); - -CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); - -/* close a SSL connection */ -void Curl_darwinssl_close(struct connectdata *conn, int sockindex); - -void Curl_darwinssl_session_free(void *ptr); -size_t Curl_darwinssl_version(char *buffer, size_t size); -int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex); -int Curl_darwinssl_check_cxn(struct connectdata *conn); -bool Curl_darwinssl_data_pending(const struct connectdata *conn, - int connindex); - -CURLcode Curl_darwinssl_random(unsigned char *entropy, - size_t length); -void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len); -void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len); -bool Curl_darwinssl_false_start(void); - -/* Set the API backend definition to SecureTransport */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL - -/* pinned public key support tests */ - -/* version 1 supports macOS 10.12+ and iOS 10+ */ -#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \ - (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)) -#define DARWIN_SSL_PINNEDPUBKEY_V1 1 -#endif - -/* version 2 supports MacOSX 10.7+ */ -#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) -#define DARWIN_SSL_PINNEDPUBKEY_V2 1 -#endif - -#if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2) -/* this backend supports CURLOPT_PINNEDPUBLICKEY */ -#define DARWIN_SSL_PINNEDPUBKEY 1 -#define have_curlssl_pinnedpubkey 1 -#endif /* DARWIN_SSL_PINNEDPUBKEY */ - -/* API setup for SecureTransport */ -#define curlssl_init() (1) -#define curlssl_cleanup() Curl_nop_stmt -#define curlssl_connect Curl_darwinssl_connect -#define curlssl_connect_nonblocking Curl_darwinssl_connect_nonblocking -#define curlssl_session_free(x) Curl_darwinssl_session_free(x) -#define curlssl_close_all(x) ((void)x) -#define curlssl_close Curl_darwinssl_close -#define curlssl_shutdown(x,y) 0 -#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) -#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) -#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) -#define curlssl_version Curl_darwinssl_version -#define curlssl_check_cxn Curl_darwinssl_check_cxn -#define curlssl_data_pending(x,y) Curl_darwinssl_data_pending(x, y) -#define curlssl_random(x,y,z) ((void)x, Curl_darwinssl_random(y,z)) -#define curlssl_md5sum(a,b,c,d) Curl_darwinssl_md5sum(a,b,c,d) -#define curlssl_sha256sum(a,b,c,d) Curl_darwinssl_sha256sum(a,b,c,d) -#define curlssl_false_start() Curl_darwinssl_false_start() +extern const struct Curl_ssl Curl_ssl_darwinssl; #endif /* USE_DARWINSSL */ #endif /* HEADER_CURL_DARWINSSL_H */ diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c index bf75bdd..ba5faef 100644 --- a/lib/vtls/gskit.c +++ b/lib/vtls/gskit.c @@ -98,6 +98,14 @@ #define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12) #define CURL_GSKPROTO_LAST 5 +struct ssl_backend_data { + gsk_handle handle; + int iocport; + int localfd; + int remotefd; +}; + +#define BACKEND connssl->backend /* Supported ciphers. */ typedef struct { @@ -427,7 +435,7 @@ static CURLcode set_ciphers(struct connectdata *conn, } -int Curl_gskit_init(void) +static int Curl_gskit_init(void) { /* No initialisation needed. */ @@ -435,7 +443,7 @@ int Curl_gskit_init(void) } -void Curl_gskit_cleanup(void) +static void Curl_gskit_cleanup(void) { /* Nothing to do. */ } @@ -495,14 +503,14 @@ static void cancel_async_handshake(struct connectdata *conn, int sockindex) Qso_OverlappedIO_t cstat; if(QsoCancelOperation(conn->sock[sockindex], 0) > 0) - QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL); + QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL); } static void close_async_handshake(struct ssl_connect_data *connssl) { - QsoDestroyIOCompletionPort(connssl->iocport); - connssl->iocport = -1; + QsoDestroyIOCompletionPort(BACKEND->iocport); + BACKEND->iocport = -1; } /* SSL over SSL @@ -620,12 +628,12 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, FD_ZERO(&fds_write); n = -1; if(directions & SOS_READ) { - FD_SET(connssl->remotefd, &fds_write); - n = connssl->remotefd; + FD_SET(BACKEND->remotefd, &fds_write); + n = BACKEND->remotefd; } if(directions & SOS_WRITE) { - FD_SET(connssl->remotefd, &fds_read); - n = connssl->remotefd; + FD_SET(BACKEND->remotefd, &fds_read); + n = BACKEND->remotefd; FD_SET(conn->sock[sockindex], &fds_write); if(n < conn->sock[sockindex]) n = conn->sock[sockindex]; @@ -634,14 +642,15 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, if(i < 0) return -1; /* Select error. */ - if(FD_ISSET(connssl->remotefd, &fds_write)) { + if(FD_ISSET(BACKEND->remotefd, &fds_write)) { /* Try getting data from HTTPS proxy and pipe it upstream. */ n = 0; - i = gsk_secure_soc_read(connproxyssl->handle, buf, sizeof buf, &n); + i = gsk_secure_soc_read(connproxyssl->backend->handle, + buf, sizeof buf, &n); switch(i) { case GSK_OK: if(n) { - i = write(connssl->remotefd, buf, n); + i = write(BACKEND->remotefd, buf, n); if(i < 0) return -1; ret = 1; @@ -655,14 +664,14 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, } } - if(FD_ISSET(connssl->remotefd, &fds_read) && + if(FD_ISSET(BACKEND->remotefd, &fds_read) && FD_ISSET(conn->sock[sockindex], &fds_write)) { /* Pipe data to HTTPS proxy. */ - n = read(connssl->remotefd, buf, sizeof buf); + n = read(BACKEND->remotefd, buf, sizeof buf); if(n < 0) return -1; if(n) { - i = gsk_secure_soc_write(connproxyssl->handle, buf, n, &m); + i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m); if(i != GSK_OK || n != m) return -1; ret = 1; @@ -676,23 +685,23 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, static void close_one(struct ssl_connect_data *connssl, struct connectdata *conn, int sockindex) { - if(connssl->handle) { - gskit_status(conn->data, gsk_secure_soc_close(&connssl->handle), + if(BACKEND->handle) { + gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle), "gsk_secure_soc_close()", 0); /* Last chance to drain output. */ while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0) ; - connssl->handle = (gsk_handle) NULL; - if(connssl->localfd >= 0) { - close(connssl->localfd); - connssl->localfd = -1; + BACKEND->handle = (gsk_handle) NULL; + if(BACKEND->localfd >= 0) { + close(BACKEND->localfd); + BACKEND->localfd = -1; } - if(connssl->remotefd >= 0) { - close(connssl->remotefd); - connssl->remotefd = -1; + if(BACKEND->remotefd >= 0) { + close(BACKEND->remotefd); + BACKEND->remotefd = -1; } } - if(connssl->iocport >= 0) + if(BACKEND->iocport >= 0) close_async_handshake(connssl); } @@ -700,13 +709,14 @@ static void close_one(struct ssl_connect_data *connssl, static ssize_t gskit_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; CURLcode cc = CURLE_SEND_ERROR; int written; if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) { cc = gskit_status(data, - gsk_secure_soc_write(conn->ssl[sockindex].handle, + gsk_secure_soc_write(BACKEND->handle, (char *) mem, (int) len, &written), "gsk_secure_soc_write()", CURLE_SEND_ERROR); if(cc == CURLE_OK) @@ -724,6 +734,7 @@ static ssize_t gskit_send(struct connectdata *conn, int sockindex, static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[num]; struct Curl_easy *data = conn->data; int buffsize; int nread; @@ -731,7 +742,7 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) { buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; - cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle, + cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle, buf, buffsize, &nread), "gsk_secure_soc_read()", CURLE_RECV_ERROR); } @@ -806,10 +817,10 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) /* Create SSL environment, start (preferably asynchronous) handshake. */ - connssl->handle = (gsk_handle) NULL; - connssl->iocport = -1; - connssl->localfd = -1; - connssl->remotefd = -1; + BACKEND->handle = (gsk_handle) NULL; + BACKEND->iocport = -1; + BACKEND->localfd = -1; + BACKEND->remotefd = -1; /* GSKit supports two ways of specifying an SSL context: either by * application identifier (that should have been defined at the system @@ -842,7 +853,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) } /* Create secure session. */ - result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle), + result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle), "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR); gsk_environment_close(&envir); if(result) @@ -852,18 +863,18 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) if(conn->proxy_ssl[sockindex].use) { if(inetsocketpair(sockpair)) return CURLE_SSL_CONNECT_ERROR; - connssl->localfd = sockpair[0]; - connssl->remotefd = sockpair[1]; - setsockopt(connssl->localfd, SOL_SOCKET, SO_RCVBUF, + BACKEND->localfd = sockpair[0]; + BACKEND->remotefd = sockpair[1]; + setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF, (void *) sobufsize, sizeof sobufsize); - setsockopt(connssl->remotefd, SOL_SOCKET, SO_RCVBUF, + setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF, (void *) sobufsize, sizeof sobufsize); - setsockopt(connssl->localfd, SOL_SOCKET, SO_SNDBUF, + setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF, (void *) sobufsize, sizeof sobufsize); - setsockopt(connssl->remotefd, SOL_SOCKET, SO_SNDBUF, + setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF, (void *) sobufsize, sizeof sobufsize); - curlx_nonblock(connssl->localfd, TRUE); - curlx_nonblock(connssl->remotefd, TRUE); + curlx_nonblock(BACKEND->localfd, TRUE); + curlx_nonblock(BACKEND->remotefd, TRUE); } /* Determine which SSL/TLS version should be enabled. */ @@ -897,7 +908,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) /* Process SNI. Ignore if not supported (on OS400 < V7R1). */ if(sni) { - result = set_buffer(data, connssl->handle, + result = set_buffer(data, BACKEND->handle, GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) result = CURLE_OK; @@ -911,34 +922,34 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) if(timeout < 0) result = CURLE_OPERATION_TIMEDOUT; else - result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT, + result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT, (timeout + 999) / 1000); } if(!result) - result = set_numeric(data, connssl->handle, GSK_OS400_READ_TIMEOUT, 1); + result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1); if(!result) - result = set_numeric(data, connssl->handle, GSK_FD, connssl->localfd >= 0? - connssl->localfd: conn->sock[sockindex]); + result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0? + BACKEND->localfd: conn->sock[sockindex]); if(!result) - result = set_ciphers(conn, connssl->handle, &protoflags); + result = set_ciphers(conn, BACKEND->handle, &protoflags); if(!protoflags) { failf(data, "No SSL protocol/cipher combination enabled"); result = CURLE_SSL_CIPHER; } if(!result) - result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2, + result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2, (protoflags & CURL_GSKPROTO_SSLV2_MASK)? GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE); if(!result) - result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3, + result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3, (protoflags & CURL_GSKPROTO_SSLV3_MASK)? GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE); if(!result) - result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1, + result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1, (protoflags & CURL_GSKPROTO_TLSV10_MASK)? GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE); if(!result) { - result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11, + result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11, (protoflags & CURL_GSKPROTO_TLSV11_MASK)? GSK_TRUE: GSK_FALSE, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) { @@ -950,7 +961,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) } } if(!result) { - result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12, + result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12, (protoflags & CURL_GSKPROTO_TLSV12_MASK)? GSK_TRUE: GSK_FALSE, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) { @@ -962,18 +973,18 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) } } if(!result) - result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE, + result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE, verifypeer? GSK_SERVER_AUTH_FULL: GSK_SERVER_AUTH_PASSTHRU, FALSE); if(!result) { /* Start handshake. Try asynchronous first. */ memset(&commarea, 0, sizeof commarea); - connssl->iocport = QsoCreateIOCompletionPort(); - if(connssl->iocport != -1) { + BACKEND->iocport = QsoCreateIOCompletionPort(); + if(BACKEND->iocport != -1) { result = gskit_status(data, - gsk_secure_soc_startInit(connssl->handle, - connssl->iocport, + gsk_secure_soc_startInit(BACKEND->handle, + BACKEND->iocport, &commarea), "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR); @@ -993,7 +1004,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) } else { /* No more completion port available. Use synchronous IO. */ - result = gskit_status(data, gsk_secure_soc_init(connssl->handle), + result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle), "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR); if(!result) { connssl->connecting_state = ssl_connect_3; @@ -1026,7 +1037,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, timeout_ms = 0; stmv.tv_sec = timeout_ms / 1000; stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000; - switch(QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) { + switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) { case 1: /* Operation complete. */ break; case -1: /* An error occurred: handshake still in progress. */ @@ -1075,7 +1086,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) /* SSL handshake done: gather certificate info and verify host. */ - if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle, + if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle, GSK_PARTNER_CERT_INFO, &cdev, &cdec), "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) == @@ -1216,9 +1227,8 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, } -CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { CURLcode result; @@ -1229,7 +1239,7 @@ CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, } -CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) +static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done; @@ -1245,14 +1255,14 @@ CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) } -void Curl_gskit_close(struct connectdata *conn, int sockindex) +static void Curl_gskit_close(struct connectdata *conn, int sockindex) { close_one(&conn->ssl[sockindex], conn, sockindex); close_one(&conn->proxy_ssl[sockindex], conn, sockindex); } -int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) +static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; @@ -1261,7 +1271,7 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) int rc; char buf[120]; - if(!connssl->handle) + if(!BACKEND->handle) return 0; if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) @@ -1306,21 +1316,22 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) } -size_t Curl_gskit_version(char *buffer, size_t size) +static size_t Curl_gskit_version(char *buffer, size_t size) { strncpy(buffer, "GSKit", size); return strlen(buffer); } -int Curl_gskit_check_cxn(struct connectdata *cxn) +static int Curl_gskit_check_cxn(struct connectdata *cxn) { + struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET]; int err; int errlen; /* The only thing that can be tested here is at the socket level. */ - if(!cxn->ssl[FIRSTSOCKET].handle) + if(!BACKEND->handle) return 0; /* connection has been closed */ err = 0; @@ -1334,4 +1345,46 @@ int Curl_gskit_check_cxn(struct connectdata *cxn) return -1; /* connection status unknown */ } +static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + (void)info; + return BACKEND->handle; +} + +const struct Curl_ssl Curl_ssl_gskit = { + { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */ + + 0, /* have_ca_path */ + 1, /* have_certinfo */ + 0, /* have_pinnedpubkey */ + 0, /* have_ssl_ctx */ + /* TODO: convert to 1 and fix test #1014 (if need) */ + 0, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_gskit_init, /* init */ + Curl_gskit_cleanup, /* cleanup */ + Curl_gskit_version, /* version */ + Curl_gskit_check_cxn, /* check_cxn */ + Curl_gskit_shutdown, /* shutdown */ + Curl_none_data_pending, /* data_pending */ + Curl_none_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + Curl_gskit_connect, /* connect */ + Curl_gskit_connect_nonblocking, /* connect_nonblocking */ + Curl_gskit_get_internals, /* get_internals */ + Curl_gskit_close, /* close */ + Curl_none_close_all, /* close_all */ + /* No session handling for GSKit */ + Curl_none_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_none_md5sum, /* md5sum */ + NULL /* sha256sum */ +}; + #endif /* USE_GSKIT */ diff --git a/lib/vtls/gskit.h b/lib/vtls/gskit.h index 2297592..466ee4d 100644 --- a/lib/vtls/gskit.h +++ b/lib/vtls/gskit.h @@ -30,44 +30,8 @@ #include "urldata.h" #ifdef USE_GSKIT -int Curl_gskit_init(void); -void Curl_gskit_cleanup(void); -CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done); -void Curl_gskit_close(struct connectdata *conn, int sockindex); -int Curl_gskit_shutdown(struct connectdata *conn, int sockindex); -size_t Curl_gskit_version(char *buffer, size_t size); -int Curl_gskit_check_cxn(struct connectdata *cxn); - -/* Support HTTPS-proxy */ -/* TODO: add '#define HTTPS_PROXY_SUPPORT 1' and fix test #1014 (if need) */ - -/* Set the API backend definition to GSKit */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_GSKIT - -/* this backend supports CURLOPT_CERTINFO */ -#define have_curlssl_certinfo 1 - -/* API setup for GSKit */ -#define curlssl_init Curl_gskit_init -#define curlssl_cleanup Curl_gskit_cleanup -#define curlssl_connect Curl_gskit_connect -#define curlssl_connect_nonblocking Curl_gskit_connect_nonblocking - -/* No session handling for GSKit */ -#define curlssl_session_free(x) Curl_nop_stmt -#define curlssl_close_all(x) ((void)x) -#define curlssl_close Curl_gskit_close -#define curlssl_shutdown(x,y) Curl_gskit_shutdown(x,y) -#define curlssl_set_engine(x,y) CURLE_NOT_BUILT_IN -#define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN -#define curlssl_engines_list(x) NULL -#define curlssl_version Curl_gskit_version -#define curlssl_check_cxn(x) Curl_gskit_check_cxn(x) -#define curlssl_data_pending(x,y) 0 -#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN) +extern const struct Curl_ssl Curl_ssl_gskit; #endif /* USE_GSKIT */ diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 844be2d..a844915 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -60,15 +60,13 @@ /* The last #include file should be: */ #include "memdebug.h" -/* - Some hackish cast macros based on: - https://developer.gnome.org/glib/unstable/glib-Type-Conversion-Macros.html -*/ -#ifndef GNUTLS_POINTER_TO_INT_CAST -#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p)) +#ifndef GNUTLS_POINTER_TO_SOCKET_CAST +#define GNUTLS_POINTER_TO_SOCKET_CAST(p) \ + ((curl_socket_t) ((char *)(p) - (char *)NULL)) #endif -#ifndef GNUTLS_INT_TO_POINTER_CAST -#define GNUTLS_INT_TO_POINTER_CAST(i) ((void *) (long) (i)) +#ifndef GNUTLS_SOCKET_TO_POINTER_CAST +#define GNUTLS_SOCKET_TO_POINTER_CAST(s) \ + ((void *) ((char *)NULL + (s))) #endif /* Enable GnuTLS debugging by defining GTLSDEBUG */ @@ -109,6 +107,16 @@ static bool gtls_inited = FALSE; # include #endif +struct ssl_backend_data { + gnutls_session_t session; + gnutls_certificate_credentials_t cred; +#ifdef USE_TLS_SRP + gnutls_srp_client_credentials_t srp_client_cred; +#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() @@ -153,7 +161,7 @@ static int gtls_mapped_sockerrno(void) static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { - ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); + ssize_t ret = swrite(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len); #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) if(ret < 0) gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); @@ -163,7 +171,7 @@ static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { - ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); + ssize_t ret = sread(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len); #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) if(ret < 0) gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); @@ -188,7 +196,7 @@ static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len) * must only be called from within curl_global_init() to keep the thread * situation under control! */ -int Curl_gtls_init(void) +static int Curl_gtls_init(void) { int ret = 1; if(!gtls_inited) { @@ -202,13 +210,12 @@ int Curl_gtls_init(void) return ret; } -int Curl_gtls_cleanup(void) +static void Curl_gtls_cleanup(void) { if(gtls_inited) { gnutls_global_deinit(); gtls_inited = FALSE; } - return 1; } #ifndef CURL_DISABLE_VERBOSE_STRINGS @@ -279,7 +286,7 @@ static CURLcode handshake(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gnutls_session_t session = conn->ssl[sockindex].session; + gnutls_session_t session = BACKEND->session; curl_socket_t sockfd = conn->sock[sockindex]; time_t timeout_ms; int rc; @@ -299,9 +306,9 @@ static CURLcode handshake(struct connectdata *conn, if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { - curl_socket_t writefd = ssl_connect_2_writing== + curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading== + curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, @@ -477,6 +484,7 @@ gtls_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned int init_flags; gnutls_session_t session; int rc; @@ -512,7 +520,7 @@ gtls_connect_step1(struct connectdata *conn, const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; - if(conn->ssl[sockindex].state == ssl_connection_complete) + if(connssl->state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ return CURLE_OK; @@ -528,7 +536,7 @@ gtls_connect_step1(struct connectdata *conn, sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ - rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].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; @@ -539,15 +547,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( - &conn->ssl[sockindex].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(conn->ssl[sockindex]. - 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) { @@ -560,10 +567,10 @@ gtls_connect_step1(struct connectdata *conn, if(SSL_CONN_CONFIG(CAfile)) { /* set the trusted CA cert bundle file */ - gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, + gnutls_certificate_set_verify_flags(BACKEND->cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); - rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, + rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred, SSL_CONN_CONFIG(CAfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { @@ -580,7 +587,7 @@ gtls_connect_step1(struct connectdata *conn, #ifdef HAS_CAPATH if(SSL_CONN_CONFIG(CApath)) { /* set the trusted CA cert directory */ - rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred, + rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred, SSL_CONN_CONFIG(CApath), GNUTLS_X509_FMT_PEM); if(rc < 0) { @@ -599,13 +606,13 @@ gtls_connect_step1(struct connectdata *conn, /* 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(conn->ssl[sockindex].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(conn->ssl[sockindex].cred, + rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred, SSL_SET_OPTION(CRLfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { @@ -626,14 +633,14 @@ gtls_connect_step1(struct connectdata *conn, init_flags |= GNUTLS_NO_TICKETS; #endif - rc = gnutls_init(&conn->ssl[sockindex].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 = conn->ssl[sockindex].session; + session = BACKEND->session; if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 @@ -763,7 +770,8 @@ gtls_connect_step1(struct connectdata *conn, gnutls_datum_t protocols[2]; #ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2 && + (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; cur++; @@ -789,7 +797,7 @@ gtls_connect_step1(struct connectdata *conn, 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( - conn->ssl[sockindex].cred, + BACKEND->cred, SSL_SET_OPTION(cert), SSL_SET_OPTION(key) ? SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), @@ -809,7 +817,7 @@ gtls_connect_step1(struct connectdata *conn, } else { if(gnutls_certificate_set_x509_key_file( - conn->ssl[sockindex].cred, + BACKEND->cred, SSL_SET_OPTION(cert), SSL_SET_OPTION(key) ? SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), @@ -825,7 +833,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, - conn->ssl[sockindex].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; @@ -835,7 +843,7 @@ gtls_connect_step1(struct connectdata *conn, #endif { rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, - conn->ssl[sockindex].cred); + BACKEND->cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; @@ -843,13 +851,13 @@ gtls_connect_step1(struct connectdata *conn, } if(conn->proxy_ssl[sockindex].use) { - transport_ptr = conn->proxy_ssl[sockindex].session; + transport_ptr = conn->proxy_ssl[sockindex].backend->session; gnutls_transport_push = Curl_gtls_push_ssl; gnutls_transport_pull = Curl_gtls_pull_ssl; } else { /* file descriptor for the socket */ - transport_ptr = GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]); + transport_ptr = GNUTLS_SOCKET_TO_POINTER_CAST(conn->sock[sockindex]); gnutls_transport_push = Curl_gtls_push; gnutls_transport_pull = Curl_gtls_pull; } @@ -968,7 +976,8 @@ gtls_connect_step3(struct connectdata *conn, time_t certclock; const char *ptr; struct Curl_easy *data = conn->data; - gnutls_session_t session = conn->ssl[sockindex].session; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + gnutls_session_t session = BACKEND->session; int rc; #ifdef HAS_ALPN gnutls_datum_t proto; @@ -1199,7 +1208,7 @@ gtls_connect_step3(struct connectdata *conn, SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); } - size=sizeof(certbuf); + size = sizeof(certbuf); rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, 0, /* the first and only one */ FALSE, @@ -1239,7 +1248,7 @@ gtls_connect_step3(struct connectdata *conn, #endif if(addrlen) { - for(i=0; ; i++) { + for(i = 0; ; i++) { certaddrlen = sizeof(certaddr); ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr, &certaddrlen, NULL); @@ -1472,7 +1481,7 @@ gtls_connect_common(struct connectdata *conn, struct ssl_connect_data *connssl = &conn->ssl[sockindex]; /* Initiate the connection, if not already done */ - if(ssl_connect_1==connssl->connecting_state) { + if(ssl_connect_1 == connssl->connecting_state) { rc = gtls_connect_step1(conn, sockindex); if(rc) return rc; @@ -1484,29 +1493,24 @@ gtls_connect_common(struct connectdata *conn, return rc; /* Finish connecting once the handshake is done */ - if(ssl_connect_1==connssl->connecting_state) { + if(ssl_connect_1 == connssl->connecting_state) { rc = gtls_connect_step3(conn, sockindex); if(rc) return rc; } - *done = ssl_connect_1==connssl->connecting_state; + *done = ssl_connect_1 == connssl->connecting_state; return CURLE_OK; } -CURLcode -Curl_gtls_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +static CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { return gtls_connect_common(conn, sockindex, TRUE, done); } -CURLcode -Curl_gtls_connect(struct connectdata *conn, - int sockindex) - +static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; @@ -1520,15 +1524,18 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_OK; } -bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex) +static bool Curl_gtls_data_pending(const struct connectdata *conn, + int connindex) { + const struct ssl_connect_data *connssl = &conn->ssl[connindex]; bool res = FALSE; - if(conn->ssl[connindex].session && - 0 != gnutls_record_check_pending(conn->ssl[connindex].session)) + if(BACKEND->session && + 0 != gnutls_record_check_pending(BACKEND->session)) res = TRUE; - if(conn->proxy_ssl[connindex].session && - 0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session)) + connssl = &conn->proxy_ssl[connindex]; + if(BACKEND->session && + 0 != gnutls_record_check_pending(BACKEND->session)) res = TRUE; return res; @@ -1540,7 +1547,8 @@ static ssize_t gtls_send(struct connectdata *conn, size_t len, CURLcode *curlcode) { - ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + ssize_t rc = gnutls_record_send(BACKEND->session, mem, len); if(rc < 0) { *curlcode = (rc == GNUTLS_E_AGAIN) @@ -1553,26 +1561,26 @@ static ssize_t gtls_send(struct connectdata *conn, return rc; } -static void close_one(struct ssl_connect_data *ssl) +static void close_one(struct ssl_connect_data *connssl) { - if(ssl->session) { - gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR); - gnutls_deinit(ssl->session); - ssl->session = NULL; + if(BACKEND->session) { + gnutls_bye(BACKEND->session, GNUTLS_SHUT_RDWR); + gnutls_deinit(BACKEND->session); + BACKEND->session = NULL; } - if(ssl->cred) { - gnutls_certificate_free_credentials(ssl->cred); - ssl->cred = NULL; + if(BACKEND->cred) { + gnutls_certificate_free_credentials(BACKEND->cred); + BACKEND->cred = NULL; } #ifdef USE_TLS_SRP - if(ssl->srp_client_cred) { - gnutls_srp_free_client_credentials(ssl->srp_client_cred); - ssl->srp_client_cred = NULL; + if(BACKEND->srp_client_cred) { + gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); + BACKEND->srp_client_cred = NULL; } #endif } -void Curl_gtls_close(struct connectdata *conn, int sockindex) +static void Curl_gtls_close(struct connectdata *conn, int sockindex) { close_one(&conn->ssl[sockindex]); close_one(&conn->proxy_ssl[sockindex]); @@ -1582,8 +1590,9 @@ void Curl_gtls_close(struct connectdata *conn, int sockindex) * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ -int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) +static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ssize_t result; int retval = 0; struct Curl_easy *data = conn->data; @@ -1596,16 +1605,16 @@ 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(conn->ssl[sockindex].session, GNUTLS_SHUT_WR); + gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); - if(conn->ssl[sockindex].session) { + if(BACKEND->session) { while(!done) { int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); 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(conn->ssl[sockindex].session, + result = gnutls_record_recv(BACKEND->session, buf, sizeof(buf)); switch(result) { case 0: @@ -1636,18 +1645,18 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) done = 1; } } - gnutls_deinit(conn->ssl[sockindex].session); + gnutls_deinit(BACKEND->session); } - gnutls_certificate_free_credentials(conn->ssl[sockindex].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(conn->ssl[sockindex].srp_client_cred); + gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); #endif - conn->ssl[sockindex].cred = NULL; - conn->ssl[sockindex].session = NULL; + BACKEND->cred = NULL; + BACKEND->session = NULL; return retval; } @@ -1658,9 +1667,10 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[num]; ssize_t ret; - ret = gnutls_record_recv(conn->ssl[num].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; @@ -1680,6 +1690,7 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ if(ret < 0) { failf(conn->data, "GnuTLS recv error (%d): %s", + (int)ret, gnutls_strerror((int)ret)); *curlcode = CURLE_RECV_ERROR; return -1; @@ -1688,12 +1699,12 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ return ret; } -void Curl_gtls_session_free(void *ptr) +static void Curl_gtls_session_free(void *ptr) { free(ptr); } -size_t Curl_gtls_version(char *buffer, size_t size) +static size_t Curl_gtls_version(char *buffer, size_t size) { return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); } @@ -1723,9 +1734,8 @@ static int Curl_gtls_seed(struct Curl_easy *data) #endif /* data might be NULL! */ -CURLcode Curl_gtls_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +static CURLcode Curl_gtls_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) { #if defined(USE_GNUTLS_NETTLE) int rc; @@ -1740,10 +1750,10 @@ CURLcode Curl_gtls_random(struct Curl_easy *data, return CURLE_OK; } -void Curl_gtls_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len) +static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) { #if defined(USE_GNUTLS_NETTLE) struct md5_ctx MD5pw; @@ -1757,12 +1767,13 @@ void Curl_gtls_md5sum(unsigned char *tmp, /* input */ memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len); gcry_md_close(MD5pw); #endif + return CURLE_OK; } -void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len) +static void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len) { #if defined(USE_GNUTLS_NETTLE) struct sha256_ctx SHA256pw; @@ -1778,7 +1789,7 @@ void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ #endif } -bool Curl_gtls_cert_status_request(void) +static bool Curl_gtls_cert_status_request(void) { #ifdef HAS_OCSP return TRUE; @@ -1787,4 +1798,44 @@ bool Curl_gtls_cert_status_request(void) #endif } +static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + (void)info; + return BACKEND->session; +} + +const struct Curl_ssl Curl_ssl_gnutls = { + { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */ + + 1, /* have_ca_path */ + 1, /* have_certinfo */ + 1, /* have_pinnedpubkey */ + 0, /* have_ssl_ctx */ + 1, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_gtls_init, /* init */ + Curl_gtls_cleanup, /* cleanup */ + Curl_gtls_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_gtls_shutdown, /* shutdown */ + Curl_gtls_data_pending, /* data_pending */ + Curl_gtls_random, /* random */ + Curl_gtls_cert_status_request, /* cert_status_request */ + Curl_gtls_connect, /* connect */ + Curl_gtls_connect_nonblocking, /* connect_nonblocking */ + Curl_gtls_get_internals, /* get_internals */ + Curl_gtls_close, /* close */ + Curl_none_close_all, /* close_all */ + Curl_gtls_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_gtls_md5sum, /* md5sum */ + Curl_gtls_sha256sum /* sha256sum */ +}; + #endif /* USE_GNUTLS */ diff --git a/lib/vtls/gtls.h b/lib/vtls/gtls.h index 462c048..780fc10 100644 --- a/lib/vtls/gtls.h +++ b/lib/vtls/gtls.h @@ -28,69 +28,7 @@ #include "urldata.h" -int Curl_gtls_init(void); -int Curl_gtls_cleanup(void); -CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); -bool Curl_gtls_data_pending(const struct connectdata *conn, - int connindex); - - /* close a SSL connection */ -void Curl_gtls_close(struct connectdata *conn, int sockindex); - -void Curl_gtls_session_free(void *ptr); -size_t Curl_gtls_version(char *buffer, size_t size); -int Curl_gtls_shutdown(struct connectdata *conn, int sockindex); -CURLcode Curl_gtls_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length); -void Curl_gtls_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len); -void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len); - -bool Curl_gtls_cert_status_request(void); - -/* Support HTTPS-proxy */ -#define HTTPS_PROXY_SUPPORT 1 - -/* Set the API backend definition to GnuTLS */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_GNUTLS - -/* this backend supports the CAPATH option */ -#define have_curlssl_ca_path 1 - -/* this backend supports CURLOPT_CERTINFO */ -#define have_curlssl_certinfo 1 - -/* this backend supports CURLOPT_PINNEDPUBLICKEY */ -#define have_curlssl_pinnedpubkey 1 - -/* API setup for GnuTLS */ -#define curlssl_init Curl_gtls_init -#define curlssl_cleanup Curl_gtls_cleanup -#define curlssl_connect Curl_gtls_connect -#define curlssl_connect_nonblocking Curl_gtls_connect_nonblocking -#define curlssl_session_free(x) Curl_gtls_session_free(x) -#define curlssl_close_all(x) ((void)x) -#define curlssl_close Curl_gtls_close -#define curlssl_shutdown(x,y) Curl_gtls_shutdown(x,y) -#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) -#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) -#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) -#define curlssl_version Curl_gtls_version -#define curlssl_check_cxn(x) ((void)x, -1) -#define curlssl_data_pending(x,y) Curl_gtls_data_pending(x,y) -#define curlssl_random(x,y,z) Curl_gtls_random(x,y,z) -#define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d) -#define curlssl_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d) -#define curlssl_cert_status_request() Curl_gtls_cert_status_request() +extern const struct Curl_ssl Curl_ssl_gnutls; #endif /* USE_GNUTLS */ #endif /* HEADER_CURL_GTLS_H */ diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 037babe..ce1f8eb 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -61,6 +61,21 @@ #include "curl_memory.h" #include "memdebug.h" +struct ssl_backend_data { + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + mbedtls_ssl_context ssl; + int server_fd; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + mbedtls_x509_crl crl; + mbedtls_pk_context pk; + mbedtls_ssl_config config; + const char *protocols[3]; +}; + +#define BACKEND connssl->backend + /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) #define THREADING_SUPPORT @@ -214,9 +229,9 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) return result; } - mbedtls_ssl_conf_min_version(&connssl->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(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, mbedtls_ver_max); return result; @@ -238,7 +253,7 @@ mbed_connect_step1(struct connectdata *conn, const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; int ret = -1; char errorbuf[128]; - errorbuf[0]=0; + errorbuf[0] = 0; /* mbedTLS only supports SSLv3 and TLSv1 */ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { @@ -248,9 +263,9 @@ mbed_connect_step1(struct connectdata *conn, #ifdef THREADING_SUPPORT entropy_init_mutex(&ts_entropy); - mbedtls_ctr_drbg_init(&connssl->ctr_drbg); + mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); - ret = mbedtls_ctr_drbg_seed(&connssl->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 @@ -260,11 +275,11 @@ mbed_connect_step1(struct connectdata *conn, -ret, errorbuf); } #else - mbedtls_entropy_init(&connssl->entropy); - mbedtls_ctr_drbg_init(&connssl->ctr_drbg); + mbedtls_entropy_init(&BACKEND->entropy); + mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); - ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func, - &connssl->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)); @@ -275,10 +290,10 @@ mbed_connect_step1(struct connectdata *conn, #endif /* THREADING_SUPPORT */ /* Load the trusted CA */ - mbedtls_x509_crt_init(&connssl->cacert); + mbedtls_x509_crt_init(&BACKEND->cacert); if(ssl_cafile) { - ret = mbedtls_x509_crt_parse_file(&connssl->cacert, ssl_cafile); + ret = mbedtls_x509_crt_parse_file(&BACKEND->cacert, ssl_cafile); if(ret<0) { #ifdef MBEDTLS_ERROR_C @@ -293,7 +308,7 @@ mbed_connect_step1(struct connectdata *conn, } if(ssl_capath) { - ret = mbedtls_x509_crt_parse_path(&connssl->cacert, ssl_capath); + ret = mbedtls_x509_crt_parse_path(&BACKEND->cacert, ssl_capath); if(ret<0) { #ifdef MBEDTLS_ERROR_C @@ -308,10 +323,10 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the client certificate */ - mbedtls_x509_crt_init(&connssl->clicert); + mbedtls_x509_crt_init(&BACKEND->clicert); if(ssl_cert) { - ret = mbedtls_x509_crt_parse_file(&connssl->clicert, ssl_cert); + ret = mbedtls_x509_crt_parse_file(&BACKEND->clicert, ssl_cert); if(ret) { #ifdef MBEDTLS_ERROR_C @@ -325,12 +340,12 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the client private key */ - mbedtls_pk_init(&connssl->pk); + mbedtls_pk_init(&BACKEND->pk); if(SSL_SET_OPTION(key)) { - ret = mbedtls_pk_parse_keyfile(&connssl->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(&connssl->pk, MBEDTLS_PK_RSA)) + if(ret == 0 && !mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA)) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; if(ret) { @@ -345,10 +360,10 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the CRL */ - mbedtls_x509_crl_init(&connssl->crl); + mbedtls_x509_crl_init(&BACKEND->crl); if(ssl_crlfile) { - ret = mbedtls_x509_crl_parse_file(&connssl->crl, ssl_crlfile); + ret = mbedtls_x509_crl_parse_file(&BACKEND->crl, ssl_crlfile); if(ret) { #ifdef MBEDTLS_ERROR_C @@ -363,14 +378,14 @@ mbed_connect_step1(struct connectdata *conn, infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port); - mbedtls_ssl_config_init(&connssl->config); + mbedtls_ssl_config_init(&BACKEND->config); - mbedtls_ssl_init(&connssl->ssl); - if(mbedtls_ssl_setup(&connssl->ssl, &connssl->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(&connssl->config, + ret = mbedtls_ssl_config_defaults(&BACKEND->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); @@ -380,20 +395,20 @@ mbed_connect_step1(struct connectdata *conn, } /* new profile with RSA min key len = 1024 ... */ - mbedtls_ssl_conf_cert_profile(&connssl->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(&connssl->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(&connssl->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(&connssl->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; @@ -412,25 +427,25 @@ mbed_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_authmode(&BACKEND->config, MBEDTLS_SSL_VERIFY_OPTIONAL); - mbedtls_ssl_conf_rng(&connssl->config, mbedtls_ctr_drbg_random, - &connssl->ctr_drbg); - mbedtls_ssl_set_bio(&connssl->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(&connssl->config, + mbedtls_ssl_conf_ciphersuites(&BACKEND->config, mbedtls_ssl_list_ciphersuites()); #if defined(MBEDTLS_SSL_RENEGOTIATION) - mbedtls_ssl_conf_renegotiation(&connssl->config, + mbedtls_ssl_conf_renegotiation(&BACKEND->config, MBEDTLS_SSL_RENEGOTIATION_ENABLED); #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) - mbedtls_ssl_conf_session_tickets(&connssl->config, + mbedtls_ssl_conf_session_tickets(&BACKEND->config, MBEDTLS_SSL_SESSION_TICKETS_DISABLED); #endif @@ -440,7 +455,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(&connssl->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); @@ -451,15 +466,15 @@ mbed_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_unlock(conn); } - mbedtls_ssl_conf_ca_chain(&connssl->config, - &connssl->cacert, - &connssl->crl); + mbedtls_ssl_conf_ca_chain(&BACKEND->config, + &BACKEND->cacert, + &BACKEND->crl); if(SSL_SET_OPTION(key)) { - mbedtls_ssl_conf_own_cert(&connssl->config, - &connssl->clicert, &connssl->pk); + mbedtls_ssl_conf_own_cert(&BACKEND->config, + &BACKEND->clicert, &BACKEND->pk); } - if(mbedtls_ssl_set_hostname(&connssl->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. */ @@ -469,7 +484,7 @@ mbed_connect_step1(struct connectdata *conn, #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { - const char **p = &connssl->protocols[0]; + const char **p = &BACKEND->protocols[0]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) *p++ = NGHTTP2_PROTO_VERSION_ID; @@ -478,19 +493,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(&connssl->config, - &connssl->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 = &connssl->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(&connssl->config, mbed_debug, data); + mbedtls_ssl_conf_dbg(&BACKEND->config, mbed_debug, data); /* - 0 No debug * - 1 Error * - 2 State change @@ -502,7 +517,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, &connssl->config, + ret = (*data->set.ssl.fsslctx)(data, &BACKEND->config, data->set.ssl.fsslctxp); if(ret) { failf(data, "error signaled by ssl ctx callback"); @@ -537,7 +552,7 @@ mbed_connect_step2(struct connectdata *conn, conn->recv[sockindex] = mbed_recv; conn->send[sockindex] = mbed_send; - ret = mbedtls_ssl_handshake(&connssl->ssl); + ret = mbedtls_ssl_handshake(&BACKEND->ssl); if(ret == MBEDTLS_ERR_SSL_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; @@ -557,10 +572,10 @@ mbed_connect_step2(struct connectdata *conn, } infof(data, "mbedTLS: Handshake complete, cipher is %s\n", - mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) + mbedtls_ssl_get_ciphersuite(&BACKEND->ssl) ); - ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl); + ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl); if(ret && SSL_CONN_CONFIG(verifypeer)) { if(ret & MBEDTLS_X509_BADCERT_EXPIRED) @@ -580,7 +595,7 @@ mbed_connect_step2(struct connectdata *conn, return CURLE_PEER_FAILED_VERIFICATION; } - peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl); + peercert = mbedtls_ssl_get_peer_cert(&BACKEND->ssl); if(peercert && data->set.verbose) { const size_t bufsize = 16384; @@ -650,7 +665,7 @@ mbed_connect_step2(struct connectdata *conn, #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { - next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl); + next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl); if(next_protocol) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); @@ -700,7 +715,7 @@ mbed_connect_step3(struct connectdata *conn, mbedtls_ssl_session_init(our_ssl_sessionid); - ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid); + ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid); if(ret) { free(our_ssl_sessionid); failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); @@ -730,9 +745,10 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; int ret = -1; - ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl, + ret = mbedtls_ssl_write(&BACKEND->ssl, (unsigned char *)mem, len); if(ret < 0) { @@ -744,22 +760,23 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex, return ret; } -void Curl_mbedtls_close_all(struct Curl_easy *data) +static void Curl_mbedtls_close_all(struct Curl_easy *data) { (void)data; } -void Curl_mbedtls_close(struct connectdata *conn, int sockindex) +static void Curl_mbedtls_close(struct connectdata *conn, int sockindex) { - mbedtls_pk_free(&conn->ssl[sockindex].pk); - mbedtls_x509_crt_free(&conn->ssl[sockindex].clicert); - mbedtls_x509_crt_free(&conn->ssl[sockindex].cacert); - mbedtls_x509_crl_free(&conn->ssl[sockindex].crl); - mbedtls_ssl_config_free(&conn->ssl[sockindex].config); - mbedtls_ssl_free(&conn->ssl[sockindex].ssl); - mbedtls_ctr_drbg_free(&conn->ssl[sockindex].ctr_drbg); + 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); #ifndef THREADING_SUPPORT - mbedtls_entropy_free(&conn->ssl[sockindex].entropy); + mbedtls_entropy_free(&BACKEND->entropy); #endif /* THREADING_SUPPORT */ } @@ -767,11 +784,12 @@ static ssize_t mbed_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[num]; int ret = -1; ssize_t len = -1; memset(buf, 0, buffersize); - ret = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, + ret = mbedtls_ssl_read(&BACKEND->ssl, (unsigned char *)buf, buffersize); if(ret <= 0) { @@ -788,21 +806,21 @@ static ssize_t mbed_recv(struct connectdata *conn, int num, return len; } -void Curl_mbedtls_session_free(void *ptr) +static void Curl_mbedtls_session_free(void *ptr) { mbedtls_ssl_session_free(ptr); free(ptr); } -size_t Curl_mbedtls_version(char *buffer, size_t size) +static size_t Curl_mbedtls_version(char *buffer, size_t size) { unsigned int version = mbedtls_version_get_number(); return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24, (version>>16)&0xff, (version>>8)&0xff); } -CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy, - size_t length) +static CURLcode Curl_mbedtls_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) { #if defined(MBEDTLS_CTR_DRBG_C) int ret = -1; @@ -811,7 +829,7 @@ CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy, mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_init(&ctr_entropy); mbedtls_ctr_drbg_init(&ctr_drbg); - errorbuf[0]=0; + errorbuf[0] = 0; ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &ctr_entropy, NULL, 0); @@ -869,7 +887,7 @@ mbed_connect_common(struct connectdata *conn, return CURLE_OK; } - if(ssl_connect_1==connssl->connecting_state) { + if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -900,9 +918,9 @@ mbed_connect_common(struct connectdata *conn, if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { - curl_socket_t writefd = ssl_connect_2_writing== + curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading== + curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, @@ -942,13 +960,13 @@ mbed_connect_common(struct connectdata *conn, } /* repeat step2 until all transactions are done. */ - if(ssl_connect_3==connssl->connecting_state) { + if(ssl_connect_3 == connssl->connecting_state) { retcode = mbed_connect_step3(conn, sockindex); if(retcode) return retcode; } - if(ssl_connect_done==connssl->connecting_state) { + if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = mbed_recv; conn->send[sockindex] = mbed_send; @@ -963,18 +981,14 @@ mbed_connect_common(struct connectdata *conn, return CURLE_OK; } -CURLcode -Curl_mbedtls_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +static CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { return mbed_connect_common(conn, sockindex, TRUE, done); } -CURLcode -Curl_mbedtls_connect(struct connectdata *conn, - int sockindex) +static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex) { CURLcode retcode; bool done = FALSE; @@ -992,19 +1006,70 @@ Curl_mbedtls_connect(struct connectdata *conn, * return 0 error initializing SSL * return 1 SSL initialized successfully */ -int Curl_mbedtls_init(void) +static int Curl_mbedtls_init(void) { return Curl_polarsslthreadlock_thread_setup(); } -void Curl_mbedtls_cleanup(void) +static void Curl_mbedtls_cleanup(void) { (void)Curl_polarsslthreadlock_thread_cleanup(); } -int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex) +static bool Curl_mbedtls_data_pending(const struct connectdata *conn, + int sockindex) { - return mbedtls_ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0; + const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0; } +static void Curl_mbedtls_sha256sum(const unsigned char *input, + size_t inputlen, + unsigned char *sha256sum, + size_t sha256len UNUSED_PARAM) +{ + (void)sha256len; + mbedtls_sha256(input, inputlen, sha256sum, 0); +} + +static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + (void)info; + return &BACKEND->ssl; +} + +const struct Curl_ssl Curl_ssl_mbedtls = { + { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */ + + 1, /* have_ca_path */ + 0, /* have_certinfo */ + 1, /* have_pinnedpubkey */ + 1, /* have_ssl_ctx */ + 0, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_mbedtls_init, /* init */ + Curl_mbedtls_cleanup, /* cleanup */ + Curl_mbedtls_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_none_shutdown, /* shutdown */ + Curl_mbedtls_data_pending, /* data_pending */ + Curl_mbedtls_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + Curl_mbedtls_connect, /* connect */ + Curl_mbedtls_connect_nonblocking, /* connect_nonblocking */ + Curl_mbedtls_get_internals, /* get_internals */ + Curl_mbedtls_close, /* close */ + Curl_mbedtls_close_all, /* close_all */ + Curl_mbedtls_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_none_md5sum, /* md5sum */ + Curl_mbedtls_sha256sum /* sha256sum */ +}; + #endif /* USE_MBEDTLS */ diff --git a/lib/vtls/mbedtls.h b/lib/vtls/mbedtls.h index 71d17a4..4a93860 100644 --- a/lib/vtls/mbedtls.h +++ b/lib/vtls/mbedtls.h @@ -26,57 +26,7 @@ #ifdef USE_MBEDTLS -#include - -/* Called on first use mbedTLS, setup threading if supported */ -int Curl_mbedtls_init(void); -void Curl_mbedtls_cleanup(void); -int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex); - -CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex); - -CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); - -/* tell mbedTLS to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_mbedtls_close_all(struct Curl_easy *data); - - /* close a SSL connection */ -void Curl_mbedtls_close(struct connectdata *conn, int sockindex); - -void Curl_mbedtls_session_free(void *ptr); -size_t Curl_mbedtls_version(char *buffer, size_t size); -int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); - -CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy, - size_t length); - -/* this backends supports CURLOPT_PINNEDPUBLICKEY */ -#define have_curlssl_pinnedpubkey 1 - -/* this backend supports CURLOPT_SSL_CTX_* */ -#define have_curlssl_ssl_ctx 1 - -/* API setup for mbedTLS */ -#define curlssl_init() Curl_mbedtls_init() -#define curlssl_cleanup() Curl_mbedtls_cleanup() -#define curlssl_connect Curl_mbedtls_connect -#define curlssl_connect_nonblocking Curl_mbedtls_connect_nonblocking -#define curlssl_session_free(x) Curl_mbedtls_session_free(x) -#define curlssl_close_all Curl_mbedtls_close_all -#define curlssl_close Curl_mbedtls_close -#define curlssl_shutdown(x,y) 0 -#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN) -#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN) -#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) -#define curlssl_version Curl_mbedtls_version -#define curlssl_check_cxn(x) (x=x, -1) -#define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y) -#define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS -#define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0) -#define curlssl_random(x,y,z) Curl_mbedtls_random(x, y, z) +extern const struct Curl_ssl Curl_ssl_mbedtls; #endif /* USE_MBEDTLS */ #endif /* HEADER_CURL_MBEDTLS_H */ diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index cd01389..c0b7e63 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -78,6 +78,16 @@ /* enough to fit the string "PEM Token #[0|1]" */ #define SLOTSIZE 13 +struct ssl_backend_data { + PRFileDesc *handle; + char *client_nickname; + struct Curl_easy *data; + struct curl_llist obj_list; + PK11GenericObject *obj_clicert; +}; + +#define BACKEND connssl->backend + static PRLock *nss_initlock = NULL; static PRLock *nss_crllock = NULL; static PRLock *nss_findslot_lock = NULL; @@ -271,7 +281,7 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, found = PR_FALSE; - for(i=0; iobj_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 */ - ssl->obj_clicert = obj; + BACKEND->obj_clicert = obj; return CURLE_OK; } @@ -992,7 +1002,7 @@ static SECStatus check_issuer_cert(PRFileDesc *sock, char *issuer_nickname) { CERTCertificate *cert, *cert_issuer, *issuer; - SECStatus res=SECSuccess; + SECStatus res = SECSuccess; void *proto_win = NULL; cert = SSL_PeerCertificate(sock); @@ -1004,7 +1014,7 @@ static SECStatus check_issuer_cert(PRFileDesc *sock, if((!cert_issuer) || (!issuer)) res = SECFailure; else if(SECITEM_CompareItem(&cert_issuer->derCert, - &issuer->derCert)!=SECEqual) + &issuer->derCert) != SECEqual) res = SECFailure; CERT_DestroyCertificate(cert); @@ -1017,7 +1027,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, const char *pinnedpubkey) { CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - struct Curl_easy *data = connssl->data; + struct Curl_easy *data = BACKEND->data; CERTCertificate *cert; if(!pinnedpubkey) @@ -1025,7 +1035,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, return CURLE_OK; /* get peer certificate */ - cert = SSL_PeerCertificate(connssl->handle); + cert = SSL_PeerCertificate(BACKEND->handle); if(cert) { /* extract public key from peer certificate */ SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert); @@ -1069,11 +1079,11 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct SECKEYPrivateKeyStr **pRetKey) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; - struct Curl_easy *data = connssl->data; - const char *nickname = connssl->client_nickname; + struct Curl_easy *data = BACKEND->data; + const char *nickname = BACKEND->client_nickname; static const char pem_slotname[] = "PEM Token #1"; - if(connssl->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); @@ -1086,7 +1096,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, return SECFailure; } - if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->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); @@ -1351,7 +1361,7 @@ static CURLcode nss_init(struct Curl_easy *data) * @retval 0 error initializing SSL * @retval 1 SSL initialized successfully */ -int Curl_nss_init(void) +static int Curl_nss_init(void) { /* curl_global_init() is not thread-safe so this test is ok */ if(nss_initlock == NULL) { @@ -1386,7 +1396,7 @@ CURLcode Curl_nss_force_init(struct Curl_easy *data) } /* Global cleanup */ -void Curl_nss_cleanup(void) +static void Curl_nss_cleanup(void) { /* This function isn't required to be threadsafe and this is only done * as a safety feature. @@ -1426,14 +1436,14 @@ void Curl_nss_cleanup(void) * 0 means the connection has been closed * -1 means the connection status is unknown */ -int -Curl_nss_check_cxn(struct connectdata *conn) +static int Curl_nss_check_cxn(struct connectdata *conn) { + struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; int rc; char buf; rc = - PR_Recv(conn->ssl[FIRSTSOCKET].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 */ @@ -1447,48 +1457,49 @@ 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 = (connssl->client_nickname != NULL) - || (connssl->obj_clicert != NULL); + const bool client_cert = (BACKEND->client_nickname != NULL) + || (BACKEND->obj_clicert != NULL); - free(connssl->client_nickname); - connssl->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(&connssl->obj_list, NULL); - connssl->obj_clicert = NULL; + Curl_llist_destroy(&BACKEND->obj_list, NULL); + BACKEND->obj_clicert = NULL; - if(connssl->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(connssl->handle); + SSL_InvalidateSession(BACKEND->handle); - PR_Close(connssl->handle); - connssl->handle = NULL; + PR_Close(BACKEND->handle); + BACKEND->handle = NULL; } } /* * This function is called when an SSL connection is closed. */ -void Curl_nss_close(struct connectdata *conn, int sockindex) +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]; - if(connssl->handle || connssl_proxy->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(connssl->handle) - /* nss_close(connssl) will transitively close also connssl_proxy->handle - if both are used. Clear it to avoid a double close leading to crash. */ - connssl_proxy->handle = NULL; + 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. */ + connssl_proxy->backend->handle = NULL; nss_close(connssl); nss_close(connssl_proxy); @@ -1732,7 +1743,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, } /* cleanup on connection failure */ - Curl_llist_destroy(&connssl->obj_list, NULL); + Curl_llist_destroy(&BACKEND->obj_list, NULL); return curlerr; } @@ -1746,7 +1757,7 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl, sock_opt.option = PR_SockOpt_Nonblocking; sock_opt.value.non_blocking = !blocking; - if(PR_SetSocketOption(connssl->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; @@ -1770,10 +1781,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) SSL_LIBRARY_VERSION_TLS_1_0 /* max */ }; - connssl->data = data; + BACKEND->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ - Curl_llist_init(&connssl->obj_list, nss_destroy_object); + Curl_llist_init(&BACKEND->obj_list, nss_destroy_object); /* FIXME. NSS doesn't support multiple databases open at the same time. */ PR_Lock(nss_initlock); @@ -1882,7 +1893,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 */ - connssl->obj_clicert = NULL; + BACKEND->obj_clicert = NULL; } else { CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert), @@ -1895,10 +1906,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } /* store the nickname for SelectClientCert() called during handshake */ - connssl->client_nickname = nickname; + BACKEND->client_nickname = nickname; } else - connssl->client_nickname = NULL; + BACKEND->client_nickname = NULL; if(SSL_GetClientAuthDataHook(model, SelectClientCert, (void *)connssl) != SECSuccess) { @@ -1908,8 +1919,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) if(conn->proxy_ssl[sockindex].use) { DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); - DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL); - nspr_io = conn->proxy_ssl[sockindex].handle; + DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL); + nspr_io = conn->proxy_ssl[sockindex].backend->handle; second_layer = TRUE; } else { @@ -1939,8 +1950,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } /* import our model socket onto the current I/O stack */ - connssl->handle = SSL_ImportFD(model, nspr_io); - if(!connssl->handle) { + BACKEND->handle = SSL_ImportFD(model, nspr_io); + if(!BACKEND->handle) { if(!second_layer) PR_Close(nspr_io); goto error; @@ -1951,36 +1962,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(connssl->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(connssl->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(connssl->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(connssl->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(connssl->handle, SSL_ENABLE_FALSE_START, PR_TRUE) + if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_FALSE_START, PR_TRUE) != SECSuccess) goto error; - if(SSL_SetCanFalseStartCallback(connssl->handle, CanFalseStartCallback, + if(SSL_SetCanFalseStartCallback(BACKEND->handle, CanFalseStartCallback, conn) != SECSuccess) goto error; } @@ -1992,7 +2003,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) unsigned char protocols[128]; #ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2 && + (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN); @@ -2003,24 +2015,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(connssl->handle, protocols, cur) != SECSuccess) + if(SSL_SetNextProtoNego(BACKEND->handle, protocols, cur) != SECSuccess) goto error; } #endif /* Force handshake on next I/O */ - if(SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE) + if(SSL_ResetHandshake(BACKEND->handle, /* asServer */ PR_FALSE) != SECSuccess) goto error; /* propagate hostname to the TLS layer */ - if(SSL_SetURL(connssl->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(connssl->handle, SSL_IS_PROXY() ? + if(SSL_SetSockPeerID(BACKEND->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name) != SECSuccess) goto error; @@ -2057,7 +2069,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) /* Force the handshake now */ timeout = PR_MillisecondsToInterval((PRUint32) time_left); - if(SSL_ForceHandshakeWithTimeout(connssl->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; @@ -2068,7 +2080,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) goto error; } - result = display_conn_info(conn, connssl->handle); + result = display_conn_info(conn, BACKEND->handle); if(result) goto error; @@ -2077,7 +2089,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(connssl->handle, nickname); + ret = check_issuer_cert(BACKEND->handle, nickname); free(nickname); } @@ -2163,13 +2175,13 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, return CURLE_OK; } -CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) +static CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) { return nss_connect_common(conn, sockindex, /* blocking */ NULL); } -CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) +static CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { return nss_connect_common(conn, sockindex, done); } @@ -2180,8 +2192,14 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */ size_t len, /* amount to write */ CURLcode *curlcode) { - ssize_t rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, - PR_INTERVAL_NO_WAIT); + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + 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; + + 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) @@ -2205,14 +2223,21 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */ return rc; /* number of bytes */ } -static ssize_t nss_recv(struct connectdata * conn, /* connection data */ - int num, /* socketindex */ +static ssize_t nss_recv(struct connectdata *conn, /* connection data */ + int sockindex, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { - ssize_t nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, - PR_INTERVAL_NO_WAIT); + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + 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; + + nread = PR_Recv(BACKEND->handle, buf, (int)buffersize, 0, + PR_INTERVAL_NO_WAIT); if(nread < 0) { /* failed SSL read */ PRInt32 err = PR_GetError(); @@ -2238,22 +2263,22 @@ static ssize_t nss_recv(struct connectdata * conn, /* connection data */ return nread; } -size_t Curl_nss_version(char *buffer, size_t size) +static size_t Curl_nss_version(char *buffer, size_t size) { return snprintf(buffer, size, "NSS/%s", NSS_VERSION); } /* data might be NULL */ -int Curl_nss_seed(struct Curl_easy *data) +static int Curl_nss_seed(struct Curl_easy *data) { /* make sure that NSS is initialized */ return !!Curl_nss_force_init(data); } /* data might be NULL */ -CURLcode Curl_nss_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +static CURLcode Curl_nss_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { Curl_nss_seed(data); /* Initiate the seed if not already done */ @@ -2264,10 +2289,10 @@ CURLcode Curl_nss_random(struct Curl_easy *data, return CURLE_OK; } -void Curl_nss_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len) +static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) { PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); unsigned int MD5out; @@ -2275,12 +2300,14 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */ PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen)); PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len)); PK11_DestroyContext(MD5pw, PR_TRUE); + + return CURLE_OK; } -void Curl_nss_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len) +static void Curl_nss_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len) { PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256); unsigned int SHA256out; @@ -2290,7 +2317,7 @@ void Curl_nss_sha256sum(const unsigned char *tmp, /* input */ PK11_DestroyContext(SHA256pw, PR_TRUE); } -bool Curl_nss_cert_status_request(void) +static bool Curl_nss_cert_status_request(void) { #ifdef SSL_ENABLE_OCSP_STAPLING return TRUE; @@ -2299,7 +2326,7 @@ bool Curl_nss_cert_status_request(void) #endif } -bool Curl_nss_false_start(void) +static bool Curl_nss_false_start(void) { #if NSSVERNUM >= 0x030f04 /* 3.15.4 */ return TRUE; @@ -2308,4 +2335,46 @@ bool Curl_nss_false_start(void) #endif } +static void *Curl_nss_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + (void)info; + return BACKEND->handle; +} + +const struct Curl_ssl Curl_ssl_nss = { + { CURLSSLBACKEND_NSS, "nss" }, /* info */ + + 1, /* have_ca_path */ + 1, /* have_certinfo */ + 1, /* have_pinnedpubkey */ + 0, /* have_ssl_ctx */ + 1, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_nss_init, /* init */ + Curl_nss_cleanup, /* cleanup */ + Curl_nss_version, /* version */ + Curl_nss_check_cxn, /* check_cxn */ + /* NSS has no shutdown function provided and thus always fail */ + Curl_none_shutdown, /* shutdown */ + Curl_none_data_pending, /* data_pending */ + Curl_nss_random, /* random */ + Curl_nss_cert_status_request, /* cert_status_request */ + Curl_nss_connect, /* connect */ + Curl_nss_connect_nonblocking, /* connect_nonblocking */ + Curl_nss_get_internals, /* get_internals */ + Curl_nss_close, /* close */ + Curl_none_close_all, /* close_all */ + /* NSS has its own session ID cache */ + Curl_none_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_nss_false_start, /* false_start */ + Curl_nss_md5sum, /* md5sum */ + Curl_nss_sha256sum /* sha256sum */ +}; + #endif /* USE_NSS */ diff --git a/lib/vtls/nssg.h b/lib/vtls/nssg.h index 8c46929..41e51b0 100644 --- a/lib/vtls/nssg.h +++ b/lib/vtls/nssg.h @@ -30,79 +30,10 @@ #include "urldata.h" -CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); -/* close a SSL connection */ -void Curl_nss_close(struct connectdata *conn, int sockindex); - -int Curl_nss_init(void); -void Curl_nss_cleanup(void); - -size_t Curl_nss_version(char *buffer, size_t size); -int Curl_nss_check_cxn(struct connectdata *cxn); -int Curl_nss_seed(struct Curl_easy *data); - /* initialize NSS library if not already */ CURLcode Curl_nss_force_init(struct Curl_easy *data); -CURLcode Curl_nss_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length); - -void Curl_nss_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len); - -void Curl_nss_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len); - -bool Curl_nss_cert_status_request(void); - -bool Curl_nss_false_start(void); - -/* Support HTTPS-proxy */ -#define HTTPS_PROXY_SUPPORT 1 - -/* Set the API backend definition to NSS */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_NSS - -/* this backend supports the CAPATH option */ -#define have_curlssl_ca_path 1 - -/* this backend supports CURLOPT_CERTINFO */ -#define have_curlssl_certinfo 1 - -/* this backends supports CURLOPT_PINNEDPUBLICKEY */ -#define have_curlssl_pinnedpubkey 1 - -/* API setup for NSS */ -#define curlssl_init Curl_nss_init -#define curlssl_cleanup Curl_nss_cleanup -#define curlssl_connect Curl_nss_connect -#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking - -/* NSS has its own session ID cache */ -#define curlssl_session_free(x) Curl_nop_stmt -#define curlssl_close_all(x) ((void)x) -#define curlssl_close Curl_nss_close -/* NSS has no shutdown function provided and thus always fail */ -#define curlssl_shutdown(x,y) ((void)x, (void)y, 1) -#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) -#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) -#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) -#define curlssl_version Curl_nss_version -#define curlssl_check_cxn(x) Curl_nss_check_cxn(x) -#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) -#define curlssl_random(x,y,z) Curl_nss_random(x,y,z) -#define curlssl_md5sum(a,b,c,d) Curl_nss_md5sum(a,b,c,d) -#define curlssl_sha256sum(a,b,c,d) Curl_nss_sha256sum(a,b,c,d) -#define curlssl_cert_status_request() Curl_nss_cert_status_request() -#define curlssl_false_start() Curl_nss_false_start() +extern const struct Curl_ssl Curl_ssl_nss; #endif /* USE_NSS */ #endif /* HEADER_CURL_NSSG_H */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index dbee369..4253160 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -51,8 +51,10 @@ #include "strcase.h" #include "hostcheck.h" #include "curl_printf.h" - #include +#ifdef HAVE_OPENSSL_ENGINE_H +#include +#endif #include #include #ifndef OPENSSL_NO_DSA @@ -64,6 +66,8 @@ #include #include #include +#include +#include #ifdef HAVE_OPENSSL_PKCS12_H #include @@ -111,7 +115,6 @@ #define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ #define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ #define CONST_EXTS const -#define CONST_ASN1_BIT_STRING const #define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 #else /* For OpenSSL before 1.1.0 */ @@ -119,7 +122,6 @@ #define X509_get0_notBefore(x) X509_get_notBefore(x) #define X509_get0_notAfter(x) X509_get_notAfter(x) #define CONST_EXTS /* nope */ -#define CONST_ASN1_BIT_STRING /* nope */ #ifdef LIBRESSL_VERSION_NUMBER static unsigned long OpenSSL_version_num(void) { @@ -146,6 +148,20 @@ static unsigned long OpenSSL_version_num(void) #define OPENSSL_load_builtin_modules(x) #endif +/* + * Whether SSL_CTX_set_keylog_callback is available. + * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 + * BoringSSL: supported since d28f59c27bac (committed 2015-11-19), the + * BORINGSSL_201512 macro from 2016-01-21 should be close enough. + * LibreSSL: unsupported in at least 2.5.1 (explicitly check for it since it + * lies and pretends to be OpenSSL 2.0.0). + */ +#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER)) || \ + defined(BORINGSSL_201512) +#define HAVE_KEYLOG_CALLBACK +#endif + #if defined(LIBRESSL_VERSION_NUMBER) #define OSSL_PACKAGE "LibreSSL" #elif defined(OPENSSL_IS_BORINGSSL) @@ -154,6 +170,38 @@ static unsigned long OpenSSL_version_num(void) #define OSSL_PACKAGE "OpenSSL" #endif +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +/* up2date versions of OpenSSL maintain the default reasonably secure without + * breaking compatibility, so it is better not to override the default by curl + */ +#define DEFAULT_CIPHER_SELECTION NULL +#else +/* ... but it is not the case with old versions of OpenSSL */ +#define DEFAULT_CIPHER_SELECTION \ + "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" +#endif + +#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; +#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 @@ -162,6 +210,112 @@ static unsigned long OpenSSL_version_num(void) */ #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; + } + strncpy(buf, line, linelen); + buf[linelen] = '\n'; + buf[linelen + 1] = '\0'; + + fputs(buf, keylog_file_fp); + if(buf != stackbuf) + free(buf); + } +} +#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. + */ +static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state) +{ + 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) + return; + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that + * we have a valid SSL context if we have a non-NULL session. */ + SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE); + master_key_length = + SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH); +#else + if(ssl->s3 && session->master_key_length > 0) { + master_key_length = session->master_key_length; + memcpy(master_key, session->master_key, session->master_key_length); + memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE); + } +#endif + + 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); +} +#endif /* !HAVE_KEYLOG_CALLBACK */ +#endif /* ENABLE_SSLKEYLOGFILE */ + static const char *SSL_ERROR_to_str(int err) { switch(err) { @@ -216,7 +370,7 @@ static int passwd_callback(char *buf, int num, int encrypting, if(!encrypting) { int klen = curlx_uztosi(strlen((char *)global_passwd)); if(num > klen) { - memcpy(buf, global_passwd, klen+1); + memcpy(buf, global_passwd, klen + 1); return klen; } } @@ -236,7 +390,6 @@ static CURLcode Curl_ossl_seed(struct Curl_easy *data) /* we have the "SSL is seeded" boolean static to prevent multiple time-consuming seedings in vain */ static bool ssl_seeded = FALSE; - int nread=0; char fname[256]; if(ssl_seeded) @@ -256,12 +409,12 @@ static CURLcode Curl_ossl_seed(struct Curl_easy *data) #endif { /* let the option override the define */ - nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]? - data->set.str[STRING_SSL_RANDOM_FILE]: - RANDOM_FILE), - RAND_LOAD_LENGTH); + RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]? + data->set.str[STRING_SSL_RANDOM_FILE]: + RANDOM_FILE), + RAND_LOAD_LENGTH); if(rand_enough()) - return nread; + return CURLE_OK; } #if defined(HAVE_RAND_EGD) @@ -279,35 +432,47 @@ static CURLcode Curl_ossl_seed(struct Curl_easy *data) int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]? data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET); if(-1 != ret) { - nread += ret; if(rand_enough()) - return nread; + return CURLE_OK; } } #endif - /* If we get here, it means we need to seed the PRNG using a "silly" - approach! */ + /* fallback to a custom seeding of the PRNG using a hash based on a current + time */ do { unsigned char randb[64]; - int len = sizeof(randb); - if(!RAND_bytes(randb, len)) - break; - RAND_add(randb, len, (len >> 1)); + size_t len = sizeof(randb); + size_t i, i_max; + for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) { + struct curltime tv = curlx_tvnow(); + Curl_wait_ms(1); + tv.tv_sec *= i + 1; + tv.tv_usec *= (unsigned int)i + 2; + tv.tv_sec ^= ((curlx_tvnow().tv_sec + curlx_tvnow().tv_usec) * + (i + 3)) << 8; + tv.tv_usec ^= (unsigned int) ((curlx_tvnow().tv_sec + + curlx_tvnow().tv_usec) * + (i + 4)) << 16; + memcpy(&randb[i * sizeof(struct curltime)], &tv, + sizeof(struct curltime)); + } + RAND_add(randb, (int)len, (double)len/2); } while(!rand_enough()); /* generates a default path for the random seed file */ - fname[0]=0; /* blank it first */ + fname[0] = 0; /* blank it first */ RAND_file_name(fname, sizeof(fname)); if(fname[0]) { /* we got a file name to try */ - nread += RAND_load_file(fname, RAND_LOAD_LENGTH); + RAND_load_file(fname, RAND_LOAD_LENGTH); if(rand_enough()) - return nread; + return CURLE_OK; } infof(data, "libcurl is now using a weak random seed!\n"); - return CURLE_SSL_CONNECT_ERROR; /* confusing error code */ + return (rand_enough() ? CURLE_OK : + CURLE_SSL_CONNECT_ERROR /* confusing error code */); } #ifndef SSL_FILETYPE_ENGINE @@ -384,6 +549,7 @@ int cert_stuff(struct connectdata *conn, { struct Curl_easy *data = conn->data; char error_buffer[256]; + bool check_privkey = TRUE; int file_type = do_file_type(cert_type); @@ -592,7 +758,7 @@ int cert_stuff(struct connectdata *conn, break; if(!key_file) /* cert & key can only be in PEM case in the same file */ - key_file=cert_file; + key_file = cert_file; /* FALLTHROUGH */ case SSL_FILETYPE_ASN1: if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { @@ -655,13 +821,13 @@ int cert_stuff(struct connectdata *conn, return 0; } - ssl=SSL_new(ctx); + ssl = SSL_new(ctx); if(!ssl) { failf(data, "unable to create an SSL structure"); return 0; } - x509=SSL_get_certificate(ssl); + x509 = SSL_get_certificate(ssl); /* This version was provided by Evan Jordan and is supposed to not leak memory as the previous version: */ @@ -671,17 +837,32 @@ int cert_stuff(struct connectdata *conn, EVP_PKEY_free(pktmp); } +#ifndef OPENSSL_NO_RSA + { + /* If RSA is used, don't check the private key if its flags indicate + * it doesn't support it. */ + EVP_PKEY *priv_key = SSL_get_privatekey(ssl); + if(EVP_PKEY_id(priv_key) == EVP_PKEY_RSA) { + RSA *rsa = EVP_PKEY_get1_RSA(priv_key); + if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK) + check_privkey = FALSE; + RSA_free(rsa); /* Decrement reference count */ + } + } +#endif + SSL_free(ssl); /* If we are using DSA, we can copy the parameters from * the private key */ - - /* Now we know that a key and cert have been set against - * the SSL context */ - if(!SSL_CTX_check_private_key(ctx)) { - failf(data, "Private key does not match the certificate public key"); - return 0; + if(check_privkey == TRUE) { + /* Now we know that a key and cert have been set against + * the SSL context */ + if(!SSL_CTX_check_private_key(ctx)) { + failf(data, "Private key does not match the certificate public key"); + return 0; + } } } return 1; @@ -709,7 +890,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) size--; /* don't overwrite the buffer end */ memcpy(buf, biomem->data, size); - buf[size]=0; + buf[size] = 0; BIO_free(bio_out); @@ -723,8 +904,12 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) * @retval 0 error initializing SSL * @retval 1 SSL initialized successfully */ -int Curl_ossl_init(void) +static int Curl_ossl_init(void) { +#ifdef ENABLE_SSLKEYLOGFILE + const char *keylog_file_name; +#endif + OPENSSL_load_builtin_modules(); #ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES @@ -761,11 +946,24 @@ int Curl_ossl_init(void) OpenSSL_add_all_algorithms(); #endif +#ifdef ENABLE_SSLKEYLOGFILE + keylog_file_name = curl_getenv("SSLKEYLOGFILE"); + if(keylog_file_name && !keylog_file_fp) { + keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); + if(keylog_file_fp) { + if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) { + fclose(keylog_file_fp); + keylog_file_fp = NULL; + } + } + } +#endif + return 1; } /* Global cleanup */ -void Curl_ossl_cleanup(void) +static void Curl_ossl_cleanup(void) { #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ !defined(LIBRESSL_VERSION_NUMBER) @@ -797,6 +995,13 @@ void Curl_ossl_cleanup(void) SSL_COMP_free_compression_methods(); #endif #endif + +#ifdef ENABLE_SSLKEYLOGFILE + if(keylog_file_fp) { + fclose(keylog_file_fp); + keylog_file_fp = NULL; + } +#endif } /* @@ -807,7 +1012,7 @@ void Curl_ossl_cleanup(void) * 0 means the connection has been closed * -1 means the connection status is unknown */ -int Curl_ossl_check_cxn(struct connectdata *conn) +static int Curl_ossl_check_cxn(struct connectdata *conn) { /* SSL_peek takes data out of the raw recv buffer without peeking so we use recv MSG_PEEK instead. Bug #795 */ @@ -853,7 +1058,8 @@ int Curl_ossl_check_cxn(struct connectdata *conn) /* Selects an OpenSSL crypto engine */ -CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine) +static CURLcode Curl_ossl_set_engine(struct Curl_easy *data, + const char *engine) { #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) ENGINE *e; @@ -898,7 +1104,7 @@ CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine) /* Sets engine as default for all SSL operations */ -CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) +static CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -920,7 +1126,7 @@ CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) /* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) +static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) { struct curl_slist *list = NULL; #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) @@ -943,23 +1149,23 @@ struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) static void ossl_close(struct ssl_connect_data *connssl) { - if(connssl->handle) { - (void)SSL_shutdown(connssl->handle); - SSL_set_connect_state(connssl->handle); + if(BACKEND->handle) { + (void)SSL_shutdown(BACKEND->handle); + SSL_set_connect_state(BACKEND->handle); - SSL_free(connssl->handle); - connssl->handle = NULL; + SSL_free(BACKEND->handle); + BACKEND->handle = NULL; } - if(connssl->ctx) { - SSL_CTX_free(connssl->ctx); - connssl->ctx = NULL; + if(BACKEND->ctx) { + SSL_CTX_free(BACKEND->ctx); + BACKEND->ctx = NULL; } } /* * This function is called when an SSL connection is closed. */ -void Curl_ossl_close(struct connectdata *conn, int sockindex) +static void Curl_ossl_close(struct connectdata *conn, int sockindex) { ossl_close(&conn->ssl[sockindex]); ossl_close(&conn->proxy_ssl[sockindex]); @@ -969,7 +1175,7 @@ void Curl_ossl_close(struct connectdata *conn, int sockindex) * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ -int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) +static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -988,9 +1194,9 @@ 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(connssl->handle); + (void)SSL_shutdown(BACKEND->handle); - if(connssl->handle) { + if(BACKEND->handle) { buffsize = (int)sizeof(buf); while(!done) { int what = SOCKET_READABLE(conn->sock[sockindex], @@ -1000,9 +1206,8 @@ 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(conn->ssl[sockindex].handle, buf, - buffsize); - err = SSL_get_error(conn->ssl[sockindex].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 */ @@ -1047,7 +1252,7 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) if(data->set.verbose) { #ifdef HAVE_SSL_GET_SHUTDOWN - switch(SSL_get_shutdown(connssl->handle)) { + switch(SSL_get_shutdown(BACKEND->handle)) { case SSL_SENT_SHUTDOWN: infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); break; @@ -1062,13 +1267,13 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) #endif } - SSL_free(connssl->handle); - connssl->handle = NULL; + SSL_free(BACKEND->handle); + BACKEND->handle = NULL; } return retval; } -void Curl_ossl_session_free(void *ptr) +static void Curl_ossl_session_free(void *ptr) { /* free the ID */ SSL_SESSION_free(ptr); @@ -1078,7 +1283,7 @@ void Curl_ossl_session_free(void *ptr) * This function is called when the 'data' struct is going away. Close * down everything and free all resources! */ -void Curl_ossl_close_all(struct Curl_easy *data) +static void Curl_ossl_close_all(struct Curl_easy *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -1170,7 +1375,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) numalts = sk_GENERAL_NAME_num(altnames); /* loop through all alternatives - until a dnsmatch */ - for(i=0; (i < numalts) && !dnsmatched; i++) { + for(i = 0; (i < numalts) && !dnsmatched; i++) { /* get a handle to alternative name number i */ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); @@ -1239,7 +1444,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) else { /* we have to look to the last occurrence of a commonName in the distinguished one to get the most significant one. */ - int j, i=-1; + int j, i = -1; /* The following is done because of a bug in 0.9.6b */ @@ -1248,14 +1453,14 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) X509_NAME *name = X509_get_subject_name(server_cert); if(name) - while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0) - i=j; + while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) + i = j; /* we have the name entry and we will now convert this to a string that we can use for comparison. Doing this we support BMPstring, UTF8 etc. */ - if(i>=0) { + if(i >= 0) { ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); @@ -1268,7 +1473,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { j = ASN1_STRING_length(tmp); if(j >= 0) { - peer_CN = OPENSSL_malloc(j+1); + peer_CN = OPENSSL_malloc(j + 1); if(peer_CN) { memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j); peer_CN[j] = '\0'; @@ -1291,7 +1496,8 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) peer_CN = NULL; else { /* convert peer_CN from UTF8 */ - CURLcode rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN)); + CURLcode rc = Curl_convert_from_utf8(data, (char *)peer_CN, + strlen((char *)peer_CN)); /* Curl_convert_from_utf8 calls failf if unsuccessful */ if(rc) { OPENSSL_free(peer_CN); @@ -1337,7 +1543,7 @@ static CURLcode verifystatus(struct connectdata *conn, X509_STORE *st = NULL; STACK_OF(X509) *ch = NULL; - long len = SSL_get_tlsext_status_ocsp_resp(connssl->handle, &p); + long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &p); if(!p) { failf(data, "No OCSP response received"); @@ -1367,8 +1573,8 @@ static CURLcode verifystatus(struct connectdata *conn, goto end; } - ch = SSL_get_peer_cert_chain(connssl->handle); - st = SSL_CTX_get_cert_store(connssl->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) && \ @@ -1759,7 +1965,7 @@ set_ssl_version_min_max(long *ctx_options, struct connectdata *conn, #ifdef TLS1_3_VERSION { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION); *ctx_options |= SSL_OP_NO_TLSv1_2; } #else @@ -1767,6 +1973,7 @@ set_ssl_version_min_max(long *ctx_options, struct connectdata *conn, failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); return CURLE_NOT_BUILT_IN; #endif + /* FALLTHROUGH */ case CURL_SSLVERSION_TLSv1_2: #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1_1; @@ -1909,25 +2116,25 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } - if(connssl->ctx) - SSL_CTX_free(connssl->ctx); - connssl->ctx = SSL_CTX_new(req_method); + if(BACKEND->ctx) + SSL_CTX_free(BACKEND->ctx); + BACKEND->ctx = SSL_CTX_new(req_method); - if(!connssl->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(connssl->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(connssl->ctx, ssl_tls_trace); - SSL_CTX_set_msg_callback_arg(connssl->ctx, conn); + SSL_CTX_set_msg_callback(BACKEND->ctx, ssl_tls_trace); + SSL_CTX_set_msg_callback_arg(BACKEND->ctx, conn); } #endif @@ -2044,11 +2251,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } - SSL_CTX_set_options(connssl->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(connssl->ctx, select_next_proto_cb, conn); + SSL_CTX_set_next_proto_select_cb(BACKEND->ctx, select_next_proto_cb, conn); #endif #ifdef HAS_ALPN @@ -2057,7 +2264,8 @@ 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) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2 && + (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, @@ -2075,12 +2283,12 @@ 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(connssl->ctx, protocols, cur); + SSL_CTX_set_alpn_protos(BACKEND->ctx, protocols, cur); } #endif if(ssl_cert || ssl_cert_type) { - if(!cert_stuff(conn, connssl->ctx, 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))) { /* failf() is already done in cert_stuff() */ @@ -2091,11 +2299,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) ciphers = SSL_CONN_CONFIG(cipher_list); if(!ciphers) ciphers = (char *)DEFAULT_CIPHER_SELECTION; - if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) { - failf(data, "failed setting cipher list: %s", ciphers); - return CURLE_SSL_CIPHER; + if(ciphers) { + if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s\n", ciphers); } - infof(data, "Cipher selection: %s\n", ciphers); #ifdef USE_TLS_SRP if(ssl_authtype == CURL_TLSAUTH_SRP) { @@ -2103,18 +2313,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(connssl->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(connssl->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(connssl->ctx, "SRP")) { + if(!SSL_CTX_set_cipher_list(BACKEND->ctx, "SRP")) { failf(data, "failed setting SRP cipher list"); return CURLE_SSL_CIPHER; } @@ -2125,7 +2335,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) 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(connssl->ctx, ssl_cafile, ssl_capath)) { + if(!SSL_CTX_load_verify_locations(BACKEND->ctx, ssl_cafile, ssl_capath)) { if(verifypeer) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" @@ -2153,14 +2363,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) else if(verifypeer) { /* verfying the peer without any CA certificates won't work so use openssl's built in default as fallback */ - SSL_CTX_set_default_verify_paths(connssl->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(connssl->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)) ) { @@ -2169,7 +2379,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(connssl->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); @@ -2184,7 +2394,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) */ #if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) if(verifypeer) { - X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), + X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), X509_V_FLAG_TRUSTED_FIRST); } #endif @@ -2193,12 +2403,19 @@ 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(connssl->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) { + SSL_CTX_set_keylog_callback(connssl->ctx, ossl_keylog_callback); + } +#endif + /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { - result = (*data->set.ssl.fsslctx)(data, connssl->ctx, + result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, data->set.ssl.fsslctxp); if(result) { failf(data, "error signaled by ssl ctx callback"); @@ -2207,10 +2424,10 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } /* Lets make an SSL structure */ - if(connssl->handle) - SSL_free(connssl->handle); - connssl->handle = SSL_new(connssl->ctx); - if(!connssl->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; } @@ -2218,19 +2435,19 @@ 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(connssl->handle, TLSEXT_STATUSTYPE_ocsp); + SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp); #endif - SSL_set_connect_state(connssl->handle); + SSL_set_connect_state(BACKEND->handle); - connssl->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(connssl->handle, hostname)) + !SSL_set_tlsext_host_name(BACKEND->handle, hostname)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); #endif @@ -2242,7 +2459,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int 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(connssl->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, @@ -2257,13 +2474,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(conn->proxy_ssl[sockindex].use) { BIO *const bio = BIO_new(BIO_f_ssl()); + SSL *handle = conn->proxy_ssl[sockindex].backend->handle; DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); - DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL); + DEBUGASSERT(handle != NULL); DEBUGASSERT(bio != NULL); - BIO_set_ssl(bio, conn->proxy_ssl[sockindex].handle, FALSE); - SSL_set_bio(connssl->handle, bio, bio); + BIO_set_ssl(bio, handle, FALSE); + SSL_set_bio(BACKEND->handle, bio, bio); } - else if(!SSL_set_fd(connssl->handle, (int)sockfd)) { + else 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))); @@ -2288,13 +2506,18 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) ERR_clear_error(); - err = SSL_connect(connssl->handle); + 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); +#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(connssl->handle, err); + int detail = SSL_get_error(BACKEND->handle, err); if(SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; @@ -2328,7 +2551,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { result = CURLE_SSL_CACERT; - lerr = SSL_get_verify_result(connssl->handle); + lerr = SSL_get_verify_result(BACKEND->handle); if(lerr != X509_V_OK) { *certverifyresult = lerr; snprintf(error_buffer, sizeof(error_buffer), @@ -2372,8 +2595,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(connssl->handle), - SSL_get_cipher(connssl->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 @@ -2382,7 +2605,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(connssl->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); @@ -2427,7 +2650,7 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) do { \ long info_len = BIO_get_mem_data(mem, &ptr); \ Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ - if(1!=BIO_reset(mem)) \ + if(1 != BIO_reset(mem)) \ break; \ } WHILE_FALSE @@ -2475,12 +2698,12 @@ static int X509V3_ext(struct Curl_easy *data, /* no extensions, bail out */ return 1; - for(i=0; i < (int)sk_X509_EXTENSION_num(exts); i++) { + for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { ASN1_OBJECT *obj; X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); BUF_MEM *biomem; char buf[512]; - char *ptr=buf; + char *ptr = buf; char namebuf[128]; BIO *bio_out = BIO_new(BIO_s_mem()); @@ -2497,16 +2720,16 @@ static int X509V3_ext(struct Curl_easy *data, BIO_get_mem_ptr(bio_out, &biomem); for(j = 0; j < (size_t)biomem->length; j++) { - const char *sep=""; + const char *sep = ""; if(biomem->data[j] == '\n') { - sep=", "; + sep = ", "; j++; /* skip the newline */ }; while((j<(size_t)biomem->length) && (biomem->data[j] == ' ')) j++; if(j<(size_t)biomem->length) - ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, - biomem->data[j]); + ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, + biomem->data[j]); } Curl_ssl_push_certinfo(data, certnum, namebuf, buf); @@ -2528,7 +2751,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, int numcerts; BIO *mem; - sk = SSL_get_peer_cert_chain(connssl->handle); + sk = SSL_get_peer_cert_chain(BACKEND->handle); if(!sk) { return CURLE_OUT_OF_MEMORY; } @@ -2545,10 +2768,10 @@ static CURLcode get_cert_chain(struct connectdata *conn, for(i = 0; i < numcerts; i++) { ASN1_INTEGER *num; X509 *x = sk_X509_value(sk, i); - EVP_PKEY *pubkey=NULL; + EVP_PKEY *pubkey = NULL; int j; char *ptr; - CONST_ASN1_BIT_STRING ASN1_BIT_STRING *psig = NULL; + const ASN1_BIT_STRING *psig = NULL; X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); push_certinfo("Subject", i); @@ -2818,8 +3041,8 @@ static CURLcode servercert(struct connectdata *conn, /* we've been asked to gather certificate info! */ (void)get_cert_chain(conn, connssl); - connssl->server_cert = SSL_get_peer_certificate(connssl->handle); - if(!connssl->server_cert) { + BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle); + if(!BACKEND->server_cert) { BIO_free(mem); if(!strict) return CURLE_OK; @@ -2830,16 +3053,16 @@ static CURLcode servercert(struct connectdata *conn, infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); - rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert), + rc = x509_name_oneline(X509_get_subject_name(BACKEND->server_cert), buffer, sizeof(buffer)); infof(data, " subject: %s\n", rc?"[NONE]":buffer); - ASN1_TIME_print(mem, X509_get0_notBefore(connssl->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); rc = BIO_reset(mem); - ASN1_TIME_print(mem, X509_get0_notAfter(connssl->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); rc = BIO_reset(mem); @@ -2847,15 +3070,15 @@ static CURLcode servercert(struct connectdata *conn, BIO_free(mem); if(SSL_CONN_CONFIG(verifyhost)) { - result = verifyhost(conn, connssl->server_cert); + result = verifyhost(conn, BACKEND->server_cert); if(result) { - X509_free(connssl->server_cert); - connssl->server_cert = NULL; + X509_free(BACKEND->server_cert); + BACKEND->server_cert = NULL; return result; } } - rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert), + rc = x509_name_oneline(X509_get_issuer_name(BACKEND->server_cert), buffer, sizeof(buffer)); if(rc) { if(strict) @@ -2875,8 +3098,8 @@ static CURLcode servercert(struct connectdata *conn, if(strict) failf(data, "SSL: Unable to open issuer cert (%s)", SSL_SET_OPTION(issuercert)); - X509_free(connssl->server_cert); - connssl->server_cert = NULL; + X509_free(BACKEND->server_cert); + BACKEND->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } @@ -2885,7 +3108,7 @@ static CURLcode servercert(struct connectdata *conn, if(strict) failf(data, "SSL: Unable to read issuer cert (%s)", SSL_SET_OPTION(issuercert)); - X509_free(connssl->server_cert); + X509_free(BACKEND->server_cert); X509_free(issuer); fclose(fp); return CURLE_SSL_ISSUER_ERROR; @@ -2893,13 +3116,13 @@ static CURLcode servercert(struct connectdata *conn, fclose(fp); - if(X509_check_issued(issuer, connssl->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)); - X509_free(connssl->server_cert); + X509_free(BACKEND->server_cert); X509_free(issuer); - connssl->server_cert = NULL; + BACKEND->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } @@ -2908,7 +3131,7 @@ static CURLcode servercert(struct connectdata *conn, X509_free(issuer); } - lerr = *certverifyresult = SSL_get_verify_result(connssl->handle); + lerr = *certverifyresult = SSL_get_verify_result(BACKEND->handle); if(*certverifyresult != X509_V_OK) { if(SSL_CONN_CONFIG(verifypeer)) { @@ -2933,8 +3156,8 @@ static CURLcode servercert(struct connectdata *conn, if(SSL_CONN_CONFIG(verifystatus)) { result = verifystatus(conn, connssl); if(result) { - X509_free(connssl->server_cert); - connssl->server_cert = NULL; + X509_free(BACKEND->server_cert); + BACKEND->server_cert = NULL; return result; } } @@ -2947,13 +3170,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, connssl->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(connssl->server_cert); - connssl->server_cert = NULL; + X509_free(BACKEND->server_cert); + BACKEND->server_cert = NULL; connssl->connecting_state = ssl_connect_done; return result; @@ -2972,7 +3195,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; - our_ssl_sessionid = SSL_get1_session(connssl->handle); + our_ssl_sessionid = SSL_get1_session(BACKEND->handle); /* SSL_get1_session() will increment the reference count and the session will stay in memory until explicitly freed with SSL_SESSION_free(3), @@ -3077,9 +3300,9 @@ static CURLcode ossl_connect_common(struct connectdata *conn, if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { - curl_socket_t writefd = ssl_connect_2_writing== + curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading== + curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, @@ -3137,14 +3360,14 @@ static CURLcode ossl_connect_common(struct connectdata *conn, return CURLE_OK; } -CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +static CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) { return ossl_connect_common(conn, sockindex, TRUE, done); } -CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex) +static CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; @@ -3158,17 +3381,22 @@ CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex) return CURLE_OK; } -bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex) +static bool Curl_ossl_data_pending(const struct connectdata *conn, + int connindex) { - if(conn->ssl[connindex].handle) + const struct ssl_connect_data *connssl = &conn->ssl[connindex]; + const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex]; + if(BACKEND->handle) /* SSL is in use */ - return (0 != SSL_pending(conn->ssl[connindex].handle) || - (conn->proxy_ssl[connindex].handle && - 0 != SSL_pending(conn->proxy_ssl[connindex].handle))) ? + return (0 != SSL_pending(BACKEND->handle) || + (proxyssl->backend->handle && + 0 != SSL_pending(proxyssl->backend->handle))) ? TRUE : FALSE; return FALSE; } +static size_t Curl_ossl_version(char *buffer, size_t size); + static ssize_t ossl_send(struct connectdata *conn, int sockindex, const void *mem, @@ -3182,14 +3410,15 @@ static ssize_t ossl_send(struct connectdata *conn, unsigned long sslerror; int memlen; int rc; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ERR_clear_error(); memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen); + rc = SSL_write(BACKEND->handle, mem, memlen); if(rc <= 0) { - err = SSL_get_error(conn->ssl[sockindex].handle, rc); + err = SSL_get_error(BACKEND->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: @@ -3243,14 +3472,15 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ unsigned long sslerror; ssize_t nread; int buffsize; + struct ssl_connect_data *connssl = &conn->ssl[num]; ERR_clear_error(); buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize); + nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); if(nread <= 0) { /* failed SSL_read */ - int err = SSL_get_error(conn->ssl[num].handle, (int)nread); + int err = SSL_get_error(BACKEND->handle, (int)nread); switch(err) { case SSL_ERROR_NONE: /* this is not an error */ @@ -3282,7 +3512,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ return nread; } -size_t Curl_ossl_version(char *buffer, size_t size) +static size_t Curl_ossl_version(char *buffer, size_t size) { #ifdef OPENSSL_IS_BORINGSSL return snprintf(buffer, size, OSSL_PACKAGE); @@ -3291,9 +3521,9 @@ size_t Curl_ossl_version(char *buffer, size_t size) unsigned long ssleay_value; sub[2]='\0'; sub[1]='\0'; - ssleay_value=OpenSSL_version_num(); + ssleay_value = OpenSSL_version_num(); if(ssleay_value < 0x906000) { - ssleay_value=SSLEAY_VERSION_NUMBER; + ssleay_value = SSLEAY_VERSION_NUMBER; sub[0]='\0'; } else { @@ -3322,8 +3552,8 @@ size_t Curl_ossl_version(char *buffer, size_t size) } /* can be called with data == NULL */ -CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, - size_t length) +static CURLcode Curl_ossl_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) { int rc; if(data) { @@ -3339,23 +3569,24 @@ CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT); } -void Curl_ossl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum /* output */, - size_t unused) +static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum /* output */, + size_t unused) { MD5_CTX MD5pw; (void)unused; MD5_Init(&MD5pw); MD5_Update(&MD5pw, tmp, tmplen); MD5_Final(md5sum, &MD5pw); + return CURLE_OK; } #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) -void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum /* output */, - size_t unused) +static void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) { SHA256_CTX SHA256pw; (void)unused; @@ -3365,7 +3596,7 @@ void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ } #endif -bool Curl_ossl_cert_status_request(void) +static bool Curl_ossl_cert_status_request(void) { #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) @@ -3374,4 +3605,50 @@ bool Curl_ossl_cert_status_request(void) return FALSE; #endif } + +static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info) +{ + /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ + return info == CURLINFO_TLS_SESSION ? + (void *)BACKEND->ctx : (void *)BACKEND->handle; +} + +const struct Curl_ssl Curl_ssl_openssl = { + { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */ + + 1, /* have_ca_path */ + 1, /* have_certinfo */ + 1, /* have_pinnedpubkey */ + 1, /* have_ssl_ctx */ + 1, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_ossl_init, /* init */ + Curl_ossl_cleanup, /* cleanup */ + Curl_ossl_version, /* version */ + Curl_ossl_check_cxn, /* check_cxn */ + Curl_ossl_shutdown, /* shutdown */ + Curl_ossl_data_pending, /* data_pending */ + Curl_ossl_random, /* random */ + Curl_ossl_cert_status_request, /* cert_status_request */ + Curl_ossl_connect, /* connect */ + Curl_ossl_connect_nonblocking, /* connect_nonblocking */ + Curl_ossl_get_internals, /* get_internals */ + Curl_ossl_close, /* close */ + Curl_ossl_close_all, /* close_all */ + Curl_ossl_session_free, /* session_free */ + Curl_ossl_set_engine, /* set_engine */ + Curl_ossl_set_engine_default, /* set_engine_default */ + Curl_ossl_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_ossl_md5sum, /* md5sum */ +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) + Curl_ossl_sha256sum /* sha256sum */ +#else + NULL /* sha256sum */ +#endif +}; + #endif /* USE_OPENSSL */ diff --git a/lib/vtls/openssl.h b/lib/vtls/openssl.h index b9648d5..114dc4b 100644 --- a/lib/vtls/openssl.h +++ b/lib/vtls/openssl.h @@ -31,96 +31,7 @@ #include "urldata.h" -CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); - -/* close a SSL connection */ -void Curl_ossl_close(struct connectdata *conn, int sockindex); - -/* tell OpenSSL to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_ossl_close_all(struct Curl_easy *data); - -/* Sets an OpenSSL engine */ -CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine); - -/* function provided for the generic SSL-layer, called when a session id - should be freed */ -void Curl_ossl_session_free(void *ptr); - -/* Sets engine as default for all SSL operations */ -CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data); - -/* Build list of OpenSSL engines */ -struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data); - -int Curl_ossl_init(void); -void Curl_ossl_cleanup(void); - -size_t Curl_ossl_version(char *buffer, size_t size); -int Curl_ossl_check_cxn(struct connectdata *cxn); -int Curl_ossl_shutdown(struct connectdata *conn, int sockindex); -bool Curl_ossl_data_pending(const struct connectdata *conn, - int connindex); - -/* return 0 if a find random is filled in */ -CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, - size_t length); -void Curl_ossl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum /* output */, - size_t unused); -void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum /* output */, - size_t unused); - -bool Curl_ossl_cert_status_request(void); - -/* Support HTTPS-proxy */ -#define HTTPS_PROXY_SUPPORT 1 - -/* Set the API backend definition to OpenSSL */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_OPENSSL - -/* this backend supports the CAPATH option */ -#define have_curlssl_ca_path 1 - -/* this backend supports CURLOPT_CERTINFO */ -#define have_curlssl_certinfo 1 - -/* this backend supports CURLOPT_SSL_CTX_* */ -#define have_curlssl_ssl_ctx 1 - -/* this backend supports CURLOPT_PINNEDPUBLICKEY */ -#define have_curlssl_pinnedpubkey 1 - -/* API setup for OpenSSL */ -#define curlssl_init Curl_ossl_init -#define curlssl_cleanup Curl_ossl_cleanup -#define curlssl_connect Curl_ossl_connect -#define curlssl_connect_nonblocking Curl_ossl_connect_nonblocking -#define curlssl_session_free(x) Curl_ossl_session_free(x) -#define curlssl_close_all Curl_ossl_close_all -#define curlssl_close Curl_ossl_close -#define curlssl_shutdown(x,y) Curl_ossl_shutdown(x,y) -#define curlssl_set_engine(x,y) Curl_ossl_set_engine(x,y) -#define curlssl_set_engine_default(x) Curl_ossl_set_engine_default(x) -#define curlssl_engines_list(x) Curl_ossl_engines_list(x) -#define curlssl_version Curl_ossl_version -#define curlssl_check_cxn Curl_ossl_check_cxn -#define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y) -#define curlssl_random(x,y,z) Curl_ossl_random(x,y,z) -#define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d) -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) -#define curlssl_sha256sum(a,b,c,d) Curl_ossl_sha256sum(a,b,c,d) -#endif -#define curlssl_cert_status_request() Curl_ossl_cert_status_request() - -#define DEFAULT_CIPHER_SELECTION \ - "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" +extern const struct Curl_ssl Curl_ssl_openssl; #endif /* USE_OPENSSL */ #endif /* HEADER_CURL_SSLUSE_H */ diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c index 669091c..fc0644f 100644 --- a/lib/vtls/polarssl.c +++ b/lib/vtls/polarssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. * Copyright (C) 2010 - 2011, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which @@ -30,7 +30,6 @@ #include "curl_setup.h" #ifdef USE_POLARSSL - #include #include #include @@ -70,6 +69,19 @@ #define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) +struct ssl_backend_data { + ctr_drbg_context ctr_drbg; + entropy_context entropy; + ssl_context ssl; + int server_fd; + x509_crt cacert; + x509_crt clicert; + x509_crl crl; + rsa_context rsa; +}; + +#define BACKEND connssl->backend + /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) #define THREADING_SUPPORT @@ -197,8 +209,8 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) return result; } - ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver); - ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver); + ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver); + ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver); return result; } @@ -215,7 +227,7 @@ polarssl_connect_step1(struct connectdata *conn, const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; int ret = -1; char errorbuf[128]; - errorbuf[0]=0; + errorbuf[0] = 0; /* PolarSSL only supports SSLv3 and TLSv1 */ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { @@ -226,16 +238,16 @@ polarssl_connect_step1(struct connectdata *conn, #ifdef THREADING_SUPPORT entropy_init_mutex(&entropy); - if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy, + if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func_mutex, &entropy, NULL, 0)) != 0) { error_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", -ret, errorbuf); } #else - entropy_init(&connssl->entropy); + entropy_init(&BACKEND->entropy); - if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy, + if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func, &BACKEND->entropy, NULL, 0)) != 0) { error_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", @@ -244,10 +256,10 @@ polarssl_connect_step1(struct connectdata *conn, #endif /* THREADING_SUPPORT */ /* Load the trusted CA */ - memset(&connssl->cacert, 0, sizeof(x509_crt)); + memset(&BACKEND->cacert, 0, sizeof(x509_crt)); if(SSL_CONN_CONFIG(CAfile)) { - ret = x509_crt_parse_file(&connssl->cacert, + ret = x509_crt_parse_file(&BACKEND->cacert, SSL_CONN_CONFIG(CAfile)); if(ret<0) { @@ -261,7 +273,7 @@ polarssl_connect_step1(struct connectdata *conn, } if(capath) { - ret = x509_crt_parse_path(&connssl->cacert, capath); + ret = x509_crt_parse_path(&BACKEND->cacert, capath); if(ret<0) { error_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -274,10 +286,10 @@ polarssl_connect_step1(struct connectdata *conn, } /* Load the client certificate */ - memset(&connssl->clicert, 0, sizeof(x509_crt)); + memset(&BACKEND->clicert, 0, sizeof(x509_crt)); if(SSL_SET_OPTION(cert)) { - ret = x509_crt_parse_file(&connssl->clicert, + ret = x509_crt_parse_file(&BACKEND->clicert, SSL_SET_OPTION(cert)); if(ret) { @@ -298,9 +310,9 @@ polarssl_connect_step1(struct connectdata *conn, if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA)) ret = POLARSSL_ERR_PK_TYPE_MISMATCH; if(ret == 0) - rsa_copy(&connssl->rsa, pk_rsa(pk)); + rsa_copy(&BACKEND->rsa, pk_rsa(pk)); else - rsa_free(&connssl->rsa); + rsa_free(&BACKEND->rsa); pk_free(&pk); if(ret) { @@ -313,10 +325,10 @@ polarssl_connect_step1(struct connectdata *conn, } /* Load the CRL */ - memset(&connssl->crl, 0, sizeof(x509_crl)); + memset(&BACKEND->crl, 0, sizeof(x509_crl)); if(SSL_SET_OPTION(CRLfile)) { - ret = x509_crl_parse_file(&connssl->crl, + ret = x509_crl_parse_file(&BACKEND->crl, SSL_SET_OPTION(CRLfile)); if(ret) { @@ -330,7 +342,7 @@ polarssl_connect_step1(struct connectdata *conn, infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port); - if(ssl_init(&connssl->ssl)) { + if(ssl_init(&BACKEND->ssl)) { failf(data, "PolarSSL: ssl_init failed"); return CURLE_SSL_CONNECT_ERROR; } @@ -338,13 +350,13 @@ polarssl_connect_step1(struct connectdata *conn, switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1); break; case CURL_SSLVERSION_SSLv3: - ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0); - ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0); infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n"); break; @@ -363,16 +375,16 @@ polarssl_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - ssl_set_endpoint(&connssl->ssl, SSL_IS_CLIENT); - ssl_set_authmode(&connssl->ssl, SSL_VERIFY_OPTIONAL); + ssl_set_endpoint(&BACKEND->ssl, SSL_IS_CLIENT); + ssl_set_authmode(&BACKEND->ssl, SSL_VERIFY_OPTIONAL); - ssl_set_rng(&connssl->ssl, ctr_drbg_random, - &connssl->ctr_drbg); - ssl_set_bio(&connssl->ssl, + ssl_set_rng(&BACKEND->ssl, ctr_drbg_random, + &BACKEND->ctr_drbg); + ssl_set_bio(&BACKEND->ssl, net_recv, &conn->sock[sockindex], net_send, &conn->sock[sockindex]); - ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites()); + ssl_set_ciphersuites(&BACKEND->ssl, ssl_list_ciphersuites()); /* Check if there's a cached ID we can/should use here! */ if(SSL_SET_OPTION(primary.sessionid)) { @@ -380,7 +392,7 @@ polarssl_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { - ret = ssl_set_session(&connssl->ssl, old_session); + ret = ssl_set_session(&BACKEND->ssl, old_session); if(ret) { Curl_ssl_sessionid_unlock(conn); failf(data, "ssl_set_session returned -0x%x", -ret); @@ -391,15 +403,15 @@ polarssl_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_unlock(conn); } - ssl_set_ca_chain(&connssl->ssl, - &connssl->cacert, - &connssl->crl, + ssl_set_ca_chain(&BACKEND->ssl, + &BACKEND->cacert, + &BACKEND->crl, hostname); - ssl_set_own_cert_rsa(&connssl->ssl, - &connssl->clicert, &connssl->rsa); + ssl_set_own_cert_rsa(&BACKEND->ssl, + &BACKEND->clicert, &BACKEND->rsa); - if(ssl_set_hostname(&connssl->ssl, hostname)) { + if(ssl_set_hostname(&BACKEND->ssl, hostname)) { /* 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. */ @@ -424,12 +436,12 @@ polarssl_connect_step1(struct connectdata *conn, protocols[cur] = NULL; - ssl_set_alpn_protocols(&connssl->ssl, protocols); + ssl_set_alpn_protocols(&BACKEND->ssl, protocols); } #endif #ifdef POLARSSL_DEBUG - ssl_set_dbg(&connssl->ssl, polarssl_debug, data); + ssl_set_dbg(&BACKEND->ssl, polarssl_debug, data); #endif connssl->connecting_state = ssl_connect_2; @@ -456,7 +468,7 @@ polarssl_connect_step2(struct connectdata *conn, conn->recv[sockindex] = polarssl_recv; conn->send[sockindex] = polarssl_send; - ret = ssl_handshake(&connssl->ssl); + ret = ssl_handshake(&BACKEND->ssl); switch(ret) { case 0: @@ -478,9 +490,9 @@ polarssl_connect_step2(struct connectdata *conn, } infof(data, "PolarSSL: Handshake complete, cipher is %s\n", - ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) ); + ssl_get_ciphersuite(&BACKEND->ssl) ); - ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); + ret = ssl_get_verify_result(&BACKEND->ssl); if(ret && SSL_CONN_CONFIG(verifypeer)) { if(ret & BADCERT_EXPIRED) @@ -500,12 +512,12 @@ polarssl_connect_step2(struct connectdata *conn, return CURLE_PEER_FAILED_VERIFICATION; } - if(ssl_get_peer_cert(&(connssl->ssl))) { + if(ssl_get_peer_cert(&(BACKEND->ssl))) { /* If the session was resumed, there will be no peer certs */ memset(buffer, 0, sizeof(buffer)); if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ", - ssl_get_peer_cert(&(connssl->ssl))) != -1) + ssl_get_peer_cert(&(BACKEND->ssl))) != -1) infof(data, "Dumping cert info:\n%s\n", buffer); } @@ -517,7 +529,7 @@ polarssl_connect_step2(struct connectdata *conn, unsigned char pubkey[PUB_DER_MAX_BYTES]; const x509_crt *peercert; - peercert = ssl_get_peer_cert(&connssl->ssl); + peercert = ssl_get_peer_cert(&BACKEND->ssl); if(!peercert || !peercert->raw.p || !peercert->raw.len) { failf(data, "Failed due to missing peer certificate"); @@ -566,7 +578,7 @@ polarssl_connect_step2(struct connectdata *conn, #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { - const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl); + const char *next_protocol = ssl_get_alpn_protocol(&BACKEND->ssl); if(next_protocol != NULL) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); @@ -614,7 +626,7 @@ polarssl_connect_step3(struct connectdata *conn, memset(our_ssl_sessionid, 0, sizeof(ssl_session)); - ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid); + ret = ssl_get_session(&BACKEND->ssl, our_ssl_sessionid); if(ret) { failf(data, "ssl_get_session returned -0x%x", -ret); return CURLE_SSL_CONNECT_ERROR; @@ -645,9 +657,10 @@ static ssize_t polarssl_send(struct connectdata *conn, size_t len, CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; int ret = -1; - ret = ssl_write(&conn->ssl[sockindex].ssl, + ret = ssl_write(&BACKEND->ssl, (unsigned char *)mem, len); if(ret < 0) { @@ -659,13 +672,14 @@ static ssize_t polarssl_send(struct connectdata *conn, return ret; } -void Curl_polarssl_close(struct connectdata *conn, int sockindex) +static void Curl_polarssl_close(struct connectdata *conn, int sockindex) { - rsa_free(&conn->ssl[sockindex].rsa); - x509_crt_free(&conn->ssl[sockindex].clicert); - x509_crt_free(&conn->ssl[sockindex].cacert); - x509_crl_free(&conn->ssl[sockindex].crl); - ssl_free(&conn->ssl[sockindex].ssl); + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + rsa_free(&BACKEND->rsa); + x509_crt_free(&BACKEND->clicert); + x509_crt_free(&BACKEND->cacert); + x509_crl_free(&BACKEND->crl); + ssl_free(&BACKEND->ssl); } static ssize_t polarssl_recv(struct connectdata *conn, @@ -674,11 +688,12 @@ static ssize_t polarssl_recv(struct connectdata *conn, size_t buffersize, CURLcode *curlcode) { + struct ssl_connect_data *connssl = &conn->ssl[num]; int ret = -1; ssize_t len = -1; memset(buf, 0, buffersize); - ret = ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, buffersize); + ret = ssl_read(&BACKEND->ssl, (unsigned char *)buf, buffersize); if(ret <= 0) { if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) @@ -694,7 +709,7 @@ static ssize_t polarssl_recv(struct connectdata *conn, return len; } -void Curl_polarssl_session_free(void *ptr) +static void Curl_polarssl_session_free(void *ptr) { ssl_session_free(ptr); free(ptr); @@ -703,7 +718,7 @@ void Curl_polarssl_session_free(void *ptr) /* 1.3.10 was the first rebranded version. All new releases (in 1.3 branch and higher) will be mbed TLS branded.. */ -size_t Curl_polarssl_version(char *buffer, size_t size) +static size_t Curl_polarssl_version(char *buffer, size_t size) { unsigned int version = version_get_number(); return snprintf(buffer, size, "%s/%d.%d.%d", @@ -762,9 +777,9 @@ polarssl_connect_common(struct connectdata *conn, if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { - curl_socket_t writefd = ssl_connect_2_writing== + curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading== + curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, @@ -825,18 +840,14 @@ polarssl_connect_common(struct connectdata *conn, return CURLE_OK; } -CURLcode -Curl_polarssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +static CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { return polarssl_connect_common(conn, sockindex, TRUE, done); } -CURLcode -Curl_polarssl_connect(struct connectdata *conn, - int sockindex) +static CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; @@ -854,20 +865,73 @@ Curl_polarssl_connect(struct connectdata *conn, * return 0 error initializing SSL * return 1 SSL initialized successfully */ -int Curl_polarssl_init(void) +static int Curl_polarssl_init(void) { return Curl_polarsslthreadlock_thread_setup(); } -void Curl_polarssl_cleanup(void) +static void Curl_polarssl_cleanup(void) { (void)Curl_polarsslthreadlock_thread_cleanup(); } +static bool Curl_polarssl_data_pending(const struct connectdata *conn, + int sockindex) +{ + const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + return ssl_get_bytes_avail(&BACKEND->ssl) != 0; +} + +static void Curl_polarssl_sha256sum(const unsigned char *input, + size_t inputlen, + unsigned char *sha256sum, + size_t sha256len UNUSED_PARAM) +{ + (void)sha256len; + sha256(input, inputlen, sha256sum, 0); +} -int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex) +static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) { - return ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0; + (void)info; + return &BACKEND->ssl; } +const struct Curl_ssl Curl_ssl_polarssl = { + { CURLSSLBACKEND_POLARSSL, "polarssl" }, /* info */ + + 1, /* have_ca_path */ + 0, /* have_certinfo */ + 1, /* have_pinnedpubkey */ + 0, /* have_ssl_ctx */ + 0, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_polarssl_init, /* init */ + Curl_polarssl_cleanup, /* cleanup */ + Curl_polarssl_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_none_shutdown, /* shutdown */ + Curl_polarssl_data_pending, /* data_pending */ + /* This might cause libcurl to use a weeker random! + * TODO: use Polarssl's CTR-DRBG or HMAC-DRBG + */ + Curl_none_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + Curl_polarssl_connect, /* connect */ + Curl_polarssl_connect_nonblocking, /* connect_nonblocking */ + Curl_polarssl_get_internals, /* get_internals */ + Curl_polarssl_close, /* close */ + Curl_none_close_all, /* close_all */ + Curl_polarssl_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_none_md5sum, /* md5sum */ + Curl_polarssl_sha256sum /* sha256sum */ +}; + #endif /* USE_POLARSSL */ diff --git a/lib/vtls/polarssl.h b/lib/vtls/polarssl.h index 47af7b4..23c3636 100644 --- a/lib/vtls/polarssl.h +++ b/lib/vtls/polarssl.h @@ -26,57 +26,7 @@ #ifdef USE_POLARSSL -#include - -/* Called on first use PolarSSL, setup threading if supported */ -int Curl_polarssl_init(void); -void Curl_polarssl_cleanup(void); -int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex); - - -CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex); - -CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); - - /* close a SSL connection */ -void Curl_polarssl_close(struct connectdata *conn, int sockindex); - -void Curl_polarssl_session_free(void *ptr); -size_t Curl_polarssl_version(char *buffer, size_t size); -int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); - -/* Set the API backend definition to PolarSSL */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_POLARSSL - -/* this backend supports the CAPATH option */ -#define have_curlssl_ca_path 1 - -/* this backends supports CURLOPT_PINNEDPUBLICKEY */ -#define have_curlssl_pinnedpubkey 1 - -/* API setup for PolarSSL */ -#define curlssl_init() Curl_polarssl_init() -#define curlssl_cleanup() Curl_polarssl_cleanup() -#define curlssl_connect Curl_polarssl_connect -#define curlssl_connect_nonblocking Curl_polarssl_connect_nonblocking -#define curlssl_session_free(x) Curl_polarssl_session_free(x) -#define curlssl_close_all(x) ((void)x) -#define curlssl_close Curl_polarssl_close -#define curlssl_shutdown(x,y) 0 -#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) -#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) -#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) -#define curlssl_version Curl_polarssl_version -#define curlssl_check_cxn(x) ((void)x, -1) -#define curlssl_data_pending(x,y) Curl_polarssl_data_pending(x, y) -#define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0) - -/* This might cause libcurl to use a weeker random! - TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that -*/ -#define curlssl_random(x,y,z) ((void)x, (void)y, (void)z, CURLE_NOT_BUILT_IN) +extern const struct Curl_ssl Curl_ssl_polarssl; #endif /* USE_POLARSSL */ #endif /* HEADER_CURL_POLARSSL_H */ diff --git a/lib/vtls/polarssl_threadlock.c b/lib/vtls/polarssl_threadlock.c index b1eb7b7..dd5fbd7 100644 --- a/lib/vtls/polarssl_threadlock.c +++ b/lib/vtls/polarssl_threadlock.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013-2016, Daniel Stenberg, , et al. + * Copyright (C) 2013-2017, Daniel Stenberg, , et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which @@ -114,7 +114,7 @@ int Curl_polarsslthreadlock_lock_function(int n) } #elif defined(HAVE_PROCESS_H) if(n < NUMT) { - ret = (WaitForSingleObject(mutex_buf[n], INFINITE)==WAIT_FAILED?1:0); + ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0); if(ret) { DEBUGF(fprintf(stderr, "Error: polarsslthreadlock_lock_function failed\n")); diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 9460301..9ca1431 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -46,6 +46,8 @@ # error "Can't compile SCHANNEL support without SSPI." #endif +#include +#include #include "curl_sspi.h" #include "schannel.h" #include "vtls.h" @@ -74,11 +76,92 @@ # define HAS_ALPN 1 #endif +#ifndef UNISP_NAME_A +#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider" +#endif + +#ifndef UNISP_NAME_W +#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider" +#endif + +#ifndef UNISP_NAME +#ifdef UNICODE +#define UNISP_NAME UNISP_NAME_W +#else +#define UNISP_NAME UNISP_NAME_A +#endif +#endif + +#ifndef SP_PROT_SSL2_CLIENT +#define SP_PROT_SSL2_CLIENT 0x00000008 +#endif + +#ifndef SP_PROT_SSL3_CLIENT +#define SP_PROT_SSL3_CLIENT 0x00000008 +#endif + +#ifndef SP_PROT_TLS1_CLIENT +#define SP_PROT_TLS1_CLIENT 0x00000080 +#endif + +#ifndef SP_PROT_TLS1_0_CLIENT +#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT +#endif + +#ifndef SP_PROT_TLS1_1_CLIENT +#define SP_PROT_TLS1_1_CLIENT 0x00000200 +#endif + +#ifndef SP_PROT_TLS1_2_CLIENT +#define SP_PROT_TLS1_2_CLIENT 0x00000800 +#endif + +#ifndef SECBUFFER_ALERT +#define SECBUFFER_ALERT 17 +#endif + +/* Both schannel buffer sizes must be > 0 */ +#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 +#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 + /* Uncomment to force verbose output * #define infof(x, y, ...) printf(y, __VA_ARGS__) * #define failf(x, y, ...) printf(y, __VA_ARGS__) */ +/* Structs to store Schannel handles */ +struct curl_schannel_cred { + CredHandle cred_handle; + TimeStamp time_stamp; + int refcount; +}; + +struct curl_schannel_ctxt { + CtxtHandle ctxt_handle; + TimeStamp time_stamp; +}; + +struct ssl_backend_data { + struct curl_schannel_cred *cred; + struct curl_schannel_ctxt *ctxt; + SecPkgContext_StreamSizes stream_sizes; + size_t encdata_length, decdata_length; + size_t encdata_offset, decdata_offset; + unsigned char *encdata_buffer, *decdata_buffer; + /* encdata_is_incomplete: if encdata contains only a partial record that + can't be decrypted without another Curl_read_plain (that is, status is + SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes + more bytes into encdata then set this back to false. */ + bool encdata_is_incomplete; + unsigned long req_flags, ret_flags; + CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ + bool recv_sspi_close_notify; /* true if connection closed by close_notify */ + bool recv_connection_closed; /* true if connection closed, regardless how */ + bool use_alpn; /* true if ALPN is used for this connection */ +}; + +#define BACKEND connssl->backend + static Curl_recv schannel_recv; static Curl_send schannel_send; @@ -176,33 +259,33 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) #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. */ - connssl->use_alpn = conn->bits.tls_enable_alpn && + 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); #else - connssl->use_alpn = false; + BACKEND->use_alpn = false; #endif - connssl->cred = NULL; + BACKEND->cred = NULL; /* check for an existing re-usable credential handle */ if(SSL_SET_OPTION(primary.sessionid)) { Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) { - connssl->cred = old_cred; + BACKEND->cred = old_cred; infof(data, "schannel: re-using existing credential handle\n"); /* increment the reference counter of the credential/session handle */ - connssl->cred->refcount++; + BACKEND->cred->refcount++; infof(data, "schannel: incremented credential handle refcount = %d\n", - connssl->cred->refcount); + BACKEND->cred->refcount); } Curl_ssl_sessionid_unlock(conn); } - if(!connssl->cred) { + if(!BACKEND->cred) { /* setup Schannel API options */ memset(&schannel_cred, 0, sizeof(schannel_cred)); schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; @@ -272,14 +355,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) } /* allocate memory for the re-usable credential handle */ - connssl->cred = (struct curl_schannel_cred *) + BACKEND->cred = (struct curl_schannel_cred *) malloc(sizeof(struct curl_schannel_cred)); - if(!connssl->cred) { + if(!BACKEND->cred) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } - memset(connssl->cred, 0, sizeof(struct curl_schannel_cred)); - connssl->cred->refcount = 1; + memset(BACKEND->cred, 0, sizeof(struct curl_schannel_cred)); + BACKEND->cred->refcount = 1; /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */ @@ -287,8 +370,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL, - &connssl->cred->cred_handle, - &connssl->cred->time_stamp); + &BACKEND->cred->cred_handle, + &BACKEND->cred->time_stamp); if(sspi_status != SEC_E_OK) { if(sspi_status == SEC_E_WRONG_PRINCIPAL) @@ -297,7 +380,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) else failf(data, "schannel: AcquireCredentialsHandle failed: %s", Curl_sspi_strerror(conn, sspi_status)); - Curl_safefree(connssl->cred); + Curl_safefree(BACKEND->cred); return CURLE_SSL_CONNECT_ERROR; } } @@ -312,7 +395,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) } #ifdef HAS_ALPN - if(connssl->use_alpn) { + if(BACKEND->use_alpn) { int cur = 0; int list_start_index = 0; unsigned int *extension_len = NULL; @@ -370,18 +453,18 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) InitSecBufferDesc(&outbuf_desc, &outbuf, 1); /* setup request flags */ - connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | + BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* allocate memory for the security context handle */ - connssl->ctxt = (struct curl_schannel_ctxt *) + BACKEND->ctxt = (struct curl_schannel_ctxt *) malloc(sizeof(struct curl_schannel_ctxt)); - if(!connssl->ctxt) { + if(!BACKEND->ctxt) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } - memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt)); + memset(BACKEND->ctxt, 0, sizeof(struct curl_schannel_ctxt)); host_name = Curl_convert_UTF8_to_tchar(hostname); if(!host_name) @@ -395,10 +478,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) us problems with inbuf regardless. https://github.com/curl/curl/issues/983 */ sspi_status = s_pSecFn->InitializeSecurityContext( - &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0, - (connssl->use_alpn ? &inbuf_desc : NULL), - 0, &connssl->ctxt->ctxt_handle, - &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); + &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0, + (BACKEND->use_alpn ? &inbuf_desc : NULL), + 0, &BACKEND->ctxt->ctxt_handle, + &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); Curl_unicodefree(host_name); @@ -409,7 +492,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) else failf(data, "schannel: initial InitializeSecurityContext failed: %s", Curl_sspi_strerror(conn, sspi_status)); - Curl_safefree(connssl->ctxt); + Curl_safefree(BACKEND->ctxt); return CURLE_SSL_CONNECT_ERROR; } @@ -429,10 +512,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: sent initial handshake data: " "sent %zd bytes\n", written); - connssl->recv_unrecoverable_err = CURLE_OK; - connssl->recv_sspi_close_notify = false; - connssl->recv_connection_closed = false; - connssl->encdata_is_incomplete = false; + BACKEND->recv_unrecoverable_err = CURLE_OK; + BACKEND->recv_sspi_close_notify = false; + BACKEND->recv_connection_closed = false; + BACKEND->encdata_is_incomplete = false; /* continue to second handshake step */ connssl->connecting_state = ssl_connect_2; @@ -465,39 +548,39 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n", hostname, conn->remote_port); - if(!connssl->cred || !connssl->ctxt) + if(!BACKEND->cred || !BACKEND->ctxt) return CURLE_SSL_CONNECT_ERROR; /* buffer to store previously received and decrypted data */ - if(connssl->decdata_buffer == NULL) { - connssl->decdata_offset = 0; - connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - connssl->decdata_buffer = malloc(connssl->decdata_length); - if(connssl->decdata_buffer == NULL) { + if(BACKEND->decdata_buffer == NULL) { + BACKEND->decdata_offset = 0; + BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + BACKEND->decdata_buffer = malloc(BACKEND->decdata_length); + if(BACKEND->decdata_buffer == NULL) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } } /* buffer to store previously received and encrypted data */ - if(connssl->encdata_buffer == NULL) { - connssl->encdata_is_incomplete = false; - connssl->encdata_offset = 0; - connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - connssl->encdata_buffer = malloc(connssl->encdata_length); - if(connssl->encdata_buffer == NULL) { + if(BACKEND->encdata_buffer == NULL) { + BACKEND->encdata_is_incomplete = false; + BACKEND->encdata_offset = 0; + BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + BACKEND->encdata_buffer = malloc(BACKEND->encdata_length); + if(BACKEND->encdata_buffer == NULL) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } } /* if we need a bigger buffer to read a full message, increase buffer now */ - if(connssl->encdata_length - connssl->encdata_offset < + if(BACKEND->encdata_length - BACKEND->encdata_offset < CURL_SCHANNEL_BUFFER_FREE_SIZE) { /* increase internal encrypted data buffer */ - reallocated_length = connssl->encdata_offset + + reallocated_length = BACKEND->encdata_offset + CURL_SCHANNEL_BUFFER_FREE_SIZE; - reallocated_buffer = realloc(connssl->encdata_buffer, + reallocated_buffer = realloc(BACKEND->encdata_buffer, reallocated_length); if(reallocated_buffer == NULL) { @@ -505,8 +588,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) return CURLE_OUT_OF_MEMORY; } else { - connssl->encdata_buffer = reallocated_buffer; - connssl->encdata_length = reallocated_length; + BACKEND->encdata_buffer = reallocated_buffer; + BACKEND->encdata_length = reallocated_length; } } @@ -514,10 +597,10 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) if(doread) { /* read encrypted handshake data from socket */ result = Curl_read_plain(conn->sock[sockindex], - (char *) (connssl->encdata_buffer + - connssl->encdata_offset), - connssl->encdata_length - - connssl->encdata_offset, + (char *) (BACKEND->encdata_buffer + + BACKEND->encdata_offset), + BACKEND->encdata_length - + BACKEND->encdata_offset, &nread); if(result == CURLE_AGAIN) { if(connssl->connecting_state != ssl_connect_2_writing) @@ -533,17 +616,17 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) } /* increase encrypted data buffer offset */ - connssl->encdata_offset += nread; - connssl->encdata_is_incomplete = false; + BACKEND->encdata_offset += nread; + BACKEND->encdata_is_incomplete = false; infof(data, "schannel: encrypted data got %zd\n", nread); } infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - connssl->encdata_offset, connssl->encdata_length); + BACKEND->encdata_offset, BACKEND->encdata_length); /* setup input buffers */ - InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset), - curlx_uztoul(connssl->encdata_offset)); + InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset), + curlx_uztoul(BACKEND->encdata_offset)); InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, inbuf, 2); @@ -559,8 +642,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) } /* copy received handshake data into input buffer */ - memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer, - connssl->encdata_offset); + memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer, + BACKEND->encdata_offset); host_name = Curl_convert_UTF8_to_tchar(hostname); if(!host_name) @@ -569,9 +652,9 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ sspi_status = s_pSecFn->InitializeSecurityContext( - &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle, - host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL, - &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); + &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, + host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL, + &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); Curl_unicodefree(host_name); @@ -580,7 +663,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) /* check if the handshake was incomplete */ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - connssl->encdata_is_incomplete = true; + BACKEND->encdata_is_incomplete = true; connssl->connecting_state = ssl_connect_2_reading; infof(data, "schannel: received incomplete message, need more data\n"); return CURLE_OK; @@ -590,8 +673,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) the handshake without one. This will allow connections to servers which request a client certificate but do not require it. */ if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && - !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { - connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { + BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; connssl->connecting_state = ssl_connect_2_writing; infof(data, "schannel: a client certificate has been requested\n"); return CURLE_OK; @@ -631,7 +714,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) failf(data, "schannel: next InitializeSecurityContext failed: %s", Curl_sspi_strerror(conn, sspi_status)); return sspi_status == SEC_E_UNTRUSTED_ROOT ? - CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CONNECT_ERROR; + CURLE_SSL_CACERT : CURLE_SSL_CONNECT_ERROR; } /* check if there was additional remaining encrypted data */ @@ -649,11 +732,11 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) */ /* check if the remaining data is less than the total amount and therefore begins after the already processed data */ - if(connssl->encdata_offset > inbuf[1].cbBuffer) { - memmove(connssl->encdata_buffer, - (connssl->encdata_buffer + connssl->encdata_offset) - + if(BACKEND->encdata_offset > inbuf[1].cbBuffer) { + memmove(BACKEND->encdata_buffer, + (BACKEND->encdata_buffer + BACKEND->encdata_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer); - connssl->encdata_offset = inbuf[1].cbBuffer; + BACKEND->encdata_offset = inbuf[1].cbBuffer; if(sspi_status == SEC_I_CONTINUE_NEEDED) { doread = FALSE; continue; @@ -661,7 +744,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) } } else { - connssl->encdata_offset = 0; + BACKEND->encdata_offset = 0; } break; } @@ -709,27 +792,27 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n", hostname, conn->remote_port); - if(!connssl->cred) + if(!BACKEND->cred) return CURLE_SSL_CONNECT_ERROR; /* check if the required context attributes are met */ - if(connssl->ret_flags != connssl->req_flags) { - if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT)) + if(BACKEND->ret_flags != BACKEND->req_flags) { + if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT)) failf(data, "schannel: failed to setup sequence detection"); - if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT)) + if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT)) failf(data, "schannel: failed to setup replay detection"); - if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY)) + if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY)) failf(data, "schannel: failed to setup confidentiality"); - if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY)) + if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY)) failf(data, "schannel: failed to setup memory allocation"); - if(!(connssl->ret_flags & ISC_RET_STREAM)) + if(!(BACKEND->ret_flags & ISC_RET_STREAM)) failf(data, "schannel: failed to setup stream orientation"); return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN - if(connssl->use_alpn) { - sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + if(BACKEND->use_alpn) { + sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); if(sspi_status != SEC_E_OK) { @@ -771,7 +854,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)); if(incache) { - if(old_cred != connssl->cred) { + if(old_cred != BACKEND->cred) { infof(data, "schannel: old credential handle is stale, removing\n"); /* we're not taking old_cred ownership here, no refcount++ is needed */ Curl_ssl_delsessionid(conn, (void *)old_cred); @@ -779,7 +862,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } } if(!incache) { - result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, + result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred, sizeof(struct curl_schannel_cred), sockindex); if(result) { @@ -789,7 +872,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } else { /* this cred session is now also referenced by sessionid cache */ - connssl->cred->refcount++; + BACKEND->cred->refcount++; infof(data, "schannel: stored credential handle in session cache\n"); } } @@ -797,7 +880,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } if(data->set.ssl.certinfo) { - sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + 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)) { @@ -951,11 +1034,11 @@ schannel_send(struct connectdata *conn, int sockindex, CURLcode result; /* check if the maximum stream sizes were queried */ - if(connssl->stream_sizes.cbMaximumMessage == 0) { + if(BACKEND->stream_sizes.cbMaximumMessage == 0) { sspi_status = s_pSecFn->QueryContextAttributes( - &connssl->ctxt->ctxt_handle, + &BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, - &connssl->stream_sizes); + &BACKEND->stream_sizes); if(sspi_status != SEC_E_OK) { *err = CURLE_SEND_ERROR; return -1; @@ -963,14 +1046,13 @@ schannel_send(struct connectdata *conn, int sockindex, } /* check if the buffer is longer than the maximum message length */ - if(len > connssl->stream_sizes.cbMaximumMessage) { - *err = CURLE_SEND_ERROR; - return -1; + if(len > BACKEND->stream_sizes.cbMaximumMessage) { + len = BACKEND->stream_sizes.cbMaximumMessage; } /* calculate the complete message length and allocate a buffer for it */ - data_len = connssl->stream_sizes.cbHeader + len + - connssl->stream_sizes.cbTrailer; + data_len = BACKEND->stream_sizes.cbHeader + len + + BACKEND->stream_sizes.cbTrailer; data = (unsigned char *) malloc(data_len); if(data == NULL) { *err = CURLE_OUT_OF_MEMORY; @@ -979,12 +1061,12 @@ schannel_send(struct connectdata *conn, int sockindex, /* setup output buffers (header, data, trailer, empty) */ InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, - data, connssl->stream_sizes.cbHeader); + data, BACKEND->stream_sizes.cbHeader); InitSecBuffer(&outbuf[1], SECBUFFER_DATA, - data + connssl->stream_sizes.cbHeader, curlx_uztoul(len)); + data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len)); InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, - data + connssl->stream_sizes.cbHeader + len, - connssl->stream_sizes.cbTrailer); + data + BACKEND->stream_sizes.cbHeader + len, + BACKEND->stream_sizes.cbTrailer); InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, outbuf, 4); @@ -992,7 +1074,7 @@ schannel_send(struct connectdata *conn, int sockindex, memcpy(outbuf[1].pvBuffer, buf, len); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ - sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0, + sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0, &outbuf_desc, 0); /* check if the message was encrypted */ @@ -1102,7 +1184,7 @@ schannel_recv(struct connectdata *conn, int sockindex, size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; /**************************************************************************** - * Don't return or set connssl->recv_unrecoverable_err unless in the cleanup. + * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup. * The pattern for return error is set *err, optional infof, goto cleanup. * * Our priority is to always return as much decrypted data to the caller as @@ -1114,16 +1196,16 @@ schannel_recv(struct connectdata *conn, int sockindex, infof(data, "schannel: client wants to read %zu bytes\n", len); *err = CURLE_OK; - if(len && len <= connssl->decdata_offset) { + if(len && len <= BACKEND->decdata_offset) { infof(data, "schannel: enough decrypted data is already available\n"); goto cleanup; } - else if(connssl->recv_unrecoverable_err) { - *err = connssl->recv_unrecoverable_err; + else if(BACKEND->recv_unrecoverable_err) { + *err = BACKEND->recv_unrecoverable_err; infof(data, "schannel: an unrecoverable error occurred in a prior call\n"); goto cleanup; } - else if(connssl->recv_sspi_close_notify) { + else if(BACKEND->recv_sspi_close_notify) { /* once a server has indicated shutdown there is no more encrypted data */ infof(data, "schannel: server indicated shutdown in a prior call\n"); goto cleanup; @@ -1135,17 +1217,17 @@ schannel_recv(struct connectdata *conn, int sockindex, */ ; /* do nothing */ } - else if(!connssl->recv_connection_closed) { + else if(!BACKEND->recv_connection_closed) { /* increase enc buffer in order to fit the requested amount of data */ - size = connssl->encdata_length - connssl->encdata_offset; + size = BACKEND->encdata_length - BACKEND->encdata_offset; if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || - connssl->encdata_length < min_encdata_length) { - reallocated_length = connssl->encdata_offset + + BACKEND->encdata_length < min_encdata_length) { + reallocated_length = BACKEND->encdata_offset + CURL_SCHANNEL_BUFFER_FREE_SIZE; if(reallocated_length < min_encdata_length) { reallocated_length = min_encdata_length; } - reallocated_buffer = realloc(connssl->encdata_buffer, + reallocated_buffer = realloc(BACKEND->encdata_buffer, reallocated_length); if(reallocated_buffer == NULL) { *err = CURLE_OUT_OF_MEMORY; @@ -1153,20 +1235,20 @@ schannel_recv(struct connectdata *conn, int sockindex, goto cleanup; } - connssl->encdata_buffer = reallocated_buffer; - connssl->encdata_length = reallocated_length; - size = connssl->encdata_length - connssl->encdata_offset; + BACKEND->encdata_buffer = reallocated_buffer; + BACKEND->encdata_length = reallocated_length; + size = BACKEND->encdata_length - BACKEND->encdata_offset; infof(data, "schannel: encdata_buffer resized %zu\n", - connssl->encdata_length); + BACKEND->encdata_length); } infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - connssl->encdata_offset, connssl->encdata_length); + BACKEND->encdata_offset, BACKEND->encdata_length); /* read encrypted data from socket */ *err = Curl_read_plain(conn->sock[sockindex], - (char *)(connssl->encdata_buffer + - connssl->encdata_offset), + (char *)(BACKEND->encdata_buffer + + BACKEND->encdata_offset), size, &nread); if(*err) { nread = -1; @@ -1178,26 +1260,26 @@ schannel_recv(struct connectdata *conn, int sockindex, infof(data, "schannel: Curl_read_plain returned error %d\n", *err); } else if(nread == 0) { - connssl->recv_connection_closed = true; + BACKEND->recv_connection_closed = true; infof(data, "schannel: server closed the connection\n"); } else if(nread > 0) { - connssl->encdata_offset += (size_t)nread; - connssl->encdata_is_incomplete = false; + BACKEND->encdata_offset += (size_t)nread; + BACKEND->encdata_is_incomplete = false; infof(data, "schannel: encrypted data got %zd\n", nread); } } infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - connssl->encdata_offset, connssl->encdata_length); + BACKEND->encdata_offset, BACKEND->encdata_length); /* decrypt loop */ - while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK && - (!len || connssl->decdata_offset < len || - connssl->recv_connection_closed)) { + while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK && + (!len || BACKEND->decdata_offset < len || + BACKEND->recv_connection_closed)) { /* prepare data buffer for DecryptMessage call */ - InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer, - curlx_uztoul(connssl->encdata_offset)); + InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer, + curlx_uztoul(BACKEND->encdata_offset)); /* we need 3 more empty input buffers for possible output */ InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); @@ -1207,7 +1289,7 @@ schannel_recv(struct connectdata *conn, int sockindex, /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */ - sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle, + sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); /* check if everything went fine (server may want to renegotiate @@ -1223,36 +1305,36 @@ 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; - if(connssl->decdata_length - connssl->decdata_offset < size || - connssl->decdata_length < len) { + if(BACKEND->decdata_length - BACKEND->decdata_offset < size || + BACKEND->decdata_length < len) { /* increase internal decrypted data buffer */ - reallocated_length = connssl->decdata_offset + size; + reallocated_length = BACKEND->decdata_offset + size; /* make sure that the requested amount of data fits */ if(reallocated_length < len) { reallocated_length = len; } - reallocated_buffer = realloc(connssl->decdata_buffer, + reallocated_buffer = realloc(BACKEND->decdata_buffer, reallocated_length); if(reallocated_buffer == NULL) { *err = CURLE_OUT_OF_MEMORY; failf(data, "schannel: unable to re-allocate memory"); goto cleanup; } - connssl->decdata_buffer = reallocated_buffer; - connssl->decdata_length = reallocated_length; + BACKEND->decdata_buffer = reallocated_buffer; + BACKEND->decdata_length = reallocated_length; } /* copy decrypted data to internal buffer */ size = inbuf[1].cbBuffer; if(size) { - memcpy(connssl->decdata_buffer + connssl->decdata_offset, + memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset, inbuf[1].pvBuffer, size); - connssl->decdata_offset += size; + BACKEND->decdata_offset += size; } infof(data, "schannel: decrypted data added: %zu\n", size); infof(data, "schannel: decrypted data cached: offset %zu length %zu\n", - connssl->decdata_offset, connssl->decdata_length); + BACKEND->decdata_offset, BACKEND->decdata_length); } /* check for remaining encrypted data */ @@ -1263,21 +1345,21 @@ schannel_recv(struct connectdata *conn, int sockindex, /* check if the remaining data is less than the total amount * and therefore begins after the already processed data */ - if(connssl->encdata_offset > inbuf[3].cbBuffer) { + if(BACKEND->encdata_offset > inbuf[3].cbBuffer) { /* move remaining encrypted data forward to the beginning of buffer */ - memmove(connssl->encdata_buffer, - (connssl->encdata_buffer + connssl->encdata_offset) - + memmove(BACKEND->encdata_buffer, + (BACKEND->encdata_buffer + BACKEND->encdata_offset) - inbuf[3].cbBuffer, inbuf[3].cbBuffer); - connssl->encdata_offset = inbuf[3].cbBuffer; + BACKEND->encdata_offset = inbuf[3].cbBuffer; } infof(data, "schannel: encrypted data cached: offset %zu length %zu\n", - connssl->encdata_offset, connssl->encdata_length); + BACKEND->encdata_offset, BACKEND->encdata_length); } else { /* reset encrypted buffer offset, because there is no data remaining */ - connssl->encdata_offset = 0; + BACKEND->encdata_offset = 0; } /* check if server wants to renegotiate the connection context */ @@ -1287,7 +1369,7 @@ schannel_recv(struct connectdata *conn, int sockindex, infof(data, "schannel: can't renogotiate, an error is pending\n"); goto cleanup; } - if(connssl->encdata_offset) { + if(BACKEND->encdata_offset) { *err = CURLE_RECV_ERROR; infof(data, "schannel: can't renogotiate, " "encrypted data available\n"); @@ -1311,16 +1393,16 @@ schannel_recv(struct connectdata *conn, int sockindex, else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not returned so we have to work around that in cleanup. */ - connssl->recv_sspi_close_notify = true; - if(!connssl->recv_connection_closed) { - connssl->recv_connection_closed = true; + BACKEND->recv_sspi_close_notify = true; + if(!BACKEND->recv_connection_closed) { + BACKEND->recv_connection_closed = true; infof(data, "schannel: server closed the connection\n"); } goto cleanup; } } else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - connssl->encdata_is_incomplete = true; + BACKEND->encdata_is_incomplete = true; if(!*err) *err = CURLE_AGAIN; infof(data, "schannel: failed to decrypt data, need more data\n"); @@ -1335,10 +1417,10 @@ schannel_recv(struct connectdata *conn, int sockindex, } infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - connssl->encdata_offset, connssl->encdata_length); + BACKEND->encdata_offset, BACKEND->encdata_length); infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", - connssl->decdata_offset, connssl->decdata_length); + BACKEND->decdata_offset, BACKEND->decdata_length); cleanup: /* Warning- there is no guarantee the encdata state is valid at this point */ @@ -1352,13 +1434,13 @@ cleanup: 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 && !connssl->decdata_offset && connssl->recv_connection_closed && - !connssl->recv_sspi_close_notify) { + if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed && + !BACKEND->recv_sspi_close_notify) { bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT, VERSION_EQUAL); if(isWin2k && sspi_status == SEC_E_OK) - connssl->recv_sspi_close_notify = true; + BACKEND->recv_sspi_close_notify = true; else { *err = CURLE_RECV_ERROR; infof(data, "schannel: server closed abruptly (missing close_notify)\n"); @@ -1367,23 +1449,23 @@ cleanup: /* Any error other than CURLE_AGAIN is an unrecoverable error. */ if(*err && *err != CURLE_AGAIN) - connssl->recv_unrecoverable_err = *err; + BACKEND->recv_unrecoverable_err = *err; - size = len < connssl->decdata_offset ? len : connssl->decdata_offset; + size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset; if(size) { - memcpy(buf, connssl->decdata_buffer, size); - memmove(connssl->decdata_buffer, connssl->decdata_buffer + size, - connssl->decdata_offset - size); - connssl->decdata_offset -= size; + memcpy(buf, BACKEND->decdata_buffer, size); + memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size, + BACKEND->decdata_offset - size); + BACKEND->decdata_offset -= size; infof(data, "schannel: decrypted data returned %zu\n", size); infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", - connssl->decdata_offset, connssl->decdata_length); + BACKEND->decdata_offset, BACKEND->decdata_length); *err = CURLE_OK; return (ssize_t)size; } - if(!*err && !connssl->recv_connection_closed) + if(!*err && !BACKEND->recv_connection_closed) *err = CURLE_AGAIN; /* It's debatable what to return when !len. We could return whatever error we @@ -1395,15 +1477,13 @@ cleanup: return *err ? -1 : 0; } -CURLcode -Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex, - bool *done) +static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) { return schannel_connect_common(conn, sockindex, TRUE, done); } -CURLcode -Curl_schannel_connect(struct connectdata *conn, int sockindex) +static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; @@ -1417,25 +1497,38 @@ Curl_schannel_connect(struct connectdata *conn, int sockindex) return CURLE_OK; } -bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) +static bool Curl_schannel_data_pending(const struct connectdata *conn, + int sockindex) { const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->use) /* SSL/TLS is in use */ - return (connssl->decdata_offset > 0 || - (connssl->encdata_offset > 0 && !connssl->encdata_is_incomplete)); + return (BACKEND->decdata_offset > 0 || + (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete)); else return FALSE; } -void Curl_schannel_close(struct connectdata *conn, int sockindex) +static void Curl_schannel_close(struct connectdata *conn, int sockindex) { if(conn->ssl[sockindex].use) /* if the SSL/TLS channel hasn't been shut down yet, do that now. */ Curl_ssl_shutdown(conn, sockindex); } -int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) +static void Curl_schannel_session_free(void *ptr) +{ + /* this is expected to be called under sessionid lock */ + struct curl_schannel_cred *cred = ptr; + + cred->refcount--; + if(cred->refcount == 0) { + s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); + Curl_safefree(cred); + } +} + +static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) { /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx * Shutting Down an Schannel Connection @@ -1448,7 +1541,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", hostname, conn->remote_port); - if(connssl->cred && connssl->ctxt) { + if(BACKEND->cred && BACKEND->ctxt) { SecBufferDesc BuffDesc; SecBuffer Buffer; SECURITY_STATUS sspi_status; @@ -1461,7 +1554,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); InitSecBufferDesc(&BuffDesc, &Buffer, 1); - sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle, + sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle, &BuffDesc); if(sspi_status != SEC_E_OK) @@ -1477,18 +1570,18 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) InitSecBufferDesc(&outbuf_desc, &outbuf, 1); sspi_status = s_pSecFn->InitializeSecurityContext( - &connssl->cred->cred_handle, - &connssl->ctxt->ctxt_handle, + &BACKEND->cred->cred_handle, + &BACKEND->ctxt->ctxt_handle, host_name, - connssl->req_flags, + BACKEND->req_flags, 0, 0, NULL, 0, - &connssl->ctxt->ctxt_handle, + &BACKEND->ctxt->ctxt_handle, &outbuf_desc, - &connssl->ret_flags, - &connssl->ctxt->time_stamp); + &BACKEND->ret_flags, + &BACKEND->ctxt->time_stamp); Curl_unicodefree(host_name); @@ -1507,71 +1600,62 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) } /* free SSPI Schannel API security context handle */ - if(connssl->ctxt) { + if(BACKEND->ctxt) { infof(data, "schannel: clear security context handle\n"); - s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle); - Curl_safefree(connssl->ctxt); + s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle); + Curl_safefree(BACKEND->ctxt); } /* free SSPI Schannel API credential handle */ - if(connssl->cred) { + if(BACKEND->cred) { Curl_ssl_sessionid_lock(conn); - Curl_schannel_session_free(connssl->cred); + Curl_schannel_session_free(BACKEND->cred); Curl_ssl_sessionid_unlock(conn); - connssl->cred = NULL; + BACKEND->cred = NULL; } /* free internal buffer for received encrypted data */ - if(connssl->encdata_buffer != NULL) { - Curl_safefree(connssl->encdata_buffer); - connssl->encdata_length = 0; - connssl->encdata_offset = 0; - connssl->encdata_is_incomplete = false; + if(BACKEND->encdata_buffer != NULL) { + Curl_safefree(BACKEND->encdata_buffer); + BACKEND->encdata_length = 0; + BACKEND->encdata_offset = 0; + BACKEND->encdata_is_incomplete = false; } /* free internal buffer for received decrypted data */ - if(connssl->decdata_buffer != NULL) { - Curl_safefree(connssl->decdata_buffer); - connssl->decdata_length = 0; - connssl->decdata_offset = 0; + if(BACKEND->decdata_buffer != NULL) { + Curl_safefree(BACKEND->decdata_buffer); + BACKEND->decdata_length = 0; + BACKEND->decdata_offset = 0; } return CURLE_OK; } -void Curl_schannel_session_free(void *ptr) -{ - /* this is expected to be called under sessionid lock */ - struct curl_schannel_cred *cred = ptr; - - cred->refcount--; - if(cred->refcount == 0) { - s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); - Curl_safefree(cred); - } -} - -int Curl_schannel_init(void) +static int Curl_schannel_init(void) { return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0); } -void Curl_schannel_cleanup(void) +static void Curl_schannel_cleanup(void) { Curl_sspi_global_cleanup(); } -size_t Curl_schannel_version(char *buffer, size_t size) +static size_t Curl_schannel_version(char *buffer, size_t size) { size = snprintf(buffer, size, "WinSSL"); return size; } -CURLcode Curl_schannel_random(unsigned char *entropy, size_t length) +static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM, + unsigned char *entropy, size_t length) { HCRYPTPROV hCryptProv = 0; + (void)data; + if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) return CURLE_FAILED_INIT; @@ -1598,7 +1682,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) conn->http_proxy.host.name : conn->host.name; - status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pCertContextServer); @@ -1725,4 +1809,44 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) } #endif /* _WIN32_WCE */ +static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl, + CURLINFO info UNUSED_PARAM) +{ + (void)info; + return &BACKEND->ctxt->ctxt_handle; +} + +const struct Curl_ssl Curl_ssl_schannel = { + { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */ + + 0, /* have_ca_path */ + 1, /* have_certinfo */ + 0, /* have_pinnedpubkey */ + 0, /* have_ssl_ctx */ + 0, /* support_https_proxy */ + + sizeof(struct ssl_backend_data), + + Curl_schannel_init, /* init */ + Curl_schannel_cleanup, /* cleanup */ + Curl_schannel_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_schannel_shutdown, /* shutdown */ + Curl_schannel_data_pending, /* data_pending */ + Curl_schannel_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + Curl_schannel_connect, /* connect */ + Curl_schannel_connect_nonblocking, /* connect_nonblocking */ + Curl_schannel_get_internals, /* get_internals */ + Curl_schannel_close, /* close */ + Curl_none_close_all, /* close_all */ + Curl_schannel_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_none_md5sum, /* md5sum */ + NULL /* sha256sum */ +}; + #endif /* USE_SCHANNEL */ diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h index 8627c63..932103d 100644 --- a/lib/vtls/schannel.h +++ b/lib/vtls/schannel.h @@ -28,94 +28,7 @@ #include "urldata.h" -#ifndef UNISP_NAME_A -#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider" -#endif - -#ifndef UNISP_NAME_W -#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider" -#endif - -#ifndef UNISP_NAME -#ifdef UNICODE -#define UNISP_NAME UNISP_NAME_W -#else -#define UNISP_NAME UNISP_NAME_A -#endif -#endif - -#ifndef SP_PROT_SSL2_CLIENT -#define SP_PROT_SSL2_CLIENT 0x00000008 -#endif - -#ifndef SP_PROT_SSL3_CLIENT -#define SP_PROT_SSL3_CLIENT 0x00000008 -#endif - -#ifndef SP_PROT_TLS1_CLIENT -#define SP_PROT_TLS1_CLIENT 0x00000080 -#endif - -#ifndef SP_PROT_TLS1_0_CLIENT -#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT -#endif - -#ifndef SP_PROT_TLS1_1_CLIENT -#define SP_PROT_TLS1_1_CLIENT 0x00000200 -#endif - -#ifndef SP_PROT_TLS1_2_CLIENT -#define SP_PROT_TLS1_2_CLIENT 0x00000800 -#endif - -#ifndef SECBUFFER_ALERT -#define SECBUFFER_ALERT 17 -#endif - -/* Both schannel buffer sizes must be > 0 */ -#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 -#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 - - -CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex); - -CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); - -bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex); -void Curl_schannel_close(struct connectdata *conn, int sockindex); -int Curl_schannel_shutdown(struct connectdata *conn, int sockindex); -void Curl_schannel_session_free(void *ptr); - -int Curl_schannel_init(void); -void Curl_schannel_cleanup(void); -size_t Curl_schannel_version(char *buffer, size_t size); - -CURLcode Curl_schannel_random(unsigned char *entropy, size_t length); - -/* Set the API backend definition to Schannel */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL - -/* this backend supports CURLOPT_CERTINFO */ -#define have_curlssl_certinfo 1 - -/* API setup for Schannel */ -#define curlssl_init Curl_schannel_init -#define curlssl_cleanup Curl_schannel_cleanup -#define curlssl_connect Curl_schannel_connect -#define curlssl_connect_nonblocking Curl_schannel_connect_nonblocking -#define curlssl_session_free Curl_schannel_session_free -#define curlssl_close_all(x) ((void)x) -#define curlssl_close Curl_schannel_close -#define curlssl_shutdown Curl_schannel_shutdown -#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) -#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) -#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) -#define curlssl_version Curl_schannel_version -#define curlssl_check_cxn(x) ((void)x, -1) -#define curlssl_data_pending Curl_schannel_data_pending -#define curlssl_random(x,y,z) ((void)x, Curl_schannel_random(y,z)) +extern const struct Curl_ssl Curl_ssl_schannel; #endif /* USE_SCHANNEL */ #endif /* HEADER_CURL_SCHANNEL_H */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index d5d0971..bb8fda4 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -28,17 +28,9 @@ to any specific SSL-layer. Curl_ssl_ - prefix for generic ones - Curl_ossl_ - prefix for OpenSSL ones - Curl_gtls_ - prefix for GnuTLS ones - Curl_nss_ - prefix for NSS ones - Curl_gskit_ - prefix for GSKit ones - Curl_polarssl_ - prefix for PolarSSL ones - Curl_cyassl_ - prefix for CyaSSL ones - Curl_schannel_ - prefix for Schannel SSPI ones - Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones - - Note that this source code uses curlssl_* functions, and they are all - defines/macros #defined by the lib-specific header files. + + Note that this source code uses the functions of the configured SSL + backend via the global Curl_ssl instance. "SSL/TLS Strong Encryption: An Introduction" https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html @@ -98,9 +90,12 @@ Curl_ssl_config_matches(struct ssl_primary_config* data, (data->version_max == needle->version_max) && (data->verifypeer == needle->verifypeer) && (data->verifyhost == needle->verifyhost) && + (data->verifystatus == needle->verifystatus) && Curl_safe_strcasecompare(data->CApath, needle->CApath) && Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && + Curl_safe_strcasecompare(data->random_file, needle->random_file) && + Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) && Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list)) return TRUE; @@ -111,42 +106,51 @@ bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source, struct ssl_primary_config *dest) { - dest->verifyhost = source->verifyhost; - dest->verifypeer = source->verifypeer; dest->version = source->version; dest->version_max = source->version_max; + dest->verifypeer = source->verifypeer; + dest->verifyhost = source->verifyhost; + dest->verifystatus = source->verifystatus; + dest->sessionid = source->sessionid; - CLONE_STRING(CAfile); CLONE_STRING(CApath); - CLONE_STRING(cipher_list); - CLONE_STRING(egdsocket); - CLONE_STRING(random_file); + CLONE_STRING(CAfile); CLONE_STRING(clientcert); + CLONE_STRING(random_file); + CLONE_STRING(egdsocket); + CLONE_STRING(cipher_list); - /* Disable dest sessionid cache if a client cert is used, CVE-2016-5419. */ - dest->sessionid = (dest->clientcert ? false : source->sessionid); return TRUE; } void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc) { - Curl_safefree(sslc->CAfile); Curl_safefree(sslc->CApath); - Curl_safefree(sslc->cipher_list); - Curl_safefree(sslc->egdsocket); - Curl_safefree(sslc->random_file); + Curl_safefree(sslc->CAfile); Curl_safefree(sslc->clientcert); + Curl_safefree(sslc->random_file); + Curl_safefree(sslc->egdsocket); + Curl_safefree(sslc->cipher_list); } +#ifdef USE_SSL +static int multissl_init(const struct Curl_ssl *backend); +#endif + int Curl_ssl_backend(void) { - return (int)CURL_SSL_BACKEND; +#ifdef USE_SSL + multissl_init(NULL); + return Curl_ssl->info.id; +#else + return (int)CURLSSLBACKEND_NONE; +#endif } #ifdef USE_SSL /* "global" init done? */ -static bool init_ssl=FALSE; +static bool init_ssl = FALSE; /** * Global SSL init @@ -161,7 +165,7 @@ int Curl_ssl_init(void) return 1; init_ssl = TRUE; /* never again */ - return curlssl_init(); + return Curl_ssl->init(); } @@ -170,7 +174,7 @@ void Curl_ssl_cleanup(void) { if(init_ssl) { /* only cleanup if we did a previous init */ - curlssl_cleanup(); + Curl_ssl->cleanup(); init_ssl = FALSE; } } @@ -205,12 +209,20 @@ ssl_connect_init_proxy(struct connectdata *conn, int sockindex) DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]); if(ssl_connection_complete == conn->ssl[sockindex].state && !conn->proxy_ssl[sockindex].use) { -#if defined(HTTPS_PROXY_SUPPORT) + struct ssl_backend_data *pbdata; + + if(!Curl_ssl->support_https_proxy) + return CURLE_NOT_BUILT_IN; + + /* The pointers to the ssl backend data, which is opaque here, are swapped + rather than move the contents. */ + pbdata = conn->proxy_ssl[sockindex].backend; conn->proxy_ssl[sockindex] = conn->ssl[sockindex]; + memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex])); -#else - return CURLE_NOT_BUILT_IN; -#endif + memset(pbdata, 0, Curl_ssl->sizeof_ssl_backend_data); + + conn->ssl[sockindex].backend = pbdata; } return CURLE_OK; } @@ -233,7 +245,7 @@ Curl_ssl_connect(struct connectdata *conn, int sockindex) conn->ssl[sockindex].use = TRUE; conn->ssl[sockindex].state = ssl_connection_negotiating; - result = curlssl_connect(conn, sockindex); + result = Curl_ssl->connect(conn, sockindex); if(!result) Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ @@ -257,12 +269,7 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, /* mark this is being ssl requested from here on. */ conn->ssl[sockindex].use = TRUE; -#ifdef curlssl_connect_nonblocking - result = curlssl_connect_nonblocking(conn, sockindex, done); -#else - *done = TRUE; /* fallback to BLOCKING */ - result = curlssl_connect(conn, sockindex); -#endif /* non-blocking connect support */ + result = Curl_ssl->connect_nonblocking(conn, sockindex, done); if(!result && *done) Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ return result; @@ -361,7 +368,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) /* defensive check */ /* free the ID the SSL-layer specific way */ - curlssl_session_free(session->sessionid); + Curl_ssl->session_free(session->sessionid); session->sessionid = NULL; session->age = 0; /* fresh */ @@ -379,7 +386,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) { size_t i; - struct Curl_easy *data=conn->data; + struct Curl_easy *data = conn->data; for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { struct curl_ssl_session *check = &data->state.session[i]; @@ -403,9 +410,9 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, int sockindex) { size_t i; - struct Curl_easy *data=conn->data; /* the mother of all structs */ + struct Curl_easy *data = conn->data; /* the mother of all structs */ struct curl_ssl_session *store = &data->state.session[0]; - long oldest_age=data->state.session[0].age; /* zero if unused */ + long oldest_age = data->state.session[0].age; /* zero if unused */ char *clone_host; char *clone_conn_to_host; int conn_to_port; @@ -499,7 +506,7 @@ void Curl_ssl_close_all(struct Curl_easy *data) Curl_safefree(data->state.session); } - curlssl_close_all(data); + Curl_ssl->close_all(data); } #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ @@ -542,12 +549,12 @@ int Curl_ssl_getsock(struct connectdata *conn, void Curl_ssl_close(struct connectdata *conn, int sockindex) { DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); - curlssl_close(conn, sockindex); + Curl_ssl->close(conn, sockindex); } CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) { - if(curlssl_shutdown(conn, sockindex)) + if(Curl_ssl->shutdown(conn, sockindex)) return CURLE_SSL_SHUTDOWN_FAILED; conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */ @@ -563,20 +570,20 @@ CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) */ CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine) { - return curlssl_set_engine(data, engine); + return Curl_ssl->set_engine(data, engine); } /* Selects the default SSL crypto engine */ CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data) { - return curlssl_set_engine_default(data); + return Curl_ssl->set_engine_default(data); } /* Return list of OpenSSL crypto engine names. */ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data) { - return curlssl_engines_list(data); + return Curl_ssl->engines_list(data); } /* @@ -602,9 +609,15 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) return CURLE_OK; } +static size_t Curl_multissl_version(char *buffer, size_t size); + size_t Curl_ssl_version(char *buffer, size_t size) { - return curlssl_version(buffer, size); +#ifdef CURL_WITH_MULTI_SSL + return Curl_multissl_version(buffer, size); +#else + return Curl_ssl->version(buffer, size); +#endif } /* @@ -617,13 +630,13 @@ size_t Curl_ssl_version(char *buffer, size_t size) */ int Curl_ssl_check_cxn(struct connectdata *conn) { - return curlssl_check_cxn(conn); + return Curl_ssl->check_cxn(conn); } bool Curl_ssl_data_pending(const struct connectdata *conn, int connindex) { - return curlssl_data_pending(conn, connindex); + return Curl_ssl->data_pending(conn, connindex); } void Curl_ssl_free_certinfo(struct Curl_easy *data) @@ -633,7 +646,7 @@ void Curl_ssl_free_certinfo(struct Curl_easy *data) if(ci->num_of_certs) { /* free all individual lists used */ - for(i=0; inum_of_certs; i++) { + for(i = 0; inum_of_certs; i++) { curl_slist_free_all(ci->certinfo[i]); ci->certinfo[i] = NULL; } @@ -687,7 +700,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, snprintf(output, outlen, "%s:", label); /* memcpy the value (it might not be zero terminated) */ - memcpy(&output[labellen+1], value, valuelen); + memcpy(&output[labellen + 1], value, valuelen); /* zero terminate the output */ output[labellen + 1 + valuelen] = 0; @@ -721,7 +734,7 @@ CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { - return curlssl_random(data, entropy, length); + return Curl_ssl->random(data, entropy, length); } /* @@ -796,12 +809,10 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, size_t size, pem_len; CURLcode pem_read; CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; -#ifdef curlssl_sha256sum CURLcode encode; size_t encodedlen, pinkeylen; char *encoded, *pinkeycopy, *begin_pos, *end_pos; unsigned char *sha256sumdigest = NULL; -#endif /* if a path wasn't specified, don't pin */ if(!pinnedpubkey) @@ -811,15 +822,20 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, /* only do this if pinnedpubkey starts with "sha256//", length 8 */ if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { -#ifdef curlssl_sha256sum + if(!Curl_ssl->sha256sum) { + /* without sha256 support, this cannot match */ + return result; + } + /* compute sha256sum of public key */ - sha256sumdigest = malloc(SHA256_DIGEST_LENGTH); + sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH); if(!sha256sumdigest) return CURLE_OUT_OF_MEMORY; - curlssl_sha256sum(pubkey, pubkeylen, - sha256sumdigest, SHA256_DIGEST_LENGTH); + Curl_ssl->sha256sum(pubkey, pubkeylen, + sha256sumdigest, CURL_SHA256_DIGEST_LENGTH); encode = Curl_base64_encode(data, (char *)sha256sumdigest, - SHA256_DIGEST_LENGTH, &encoded, &encodedlen); + CURL_SHA256_DIGEST_LENGTH, &encoded, + &encodedlen); Curl_safefree(sha256sumdigest); if(encode) @@ -864,10 +880,6 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, } while(end_pos && begin_pos); Curl_safefree(encoded); Curl_safefree(pinkeycopy); -#else - /* without sha256 support, this cannot match */ - (void)data; -#endif return result; } @@ -943,20 +955,7 @@ CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ unsigned char *md5sum, /* output */ size_t md5len) { -#ifdef curlssl_md5sum - curlssl_md5sum(tmp, tmplen, md5sum, md5len); -#else - MD5_context *MD5pw; - - (void) md5len; - - MD5pw = Curl_MD5_init(Curl_DIGEST_MD5); - if(!MD5pw) - return CURLE_OUT_OF_MEMORY; - Curl_MD5_update(MD5pw, tmp, curlx_uztoui(tmplen)); - Curl_MD5_final(MD5pw, md5sum); -#endif - return CURLE_OK; + return Curl_ssl->md5sum(tmp, tmplen, md5sum, md5len); } #endif @@ -965,11 +964,7 @@ CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ */ bool Curl_ssl_cert_status_request(void) { -#ifdef curlssl_cert_status_request - return curlssl_cert_status_request(); -#else - return FALSE; -#endif + return Curl_ssl->cert_status_request(); } /* @@ -977,11 +972,341 @@ bool Curl_ssl_cert_status_request(void) */ bool Curl_ssl_false_start(void) { -#ifdef curlssl_false_start - return curlssl_false_start(); -#else + return Curl_ssl->false_start(); +} + +/* + * Default implementations for unsupported functions. + */ + +int Curl_none_init(void) +{ + return 1; +} + +void Curl_none_cleanup(void) +{ } + +int Curl_none_shutdown(struct connectdata *conn UNUSED_PARAM, + int sockindex UNUSED_PARAM) +{ + (void)conn; + (void)sockindex; + return 0; +} + +int Curl_none_check_cxn(struct connectdata *conn UNUSED_PARAM) +{ + (void)conn; + return -1; +} + +CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM, + unsigned char *entropy UNUSED_PARAM, + size_t length UNUSED_PARAM) +{ + (void)data; + (void)entropy; + (void)length; + return CURLE_NOT_BUILT_IN; +} + +void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM) +{ + (void)data; +} + +void Curl_none_session_free(void *ptr UNUSED_PARAM) +{ + (void)ptr; +} + +bool Curl_none_data_pending(const struct connectdata *conn UNUSED_PARAM, + int connindex UNUSED_PARAM) +{ + (void)conn; + (void)connindex; + return 0; +} + +bool Curl_none_cert_status_request(void) +{ return FALSE; +} + +CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM, + const char *engine UNUSED_PARAM) +{ + (void)data; + (void)engine; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM) +{ + (void)data; + return CURLE_NOT_BUILT_IN; +} + +struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM) +{ + (void)data; + return (struct curl_slist *)NULL; +} + +bool Curl_none_false_start(void) +{ + return FALSE; +} + +CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, + unsigned char *md5sum, size_t md5len UNUSED_PARAM) +{ + MD5_context *MD5pw; + + (void)md5len; + + MD5pw = Curl_MD5_init(Curl_DIGEST_MD5); + if(!MD5pw) + return CURLE_OUT_OF_MEMORY; + Curl_MD5_update(MD5pw, input, curlx_uztoui(inputlen)); + Curl_MD5_final(MD5pw, md5sum); + return CURLE_OK; +} + +static int Curl_multissl_init(void) +{ + if(multissl_init(NULL)) + return 1; + return Curl_ssl->init(); +} + +static CURLcode Curl_multissl_connect(struct connectdata *conn, int sockindex) +{ + if(multissl_init(NULL)) + return CURLE_FAILED_INIT; + return Curl_ssl->connect(conn, sockindex); +} + +static CURLcode Curl_multissl_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) +{ + if(multissl_init(NULL)) + return CURLE_FAILED_INIT; + return Curl_ssl->connect_nonblocking(conn, sockindex, done); +} + +static void *Curl_multissl_get_internals(struct ssl_connect_data *connssl, + CURLINFO info) +{ + if(multissl_init(NULL)) + return NULL; + return Curl_ssl->get_internals(connssl, info); +} + +static void Curl_multissl_close(struct connectdata *conn, int sockindex) +{ + if(multissl_init(NULL)) + return; + Curl_ssl->close(conn, sockindex); +} + +static const struct Curl_ssl Curl_ssl_multi = { + { CURLSSLBACKEND_NONE, "multi" }, /* info */ + + 0, /* have_ca_path */ + 0, /* have_certinfo */ + 0, /* have_pinnedpubkey */ + 0, /* have_ssl_ctx */ + 0, /* support_https_proxy */ + + (size_t)-1, /* something insanely large to be on the safe side */ + + Curl_multissl_init, /* init */ + Curl_none_cleanup, /* cleanup */ + Curl_multissl_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_none_shutdown, /* shutdown */ + Curl_none_data_pending, /* data_pending */ + Curl_none_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + Curl_multissl_connect, /* connect */ + Curl_multissl_connect_nonblocking, /* connect_nonblocking */ + Curl_multissl_get_internals, /* get_internals */ + Curl_multissl_close, /* close */ + Curl_none_close_all, /* close_all */ + Curl_none_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + Curl_none_md5sum, /* md5sum */ + NULL /* sha256sum */ +}; + +const struct Curl_ssl *Curl_ssl = +#if defined(CURL_WITH_MULTI_SSL) + &Curl_ssl_multi; +#elif defined(USE_AXTLS) + &Curl_ssl_axtls; +#elif defined(USE_CYASSL) + &Curl_ssl_cyassl; +#elif defined(USE_DARWINSSL) + &Curl_ssl_darwinssl; +#elif defined(USE_GNUTLS) + &Curl_ssl_gnutls; +#elif defined(USE_GSKIT) + &Curl_ssl_gskit; +#elif defined(USE_MBEDTLS) + &Curl_ssl_mbedtls; +#elif defined(USE_NSS) + &Curl_ssl_nss; +#elif defined(USE_OPENSSL) + &Curl_ssl_openssl; +#elif defined(USE_POLARSSL) + &Curl_ssl_polarssl; +#elif defined(USE_SCHANNEL) + &Curl_ssl_schannel; +#else +#error "Missing struct Curl_ssl for selected SSL backend" +#endif + +static const struct Curl_ssl *available_backends[] = { +#if defined(USE_AXTLS) + &Curl_ssl_axtls, +#endif +#if defined(USE_CYASSL) + &Curl_ssl_cyassl, #endif +#if defined(USE_DARWINSSL) + &Curl_ssl_darwinssl, +#endif +#if defined(USE_GNUTLS) + &Curl_ssl_gnutls, +#endif +#if defined(USE_GSKIT) + &Curl_ssl_gskit, +#endif +#if defined(USE_MBEDTLS) + &Curl_ssl_mbedtls, +#endif +#if defined(USE_NSS) + &Curl_ssl_nss, +#endif +#if defined(USE_OPENSSL) + &Curl_ssl_openssl, +#endif +#if defined(USE_POLARSSL) + &Curl_ssl_polarssl, +#endif +#if defined(USE_SCHANNEL) + &Curl_ssl_schannel, +#endif + NULL +}; + +static size_t Curl_multissl_version(char *buffer, size_t size) +{ + static const struct Curl_ssl *selected; + static char backends[200]; + static size_t total; + const struct Curl_ssl *current; + + current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl; + + if(current != selected) { + char *p = backends; + int i; + + selected = current; + + for(i = 0; available_backends[i]; i++) { + if(i) + *(p++) = ' '; + if(selected != available_backends[i]) + *(p++) = '('; + p += available_backends[i]->version(p, backends + sizeof(backends) - p); + if(selected != available_backends[i]) + *(p++) = ')'; + } + *p = '\0'; + total = p - backends; + } + + if(size < total) + memcpy(buffer, backends, total + 1); + else { + memcpy(buffer, backends, size - 1); + buffer[size - 1] = '\0'; + } + + return total; +} + +static int multissl_init(const struct Curl_ssl *backend) +{ + const char *env; + int i; + + if(Curl_ssl != &Curl_ssl_multi) + return 1; + + if(backend) { + Curl_ssl = backend; + return 0; + } + + if(!available_backends[0]) + return 1; + + env = getenv("CURL_SSL_BACKEND"); +#ifdef CURL_DEFAULT_SSL_BACKEND + if(!env) + env = CURL_DEFAULT_SSL_BACKEND; +#endif + if(env) { + for(i = 0; available_backends[i]; i++) { + if(strcasecompare(env, available_backends[i]->info.name)) { + Curl_ssl = available_backends[i]; + return 0; + } + } + } + + /* Fall back to first available backend */ + Curl_ssl = available_backends[0]; + return 0; +} + +CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) +{ + int i; + + if(Curl_ssl != &Curl_ssl_multi) + return id == Curl_ssl->info.id ? CURLSSLSET_OK : CURLSSLSET_TOO_LATE; + + for(i = 0; available_backends[i]; i++) { + if(available_backends[i]->info.id == id || + (name && strcasecompare(available_backends[i]->info.name, name))) { + multissl_init(available_backends[i]); + return CURLSSLSET_OK; + } + } + + if(avail) + *avail = (const curl_ssl_backend **)&available_backends; + return CURLSSLSET_UNKNOWN_BACKEND; +} + +#else /* USE_SSL */ +CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) +{ + (void)id; + (void)name; + (void)avail; + return CURLSSLSET_NO_BACKENDS; } -#endif /* USE_SSL */ +#endif /* !USE_SSL */ diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index 2aabeda..f1a11ea 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,6 +23,80 @@ ***************************************************************************/ #include "curl_setup.h" +struct connectdata; +struct ssl_connect_data; + +struct Curl_ssl { + /* + * This *must* be the first entry to allow returning the list of available + * backends in curl_global_sslset(). + */ + curl_ssl_backend info; + + unsigned have_ca_path:1; /* supports CAPATH */ + unsigned have_certinfo:1; /* supports CURLOPT_CERTINFO */ + unsigned have_pinnedpubkey:1; /* supports CURLOPT_PINNEDPUBLICKEY */ + unsigned have_ssl_ctx:1; /* supports CURLOPT_SSL_CTX_* */ + + unsigned support_https_proxy:1; /* supports access via HTTPS proxies */ + + size_t sizeof_ssl_backend_data; + + int (*init)(void); + void (*cleanup)(void); + + size_t (*version)(char *buffer, size_t size); + int (*check_cxn)(struct connectdata *cxn); + int (*shutdown)(struct connectdata *conn, int sockindex); + bool (*data_pending)(const struct connectdata *conn, + int connindex); + + /* return 0 if a find random is filled in */ + CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy, + size_t length); + bool (*cert_status_request)(void); + + CURLcode (*connect)(struct connectdata *conn, int sockindex); + CURLcode (*connect_nonblocking)(struct connectdata *conn, int sockindex, + bool *done); + void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info); + void (*close)(struct connectdata *conn, int sockindex); + void (*close_all)(struct Curl_easy *data); + void (*session_free)(void *ptr); + + CURLcode (*set_engine)(struct Curl_easy *data, const char *engine); + CURLcode (*set_engine_default)(struct Curl_easy *data); + struct curl_slist *(*engines_list)(struct Curl_easy *data); + + bool (*false_start)(void); + + CURLcode (*md5sum)(unsigned char *input, size_t inputlen, + unsigned char *md5sum, size_t md5sumlen); + void (*sha256sum)(const unsigned char *input, size_t inputlen, + unsigned char *sha256sum, size_t sha256sumlen); +}; + +#ifdef USE_SSL +extern const struct Curl_ssl *Curl_ssl; +#endif + +int Curl_none_init(void); +void Curl_none_cleanup(void); +int Curl_none_shutdown(struct connectdata *conn, int sockindex); +int Curl_none_check_cxn(struct connectdata *conn); +CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy, + size_t length); +void Curl_none_close_all(struct Curl_easy *data); +void Curl_none_session_free(void *ptr); +bool Curl_none_data_pending(const struct connectdata *conn, int connindex); +bool Curl_none_cert_status_request(void); +CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine); +CURLcode Curl_none_set_engine_default(struct Curl_easy *data); +struct curl_slist *Curl_none_engines_list(struct Curl_easy *data); +bool Curl_none_false_start(void); +CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, + unsigned char *md5sum, size_t md5len); + #include "openssl.h" /* OpenSSL versions */ #include "gtls.h" /* GnuTLS versions */ #include "nssg.h" /* NSS versions */ @@ -42,8 +116,8 @@ #define MD5_DIGEST_LENGTH 16 /* fixed size */ #endif -#ifndef SHA256_DIGEST_LENGTH -#define SHA256_DIGEST_LENGTH 32 /* fixed size */ +#ifndef CURL_SHA256_DIGEST_LENGTH +#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */ #endif /* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */ @@ -172,8 +246,6 @@ bool Curl_ssl_false_start(void); #define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ #else -/* Set the API backend definition to none */ -#define CURL_SSL_BACKEND CURLSSLBACKEND_NONE /* When SSL support is not present, just define away these function calls */ #define Curl_ssl_init() 1 diff --git a/lib/warnless.c b/lib/warnless.c index fb085c8..05d9038 100644 --- a/lib/warnless.c +++ b/lib/warnless.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -69,36 +69,36 @@ # error "SIZEOF_INT not defined" #endif -#if (CURL_SIZEOF_LONG == 2) +#if (SIZEOF_LONG == 2) # define CURL_MASK_SLONG 0x7FFFL # define CURL_MASK_ULONG 0xFFFFUL -#elif (CURL_SIZEOF_LONG == 4) +#elif (SIZEOF_LONG == 4) # define CURL_MASK_SLONG 0x7FFFFFFFL # define CURL_MASK_ULONG 0xFFFFFFFFUL -#elif (CURL_SIZEOF_LONG == 8) +#elif (SIZEOF_LONG == 8) # define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFL # define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFUL -#elif (CURL_SIZEOF_LONG == 16) +#elif (SIZEOF_LONG == 16) # define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL # define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL #else -# error "CURL_SIZEOF_LONG not defined" +# error "SIZEOF_LONG not defined" #endif -#if (CURL_SIZEOF_CURL_OFF_T == 2) +#if (SIZEOF_CURL_OFF_T == 2) # define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFF) # define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFF) -#elif (CURL_SIZEOF_CURL_OFF_T == 4) +#elif (SIZEOF_CURL_OFF_T == 4) # define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFF) # define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFF) -#elif (CURL_SIZEOF_CURL_OFF_T == 8) +#elif (SIZEOF_CURL_OFF_T == 8) # define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) # define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFF) -#elif (CURL_SIZEOF_CURL_OFF_T == 16) +#elif (SIZEOF_CURL_OFF_T == 16) # define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) # define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) #else -# error "CURL_SIZEOF_CURL_OFF_T not defined" +# error "SIZEOF_CURL_OFF_T not defined" #endif #if (SIZEOF_SIZE_T == SIZEOF_SHORT) @@ -107,10 +107,10 @@ #elif (SIZEOF_SIZE_T == SIZEOF_INT) # define CURL_MASK_SSIZE_T CURL_MASK_SINT # define CURL_MASK_USIZE_T CURL_MASK_UINT -#elif (SIZEOF_SIZE_T == CURL_SIZEOF_LONG) +#elif (SIZEOF_SIZE_T == SIZEOF_LONG) # define CURL_MASK_SSIZE_T CURL_MASK_SLONG # define CURL_MASK_USIZE_T CURL_MASK_ULONG -#elif (SIZEOF_SIZE_T == CURL_SIZEOF_CURL_OFF_T) +#elif (SIZEOF_SIZE_T == SIZEOF_CURL_OFF_T) # define CURL_MASK_SSIZE_T CURL_MASK_SCOFFT # define CURL_MASK_USIZE_T CURL_MASK_UCOFFT #else @@ -226,7 +226,7 @@ unsigned long curlx_uztoul(size_t uznum) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif -#if (CURL_SIZEOF_LONG < SIZEOF_SIZE_T) +#if (SIZEOF_LONG < SIZEOF_SIZE_T) DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG); #endif return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG); @@ -269,7 +269,7 @@ int curlx_sltosi(long slnum) #endif DEBUGASSERT(slnum >= 0); -#if (SIZEOF_INT < CURL_SIZEOF_LONG) +#if (SIZEOF_INT < SIZEOF_LONG) DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT); #endif return (int)(slnum & (long) CURL_MASK_SINT); @@ -291,7 +291,7 @@ unsigned int curlx_sltoui(long slnum) #endif DEBUGASSERT(slnum >= 0); -#if (SIZEOF_INT < CURL_SIZEOF_LONG) +#if (SIZEOF_INT < SIZEOF_LONG) DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT); #endif return (unsigned int)(slnum & (long) CURL_MASK_UINT); -- cgit v0.12